162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
362306a36Sopenharmony_ci * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies.
462306a36Sopenharmony_ci * All rights reserved.
562306a36Sopenharmony_ci * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc.  All rights reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This software is available to you under a choice of one of two
862306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
962306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
1062306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
1162306a36Sopenharmony_ci * OpenIB.org BSD license below:
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1462306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1562306a36Sopenharmony_ci *     conditions are met:
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1862306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1962306a36Sopenharmony_ci *        disclaimer.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
2262306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2362306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2462306a36Sopenharmony_ci *        provided with the distribution.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2762306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2862306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2962306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
3062306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
3162306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3262306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3362306a36Sopenharmony_ci * SOFTWARE.
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include <linux/sched.h>
3762306a36Sopenharmony_ci#include <linux/pci.h>
3862306a36Sopenharmony_ci#include <linux/errno.h>
3962306a36Sopenharmony_ci#include <linux/kernel.h>
4062306a36Sopenharmony_ci#include <linux/io.h>
4162306a36Sopenharmony_ci#include <linux/slab.h>
4262306a36Sopenharmony_ci#include <linux/mlx4/cmd.h>
4362306a36Sopenharmony_ci#include <linux/mlx4/qp.h>
4462306a36Sopenharmony_ci#include <linux/if_ether.h>
4562306a36Sopenharmony_ci#include <linux/etherdevice.h>
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#include "mlx4.h"
4862306a36Sopenharmony_ci#include "fw.h"
4962306a36Sopenharmony_ci#include "mlx4_stats.h"
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define MLX4_MAC_VALID		(1ull << 63)
5262306a36Sopenharmony_ci#define MLX4_PF_COUNTERS_PER_PORT	2
5362306a36Sopenharmony_ci#define MLX4_VF_COUNTERS_PER_PORT	1
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistruct mac_res {
5662306a36Sopenharmony_ci	struct list_head list;
5762306a36Sopenharmony_ci	u64 mac;
5862306a36Sopenharmony_ci	int ref_count;
5962306a36Sopenharmony_ci	u8 smac_index;
6062306a36Sopenharmony_ci	u8 port;
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistruct vlan_res {
6462306a36Sopenharmony_ci	struct list_head list;
6562306a36Sopenharmony_ci	u16 vlan;
6662306a36Sopenharmony_ci	int ref_count;
6762306a36Sopenharmony_ci	int vlan_index;
6862306a36Sopenharmony_ci	u8 port;
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistruct res_common {
7262306a36Sopenharmony_ci	struct list_head	list;
7362306a36Sopenharmony_ci	struct rb_node		node;
7462306a36Sopenharmony_ci	u64		        res_id;
7562306a36Sopenharmony_ci	int			owner;
7662306a36Sopenharmony_ci	int			state;
7762306a36Sopenharmony_ci	int			from_state;
7862306a36Sopenharmony_ci	int			to_state;
7962306a36Sopenharmony_ci	int			removing;
8062306a36Sopenharmony_ci	const char		*func_name;
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cienum {
8462306a36Sopenharmony_ci	RES_ANY_BUSY = 1
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistruct res_gid {
8862306a36Sopenharmony_ci	struct list_head	list;
8962306a36Sopenharmony_ci	u8			gid[16];
9062306a36Sopenharmony_ci	enum mlx4_protocol	prot;
9162306a36Sopenharmony_ci	enum mlx4_steer_type	steer;
9262306a36Sopenharmony_ci	u64			reg_id;
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cienum res_qp_states {
9662306a36Sopenharmony_ci	RES_QP_BUSY = RES_ANY_BUSY,
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/* QP number was allocated */
9962306a36Sopenharmony_ci	RES_QP_RESERVED,
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* ICM memory for QP context was mapped */
10262306a36Sopenharmony_ci	RES_QP_MAPPED,
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* QP is in hw ownership */
10562306a36Sopenharmony_ci	RES_QP_HW
10662306a36Sopenharmony_ci};
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistruct res_qp {
10962306a36Sopenharmony_ci	struct res_common	com;
11062306a36Sopenharmony_ci	struct res_mtt	       *mtt;
11162306a36Sopenharmony_ci	struct res_cq	       *rcq;
11262306a36Sopenharmony_ci	struct res_cq	       *scq;
11362306a36Sopenharmony_ci	struct res_srq	       *srq;
11462306a36Sopenharmony_ci	struct list_head	mcg_list;
11562306a36Sopenharmony_ci	spinlock_t		mcg_spl;
11662306a36Sopenharmony_ci	int			local_qpn;
11762306a36Sopenharmony_ci	atomic_t		ref_count;
11862306a36Sopenharmony_ci	u32			qpc_flags;
11962306a36Sopenharmony_ci	/* saved qp params before VST enforcement in order to restore on VGT */
12062306a36Sopenharmony_ci	u8			sched_queue;
12162306a36Sopenharmony_ci	__be32			param3;
12262306a36Sopenharmony_ci	u8			vlan_control;
12362306a36Sopenharmony_ci	u8			fvl_rx;
12462306a36Sopenharmony_ci	u8			pri_path_fl;
12562306a36Sopenharmony_ci	u8			vlan_index;
12662306a36Sopenharmony_ci	u8			feup;
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cienum res_mtt_states {
13062306a36Sopenharmony_ci	RES_MTT_BUSY = RES_ANY_BUSY,
13162306a36Sopenharmony_ci	RES_MTT_ALLOCATED,
13262306a36Sopenharmony_ci};
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic inline const char *mtt_states_str(enum res_mtt_states state)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	switch (state) {
13762306a36Sopenharmony_ci	case RES_MTT_BUSY: return "RES_MTT_BUSY";
13862306a36Sopenharmony_ci	case RES_MTT_ALLOCATED: return "RES_MTT_ALLOCATED";
13962306a36Sopenharmony_ci	default: return "Unknown";
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistruct res_mtt {
14462306a36Sopenharmony_ci	struct res_common	com;
14562306a36Sopenharmony_ci	int			order;
14662306a36Sopenharmony_ci	atomic_t		ref_count;
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cienum res_mpt_states {
15062306a36Sopenharmony_ci	RES_MPT_BUSY = RES_ANY_BUSY,
15162306a36Sopenharmony_ci	RES_MPT_RESERVED,
15262306a36Sopenharmony_ci	RES_MPT_MAPPED,
15362306a36Sopenharmony_ci	RES_MPT_HW,
15462306a36Sopenharmony_ci};
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistruct res_mpt {
15762306a36Sopenharmony_ci	struct res_common	com;
15862306a36Sopenharmony_ci	struct res_mtt	       *mtt;
15962306a36Sopenharmony_ci	int			key;
16062306a36Sopenharmony_ci};
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cienum res_eq_states {
16362306a36Sopenharmony_ci	RES_EQ_BUSY = RES_ANY_BUSY,
16462306a36Sopenharmony_ci	RES_EQ_RESERVED,
16562306a36Sopenharmony_ci	RES_EQ_HW,
16662306a36Sopenharmony_ci};
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistruct res_eq {
16962306a36Sopenharmony_ci	struct res_common	com;
17062306a36Sopenharmony_ci	struct res_mtt	       *mtt;
17162306a36Sopenharmony_ci};
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cienum res_cq_states {
17462306a36Sopenharmony_ci	RES_CQ_BUSY = RES_ANY_BUSY,
17562306a36Sopenharmony_ci	RES_CQ_ALLOCATED,
17662306a36Sopenharmony_ci	RES_CQ_HW,
17762306a36Sopenharmony_ci};
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistruct res_cq {
18062306a36Sopenharmony_ci	struct res_common	com;
18162306a36Sopenharmony_ci	struct res_mtt	       *mtt;
18262306a36Sopenharmony_ci	atomic_t		ref_count;
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cienum res_srq_states {
18662306a36Sopenharmony_ci	RES_SRQ_BUSY = RES_ANY_BUSY,
18762306a36Sopenharmony_ci	RES_SRQ_ALLOCATED,
18862306a36Sopenharmony_ci	RES_SRQ_HW,
18962306a36Sopenharmony_ci};
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistruct res_srq {
19262306a36Sopenharmony_ci	struct res_common	com;
19362306a36Sopenharmony_ci	struct res_mtt	       *mtt;
19462306a36Sopenharmony_ci	struct res_cq	       *cq;
19562306a36Sopenharmony_ci	atomic_t		ref_count;
19662306a36Sopenharmony_ci};
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cienum res_counter_states {
19962306a36Sopenharmony_ci	RES_COUNTER_BUSY = RES_ANY_BUSY,
20062306a36Sopenharmony_ci	RES_COUNTER_ALLOCATED,
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistruct res_counter {
20462306a36Sopenharmony_ci	struct res_common	com;
20562306a36Sopenharmony_ci	int			port;
20662306a36Sopenharmony_ci};
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cienum res_xrcdn_states {
20962306a36Sopenharmony_ci	RES_XRCD_BUSY = RES_ANY_BUSY,
21062306a36Sopenharmony_ci	RES_XRCD_ALLOCATED,
21162306a36Sopenharmony_ci};
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistruct res_xrcdn {
21462306a36Sopenharmony_ci	struct res_common	com;
21562306a36Sopenharmony_ci	int			port;
21662306a36Sopenharmony_ci};
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cienum res_fs_rule_states {
21962306a36Sopenharmony_ci	RES_FS_RULE_BUSY = RES_ANY_BUSY,
22062306a36Sopenharmony_ci	RES_FS_RULE_ALLOCATED,
22162306a36Sopenharmony_ci};
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistruct res_fs_rule {
22462306a36Sopenharmony_ci	struct res_common	com;
22562306a36Sopenharmony_ci	int			qpn;
22662306a36Sopenharmony_ci	/* VF DMFS mbox with port flipped */
22762306a36Sopenharmony_ci	void			*mirr_mbox;
22862306a36Sopenharmony_ci	/* > 0 --> apply mirror when getting into HA mode      */
22962306a36Sopenharmony_ci	/* = 0 --> un-apply mirror when getting out of HA mode */
23062306a36Sopenharmony_ci	u32			mirr_mbox_size;
23162306a36Sopenharmony_ci	struct list_head	mirr_list;
23262306a36Sopenharmony_ci	u64			mirr_rule_id;
23362306a36Sopenharmony_ci};
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic void *res_tracker_lookup(struct rb_root *root, u64 res_id)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	struct rb_node *node = root->rb_node;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	while (node) {
24062306a36Sopenharmony_ci		struct res_common *res = rb_entry(node, struct res_common,
24162306a36Sopenharmony_ci						  node);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		if (res_id < res->res_id)
24462306a36Sopenharmony_ci			node = node->rb_left;
24562306a36Sopenharmony_ci		else if (res_id > res->res_id)
24662306a36Sopenharmony_ci			node = node->rb_right;
24762306a36Sopenharmony_ci		else
24862306a36Sopenharmony_ci			return res;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci	return NULL;
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic int res_tracker_insert(struct rb_root *root, struct res_common *res)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	struct rb_node **new = &(root->rb_node), *parent = NULL;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/* Figure out where to put new node */
25862306a36Sopenharmony_ci	while (*new) {
25962306a36Sopenharmony_ci		struct res_common *this = rb_entry(*new, struct res_common,
26062306a36Sopenharmony_ci						   node);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		parent = *new;
26362306a36Sopenharmony_ci		if (res->res_id < this->res_id)
26462306a36Sopenharmony_ci			new = &((*new)->rb_left);
26562306a36Sopenharmony_ci		else if (res->res_id > this->res_id)
26662306a36Sopenharmony_ci			new = &((*new)->rb_right);
26762306a36Sopenharmony_ci		else
26862306a36Sopenharmony_ci			return -EEXIST;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* Add new node and rebalance tree. */
27262306a36Sopenharmony_ci	rb_link_node(&res->node, parent, new);
27362306a36Sopenharmony_ci	rb_insert_color(&res->node, root);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	return 0;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cienum qp_transition {
27962306a36Sopenharmony_ci	QP_TRANS_INIT2RTR,
28062306a36Sopenharmony_ci	QP_TRANS_RTR2RTS,
28162306a36Sopenharmony_ci	QP_TRANS_RTS2RTS,
28262306a36Sopenharmony_ci	QP_TRANS_SQERR2RTS,
28362306a36Sopenharmony_ci	QP_TRANS_SQD2SQD,
28462306a36Sopenharmony_ci	QP_TRANS_SQD2RTS
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci/* For Debug uses */
28862306a36Sopenharmony_cistatic const char *resource_str(enum mlx4_resource rt)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	switch (rt) {
29162306a36Sopenharmony_ci	case RES_QP: return "RES_QP";
29262306a36Sopenharmony_ci	case RES_CQ: return "RES_CQ";
29362306a36Sopenharmony_ci	case RES_SRQ: return "RES_SRQ";
29462306a36Sopenharmony_ci	case RES_MPT: return "RES_MPT";
29562306a36Sopenharmony_ci	case RES_MTT: return "RES_MTT";
29662306a36Sopenharmony_ci	case RES_MAC: return  "RES_MAC";
29762306a36Sopenharmony_ci	case RES_VLAN: return  "RES_VLAN";
29862306a36Sopenharmony_ci	case RES_EQ: return "RES_EQ";
29962306a36Sopenharmony_ci	case RES_COUNTER: return "RES_COUNTER";
30062306a36Sopenharmony_ci	case RES_FS_RULE: return "RES_FS_RULE";
30162306a36Sopenharmony_ci	case RES_XRCD: return "RES_XRCD";
30262306a36Sopenharmony_ci	default: return "Unknown resource type !!!";
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic void rem_slave_vlans(struct mlx4_dev *dev, int slave);
30762306a36Sopenharmony_cistatic inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave,
30862306a36Sopenharmony_ci				      enum mlx4_resource res_type, int count,
30962306a36Sopenharmony_ci				      int port)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
31262306a36Sopenharmony_ci	struct resource_allocator *res_alloc =
31362306a36Sopenharmony_ci		&priv->mfunc.master.res_tracker.res_alloc[res_type];
31462306a36Sopenharmony_ci	int err = -EDQUOT;
31562306a36Sopenharmony_ci	int allocated, free, reserved, guaranteed, from_free;
31662306a36Sopenharmony_ci	int from_rsvd;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (slave > dev->persist->num_vfs)
31962306a36Sopenharmony_ci		return -EINVAL;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	spin_lock(&res_alloc->alloc_lock);
32262306a36Sopenharmony_ci	allocated = (port > 0) ?
32362306a36Sopenharmony_ci		res_alloc->allocated[(port - 1) *
32462306a36Sopenharmony_ci		(dev->persist->num_vfs + 1) + slave] :
32562306a36Sopenharmony_ci		res_alloc->allocated[slave];
32662306a36Sopenharmony_ci	free = (port > 0) ? res_alloc->res_port_free[port - 1] :
32762306a36Sopenharmony_ci		res_alloc->res_free;
32862306a36Sopenharmony_ci	reserved = (port > 0) ? res_alloc->res_port_rsvd[port - 1] :
32962306a36Sopenharmony_ci		res_alloc->res_reserved;
33062306a36Sopenharmony_ci	guaranteed = res_alloc->guaranteed[slave];
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (allocated + count > res_alloc->quota[slave]) {
33362306a36Sopenharmony_ci		mlx4_warn(dev, "VF %d port %d res %s: quota exceeded, count %d alloc %d quota %d\n",
33462306a36Sopenharmony_ci			  slave, port, resource_str(res_type), count,
33562306a36Sopenharmony_ci			  allocated, res_alloc->quota[slave]);
33662306a36Sopenharmony_ci		goto out;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (allocated + count <= guaranteed) {
34062306a36Sopenharmony_ci		err = 0;
34162306a36Sopenharmony_ci		from_rsvd = count;
34262306a36Sopenharmony_ci	} else {
34362306a36Sopenharmony_ci		/* portion may need to be obtained from free area */
34462306a36Sopenharmony_ci		if (guaranteed - allocated > 0)
34562306a36Sopenharmony_ci			from_free = count - (guaranteed - allocated);
34662306a36Sopenharmony_ci		else
34762306a36Sopenharmony_ci			from_free = count;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		from_rsvd = count - from_free;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		if (free - from_free >= reserved)
35262306a36Sopenharmony_ci			err = 0;
35362306a36Sopenharmony_ci		else
35462306a36Sopenharmony_ci			mlx4_warn(dev, "VF %d port %d res %s: free pool empty, free %d from_free %d rsvd %d\n",
35562306a36Sopenharmony_ci				  slave, port, resource_str(res_type), free,
35662306a36Sopenharmony_ci				  from_free, reserved);
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (!err) {
36062306a36Sopenharmony_ci		/* grant the request */
36162306a36Sopenharmony_ci		if (port > 0) {
36262306a36Sopenharmony_ci			res_alloc->allocated[(port - 1) *
36362306a36Sopenharmony_ci			(dev->persist->num_vfs + 1) + slave] += count;
36462306a36Sopenharmony_ci			res_alloc->res_port_free[port - 1] -= count;
36562306a36Sopenharmony_ci			res_alloc->res_port_rsvd[port - 1] -= from_rsvd;
36662306a36Sopenharmony_ci		} else {
36762306a36Sopenharmony_ci			res_alloc->allocated[slave] += count;
36862306a36Sopenharmony_ci			res_alloc->res_free -= count;
36962306a36Sopenharmony_ci			res_alloc->res_reserved -= from_rsvd;
37062306a36Sopenharmony_ci		}
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ciout:
37462306a36Sopenharmony_ci	spin_unlock(&res_alloc->alloc_lock);
37562306a36Sopenharmony_ci	return err;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic inline void mlx4_release_resource(struct mlx4_dev *dev, int slave,
37962306a36Sopenharmony_ci				    enum mlx4_resource res_type, int count,
38062306a36Sopenharmony_ci				    int port)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
38362306a36Sopenharmony_ci	struct resource_allocator *res_alloc =
38462306a36Sopenharmony_ci		&priv->mfunc.master.res_tracker.res_alloc[res_type];
38562306a36Sopenharmony_ci	int allocated, guaranteed, from_rsvd;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (slave > dev->persist->num_vfs)
38862306a36Sopenharmony_ci		return;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	spin_lock(&res_alloc->alloc_lock);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	allocated = (port > 0) ?
39362306a36Sopenharmony_ci		res_alloc->allocated[(port - 1) *
39462306a36Sopenharmony_ci		(dev->persist->num_vfs + 1) + slave] :
39562306a36Sopenharmony_ci		res_alloc->allocated[slave];
39662306a36Sopenharmony_ci	guaranteed = res_alloc->guaranteed[slave];
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (allocated - count >= guaranteed) {
39962306a36Sopenharmony_ci		from_rsvd = 0;
40062306a36Sopenharmony_ci	} else {
40162306a36Sopenharmony_ci		/* portion may need to be returned to reserved area */
40262306a36Sopenharmony_ci		if (allocated - guaranteed > 0)
40362306a36Sopenharmony_ci			from_rsvd = count - (allocated - guaranteed);
40462306a36Sopenharmony_ci		else
40562306a36Sopenharmony_ci			from_rsvd = count;
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (port > 0) {
40962306a36Sopenharmony_ci		res_alloc->allocated[(port - 1) *
41062306a36Sopenharmony_ci		(dev->persist->num_vfs + 1) + slave] -= count;
41162306a36Sopenharmony_ci		res_alloc->res_port_free[port - 1] += count;
41262306a36Sopenharmony_ci		res_alloc->res_port_rsvd[port - 1] += from_rsvd;
41362306a36Sopenharmony_ci	} else {
41462306a36Sopenharmony_ci		res_alloc->allocated[slave] -= count;
41562306a36Sopenharmony_ci		res_alloc->res_free += count;
41662306a36Sopenharmony_ci		res_alloc->res_reserved += from_rsvd;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	spin_unlock(&res_alloc->alloc_lock);
42062306a36Sopenharmony_ci	return;
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic inline void initialize_res_quotas(struct mlx4_dev *dev,
42462306a36Sopenharmony_ci					 struct resource_allocator *res_alloc,
42562306a36Sopenharmony_ci					 enum mlx4_resource res_type,
42662306a36Sopenharmony_ci					 int vf, int num_instances)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	res_alloc->guaranteed[vf] = num_instances /
42962306a36Sopenharmony_ci				    (2 * (dev->persist->num_vfs + 1));
43062306a36Sopenharmony_ci	res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf];
43162306a36Sopenharmony_ci	if (vf == mlx4_master_func_num(dev)) {
43262306a36Sopenharmony_ci		res_alloc->res_free = num_instances;
43362306a36Sopenharmony_ci		if (res_type == RES_MTT) {
43462306a36Sopenharmony_ci			/* reserved mtts will be taken out of the PF allocation */
43562306a36Sopenharmony_ci			res_alloc->res_free += dev->caps.reserved_mtts;
43662306a36Sopenharmony_ci			res_alloc->guaranteed[vf] += dev->caps.reserved_mtts;
43762306a36Sopenharmony_ci			res_alloc->quota[vf] += dev->caps.reserved_mtts;
43862306a36Sopenharmony_ci		}
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_civoid mlx4_init_quotas(struct mlx4_dev *dev)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
44562306a36Sopenharmony_ci	int pf;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	/* quotas for VFs are initialized in mlx4_slave_cap */
44862306a36Sopenharmony_ci	if (mlx4_is_slave(dev))
44962306a36Sopenharmony_ci		return;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (!mlx4_is_mfunc(dev)) {
45262306a36Sopenharmony_ci		dev->quotas.qp = dev->caps.num_qps - dev->caps.reserved_qps -
45362306a36Sopenharmony_ci			mlx4_num_reserved_sqps(dev);
45462306a36Sopenharmony_ci		dev->quotas.cq = dev->caps.num_cqs - dev->caps.reserved_cqs;
45562306a36Sopenharmony_ci		dev->quotas.srq = dev->caps.num_srqs - dev->caps.reserved_srqs;
45662306a36Sopenharmony_ci		dev->quotas.mtt = dev->caps.num_mtts - dev->caps.reserved_mtts;
45762306a36Sopenharmony_ci		dev->quotas.mpt = dev->caps.num_mpts - dev->caps.reserved_mrws;
45862306a36Sopenharmony_ci		return;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	pf = mlx4_master_func_num(dev);
46262306a36Sopenharmony_ci	dev->quotas.qp =
46362306a36Sopenharmony_ci		priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[pf];
46462306a36Sopenharmony_ci	dev->quotas.cq =
46562306a36Sopenharmony_ci		priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[pf];
46662306a36Sopenharmony_ci	dev->quotas.srq =
46762306a36Sopenharmony_ci		priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[pf];
46862306a36Sopenharmony_ci	dev->quotas.mtt =
46962306a36Sopenharmony_ci		priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[pf];
47062306a36Sopenharmony_ci	dev->quotas.mpt =
47162306a36Sopenharmony_ci		priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf];
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic int
47562306a36Sopenharmony_cimlx4_calc_res_counter_guaranteed(struct mlx4_dev *dev,
47662306a36Sopenharmony_ci				 struct resource_allocator *res_alloc,
47762306a36Sopenharmony_ci				 int vf)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	struct mlx4_active_ports actv_ports;
48062306a36Sopenharmony_ci	int ports, counters_guaranteed;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	/* For master, only allocate according to the number of phys ports */
48362306a36Sopenharmony_ci	if (vf == mlx4_master_func_num(dev))
48462306a36Sopenharmony_ci		return MLX4_PF_COUNTERS_PER_PORT * dev->caps.num_ports;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	/* calculate real number of ports for the VF */
48762306a36Sopenharmony_ci	actv_ports = mlx4_get_active_ports(dev, vf);
48862306a36Sopenharmony_ci	ports = bitmap_weight(actv_ports.ports, dev->caps.num_ports);
48962306a36Sopenharmony_ci	counters_guaranteed = ports * MLX4_VF_COUNTERS_PER_PORT;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	/* If we do not have enough counters for this VF, do not
49262306a36Sopenharmony_ci	 * allocate any for it. '-1' to reduce the sink counter.
49362306a36Sopenharmony_ci	 */
49462306a36Sopenharmony_ci	if ((res_alloc->res_reserved + counters_guaranteed) >
49562306a36Sopenharmony_ci	    (dev->caps.max_counters - 1))
49662306a36Sopenharmony_ci		return 0;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return counters_guaranteed;
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ciint mlx4_init_resource_tracker(struct mlx4_dev *dev)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
50462306a36Sopenharmony_ci	int i, j;
50562306a36Sopenharmony_ci	int t;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	priv->mfunc.master.res_tracker.slave_list =
50862306a36Sopenharmony_ci		kcalloc(dev->num_slaves, sizeof(struct slave_list),
50962306a36Sopenharmony_ci			GFP_KERNEL);
51062306a36Sopenharmony_ci	if (!priv->mfunc.master.res_tracker.slave_list)
51162306a36Sopenharmony_ci		return -ENOMEM;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	for (i = 0 ; i < dev->num_slaves; i++) {
51462306a36Sopenharmony_ci		for (t = 0; t < MLX4_NUM_OF_RESOURCE_TYPE; ++t)
51562306a36Sopenharmony_ci			INIT_LIST_HEAD(&priv->mfunc.master.res_tracker.
51662306a36Sopenharmony_ci				       slave_list[i].res_list[t]);
51762306a36Sopenharmony_ci		mutex_init(&priv->mfunc.master.res_tracker.slave_list[i].mutex);
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	mlx4_dbg(dev, "Started init_resource_tracker: %ld slaves\n",
52162306a36Sopenharmony_ci		 dev->num_slaves);
52262306a36Sopenharmony_ci	for (i = 0 ; i < MLX4_NUM_OF_RESOURCE_TYPE; i++)
52362306a36Sopenharmony_ci		priv->mfunc.master.res_tracker.res_tree[i] = RB_ROOT;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {
52662306a36Sopenharmony_ci		struct resource_allocator *res_alloc =
52762306a36Sopenharmony_ci			&priv->mfunc.master.res_tracker.res_alloc[i];
52862306a36Sopenharmony_ci		res_alloc->quota = kmalloc_array(dev->persist->num_vfs + 1,
52962306a36Sopenharmony_ci						 sizeof(int),
53062306a36Sopenharmony_ci						 GFP_KERNEL);
53162306a36Sopenharmony_ci		res_alloc->guaranteed = kmalloc_array(dev->persist->num_vfs + 1,
53262306a36Sopenharmony_ci						      sizeof(int),
53362306a36Sopenharmony_ci						      GFP_KERNEL);
53462306a36Sopenharmony_ci		if (i == RES_MAC || i == RES_VLAN)
53562306a36Sopenharmony_ci			res_alloc->allocated =
53662306a36Sopenharmony_ci				kcalloc(MLX4_MAX_PORTS *
53762306a36Sopenharmony_ci						(dev->persist->num_vfs + 1),
53862306a36Sopenharmony_ci					sizeof(int), GFP_KERNEL);
53962306a36Sopenharmony_ci		else
54062306a36Sopenharmony_ci			res_alloc->allocated =
54162306a36Sopenharmony_ci				kcalloc(dev->persist->num_vfs + 1,
54262306a36Sopenharmony_ci					sizeof(int), GFP_KERNEL);
54362306a36Sopenharmony_ci		/* Reduce the sink counter */
54462306a36Sopenharmony_ci		if (i == RES_COUNTER)
54562306a36Sopenharmony_ci			res_alloc->res_free = dev->caps.max_counters - 1;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		if (!res_alloc->quota || !res_alloc->guaranteed ||
54862306a36Sopenharmony_ci		    !res_alloc->allocated)
54962306a36Sopenharmony_ci			goto no_mem_err;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci		spin_lock_init(&res_alloc->alloc_lock);
55262306a36Sopenharmony_ci		for (t = 0; t < dev->persist->num_vfs + 1; t++) {
55362306a36Sopenharmony_ci			struct mlx4_active_ports actv_ports =
55462306a36Sopenharmony_ci				mlx4_get_active_ports(dev, t);
55562306a36Sopenharmony_ci			switch (i) {
55662306a36Sopenharmony_ci			case RES_QP:
55762306a36Sopenharmony_ci				initialize_res_quotas(dev, res_alloc, RES_QP,
55862306a36Sopenharmony_ci						      t, dev->caps.num_qps -
55962306a36Sopenharmony_ci						      dev->caps.reserved_qps -
56062306a36Sopenharmony_ci						      mlx4_num_reserved_sqps(dev));
56162306a36Sopenharmony_ci				break;
56262306a36Sopenharmony_ci			case RES_CQ:
56362306a36Sopenharmony_ci				initialize_res_quotas(dev, res_alloc, RES_CQ,
56462306a36Sopenharmony_ci						      t, dev->caps.num_cqs -
56562306a36Sopenharmony_ci						      dev->caps.reserved_cqs);
56662306a36Sopenharmony_ci				break;
56762306a36Sopenharmony_ci			case RES_SRQ:
56862306a36Sopenharmony_ci				initialize_res_quotas(dev, res_alloc, RES_SRQ,
56962306a36Sopenharmony_ci						      t, dev->caps.num_srqs -
57062306a36Sopenharmony_ci						      dev->caps.reserved_srqs);
57162306a36Sopenharmony_ci				break;
57262306a36Sopenharmony_ci			case RES_MPT:
57362306a36Sopenharmony_ci				initialize_res_quotas(dev, res_alloc, RES_MPT,
57462306a36Sopenharmony_ci						      t, dev->caps.num_mpts -
57562306a36Sopenharmony_ci						      dev->caps.reserved_mrws);
57662306a36Sopenharmony_ci				break;
57762306a36Sopenharmony_ci			case RES_MTT:
57862306a36Sopenharmony_ci				initialize_res_quotas(dev, res_alloc, RES_MTT,
57962306a36Sopenharmony_ci						      t, dev->caps.num_mtts -
58062306a36Sopenharmony_ci						      dev->caps.reserved_mtts);
58162306a36Sopenharmony_ci				break;
58262306a36Sopenharmony_ci			case RES_MAC:
58362306a36Sopenharmony_ci				if (t == mlx4_master_func_num(dev)) {
58462306a36Sopenharmony_ci					int max_vfs_pport = 0;
58562306a36Sopenharmony_ci					/* Calculate the max vfs per port for */
58662306a36Sopenharmony_ci					/* both ports.			      */
58762306a36Sopenharmony_ci					for (j = 0; j < dev->caps.num_ports;
58862306a36Sopenharmony_ci					     j++) {
58962306a36Sopenharmony_ci						struct mlx4_slaves_pport slaves_pport =
59062306a36Sopenharmony_ci							mlx4_phys_to_slaves_pport(dev, j + 1);
59162306a36Sopenharmony_ci						unsigned current_slaves =
59262306a36Sopenharmony_ci							bitmap_weight(slaves_pport.slaves,
59362306a36Sopenharmony_ci								      dev->caps.num_ports) - 1;
59462306a36Sopenharmony_ci						if (max_vfs_pport < current_slaves)
59562306a36Sopenharmony_ci							max_vfs_pport =
59662306a36Sopenharmony_ci								current_slaves;
59762306a36Sopenharmony_ci					}
59862306a36Sopenharmony_ci					res_alloc->quota[t] =
59962306a36Sopenharmony_ci						MLX4_MAX_MAC_NUM -
60062306a36Sopenharmony_ci						2 * max_vfs_pport;
60162306a36Sopenharmony_ci					res_alloc->guaranteed[t] = 2;
60262306a36Sopenharmony_ci					for (j = 0; j < MLX4_MAX_PORTS; j++)
60362306a36Sopenharmony_ci						res_alloc->res_port_free[j] =
60462306a36Sopenharmony_ci							MLX4_MAX_MAC_NUM;
60562306a36Sopenharmony_ci				} else {
60662306a36Sopenharmony_ci					res_alloc->quota[t] = MLX4_MAX_MAC_NUM;
60762306a36Sopenharmony_ci					res_alloc->guaranteed[t] = 2;
60862306a36Sopenharmony_ci				}
60962306a36Sopenharmony_ci				break;
61062306a36Sopenharmony_ci			case RES_VLAN:
61162306a36Sopenharmony_ci				if (t == mlx4_master_func_num(dev)) {
61262306a36Sopenharmony_ci					res_alloc->quota[t] = MLX4_MAX_VLAN_NUM;
61362306a36Sopenharmony_ci					res_alloc->guaranteed[t] = MLX4_MAX_VLAN_NUM / 2;
61462306a36Sopenharmony_ci					for (j = 0; j < MLX4_MAX_PORTS; j++)
61562306a36Sopenharmony_ci						res_alloc->res_port_free[j] =
61662306a36Sopenharmony_ci							res_alloc->quota[t];
61762306a36Sopenharmony_ci				} else {
61862306a36Sopenharmony_ci					res_alloc->quota[t] = MLX4_MAX_VLAN_NUM / 2;
61962306a36Sopenharmony_ci					res_alloc->guaranteed[t] = 0;
62062306a36Sopenharmony_ci				}
62162306a36Sopenharmony_ci				break;
62262306a36Sopenharmony_ci			case RES_COUNTER:
62362306a36Sopenharmony_ci				res_alloc->quota[t] = dev->caps.max_counters;
62462306a36Sopenharmony_ci				res_alloc->guaranteed[t] =
62562306a36Sopenharmony_ci					mlx4_calc_res_counter_guaranteed(dev, res_alloc, t);
62662306a36Sopenharmony_ci				break;
62762306a36Sopenharmony_ci			default:
62862306a36Sopenharmony_ci				break;
62962306a36Sopenharmony_ci			}
63062306a36Sopenharmony_ci			if (i == RES_MAC || i == RES_VLAN) {
63162306a36Sopenharmony_ci				for (j = 0; j < dev->caps.num_ports; j++)
63262306a36Sopenharmony_ci					if (test_bit(j, actv_ports.ports))
63362306a36Sopenharmony_ci						res_alloc->res_port_rsvd[j] +=
63462306a36Sopenharmony_ci							res_alloc->guaranteed[t];
63562306a36Sopenharmony_ci			} else {
63662306a36Sopenharmony_ci				res_alloc->res_reserved += res_alloc->guaranteed[t];
63762306a36Sopenharmony_ci			}
63862306a36Sopenharmony_ci		}
63962306a36Sopenharmony_ci	}
64062306a36Sopenharmony_ci	spin_lock_init(&priv->mfunc.master.res_tracker.lock);
64162306a36Sopenharmony_ci	return 0;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_cino_mem_err:
64462306a36Sopenharmony_ci	for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {
64562306a36Sopenharmony_ci		kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated);
64662306a36Sopenharmony_ci		priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL;
64762306a36Sopenharmony_ci		kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed);
64862306a36Sopenharmony_ci		priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL;
64962306a36Sopenharmony_ci		kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota);
65062306a36Sopenharmony_ci		priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL;
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci	return -ENOMEM;
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_civoid mlx4_free_resource_tracker(struct mlx4_dev *dev,
65662306a36Sopenharmony_ci				enum mlx4_res_tracker_free_type type)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
65962306a36Sopenharmony_ci	int i;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	if (priv->mfunc.master.res_tracker.slave_list) {
66262306a36Sopenharmony_ci		if (type != RES_TR_FREE_STRUCTS_ONLY) {
66362306a36Sopenharmony_ci			for (i = 0; i < dev->num_slaves; i++) {
66462306a36Sopenharmony_ci				if (type == RES_TR_FREE_ALL ||
66562306a36Sopenharmony_ci				    dev->caps.function != i)
66662306a36Sopenharmony_ci					mlx4_delete_all_resources_for_slave(dev, i);
66762306a36Sopenharmony_ci			}
66862306a36Sopenharmony_ci			/* free master's vlans */
66962306a36Sopenharmony_ci			i = dev->caps.function;
67062306a36Sopenharmony_ci			mlx4_reset_roce_gids(dev, i);
67162306a36Sopenharmony_ci			mutex_lock(&priv->mfunc.master.res_tracker.slave_list[i].mutex);
67262306a36Sopenharmony_ci			rem_slave_vlans(dev, i);
67362306a36Sopenharmony_ci			mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[i].mutex);
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		if (type != RES_TR_FREE_SLAVES_ONLY) {
67762306a36Sopenharmony_ci			for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {
67862306a36Sopenharmony_ci				kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated);
67962306a36Sopenharmony_ci				priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL;
68062306a36Sopenharmony_ci				kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed);
68162306a36Sopenharmony_ci				priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL;
68262306a36Sopenharmony_ci				kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota);
68362306a36Sopenharmony_ci				priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL;
68462306a36Sopenharmony_ci			}
68562306a36Sopenharmony_ci			kfree(priv->mfunc.master.res_tracker.slave_list);
68662306a36Sopenharmony_ci			priv->mfunc.master.res_tracker.slave_list = NULL;
68762306a36Sopenharmony_ci		}
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cistatic void update_pkey_index(struct mlx4_dev *dev, int slave,
69262306a36Sopenharmony_ci			      struct mlx4_cmd_mailbox *inbox)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	u8 sched = *(u8 *)(inbox->buf + 64);
69562306a36Sopenharmony_ci	u8 orig_index = *(u8 *)(inbox->buf + 35);
69662306a36Sopenharmony_ci	u8 new_index;
69762306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
69862306a36Sopenharmony_ci	int port;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	port = (sched >> 6 & 1) + 1;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	new_index = priv->virt2phys_pkey[slave][port - 1][orig_index];
70362306a36Sopenharmony_ci	*(u8 *)(inbox->buf + 35) = new_index;
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,
70762306a36Sopenharmony_ci		       u8 slave)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	struct mlx4_qp_context	*qp_ctx = inbox->buf + 8;
71062306a36Sopenharmony_ci	enum mlx4_qp_optpar	optpar = be32_to_cpu(*(__be32 *) inbox->buf);
71162306a36Sopenharmony_ci	u32			ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;
71262306a36Sopenharmony_ci	int port;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	if (MLX4_QP_ST_UD == ts) {
71562306a36Sopenharmony_ci		port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
71662306a36Sopenharmony_ci		if (mlx4_is_eth(dev, port))
71762306a36Sopenharmony_ci			qp_ctx->pri_path.mgid_index =
71862306a36Sopenharmony_ci				mlx4_get_base_gid_ix(dev, slave, port) | 0x80;
71962306a36Sopenharmony_ci		else
72062306a36Sopenharmony_ci			qp_ctx->pri_path.mgid_index = slave | 0x80;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	} else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_XRC == ts || MLX4_QP_ST_UC == ts) {
72362306a36Sopenharmony_ci		if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {
72462306a36Sopenharmony_ci			port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
72562306a36Sopenharmony_ci			if (mlx4_is_eth(dev, port)) {
72662306a36Sopenharmony_ci				qp_ctx->pri_path.mgid_index +=
72762306a36Sopenharmony_ci					mlx4_get_base_gid_ix(dev, slave, port);
72862306a36Sopenharmony_ci				qp_ctx->pri_path.mgid_index &= 0x7f;
72962306a36Sopenharmony_ci			} else {
73062306a36Sopenharmony_ci				qp_ctx->pri_path.mgid_index = slave & 0x7F;
73162306a36Sopenharmony_ci			}
73262306a36Sopenharmony_ci		}
73362306a36Sopenharmony_ci		if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
73462306a36Sopenharmony_ci			port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1;
73562306a36Sopenharmony_ci			if (mlx4_is_eth(dev, port)) {
73662306a36Sopenharmony_ci				qp_ctx->alt_path.mgid_index +=
73762306a36Sopenharmony_ci					mlx4_get_base_gid_ix(dev, slave, port);
73862306a36Sopenharmony_ci				qp_ctx->alt_path.mgid_index &= 0x7f;
73962306a36Sopenharmony_ci			} else {
74062306a36Sopenharmony_ci				qp_ctx->alt_path.mgid_index = slave & 0x7F;
74162306a36Sopenharmony_ci			}
74262306a36Sopenharmony_ci		}
74362306a36Sopenharmony_ci	}
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc,
74762306a36Sopenharmony_ci			  u8 slave, int port);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_cistatic int update_vport_qp_param(struct mlx4_dev *dev,
75062306a36Sopenharmony_ci				 struct mlx4_cmd_mailbox *inbox,
75162306a36Sopenharmony_ci				 u8 slave, u32 qpn)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	struct mlx4_qp_context	*qpc = inbox->buf + 8;
75462306a36Sopenharmony_ci	struct mlx4_vport_oper_state *vp_oper;
75562306a36Sopenharmony_ci	struct mlx4_priv *priv;
75662306a36Sopenharmony_ci	u32 qp_type;
75762306a36Sopenharmony_ci	int port, err = 0;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1;
76062306a36Sopenharmony_ci	priv = mlx4_priv(dev);
76162306a36Sopenharmony_ci	vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
76262306a36Sopenharmony_ci	qp_type	= (be32_to_cpu(qpc->flags) >> 16) & 0xff;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	err = handle_counter(dev, qpc, slave, port);
76562306a36Sopenharmony_ci	if (err)
76662306a36Sopenharmony_ci		goto out;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	if (MLX4_VGT != vp_oper->state.default_vlan) {
76962306a36Sopenharmony_ci		/* the reserved QPs (special, proxy, tunnel)
77062306a36Sopenharmony_ci		 * do not operate over vlans
77162306a36Sopenharmony_ci		 */
77262306a36Sopenharmony_ci		if (mlx4_is_qp_reserved(dev, qpn))
77362306a36Sopenharmony_ci			return 0;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci		/* force strip vlan by clear vsd, MLX QP refers to Raw Ethernet */
77662306a36Sopenharmony_ci		if (qp_type == MLX4_QP_ST_UD ||
77762306a36Sopenharmony_ci		    (qp_type == MLX4_QP_ST_MLX && mlx4_is_eth(dev, port))) {
77862306a36Sopenharmony_ci			if (dev->caps.bmme_flags & MLX4_BMME_FLAG_VSD_INIT2RTR) {
77962306a36Sopenharmony_ci				*(__be32 *)inbox->buf =
78062306a36Sopenharmony_ci					cpu_to_be32(be32_to_cpu(*(__be32 *)inbox->buf) |
78162306a36Sopenharmony_ci					MLX4_QP_OPTPAR_VLAN_STRIPPING);
78262306a36Sopenharmony_ci				qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN);
78362306a36Sopenharmony_ci			} else {
78462306a36Sopenharmony_ci				struct mlx4_update_qp_params params = {.flags = 0};
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci				err = mlx4_update_qp(dev, qpn, MLX4_UPDATE_QP_VSD, &params);
78762306a36Sopenharmony_ci				if (err)
78862306a36Sopenharmony_ci					goto out;
78962306a36Sopenharmony_ci			}
79062306a36Sopenharmony_ci		}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci		/* preserve IF_COUNTER flag */
79362306a36Sopenharmony_ci		qpc->pri_path.vlan_control &=
79462306a36Sopenharmony_ci			MLX4_CTRL_ETH_SRC_CHECK_IF_COUNTER;
79562306a36Sopenharmony_ci		if (vp_oper->state.link_state == IFLA_VF_LINK_STATE_DISABLE &&
79662306a36Sopenharmony_ci		    dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) {
79762306a36Sopenharmony_ci			qpc->pri_path.vlan_control |=
79862306a36Sopenharmony_ci				MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
79962306a36Sopenharmony_ci				MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
80062306a36Sopenharmony_ci				MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED |
80162306a36Sopenharmony_ci				MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
80262306a36Sopenharmony_ci				MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED |
80362306a36Sopenharmony_ci				MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
80462306a36Sopenharmony_ci		} else if (0 != vp_oper->state.default_vlan) {
80562306a36Sopenharmony_ci			if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD)) {
80662306a36Sopenharmony_ci				/* vst QinQ should block untagged on TX,
80762306a36Sopenharmony_ci				 * but cvlan is in payload and phv is set so
80862306a36Sopenharmony_ci				 * hw see it as untagged. Block tagged instead.
80962306a36Sopenharmony_ci				 */
81062306a36Sopenharmony_ci				qpc->pri_path.vlan_control |=
81162306a36Sopenharmony_ci					MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
81262306a36Sopenharmony_ci					MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
81362306a36Sopenharmony_ci					MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
81462306a36Sopenharmony_ci					MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
81562306a36Sopenharmony_ci			} else { /* vst 802.1Q */
81662306a36Sopenharmony_ci				qpc->pri_path.vlan_control |=
81762306a36Sopenharmony_ci					MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
81862306a36Sopenharmony_ci					MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
81962306a36Sopenharmony_ci					MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
82062306a36Sopenharmony_ci			}
82162306a36Sopenharmony_ci		} else { /* priority tagged */
82262306a36Sopenharmony_ci			qpc->pri_path.vlan_control |=
82362306a36Sopenharmony_ci				MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
82462306a36Sopenharmony_ci				MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
82562306a36Sopenharmony_ci		}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci		qpc->pri_path.fvl_rx |= MLX4_FVL_RX_FORCE_ETH_VLAN;
82862306a36Sopenharmony_ci		qpc->pri_path.vlan_index = vp_oper->vlan_idx;
82962306a36Sopenharmony_ci		qpc->pri_path.fl |= MLX4_FL_ETH_HIDE_CQE_VLAN;
83062306a36Sopenharmony_ci		if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD))
83162306a36Sopenharmony_ci			qpc->pri_path.fl |= MLX4_FL_SV;
83262306a36Sopenharmony_ci		else
83362306a36Sopenharmony_ci			qpc->pri_path.fl |= MLX4_FL_CV;
83462306a36Sopenharmony_ci		qpc->pri_path.feup |= MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN;
83562306a36Sopenharmony_ci		qpc->pri_path.sched_queue &= 0xC7;
83662306a36Sopenharmony_ci		qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3;
83762306a36Sopenharmony_ci		qpc->qos_vport = vp_oper->state.qos_vport;
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci	if (vp_oper->state.spoofchk) {
84062306a36Sopenharmony_ci		qpc->pri_path.feup |= MLX4_FSM_FORCE_ETH_SRC_MAC;
84162306a36Sopenharmony_ci		qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx;
84262306a36Sopenharmony_ci	}
84362306a36Sopenharmony_ciout:
84462306a36Sopenharmony_ci	return err;
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic int mpt_mask(struct mlx4_dev *dev)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	return dev->caps.num_mpts - 1;
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_cistatic const char *mlx4_resource_type_to_str(enum mlx4_resource t)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	switch (t) {
85562306a36Sopenharmony_ci	case RES_QP:
85662306a36Sopenharmony_ci		return "QP";
85762306a36Sopenharmony_ci	case RES_CQ:
85862306a36Sopenharmony_ci		return "CQ";
85962306a36Sopenharmony_ci	case RES_SRQ:
86062306a36Sopenharmony_ci		return "SRQ";
86162306a36Sopenharmony_ci	case RES_XRCD:
86262306a36Sopenharmony_ci		return "XRCD";
86362306a36Sopenharmony_ci	case RES_MPT:
86462306a36Sopenharmony_ci		return "MPT";
86562306a36Sopenharmony_ci	case RES_MTT:
86662306a36Sopenharmony_ci		return "MTT";
86762306a36Sopenharmony_ci	case RES_MAC:
86862306a36Sopenharmony_ci		return "MAC";
86962306a36Sopenharmony_ci	case RES_VLAN:
87062306a36Sopenharmony_ci		return "VLAN";
87162306a36Sopenharmony_ci	case RES_COUNTER:
87262306a36Sopenharmony_ci		return "COUNTER";
87362306a36Sopenharmony_ci	case RES_FS_RULE:
87462306a36Sopenharmony_ci		return "FS_RULE";
87562306a36Sopenharmony_ci	case RES_EQ:
87662306a36Sopenharmony_ci		return "EQ";
87762306a36Sopenharmony_ci	default:
87862306a36Sopenharmony_ci		return "INVALID RESOURCE";
87962306a36Sopenharmony_ci	}
88062306a36Sopenharmony_ci}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_cistatic void *find_res(struct mlx4_dev *dev, u64 res_id,
88362306a36Sopenharmony_ci		      enum mlx4_resource type)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	return res_tracker_lookup(&priv->mfunc.master.res_tracker.res_tree[type],
88862306a36Sopenharmony_ci				  res_id);
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cistatic int _get_res(struct mlx4_dev *dev, int slave, u64 res_id,
89262306a36Sopenharmony_ci		    enum mlx4_resource type,
89362306a36Sopenharmony_ci		    void *res, const char *func_name)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	struct res_common *r;
89662306a36Sopenharmony_ci	int err = 0;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
89962306a36Sopenharmony_ci	r = find_res(dev, res_id, type);
90062306a36Sopenharmony_ci	if (!r) {
90162306a36Sopenharmony_ci		err = -ENONET;
90262306a36Sopenharmony_ci		goto exit;
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	if (r->state == RES_ANY_BUSY) {
90662306a36Sopenharmony_ci		mlx4_warn(dev,
90762306a36Sopenharmony_ci			  "%s(%d) trying to get resource %llx of type %s, but it's already taken by %s\n",
90862306a36Sopenharmony_ci			  func_name, slave, res_id, mlx4_resource_type_to_str(type),
90962306a36Sopenharmony_ci			  r->func_name);
91062306a36Sopenharmony_ci		err = -EBUSY;
91162306a36Sopenharmony_ci		goto exit;
91262306a36Sopenharmony_ci	}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	if (r->owner != slave) {
91562306a36Sopenharmony_ci		err = -EPERM;
91662306a36Sopenharmony_ci		goto exit;
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	r->from_state = r->state;
92062306a36Sopenharmony_ci	r->state = RES_ANY_BUSY;
92162306a36Sopenharmony_ci	r->func_name = func_name;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (res)
92462306a36Sopenharmony_ci		*((struct res_common **)res) = r;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ciexit:
92762306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
92862306a36Sopenharmony_ci	return err;
92962306a36Sopenharmony_ci}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci#define get_res(dev, slave, res_id, type, res) \
93262306a36Sopenharmony_ci	_get_res((dev), (slave), (res_id), (type), (res), __func__)
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ciint mlx4_get_slave_from_resource_id(struct mlx4_dev *dev,
93562306a36Sopenharmony_ci				    enum mlx4_resource type,
93662306a36Sopenharmony_ci				    u64 res_id, int *slave)
93762306a36Sopenharmony_ci{
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	struct res_common *r;
94062306a36Sopenharmony_ci	int err = -ENOENT;
94162306a36Sopenharmony_ci	int id = res_id;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	if (type == RES_QP)
94462306a36Sopenharmony_ci		id &= 0x7fffff;
94562306a36Sopenharmony_ci	spin_lock(mlx4_tlock(dev));
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	r = find_res(dev, id, type);
94862306a36Sopenharmony_ci	if (r) {
94962306a36Sopenharmony_ci		*slave = r->owner;
95062306a36Sopenharmony_ci		err = 0;
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci	spin_unlock(mlx4_tlock(dev));
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	return err;
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic void put_res(struct mlx4_dev *dev, int slave, u64 res_id,
95862306a36Sopenharmony_ci		    enum mlx4_resource type)
95962306a36Sopenharmony_ci{
96062306a36Sopenharmony_ci	struct res_common *r;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
96362306a36Sopenharmony_ci	r = find_res(dev, res_id, type);
96462306a36Sopenharmony_ci	if (r) {
96562306a36Sopenharmony_ci		r->state = r->from_state;
96662306a36Sopenharmony_ci		r->func_name = "";
96762306a36Sopenharmony_ci	}
96862306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cistatic int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
97262306a36Sopenharmony_ci			     u64 in_param, u64 *out_param, int port);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_cistatic int handle_existing_counter(struct mlx4_dev *dev, u8 slave, int port,
97562306a36Sopenharmony_ci				   int counter_index)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	struct res_common *r;
97862306a36Sopenharmony_ci	struct res_counter *counter;
97962306a36Sopenharmony_ci	int ret = 0;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	if (counter_index == MLX4_SINK_COUNTER_INDEX(dev))
98262306a36Sopenharmony_ci		return ret;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
98562306a36Sopenharmony_ci	r = find_res(dev, counter_index, RES_COUNTER);
98662306a36Sopenharmony_ci	if (!r || r->owner != slave) {
98762306a36Sopenharmony_ci		ret = -EINVAL;
98862306a36Sopenharmony_ci	} else {
98962306a36Sopenharmony_ci		counter = container_of(r, struct res_counter, com);
99062306a36Sopenharmony_ci		if (!counter->port)
99162306a36Sopenharmony_ci			counter->port = port;
99262306a36Sopenharmony_ci	}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
99562306a36Sopenharmony_ci	return ret;
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic int handle_unexisting_counter(struct mlx4_dev *dev,
99962306a36Sopenharmony_ci				     struct mlx4_qp_context *qpc, u8 slave,
100062306a36Sopenharmony_ci				     int port)
100162306a36Sopenharmony_ci{
100262306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
100362306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
100462306a36Sopenharmony_ci	struct res_common *tmp;
100562306a36Sopenharmony_ci	struct res_counter *counter;
100662306a36Sopenharmony_ci	u64 counter_idx = MLX4_SINK_COUNTER_INDEX(dev);
100762306a36Sopenharmony_ci	int err = 0;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
101062306a36Sopenharmony_ci	list_for_each_entry(tmp,
101162306a36Sopenharmony_ci			    &tracker->slave_list[slave].res_list[RES_COUNTER],
101262306a36Sopenharmony_ci			    list) {
101362306a36Sopenharmony_ci		counter = container_of(tmp, struct res_counter, com);
101462306a36Sopenharmony_ci		if (port == counter->port) {
101562306a36Sopenharmony_ci			qpc->pri_path.counter_index  = counter->com.res_id;
101662306a36Sopenharmony_ci			spin_unlock_irq(mlx4_tlock(dev));
101762306a36Sopenharmony_ci			return 0;
101862306a36Sopenharmony_ci		}
101962306a36Sopenharmony_ci	}
102062306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	/* No existing counter, need to allocate a new counter */
102362306a36Sopenharmony_ci	err = counter_alloc_res(dev, slave, RES_OP_RESERVE, 0, 0, &counter_idx,
102462306a36Sopenharmony_ci				port);
102562306a36Sopenharmony_ci	if (err == -ENOENT) {
102662306a36Sopenharmony_ci		err = 0;
102762306a36Sopenharmony_ci	} else if (err && err != -ENOSPC) {
102862306a36Sopenharmony_ci		mlx4_err(dev, "%s: failed to create new counter for slave %d err %d\n",
102962306a36Sopenharmony_ci			 __func__, slave, err);
103062306a36Sopenharmony_ci	} else {
103162306a36Sopenharmony_ci		qpc->pri_path.counter_index = counter_idx;
103262306a36Sopenharmony_ci		mlx4_dbg(dev, "%s: alloc new counter for slave %d index %d\n",
103362306a36Sopenharmony_ci			 __func__, slave, qpc->pri_path.counter_index);
103462306a36Sopenharmony_ci		err = 0;
103562306a36Sopenharmony_ci	}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	return err;
103862306a36Sopenharmony_ci}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_cistatic int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc,
104162306a36Sopenharmony_ci			  u8 slave, int port)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	if (qpc->pri_path.counter_index != MLX4_SINK_COUNTER_INDEX(dev))
104462306a36Sopenharmony_ci		return handle_existing_counter(dev, slave, port,
104562306a36Sopenharmony_ci					       qpc->pri_path.counter_index);
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	return handle_unexisting_counter(dev, qpc, slave, port);
104862306a36Sopenharmony_ci}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_cistatic struct res_common *alloc_qp_tr(int id)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	struct res_qp *ret;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
105562306a36Sopenharmony_ci	if (!ret)
105662306a36Sopenharmony_ci		return NULL;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	ret->com.res_id = id;
105962306a36Sopenharmony_ci	ret->com.state = RES_QP_RESERVED;
106062306a36Sopenharmony_ci	ret->local_qpn = id;
106162306a36Sopenharmony_ci	INIT_LIST_HEAD(&ret->mcg_list);
106262306a36Sopenharmony_ci	spin_lock_init(&ret->mcg_spl);
106362306a36Sopenharmony_ci	atomic_set(&ret->ref_count, 0);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	return &ret->com;
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_cistatic struct res_common *alloc_mtt_tr(int id, int order)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	struct res_mtt *ret;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
107362306a36Sopenharmony_ci	if (!ret)
107462306a36Sopenharmony_ci		return NULL;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	ret->com.res_id = id;
107762306a36Sopenharmony_ci	ret->order = order;
107862306a36Sopenharmony_ci	ret->com.state = RES_MTT_ALLOCATED;
107962306a36Sopenharmony_ci	atomic_set(&ret->ref_count, 0);
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	return &ret->com;
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic struct res_common *alloc_mpt_tr(int id, int key)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	struct res_mpt *ret;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
108962306a36Sopenharmony_ci	if (!ret)
109062306a36Sopenharmony_ci		return NULL;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	ret->com.res_id = id;
109362306a36Sopenharmony_ci	ret->com.state = RES_MPT_RESERVED;
109462306a36Sopenharmony_ci	ret->key = key;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	return &ret->com;
109762306a36Sopenharmony_ci}
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_cistatic struct res_common *alloc_eq_tr(int id)
110062306a36Sopenharmony_ci{
110162306a36Sopenharmony_ci	struct res_eq *ret;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
110462306a36Sopenharmony_ci	if (!ret)
110562306a36Sopenharmony_ci		return NULL;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	ret->com.res_id = id;
110862306a36Sopenharmony_ci	ret->com.state = RES_EQ_RESERVED;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	return &ret->com;
111162306a36Sopenharmony_ci}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_cistatic struct res_common *alloc_cq_tr(int id)
111462306a36Sopenharmony_ci{
111562306a36Sopenharmony_ci	struct res_cq *ret;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
111862306a36Sopenharmony_ci	if (!ret)
111962306a36Sopenharmony_ci		return NULL;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	ret->com.res_id = id;
112262306a36Sopenharmony_ci	ret->com.state = RES_CQ_ALLOCATED;
112362306a36Sopenharmony_ci	atomic_set(&ret->ref_count, 0);
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	return &ret->com;
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_cistatic struct res_common *alloc_srq_tr(int id)
112962306a36Sopenharmony_ci{
113062306a36Sopenharmony_ci	struct res_srq *ret;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
113362306a36Sopenharmony_ci	if (!ret)
113462306a36Sopenharmony_ci		return NULL;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	ret->com.res_id = id;
113762306a36Sopenharmony_ci	ret->com.state = RES_SRQ_ALLOCATED;
113862306a36Sopenharmony_ci	atomic_set(&ret->ref_count, 0);
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	return &ret->com;
114162306a36Sopenharmony_ci}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_cistatic struct res_common *alloc_counter_tr(int id, int port)
114462306a36Sopenharmony_ci{
114562306a36Sopenharmony_ci	struct res_counter *ret;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
114862306a36Sopenharmony_ci	if (!ret)
114962306a36Sopenharmony_ci		return NULL;
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	ret->com.res_id = id;
115262306a36Sopenharmony_ci	ret->com.state = RES_COUNTER_ALLOCATED;
115362306a36Sopenharmony_ci	ret->port = port;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	return &ret->com;
115662306a36Sopenharmony_ci}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_cistatic struct res_common *alloc_xrcdn_tr(int id)
115962306a36Sopenharmony_ci{
116062306a36Sopenharmony_ci	struct res_xrcdn *ret;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
116362306a36Sopenharmony_ci	if (!ret)
116462306a36Sopenharmony_ci		return NULL;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	ret->com.res_id = id;
116762306a36Sopenharmony_ci	ret->com.state = RES_XRCD_ALLOCATED;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	return &ret->com;
117062306a36Sopenharmony_ci}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_cistatic struct res_common *alloc_fs_rule_tr(u64 id, int qpn)
117362306a36Sopenharmony_ci{
117462306a36Sopenharmony_ci	struct res_fs_rule *ret;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
117762306a36Sopenharmony_ci	if (!ret)
117862306a36Sopenharmony_ci		return NULL;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	ret->com.res_id = id;
118162306a36Sopenharmony_ci	ret->com.state = RES_FS_RULE_ALLOCATED;
118262306a36Sopenharmony_ci	ret->qpn = qpn;
118362306a36Sopenharmony_ci	return &ret->com;
118462306a36Sopenharmony_ci}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_cistatic struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave,
118762306a36Sopenharmony_ci				   int extra)
118862306a36Sopenharmony_ci{
118962306a36Sopenharmony_ci	struct res_common *ret;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	switch (type) {
119262306a36Sopenharmony_ci	case RES_QP:
119362306a36Sopenharmony_ci		ret = alloc_qp_tr(id);
119462306a36Sopenharmony_ci		break;
119562306a36Sopenharmony_ci	case RES_MPT:
119662306a36Sopenharmony_ci		ret = alloc_mpt_tr(id, extra);
119762306a36Sopenharmony_ci		break;
119862306a36Sopenharmony_ci	case RES_MTT:
119962306a36Sopenharmony_ci		ret = alloc_mtt_tr(id, extra);
120062306a36Sopenharmony_ci		break;
120162306a36Sopenharmony_ci	case RES_EQ:
120262306a36Sopenharmony_ci		ret = alloc_eq_tr(id);
120362306a36Sopenharmony_ci		break;
120462306a36Sopenharmony_ci	case RES_CQ:
120562306a36Sopenharmony_ci		ret = alloc_cq_tr(id);
120662306a36Sopenharmony_ci		break;
120762306a36Sopenharmony_ci	case RES_SRQ:
120862306a36Sopenharmony_ci		ret = alloc_srq_tr(id);
120962306a36Sopenharmony_ci		break;
121062306a36Sopenharmony_ci	case RES_MAC:
121162306a36Sopenharmony_ci		pr_err("implementation missing\n");
121262306a36Sopenharmony_ci		return NULL;
121362306a36Sopenharmony_ci	case RES_COUNTER:
121462306a36Sopenharmony_ci		ret = alloc_counter_tr(id, extra);
121562306a36Sopenharmony_ci		break;
121662306a36Sopenharmony_ci	case RES_XRCD:
121762306a36Sopenharmony_ci		ret = alloc_xrcdn_tr(id);
121862306a36Sopenharmony_ci		break;
121962306a36Sopenharmony_ci	case RES_FS_RULE:
122062306a36Sopenharmony_ci		ret = alloc_fs_rule_tr(id, extra);
122162306a36Sopenharmony_ci		break;
122262306a36Sopenharmony_ci	default:
122362306a36Sopenharmony_ci		return NULL;
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci	if (ret)
122662306a36Sopenharmony_ci		ret->owner = slave;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	return ret;
122962306a36Sopenharmony_ci}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ciint mlx4_calc_vf_counters(struct mlx4_dev *dev, int slave, int port,
123262306a36Sopenharmony_ci			  struct mlx4_counter *data)
123362306a36Sopenharmony_ci{
123462306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
123562306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
123662306a36Sopenharmony_ci	struct res_common *tmp;
123762306a36Sopenharmony_ci	struct res_counter *counter;
123862306a36Sopenharmony_ci	int *counters_arr;
123962306a36Sopenharmony_ci	int i = 0, err = 0;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	memset(data, 0, sizeof(*data));
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	counters_arr = kmalloc_array(dev->caps.max_counters,
124462306a36Sopenharmony_ci				     sizeof(*counters_arr), GFP_KERNEL);
124562306a36Sopenharmony_ci	if (!counters_arr)
124662306a36Sopenharmony_ci		return -ENOMEM;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
124962306a36Sopenharmony_ci	list_for_each_entry(tmp,
125062306a36Sopenharmony_ci			    &tracker->slave_list[slave].res_list[RES_COUNTER],
125162306a36Sopenharmony_ci			    list) {
125262306a36Sopenharmony_ci		counter = container_of(tmp, struct res_counter, com);
125362306a36Sopenharmony_ci		if (counter->port == port) {
125462306a36Sopenharmony_ci			counters_arr[i] = (int)tmp->res_id;
125562306a36Sopenharmony_ci			i++;
125662306a36Sopenharmony_ci		}
125762306a36Sopenharmony_ci	}
125862306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
125962306a36Sopenharmony_ci	counters_arr[i] = -1;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	i = 0;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	while (counters_arr[i] != -1) {
126462306a36Sopenharmony_ci		err = mlx4_get_counter_stats(dev, counters_arr[i], data,
126562306a36Sopenharmony_ci					     0);
126662306a36Sopenharmony_ci		if (err) {
126762306a36Sopenharmony_ci			memset(data, 0, sizeof(*data));
126862306a36Sopenharmony_ci			goto table_changed;
126962306a36Sopenharmony_ci		}
127062306a36Sopenharmony_ci		i++;
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_citable_changed:
127462306a36Sopenharmony_ci	kfree(counters_arr);
127562306a36Sopenharmony_ci	return 0;
127662306a36Sopenharmony_ci}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_cistatic int add_res_range(struct mlx4_dev *dev, int slave, u64 base, int count,
127962306a36Sopenharmony_ci			 enum mlx4_resource type, int extra)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	int i;
128262306a36Sopenharmony_ci	int err;
128362306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
128462306a36Sopenharmony_ci	struct res_common **res_arr;
128562306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
128662306a36Sopenharmony_ci	struct rb_root *root = &tracker->res_tree[type];
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	res_arr = kcalloc(count, sizeof(*res_arr), GFP_KERNEL);
128962306a36Sopenharmony_ci	if (!res_arr)
129062306a36Sopenharmony_ci		return -ENOMEM;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	for (i = 0; i < count; ++i) {
129362306a36Sopenharmony_ci		res_arr[i] = alloc_tr(base + i, type, slave, extra);
129462306a36Sopenharmony_ci		if (!res_arr[i]) {
129562306a36Sopenharmony_ci			for (--i; i >= 0; --i)
129662306a36Sopenharmony_ci				kfree(res_arr[i]);
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci			kfree(res_arr);
129962306a36Sopenharmony_ci			return -ENOMEM;
130062306a36Sopenharmony_ci		}
130162306a36Sopenharmony_ci	}
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
130462306a36Sopenharmony_ci	for (i = 0; i < count; ++i) {
130562306a36Sopenharmony_ci		if (find_res(dev, base + i, type)) {
130662306a36Sopenharmony_ci			err = -EEXIST;
130762306a36Sopenharmony_ci			goto undo;
130862306a36Sopenharmony_ci		}
130962306a36Sopenharmony_ci		err = res_tracker_insert(root, res_arr[i]);
131062306a36Sopenharmony_ci		if (err)
131162306a36Sopenharmony_ci			goto undo;
131262306a36Sopenharmony_ci		list_add_tail(&res_arr[i]->list,
131362306a36Sopenharmony_ci			      &tracker->slave_list[slave].res_list[type]);
131462306a36Sopenharmony_ci	}
131562306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
131662306a36Sopenharmony_ci	kfree(res_arr);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	return 0;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ciundo:
132162306a36Sopenharmony_ci	for (--i; i >= 0; --i) {
132262306a36Sopenharmony_ci		rb_erase(&res_arr[i]->node, root);
132362306a36Sopenharmony_ci		list_del_init(&res_arr[i]->list);
132462306a36Sopenharmony_ci	}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	for (i = 0; i < count; ++i)
132962306a36Sopenharmony_ci		kfree(res_arr[i]);
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	kfree(res_arr);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	return err;
133462306a36Sopenharmony_ci}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_cistatic int remove_qp_ok(struct res_qp *res)
133762306a36Sopenharmony_ci{
133862306a36Sopenharmony_ci	if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) ||
133962306a36Sopenharmony_ci	    !list_empty(&res->mcg_list)) {
134062306a36Sopenharmony_ci		pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n",
134162306a36Sopenharmony_ci		       res->com.state, atomic_read(&res->ref_count));
134262306a36Sopenharmony_ci		return -EBUSY;
134362306a36Sopenharmony_ci	} else if (res->com.state != RES_QP_RESERVED) {
134462306a36Sopenharmony_ci		return -EPERM;
134562306a36Sopenharmony_ci	}
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	return 0;
134862306a36Sopenharmony_ci}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_cistatic int remove_mtt_ok(struct res_mtt *res, int order)
135162306a36Sopenharmony_ci{
135262306a36Sopenharmony_ci	if (res->com.state == RES_MTT_BUSY ||
135362306a36Sopenharmony_ci	    atomic_read(&res->ref_count)) {
135462306a36Sopenharmony_ci		pr_devel("%s-%d: state %s, ref_count %d\n",
135562306a36Sopenharmony_ci			 __func__, __LINE__,
135662306a36Sopenharmony_ci			 mtt_states_str(res->com.state),
135762306a36Sopenharmony_ci			 atomic_read(&res->ref_count));
135862306a36Sopenharmony_ci		return -EBUSY;
135962306a36Sopenharmony_ci	} else if (res->com.state != RES_MTT_ALLOCATED)
136062306a36Sopenharmony_ci		return -EPERM;
136162306a36Sopenharmony_ci	else if (res->order != order)
136262306a36Sopenharmony_ci		return -EINVAL;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	return 0;
136562306a36Sopenharmony_ci}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_cistatic int remove_mpt_ok(struct res_mpt *res)
136862306a36Sopenharmony_ci{
136962306a36Sopenharmony_ci	if (res->com.state == RES_MPT_BUSY)
137062306a36Sopenharmony_ci		return -EBUSY;
137162306a36Sopenharmony_ci	else if (res->com.state != RES_MPT_RESERVED)
137262306a36Sopenharmony_ci		return -EPERM;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	return 0;
137562306a36Sopenharmony_ci}
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_cistatic int remove_eq_ok(struct res_eq *res)
137862306a36Sopenharmony_ci{
137962306a36Sopenharmony_ci	if (res->com.state == RES_MPT_BUSY)
138062306a36Sopenharmony_ci		return -EBUSY;
138162306a36Sopenharmony_ci	else if (res->com.state != RES_MPT_RESERVED)
138262306a36Sopenharmony_ci		return -EPERM;
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	return 0;
138562306a36Sopenharmony_ci}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_cistatic int remove_counter_ok(struct res_counter *res)
138862306a36Sopenharmony_ci{
138962306a36Sopenharmony_ci	if (res->com.state == RES_COUNTER_BUSY)
139062306a36Sopenharmony_ci		return -EBUSY;
139162306a36Sopenharmony_ci	else if (res->com.state != RES_COUNTER_ALLOCATED)
139262306a36Sopenharmony_ci		return -EPERM;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	return 0;
139562306a36Sopenharmony_ci}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_cistatic int remove_xrcdn_ok(struct res_xrcdn *res)
139862306a36Sopenharmony_ci{
139962306a36Sopenharmony_ci	if (res->com.state == RES_XRCD_BUSY)
140062306a36Sopenharmony_ci		return -EBUSY;
140162306a36Sopenharmony_ci	else if (res->com.state != RES_XRCD_ALLOCATED)
140262306a36Sopenharmony_ci		return -EPERM;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	return 0;
140562306a36Sopenharmony_ci}
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_cistatic int remove_fs_rule_ok(struct res_fs_rule *res)
140862306a36Sopenharmony_ci{
140962306a36Sopenharmony_ci	if (res->com.state == RES_FS_RULE_BUSY)
141062306a36Sopenharmony_ci		return -EBUSY;
141162306a36Sopenharmony_ci	else if (res->com.state != RES_FS_RULE_ALLOCATED)
141262306a36Sopenharmony_ci		return -EPERM;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	return 0;
141562306a36Sopenharmony_ci}
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_cistatic int remove_cq_ok(struct res_cq *res)
141862306a36Sopenharmony_ci{
141962306a36Sopenharmony_ci	if (res->com.state == RES_CQ_BUSY)
142062306a36Sopenharmony_ci		return -EBUSY;
142162306a36Sopenharmony_ci	else if (res->com.state != RES_CQ_ALLOCATED)
142262306a36Sopenharmony_ci		return -EPERM;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	return 0;
142562306a36Sopenharmony_ci}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_cistatic int remove_srq_ok(struct res_srq *res)
142862306a36Sopenharmony_ci{
142962306a36Sopenharmony_ci	if (res->com.state == RES_SRQ_BUSY)
143062306a36Sopenharmony_ci		return -EBUSY;
143162306a36Sopenharmony_ci	else if (res->com.state != RES_SRQ_ALLOCATED)
143262306a36Sopenharmony_ci		return -EPERM;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	return 0;
143562306a36Sopenharmony_ci}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_cistatic int remove_ok(struct res_common *res, enum mlx4_resource type, int extra)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	switch (type) {
144062306a36Sopenharmony_ci	case RES_QP:
144162306a36Sopenharmony_ci		return remove_qp_ok((struct res_qp *)res);
144262306a36Sopenharmony_ci	case RES_CQ:
144362306a36Sopenharmony_ci		return remove_cq_ok((struct res_cq *)res);
144462306a36Sopenharmony_ci	case RES_SRQ:
144562306a36Sopenharmony_ci		return remove_srq_ok((struct res_srq *)res);
144662306a36Sopenharmony_ci	case RES_MPT:
144762306a36Sopenharmony_ci		return remove_mpt_ok((struct res_mpt *)res);
144862306a36Sopenharmony_ci	case RES_MTT:
144962306a36Sopenharmony_ci		return remove_mtt_ok((struct res_mtt *)res, extra);
145062306a36Sopenharmony_ci	case RES_MAC:
145162306a36Sopenharmony_ci		return -EOPNOTSUPP;
145262306a36Sopenharmony_ci	case RES_EQ:
145362306a36Sopenharmony_ci		return remove_eq_ok((struct res_eq *)res);
145462306a36Sopenharmony_ci	case RES_COUNTER:
145562306a36Sopenharmony_ci		return remove_counter_ok((struct res_counter *)res);
145662306a36Sopenharmony_ci	case RES_XRCD:
145762306a36Sopenharmony_ci		return remove_xrcdn_ok((struct res_xrcdn *)res);
145862306a36Sopenharmony_ci	case RES_FS_RULE:
145962306a36Sopenharmony_ci		return remove_fs_rule_ok((struct res_fs_rule *)res);
146062306a36Sopenharmony_ci	default:
146162306a36Sopenharmony_ci		return -EINVAL;
146262306a36Sopenharmony_ci	}
146362306a36Sopenharmony_ci}
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_cistatic int rem_res_range(struct mlx4_dev *dev, int slave, u64 base, int count,
146662306a36Sopenharmony_ci			 enum mlx4_resource type, int extra)
146762306a36Sopenharmony_ci{
146862306a36Sopenharmony_ci	u64 i;
146962306a36Sopenharmony_ci	int err;
147062306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
147162306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
147262306a36Sopenharmony_ci	struct res_common *r;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
147562306a36Sopenharmony_ci	for (i = base; i < base + count; ++i) {
147662306a36Sopenharmony_ci		r = res_tracker_lookup(&tracker->res_tree[type], i);
147762306a36Sopenharmony_ci		if (!r) {
147862306a36Sopenharmony_ci			err = -ENOENT;
147962306a36Sopenharmony_ci			goto out;
148062306a36Sopenharmony_ci		}
148162306a36Sopenharmony_ci		if (r->owner != slave) {
148262306a36Sopenharmony_ci			err = -EPERM;
148362306a36Sopenharmony_ci			goto out;
148462306a36Sopenharmony_ci		}
148562306a36Sopenharmony_ci		err = remove_ok(r, type, extra);
148662306a36Sopenharmony_ci		if (err)
148762306a36Sopenharmony_ci			goto out;
148862306a36Sopenharmony_ci	}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	for (i = base; i < base + count; ++i) {
149162306a36Sopenharmony_ci		r = res_tracker_lookup(&tracker->res_tree[type], i);
149262306a36Sopenharmony_ci		rb_erase(&r->node, &tracker->res_tree[type]);
149362306a36Sopenharmony_ci		list_del(&r->list);
149462306a36Sopenharmony_ci		kfree(r);
149562306a36Sopenharmony_ci	}
149662306a36Sopenharmony_ci	err = 0;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ciout:
149962306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	return err;
150262306a36Sopenharmony_ci}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_cistatic int qp_res_start_move_to(struct mlx4_dev *dev, int slave, int qpn,
150562306a36Sopenharmony_ci				enum res_qp_states state, struct res_qp **qp,
150662306a36Sopenharmony_ci				int alloc)
150762306a36Sopenharmony_ci{
150862306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
150962306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
151062306a36Sopenharmony_ci	struct res_qp *r;
151162306a36Sopenharmony_ci	int err = 0;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
151462306a36Sopenharmony_ci	r = res_tracker_lookup(&tracker->res_tree[RES_QP], qpn);
151562306a36Sopenharmony_ci	if (!r)
151662306a36Sopenharmony_ci		err = -ENOENT;
151762306a36Sopenharmony_ci	else if (r->com.owner != slave)
151862306a36Sopenharmony_ci		err = -EPERM;
151962306a36Sopenharmony_ci	else {
152062306a36Sopenharmony_ci		switch (state) {
152162306a36Sopenharmony_ci		case RES_QP_BUSY:
152262306a36Sopenharmony_ci			mlx4_dbg(dev, "%s: failed RES_QP, 0x%llx\n",
152362306a36Sopenharmony_ci				 __func__, r->com.res_id);
152462306a36Sopenharmony_ci			err = -EBUSY;
152562306a36Sopenharmony_ci			break;
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci		case RES_QP_RESERVED:
152862306a36Sopenharmony_ci			if (r->com.state == RES_QP_MAPPED && !alloc)
152962306a36Sopenharmony_ci				break;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci			mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", r->com.res_id);
153262306a36Sopenharmony_ci			err = -EINVAL;
153362306a36Sopenharmony_ci			break;
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci		case RES_QP_MAPPED:
153662306a36Sopenharmony_ci			if ((r->com.state == RES_QP_RESERVED && alloc) ||
153762306a36Sopenharmony_ci			    r->com.state == RES_QP_HW)
153862306a36Sopenharmony_ci				break;
153962306a36Sopenharmony_ci			else {
154062306a36Sopenharmony_ci				mlx4_dbg(dev, "failed RES_QP, 0x%llx\n",
154162306a36Sopenharmony_ci					  r->com.res_id);
154262306a36Sopenharmony_ci				err = -EINVAL;
154362306a36Sopenharmony_ci			}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci			break;
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci		case RES_QP_HW:
154862306a36Sopenharmony_ci			if (r->com.state != RES_QP_MAPPED)
154962306a36Sopenharmony_ci				err = -EINVAL;
155062306a36Sopenharmony_ci			break;
155162306a36Sopenharmony_ci		default:
155262306a36Sopenharmony_ci			err = -EINVAL;
155362306a36Sopenharmony_ci		}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci		if (!err) {
155662306a36Sopenharmony_ci			r->com.from_state = r->com.state;
155762306a36Sopenharmony_ci			r->com.to_state = state;
155862306a36Sopenharmony_ci			r->com.state = RES_QP_BUSY;
155962306a36Sopenharmony_ci			if (qp)
156062306a36Sopenharmony_ci				*qp = r;
156162306a36Sopenharmony_ci		}
156262306a36Sopenharmony_ci	}
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	return err;
156762306a36Sopenharmony_ci}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_cistatic int mr_res_start_move_to(struct mlx4_dev *dev, int slave, int index,
157062306a36Sopenharmony_ci				enum res_mpt_states state, struct res_mpt **mpt)
157162306a36Sopenharmony_ci{
157262306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
157362306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
157462306a36Sopenharmony_ci	struct res_mpt *r;
157562306a36Sopenharmony_ci	int err = 0;
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
157862306a36Sopenharmony_ci	r = res_tracker_lookup(&tracker->res_tree[RES_MPT], index);
157962306a36Sopenharmony_ci	if (!r)
158062306a36Sopenharmony_ci		err = -ENOENT;
158162306a36Sopenharmony_ci	else if (r->com.owner != slave)
158262306a36Sopenharmony_ci		err = -EPERM;
158362306a36Sopenharmony_ci	else {
158462306a36Sopenharmony_ci		switch (state) {
158562306a36Sopenharmony_ci		case RES_MPT_BUSY:
158662306a36Sopenharmony_ci			err = -EINVAL;
158762306a36Sopenharmony_ci			break;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci		case RES_MPT_RESERVED:
159062306a36Sopenharmony_ci			if (r->com.state != RES_MPT_MAPPED)
159162306a36Sopenharmony_ci				err = -EINVAL;
159262306a36Sopenharmony_ci			break;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci		case RES_MPT_MAPPED:
159562306a36Sopenharmony_ci			if (r->com.state != RES_MPT_RESERVED &&
159662306a36Sopenharmony_ci			    r->com.state != RES_MPT_HW)
159762306a36Sopenharmony_ci				err = -EINVAL;
159862306a36Sopenharmony_ci			break;
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci		case RES_MPT_HW:
160162306a36Sopenharmony_ci			if (r->com.state != RES_MPT_MAPPED)
160262306a36Sopenharmony_ci				err = -EINVAL;
160362306a36Sopenharmony_ci			break;
160462306a36Sopenharmony_ci		default:
160562306a36Sopenharmony_ci			err = -EINVAL;
160662306a36Sopenharmony_ci		}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci		if (!err) {
160962306a36Sopenharmony_ci			r->com.from_state = r->com.state;
161062306a36Sopenharmony_ci			r->com.to_state = state;
161162306a36Sopenharmony_ci			r->com.state = RES_MPT_BUSY;
161262306a36Sopenharmony_ci			if (mpt)
161362306a36Sopenharmony_ci				*mpt = r;
161462306a36Sopenharmony_ci		}
161562306a36Sopenharmony_ci	}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	return err;
162062306a36Sopenharmony_ci}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_cistatic int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index,
162362306a36Sopenharmony_ci				enum res_eq_states state, struct res_eq **eq)
162462306a36Sopenharmony_ci{
162562306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
162662306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
162762306a36Sopenharmony_ci	struct res_eq *r;
162862306a36Sopenharmony_ci	int err = 0;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
163162306a36Sopenharmony_ci	r = res_tracker_lookup(&tracker->res_tree[RES_EQ], index);
163262306a36Sopenharmony_ci	if (!r)
163362306a36Sopenharmony_ci		err = -ENOENT;
163462306a36Sopenharmony_ci	else if (r->com.owner != slave)
163562306a36Sopenharmony_ci		err = -EPERM;
163662306a36Sopenharmony_ci	else {
163762306a36Sopenharmony_ci		switch (state) {
163862306a36Sopenharmony_ci		case RES_EQ_BUSY:
163962306a36Sopenharmony_ci			err = -EINVAL;
164062306a36Sopenharmony_ci			break;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci		case RES_EQ_RESERVED:
164362306a36Sopenharmony_ci			if (r->com.state != RES_EQ_HW)
164462306a36Sopenharmony_ci				err = -EINVAL;
164562306a36Sopenharmony_ci			break;
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci		case RES_EQ_HW:
164862306a36Sopenharmony_ci			if (r->com.state != RES_EQ_RESERVED)
164962306a36Sopenharmony_ci				err = -EINVAL;
165062306a36Sopenharmony_ci			break;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci		default:
165362306a36Sopenharmony_ci			err = -EINVAL;
165462306a36Sopenharmony_ci		}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci		if (!err) {
165762306a36Sopenharmony_ci			r->com.from_state = r->com.state;
165862306a36Sopenharmony_ci			r->com.to_state = state;
165962306a36Sopenharmony_ci			r->com.state = RES_EQ_BUSY;
166062306a36Sopenharmony_ci		}
166162306a36Sopenharmony_ci	}
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	if (!err && eq)
166662306a36Sopenharmony_ci		*eq = r;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	return err;
166962306a36Sopenharmony_ci}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_cistatic int cq_res_start_move_to(struct mlx4_dev *dev, int slave, int cqn,
167262306a36Sopenharmony_ci				enum res_cq_states state, struct res_cq **cq)
167362306a36Sopenharmony_ci{
167462306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
167562306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
167662306a36Sopenharmony_ci	struct res_cq *r;
167762306a36Sopenharmony_ci	int err;
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
168062306a36Sopenharmony_ci	r = res_tracker_lookup(&tracker->res_tree[RES_CQ], cqn);
168162306a36Sopenharmony_ci	if (!r) {
168262306a36Sopenharmony_ci		err = -ENOENT;
168362306a36Sopenharmony_ci	} else if (r->com.owner != slave) {
168462306a36Sopenharmony_ci		err = -EPERM;
168562306a36Sopenharmony_ci	} else if (state == RES_CQ_ALLOCATED) {
168662306a36Sopenharmony_ci		if (r->com.state != RES_CQ_HW)
168762306a36Sopenharmony_ci			err = -EINVAL;
168862306a36Sopenharmony_ci		else if (atomic_read(&r->ref_count))
168962306a36Sopenharmony_ci			err = -EBUSY;
169062306a36Sopenharmony_ci		else
169162306a36Sopenharmony_ci			err = 0;
169262306a36Sopenharmony_ci	} else if (state != RES_CQ_HW || r->com.state != RES_CQ_ALLOCATED) {
169362306a36Sopenharmony_ci		err = -EINVAL;
169462306a36Sopenharmony_ci	} else {
169562306a36Sopenharmony_ci		err = 0;
169662306a36Sopenharmony_ci	}
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	if (!err) {
169962306a36Sopenharmony_ci		r->com.from_state = r->com.state;
170062306a36Sopenharmony_ci		r->com.to_state = state;
170162306a36Sopenharmony_ci		r->com.state = RES_CQ_BUSY;
170262306a36Sopenharmony_ci		if (cq)
170362306a36Sopenharmony_ci			*cq = r;
170462306a36Sopenharmony_ci	}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	return err;
170962306a36Sopenharmony_ci}
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_cistatic int srq_res_start_move_to(struct mlx4_dev *dev, int slave, int index,
171262306a36Sopenharmony_ci				 enum res_srq_states state, struct res_srq **srq)
171362306a36Sopenharmony_ci{
171462306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
171562306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
171662306a36Sopenharmony_ci	struct res_srq *r;
171762306a36Sopenharmony_ci	int err = 0;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
172062306a36Sopenharmony_ci	r = res_tracker_lookup(&tracker->res_tree[RES_SRQ], index);
172162306a36Sopenharmony_ci	if (!r) {
172262306a36Sopenharmony_ci		err = -ENOENT;
172362306a36Sopenharmony_ci	} else if (r->com.owner != slave) {
172462306a36Sopenharmony_ci		err = -EPERM;
172562306a36Sopenharmony_ci	} else if (state == RES_SRQ_ALLOCATED) {
172662306a36Sopenharmony_ci		if (r->com.state != RES_SRQ_HW)
172762306a36Sopenharmony_ci			err = -EINVAL;
172862306a36Sopenharmony_ci		else if (atomic_read(&r->ref_count))
172962306a36Sopenharmony_ci			err = -EBUSY;
173062306a36Sopenharmony_ci	} else if (state != RES_SRQ_HW || r->com.state != RES_SRQ_ALLOCATED) {
173162306a36Sopenharmony_ci		err = -EINVAL;
173262306a36Sopenharmony_ci	}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	if (!err) {
173562306a36Sopenharmony_ci		r->com.from_state = r->com.state;
173662306a36Sopenharmony_ci		r->com.to_state = state;
173762306a36Sopenharmony_ci		r->com.state = RES_SRQ_BUSY;
173862306a36Sopenharmony_ci		if (srq)
173962306a36Sopenharmony_ci			*srq = r;
174062306a36Sopenharmony_ci	}
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	return err;
174562306a36Sopenharmony_ci}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_cistatic void res_abort_move(struct mlx4_dev *dev, int slave,
174862306a36Sopenharmony_ci			   enum mlx4_resource type, int id)
174962306a36Sopenharmony_ci{
175062306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
175162306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
175262306a36Sopenharmony_ci	struct res_common *r;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
175562306a36Sopenharmony_ci	r = res_tracker_lookup(&tracker->res_tree[type], id);
175662306a36Sopenharmony_ci	if (r && (r->owner == slave))
175762306a36Sopenharmony_ci		r->state = r->from_state;
175862306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
175962306a36Sopenharmony_ci}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_cistatic void res_end_move(struct mlx4_dev *dev, int slave,
176262306a36Sopenharmony_ci			 enum mlx4_resource type, int id)
176362306a36Sopenharmony_ci{
176462306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
176562306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
176662306a36Sopenharmony_ci	struct res_common *r;
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
176962306a36Sopenharmony_ci	r = res_tracker_lookup(&tracker->res_tree[type], id);
177062306a36Sopenharmony_ci	if (r && (r->owner == slave))
177162306a36Sopenharmony_ci		r->state = r->to_state;
177262306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
177362306a36Sopenharmony_ci}
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_cistatic int valid_reserved(struct mlx4_dev *dev, int slave, int qpn)
177662306a36Sopenharmony_ci{
177762306a36Sopenharmony_ci	return mlx4_is_qp_reserved(dev, qpn) &&
177862306a36Sopenharmony_ci		(mlx4_is_master(dev) || mlx4_is_guest_proxy(dev, slave, qpn));
177962306a36Sopenharmony_ci}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_cistatic int fw_reserved(struct mlx4_dev *dev, int qpn)
178262306a36Sopenharmony_ci{
178362306a36Sopenharmony_ci	return qpn < dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW];
178462306a36Sopenharmony_ci}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_cistatic int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
178762306a36Sopenharmony_ci			u64 in_param, u64 *out_param)
178862306a36Sopenharmony_ci{
178962306a36Sopenharmony_ci	int err;
179062306a36Sopenharmony_ci	int count;
179162306a36Sopenharmony_ci	int align;
179262306a36Sopenharmony_ci	int base;
179362306a36Sopenharmony_ci	int qpn;
179462306a36Sopenharmony_ci	u8 flags;
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	switch (op) {
179762306a36Sopenharmony_ci	case RES_OP_RESERVE:
179862306a36Sopenharmony_ci		count = get_param_l(&in_param) & 0xffffff;
179962306a36Sopenharmony_ci		/* Turn off all unsupported QP allocation flags that the
180062306a36Sopenharmony_ci		 * slave tries to set.
180162306a36Sopenharmony_ci		 */
180262306a36Sopenharmony_ci		flags = (get_param_l(&in_param) >> 24) & dev->caps.alloc_res_qp_mask;
180362306a36Sopenharmony_ci		align = get_param_h(&in_param);
180462306a36Sopenharmony_ci		err = mlx4_grant_resource(dev, slave, RES_QP, count, 0);
180562306a36Sopenharmony_ci		if (err)
180662306a36Sopenharmony_ci			return err;
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci		err = __mlx4_qp_reserve_range(dev, count, align, &base, flags);
180962306a36Sopenharmony_ci		if (err) {
181062306a36Sopenharmony_ci			mlx4_release_resource(dev, slave, RES_QP, count, 0);
181162306a36Sopenharmony_ci			return err;
181262306a36Sopenharmony_ci		}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci		err = add_res_range(dev, slave, base, count, RES_QP, 0);
181562306a36Sopenharmony_ci		if (err) {
181662306a36Sopenharmony_ci			mlx4_release_resource(dev, slave, RES_QP, count, 0);
181762306a36Sopenharmony_ci			__mlx4_qp_release_range(dev, base, count);
181862306a36Sopenharmony_ci			return err;
181962306a36Sopenharmony_ci		}
182062306a36Sopenharmony_ci		set_param_l(out_param, base);
182162306a36Sopenharmony_ci		break;
182262306a36Sopenharmony_ci	case RES_OP_MAP_ICM:
182362306a36Sopenharmony_ci		qpn = get_param_l(&in_param) & 0x7fffff;
182462306a36Sopenharmony_ci		if (valid_reserved(dev, slave, qpn)) {
182562306a36Sopenharmony_ci			err = add_res_range(dev, slave, qpn, 1, RES_QP, 0);
182662306a36Sopenharmony_ci			if (err)
182762306a36Sopenharmony_ci				return err;
182862306a36Sopenharmony_ci		}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci		err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED,
183162306a36Sopenharmony_ci					   NULL, 1);
183262306a36Sopenharmony_ci		if (err)
183362306a36Sopenharmony_ci			return err;
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci		if (!fw_reserved(dev, qpn)) {
183662306a36Sopenharmony_ci			err = __mlx4_qp_alloc_icm(dev, qpn);
183762306a36Sopenharmony_ci			if (err) {
183862306a36Sopenharmony_ci				res_abort_move(dev, slave, RES_QP, qpn);
183962306a36Sopenharmony_ci				return err;
184062306a36Sopenharmony_ci			}
184162306a36Sopenharmony_ci		}
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci		res_end_move(dev, slave, RES_QP, qpn);
184462306a36Sopenharmony_ci		break;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	default:
184762306a36Sopenharmony_ci		err = -EINVAL;
184862306a36Sopenharmony_ci		break;
184962306a36Sopenharmony_ci	}
185062306a36Sopenharmony_ci	return err;
185162306a36Sopenharmony_ci}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_cistatic int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
185462306a36Sopenharmony_ci			 u64 in_param, u64 *out_param)
185562306a36Sopenharmony_ci{
185662306a36Sopenharmony_ci	int err = -EINVAL;
185762306a36Sopenharmony_ci	int base;
185862306a36Sopenharmony_ci	int order;
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	if (op != RES_OP_RESERVE_AND_MAP)
186162306a36Sopenharmony_ci		return err;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	order = get_param_l(&in_param);
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	err = mlx4_grant_resource(dev, slave, RES_MTT, 1 << order, 0);
186662306a36Sopenharmony_ci	if (err)
186762306a36Sopenharmony_ci		return err;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	base = __mlx4_alloc_mtt_range(dev, order);
187062306a36Sopenharmony_ci	if (base == -1) {
187162306a36Sopenharmony_ci		mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
187262306a36Sopenharmony_ci		return -ENOMEM;
187362306a36Sopenharmony_ci	}
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	err = add_res_range(dev, slave, base, 1, RES_MTT, order);
187662306a36Sopenharmony_ci	if (err) {
187762306a36Sopenharmony_ci		mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
187862306a36Sopenharmony_ci		__mlx4_free_mtt_range(dev, base, order);
187962306a36Sopenharmony_ci	} else {
188062306a36Sopenharmony_ci		set_param_l(out_param, base);
188162306a36Sopenharmony_ci	}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	return err;
188462306a36Sopenharmony_ci}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_cistatic int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
188762306a36Sopenharmony_ci			 u64 in_param, u64 *out_param)
188862306a36Sopenharmony_ci{
188962306a36Sopenharmony_ci	int err = -EINVAL;
189062306a36Sopenharmony_ci	int index;
189162306a36Sopenharmony_ci	int id;
189262306a36Sopenharmony_ci	struct res_mpt *mpt;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	switch (op) {
189562306a36Sopenharmony_ci	case RES_OP_RESERVE:
189662306a36Sopenharmony_ci		err = mlx4_grant_resource(dev, slave, RES_MPT, 1, 0);
189762306a36Sopenharmony_ci		if (err)
189862306a36Sopenharmony_ci			break;
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci		index = __mlx4_mpt_reserve(dev);
190162306a36Sopenharmony_ci		if (index == -1) {
190262306a36Sopenharmony_ci			mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
190362306a36Sopenharmony_ci			break;
190462306a36Sopenharmony_ci		}
190562306a36Sopenharmony_ci		id = index & mpt_mask(dev);
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci		err = add_res_range(dev, slave, id, 1, RES_MPT, index);
190862306a36Sopenharmony_ci		if (err) {
190962306a36Sopenharmony_ci			mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
191062306a36Sopenharmony_ci			__mlx4_mpt_release(dev, index);
191162306a36Sopenharmony_ci			break;
191262306a36Sopenharmony_ci		}
191362306a36Sopenharmony_ci		set_param_l(out_param, index);
191462306a36Sopenharmony_ci		break;
191562306a36Sopenharmony_ci	case RES_OP_MAP_ICM:
191662306a36Sopenharmony_ci		index = get_param_l(&in_param);
191762306a36Sopenharmony_ci		id = index & mpt_mask(dev);
191862306a36Sopenharmony_ci		err = mr_res_start_move_to(dev, slave, id,
191962306a36Sopenharmony_ci					   RES_MPT_MAPPED, &mpt);
192062306a36Sopenharmony_ci		if (err)
192162306a36Sopenharmony_ci			return err;
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci		err = __mlx4_mpt_alloc_icm(dev, mpt->key);
192462306a36Sopenharmony_ci		if (err) {
192562306a36Sopenharmony_ci			res_abort_move(dev, slave, RES_MPT, id);
192662306a36Sopenharmony_ci			return err;
192762306a36Sopenharmony_ci		}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci		res_end_move(dev, slave, RES_MPT, id);
193062306a36Sopenharmony_ci		break;
193162306a36Sopenharmony_ci	}
193262306a36Sopenharmony_ci	return err;
193362306a36Sopenharmony_ci}
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_cistatic int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
193662306a36Sopenharmony_ci			u64 in_param, u64 *out_param)
193762306a36Sopenharmony_ci{
193862306a36Sopenharmony_ci	int cqn;
193962306a36Sopenharmony_ci	int err;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	switch (op) {
194262306a36Sopenharmony_ci	case RES_OP_RESERVE_AND_MAP:
194362306a36Sopenharmony_ci		err = mlx4_grant_resource(dev, slave, RES_CQ, 1, 0);
194462306a36Sopenharmony_ci		if (err)
194562306a36Sopenharmony_ci			break;
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci		err = __mlx4_cq_alloc_icm(dev, &cqn);
194862306a36Sopenharmony_ci		if (err) {
194962306a36Sopenharmony_ci			mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
195062306a36Sopenharmony_ci			break;
195162306a36Sopenharmony_ci		}
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci		err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0);
195462306a36Sopenharmony_ci		if (err) {
195562306a36Sopenharmony_ci			mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
195662306a36Sopenharmony_ci			__mlx4_cq_free_icm(dev, cqn);
195762306a36Sopenharmony_ci			break;
195862306a36Sopenharmony_ci		}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci		set_param_l(out_param, cqn);
196162306a36Sopenharmony_ci		break;
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	default:
196462306a36Sopenharmony_ci		err = -EINVAL;
196562306a36Sopenharmony_ci	}
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	return err;
196862306a36Sopenharmony_ci}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_cistatic int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
197162306a36Sopenharmony_ci			 u64 in_param, u64 *out_param)
197262306a36Sopenharmony_ci{
197362306a36Sopenharmony_ci	int srqn;
197462306a36Sopenharmony_ci	int err;
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	switch (op) {
197762306a36Sopenharmony_ci	case RES_OP_RESERVE_AND_MAP:
197862306a36Sopenharmony_ci		err = mlx4_grant_resource(dev, slave, RES_SRQ, 1, 0);
197962306a36Sopenharmony_ci		if (err)
198062306a36Sopenharmony_ci			break;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci		err = __mlx4_srq_alloc_icm(dev, &srqn);
198362306a36Sopenharmony_ci		if (err) {
198462306a36Sopenharmony_ci			mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
198562306a36Sopenharmony_ci			break;
198662306a36Sopenharmony_ci		}
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci		err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0);
198962306a36Sopenharmony_ci		if (err) {
199062306a36Sopenharmony_ci			mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
199162306a36Sopenharmony_ci			__mlx4_srq_free_icm(dev, srqn);
199262306a36Sopenharmony_ci			break;
199362306a36Sopenharmony_ci		}
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci		set_param_l(out_param, srqn);
199662306a36Sopenharmony_ci		break;
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	default:
199962306a36Sopenharmony_ci		err = -EINVAL;
200062306a36Sopenharmony_ci	}
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	return err;
200362306a36Sopenharmony_ci}
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_cistatic int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port,
200662306a36Sopenharmony_ci				     u8 smac_index, u64 *mac)
200762306a36Sopenharmony_ci{
200862306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
200962306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
201062306a36Sopenharmony_ci	struct list_head *mac_list =
201162306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_MAC];
201262306a36Sopenharmony_ci	struct mac_res *res, *tmp;
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci	list_for_each_entry_safe(res, tmp, mac_list, list) {
201562306a36Sopenharmony_ci		if (res->smac_index == smac_index && res->port == (u8) port) {
201662306a36Sopenharmony_ci			*mac = res->mac;
201762306a36Sopenharmony_ci			return 0;
201862306a36Sopenharmony_ci		}
201962306a36Sopenharmony_ci	}
202062306a36Sopenharmony_ci	return -ENOENT;
202162306a36Sopenharmony_ci}
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_cistatic int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index)
202462306a36Sopenharmony_ci{
202562306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
202662306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
202762306a36Sopenharmony_ci	struct list_head *mac_list =
202862306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_MAC];
202962306a36Sopenharmony_ci	struct mac_res *res, *tmp;
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	list_for_each_entry_safe(res, tmp, mac_list, list) {
203262306a36Sopenharmony_ci		if (res->mac == mac && res->port == (u8) port) {
203362306a36Sopenharmony_ci			/* mac found. update ref count */
203462306a36Sopenharmony_ci			++res->ref_count;
203562306a36Sopenharmony_ci			return 0;
203662306a36Sopenharmony_ci		}
203762306a36Sopenharmony_ci	}
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port))
204062306a36Sopenharmony_ci		return -EINVAL;
204162306a36Sopenharmony_ci	res = kzalloc(sizeof(*res), GFP_KERNEL);
204262306a36Sopenharmony_ci	if (!res) {
204362306a36Sopenharmony_ci		mlx4_release_resource(dev, slave, RES_MAC, 1, port);
204462306a36Sopenharmony_ci		return -ENOMEM;
204562306a36Sopenharmony_ci	}
204662306a36Sopenharmony_ci	res->mac = mac;
204762306a36Sopenharmony_ci	res->port = (u8) port;
204862306a36Sopenharmony_ci	res->smac_index = smac_index;
204962306a36Sopenharmony_ci	res->ref_count = 1;
205062306a36Sopenharmony_ci	list_add_tail(&res->list,
205162306a36Sopenharmony_ci		      &tracker->slave_list[slave].res_list[RES_MAC]);
205262306a36Sopenharmony_ci	return 0;
205362306a36Sopenharmony_ci}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_cistatic void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac,
205662306a36Sopenharmony_ci			       int port)
205762306a36Sopenharmony_ci{
205862306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
205962306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
206062306a36Sopenharmony_ci	struct list_head *mac_list =
206162306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_MAC];
206262306a36Sopenharmony_ci	struct mac_res *res, *tmp;
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	list_for_each_entry_safe(res, tmp, mac_list, list) {
206562306a36Sopenharmony_ci		if (res->mac == mac && res->port == (u8) port) {
206662306a36Sopenharmony_ci			if (!--res->ref_count) {
206762306a36Sopenharmony_ci				list_del(&res->list);
206862306a36Sopenharmony_ci				mlx4_release_resource(dev, slave, RES_MAC, 1, port);
206962306a36Sopenharmony_ci				kfree(res);
207062306a36Sopenharmony_ci			}
207162306a36Sopenharmony_ci			break;
207262306a36Sopenharmony_ci		}
207362306a36Sopenharmony_ci	}
207462306a36Sopenharmony_ci}
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_cistatic void rem_slave_macs(struct mlx4_dev *dev, int slave)
207762306a36Sopenharmony_ci{
207862306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
207962306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
208062306a36Sopenharmony_ci	struct list_head *mac_list =
208162306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_MAC];
208262306a36Sopenharmony_ci	struct mac_res *res, *tmp;
208362306a36Sopenharmony_ci	int i;
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	list_for_each_entry_safe(res, tmp, mac_list, list) {
208662306a36Sopenharmony_ci		list_del(&res->list);
208762306a36Sopenharmony_ci		/* dereference the mac the num times the slave referenced it */
208862306a36Sopenharmony_ci		for (i = 0; i < res->ref_count; i++)
208962306a36Sopenharmony_ci			__mlx4_unregister_mac(dev, res->port, res->mac);
209062306a36Sopenharmony_ci		mlx4_release_resource(dev, slave, RES_MAC, 1, res->port);
209162306a36Sopenharmony_ci		kfree(res);
209262306a36Sopenharmony_ci	}
209362306a36Sopenharmony_ci}
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_cistatic int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
209662306a36Sopenharmony_ci			 u64 in_param, u64 *out_param, int in_port)
209762306a36Sopenharmony_ci{
209862306a36Sopenharmony_ci	int err = -EINVAL;
209962306a36Sopenharmony_ci	int port;
210062306a36Sopenharmony_ci	u64 mac;
210162306a36Sopenharmony_ci	u8 smac_index;
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	if (op != RES_OP_RESERVE_AND_MAP)
210462306a36Sopenharmony_ci		return err;
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	port = !in_port ? get_param_l(out_param) : in_port;
210762306a36Sopenharmony_ci	port = mlx4_slave_convert_port(
210862306a36Sopenharmony_ci			dev, slave, port);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	if (port < 0)
211162306a36Sopenharmony_ci		return -EINVAL;
211262306a36Sopenharmony_ci	mac = in_param;
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	err = __mlx4_register_mac(dev, port, mac);
211562306a36Sopenharmony_ci	if (err >= 0) {
211662306a36Sopenharmony_ci		smac_index = err;
211762306a36Sopenharmony_ci		set_param_l(out_param, err);
211862306a36Sopenharmony_ci		err = 0;
211962306a36Sopenharmony_ci	}
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	if (!err) {
212262306a36Sopenharmony_ci		err = mac_add_to_slave(dev, slave, mac, port, smac_index);
212362306a36Sopenharmony_ci		if (err)
212462306a36Sopenharmony_ci			__mlx4_unregister_mac(dev, port, mac);
212562306a36Sopenharmony_ci	}
212662306a36Sopenharmony_ci	return err;
212762306a36Sopenharmony_ci}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_cistatic int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan,
213062306a36Sopenharmony_ci			     int port, int vlan_index)
213162306a36Sopenharmony_ci{
213262306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
213362306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
213462306a36Sopenharmony_ci	struct list_head *vlan_list =
213562306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_VLAN];
213662306a36Sopenharmony_ci	struct vlan_res *res, *tmp;
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	list_for_each_entry_safe(res, tmp, vlan_list, list) {
213962306a36Sopenharmony_ci		if (res->vlan == vlan && res->port == (u8) port) {
214062306a36Sopenharmony_ci			/* vlan found. update ref count */
214162306a36Sopenharmony_ci			++res->ref_count;
214262306a36Sopenharmony_ci			return 0;
214362306a36Sopenharmony_ci		}
214462306a36Sopenharmony_ci	}
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	if (mlx4_grant_resource(dev, slave, RES_VLAN, 1, port))
214762306a36Sopenharmony_ci		return -EINVAL;
214862306a36Sopenharmony_ci	res = kzalloc(sizeof(*res), GFP_KERNEL);
214962306a36Sopenharmony_ci	if (!res) {
215062306a36Sopenharmony_ci		mlx4_release_resource(dev, slave, RES_VLAN, 1, port);
215162306a36Sopenharmony_ci		return -ENOMEM;
215262306a36Sopenharmony_ci	}
215362306a36Sopenharmony_ci	res->vlan = vlan;
215462306a36Sopenharmony_ci	res->port = (u8) port;
215562306a36Sopenharmony_ci	res->vlan_index = vlan_index;
215662306a36Sopenharmony_ci	res->ref_count = 1;
215762306a36Sopenharmony_ci	list_add_tail(&res->list,
215862306a36Sopenharmony_ci		      &tracker->slave_list[slave].res_list[RES_VLAN]);
215962306a36Sopenharmony_ci	return 0;
216062306a36Sopenharmony_ci}
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_cistatic void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan,
216462306a36Sopenharmony_ci				int port)
216562306a36Sopenharmony_ci{
216662306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
216762306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
216862306a36Sopenharmony_ci	struct list_head *vlan_list =
216962306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_VLAN];
217062306a36Sopenharmony_ci	struct vlan_res *res, *tmp;
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	list_for_each_entry_safe(res, tmp, vlan_list, list) {
217362306a36Sopenharmony_ci		if (res->vlan == vlan && res->port == (u8) port) {
217462306a36Sopenharmony_ci			if (!--res->ref_count) {
217562306a36Sopenharmony_ci				list_del(&res->list);
217662306a36Sopenharmony_ci				mlx4_release_resource(dev, slave, RES_VLAN,
217762306a36Sopenharmony_ci						      1, port);
217862306a36Sopenharmony_ci				kfree(res);
217962306a36Sopenharmony_ci			}
218062306a36Sopenharmony_ci			break;
218162306a36Sopenharmony_ci		}
218262306a36Sopenharmony_ci	}
218362306a36Sopenharmony_ci}
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_cistatic void rem_slave_vlans(struct mlx4_dev *dev, int slave)
218662306a36Sopenharmony_ci{
218762306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
218862306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
218962306a36Sopenharmony_ci	struct list_head *vlan_list =
219062306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_VLAN];
219162306a36Sopenharmony_ci	struct vlan_res *res, *tmp;
219262306a36Sopenharmony_ci	int i;
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	list_for_each_entry_safe(res, tmp, vlan_list, list) {
219562306a36Sopenharmony_ci		list_del(&res->list);
219662306a36Sopenharmony_ci		/* dereference the vlan the num times the slave referenced it */
219762306a36Sopenharmony_ci		for (i = 0; i < res->ref_count; i++)
219862306a36Sopenharmony_ci			__mlx4_unregister_vlan(dev, res->port, res->vlan);
219962306a36Sopenharmony_ci		mlx4_release_resource(dev, slave, RES_VLAN, 1, res->port);
220062306a36Sopenharmony_ci		kfree(res);
220162306a36Sopenharmony_ci	}
220262306a36Sopenharmony_ci}
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_cistatic int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
220562306a36Sopenharmony_ci			  u64 in_param, u64 *out_param, int in_port)
220662306a36Sopenharmony_ci{
220762306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
220862306a36Sopenharmony_ci	struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
220962306a36Sopenharmony_ci	int err;
221062306a36Sopenharmony_ci	u16 vlan;
221162306a36Sopenharmony_ci	int vlan_index;
221262306a36Sopenharmony_ci	int port;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	port = !in_port ? get_param_l(out_param) : in_port;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	if (!port || op != RES_OP_RESERVE_AND_MAP)
221762306a36Sopenharmony_ci		return -EINVAL;
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	port = mlx4_slave_convert_port(
222062306a36Sopenharmony_ci			dev, slave, port);
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	if (port < 0)
222362306a36Sopenharmony_ci		return -EINVAL;
222462306a36Sopenharmony_ci	/* upstream kernels had NOP for reg/unreg vlan. Continue this. */
222562306a36Sopenharmony_ci	if (!in_port && port > 0 && port <= dev->caps.num_ports) {
222662306a36Sopenharmony_ci		slave_state[slave].old_vlan_api = true;
222762306a36Sopenharmony_ci		return 0;
222862306a36Sopenharmony_ci	}
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	vlan = (u16) in_param;
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	err = __mlx4_register_vlan(dev, port, vlan, &vlan_index);
223362306a36Sopenharmony_ci	if (!err) {
223462306a36Sopenharmony_ci		set_param_l(out_param, (u32) vlan_index);
223562306a36Sopenharmony_ci		err = vlan_add_to_slave(dev, slave, vlan, port, vlan_index);
223662306a36Sopenharmony_ci		if (err)
223762306a36Sopenharmony_ci			__mlx4_unregister_vlan(dev, port, vlan);
223862306a36Sopenharmony_ci	}
223962306a36Sopenharmony_ci	return err;
224062306a36Sopenharmony_ci}
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_cistatic int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
224362306a36Sopenharmony_ci			     u64 in_param, u64 *out_param, int port)
224462306a36Sopenharmony_ci{
224562306a36Sopenharmony_ci	u32 index;
224662306a36Sopenharmony_ci	int err;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	if (op != RES_OP_RESERVE)
224962306a36Sopenharmony_ci		return -EINVAL;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	err = mlx4_grant_resource(dev, slave, RES_COUNTER, 1, 0);
225262306a36Sopenharmony_ci	if (err)
225362306a36Sopenharmony_ci		return err;
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci	err = __mlx4_counter_alloc(dev, &index);
225662306a36Sopenharmony_ci	if (err) {
225762306a36Sopenharmony_ci		mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
225862306a36Sopenharmony_ci		return err;
225962306a36Sopenharmony_ci	}
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	err = add_res_range(dev, slave, index, 1, RES_COUNTER, port);
226262306a36Sopenharmony_ci	if (err) {
226362306a36Sopenharmony_ci		__mlx4_counter_free(dev, index);
226462306a36Sopenharmony_ci		mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
226562306a36Sopenharmony_ci	} else {
226662306a36Sopenharmony_ci		set_param_l(out_param, index);
226762306a36Sopenharmony_ci	}
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	return err;
227062306a36Sopenharmony_ci}
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_cistatic int xrcdn_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
227362306a36Sopenharmony_ci			   u64 in_param, u64 *out_param)
227462306a36Sopenharmony_ci{
227562306a36Sopenharmony_ci	u32 xrcdn;
227662306a36Sopenharmony_ci	int err;
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci	if (op != RES_OP_RESERVE)
227962306a36Sopenharmony_ci		return -EINVAL;
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci	err = __mlx4_xrcd_alloc(dev, &xrcdn);
228262306a36Sopenharmony_ci	if (err)
228362306a36Sopenharmony_ci		return err;
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci	err = add_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0);
228662306a36Sopenharmony_ci	if (err)
228762306a36Sopenharmony_ci		__mlx4_xrcd_free(dev, xrcdn);
228862306a36Sopenharmony_ci	else
228962306a36Sopenharmony_ci		set_param_l(out_param, xrcdn);
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	return err;
229262306a36Sopenharmony_ci}
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ciint mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave,
229562306a36Sopenharmony_ci			   struct mlx4_vhcr *vhcr,
229662306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *inbox,
229762306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *outbox,
229862306a36Sopenharmony_ci			   struct mlx4_cmd_info *cmd)
229962306a36Sopenharmony_ci{
230062306a36Sopenharmony_ci	int err;
230162306a36Sopenharmony_ci	int alop = vhcr->op_modifier;
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	switch (vhcr->in_modifier & 0xFF) {
230462306a36Sopenharmony_ci	case RES_QP:
230562306a36Sopenharmony_ci		err = qp_alloc_res(dev, slave, vhcr->op_modifier, alop,
230662306a36Sopenharmony_ci				   vhcr->in_param, &vhcr->out_param);
230762306a36Sopenharmony_ci		break;
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	case RES_MTT:
231062306a36Sopenharmony_ci		err = mtt_alloc_res(dev, slave, vhcr->op_modifier, alop,
231162306a36Sopenharmony_ci				    vhcr->in_param, &vhcr->out_param);
231262306a36Sopenharmony_ci		break;
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	case RES_MPT:
231562306a36Sopenharmony_ci		err = mpt_alloc_res(dev, slave, vhcr->op_modifier, alop,
231662306a36Sopenharmony_ci				    vhcr->in_param, &vhcr->out_param);
231762306a36Sopenharmony_ci		break;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	case RES_CQ:
232062306a36Sopenharmony_ci		err = cq_alloc_res(dev, slave, vhcr->op_modifier, alop,
232162306a36Sopenharmony_ci				   vhcr->in_param, &vhcr->out_param);
232262306a36Sopenharmony_ci		break;
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci	case RES_SRQ:
232562306a36Sopenharmony_ci		err = srq_alloc_res(dev, slave, vhcr->op_modifier, alop,
232662306a36Sopenharmony_ci				    vhcr->in_param, &vhcr->out_param);
232762306a36Sopenharmony_ci		break;
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	case RES_MAC:
233062306a36Sopenharmony_ci		err = mac_alloc_res(dev, slave, vhcr->op_modifier, alop,
233162306a36Sopenharmony_ci				    vhcr->in_param, &vhcr->out_param,
233262306a36Sopenharmony_ci				    (vhcr->in_modifier >> 8) & 0xFF);
233362306a36Sopenharmony_ci		break;
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci	case RES_VLAN:
233662306a36Sopenharmony_ci		err = vlan_alloc_res(dev, slave, vhcr->op_modifier, alop,
233762306a36Sopenharmony_ci				     vhcr->in_param, &vhcr->out_param,
233862306a36Sopenharmony_ci				     (vhcr->in_modifier >> 8) & 0xFF);
233962306a36Sopenharmony_ci		break;
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	case RES_COUNTER:
234262306a36Sopenharmony_ci		err = counter_alloc_res(dev, slave, vhcr->op_modifier, alop,
234362306a36Sopenharmony_ci					vhcr->in_param, &vhcr->out_param, 0);
234462306a36Sopenharmony_ci		break;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	case RES_XRCD:
234762306a36Sopenharmony_ci		err = xrcdn_alloc_res(dev, slave, vhcr->op_modifier, alop,
234862306a36Sopenharmony_ci				      vhcr->in_param, &vhcr->out_param);
234962306a36Sopenharmony_ci		break;
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	default:
235262306a36Sopenharmony_ci		err = -EINVAL;
235362306a36Sopenharmony_ci		break;
235462306a36Sopenharmony_ci	}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	return err;
235762306a36Sopenharmony_ci}
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_cistatic int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
236062306a36Sopenharmony_ci		       u64 in_param)
236162306a36Sopenharmony_ci{
236262306a36Sopenharmony_ci	int err;
236362306a36Sopenharmony_ci	int count;
236462306a36Sopenharmony_ci	int base;
236562306a36Sopenharmony_ci	int qpn;
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	switch (op) {
236862306a36Sopenharmony_ci	case RES_OP_RESERVE:
236962306a36Sopenharmony_ci		base = get_param_l(&in_param) & 0x7fffff;
237062306a36Sopenharmony_ci		count = get_param_h(&in_param);
237162306a36Sopenharmony_ci		err = rem_res_range(dev, slave, base, count, RES_QP, 0);
237262306a36Sopenharmony_ci		if (err)
237362306a36Sopenharmony_ci			break;
237462306a36Sopenharmony_ci		mlx4_release_resource(dev, slave, RES_QP, count, 0);
237562306a36Sopenharmony_ci		__mlx4_qp_release_range(dev, base, count);
237662306a36Sopenharmony_ci		break;
237762306a36Sopenharmony_ci	case RES_OP_MAP_ICM:
237862306a36Sopenharmony_ci		qpn = get_param_l(&in_param) & 0x7fffff;
237962306a36Sopenharmony_ci		err = qp_res_start_move_to(dev, slave, qpn, RES_QP_RESERVED,
238062306a36Sopenharmony_ci					   NULL, 0);
238162306a36Sopenharmony_ci		if (err)
238262306a36Sopenharmony_ci			return err;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci		if (!fw_reserved(dev, qpn))
238562306a36Sopenharmony_ci			__mlx4_qp_free_icm(dev, qpn);
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci		res_end_move(dev, slave, RES_QP, qpn);
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_ci		if (valid_reserved(dev, slave, qpn))
239062306a36Sopenharmony_ci			err = rem_res_range(dev, slave, qpn, 1, RES_QP, 0);
239162306a36Sopenharmony_ci		break;
239262306a36Sopenharmony_ci	default:
239362306a36Sopenharmony_ci		err = -EINVAL;
239462306a36Sopenharmony_ci		break;
239562306a36Sopenharmony_ci	}
239662306a36Sopenharmony_ci	return err;
239762306a36Sopenharmony_ci}
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_cistatic int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
240062306a36Sopenharmony_ci			u64 in_param, u64 *out_param)
240162306a36Sopenharmony_ci{
240262306a36Sopenharmony_ci	int err = -EINVAL;
240362306a36Sopenharmony_ci	int base;
240462306a36Sopenharmony_ci	int order;
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	if (op != RES_OP_RESERVE_AND_MAP)
240762306a36Sopenharmony_ci		return err;
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci	base = get_param_l(&in_param);
241062306a36Sopenharmony_ci	order = get_param_h(&in_param);
241162306a36Sopenharmony_ci	err = rem_res_range(dev, slave, base, 1, RES_MTT, order);
241262306a36Sopenharmony_ci	if (!err) {
241362306a36Sopenharmony_ci		mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
241462306a36Sopenharmony_ci		__mlx4_free_mtt_range(dev, base, order);
241562306a36Sopenharmony_ci	}
241662306a36Sopenharmony_ci	return err;
241762306a36Sopenharmony_ci}
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_cistatic int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
242062306a36Sopenharmony_ci			u64 in_param)
242162306a36Sopenharmony_ci{
242262306a36Sopenharmony_ci	int err = -EINVAL;
242362306a36Sopenharmony_ci	int index;
242462306a36Sopenharmony_ci	int id;
242562306a36Sopenharmony_ci	struct res_mpt *mpt;
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci	switch (op) {
242862306a36Sopenharmony_ci	case RES_OP_RESERVE:
242962306a36Sopenharmony_ci		index = get_param_l(&in_param);
243062306a36Sopenharmony_ci		id = index & mpt_mask(dev);
243162306a36Sopenharmony_ci		err = get_res(dev, slave, id, RES_MPT, &mpt);
243262306a36Sopenharmony_ci		if (err)
243362306a36Sopenharmony_ci			break;
243462306a36Sopenharmony_ci		index = mpt->key;
243562306a36Sopenharmony_ci		put_res(dev, slave, id, RES_MPT);
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_ci		err = rem_res_range(dev, slave, id, 1, RES_MPT, 0);
243862306a36Sopenharmony_ci		if (err)
243962306a36Sopenharmony_ci			break;
244062306a36Sopenharmony_ci		mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
244162306a36Sopenharmony_ci		__mlx4_mpt_release(dev, index);
244262306a36Sopenharmony_ci		break;
244362306a36Sopenharmony_ci	case RES_OP_MAP_ICM:
244462306a36Sopenharmony_ci		index = get_param_l(&in_param);
244562306a36Sopenharmony_ci		id = index & mpt_mask(dev);
244662306a36Sopenharmony_ci		err = mr_res_start_move_to(dev, slave, id,
244762306a36Sopenharmony_ci					   RES_MPT_RESERVED, &mpt);
244862306a36Sopenharmony_ci		if (err)
244962306a36Sopenharmony_ci			return err;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci		__mlx4_mpt_free_icm(dev, mpt->key);
245262306a36Sopenharmony_ci		res_end_move(dev, slave, RES_MPT, id);
245362306a36Sopenharmony_ci		break;
245462306a36Sopenharmony_ci	default:
245562306a36Sopenharmony_ci		err = -EINVAL;
245662306a36Sopenharmony_ci		break;
245762306a36Sopenharmony_ci	}
245862306a36Sopenharmony_ci	return err;
245962306a36Sopenharmony_ci}
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_cistatic int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
246262306a36Sopenharmony_ci		       u64 in_param, u64 *out_param)
246362306a36Sopenharmony_ci{
246462306a36Sopenharmony_ci	int cqn;
246562306a36Sopenharmony_ci	int err;
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci	switch (op) {
246862306a36Sopenharmony_ci	case RES_OP_RESERVE_AND_MAP:
246962306a36Sopenharmony_ci		cqn = get_param_l(&in_param);
247062306a36Sopenharmony_ci		err = rem_res_range(dev, slave, cqn, 1, RES_CQ, 0);
247162306a36Sopenharmony_ci		if (err)
247262306a36Sopenharmony_ci			break;
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci		mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
247562306a36Sopenharmony_ci		__mlx4_cq_free_icm(dev, cqn);
247662306a36Sopenharmony_ci		break;
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci	default:
247962306a36Sopenharmony_ci		err = -EINVAL;
248062306a36Sopenharmony_ci		break;
248162306a36Sopenharmony_ci	}
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	return err;
248462306a36Sopenharmony_ci}
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_cistatic int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
248762306a36Sopenharmony_ci			u64 in_param, u64 *out_param)
248862306a36Sopenharmony_ci{
248962306a36Sopenharmony_ci	int srqn;
249062306a36Sopenharmony_ci	int err;
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	switch (op) {
249362306a36Sopenharmony_ci	case RES_OP_RESERVE_AND_MAP:
249462306a36Sopenharmony_ci		srqn = get_param_l(&in_param);
249562306a36Sopenharmony_ci		err = rem_res_range(dev, slave, srqn, 1, RES_SRQ, 0);
249662306a36Sopenharmony_ci		if (err)
249762306a36Sopenharmony_ci			break;
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci		mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
250062306a36Sopenharmony_ci		__mlx4_srq_free_icm(dev, srqn);
250162306a36Sopenharmony_ci		break;
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	default:
250462306a36Sopenharmony_ci		err = -EINVAL;
250562306a36Sopenharmony_ci		break;
250662306a36Sopenharmony_ci	}
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	return err;
250962306a36Sopenharmony_ci}
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_cistatic int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
251262306a36Sopenharmony_ci			    u64 in_param, u64 *out_param, int in_port)
251362306a36Sopenharmony_ci{
251462306a36Sopenharmony_ci	int port;
251562306a36Sopenharmony_ci	int err = 0;
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	switch (op) {
251862306a36Sopenharmony_ci	case RES_OP_RESERVE_AND_MAP:
251962306a36Sopenharmony_ci		port = !in_port ? get_param_l(out_param) : in_port;
252062306a36Sopenharmony_ci		port = mlx4_slave_convert_port(
252162306a36Sopenharmony_ci				dev, slave, port);
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci		if (port < 0)
252462306a36Sopenharmony_ci			return -EINVAL;
252562306a36Sopenharmony_ci		mac_del_from_slave(dev, slave, in_param, port);
252662306a36Sopenharmony_ci		__mlx4_unregister_mac(dev, port, in_param);
252762306a36Sopenharmony_ci		break;
252862306a36Sopenharmony_ci	default:
252962306a36Sopenharmony_ci		err = -EINVAL;
253062306a36Sopenharmony_ci		break;
253162306a36Sopenharmony_ci	}
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_ci	return err;
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_cistatic int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
253862306a36Sopenharmony_ci			    u64 in_param, u64 *out_param, int port)
253962306a36Sopenharmony_ci{
254062306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
254162306a36Sopenharmony_ci	struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
254262306a36Sopenharmony_ci	int err = 0;
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci	port = mlx4_slave_convert_port(
254562306a36Sopenharmony_ci			dev, slave, port);
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci	if (port < 0)
254862306a36Sopenharmony_ci		return -EINVAL;
254962306a36Sopenharmony_ci	switch (op) {
255062306a36Sopenharmony_ci	case RES_OP_RESERVE_AND_MAP:
255162306a36Sopenharmony_ci		if (slave_state[slave].old_vlan_api)
255262306a36Sopenharmony_ci			return 0;
255362306a36Sopenharmony_ci		if (!port)
255462306a36Sopenharmony_ci			return -EINVAL;
255562306a36Sopenharmony_ci		vlan_del_from_slave(dev, slave, in_param, port);
255662306a36Sopenharmony_ci		__mlx4_unregister_vlan(dev, port, in_param);
255762306a36Sopenharmony_ci		break;
255862306a36Sopenharmony_ci	default:
255962306a36Sopenharmony_ci		err = -EINVAL;
256062306a36Sopenharmony_ci		break;
256162306a36Sopenharmony_ci	}
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ci	return err;
256462306a36Sopenharmony_ci}
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_cistatic int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
256762306a36Sopenharmony_ci			    u64 in_param, u64 *out_param)
256862306a36Sopenharmony_ci{
256962306a36Sopenharmony_ci	int index;
257062306a36Sopenharmony_ci	int err;
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_ci	if (op != RES_OP_RESERVE)
257362306a36Sopenharmony_ci		return -EINVAL;
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	index = get_param_l(&in_param);
257662306a36Sopenharmony_ci	if (index == MLX4_SINK_COUNTER_INDEX(dev))
257762306a36Sopenharmony_ci		return 0;
257862306a36Sopenharmony_ci
257962306a36Sopenharmony_ci	err = rem_res_range(dev, slave, index, 1, RES_COUNTER, 0);
258062306a36Sopenharmony_ci	if (err)
258162306a36Sopenharmony_ci		return err;
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	__mlx4_counter_free(dev, index);
258462306a36Sopenharmony_ci	mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci	return err;
258762306a36Sopenharmony_ci}
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_cistatic int xrcdn_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
259062306a36Sopenharmony_ci			  u64 in_param, u64 *out_param)
259162306a36Sopenharmony_ci{
259262306a36Sopenharmony_ci	int xrcdn;
259362306a36Sopenharmony_ci	int err;
259462306a36Sopenharmony_ci
259562306a36Sopenharmony_ci	if (op != RES_OP_RESERVE)
259662306a36Sopenharmony_ci		return -EINVAL;
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_ci	xrcdn = get_param_l(&in_param);
259962306a36Sopenharmony_ci	err = rem_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0);
260062306a36Sopenharmony_ci	if (err)
260162306a36Sopenharmony_ci		return err;
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci	__mlx4_xrcd_free(dev, xrcdn);
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci	return err;
260662306a36Sopenharmony_ci}
260762306a36Sopenharmony_ci
260862306a36Sopenharmony_ciint mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave,
260962306a36Sopenharmony_ci			  struct mlx4_vhcr *vhcr,
261062306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *inbox,
261162306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *outbox,
261262306a36Sopenharmony_ci			  struct mlx4_cmd_info *cmd)
261362306a36Sopenharmony_ci{
261462306a36Sopenharmony_ci	int err = -EINVAL;
261562306a36Sopenharmony_ci	int alop = vhcr->op_modifier;
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	switch (vhcr->in_modifier & 0xFF) {
261862306a36Sopenharmony_ci	case RES_QP:
261962306a36Sopenharmony_ci		err = qp_free_res(dev, slave, vhcr->op_modifier, alop,
262062306a36Sopenharmony_ci				  vhcr->in_param);
262162306a36Sopenharmony_ci		break;
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci	case RES_MTT:
262462306a36Sopenharmony_ci		err = mtt_free_res(dev, slave, vhcr->op_modifier, alop,
262562306a36Sopenharmony_ci				   vhcr->in_param, &vhcr->out_param);
262662306a36Sopenharmony_ci		break;
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci	case RES_MPT:
262962306a36Sopenharmony_ci		err = mpt_free_res(dev, slave, vhcr->op_modifier, alop,
263062306a36Sopenharmony_ci				   vhcr->in_param);
263162306a36Sopenharmony_ci		break;
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci	case RES_CQ:
263462306a36Sopenharmony_ci		err = cq_free_res(dev, slave, vhcr->op_modifier, alop,
263562306a36Sopenharmony_ci				  vhcr->in_param, &vhcr->out_param);
263662306a36Sopenharmony_ci		break;
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ci	case RES_SRQ:
263962306a36Sopenharmony_ci		err = srq_free_res(dev, slave, vhcr->op_modifier, alop,
264062306a36Sopenharmony_ci				   vhcr->in_param, &vhcr->out_param);
264162306a36Sopenharmony_ci		break;
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci	case RES_MAC:
264462306a36Sopenharmony_ci		err = mac_free_res(dev, slave, vhcr->op_modifier, alop,
264562306a36Sopenharmony_ci				   vhcr->in_param, &vhcr->out_param,
264662306a36Sopenharmony_ci				   (vhcr->in_modifier >> 8) & 0xFF);
264762306a36Sopenharmony_ci		break;
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_ci	case RES_VLAN:
265062306a36Sopenharmony_ci		err = vlan_free_res(dev, slave, vhcr->op_modifier, alop,
265162306a36Sopenharmony_ci				    vhcr->in_param, &vhcr->out_param,
265262306a36Sopenharmony_ci				    (vhcr->in_modifier >> 8) & 0xFF);
265362306a36Sopenharmony_ci		break;
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	case RES_COUNTER:
265662306a36Sopenharmony_ci		err = counter_free_res(dev, slave, vhcr->op_modifier, alop,
265762306a36Sopenharmony_ci				       vhcr->in_param, &vhcr->out_param);
265862306a36Sopenharmony_ci		break;
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci	case RES_XRCD:
266162306a36Sopenharmony_ci		err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop,
266262306a36Sopenharmony_ci				     vhcr->in_param, &vhcr->out_param);
266362306a36Sopenharmony_ci		break;
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci	default:
266662306a36Sopenharmony_ci		break;
266762306a36Sopenharmony_ci	}
266862306a36Sopenharmony_ci	return err;
266962306a36Sopenharmony_ci}
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci/* ugly but other choices are uglier */
267262306a36Sopenharmony_cistatic int mr_phys_mpt(struct mlx4_mpt_entry *mpt)
267362306a36Sopenharmony_ci{
267462306a36Sopenharmony_ci	return (be32_to_cpu(mpt->flags) >> 9) & 1;
267562306a36Sopenharmony_ci}
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_cistatic int mr_get_mtt_addr(struct mlx4_mpt_entry *mpt)
267862306a36Sopenharmony_ci{
267962306a36Sopenharmony_ci	return (int)be64_to_cpu(mpt->mtt_addr) & 0xfffffff8;
268062306a36Sopenharmony_ci}
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_cistatic int mr_get_mtt_size(struct mlx4_mpt_entry *mpt)
268362306a36Sopenharmony_ci{
268462306a36Sopenharmony_ci	return be32_to_cpu(mpt->mtt_sz);
268562306a36Sopenharmony_ci}
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_cistatic u32 mr_get_pd(struct mlx4_mpt_entry *mpt)
268862306a36Sopenharmony_ci{
268962306a36Sopenharmony_ci	return be32_to_cpu(mpt->pd_flags) & 0x00ffffff;
269062306a36Sopenharmony_ci}
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_cistatic int mr_is_fmr(struct mlx4_mpt_entry *mpt)
269362306a36Sopenharmony_ci{
269462306a36Sopenharmony_ci	return be32_to_cpu(mpt->pd_flags) & MLX4_MPT_PD_FLAG_FAST_REG;
269562306a36Sopenharmony_ci}
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_cistatic int mr_is_bind_enabled(struct mlx4_mpt_entry *mpt)
269862306a36Sopenharmony_ci{
269962306a36Sopenharmony_ci	return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_BIND_ENABLE;
270062306a36Sopenharmony_ci}
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_cistatic int mr_is_region(struct mlx4_mpt_entry *mpt)
270362306a36Sopenharmony_ci{
270462306a36Sopenharmony_ci	return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_REGION;
270562306a36Sopenharmony_ci}
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_cistatic int qp_get_mtt_addr(struct mlx4_qp_context *qpc)
270862306a36Sopenharmony_ci{
270962306a36Sopenharmony_ci	return be32_to_cpu(qpc->mtt_base_addr_l) & 0xfffffff8;
271062306a36Sopenharmony_ci}
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_cistatic int srq_get_mtt_addr(struct mlx4_srq_context *srqc)
271362306a36Sopenharmony_ci{
271462306a36Sopenharmony_ci	return be32_to_cpu(srqc->mtt_base_addr_l) & 0xfffffff8;
271562306a36Sopenharmony_ci}
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_cistatic int qp_get_mtt_size(struct mlx4_qp_context *qpc)
271862306a36Sopenharmony_ci{
271962306a36Sopenharmony_ci	int page_shift = (qpc->log_page_size & 0x3f) + 12;
272062306a36Sopenharmony_ci	int log_sq_size = (qpc->sq_size_stride >> 3) & 0xf;
272162306a36Sopenharmony_ci	int log_sq_sride = qpc->sq_size_stride & 7;
272262306a36Sopenharmony_ci	int log_rq_size = (qpc->rq_size_stride >> 3) & 0xf;
272362306a36Sopenharmony_ci	int log_rq_stride = qpc->rq_size_stride & 7;
272462306a36Sopenharmony_ci	int srq = (be32_to_cpu(qpc->srqn) >> 24) & 1;
272562306a36Sopenharmony_ci	int rss = (be32_to_cpu(qpc->flags) >> 13) & 1;
272662306a36Sopenharmony_ci	u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
272762306a36Sopenharmony_ci	int xrc = (ts == MLX4_QP_ST_XRC) ? 1 : 0;
272862306a36Sopenharmony_ci	int sq_size;
272962306a36Sopenharmony_ci	int rq_size;
273062306a36Sopenharmony_ci	int total_pages;
273162306a36Sopenharmony_ci	int total_mem;
273262306a36Sopenharmony_ci	int page_offset = (be32_to_cpu(qpc->params2) >> 6) & 0x3f;
273362306a36Sopenharmony_ci	int tot;
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	sq_size = 1 << (log_sq_size + log_sq_sride + 4);
273662306a36Sopenharmony_ci	rq_size = (srq|rss|xrc) ? 0 : (1 << (log_rq_size + log_rq_stride + 4));
273762306a36Sopenharmony_ci	total_mem = sq_size + rq_size;
273862306a36Sopenharmony_ci	tot = (total_mem + (page_offset << 6)) >> page_shift;
273962306a36Sopenharmony_ci	total_pages = !tot ? 1 : roundup_pow_of_two(tot);
274062306a36Sopenharmony_ci
274162306a36Sopenharmony_ci	return total_pages;
274262306a36Sopenharmony_ci}
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_cistatic int check_mtt_range(struct mlx4_dev *dev, int slave, int start,
274562306a36Sopenharmony_ci			   int size, struct res_mtt *mtt)
274662306a36Sopenharmony_ci{
274762306a36Sopenharmony_ci	int res_start = mtt->com.res_id;
274862306a36Sopenharmony_ci	int res_size = (1 << mtt->order);
274962306a36Sopenharmony_ci
275062306a36Sopenharmony_ci	if (start < res_start || start + size > res_start + res_size)
275162306a36Sopenharmony_ci		return -EPERM;
275262306a36Sopenharmony_ci	return 0;
275362306a36Sopenharmony_ci}
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ciint mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave,
275662306a36Sopenharmony_ci			   struct mlx4_vhcr *vhcr,
275762306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *inbox,
275862306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *outbox,
275962306a36Sopenharmony_ci			   struct mlx4_cmd_info *cmd)
276062306a36Sopenharmony_ci{
276162306a36Sopenharmony_ci	int err;
276262306a36Sopenharmony_ci	int index = vhcr->in_modifier;
276362306a36Sopenharmony_ci	struct res_mtt *mtt;
276462306a36Sopenharmony_ci	struct res_mpt *mpt = NULL;
276562306a36Sopenharmony_ci	int mtt_base = mr_get_mtt_addr(inbox->buf) / dev->caps.mtt_entry_sz;
276662306a36Sopenharmony_ci	int phys;
276762306a36Sopenharmony_ci	int id;
276862306a36Sopenharmony_ci	u32 pd;
276962306a36Sopenharmony_ci	int pd_slave;
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci	id = index & mpt_mask(dev);
277262306a36Sopenharmony_ci	err = mr_res_start_move_to(dev, slave, id, RES_MPT_HW, &mpt);
277362306a36Sopenharmony_ci	if (err)
277462306a36Sopenharmony_ci		return err;
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci	/* Disable memory windows for VFs. */
277762306a36Sopenharmony_ci	if (!mr_is_region(inbox->buf)) {
277862306a36Sopenharmony_ci		err = -EPERM;
277962306a36Sopenharmony_ci		goto ex_abort;
278062306a36Sopenharmony_ci	}
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci	/* Make sure that the PD bits related to the slave id are zeros. */
278362306a36Sopenharmony_ci	pd = mr_get_pd(inbox->buf);
278462306a36Sopenharmony_ci	pd_slave = (pd >> 17) & 0x7f;
278562306a36Sopenharmony_ci	if (pd_slave != 0 && --pd_slave != slave) {
278662306a36Sopenharmony_ci		err = -EPERM;
278762306a36Sopenharmony_ci		goto ex_abort;
278862306a36Sopenharmony_ci	}
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	if (mr_is_fmr(inbox->buf)) {
279162306a36Sopenharmony_ci		/* FMR and Bind Enable are forbidden in slave devices. */
279262306a36Sopenharmony_ci		if (mr_is_bind_enabled(inbox->buf)) {
279362306a36Sopenharmony_ci			err = -EPERM;
279462306a36Sopenharmony_ci			goto ex_abort;
279562306a36Sopenharmony_ci		}
279662306a36Sopenharmony_ci		/* FMR and Memory Windows are also forbidden. */
279762306a36Sopenharmony_ci		if (!mr_is_region(inbox->buf)) {
279862306a36Sopenharmony_ci			err = -EPERM;
279962306a36Sopenharmony_ci			goto ex_abort;
280062306a36Sopenharmony_ci		}
280162306a36Sopenharmony_ci	}
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	phys = mr_phys_mpt(inbox->buf);
280462306a36Sopenharmony_ci	if (!phys) {
280562306a36Sopenharmony_ci		err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);
280662306a36Sopenharmony_ci		if (err)
280762306a36Sopenharmony_ci			goto ex_abort;
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci		err = check_mtt_range(dev, slave, mtt_base,
281062306a36Sopenharmony_ci				      mr_get_mtt_size(inbox->buf), mtt);
281162306a36Sopenharmony_ci		if (err)
281262306a36Sopenharmony_ci			goto ex_put;
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci		mpt->mtt = mtt;
281562306a36Sopenharmony_ci	}
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
281862306a36Sopenharmony_ci	if (err)
281962306a36Sopenharmony_ci		goto ex_put;
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci	if (!phys) {
282262306a36Sopenharmony_ci		atomic_inc(&mtt->ref_count);
282362306a36Sopenharmony_ci		put_res(dev, slave, mtt->com.res_id, RES_MTT);
282462306a36Sopenharmony_ci	}
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	res_end_move(dev, slave, RES_MPT, id);
282762306a36Sopenharmony_ci	return 0;
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ciex_put:
283062306a36Sopenharmony_ci	if (!phys)
283162306a36Sopenharmony_ci		put_res(dev, slave, mtt->com.res_id, RES_MTT);
283262306a36Sopenharmony_ciex_abort:
283362306a36Sopenharmony_ci	res_abort_move(dev, slave, RES_MPT, id);
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci	return err;
283662306a36Sopenharmony_ci}
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ciint mlx4_HW2SW_MPT_wrapper(struct mlx4_dev *dev, int slave,
283962306a36Sopenharmony_ci			   struct mlx4_vhcr *vhcr,
284062306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *inbox,
284162306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *outbox,
284262306a36Sopenharmony_ci			   struct mlx4_cmd_info *cmd)
284362306a36Sopenharmony_ci{
284462306a36Sopenharmony_ci	int err;
284562306a36Sopenharmony_ci	int index = vhcr->in_modifier;
284662306a36Sopenharmony_ci	struct res_mpt *mpt;
284762306a36Sopenharmony_ci	int id;
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_ci	id = index & mpt_mask(dev);
285062306a36Sopenharmony_ci	err = mr_res_start_move_to(dev, slave, id, RES_MPT_MAPPED, &mpt);
285162306a36Sopenharmony_ci	if (err)
285262306a36Sopenharmony_ci		return err;
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
285562306a36Sopenharmony_ci	if (err)
285662306a36Sopenharmony_ci		goto ex_abort;
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci	if (mpt->mtt)
285962306a36Sopenharmony_ci		atomic_dec(&mpt->mtt->ref_count);
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci	res_end_move(dev, slave, RES_MPT, id);
286262306a36Sopenharmony_ci	return 0;
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ciex_abort:
286562306a36Sopenharmony_ci	res_abort_move(dev, slave, RES_MPT, id);
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci	return err;
286862306a36Sopenharmony_ci}
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ciint mlx4_QUERY_MPT_wrapper(struct mlx4_dev *dev, int slave,
287162306a36Sopenharmony_ci			   struct mlx4_vhcr *vhcr,
287262306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *inbox,
287362306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *outbox,
287462306a36Sopenharmony_ci			   struct mlx4_cmd_info *cmd)
287562306a36Sopenharmony_ci{
287662306a36Sopenharmony_ci	int err;
287762306a36Sopenharmony_ci	int index = vhcr->in_modifier;
287862306a36Sopenharmony_ci	struct res_mpt *mpt;
287962306a36Sopenharmony_ci	int id;
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci	id = index & mpt_mask(dev);
288262306a36Sopenharmony_ci	err = get_res(dev, slave, id, RES_MPT, &mpt);
288362306a36Sopenharmony_ci	if (err)
288462306a36Sopenharmony_ci		return err;
288562306a36Sopenharmony_ci
288662306a36Sopenharmony_ci	if (mpt->com.from_state == RES_MPT_MAPPED) {
288762306a36Sopenharmony_ci		/* In order to allow rereg in SRIOV, we need to alter the MPT entry. To do
288862306a36Sopenharmony_ci		 * that, the VF must read the MPT. But since the MPT entry memory is not
288962306a36Sopenharmony_ci		 * in the VF's virtual memory space, it must use QUERY_MPT to obtain the
289062306a36Sopenharmony_ci		 * entry contents. To guarantee that the MPT cannot be changed, the driver
289162306a36Sopenharmony_ci		 * must perform HW2SW_MPT before this query and return the MPT entry to HW
289262306a36Sopenharmony_ci		 * ownership fofollowing the change. The change here allows the VF to
289362306a36Sopenharmony_ci		 * perform QUERY_MPT also when the entry is in SW ownership.
289462306a36Sopenharmony_ci		 */
289562306a36Sopenharmony_ci		struct mlx4_mpt_entry *mpt_entry = mlx4_table_find(
289662306a36Sopenharmony_ci					&mlx4_priv(dev)->mr_table.dmpt_table,
289762306a36Sopenharmony_ci					mpt->key, NULL);
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci		if (NULL == mpt_entry || NULL == outbox->buf) {
290062306a36Sopenharmony_ci			err = -EINVAL;
290162306a36Sopenharmony_ci			goto out;
290262306a36Sopenharmony_ci		}
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci		memcpy(outbox->buf, mpt_entry, sizeof(*mpt_entry));
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci		err = 0;
290762306a36Sopenharmony_ci	} else if (mpt->com.from_state == RES_MPT_HW) {
290862306a36Sopenharmony_ci		err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
290962306a36Sopenharmony_ci	} else {
291062306a36Sopenharmony_ci		err = -EBUSY;
291162306a36Sopenharmony_ci		goto out;
291262306a36Sopenharmony_ci	}
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ciout:
291662306a36Sopenharmony_ci	put_res(dev, slave, id, RES_MPT);
291762306a36Sopenharmony_ci	return err;
291862306a36Sopenharmony_ci}
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_cistatic int qp_get_rcqn(struct mlx4_qp_context *qpc)
292162306a36Sopenharmony_ci{
292262306a36Sopenharmony_ci	return be32_to_cpu(qpc->cqn_recv) & 0xffffff;
292362306a36Sopenharmony_ci}
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_cistatic int qp_get_scqn(struct mlx4_qp_context *qpc)
292662306a36Sopenharmony_ci{
292762306a36Sopenharmony_ci	return be32_to_cpu(qpc->cqn_send) & 0xffffff;
292862306a36Sopenharmony_ci}
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_cistatic u32 qp_get_srqn(struct mlx4_qp_context *qpc)
293162306a36Sopenharmony_ci{
293262306a36Sopenharmony_ci	return be32_to_cpu(qpc->srqn) & 0x1ffffff;
293362306a36Sopenharmony_ci}
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_cistatic void adjust_proxy_tun_qkey(struct mlx4_dev *dev, struct mlx4_vhcr *vhcr,
293662306a36Sopenharmony_ci				  struct mlx4_qp_context *context)
293762306a36Sopenharmony_ci{
293862306a36Sopenharmony_ci	u32 qpn = vhcr->in_modifier & 0xffffff;
293962306a36Sopenharmony_ci	u32 qkey = 0;
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci	if (mlx4_get_parav_qkey(dev, qpn, &qkey))
294262306a36Sopenharmony_ci		return;
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ci	/* adjust qkey in qp context */
294562306a36Sopenharmony_ci	context->qkey = cpu_to_be32(qkey);
294662306a36Sopenharmony_ci}
294762306a36Sopenharmony_ci
294862306a36Sopenharmony_cistatic int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave,
294962306a36Sopenharmony_ci				 struct mlx4_qp_context *qpc,
295062306a36Sopenharmony_ci				 struct mlx4_cmd_mailbox *inbox);
295162306a36Sopenharmony_ci
295262306a36Sopenharmony_ciint mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,
295362306a36Sopenharmony_ci			     struct mlx4_vhcr *vhcr,
295462306a36Sopenharmony_ci			     struct mlx4_cmd_mailbox *inbox,
295562306a36Sopenharmony_ci			     struct mlx4_cmd_mailbox *outbox,
295662306a36Sopenharmony_ci			     struct mlx4_cmd_info *cmd)
295762306a36Sopenharmony_ci{
295862306a36Sopenharmony_ci	int err;
295962306a36Sopenharmony_ci	int qpn = vhcr->in_modifier & 0x7fffff;
296062306a36Sopenharmony_ci	struct res_mtt *mtt;
296162306a36Sopenharmony_ci	struct res_qp *qp;
296262306a36Sopenharmony_ci	struct mlx4_qp_context *qpc = inbox->buf + 8;
296362306a36Sopenharmony_ci	int mtt_base = qp_get_mtt_addr(qpc) / dev->caps.mtt_entry_sz;
296462306a36Sopenharmony_ci	int mtt_size = qp_get_mtt_size(qpc);
296562306a36Sopenharmony_ci	struct res_cq *rcq;
296662306a36Sopenharmony_ci	struct res_cq *scq;
296762306a36Sopenharmony_ci	int rcqn = qp_get_rcqn(qpc);
296862306a36Sopenharmony_ci	int scqn = qp_get_scqn(qpc);
296962306a36Sopenharmony_ci	u32 srqn = qp_get_srqn(qpc) & 0xffffff;
297062306a36Sopenharmony_ci	int use_srq = (qp_get_srqn(qpc) >> 24) & 1;
297162306a36Sopenharmony_ci	struct res_srq *srq;
297262306a36Sopenharmony_ci	int local_qpn = vhcr->in_modifier & 0xffffff;
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	err = adjust_qp_sched_queue(dev, slave, qpc, inbox);
297562306a36Sopenharmony_ci	if (err)
297662306a36Sopenharmony_ci		return err;
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci	err = qp_res_start_move_to(dev, slave, qpn, RES_QP_HW, &qp, 0);
297962306a36Sopenharmony_ci	if (err)
298062306a36Sopenharmony_ci		return err;
298162306a36Sopenharmony_ci	qp->local_qpn = local_qpn;
298262306a36Sopenharmony_ci	qp->sched_queue = 0;
298362306a36Sopenharmony_ci	qp->param3 = 0;
298462306a36Sopenharmony_ci	qp->vlan_control = 0;
298562306a36Sopenharmony_ci	qp->fvl_rx = 0;
298662306a36Sopenharmony_ci	qp->pri_path_fl = 0;
298762306a36Sopenharmony_ci	qp->vlan_index = 0;
298862306a36Sopenharmony_ci	qp->feup = 0;
298962306a36Sopenharmony_ci	qp->qpc_flags = be32_to_cpu(qpc->flags);
299062306a36Sopenharmony_ci
299162306a36Sopenharmony_ci	err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);
299262306a36Sopenharmony_ci	if (err)
299362306a36Sopenharmony_ci		goto ex_abort;
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ci	err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt);
299662306a36Sopenharmony_ci	if (err)
299762306a36Sopenharmony_ci		goto ex_put_mtt;
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_ci	err = get_res(dev, slave, rcqn, RES_CQ, &rcq);
300062306a36Sopenharmony_ci	if (err)
300162306a36Sopenharmony_ci		goto ex_put_mtt;
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_ci	if (scqn != rcqn) {
300462306a36Sopenharmony_ci		err = get_res(dev, slave, scqn, RES_CQ, &scq);
300562306a36Sopenharmony_ci		if (err)
300662306a36Sopenharmony_ci			goto ex_put_rcq;
300762306a36Sopenharmony_ci	} else
300862306a36Sopenharmony_ci		scq = rcq;
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci	if (use_srq) {
301162306a36Sopenharmony_ci		err = get_res(dev, slave, srqn, RES_SRQ, &srq);
301262306a36Sopenharmony_ci		if (err)
301362306a36Sopenharmony_ci			goto ex_put_scq;
301462306a36Sopenharmony_ci	}
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci	adjust_proxy_tun_qkey(dev, vhcr, qpc);
301762306a36Sopenharmony_ci	update_pkey_index(dev, slave, inbox);
301862306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
301962306a36Sopenharmony_ci	if (err)
302062306a36Sopenharmony_ci		goto ex_put_srq;
302162306a36Sopenharmony_ci	atomic_inc(&mtt->ref_count);
302262306a36Sopenharmony_ci	qp->mtt = mtt;
302362306a36Sopenharmony_ci	atomic_inc(&rcq->ref_count);
302462306a36Sopenharmony_ci	qp->rcq = rcq;
302562306a36Sopenharmony_ci	atomic_inc(&scq->ref_count);
302662306a36Sopenharmony_ci	qp->scq = scq;
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci	if (scqn != rcqn)
302962306a36Sopenharmony_ci		put_res(dev, slave, scqn, RES_CQ);
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	if (use_srq) {
303262306a36Sopenharmony_ci		atomic_inc(&srq->ref_count);
303362306a36Sopenharmony_ci		put_res(dev, slave, srqn, RES_SRQ);
303462306a36Sopenharmony_ci		qp->srq = srq;
303562306a36Sopenharmony_ci	}
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci	/* Save param3 for dynamic changes from VST back to VGT */
303862306a36Sopenharmony_ci	qp->param3 = qpc->param3;
303962306a36Sopenharmony_ci	put_res(dev, slave, rcqn, RES_CQ);
304062306a36Sopenharmony_ci	put_res(dev, slave, mtt_base, RES_MTT);
304162306a36Sopenharmony_ci	res_end_move(dev, slave, RES_QP, qpn);
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci	return 0;
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ciex_put_srq:
304662306a36Sopenharmony_ci	if (use_srq)
304762306a36Sopenharmony_ci		put_res(dev, slave, srqn, RES_SRQ);
304862306a36Sopenharmony_ciex_put_scq:
304962306a36Sopenharmony_ci	if (scqn != rcqn)
305062306a36Sopenharmony_ci		put_res(dev, slave, scqn, RES_CQ);
305162306a36Sopenharmony_ciex_put_rcq:
305262306a36Sopenharmony_ci	put_res(dev, slave, rcqn, RES_CQ);
305362306a36Sopenharmony_ciex_put_mtt:
305462306a36Sopenharmony_ci	put_res(dev, slave, mtt_base, RES_MTT);
305562306a36Sopenharmony_ciex_abort:
305662306a36Sopenharmony_ci	res_abort_move(dev, slave, RES_QP, qpn);
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci	return err;
305962306a36Sopenharmony_ci}
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_cistatic int eq_get_mtt_addr(struct mlx4_eq_context *eqc)
306262306a36Sopenharmony_ci{
306362306a36Sopenharmony_ci	return be32_to_cpu(eqc->mtt_base_addr_l) & 0xfffffff8;
306462306a36Sopenharmony_ci}
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_cistatic int eq_get_mtt_size(struct mlx4_eq_context *eqc)
306762306a36Sopenharmony_ci{
306862306a36Sopenharmony_ci	int log_eq_size = eqc->log_eq_size & 0x1f;
306962306a36Sopenharmony_ci	int page_shift = (eqc->log_page_size & 0x3f) + 12;
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci	if (log_eq_size + 5 < page_shift)
307262306a36Sopenharmony_ci		return 1;
307362306a36Sopenharmony_ci
307462306a36Sopenharmony_ci	return 1 << (log_eq_size + 5 - page_shift);
307562306a36Sopenharmony_ci}
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_cistatic int cq_get_mtt_addr(struct mlx4_cq_context *cqc)
307862306a36Sopenharmony_ci{
307962306a36Sopenharmony_ci	return be32_to_cpu(cqc->mtt_base_addr_l) & 0xfffffff8;
308062306a36Sopenharmony_ci}
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_cistatic int cq_get_mtt_size(struct mlx4_cq_context *cqc)
308362306a36Sopenharmony_ci{
308462306a36Sopenharmony_ci	int log_cq_size = (be32_to_cpu(cqc->logsize_usrpage) >> 24) & 0x1f;
308562306a36Sopenharmony_ci	int page_shift = (cqc->log_page_size & 0x3f) + 12;
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci	if (log_cq_size + 5 < page_shift)
308862306a36Sopenharmony_ci		return 1;
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	return 1 << (log_cq_size + 5 - page_shift);
309162306a36Sopenharmony_ci}
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ciint mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave,
309462306a36Sopenharmony_ci			  struct mlx4_vhcr *vhcr,
309562306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *inbox,
309662306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *outbox,
309762306a36Sopenharmony_ci			  struct mlx4_cmd_info *cmd)
309862306a36Sopenharmony_ci{
309962306a36Sopenharmony_ci	int err;
310062306a36Sopenharmony_ci	int eqn = vhcr->in_modifier;
310162306a36Sopenharmony_ci	int res_id = (slave << 10) | eqn;
310262306a36Sopenharmony_ci	struct mlx4_eq_context *eqc = inbox->buf;
310362306a36Sopenharmony_ci	int mtt_base = eq_get_mtt_addr(eqc) / dev->caps.mtt_entry_sz;
310462306a36Sopenharmony_ci	int mtt_size = eq_get_mtt_size(eqc);
310562306a36Sopenharmony_ci	struct res_eq *eq;
310662306a36Sopenharmony_ci	struct res_mtt *mtt;
310762306a36Sopenharmony_ci
310862306a36Sopenharmony_ci	err = add_res_range(dev, slave, res_id, 1, RES_EQ, 0);
310962306a36Sopenharmony_ci	if (err)
311062306a36Sopenharmony_ci		return err;
311162306a36Sopenharmony_ci	err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_HW, &eq);
311262306a36Sopenharmony_ci	if (err)
311362306a36Sopenharmony_ci		goto out_add;
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci	err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);
311662306a36Sopenharmony_ci	if (err)
311762306a36Sopenharmony_ci		goto out_move;
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt);
312062306a36Sopenharmony_ci	if (err)
312162306a36Sopenharmony_ci		goto out_put;
312262306a36Sopenharmony_ci
312362306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
312462306a36Sopenharmony_ci	if (err)
312562306a36Sopenharmony_ci		goto out_put;
312662306a36Sopenharmony_ci
312762306a36Sopenharmony_ci	atomic_inc(&mtt->ref_count);
312862306a36Sopenharmony_ci	eq->mtt = mtt;
312962306a36Sopenharmony_ci	put_res(dev, slave, mtt->com.res_id, RES_MTT);
313062306a36Sopenharmony_ci	res_end_move(dev, slave, RES_EQ, res_id);
313162306a36Sopenharmony_ci	return 0;
313262306a36Sopenharmony_ci
313362306a36Sopenharmony_ciout_put:
313462306a36Sopenharmony_ci	put_res(dev, slave, mtt->com.res_id, RES_MTT);
313562306a36Sopenharmony_ciout_move:
313662306a36Sopenharmony_ci	res_abort_move(dev, slave, RES_EQ, res_id);
313762306a36Sopenharmony_ciout_add:
313862306a36Sopenharmony_ci	rem_res_range(dev, slave, res_id, 1, RES_EQ, 0);
313962306a36Sopenharmony_ci	return err;
314062306a36Sopenharmony_ci}
314162306a36Sopenharmony_ci
314262306a36Sopenharmony_ciint mlx4_CONFIG_DEV_wrapper(struct mlx4_dev *dev, int slave,
314362306a36Sopenharmony_ci			    struct mlx4_vhcr *vhcr,
314462306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *inbox,
314562306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *outbox,
314662306a36Sopenharmony_ci			    struct mlx4_cmd_info *cmd)
314762306a36Sopenharmony_ci{
314862306a36Sopenharmony_ci	int err;
314962306a36Sopenharmony_ci	u8 get = vhcr->op_modifier;
315062306a36Sopenharmony_ci
315162306a36Sopenharmony_ci	if (get != 1)
315262306a36Sopenharmony_ci		return -EPERM;
315362306a36Sopenharmony_ci
315462306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci	return err;
315762306a36Sopenharmony_ci}
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_cistatic int get_containing_mtt(struct mlx4_dev *dev, int slave, int start,
316062306a36Sopenharmony_ci			      int len, struct res_mtt **res)
316162306a36Sopenharmony_ci{
316262306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
316362306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
316462306a36Sopenharmony_ci	struct res_mtt *mtt;
316562306a36Sopenharmony_ci	int err = -EINVAL;
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
316862306a36Sopenharmony_ci	list_for_each_entry(mtt, &tracker->slave_list[slave].res_list[RES_MTT],
316962306a36Sopenharmony_ci			    com.list) {
317062306a36Sopenharmony_ci		if (!check_mtt_range(dev, slave, start, len, mtt)) {
317162306a36Sopenharmony_ci			*res = mtt;
317262306a36Sopenharmony_ci			mtt->com.from_state = mtt->com.state;
317362306a36Sopenharmony_ci			mtt->com.state = RES_MTT_BUSY;
317462306a36Sopenharmony_ci			err = 0;
317562306a36Sopenharmony_ci			break;
317662306a36Sopenharmony_ci		}
317762306a36Sopenharmony_ci	}
317862306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_ci	return err;
318162306a36Sopenharmony_ci}
318262306a36Sopenharmony_ci
318362306a36Sopenharmony_cistatic int verify_qp_parameters(struct mlx4_dev *dev,
318462306a36Sopenharmony_ci				struct mlx4_vhcr *vhcr,
318562306a36Sopenharmony_ci				struct mlx4_cmd_mailbox *inbox,
318662306a36Sopenharmony_ci				enum qp_transition transition, u8 slave)
318762306a36Sopenharmony_ci{
318862306a36Sopenharmony_ci	u32			qp_type;
318962306a36Sopenharmony_ci	u32			qpn;
319062306a36Sopenharmony_ci	struct mlx4_qp_context	*qp_ctx;
319162306a36Sopenharmony_ci	enum mlx4_qp_optpar	optpar;
319262306a36Sopenharmony_ci	int port;
319362306a36Sopenharmony_ci	int num_gids;
319462306a36Sopenharmony_ci
319562306a36Sopenharmony_ci	qp_ctx  = inbox->buf + 8;
319662306a36Sopenharmony_ci	qp_type	= (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;
319762306a36Sopenharmony_ci	optpar	= be32_to_cpu(*(__be32 *) inbox->buf);
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci	if (slave != mlx4_master_func_num(dev)) {
320062306a36Sopenharmony_ci		qp_ctx->params2 &= ~cpu_to_be32(MLX4_QP_BIT_FPP);
320162306a36Sopenharmony_ci		/* setting QP rate-limit is disallowed for VFs */
320262306a36Sopenharmony_ci		if (qp_ctx->rate_limit_params)
320362306a36Sopenharmony_ci			return -EPERM;
320462306a36Sopenharmony_ci	}
320562306a36Sopenharmony_ci
320662306a36Sopenharmony_ci	switch (qp_type) {
320762306a36Sopenharmony_ci	case MLX4_QP_ST_RC:
320862306a36Sopenharmony_ci	case MLX4_QP_ST_XRC:
320962306a36Sopenharmony_ci	case MLX4_QP_ST_UC:
321062306a36Sopenharmony_ci		switch (transition) {
321162306a36Sopenharmony_ci		case QP_TRANS_INIT2RTR:
321262306a36Sopenharmony_ci		case QP_TRANS_RTR2RTS:
321362306a36Sopenharmony_ci		case QP_TRANS_RTS2RTS:
321462306a36Sopenharmony_ci		case QP_TRANS_SQD2SQD:
321562306a36Sopenharmony_ci		case QP_TRANS_SQD2RTS:
321662306a36Sopenharmony_ci			if (slave != mlx4_master_func_num(dev)) {
321762306a36Sopenharmony_ci				if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {
321862306a36Sopenharmony_ci					port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
321962306a36Sopenharmony_ci					if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)
322062306a36Sopenharmony_ci						num_gids = mlx4_get_slave_num_gids(dev, slave, port);
322162306a36Sopenharmony_ci					else
322262306a36Sopenharmony_ci						num_gids = 1;
322362306a36Sopenharmony_ci					if (qp_ctx->pri_path.mgid_index >= num_gids)
322462306a36Sopenharmony_ci						return -EINVAL;
322562306a36Sopenharmony_ci				}
322662306a36Sopenharmony_ci				if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
322762306a36Sopenharmony_ci					port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1;
322862306a36Sopenharmony_ci					if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)
322962306a36Sopenharmony_ci						num_gids = mlx4_get_slave_num_gids(dev, slave, port);
323062306a36Sopenharmony_ci					else
323162306a36Sopenharmony_ci						num_gids = 1;
323262306a36Sopenharmony_ci					if (qp_ctx->alt_path.mgid_index >= num_gids)
323362306a36Sopenharmony_ci						return -EINVAL;
323462306a36Sopenharmony_ci				}
323562306a36Sopenharmony_ci			}
323662306a36Sopenharmony_ci			break;
323762306a36Sopenharmony_ci		default:
323862306a36Sopenharmony_ci			break;
323962306a36Sopenharmony_ci		}
324062306a36Sopenharmony_ci		break;
324162306a36Sopenharmony_ci
324262306a36Sopenharmony_ci	case MLX4_QP_ST_MLX:
324362306a36Sopenharmony_ci		qpn = vhcr->in_modifier & 0x7fffff;
324462306a36Sopenharmony_ci		port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
324562306a36Sopenharmony_ci		if (transition == QP_TRANS_INIT2RTR &&
324662306a36Sopenharmony_ci		    slave != mlx4_master_func_num(dev) &&
324762306a36Sopenharmony_ci		    mlx4_is_qp_reserved(dev, qpn) &&
324862306a36Sopenharmony_ci		    !mlx4_vf_smi_enabled(dev, slave, port)) {
324962306a36Sopenharmony_ci			/* only enabled VFs may create MLX proxy QPs */
325062306a36Sopenharmony_ci			mlx4_err(dev, "%s: unprivileged slave %d attempting to create an MLX proxy special QP on port %d\n",
325162306a36Sopenharmony_ci				 __func__, slave, port);
325262306a36Sopenharmony_ci			return -EPERM;
325362306a36Sopenharmony_ci		}
325462306a36Sopenharmony_ci		break;
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_ci	default:
325762306a36Sopenharmony_ci		break;
325862306a36Sopenharmony_ci	}
325962306a36Sopenharmony_ci
326062306a36Sopenharmony_ci	return 0;
326162306a36Sopenharmony_ci}
326262306a36Sopenharmony_ci
326362306a36Sopenharmony_ciint mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave,
326462306a36Sopenharmony_ci			   struct mlx4_vhcr *vhcr,
326562306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *inbox,
326662306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *outbox,
326762306a36Sopenharmony_ci			   struct mlx4_cmd_info *cmd)
326862306a36Sopenharmony_ci{
326962306a36Sopenharmony_ci	struct mlx4_mtt mtt;
327062306a36Sopenharmony_ci	__be64 *page_list = inbox->buf;
327162306a36Sopenharmony_ci	u64 *pg_list = (u64 *)page_list;
327262306a36Sopenharmony_ci	int i;
327362306a36Sopenharmony_ci	struct res_mtt *rmtt = NULL;
327462306a36Sopenharmony_ci	int start = be64_to_cpu(page_list[0]);
327562306a36Sopenharmony_ci	int npages = vhcr->in_modifier;
327662306a36Sopenharmony_ci	int err;
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci	err = get_containing_mtt(dev, slave, start, npages, &rmtt);
327962306a36Sopenharmony_ci	if (err)
328062306a36Sopenharmony_ci		return err;
328162306a36Sopenharmony_ci
328262306a36Sopenharmony_ci	/* Call the SW implementation of write_mtt:
328362306a36Sopenharmony_ci	 * - Prepare a dummy mtt struct
328462306a36Sopenharmony_ci	 * - Translate inbox contents to simple addresses in host endianness */
328562306a36Sopenharmony_ci	mtt.offset = 0;  /* TBD this is broken but I don't handle it since
328662306a36Sopenharmony_ci			    we don't really use it */
328762306a36Sopenharmony_ci	mtt.order = 0;
328862306a36Sopenharmony_ci	mtt.page_shift = 0;
328962306a36Sopenharmony_ci	for (i = 0; i < npages; ++i)
329062306a36Sopenharmony_ci		pg_list[i + 2] = (be64_to_cpu(page_list[i + 2]) & ~1ULL);
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_ci	err = __mlx4_write_mtt(dev, &mtt, be64_to_cpu(page_list[0]), npages,
329362306a36Sopenharmony_ci			       ((u64 *)page_list + 2));
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	if (rmtt)
329662306a36Sopenharmony_ci		put_res(dev, slave, rmtt->com.res_id, RES_MTT);
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci	return err;
329962306a36Sopenharmony_ci}
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_ciint mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave,
330262306a36Sopenharmony_ci			  struct mlx4_vhcr *vhcr,
330362306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *inbox,
330462306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *outbox,
330562306a36Sopenharmony_ci			  struct mlx4_cmd_info *cmd)
330662306a36Sopenharmony_ci{
330762306a36Sopenharmony_ci	int eqn = vhcr->in_modifier;
330862306a36Sopenharmony_ci	int res_id = eqn | (slave << 10);
330962306a36Sopenharmony_ci	struct res_eq *eq;
331062306a36Sopenharmony_ci	int err;
331162306a36Sopenharmony_ci
331262306a36Sopenharmony_ci	err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_RESERVED, &eq);
331362306a36Sopenharmony_ci	if (err)
331462306a36Sopenharmony_ci		return err;
331562306a36Sopenharmony_ci
331662306a36Sopenharmony_ci	err = get_res(dev, slave, eq->mtt->com.res_id, RES_MTT, NULL);
331762306a36Sopenharmony_ci	if (err)
331862306a36Sopenharmony_ci		goto ex_abort;
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
332162306a36Sopenharmony_ci	if (err)
332262306a36Sopenharmony_ci		goto ex_put;
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_ci	atomic_dec(&eq->mtt->ref_count);
332562306a36Sopenharmony_ci	put_res(dev, slave, eq->mtt->com.res_id, RES_MTT);
332662306a36Sopenharmony_ci	res_end_move(dev, slave, RES_EQ, res_id);
332762306a36Sopenharmony_ci	rem_res_range(dev, slave, res_id, 1, RES_EQ, 0);
332862306a36Sopenharmony_ci
332962306a36Sopenharmony_ci	return 0;
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_ciex_put:
333262306a36Sopenharmony_ci	put_res(dev, slave, eq->mtt->com.res_id, RES_MTT);
333362306a36Sopenharmony_ciex_abort:
333462306a36Sopenharmony_ci	res_abort_move(dev, slave, RES_EQ, res_id);
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci	return err;
333762306a36Sopenharmony_ci}
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ciint mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe)
334062306a36Sopenharmony_ci{
334162306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
334262306a36Sopenharmony_ci	struct mlx4_slave_event_eq_info *event_eq;
334362306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
334462306a36Sopenharmony_ci	u32 in_modifier = 0;
334562306a36Sopenharmony_ci	int err;
334662306a36Sopenharmony_ci	int res_id;
334762306a36Sopenharmony_ci	struct res_eq *req;
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci	if (!priv->mfunc.master.slave_state)
335062306a36Sopenharmony_ci		return -EINVAL;
335162306a36Sopenharmony_ci
335262306a36Sopenharmony_ci	/* check for slave valid, slave not PF, and slave active */
335362306a36Sopenharmony_ci	if (slave < 0 || slave > dev->persist->num_vfs ||
335462306a36Sopenharmony_ci	    slave == dev->caps.function ||
335562306a36Sopenharmony_ci	    !priv->mfunc.master.slave_state[slave].active)
335662306a36Sopenharmony_ci		return 0;
335762306a36Sopenharmony_ci
335862306a36Sopenharmony_ci	event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type];
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci	/* Create the event only if the slave is registered */
336162306a36Sopenharmony_ci	if (event_eq->eqn < 0)
336262306a36Sopenharmony_ci		return 0;
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]);
336562306a36Sopenharmony_ci	res_id = (slave << 10) | event_eq->eqn;
336662306a36Sopenharmony_ci	err = get_res(dev, slave, res_id, RES_EQ, &req);
336762306a36Sopenharmony_ci	if (err)
336862306a36Sopenharmony_ci		goto unlock;
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci	if (req->com.from_state != RES_EQ_HW) {
337162306a36Sopenharmony_ci		err = -EINVAL;
337262306a36Sopenharmony_ci		goto put;
337362306a36Sopenharmony_ci	}
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
337662306a36Sopenharmony_ci	if (IS_ERR(mailbox)) {
337762306a36Sopenharmony_ci		err = PTR_ERR(mailbox);
337862306a36Sopenharmony_ci		goto put;
337962306a36Sopenharmony_ci	}
338062306a36Sopenharmony_ci
338162306a36Sopenharmony_ci	if (eqe->type == MLX4_EVENT_TYPE_CMD) {
338262306a36Sopenharmony_ci		++event_eq->token;
338362306a36Sopenharmony_ci		eqe->event.cmd.token = cpu_to_be16(event_eq->token);
338462306a36Sopenharmony_ci	}
338562306a36Sopenharmony_ci
338662306a36Sopenharmony_ci	memcpy(mailbox->buf, (u8 *) eqe, 28);
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci	in_modifier = (slave & 0xff) | ((event_eq->eqn & 0x3ff) << 16);
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_ci	err = mlx4_cmd(dev, mailbox->dma, in_modifier, 0,
339162306a36Sopenharmony_ci		       MLX4_CMD_GEN_EQE, MLX4_CMD_TIME_CLASS_B,
339262306a36Sopenharmony_ci		       MLX4_CMD_NATIVE);
339362306a36Sopenharmony_ci
339462306a36Sopenharmony_ci	put_res(dev, slave, res_id, RES_EQ);
339562306a36Sopenharmony_ci	mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]);
339662306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
339762306a36Sopenharmony_ci	return err;
339862306a36Sopenharmony_ci
339962306a36Sopenharmony_ciput:
340062306a36Sopenharmony_ci	put_res(dev, slave, res_id, RES_EQ);
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_ciunlock:
340362306a36Sopenharmony_ci	mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]);
340462306a36Sopenharmony_ci	return err;
340562306a36Sopenharmony_ci}
340662306a36Sopenharmony_ci
340762306a36Sopenharmony_ciint mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave,
340862306a36Sopenharmony_ci			  struct mlx4_vhcr *vhcr,
340962306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *inbox,
341062306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *outbox,
341162306a36Sopenharmony_ci			  struct mlx4_cmd_info *cmd)
341262306a36Sopenharmony_ci{
341362306a36Sopenharmony_ci	int eqn = vhcr->in_modifier;
341462306a36Sopenharmony_ci	int res_id = eqn | (slave << 10);
341562306a36Sopenharmony_ci	struct res_eq *eq;
341662306a36Sopenharmony_ci	int err;
341762306a36Sopenharmony_ci
341862306a36Sopenharmony_ci	err = get_res(dev, slave, res_id, RES_EQ, &eq);
341962306a36Sopenharmony_ci	if (err)
342062306a36Sopenharmony_ci		return err;
342162306a36Sopenharmony_ci
342262306a36Sopenharmony_ci	if (eq->com.from_state != RES_EQ_HW) {
342362306a36Sopenharmony_ci		err = -EINVAL;
342462306a36Sopenharmony_ci		goto ex_put;
342562306a36Sopenharmony_ci	}
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ciex_put:
343062306a36Sopenharmony_ci	put_res(dev, slave, res_id, RES_EQ);
343162306a36Sopenharmony_ci	return err;
343262306a36Sopenharmony_ci}
343362306a36Sopenharmony_ci
343462306a36Sopenharmony_ciint mlx4_SW2HW_CQ_wrapper(struct mlx4_dev *dev, int slave,
343562306a36Sopenharmony_ci			  struct mlx4_vhcr *vhcr,
343662306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *inbox,
343762306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *outbox,
343862306a36Sopenharmony_ci			  struct mlx4_cmd_info *cmd)
343962306a36Sopenharmony_ci{
344062306a36Sopenharmony_ci	int err;
344162306a36Sopenharmony_ci	int cqn = vhcr->in_modifier;
344262306a36Sopenharmony_ci	struct mlx4_cq_context *cqc = inbox->buf;
344362306a36Sopenharmony_ci	int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz;
344462306a36Sopenharmony_ci	struct res_cq *cq = NULL;
344562306a36Sopenharmony_ci	struct res_mtt *mtt;
344662306a36Sopenharmony_ci
344762306a36Sopenharmony_ci	err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_HW, &cq);
344862306a36Sopenharmony_ci	if (err)
344962306a36Sopenharmony_ci		return err;
345062306a36Sopenharmony_ci	err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);
345162306a36Sopenharmony_ci	if (err)
345262306a36Sopenharmony_ci		goto out_move;
345362306a36Sopenharmony_ci	err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt);
345462306a36Sopenharmony_ci	if (err)
345562306a36Sopenharmony_ci		goto out_put;
345662306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
345762306a36Sopenharmony_ci	if (err)
345862306a36Sopenharmony_ci		goto out_put;
345962306a36Sopenharmony_ci	atomic_inc(&mtt->ref_count);
346062306a36Sopenharmony_ci	cq->mtt = mtt;
346162306a36Sopenharmony_ci	put_res(dev, slave, mtt->com.res_id, RES_MTT);
346262306a36Sopenharmony_ci	res_end_move(dev, slave, RES_CQ, cqn);
346362306a36Sopenharmony_ci	return 0;
346462306a36Sopenharmony_ci
346562306a36Sopenharmony_ciout_put:
346662306a36Sopenharmony_ci	put_res(dev, slave, mtt->com.res_id, RES_MTT);
346762306a36Sopenharmony_ciout_move:
346862306a36Sopenharmony_ci	res_abort_move(dev, slave, RES_CQ, cqn);
346962306a36Sopenharmony_ci	return err;
347062306a36Sopenharmony_ci}
347162306a36Sopenharmony_ci
347262306a36Sopenharmony_ciint mlx4_HW2SW_CQ_wrapper(struct mlx4_dev *dev, int slave,
347362306a36Sopenharmony_ci			  struct mlx4_vhcr *vhcr,
347462306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *inbox,
347562306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *outbox,
347662306a36Sopenharmony_ci			  struct mlx4_cmd_info *cmd)
347762306a36Sopenharmony_ci{
347862306a36Sopenharmony_ci	int err;
347962306a36Sopenharmony_ci	int cqn = vhcr->in_modifier;
348062306a36Sopenharmony_ci	struct res_cq *cq = NULL;
348162306a36Sopenharmony_ci
348262306a36Sopenharmony_ci	err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_ALLOCATED, &cq);
348362306a36Sopenharmony_ci	if (err)
348462306a36Sopenharmony_ci		return err;
348562306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
348662306a36Sopenharmony_ci	if (err)
348762306a36Sopenharmony_ci		goto out_move;
348862306a36Sopenharmony_ci	atomic_dec(&cq->mtt->ref_count);
348962306a36Sopenharmony_ci	res_end_move(dev, slave, RES_CQ, cqn);
349062306a36Sopenharmony_ci	return 0;
349162306a36Sopenharmony_ci
349262306a36Sopenharmony_ciout_move:
349362306a36Sopenharmony_ci	res_abort_move(dev, slave, RES_CQ, cqn);
349462306a36Sopenharmony_ci	return err;
349562306a36Sopenharmony_ci}
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ciint mlx4_QUERY_CQ_wrapper(struct mlx4_dev *dev, int slave,
349862306a36Sopenharmony_ci			  struct mlx4_vhcr *vhcr,
349962306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *inbox,
350062306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *outbox,
350162306a36Sopenharmony_ci			  struct mlx4_cmd_info *cmd)
350262306a36Sopenharmony_ci{
350362306a36Sopenharmony_ci	int cqn = vhcr->in_modifier;
350462306a36Sopenharmony_ci	struct res_cq *cq;
350562306a36Sopenharmony_ci	int err;
350662306a36Sopenharmony_ci
350762306a36Sopenharmony_ci	err = get_res(dev, slave, cqn, RES_CQ, &cq);
350862306a36Sopenharmony_ci	if (err)
350962306a36Sopenharmony_ci		return err;
351062306a36Sopenharmony_ci
351162306a36Sopenharmony_ci	if (cq->com.from_state != RES_CQ_HW)
351262306a36Sopenharmony_ci		goto ex_put;
351362306a36Sopenharmony_ci
351462306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
351562306a36Sopenharmony_ciex_put:
351662306a36Sopenharmony_ci	put_res(dev, slave, cqn, RES_CQ);
351762306a36Sopenharmony_ci
351862306a36Sopenharmony_ci	return err;
351962306a36Sopenharmony_ci}
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_cistatic int handle_resize(struct mlx4_dev *dev, int slave,
352262306a36Sopenharmony_ci			 struct mlx4_vhcr *vhcr,
352362306a36Sopenharmony_ci			 struct mlx4_cmd_mailbox *inbox,
352462306a36Sopenharmony_ci			 struct mlx4_cmd_mailbox *outbox,
352562306a36Sopenharmony_ci			 struct mlx4_cmd_info *cmd,
352662306a36Sopenharmony_ci			 struct res_cq *cq)
352762306a36Sopenharmony_ci{
352862306a36Sopenharmony_ci	int err;
352962306a36Sopenharmony_ci	struct res_mtt *orig_mtt;
353062306a36Sopenharmony_ci	struct res_mtt *mtt;
353162306a36Sopenharmony_ci	struct mlx4_cq_context *cqc = inbox->buf;
353262306a36Sopenharmony_ci	int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz;
353362306a36Sopenharmony_ci
353462306a36Sopenharmony_ci	err = get_res(dev, slave, cq->mtt->com.res_id, RES_MTT, &orig_mtt);
353562306a36Sopenharmony_ci	if (err)
353662306a36Sopenharmony_ci		return err;
353762306a36Sopenharmony_ci
353862306a36Sopenharmony_ci	if (orig_mtt != cq->mtt) {
353962306a36Sopenharmony_ci		err = -EINVAL;
354062306a36Sopenharmony_ci		goto ex_put;
354162306a36Sopenharmony_ci	}
354262306a36Sopenharmony_ci
354362306a36Sopenharmony_ci	err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);
354462306a36Sopenharmony_ci	if (err)
354562306a36Sopenharmony_ci		goto ex_put;
354662306a36Sopenharmony_ci
354762306a36Sopenharmony_ci	err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt);
354862306a36Sopenharmony_ci	if (err)
354962306a36Sopenharmony_ci		goto ex_put1;
355062306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
355162306a36Sopenharmony_ci	if (err)
355262306a36Sopenharmony_ci		goto ex_put1;
355362306a36Sopenharmony_ci	atomic_dec(&orig_mtt->ref_count);
355462306a36Sopenharmony_ci	put_res(dev, slave, orig_mtt->com.res_id, RES_MTT);
355562306a36Sopenharmony_ci	atomic_inc(&mtt->ref_count);
355662306a36Sopenharmony_ci	cq->mtt = mtt;
355762306a36Sopenharmony_ci	put_res(dev, slave, mtt->com.res_id, RES_MTT);
355862306a36Sopenharmony_ci	return 0;
355962306a36Sopenharmony_ci
356062306a36Sopenharmony_ciex_put1:
356162306a36Sopenharmony_ci	put_res(dev, slave, mtt->com.res_id, RES_MTT);
356262306a36Sopenharmony_ciex_put:
356362306a36Sopenharmony_ci	put_res(dev, slave, orig_mtt->com.res_id, RES_MTT);
356462306a36Sopenharmony_ci
356562306a36Sopenharmony_ci	return err;
356662306a36Sopenharmony_ci
356762306a36Sopenharmony_ci}
356862306a36Sopenharmony_ci
356962306a36Sopenharmony_ciint mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave,
357062306a36Sopenharmony_ci			   struct mlx4_vhcr *vhcr,
357162306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *inbox,
357262306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *outbox,
357362306a36Sopenharmony_ci			   struct mlx4_cmd_info *cmd)
357462306a36Sopenharmony_ci{
357562306a36Sopenharmony_ci	int cqn = vhcr->in_modifier;
357662306a36Sopenharmony_ci	struct res_cq *cq;
357762306a36Sopenharmony_ci	int err;
357862306a36Sopenharmony_ci
357962306a36Sopenharmony_ci	err = get_res(dev, slave, cqn, RES_CQ, &cq);
358062306a36Sopenharmony_ci	if (err)
358162306a36Sopenharmony_ci		return err;
358262306a36Sopenharmony_ci
358362306a36Sopenharmony_ci	if (cq->com.from_state != RES_CQ_HW)
358462306a36Sopenharmony_ci		goto ex_put;
358562306a36Sopenharmony_ci
358662306a36Sopenharmony_ci	if (vhcr->op_modifier == 0) {
358762306a36Sopenharmony_ci		err = handle_resize(dev, slave, vhcr, inbox, outbox, cmd, cq);
358862306a36Sopenharmony_ci		goto ex_put;
358962306a36Sopenharmony_ci	}
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
359262306a36Sopenharmony_ciex_put:
359362306a36Sopenharmony_ci	put_res(dev, slave, cqn, RES_CQ);
359462306a36Sopenharmony_ci
359562306a36Sopenharmony_ci	return err;
359662306a36Sopenharmony_ci}
359762306a36Sopenharmony_ci
359862306a36Sopenharmony_cistatic int srq_get_mtt_size(struct mlx4_srq_context *srqc)
359962306a36Sopenharmony_ci{
360062306a36Sopenharmony_ci	int log_srq_size = (be32_to_cpu(srqc->state_logsize_srqn) >> 24) & 0xf;
360162306a36Sopenharmony_ci	int log_rq_stride = srqc->logstride & 7;
360262306a36Sopenharmony_ci	int page_shift = (srqc->log_page_size & 0x3f) + 12;
360362306a36Sopenharmony_ci
360462306a36Sopenharmony_ci	if (log_srq_size + log_rq_stride + 4 < page_shift)
360562306a36Sopenharmony_ci		return 1;
360662306a36Sopenharmony_ci
360762306a36Sopenharmony_ci	return 1 << (log_srq_size + log_rq_stride + 4 - page_shift);
360862306a36Sopenharmony_ci}
360962306a36Sopenharmony_ci
361062306a36Sopenharmony_ciint mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave,
361162306a36Sopenharmony_ci			   struct mlx4_vhcr *vhcr,
361262306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *inbox,
361362306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *outbox,
361462306a36Sopenharmony_ci			   struct mlx4_cmd_info *cmd)
361562306a36Sopenharmony_ci{
361662306a36Sopenharmony_ci	int err;
361762306a36Sopenharmony_ci	int srqn = vhcr->in_modifier;
361862306a36Sopenharmony_ci	struct res_mtt *mtt;
361962306a36Sopenharmony_ci	struct res_srq *srq = NULL;
362062306a36Sopenharmony_ci	struct mlx4_srq_context *srqc = inbox->buf;
362162306a36Sopenharmony_ci	int mtt_base = srq_get_mtt_addr(srqc) / dev->caps.mtt_entry_sz;
362262306a36Sopenharmony_ci
362362306a36Sopenharmony_ci	if (srqn != (be32_to_cpu(srqc->state_logsize_srqn) & 0xffffff))
362462306a36Sopenharmony_ci		return -EINVAL;
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_ci	err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_HW, &srq);
362762306a36Sopenharmony_ci	if (err)
362862306a36Sopenharmony_ci		return err;
362962306a36Sopenharmony_ci	err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);
363062306a36Sopenharmony_ci	if (err)
363162306a36Sopenharmony_ci		goto ex_abort;
363262306a36Sopenharmony_ci	err = check_mtt_range(dev, slave, mtt_base, srq_get_mtt_size(srqc),
363362306a36Sopenharmony_ci			      mtt);
363462306a36Sopenharmony_ci	if (err)
363562306a36Sopenharmony_ci		goto ex_put_mtt;
363662306a36Sopenharmony_ci
363762306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
363862306a36Sopenharmony_ci	if (err)
363962306a36Sopenharmony_ci		goto ex_put_mtt;
364062306a36Sopenharmony_ci
364162306a36Sopenharmony_ci	atomic_inc(&mtt->ref_count);
364262306a36Sopenharmony_ci	srq->mtt = mtt;
364362306a36Sopenharmony_ci	put_res(dev, slave, mtt->com.res_id, RES_MTT);
364462306a36Sopenharmony_ci	res_end_move(dev, slave, RES_SRQ, srqn);
364562306a36Sopenharmony_ci	return 0;
364662306a36Sopenharmony_ci
364762306a36Sopenharmony_ciex_put_mtt:
364862306a36Sopenharmony_ci	put_res(dev, slave, mtt->com.res_id, RES_MTT);
364962306a36Sopenharmony_ciex_abort:
365062306a36Sopenharmony_ci	res_abort_move(dev, slave, RES_SRQ, srqn);
365162306a36Sopenharmony_ci
365262306a36Sopenharmony_ci	return err;
365362306a36Sopenharmony_ci}
365462306a36Sopenharmony_ci
365562306a36Sopenharmony_ciint mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev *dev, int slave,
365662306a36Sopenharmony_ci			   struct mlx4_vhcr *vhcr,
365762306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *inbox,
365862306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *outbox,
365962306a36Sopenharmony_ci			   struct mlx4_cmd_info *cmd)
366062306a36Sopenharmony_ci{
366162306a36Sopenharmony_ci	int err;
366262306a36Sopenharmony_ci	int srqn = vhcr->in_modifier;
366362306a36Sopenharmony_ci	struct res_srq *srq = NULL;
366462306a36Sopenharmony_ci
366562306a36Sopenharmony_ci	err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_ALLOCATED, &srq);
366662306a36Sopenharmony_ci	if (err)
366762306a36Sopenharmony_ci		return err;
366862306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
366962306a36Sopenharmony_ci	if (err)
367062306a36Sopenharmony_ci		goto ex_abort;
367162306a36Sopenharmony_ci	atomic_dec(&srq->mtt->ref_count);
367262306a36Sopenharmony_ci	if (srq->cq)
367362306a36Sopenharmony_ci		atomic_dec(&srq->cq->ref_count);
367462306a36Sopenharmony_ci	res_end_move(dev, slave, RES_SRQ, srqn);
367562306a36Sopenharmony_ci
367662306a36Sopenharmony_ci	return 0;
367762306a36Sopenharmony_ci
367862306a36Sopenharmony_ciex_abort:
367962306a36Sopenharmony_ci	res_abort_move(dev, slave, RES_SRQ, srqn);
368062306a36Sopenharmony_ci
368162306a36Sopenharmony_ci	return err;
368262306a36Sopenharmony_ci}
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_ciint mlx4_QUERY_SRQ_wrapper(struct mlx4_dev *dev, int slave,
368562306a36Sopenharmony_ci			   struct mlx4_vhcr *vhcr,
368662306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *inbox,
368762306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *outbox,
368862306a36Sopenharmony_ci			   struct mlx4_cmd_info *cmd)
368962306a36Sopenharmony_ci{
369062306a36Sopenharmony_ci	int err;
369162306a36Sopenharmony_ci	int srqn = vhcr->in_modifier;
369262306a36Sopenharmony_ci	struct res_srq *srq;
369362306a36Sopenharmony_ci
369462306a36Sopenharmony_ci	err = get_res(dev, slave, srqn, RES_SRQ, &srq);
369562306a36Sopenharmony_ci	if (err)
369662306a36Sopenharmony_ci		return err;
369762306a36Sopenharmony_ci	if (srq->com.from_state != RES_SRQ_HW) {
369862306a36Sopenharmony_ci		err = -EBUSY;
369962306a36Sopenharmony_ci		goto out;
370062306a36Sopenharmony_ci	}
370162306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
370262306a36Sopenharmony_ciout:
370362306a36Sopenharmony_ci	put_res(dev, slave, srqn, RES_SRQ);
370462306a36Sopenharmony_ci	return err;
370562306a36Sopenharmony_ci}
370662306a36Sopenharmony_ci
370762306a36Sopenharmony_ciint mlx4_ARM_SRQ_wrapper(struct mlx4_dev *dev, int slave,
370862306a36Sopenharmony_ci			 struct mlx4_vhcr *vhcr,
370962306a36Sopenharmony_ci			 struct mlx4_cmd_mailbox *inbox,
371062306a36Sopenharmony_ci			 struct mlx4_cmd_mailbox *outbox,
371162306a36Sopenharmony_ci			 struct mlx4_cmd_info *cmd)
371262306a36Sopenharmony_ci{
371362306a36Sopenharmony_ci	int err;
371462306a36Sopenharmony_ci	int srqn = vhcr->in_modifier;
371562306a36Sopenharmony_ci	struct res_srq *srq;
371662306a36Sopenharmony_ci
371762306a36Sopenharmony_ci	err = get_res(dev, slave, srqn, RES_SRQ, &srq);
371862306a36Sopenharmony_ci	if (err)
371962306a36Sopenharmony_ci		return err;
372062306a36Sopenharmony_ci
372162306a36Sopenharmony_ci	if (srq->com.from_state != RES_SRQ_HW) {
372262306a36Sopenharmony_ci		err = -EBUSY;
372362306a36Sopenharmony_ci		goto out;
372462306a36Sopenharmony_ci	}
372562306a36Sopenharmony_ci
372662306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
372762306a36Sopenharmony_ciout:
372862306a36Sopenharmony_ci	put_res(dev, slave, srqn, RES_SRQ);
372962306a36Sopenharmony_ci	return err;
373062306a36Sopenharmony_ci}
373162306a36Sopenharmony_ci
373262306a36Sopenharmony_ciint mlx4_GEN_QP_wrapper(struct mlx4_dev *dev, int slave,
373362306a36Sopenharmony_ci			struct mlx4_vhcr *vhcr,
373462306a36Sopenharmony_ci			struct mlx4_cmd_mailbox *inbox,
373562306a36Sopenharmony_ci			struct mlx4_cmd_mailbox *outbox,
373662306a36Sopenharmony_ci			struct mlx4_cmd_info *cmd)
373762306a36Sopenharmony_ci{
373862306a36Sopenharmony_ci	int err;
373962306a36Sopenharmony_ci	int qpn = vhcr->in_modifier & 0x7fffff;
374062306a36Sopenharmony_ci	struct res_qp *qp;
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_ci	err = get_res(dev, slave, qpn, RES_QP, &qp);
374362306a36Sopenharmony_ci	if (err)
374462306a36Sopenharmony_ci		return err;
374562306a36Sopenharmony_ci	if (qp->com.from_state != RES_QP_HW) {
374662306a36Sopenharmony_ci		err = -EBUSY;
374762306a36Sopenharmony_ci		goto out;
374862306a36Sopenharmony_ci	}
374962306a36Sopenharmony_ci
375062306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
375162306a36Sopenharmony_ciout:
375262306a36Sopenharmony_ci	put_res(dev, slave, qpn, RES_QP);
375362306a36Sopenharmony_ci	return err;
375462306a36Sopenharmony_ci}
375562306a36Sopenharmony_ci
375662306a36Sopenharmony_ciint mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,
375762306a36Sopenharmony_ci			      struct mlx4_vhcr *vhcr,
375862306a36Sopenharmony_ci			      struct mlx4_cmd_mailbox *inbox,
375962306a36Sopenharmony_ci			      struct mlx4_cmd_mailbox *outbox,
376062306a36Sopenharmony_ci			      struct mlx4_cmd_info *cmd)
376162306a36Sopenharmony_ci{
376262306a36Sopenharmony_ci	struct mlx4_qp_context *context = inbox->buf + 8;
376362306a36Sopenharmony_ci	adjust_proxy_tun_qkey(dev, vhcr, context);
376462306a36Sopenharmony_ci	update_pkey_index(dev, slave, inbox);
376562306a36Sopenharmony_ci	return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
376662306a36Sopenharmony_ci}
376762306a36Sopenharmony_ci
376862306a36Sopenharmony_cistatic int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave,
376962306a36Sopenharmony_ci				  struct mlx4_qp_context *qpc,
377062306a36Sopenharmony_ci				  struct mlx4_cmd_mailbox *inbox)
377162306a36Sopenharmony_ci{
377262306a36Sopenharmony_ci	enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *)inbox->buf);
377362306a36Sopenharmony_ci	u8 pri_sched_queue;
377462306a36Sopenharmony_ci	int port = mlx4_slave_convert_port(
377562306a36Sopenharmony_ci		   dev, slave, (qpc->pri_path.sched_queue >> 6 & 1) + 1) - 1;
377662306a36Sopenharmony_ci
377762306a36Sopenharmony_ci	if (port < 0)
377862306a36Sopenharmony_ci		return -EINVAL;
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_ci	pri_sched_queue = (qpc->pri_path.sched_queue & ~(1 << 6)) |
378162306a36Sopenharmony_ci			  ((port & 1) << 6);
378262306a36Sopenharmony_ci
378362306a36Sopenharmony_ci	if (optpar & (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH | MLX4_QP_OPTPAR_SCHED_QUEUE) ||
378462306a36Sopenharmony_ci	    qpc->pri_path.sched_queue || mlx4_is_eth(dev, port + 1)) {
378562306a36Sopenharmony_ci		qpc->pri_path.sched_queue = pri_sched_queue;
378662306a36Sopenharmony_ci	}
378762306a36Sopenharmony_ci
378862306a36Sopenharmony_ci	if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
378962306a36Sopenharmony_ci		port = mlx4_slave_convert_port(
379062306a36Sopenharmony_ci				dev, slave, (qpc->alt_path.sched_queue >> 6 & 1)
379162306a36Sopenharmony_ci				+ 1) - 1;
379262306a36Sopenharmony_ci		if (port < 0)
379362306a36Sopenharmony_ci			return -EINVAL;
379462306a36Sopenharmony_ci		qpc->alt_path.sched_queue =
379562306a36Sopenharmony_ci			(qpc->alt_path.sched_queue & ~(1 << 6)) |
379662306a36Sopenharmony_ci			(port & 1) << 6;
379762306a36Sopenharmony_ci	}
379862306a36Sopenharmony_ci	return 0;
379962306a36Sopenharmony_ci}
380062306a36Sopenharmony_ci
380162306a36Sopenharmony_cistatic int roce_verify_mac(struct mlx4_dev *dev, int slave,
380262306a36Sopenharmony_ci				struct mlx4_qp_context *qpc,
380362306a36Sopenharmony_ci				struct mlx4_cmd_mailbox *inbox)
380462306a36Sopenharmony_ci{
380562306a36Sopenharmony_ci	u64 mac;
380662306a36Sopenharmony_ci	int port;
380762306a36Sopenharmony_ci	u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
380862306a36Sopenharmony_ci	u8 sched = *(u8 *)(inbox->buf + 64);
380962306a36Sopenharmony_ci	u8 smac_ix;
381062306a36Sopenharmony_ci
381162306a36Sopenharmony_ci	port = (sched >> 6 & 1) + 1;
381262306a36Sopenharmony_ci	if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) {
381362306a36Sopenharmony_ci		smac_ix = qpc->pri_path.grh_mylmc & 0x7f;
381462306a36Sopenharmony_ci		if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac))
381562306a36Sopenharmony_ci			return -ENOENT;
381662306a36Sopenharmony_ci	}
381762306a36Sopenharmony_ci	return 0;
381862306a36Sopenharmony_ci}
381962306a36Sopenharmony_ci
382062306a36Sopenharmony_ciint mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
382162306a36Sopenharmony_ci			     struct mlx4_vhcr *vhcr,
382262306a36Sopenharmony_ci			     struct mlx4_cmd_mailbox *inbox,
382362306a36Sopenharmony_ci			     struct mlx4_cmd_mailbox *outbox,
382462306a36Sopenharmony_ci			     struct mlx4_cmd_info *cmd)
382562306a36Sopenharmony_ci{
382662306a36Sopenharmony_ci	int err;
382762306a36Sopenharmony_ci	struct mlx4_qp_context *qpc = inbox->buf + 8;
382862306a36Sopenharmony_ci	int qpn = vhcr->in_modifier & 0x7fffff;
382962306a36Sopenharmony_ci	struct res_qp *qp;
383062306a36Sopenharmony_ci	u8 orig_sched_queue;
383162306a36Sopenharmony_ci	u8 orig_vlan_control = qpc->pri_path.vlan_control;
383262306a36Sopenharmony_ci	u8 orig_fvl_rx = qpc->pri_path.fvl_rx;
383362306a36Sopenharmony_ci	u8 orig_pri_path_fl = qpc->pri_path.fl;
383462306a36Sopenharmony_ci	u8 orig_vlan_index = qpc->pri_path.vlan_index;
383562306a36Sopenharmony_ci	u8 orig_feup = qpc->pri_path.feup;
383662306a36Sopenharmony_ci
383762306a36Sopenharmony_ci	err = adjust_qp_sched_queue(dev, slave, qpc, inbox);
383862306a36Sopenharmony_ci	if (err)
383962306a36Sopenharmony_ci		return err;
384062306a36Sopenharmony_ci	err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_INIT2RTR, slave);
384162306a36Sopenharmony_ci	if (err)
384262306a36Sopenharmony_ci		return err;
384362306a36Sopenharmony_ci
384462306a36Sopenharmony_ci	if (roce_verify_mac(dev, slave, qpc, inbox))
384562306a36Sopenharmony_ci		return -EINVAL;
384662306a36Sopenharmony_ci
384762306a36Sopenharmony_ci	update_pkey_index(dev, slave, inbox);
384862306a36Sopenharmony_ci	update_gid(dev, inbox, (u8)slave);
384962306a36Sopenharmony_ci	adjust_proxy_tun_qkey(dev, vhcr, qpc);
385062306a36Sopenharmony_ci	orig_sched_queue = qpc->pri_path.sched_queue;
385162306a36Sopenharmony_ci
385262306a36Sopenharmony_ci	err = get_res(dev, slave, qpn, RES_QP, &qp);
385362306a36Sopenharmony_ci	if (err)
385462306a36Sopenharmony_ci		return err;
385562306a36Sopenharmony_ci	if (qp->com.from_state != RES_QP_HW) {
385662306a36Sopenharmony_ci		err = -EBUSY;
385762306a36Sopenharmony_ci		goto out;
385862306a36Sopenharmony_ci	}
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci	err = update_vport_qp_param(dev, inbox, slave, qpn);
386162306a36Sopenharmony_ci	if (err)
386262306a36Sopenharmony_ci		goto out;
386362306a36Sopenharmony_ci
386462306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
386562306a36Sopenharmony_ciout:
386662306a36Sopenharmony_ci	/* if no error, save sched queue value passed in by VF. This is
386762306a36Sopenharmony_ci	 * essentially the QOS value provided by the VF. This will be useful
386862306a36Sopenharmony_ci	 * if we allow dynamic changes from VST back to VGT
386962306a36Sopenharmony_ci	 */
387062306a36Sopenharmony_ci	if (!err) {
387162306a36Sopenharmony_ci		qp->sched_queue = orig_sched_queue;
387262306a36Sopenharmony_ci		qp->vlan_control = orig_vlan_control;
387362306a36Sopenharmony_ci		qp->fvl_rx	=  orig_fvl_rx;
387462306a36Sopenharmony_ci		qp->pri_path_fl = orig_pri_path_fl;
387562306a36Sopenharmony_ci		qp->vlan_index  = orig_vlan_index;
387662306a36Sopenharmony_ci		qp->feup	= orig_feup;
387762306a36Sopenharmony_ci	}
387862306a36Sopenharmony_ci	put_res(dev, slave, qpn, RES_QP);
387962306a36Sopenharmony_ci	return err;
388062306a36Sopenharmony_ci}
388162306a36Sopenharmony_ci
388262306a36Sopenharmony_ciint mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
388362306a36Sopenharmony_ci			    struct mlx4_vhcr *vhcr,
388462306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *inbox,
388562306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *outbox,
388662306a36Sopenharmony_ci			    struct mlx4_cmd_info *cmd)
388762306a36Sopenharmony_ci{
388862306a36Sopenharmony_ci	int err;
388962306a36Sopenharmony_ci	struct mlx4_qp_context *context = inbox->buf + 8;
389062306a36Sopenharmony_ci
389162306a36Sopenharmony_ci	err = adjust_qp_sched_queue(dev, slave, context, inbox);
389262306a36Sopenharmony_ci	if (err)
389362306a36Sopenharmony_ci		return err;
389462306a36Sopenharmony_ci	err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTR2RTS, slave);
389562306a36Sopenharmony_ci	if (err)
389662306a36Sopenharmony_ci		return err;
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci	update_pkey_index(dev, slave, inbox);
389962306a36Sopenharmony_ci	update_gid(dev, inbox, (u8)slave);
390062306a36Sopenharmony_ci	adjust_proxy_tun_qkey(dev, vhcr, context);
390162306a36Sopenharmony_ci	return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
390262306a36Sopenharmony_ci}
390362306a36Sopenharmony_ci
390462306a36Sopenharmony_ciint mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
390562306a36Sopenharmony_ci			    struct mlx4_vhcr *vhcr,
390662306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *inbox,
390762306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *outbox,
390862306a36Sopenharmony_ci			    struct mlx4_cmd_info *cmd)
390962306a36Sopenharmony_ci{
391062306a36Sopenharmony_ci	int err;
391162306a36Sopenharmony_ci	struct mlx4_qp_context *context = inbox->buf + 8;
391262306a36Sopenharmony_ci
391362306a36Sopenharmony_ci	err = adjust_qp_sched_queue(dev, slave, context, inbox);
391462306a36Sopenharmony_ci	if (err)
391562306a36Sopenharmony_ci		return err;
391662306a36Sopenharmony_ci	err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTS2RTS, slave);
391762306a36Sopenharmony_ci	if (err)
391862306a36Sopenharmony_ci		return err;
391962306a36Sopenharmony_ci
392062306a36Sopenharmony_ci	update_pkey_index(dev, slave, inbox);
392162306a36Sopenharmony_ci	update_gid(dev, inbox, (u8)slave);
392262306a36Sopenharmony_ci	adjust_proxy_tun_qkey(dev, vhcr, context);
392362306a36Sopenharmony_ci	return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
392462306a36Sopenharmony_ci}
392562306a36Sopenharmony_ci
392662306a36Sopenharmony_ci
392762306a36Sopenharmony_ciint mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
392862306a36Sopenharmony_ci			      struct mlx4_vhcr *vhcr,
392962306a36Sopenharmony_ci			      struct mlx4_cmd_mailbox *inbox,
393062306a36Sopenharmony_ci			      struct mlx4_cmd_mailbox *outbox,
393162306a36Sopenharmony_ci			      struct mlx4_cmd_info *cmd)
393262306a36Sopenharmony_ci{
393362306a36Sopenharmony_ci	struct mlx4_qp_context *context = inbox->buf + 8;
393462306a36Sopenharmony_ci	int err = adjust_qp_sched_queue(dev, slave, context, inbox);
393562306a36Sopenharmony_ci	if (err)
393662306a36Sopenharmony_ci		return err;
393762306a36Sopenharmony_ci	adjust_proxy_tun_qkey(dev, vhcr, context);
393862306a36Sopenharmony_ci	return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
393962306a36Sopenharmony_ci}
394062306a36Sopenharmony_ci
394162306a36Sopenharmony_ciint mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave,
394262306a36Sopenharmony_ci			    struct mlx4_vhcr *vhcr,
394362306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *inbox,
394462306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *outbox,
394562306a36Sopenharmony_ci			    struct mlx4_cmd_info *cmd)
394662306a36Sopenharmony_ci{
394762306a36Sopenharmony_ci	int err;
394862306a36Sopenharmony_ci	struct mlx4_qp_context *context = inbox->buf + 8;
394962306a36Sopenharmony_ci
395062306a36Sopenharmony_ci	err = adjust_qp_sched_queue(dev, slave, context, inbox);
395162306a36Sopenharmony_ci	if (err)
395262306a36Sopenharmony_ci		return err;
395362306a36Sopenharmony_ci	err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2SQD, slave);
395462306a36Sopenharmony_ci	if (err)
395562306a36Sopenharmony_ci		return err;
395662306a36Sopenharmony_ci
395762306a36Sopenharmony_ci	adjust_proxy_tun_qkey(dev, vhcr, context);
395862306a36Sopenharmony_ci	update_gid(dev, inbox, (u8)slave);
395962306a36Sopenharmony_ci	update_pkey_index(dev, slave, inbox);
396062306a36Sopenharmony_ci	return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
396162306a36Sopenharmony_ci}
396262306a36Sopenharmony_ci
396362306a36Sopenharmony_ciint mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
396462306a36Sopenharmony_ci			    struct mlx4_vhcr *vhcr,
396562306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *inbox,
396662306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *outbox,
396762306a36Sopenharmony_ci			    struct mlx4_cmd_info *cmd)
396862306a36Sopenharmony_ci{
396962306a36Sopenharmony_ci	int err;
397062306a36Sopenharmony_ci	struct mlx4_qp_context *context = inbox->buf + 8;
397162306a36Sopenharmony_ci
397262306a36Sopenharmony_ci	err = adjust_qp_sched_queue(dev, slave, context, inbox);
397362306a36Sopenharmony_ci	if (err)
397462306a36Sopenharmony_ci		return err;
397562306a36Sopenharmony_ci	err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2RTS, slave);
397662306a36Sopenharmony_ci	if (err)
397762306a36Sopenharmony_ci		return err;
397862306a36Sopenharmony_ci
397962306a36Sopenharmony_ci	adjust_proxy_tun_qkey(dev, vhcr, context);
398062306a36Sopenharmony_ci	update_gid(dev, inbox, (u8)slave);
398162306a36Sopenharmony_ci	update_pkey_index(dev, slave, inbox);
398262306a36Sopenharmony_ci	return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
398362306a36Sopenharmony_ci}
398462306a36Sopenharmony_ci
398562306a36Sopenharmony_ciint mlx4_2RST_QP_wrapper(struct mlx4_dev *dev, int slave,
398662306a36Sopenharmony_ci			 struct mlx4_vhcr *vhcr,
398762306a36Sopenharmony_ci			 struct mlx4_cmd_mailbox *inbox,
398862306a36Sopenharmony_ci			 struct mlx4_cmd_mailbox *outbox,
398962306a36Sopenharmony_ci			 struct mlx4_cmd_info *cmd)
399062306a36Sopenharmony_ci{
399162306a36Sopenharmony_ci	int err;
399262306a36Sopenharmony_ci	int qpn = vhcr->in_modifier & 0x7fffff;
399362306a36Sopenharmony_ci	struct res_qp *qp;
399462306a36Sopenharmony_ci
399562306a36Sopenharmony_ci	err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, &qp, 0);
399662306a36Sopenharmony_ci	if (err)
399762306a36Sopenharmony_ci		return err;
399862306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
399962306a36Sopenharmony_ci	if (err)
400062306a36Sopenharmony_ci		goto ex_abort;
400162306a36Sopenharmony_ci
400262306a36Sopenharmony_ci	atomic_dec(&qp->mtt->ref_count);
400362306a36Sopenharmony_ci	atomic_dec(&qp->rcq->ref_count);
400462306a36Sopenharmony_ci	atomic_dec(&qp->scq->ref_count);
400562306a36Sopenharmony_ci	if (qp->srq)
400662306a36Sopenharmony_ci		atomic_dec(&qp->srq->ref_count);
400762306a36Sopenharmony_ci	res_end_move(dev, slave, RES_QP, qpn);
400862306a36Sopenharmony_ci	return 0;
400962306a36Sopenharmony_ci
401062306a36Sopenharmony_ciex_abort:
401162306a36Sopenharmony_ci	res_abort_move(dev, slave, RES_QP, qpn);
401262306a36Sopenharmony_ci
401362306a36Sopenharmony_ci	return err;
401462306a36Sopenharmony_ci}
401562306a36Sopenharmony_ci
401662306a36Sopenharmony_cistatic struct res_gid *find_gid(struct mlx4_dev *dev, int slave,
401762306a36Sopenharmony_ci				struct res_qp *rqp, u8 *gid)
401862306a36Sopenharmony_ci{
401962306a36Sopenharmony_ci	struct res_gid *res;
402062306a36Sopenharmony_ci
402162306a36Sopenharmony_ci	list_for_each_entry(res, &rqp->mcg_list, list) {
402262306a36Sopenharmony_ci		if (!memcmp(res->gid, gid, 16))
402362306a36Sopenharmony_ci			return res;
402462306a36Sopenharmony_ci	}
402562306a36Sopenharmony_ci	return NULL;
402662306a36Sopenharmony_ci}
402762306a36Sopenharmony_ci
402862306a36Sopenharmony_cistatic int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
402962306a36Sopenharmony_ci		       u8 *gid, enum mlx4_protocol prot,
403062306a36Sopenharmony_ci		       enum mlx4_steer_type steer, u64 reg_id)
403162306a36Sopenharmony_ci{
403262306a36Sopenharmony_ci	struct res_gid *res;
403362306a36Sopenharmony_ci	int err;
403462306a36Sopenharmony_ci
403562306a36Sopenharmony_ci	res = kzalloc(sizeof(*res), GFP_KERNEL);
403662306a36Sopenharmony_ci	if (!res)
403762306a36Sopenharmony_ci		return -ENOMEM;
403862306a36Sopenharmony_ci
403962306a36Sopenharmony_ci	spin_lock_irq(&rqp->mcg_spl);
404062306a36Sopenharmony_ci	if (find_gid(dev, slave, rqp, gid)) {
404162306a36Sopenharmony_ci		kfree(res);
404262306a36Sopenharmony_ci		err = -EEXIST;
404362306a36Sopenharmony_ci	} else {
404462306a36Sopenharmony_ci		memcpy(res->gid, gid, 16);
404562306a36Sopenharmony_ci		res->prot = prot;
404662306a36Sopenharmony_ci		res->steer = steer;
404762306a36Sopenharmony_ci		res->reg_id = reg_id;
404862306a36Sopenharmony_ci		list_add_tail(&res->list, &rqp->mcg_list);
404962306a36Sopenharmony_ci		err = 0;
405062306a36Sopenharmony_ci	}
405162306a36Sopenharmony_ci	spin_unlock_irq(&rqp->mcg_spl);
405262306a36Sopenharmony_ci
405362306a36Sopenharmony_ci	return err;
405462306a36Sopenharmony_ci}
405562306a36Sopenharmony_ci
405662306a36Sopenharmony_cistatic int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
405762306a36Sopenharmony_ci		       u8 *gid, enum mlx4_protocol prot,
405862306a36Sopenharmony_ci		       enum mlx4_steer_type steer, u64 *reg_id)
405962306a36Sopenharmony_ci{
406062306a36Sopenharmony_ci	struct res_gid *res;
406162306a36Sopenharmony_ci	int err;
406262306a36Sopenharmony_ci
406362306a36Sopenharmony_ci	spin_lock_irq(&rqp->mcg_spl);
406462306a36Sopenharmony_ci	res = find_gid(dev, slave, rqp, gid);
406562306a36Sopenharmony_ci	if (!res || res->prot != prot || res->steer != steer)
406662306a36Sopenharmony_ci		err = -EINVAL;
406762306a36Sopenharmony_ci	else {
406862306a36Sopenharmony_ci		*reg_id = res->reg_id;
406962306a36Sopenharmony_ci		list_del(&res->list);
407062306a36Sopenharmony_ci		kfree(res);
407162306a36Sopenharmony_ci		err = 0;
407262306a36Sopenharmony_ci	}
407362306a36Sopenharmony_ci	spin_unlock_irq(&rqp->mcg_spl);
407462306a36Sopenharmony_ci
407562306a36Sopenharmony_ci	return err;
407662306a36Sopenharmony_ci}
407762306a36Sopenharmony_ci
407862306a36Sopenharmony_cistatic int qp_attach(struct mlx4_dev *dev, int slave, struct mlx4_qp *qp,
407962306a36Sopenharmony_ci		     u8 gid[16], int block_loopback, enum mlx4_protocol prot,
408062306a36Sopenharmony_ci		     enum mlx4_steer_type type, u64 *reg_id)
408162306a36Sopenharmony_ci{
408262306a36Sopenharmony_ci	switch (dev->caps.steering_mode) {
408362306a36Sopenharmony_ci	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
408462306a36Sopenharmony_ci		int port = mlx4_slave_convert_port(dev, slave, gid[5]);
408562306a36Sopenharmony_ci		if (port < 0)
408662306a36Sopenharmony_ci			return port;
408762306a36Sopenharmony_ci		return mlx4_trans_to_dmfs_attach(dev, qp, gid, port,
408862306a36Sopenharmony_ci						block_loopback, prot,
408962306a36Sopenharmony_ci						reg_id);
409062306a36Sopenharmony_ci	}
409162306a36Sopenharmony_ci	case MLX4_STEERING_MODE_B0:
409262306a36Sopenharmony_ci		if (prot == MLX4_PROT_ETH) {
409362306a36Sopenharmony_ci			int port = mlx4_slave_convert_port(dev, slave, gid[5]);
409462306a36Sopenharmony_ci			if (port < 0)
409562306a36Sopenharmony_ci				return port;
409662306a36Sopenharmony_ci			gid[5] = port;
409762306a36Sopenharmony_ci		}
409862306a36Sopenharmony_ci		return mlx4_qp_attach_common(dev, qp, gid,
409962306a36Sopenharmony_ci					    block_loopback, prot, type);
410062306a36Sopenharmony_ci	default:
410162306a36Sopenharmony_ci		return -EINVAL;
410262306a36Sopenharmony_ci	}
410362306a36Sopenharmony_ci}
410462306a36Sopenharmony_ci
410562306a36Sopenharmony_cistatic int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,
410662306a36Sopenharmony_ci		     u8 gid[16], enum mlx4_protocol prot,
410762306a36Sopenharmony_ci		     enum mlx4_steer_type type, u64 reg_id)
410862306a36Sopenharmony_ci{
410962306a36Sopenharmony_ci	switch (dev->caps.steering_mode) {
411062306a36Sopenharmony_ci	case MLX4_STEERING_MODE_DEVICE_MANAGED:
411162306a36Sopenharmony_ci		return mlx4_flow_detach(dev, reg_id);
411262306a36Sopenharmony_ci	case MLX4_STEERING_MODE_B0:
411362306a36Sopenharmony_ci		return mlx4_qp_detach_common(dev, qp, gid, prot, type);
411462306a36Sopenharmony_ci	default:
411562306a36Sopenharmony_ci		return -EINVAL;
411662306a36Sopenharmony_ci	}
411762306a36Sopenharmony_ci}
411862306a36Sopenharmony_ci
411962306a36Sopenharmony_cistatic int mlx4_adjust_port(struct mlx4_dev *dev, int slave,
412062306a36Sopenharmony_ci			    u8 *gid, enum mlx4_protocol prot)
412162306a36Sopenharmony_ci{
412262306a36Sopenharmony_ci	int real_port;
412362306a36Sopenharmony_ci
412462306a36Sopenharmony_ci	if (prot != MLX4_PROT_ETH)
412562306a36Sopenharmony_ci		return 0;
412662306a36Sopenharmony_ci
412762306a36Sopenharmony_ci	if (dev->caps.steering_mode == MLX4_STEERING_MODE_B0 ||
412862306a36Sopenharmony_ci	    dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) {
412962306a36Sopenharmony_ci		real_port = mlx4_slave_convert_port(dev, slave, gid[5]);
413062306a36Sopenharmony_ci		if (real_port < 0)
413162306a36Sopenharmony_ci			return -EINVAL;
413262306a36Sopenharmony_ci		gid[5] = real_port;
413362306a36Sopenharmony_ci	}
413462306a36Sopenharmony_ci
413562306a36Sopenharmony_ci	return 0;
413662306a36Sopenharmony_ci}
413762306a36Sopenharmony_ci
413862306a36Sopenharmony_ciint mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
413962306a36Sopenharmony_ci			       struct mlx4_vhcr *vhcr,
414062306a36Sopenharmony_ci			       struct mlx4_cmd_mailbox *inbox,
414162306a36Sopenharmony_ci			       struct mlx4_cmd_mailbox *outbox,
414262306a36Sopenharmony_ci			       struct mlx4_cmd_info *cmd)
414362306a36Sopenharmony_ci{
414462306a36Sopenharmony_ci	struct mlx4_qp qp; /* dummy for calling attach/detach */
414562306a36Sopenharmony_ci	u8 *gid = inbox->buf;
414662306a36Sopenharmony_ci	enum mlx4_protocol prot = (vhcr->in_modifier >> 28) & 0x7;
414762306a36Sopenharmony_ci	int err;
414862306a36Sopenharmony_ci	int qpn;
414962306a36Sopenharmony_ci	struct res_qp *rqp;
415062306a36Sopenharmony_ci	u64 reg_id = 0;
415162306a36Sopenharmony_ci	int attach = vhcr->op_modifier;
415262306a36Sopenharmony_ci	int block_loopback = vhcr->in_modifier >> 31;
415362306a36Sopenharmony_ci	u8 steer_type_mask = 2;
415462306a36Sopenharmony_ci	enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1;
415562306a36Sopenharmony_ci
415662306a36Sopenharmony_ci	qpn = vhcr->in_modifier & 0xffffff;
415762306a36Sopenharmony_ci	err = get_res(dev, slave, qpn, RES_QP, &rqp);
415862306a36Sopenharmony_ci	if (err)
415962306a36Sopenharmony_ci		return err;
416062306a36Sopenharmony_ci
416162306a36Sopenharmony_ci	qp.qpn = qpn;
416262306a36Sopenharmony_ci	if (attach) {
416362306a36Sopenharmony_ci		err = qp_attach(dev, slave, &qp, gid, block_loopback, prot,
416462306a36Sopenharmony_ci				type, &reg_id);
416562306a36Sopenharmony_ci		if (err) {
416662306a36Sopenharmony_ci			pr_err("Fail to attach rule to qp 0x%x\n", qpn);
416762306a36Sopenharmony_ci			goto ex_put;
416862306a36Sopenharmony_ci		}
416962306a36Sopenharmony_ci		err = add_mcg_res(dev, slave, rqp, gid, prot, type, reg_id);
417062306a36Sopenharmony_ci		if (err)
417162306a36Sopenharmony_ci			goto ex_detach;
417262306a36Sopenharmony_ci	} else {
417362306a36Sopenharmony_ci		err = mlx4_adjust_port(dev, slave, gid, prot);
417462306a36Sopenharmony_ci		if (err)
417562306a36Sopenharmony_ci			goto ex_put;
417662306a36Sopenharmony_ci
417762306a36Sopenharmony_ci		err = rem_mcg_res(dev, slave, rqp, gid, prot, type, &reg_id);
417862306a36Sopenharmony_ci		if (err)
417962306a36Sopenharmony_ci			goto ex_put;
418062306a36Sopenharmony_ci
418162306a36Sopenharmony_ci		err = qp_detach(dev, &qp, gid, prot, type, reg_id);
418262306a36Sopenharmony_ci		if (err)
418362306a36Sopenharmony_ci			pr_err("Fail to detach rule from qp 0x%x reg_id = 0x%llx\n",
418462306a36Sopenharmony_ci			       qpn, reg_id);
418562306a36Sopenharmony_ci	}
418662306a36Sopenharmony_ci	put_res(dev, slave, qpn, RES_QP);
418762306a36Sopenharmony_ci	return err;
418862306a36Sopenharmony_ci
418962306a36Sopenharmony_ciex_detach:
419062306a36Sopenharmony_ci	qp_detach(dev, &qp, gid, prot, type, reg_id);
419162306a36Sopenharmony_ciex_put:
419262306a36Sopenharmony_ci	put_res(dev, slave, qpn, RES_QP);
419362306a36Sopenharmony_ci	return err;
419462306a36Sopenharmony_ci}
419562306a36Sopenharmony_ci
419662306a36Sopenharmony_ci/*
419762306a36Sopenharmony_ci * MAC validation for Flow Steering rules.
419862306a36Sopenharmony_ci * VF can attach rules only with a mac address which is assigned to it.
419962306a36Sopenharmony_ci */
420062306a36Sopenharmony_cistatic int validate_eth_header_mac(int slave, struct _rule_hw *eth_header,
420162306a36Sopenharmony_ci				   struct list_head *rlist)
420262306a36Sopenharmony_ci{
420362306a36Sopenharmony_ci	struct mac_res *res, *tmp;
420462306a36Sopenharmony_ci	__be64 be_mac;
420562306a36Sopenharmony_ci
420662306a36Sopenharmony_ci	/* make sure it isn't multicast or broadcast mac*/
420762306a36Sopenharmony_ci	if (!is_multicast_ether_addr(eth_header->eth.dst_mac) &&
420862306a36Sopenharmony_ci	    !is_broadcast_ether_addr(eth_header->eth.dst_mac)) {
420962306a36Sopenharmony_ci		list_for_each_entry_safe(res, tmp, rlist, list) {
421062306a36Sopenharmony_ci			be_mac = cpu_to_be64(res->mac << 16);
421162306a36Sopenharmony_ci			if (ether_addr_equal((u8 *)&be_mac, eth_header->eth.dst_mac))
421262306a36Sopenharmony_ci				return 0;
421362306a36Sopenharmony_ci		}
421462306a36Sopenharmony_ci		pr_err("MAC %pM doesn't belong to VF %d, Steering rule rejected\n",
421562306a36Sopenharmony_ci		       eth_header->eth.dst_mac, slave);
421662306a36Sopenharmony_ci		return -EINVAL;
421762306a36Sopenharmony_ci	}
421862306a36Sopenharmony_ci	return 0;
421962306a36Sopenharmony_ci}
422062306a36Sopenharmony_ci
422162306a36Sopenharmony_ci/*
422262306a36Sopenharmony_ci * In case of missing eth header, append eth header with a MAC address
422362306a36Sopenharmony_ci * assigned to the VF.
422462306a36Sopenharmony_ci */
422562306a36Sopenharmony_cistatic int add_eth_header(struct mlx4_dev *dev, int slave,
422662306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *inbox,
422762306a36Sopenharmony_ci			  struct list_head *rlist, int header_id)
422862306a36Sopenharmony_ci{
422962306a36Sopenharmony_ci	struct mac_res *res, *tmp;
423062306a36Sopenharmony_ci	u8 port;
423162306a36Sopenharmony_ci	struct mlx4_net_trans_rule_hw_ctrl *ctrl;
423262306a36Sopenharmony_ci	struct mlx4_net_trans_rule_hw_eth *eth_header;
423362306a36Sopenharmony_ci	struct mlx4_net_trans_rule_hw_ipv4 *ip_header;
423462306a36Sopenharmony_ci	struct mlx4_net_trans_rule_hw_tcp_udp *l4_header;
423562306a36Sopenharmony_ci	__be64 be_mac = 0;
423662306a36Sopenharmony_ci	__be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16);
423762306a36Sopenharmony_ci
423862306a36Sopenharmony_ci	ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
423962306a36Sopenharmony_ci	port = ctrl->port;
424062306a36Sopenharmony_ci	eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1);
424162306a36Sopenharmony_ci
424262306a36Sopenharmony_ci	/* Clear a space in the inbox for eth header */
424362306a36Sopenharmony_ci	switch (header_id) {
424462306a36Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_IPV4:
424562306a36Sopenharmony_ci		ip_header =
424662306a36Sopenharmony_ci			(struct mlx4_net_trans_rule_hw_ipv4 *)(eth_header + 1);
424762306a36Sopenharmony_ci		memmove(ip_header, eth_header,
424862306a36Sopenharmony_ci			sizeof(*ip_header) + sizeof(*l4_header));
424962306a36Sopenharmony_ci		break;
425062306a36Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_TCP:
425162306a36Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_UDP:
425262306a36Sopenharmony_ci		l4_header = (struct mlx4_net_trans_rule_hw_tcp_udp *)
425362306a36Sopenharmony_ci			    (eth_header + 1);
425462306a36Sopenharmony_ci		memmove(l4_header, eth_header, sizeof(*l4_header));
425562306a36Sopenharmony_ci		break;
425662306a36Sopenharmony_ci	default:
425762306a36Sopenharmony_ci		return -EINVAL;
425862306a36Sopenharmony_ci	}
425962306a36Sopenharmony_ci	list_for_each_entry_safe(res, tmp, rlist, list) {
426062306a36Sopenharmony_ci		if (port == res->port) {
426162306a36Sopenharmony_ci			be_mac = cpu_to_be64(res->mac << 16);
426262306a36Sopenharmony_ci			break;
426362306a36Sopenharmony_ci		}
426462306a36Sopenharmony_ci	}
426562306a36Sopenharmony_ci	if (!be_mac) {
426662306a36Sopenharmony_ci		pr_err("Failed adding eth header to FS rule, Can't find matching MAC for port %d\n",
426762306a36Sopenharmony_ci		       port);
426862306a36Sopenharmony_ci		return -EINVAL;
426962306a36Sopenharmony_ci	}
427062306a36Sopenharmony_ci
427162306a36Sopenharmony_ci	memset(eth_header, 0, sizeof(*eth_header));
427262306a36Sopenharmony_ci	eth_header->size = sizeof(*eth_header) >> 2;
427362306a36Sopenharmony_ci	eth_header->id = cpu_to_be16(__sw_id_hw[MLX4_NET_TRANS_RULE_ID_ETH]);
427462306a36Sopenharmony_ci	memcpy(eth_header->dst_mac, &be_mac, ETH_ALEN);
427562306a36Sopenharmony_ci	memcpy(eth_header->dst_mac_msk, &mac_msk, ETH_ALEN);
427662306a36Sopenharmony_ci
427762306a36Sopenharmony_ci	return 0;
427862306a36Sopenharmony_ci
427962306a36Sopenharmony_ci}
428062306a36Sopenharmony_ci
428162306a36Sopenharmony_ci#define MLX4_UPD_QP_PATH_MASK_SUPPORTED      (                                \
428262306a36Sopenharmony_ci	1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX                     |\
428362306a36Sopenharmony_ci	1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB)
428462306a36Sopenharmony_ciint mlx4_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave,
428562306a36Sopenharmony_ci			   struct mlx4_vhcr *vhcr,
428662306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *inbox,
428762306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *outbox,
428862306a36Sopenharmony_ci			   struct mlx4_cmd_info *cmd_info)
428962306a36Sopenharmony_ci{
429062306a36Sopenharmony_ci	int err;
429162306a36Sopenharmony_ci	u32 qpn = vhcr->in_modifier & 0xffffff;
429262306a36Sopenharmony_ci	struct res_qp *rqp;
429362306a36Sopenharmony_ci	u64 mac;
429462306a36Sopenharmony_ci	unsigned port;
429562306a36Sopenharmony_ci	u64 pri_addr_path_mask;
429662306a36Sopenharmony_ci	struct mlx4_update_qp_context *cmd;
429762306a36Sopenharmony_ci	int smac_index;
429862306a36Sopenharmony_ci
429962306a36Sopenharmony_ci	cmd = (struct mlx4_update_qp_context *)inbox->buf;
430062306a36Sopenharmony_ci
430162306a36Sopenharmony_ci	pri_addr_path_mask = be64_to_cpu(cmd->primary_addr_path_mask);
430262306a36Sopenharmony_ci	if (cmd->qp_mask || cmd->secondary_addr_path_mask ||
430362306a36Sopenharmony_ci	    (pri_addr_path_mask & ~MLX4_UPD_QP_PATH_MASK_SUPPORTED))
430462306a36Sopenharmony_ci		return -EPERM;
430562306a36Sopenharmony_ci
430662306a36Sopenharmony_ci	if ((pri_addr_path_mask &
430762306a36Sopenharmony_ci	     (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB)) &&
430862306a36Sopenharmony_ci		!(dev->caps.flags2 &
430962306a36Sopenharmony_ci		  MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB)) {
431062306a36Sopenharmony_ci		mlx4_warn(dev, "Src check LB for slave %d isn't supported\n",
431162306a36Sopenharmony_ci			  slave);
431262306a36Sopenharmony_ci		return -EOPNOTSUPP;
431362306a36Sopenharmony_ci	}
431462306a36Sopenharmony_ci
431562306a36Sopenharmony_ci	/* Just change the smac for the QP */
431662306a36Sopenharmony_ci	err = get_res(dev, slave, qpn, RES_QP, &rqp);
431762306a36Sopenharmony_ci	if (err) {
431862306a36Sopenharmony_ci		mlx4_err(dev, "Updating qpn 0x%x for slave %d rejected\n", qpn, slave);
431962306a36Sopenharmony_ci		return err;
432062306a36Sopenharmony_ci	}
432162306a36Sopenharmony_ci
432262306a36Sopenharmony_ci	port = (rqp->sched_queue >> 6 & 1) + 1;
432362306a36Sopenharmony_ci
432462306a36Sopenharmony_ci	if (pri_addr_path_mask & (1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX)) {
432562306a36Sopenharmony_ci		smac_index = cmd->qp_context.pri_path.grh_mylmc;
432662306a36Sopenharmony_ci		err = mac_find_smac_ix_in_slave(dev, slave, port,
432762306a36Sopenharmony_ci						smac_index, &mac);
432862306a36Sopenharmony_ci
432962306a36Sopenharmony_ci		if (err) {
433062306a36Sopenharmony_ci			mlx4_err(dev, "Failed to update qpn 0x%x, MAC is invalid. smac_ix: %d\n",
433162306a36Sopenharmony_ci				 qpn, smac_index);
433262306a36Sopenharmony_ci			goto err_mac;
433362306a36Sopenharmony_ci		}
433462306a36Sopenharmony_ci	}
433562306a36Sopenharmony_ci
433662306a36Sopenharmony_ci	err = mlx4_cmd(dev, inbox->dma,
433762306a36Sopenharmony_ci		       vhcr->in_modifier, 0,
433862306a36Sopenharmony_ci		       MLX4_CMD_UPDATE_QP, MLX4_CMD_TIME_CLASS_A,
433962306a36Sopenharmony_ci		       MLX4_CMD_NATIVE);
434062306a36Sopenharmony_ci	if (err) {
434162306a36Sopenharmony_ci		mlx4_err(dev, "Failed to update qpn on qpn 0x%x, command failed\n", qpn);
434262306a36Sopenharmony_ci		goto err_mac;
434362306a36Sopenharmony_ci	}
434462306a36Sopenharmony_ci
434562306a36Sopenharmony_cierr_mac:
434662306a36Sopenharmony_ci	put_res(dev, slave, qpn, RES_QP);
434762306a36Sopenharmony_ci	return err;
434862306a36Sopenharmony_ci}
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_cistatic u32 qp_attach_mbox_size(void *mbox)
435162306a36Sopenharmony_ci{
435262306a36Sopenharmony_ci	u32 size = sizeof(struct mlx4_net_trans_rule_hw_ctrl);
435362306a36Sopenharmony_ci	struct _rule_hw  *rule_header;
435462306a36Sopenharmony_ci
435562306a36Sopenharmony_ci	rule_header = (struct _rule_hw *)(mbox + size);
435662306a36Sopenharmony_ci
435762306a36Sopenharmony_ci	while (rule_header->size) {
435862306a36Sopenharmony_ci		size += rule_header->size * sizeof(u32);
435962306a36Sopenharmony_ci		rule_header += 1;
436062306a36Sopenharmony_ci	}
436162306a36Sopenharmony_ci	return size;
436262306a36Sopenharmony_ci}
436362306a36Sopenharmony_ci
436462306a36Sopenharmony_cistatic int mlx4_do_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule);
436562306a36Sopenharmony_ci
436662306a36Sopenharmony_ciint mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
436762306a36Sopenharmony_ci					 struct mlx4_vhcr *vhcr,
436862306a36Sopenharmony_ci					 struct mlx4_cmd_mailbox *inbox,
436962306a36Sopenharmony_ci					 struct mlx4_cmd_mailbox *outbox,
437062306a36Sopenharmony_ci					 struct mlx4_cmd_info *cmd)
437162306a36Sopenharmony_ci{
437262306a36Sopenharmony_ci
437362306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
437462306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
437562306a36Sopenharmony_ci	struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC];
437662306a36Sopenharmony_ci	int err;
437762306a36Sopenharmony_ci	int qpn;
437862306a36Sopenharmony_ci	struct res_qp *rqp;
437962306a36Sopenharmony_ci	struct mlx4_net_trans_rule_hw_ctrl *ctrl;
438062306a36Sopenharmony_ci	struct _rule_hw  *rule_header;
438162306a36Sopenharmony_ci	int header_id;
438262306a36Sopenharmony_ci	struct res_fs_rule *rrule;
438362306a36Sopenharmony_ci	u32 mbox_size;
438462306a36Sopenharmony_ci
438562306a36Sopenharmony_ci	if (dev->caps.steering_mode !=
438662306a36Sopenharmony_ci	    MLX4_STEERING_MODE_DEVICE_MANAGED)
438762306a36Sopenharmony_ci		return -EOPNOTSUPP;
438862306a36Sopenharmony_ci
438962306a36Sopenharmony_ci	ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
439062306a36Sopenharmony_ci	err = mlx4_slave_convert_port(dev, slave, ctrl->port);
439162306a36Sopenharmony_ci	if (err <= 0)
439262306a36Sopenharmony_ci		return -EINVAL;
439362306a36Sopenharmony_ci	ctrl->port = err;
439462306a36Sopenharmony_ci	qpn = be32_to_cpu(ctrl->qpn) & 0xffffff;
439562306a36Sopenharmony_ci	err = get_res(dev, slave, qpn, RES_QP, &rqp);
439662306a36Sopenharmony_ci	if (err) {
439762306a36Sopenharmony_ci		pr_err("Steering rule with qpn 0x%x rejected\n", qpn);
439862306a36Sopenharmony_ci		return err;
439962306a36Sopenharmony_ci	}
440062306a36Sopenharmony_ci	rule_header = (struct _rule_hw *)(ctrl + 1);
440162306a36Sopenharmony_ci	header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id));
440262306a36Sopenharmony_ci
440362306a36Sopenharmony_ci	if (header_id == MLX4_NET_TRANS_RULE_ID_ETH)
440462306a36Sopenharmony_ci		mlx4_handle_eth_header_mcast_prio(ctrl, rule_header);
440562306a36Sopenharmony_ci
440662306a36Sopenharmony_ci	switch (header_id) {
440762306a36Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_ETH:
440862306a36Sopenharmony_ci		if (validate_eth_header_mac(slave, rule_header, rlist)) {
440962306a36Sopenharmony_ci			err = -EINVAL;
441062306a36Sopenharmony_ci			goto err_put_qp;
441162306a36Sopenharmony_ci		}
441262306a36Sopenharmony_ci		break;
441362306a36Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_IB:
441462306a36Sopenharmony_ci		break;
441562306a36Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_IPV4:
441662306a36Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_TCP:
441762306a36Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_UDP:
441862306a36Sopenharmony_ci		pr_warn("Can't attach FS rule without L2 headers, adding L2 header\n");
441962306a36Sopenharmony_ci		if (add_eth_header(dev, slave, inbox, rlist, header_id)) {
442062306a36Sopenharmony_ci			err = -EINVAL;
442162306a36Sopenharmony_ci			goto err_put_qp;
442262306a36Sopenharmony_ci		}
442362306a36Sopenharmony_ci		vhcr->in_modifier +=
442462306a36Sopenharmony_ci			sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2;
442562306a36Sopenharmony_ci		break;
442662306a36Sopenharmony_ci	default:
442762306a36Sopenharmony_ci		pr_err("Corrupted mailbox\n");
442862306a36Sopenharmony_ci		err = -EINVAL;
442962306a36Sopenharmony_ci		goto err_put_qp;
443062306a36Sopenharmony_ci	}
443162306a36Sopenharmony_ci
443262306a36Sopenharmony_ci	err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param,
443362306a36Sopenharmony_ci			   vhcr->in_modifier, 0,
443462306a36Sopenharmony_ci			   MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
443562306a36Sopenharmony_ci			   MLX4_CMD_NATIVE);
443662306a36Sopenharmony_ci	if (err)
443762306a36Sopenharmony_ci		goto err_put_qp;
443862306a36Sopenharmony_ci
443962306a36Sopenharmony_ci
444062306a36Sopenharmony_ci	err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn);
444162306a36Sopenharmony_ci	if (err) {
444262306a36Sopenharmony_ci		mlx4_err(dev, "Fail to add flow steering resources\n");
444362306a36Sopenharmony_ci		goto err_detach;
444462306a36Sopenharmony_ci	}
444562306a36Sopenharmony_ci
444662306a36Sopenharmony_ci	err = get_res(dev, slave, vhcr->out_param, RES_FS_RULE, &rrule);
444762306a36Sopenharmony_ci	if (err)
444862306a36Sopenharmony_ci		goto err_detach;
444962306a36Sopenharmony_ci
445062306a36Sopenharmony_ci	mbox_size = qp_attach_mbox_size(inbox->buf);
445162306a36Sopenharmony_ci	rrule->mirr_mbox = kmalloc(mbox_size, GFP_KERNEL);
445262306a36Sopenharmony_ci	if (!rrule->mirr_mbox) {
445362306a36Sopenharmony_ci		err = -ENOMEM;
445462306a36Sopenharmony_ci		goto err_put_rule;
445562306a36Sopenharmony_ci	}
445662306a36Sopenharmony_ci	rrule->mirr_mbox_size = mbox_size;
445762306a36Sopenharmony_ci	rrule->mirr_rule_id = 0;
445862306a36Sopenharmony_ci	memcpy(rrule->mirr_mbox, inbox->buf, mbox_size);
445962306a36Sopenharmony_ci
446062306a36Sopenharmony_ci	/* set different port */
446162306a36Sopenharmony_ci	ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)rrule->mirr_mbox;
446262306a36Sopenharmony_ci	if (ctrl->port == 1)
446362306a36Sopenharmony_ci		ctrl->port = 2;
446462306a36Sopenharmony_ci	else
446562306a36Sopenharmony_ci		ctrl->port = 1;
446662306a36Sopenharmony_ci
446762306a36Sopenharmony_ci	if (mlx4_is_bonded(dev))
446862306a36Sopenharmony_ci		mlx4_do_mirror_rule(dev, rrule);
446962306a36Sopenharmony_ci
447062306a36Sopenharmony_ci	atomic_inc(&rqp->ref_count);
447162306a36Sopenharmony_ci
447262306a36Sopenharmony_cierr_put_rule:
447362306a36Sopenharmony_ci	put_res(dev, slave, vhcr->out_param, RES_FS_RULE);
447462306a36Sopenharmony_cierr_detach:
447562306a36Sopenharmony_ci	/* detach rule on error */
447662306a36Sopenharmony_ci	if (err)
447762306a36Sopenharmony_ci		mlx4_cmd(dev, vhcr->out_param, 0, 0,
447862306a36Sopenharmony_ci			 MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
447962306a36Sopenharmony_ci			 MLX4_CMD_NATIVE);
448062306a36Sopenharmony_cierr_put_qp:
448162306a36Sopenharmony_ci	put_res(dev, slave, qpn, RES_QP);
448262306a36Sopenharmony_ci	return err;
448362306a36Sopenharmony_ci}
448462306a36Sopenharmony_ci
448562306a36Sopenharmony_cistatic int mlx4_undo_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule)
448662306a36Sopenharmony_ci{
448762306a36Sopenharmony_ci	int err;
448862306a36Sopenharmony_ci
448962306a36Sopenharmony_ci	err = rem_res_range(dev, fs_rule->com.owner, fs_rule->com.res_id, 1, RES_FS_RULE, 0);
449062306a36Sopenharmony_ci	if (err) {
449162306a36Sopenharmony_ci		mlx4_err(dev, "Fail to remove flow steering resources\n");
449262306a36Sopenharmony_ci		return err;
449362306a36Sopenharmony_ci	}
449462306a36Sopenharmony_ci
449562306a36Sopenharmony_ci	mlx4_cmd(dev, fs_rule->com.res_id, 0, 0, MLX4_QP_FLOW_STEERING_DETACH,
449662306a36Sopenharmony_ci		 MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
449762306a36Sopenharmony_ci	return 0;
449862306a36Sopenharmony_ci}
449962306a36Sopenharmony_ci
450062306a36Sopenharmony_ciint mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave,
450162306a36Sopenharmony_ci					 struct mlx4_vhcr *vhcr,
450262306a36Sopenharmony_ci					 struct mlx4_cmd_mailbox *inbox,
450362306a36Sopenharmony_ci					 struct mlx4_cmd_mailbox *outbox,
450462306a36Sopenharmony_ci					 struct mlx4_cmd_info *cmd)
450562306a36Sopenharmony_ci{
450662306a36Sopenharmony_ci	int err;
450762306a36Sopenharmony_ci	struct res_qp *rqp;
450862306a36Sopenharmony_ci	struct res_fs_rule *rrule;
450962306a36Sopenharmony_ci	u64 mirr_reg_id;
451062306a36Sopenharmony_ci	int qpn;
451162306a36Sopenharmony_ci
451262306a36Sopenharmony_ci	if (dev->caps.steering_mode !=
451362306a36Sopenharmony_ci	    MLX4_STEERING_MODE_DEVICE_MANAGED)
451462306a36Sopenharmony_ci		return -EOPNOTSUPP;
451562306a36Sopenharmony_ci
451662306a36Sopenharmony_ci	err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule);
451762306a36Sopenharmony_ci	if (err)
451862306a36Sopenharmony_ci		return err;
451962306a36Sopenharmony_ci
452062306a36Sopenharmony_ci	if (!rrule->mirr_mbox) {
452162306a36Sopenharmony_ci		mlx4_err(dev, "Mirror rules cannot be removed explicitly\n");
452262306a36Sopenharmony_ci		put_res(dev, slave, vhcr->in_param, RES_FS_RULE);
452362306a36Sopenharmony_ci		return -EINVAL;
452462306a36Sopenharmony_ci	}
452562306a36Sopenharmony_ci	mirr_reg_id = rrule->mirr_rule_id;
452662306a36Sopenharmony_ci	kfree(rrule->mirr_mbox);
452762306a36Sopenharmony_ci	qpn = rrule->qpn;
452862306a36Sopenharmony_ci
452962306a36Sopenharmony_ci	/* Release the rule form busy state before removal */
453062306a36Sopenharmony_ci	put_res(dev, slave, vhcr->in_param, RES_FS_RULE);
453162306a36Sopenharmony_ci	err = get_res(dev, slave, qpn, RES_QP, &rqp);
453262306a36Sopenharmony_ci	if (err)
453362306a36Sopenharmony_ci		return err;
453462306a36Sopenharmony_ci
453562306a36Sopenharmony_ci	if (mirr_reg_id && mlx4_is_bonded(dev)) {
453662306a36Sopenharmony_ci		err = get_res(dev, slave, mirr_reg_id, RES_FS_RULE, &rrule);
453762306a36Sopenharmony_ci		if (err) {
453862306a36Sopenharmony_ci			mlx4_err(dev, "Fail to get resource of mirror rule\n");
453962306a36Sopenharmony_ci		} else {
454062306a36Sopenharmony_ci			put_res(dev, slave, mirr_reg_id, RES_FS_RULE);
454162306a36Sopenharmony_ci			mlx4_undo_mirror_rule(dev, rrule);
454262306a36Sopenharmony_ci		}
454362306a36Sopenharmony_ci	}
454462306a36Sopenharmony_ci	err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 0);
454562306a36Sopenharmony_ci	if (err) {
454662306a36Sopenharmony_ci		mlx4_err(dev, "Fail to remove flow steering resources\n");
454762306a36Sopenharmony_ci		goto out;
454862306a36Sopenharmony_ci	}
454962306a36Sopenharmony_ci
455062306a36Sopenharmony_ci	err = mlx4_cmd(dev, vhcr->in_param, 0, 0,
455162306a36Sopenharmony_ci		       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
455262306a36Sopenharmony_ci		       MLX4_CMD_NATIVE);
455362306a36Sopenharmony_ci	if (!err)
455462306a36Sopenharmony_ci		atomic_dec(&rqp->ref_count);
455562306a36Sopenharmony_ciout:
455662306a36Sopenharmony_ci	put_res(dev, slave, qpn, RES_QP);
455762306a36Sopenharmony_ci	return err;
455862306a36Sopenharmony_ci}
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_cienum {
456162306a36Sopenharmony_ci	BUSY_MAX_RETRIES = 10
456262306a36Sopenharmony_ci};
456362306a36Sopenharmony_ci
456462306a36Sopenharmony_ciint mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave,
456562306a36Sopenharmony_ci			       struct mlx4_vhcr *vhcr,
456662306a36Sopenharmony_ci			       struct mlx4_cmd_mailbox *inbox,
456762306a36Sopenharmony_ci			       struct mlx4_cmd_mailbox *outbox,
456862306a36Sopenharmony_ci			       struct mlx4_cmd_info *cmd)
456962306a36Sopenharmony_ci{
457062306a36Sopenharmony_ci	int err;
457162306a36Sopenharmony_ci	int index = vhcr->in_modifier & 0xffff;
457262306a36Sopenharmony_ci
457362306a36Sopenharmony_ci	err = get_res(dev, slave, index, RES_COUNTER, NULL);
457462306a36Sopenharmony_ci	if (err)
457562306a36Sopenharmony_ci		return err;
457662306a36Sopenharmony_ci
457762306a36Sopenharmony_ci	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
457862306a36Sopenharmony_ci	put_res(dev, slave, index, RES_COUNTER);
457962306a36Sopenharmony_ci	return err;
458062306a36Sopenharmony_ci}
458162306a36Sopenharmony_ci
458262306a36Sopenharmony_cistatic void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp)
458362306a36Sopenharmony_ci{
458462306a36Sopenharmony_ci	struct res_gid *rgid;
458562306a36Sopenharmony_ci	struct res_gid *tmp;
458662306a36Sopenharmony_ci	struct mlx4_qp qp; /* dummy for calling attach/detach */
458762306a36Sopenharmony_ci
458862306a36Sopenharmony_ci	list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) {
458962306a36Sopenharmony_ci		switch (dev->caps.steering_mode) {
459062306a36Sopenharmony_ci		case MLX4_STEERING_MODE_DEVICE_MANAGED:
459162306a36Sopenharmony_ci			mlx4_flow_detach(dev, rgid->reg_id);
459262306a36Sopenharmony_ci			break;
459362306a36Sopenharmony_ci		case MLX4_STEERING_MODE_B0:
459462306a36Sopenharmony_ci			qp.qpn = rqp->local_qpn;
459562306a36Sopenharmony_ci			(void) mlx4_qp_detach_common(dev, &qp, rgid->gid,
459662306a36Sopenharmony_ci						     rgid->prot, rgid->steer);
459762306a36Sopenharmony_ci			break;
459862306a36Sopenharmony_ci		}
459962306a36Sopenharmony_ci		list_del(&rgid->list);
460062306a36Sopenharmony_ci		kfree(rgid);
460162306a36Sopenharmony_ci	}
460262306a36Sopenharmony_ci}
460362306a36Sopenharmony_ci
460462306a36Sopenharmony_cistatic int _move_all_busy(struct mlx4_dev *dev, int slave,
460562306a36Sopenharmony_ci			  enum mlx4_resource type, int print)
460662306a36Sopenharmony_ci{
460762306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
460862306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker =
460962306a36Sopenharmony_ci		&priv->mfunc.master.res_tracker;
461062306a36Sopenharmony_ci	struct list_head *rlist = &tracker->slave_list[slave].res_list[type];
461162306a36Sopenharmony_ci	struct res_common *r;
461262306a36Sopenharmony_ci	struct res_common *tmp;
461362306a36Sopenharmony_ci	int busy;
461462306a36Sopenharmony_ci
461562306a36Sopenharmony_ci	busy = 0;
461662306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
461762306a36Sopenharmony_ci	list_for_each_entry_safe(r, tmp, rlist, list) {
461862306a36Sopenharmony_ci		if (r->owner == slave) {
461962306a36Sopenharmony_ci			if (!r->removing) {
462062306a36Sopenharmony_ci				if (r->state == RES_ANY_BUSY) {
462162306a36Sopenharmony_ci					if (print)
462262306a36Sopenharmony_ci						mlx4_dbg(dev,
462362306a36Sopenharmony_ci							 "%s id 0x%llx is busy\n",
462462306a36Sopenharmony_ci							  resource_str(type),
462562306a36Sopenharmony_ci							  r->res_id);
462662306a36Sopenharmony_ci					++busy;
462762306a36Sopenharmony_ci				} else {
462862306a36Sopenharmony_ci					r->from_state = r->state;
462962306a36Sopenharmony_ci					r->state = RES_ANY_BUSY;
463062306a36Sopenharmony_ci					r->removing = 1;
463162306a36Sopenharmony_ci				}
463262306a36Sopenharmony_ci			}
463362306a36Sopenharmony_ci		}
463462306a36Sopenharmony_ci	}
463562306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
463662306a36Sopenharmony_ci
463762306a36Sopenharmony_ci	return busy;
463862306a36Sopenharmony_ci}
463962306a36Sopenharmony_ci
464062306a36Sopenharmony_cistatic int move_all_busy(struct mlx4_dev *dev, int slave,
464162306a36Sopenharmony_ci			 enum mlx4_resource type)
464262306a36Sopenharmony_ci{
464362306a36Sopenharmony_ci	unsigned long begin;
464462306a36Sopenharmony_ci	int busy;
464562306a36Sopenharmony_ci
464662306a36Sopenharmony_ci	begin = jiffies;
464762306a36Sopenharmony_ci	do {
464862306a36Sopenharmony_ci		busy = _move_all_busy(dev, slave, type, 0);
464962306a36Sopenharmony_ci		if (time_after(jiffies, begin + 5 * HZ))
465062306a36Sopenharmony_ci			break;
465162306a36Sopenharmony_ci		if (busy)
465262306a36Sopenharmony_ci			cond_resched();
465362306a36Sopenharmony_ci	} while (busy);
465462306a36Sopenharmony_ci
465562306a36Sopenharmony_ci	if (busy)
465662306a36Sopenharmony_ci		busy = _move_all_busy(dev, slave, type, 1);
465762306a36Sopenharmony_ci
465862306a36Sopenharmony_ci	return busy;
465962306a36Sopenharmony_ci}
466062306a36Sopenharmony_cistatic void rem_slave_qps(struct mlx4_dev *dev, int slave)
466162306a36Sopenharmony_ci{
466262306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
466362306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
466462306a36Sopenharmony_ci	struct list_head *qp_list =
466562306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_QP];
466662306a36Sopenharmony_ci	struct res_qp *qp;
466762306a36Sopenharmony_ci	struct res_qp *tmp;
466862306a36Sopenharmony_ci	int state;
466962306a36Sopenharmony_ci	u64 in_param;
467062306a36Sopenharmony_ci	int qpn;
467162306a36Sopenharmony_ci	int err;
467262306a36Sopenharmony_ci
467362306a36Sopenharmony_ci	err = move_all_busy(dev, slave, RES_QP);
467462306a36Sopenharmony_ci	if (err)
467562306a36Sopenharmony_ci		mlx4_warn(dev, "rem_slave_qps: Could not move all qps to busy for slave %d\n",
467662306a36Sopenharmony_ci			  slave);
467762306a36Sopenharmony_ci
467862306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
467962306a36Sopenharmony_ci	list_for_each_entry_safe(qp, tmp, qp_list, com.list) {
468062306a36Sopenharmony_ci		spin_unlock_irq(mlx4_tlock(dev));
468162306a36Sopenharmony_ci		if (qp->com.owner == slave) {
468262306a36Sopenharmony_ci			qpn = qp->com.res_id;
468362306a36Sopenharmony_ci			detach_qp(dev, slave, qp);
468462306a36Sopenharmony_ci			state = qp->com.from_state;
468562306a36Sopenharmony_ci			while (state != 0) {
468662306a36Sopenharmony_ci				switch (state) {
468762306a36Sopenharmony_ci				case RES_QP_RESERVED:
468862306a36Sopenharmony_ci					spin_lock_irq(mlx4_tlock(dev));
468962306a36Sopenharmony_ci					rb_erase(&qp->com.node,
469062306a36Sopenharmony_ci						 &tracker->res_tree[RES_QP]);
469162306a36Sopenharmony_ci					list_del(&qp->com.list);
469262306a36Sopenharmony_ci					spin_unlock_irq(mlx4_tlock(dev));
469362306a36Sopenharmony_ci					if (!valid_reserved(dev, slave, qpn)) {
469462306a36Sopenharmony_ci						__mlx4_qp_release_range(dev, qpn, 1);
469562306a36Sopenharmony_ci						mlx4_release_resource(dev, slave,
469662306a36Sopenharmony_ci								      RES_QP, 1, 0);
469762306a36Sopenharmony_ci					}
469862306a36Sopenharmony_ci					kfree(qp);
469962306a36Sopenharmony_ci					state = 0;
470062306a36Sopenharmony_ci					break;
470162306a36Sopenharmony_ci				case RES_QP_MAPPED:
470262306a36Sopenharmony_ci					if (!valid_reserved(dev, slave, qpn))
470362306a36Sopenharmony_ci						__mlx4_qp_free_icm(dev, qpn);
470462306a36Sopenharmony_ci					state = RES_QP_RESERVED;
470562306a36Sopenharmony_ci					break;
470662306a36Sopenharmony_ci				case RES_QP_HW:
470762306a36Sopenharmony_ci					in_param = slave;
470862306a36Sopenharmony_ci					err = mlx4_cmd(dev, in_param,
470962306a36Sopenharmony_ci						       qp->local_qpn, 2,
471062306a36Sopenharmony_ci						       MLX4_CMD_2RST_QP,
471162306a36Sopenharmony_ci						       MLX4_CMD_TIME_CLASS_A,
471262306a36Sopenharmony_ci						       MLX4_CMD_NATIVE);
471362306a36Sopenharmony_ci					if (err)
471462306a36Sopenharmony_ci						mlx4_dbg(dev, "rem_slave_qps: failed to move slave %d qpn %d to reset\n",
471562306a36Sopenharmony_ci							 slave, qp->local_qpn);
471662306a36Sopenharmony_ci					atomic_dec(&qp->rcq->ref_count);
471762306a36Sopenharmony_ci					atomic_dec(&qp->scq->ref_count);
471862306a36Sopenharmony_ci					atomic_dec(&qp->mtt->ref_count);
471962306a36Sopenharmony_ci					if (qp->srq)
472062306a36Sopenharmony_ci						atomic_dec(&qp->srq->ref_count);
472162306a36Sopenharmony_ci					state = RES_QP_MAPPED;
472262306a36Sopenharmony_ci					break;
472362306a36Sopenharmony_ci				default:
472462306a36Sopenharmony_ci					state = 0;
472562306a36Sopenharmony_ci				}
472662306a36Sopenharmony_ci			}
472762306a36Sopenharmony_ci		}
472862306a36Sopenharmony_ci		spin_lock_irq(mlx4_tlock(dev));
472962306a36Sopenharmony_ci	}
473062306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
473162306a36Sopenharmony_ci}
473262306a36Sopenharmony_ci
473362306a36Sopenharmony_cistatic void rem_slave_srqs(struct mlx4_dev *dev, int slave)
473462306a36Sopenharmony_ci{
473562306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
473662306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
473762306a36Sopenharmony_ci	struct list_head *srq_list =
473862306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_SRQ];
473962306a36Sopenharmony_ci	struct res_srq *srq;
474062306a36Sopenharmony_ci	struct res_srq *tmp;
474162306a36Sopenharmony_ci	int state;
474262306a36Sopenharmony_ci	u64 in_param;
474362306a36Sopenharmony_ci	int srqn;
474462306a36Sopenharmony_ci	int err;
474562306a36Sopenharmony_ci
474662306a36Sopenharmony_ci	err = move_all_busy(dev, slave, RES_SRQ);
474762306a36Sopenharmony_ci	if (err)
474862306a36Sopenharmony_ci		mlx4_warn(dev, "rem_slave_srqs: Could not move all srqs - too busy for slave %d\n",
474962306a36Sopenharmony_ci			  slave);
475062306a36Sopenharmony_ci
475162306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
475262306a36Sopenharmony_ci	list_for_each_entry_safe(srq, tmp, srq_list, com.list) {
475362306a36Sopenharmony_ci		spin_unlock_irq(mlx4_tlock(dev));
475462306a36Sopenharmony_ci		if (srq->com.owner == slave) {
475562306a36Sopenharmony_ci			srqn = srq->com.res_id;
475662306a36Sopenharmony_ci			state = srq->com.from_state;
475762306a36Sopenharmony_ci			while (state != 0) {
475862306a36Sopenharmony_ci				switch (state) {
475962306a36Sopenharmony_ci				case RES_SRQ_ALLOCATED:
476062306a36Sopenharmony_ci					__mlx4_srq_free_icm(dev, srqn);
476162306a36Sopenharmony_ci					spin_lock_irq(mlx4_tlock(dev));
476262306a36Sopenharmony_ci					rb_erase(&srq->com.node,
476362306a36Sopenharmony_ci						 &tracker->res_tree[RES_SRQ]);
476462306a36Sopenharmony_ci					list_del(&srq->com.list);
476562306a36Sopenharmony_ci					spin_unlock_irq(mlx4_tlock(dev));
476662306a36Sopenharmony_ci					mlx4_release_resource(dev, slave,
476762306a36Sopenharmony_ci							      RES_SRQ, 1, 0);
476862306a36Sopenharmony_ci					kfree(srq);
476962306a36Sopenharmony_ci					state = 0;
477062306a36Sopenharmony_ci					break;
477162306a36Sopenharmony_ci
477262306a36Sopenharmony_ci				case RES_SRQ_HW:
477362306a36Sopenharmony_ci					in_param = slave;
477462306a36Sopenharmony_ci					err = mlx4_cmd(dev, in_param, srqn, 1,
477562306a36Sopenharmony_ci						       MLX4_CMD_HW2SW_SRQ,
477662306a36Sopenharmony_ci						       MLX4_CMD_TIME_CLASS_A,
477762306a36Sopenharmony_ci						       MLX4_CMD_NATIVE);
477862306a36Sopenharmony_ci					if (err)
477962306a36Sopenharmony_ci						mlx4_dbg(dev, "rem_slave_srqs: failed to move slave %d srq %d to SW ownership\n",
478062306a36Sopenharmony_ci							 slave, srqn);
478162306a36Sopenharmony_ci
478262306a36Sopenharmony_ci					atomic_dec(&srq->mtt->ref_count);
478362306a36Sopenharmony_ci					if (srq->cq)
478462306a36Sopenharmony_ci						atomic_dec(&srq->cq->ref_count);
478562306a36Sopenharmony_ci					state = RES_SRQ_ALLOCATED;
478662306a36Sopenharmony_ci					break;
478762306a36Sopenharmony_ci
478862306a36Sopenharmony_ci				default:
478962306a36Sopenharmony_ci					state = 0;
479062306a36Sopenharmony_ci				}
479162306a36Sopenharmony_ci			}
479262306a36Sopenharmony_ci		}
479362306a36Sopenharmony_ci		spin_lock_irq(mlx4_tlock(dev));
479462306a36Sopenharmony_ci	}
479562306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
479662306a36Sopenharmony_ci}
479762306a36Sopenharmony_ci
479862306a36Sopenharmony_cistatic void rem_slave_cqs(struct mlx4_dev *dev, int slave)
479962306a36Sopenharmony_ci{
480062306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
480162306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
480262306a36Sopenharmony_ci	struct list_head *cq_list =
480362306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_CQ];
480462306a36Sopenharmony_ci	struct res_cq *cq;
480562306a36Sopenharmony_ci	struct res_cq *tmp;
480662306a36Sopenharmony_ci	int state;
480762306a36Sopenharmony_ci	u64 in_param;
480862306a36Sopenharmony_ci	int cqn;
480962306a36Sopenharmony_ci	int err;
481062306a36Sopenharmony_ci
481162306a36Sopenharmony_ci	err = move_all_busy(dev, slave, RES_CQ);
481262306a36Sopenharmony_ci	if (err)
481362306a36Sopenharmony_ci		mlx4_warn(dev, "rem_slave_cqs: Could not move all cqs - too busy for slave %d\n",
481462306a36Sopenharmony_ci			  slave);
481562306a36Sopenharmony_ci
481662306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
481762306a36Sopenharmony_ci	list_for_each_entry_safe(cq, tmp, cq_list, com.list) {
481862306a36Sopenharmony_ci		spin_unlock_irq(mlx4_tlock(dev));
481962306a36Sopenharmony_ci		if (cq->com.owner == slave && !atomic_read(&cq->ref_count)) {
482062306a36Sopenharmony_ci			cqn = cq->com.res_id;
482162306a36Sopenharmony_ci			state = cq->com.from_state;
482262306a36Sopenharmony_ci			while (state != 0) {
482362306a36Sopenharmony_ci				switch (state) {
482462306a36Sopenharmony_ci				case RES_CQ_ALLOCATED:
482562306a36Sopenharmony_ci					__mlx4_cq_free_icm(dev, cqn);
482662306a36Sopenharmony_ci					spin_lock_irq(mlx4_tlock(dev));
482762306a36Sopenharmony_ci					rb_erase(&cq->com.node,
482862306a36Sopenharmony_ci						 &tracker->res_tree[RES_CQ]);
482962306a36Sopenharmony_ci					list_del(&cq->com.list);
483062306a36Sopenharmony_ci					spin_unlock_irq(mlx4_tlock(dev));
483162306a36Sopenharmony_ci					mlx4_release_resource(dev, slave,
483262306a36Sopenharmony_ci							      RES_CQ, 1, 0);
483362306a36Sopenharmony_ci					kfree(cq);
483462306a36Sopenharmony_ci					state = 0;
483562306a36Sopenharmony_ci					break;
483662306a36Sopenharmony_ci
483762306a36Sopenharmony_ci				case RES_CQ_HW:
483862306a36Sopenharmony_ci					in_param = slave;
483962306a36Sopenharmony_ci					err = mlx4_cmd(dev, in_param, cqn, 1,
484062306a36Sopenharmony_ci						       MLX4_CMD_HW2SW_CQ,
484162306a36Sopenharmony_ci						       MLX4_CMD_TIME_CLASS_A,
484262306a36Sopenharmony_ci						       MLX4_CMD_NATIVE);
484362306a36Sopenharmony_ci					if (err)
484462306a36Sopenharmony_ci						mlx4_dbg(dev, "rem_slave_cqs: failed to move slave %d cq %d to SW ownership\n",
484562306a36Sopenharmony_ci							 slave, cqn);
484662306a36Sopenharmony_ci					atomic_dec(&cq->mtt->ref_count);
484762306a36Sopenharmony_ci					state = RES_CQ_ALLOCATED;
484862306a36Sopenharmony_ci					break;
484962306a36Sopenharmony_ci
485062306a36Sopenharmony_ci				default:
485162306a36Sopenharmony_ci					state = 0;
485262306a36Sopenharmony_ci				}
485362306a36Sopenharmony_ci			}
485462306a36Sopenharmony_ci		}
485562306a36Sopenharmony_ci		spin_lock_irq(mlx4_tlock(dev));
485662306a36Sopenharmony_ci	}
485762306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
485862306a36Sopenharmony_ci}
485962306a36Sopenharmony_ci
486062306a36Sopenharmony_cistatic void rem_slave_mrs(struct mlx4_dev *dev, int slave)
486162306a36Sopenharmony_ci{
486262306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
486362306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
486462306a36Sopenharmony_ci	struct list_head *mpt_list =
486562306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_MPT];
486662306a36Sopenharmony_ci	struct res_mpt *mpt;
486762306a36Sopenharmony_ci	struct res_mpt *tmp;
486862306a36Sopenharmony_ci	int state;
486962306a36Sopenharmony_ci	u64 in_param;
487062306a36Sopenharmony_ci	int mptn;
487162306a36Sopenharmony_ci	int err;
487262306a36Sopenharmony_ci
487362306a36Sopenharmony_ci	err = move_all_busy(dev, slave, RES_MPT);
487462306a36Sopenharmony_ci	if (err)
487562306a36Sopenharmony_ci		mlx4_warn(dev, "rem_slave_mrs: Could not move all mpts - too busy for slave %d\n",
487662306a36Sopenharmony_ci			  slave);
487762306a36Sopenharmony_ci
487862306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
487962306a36Sopenharmony_ci	list_for_each_entry_safe(mpt, tmp, mpt_list, com.list) {
488062306a36Sopenharmony_ci		spin_unlock_irq(mlx4_tlock(dev));
488162306a36Sopenharmony_ci		if (mpt->com.owner == slave) {
488262306a36Sopenharmony_ci			mptn = mpt->com.res_id;
488362306a36Sopenharmony_ci			state = mpt->com.from_state;
488462306a36Sopenharmony_ci			while (state != 0) {
488562306a36Sopenharmony_ci				switch (state) {
488662306a36Sopenharmony_ci				case RES_MPT_RESERVED:
488762306a36Sopenharmony_ci					__mlx4_mpt_release(dev, mpt->key);
488862306a36Sopenharmony_ci					spin_lock_irq(mlx4_tlock(dev));
488962306a36Sopenharmony_ci					rb_erase(&mpt->com.node,
489062306a36Sopenharmony_ci						 &tracker->res_tree[RES_MPT]);
489162306a36Sopenharmony_ci					list_del(&mpt->com.list);
489262306a36Sopenharmony_ci					spin_unlock_irq(mlx4_tlock(dev));
489362306a36Sopenharmony_ci					mlx4_release_resource(dev, slave,
489462306a36Sopenharmony_ci							      RES_MPT, 1, 0);
489562306a36Sopenharmony_ci					kfree(mpt);
489662306a36Sopenharmony_ci					state = 0;
489762306a36Sopenharmony_ci					break;
489862306a36Sopenharmony_ci
489962306a36Sopenharmony_ci				case RES_MPT_MAPPED:
490062306a36Sopenharmony_ci					__mlx4_mpt_free_icm(dev, mpt->key);
490162306a36Sopenharmony_ci					state = RES_MPT_RESERVED;
490262306a36Sopenharmony_ci					break;
490362306a36Sopenharmony_ci
490462306a36Sopenharmony_ci				case RES_MPT_HW:
490562306a36Sopenharmony_ci					in_param = slave;
490662306a36Sopenharmony_ci					err = mlx4_cmd(dev, in_param, mptn, 0,
490762306a36Sopenharmony_ci						     MLX4_CMD_HW2SW_MPT,
490862306a36Sopenharmony_ci						     MLX4_CMD_TIME_CLASS_A,
490962306a36Sopenharmony_ci						     MLX4_CMD_NATIVE);
491062306a36Sopenharmony_ci					if (err)
491162306a36Sopenharmony_ci						mlx4_dbg(dev, "rem_slave_mrs: failed to move slave %d mpt %d to SW ownership\n",
491262306a36Sopenharmony_ci							 slave, mptn);
491362306a36Sopenharmony_ci					if (mpt->mtt)
491462306a36Sopenharmony_ci						atomic_dec(&mpt->mtt->ref_count);
491562306a36Sopenharmony_ci					state = RES_MPT_MAPPED;
491662306a36Sopenharmony_ci					break;
491762306a36Sopenharmony_ci				default:
491862306a36Sopenharmony_ci					state = 0;
491962306a36Sopenharmony_ci				}
492062306a36Sopenharmony_ci			}
492162306a36Sopenharmony_ci		}
492262306a36Sopenharmony_ci		spin_lock_irq(mlx4_tlock(dev));
492362306a36Sopenharmony_ci	}
492462306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
492562306a36Sopenharmony_ci}
492662306a36Sopenharmony_ci
492762306a36Sopenharmony_cistatic void rem_slave_mtts(struct mlx4_dev *dev, int slave)
492862306a36Sopenharmony_ci{
492962306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
493062306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker =
493162306a36Sopenharmony_ci		&priv->mfunc.master.res_tracker;
493262306a36Sopenharmony_ci	struct list_head *mtt_list =
493362306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_MTT];
493462306a36Sopenharmony_ci	struct res_mtt *mtt;
493562306a36Sopenharmony_ci	struct res_mtt *tmp;
493662306a36Sopenharmony_ci	int state;
493762306a36Sopenharmony_ci	int base;
493862306a36Sopenharmony_ci	int err;
493962306a36Sopenharmony_ci
494062306a36Sopenharmony_ci	err = move_all_busy(dev, slave, RES_MTT);
494162306a36Sopenharmony_ci	if (err)
494262306a36Sopenharmony_ci		mlx4_warn(dev, "rem_slave_mtts: Could not move all mtts  - too busy for slave %d\n",
494362306a36Sopenharmony_ci			  slave);
494462306a36Sopenharmony_ci
494562306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
494662306a36Sopenharmony_ci	list_for_each_entry_safe(mtt, tmp, mtt_list, com.list) {
494762306a36Sopenharmony_ci		spin_unlock_irq(mlx4_tlock(dev));
494862306a36Sopenharmony_ci		if (mtt->com.owner == slave) {
494962306a36Sopenharmony_ci			base = mtt->com.res_id;
495062306a36Sopenharmony_ci			state = mtt->com.from_state;
495162306a36Sopenharmony_ci			while (state != 0) {
495262306a36Sopenharmony_ci				switch (state) {
495362306a36Sopenharmony_ci				case RES_MTT_ALLOCATED:
495462306a36Sopenharmony_ci					__mlx4_free_mtt_range(dev, base,
495562306a36Sopenharmony_ci							      mtt->order);
495662306a36Sopenharmony_ci					spin_lock_irq(mlx4_tlock(dev));
495762306a36Sopenharmony_ci					rb_erase(&mtt->com.node,
495862306a36Sopenharmony_ci						 &tracker->res_tree[RES_MTT]);
495962306a36Sopenharmony_ci					list_del(&mtt->com.list);
496062306a36Sopenharmony_ci					spin_unlock_irq(mlx4_tlock(dev));
496162306a36Sopenharmony_ci					mlx4_release_resource(dev, slave, RES_MTT,
496262306a36Sopenharmony_ci							      1 << mtt->order, 0);
496362306a36Sopenharmony_ci					kfree(mtt);
496462306a36Sopenharmony_ci					state = 0;
496562306a36Sopenharmony_ci					break;
496662306a36Sopenharmony_ci
496762306a36Sopenharmony_ci				default:
496862306a36Sopenharmony_ci					state = 0;
496962306a36Sopenharmony_ci				}
497062306a36Sopenharmony_ci			}
497162306a36Sopenharmony_ci		}
497262306a36Sopenharmony_ci		spin_lock_irq(mlx4_tlock(dev));
497362306a36Sopenharmony_ci	}
497462306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
497562306a36Sopenharmony_ci}
497662306a36Sopenharmony_ci
497762306a36Sopenharmony_cistatic int mlx4_do_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule)
497862306a36Sopenharmony_ci{
497962306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
498062306a36Sopenharmony_ci	int err;
498162306a36Sopenharmony_ci	struct res_fs_rule *mirr_rule;
498262306a36Sopenharmony_ci	u64 reg_id;
498362306a36Sopenharmony_ci
498462306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
498562306a36Sopenharmony_ci	if (IS_ERR(mailbox))
498662306a36Sopenharmony_ci		return PTR_ERR(mailbox);
498762306a36Sopenharmony_ci
498862306a36Sopenharmony_ci	if (!fs_rule->mirr_mbox) {
498962306a36Sopenharmony_ci		mlx4_err(dev, "rule mirroring mailbox is null\n");
499062306a36Sopenharmony_ci		mlx4_free_cmd_mailbox(dev, mailbox);
499162306a36Sopenharmony_ci		return -EINVAL;
499262306a36Sopenharmony_ci	}
499362306a36Sopenharmony_ci	memcpy(mailbox->buf, fs_rule->mirr_mbox, fs_rule->mirr_mbox_size);
499462306a36Sopenharmony_ci	err = mlx4_cmd_imm(dev, mailbox->dma, &reg_id, fs_rule->mirr_mbox_size >> 2, 0,
499562306a36Sopenharmony_ci			   MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
499662306a36Sopenharmony_ci			   MLX4_CMD_NATIVE);
499762306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
499862306a36Sopenharmony_ci
499962306a36Sopenharmony_ci	if (err)
500062306a36Sopenharmony_ci		goto err;
500162306a36Sopenharmony_ci
500262306a36Sopenharmony_ci	err = add_res_range(dev, fs_rule->com.owner, reg_id, 1, RES_FS_RULE, fs_rule->qpn);
500362306a36Sopenharmony_ci	if (err)
500462306a36Sopenharmony_ci		goto err_detach;
500562306a36Sopenharmony_ci
500662306a36Sopenharmony_ci	err = get_res(dev, fs_rule->com.owner, reg_id, RES_FS_RULE, &mirr_rule);
500762306a36Sopenharmony_ci	if (err)
500862306a36Sopenharmony_ci		goto err_rem;
500962306a36Sopenharmony_ci
501062306a36Sopenharmony_ci	fs_rule->mirr_rule_id = reg_id;
501162306a36Sopenharmony_ci	mirr_rule->mirr_rule_id = 0;
501262306a36Sopenharmony_ci	mirr_rule->mirr_mbox_size = 0;
501362306a36Sopenharmony_ci	mirr_rule->mirr_mbox = NULL;
501462306a36Sopenharmony_ci	put_res(dev, fs_rule->com.owner, reg_id, RES_FS_RULE);
501562306a36Sopenharmony_ci
501662306a36Sopenharmony_ci	return 0;
501762306a36Sopenharmony_cierr_rem:
501862306a36Sopenharmony_ci	rem_res_range(dev, fs_rule->com.owner, reg_id, 1, RES_FS_RULE, 0);
501962306a36Sopenharmony_cierr_detach:
502062306a36Sopenharmony_ci	mlx4_cmd(dev, reg_id, 0, 0, MLX4_QP_FLOW_STEERING_DETACH,
502162306a36Sopenharmony_ci		 MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
502262306a36Sopenharmony_cierr:
502362306a36Sopenharmony_ci	return err;
502462306a36Sopenharmony_ci}
502562306a36Sopenharmony_ci
502662306a36Sopenharmony_cistatic int mlx4_mirror_fs_rules(struct mlx4_dev *dev, bool bond)
502762306a36Sopenharmony_ci{
502862306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
502962306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker =
503062306a36Sopenharmony_ci		&priv->mfunc.master.res_tracker;
503162306a36Sopenharmony_ci	struct rb_root *root = &tracker->res_tree[RES_FS_RULE];
503262306a36Sopenharmony_ci	struct rb_node *p;
503362306a36Sopenharmony_ci	struct res_fs_rule *fs_rule;
503462306a36Sopenharmony_ci	int err = 0;
503562306a36Sopenharmony_ci	LIST_HEAD(mirr_list);
503662306a36Sopenharmony_ci
503762306a36Sopenharmony_ci	for (p = rb_first(root); p; p = rb_next(p)) {
503862306a36Sopenharmony_ci		fs_rule = rb_entry(p, struct res_fs_rule, com.node);
503962306a36Sopenharmony_ci		if ((bond && fs_rule->mirr_mbox_size) ||
504062306a36Sopenharmony_ci		    (!bond && !fs_rule->mirr_mbox_size))
504162306a36Sopenharmony_ci			list_add_tail(&fs_rule->mirr_list, &mirr_list);
504262306a36Sopenharmony_ci	}
504362306a36Sopenharmony_ci
504462306a36Sopenharmony_ci	list_for_each_entry(fs_rule, &mirr_list, mirr_list) {
504562306a36Sopenharmony_ci		if (bond)
504662306a36Sopenharmony_ci			err += mlx4_do_mirror_rule(dev, fs_rule);
504762306a36Sopenharmony_ci		else
504862306a36Sopenharmony_ci			err += mlx4_undo_mirror_rule(dev, fs_rule);
504962306a36Sopenharmony_ci	}
505062306a36Sopenharmony_ci	return err;
505162306a36Sopenharmony_ci}
505262306a36Sopenharmony_ci
505362306a36Sopenharmony_ciint mlx4_bond_fs_rules(struct mlx4_dev *dev)
505462306a36Sopenharmony_ci{
505562306a36Sopenharmony_ci	return mlx4_mirror_fs_rules(dev, true);
505662306a36Sopenharmony_ci}
505762306a36Sopenharmony_ci
505862306a36Sopenharmony_ciint mlx4_unbond_fs_rules(struct mlx4_dev *dev)
505962306a36Sopenharmony_ci{
506062306a36Sopenharmony_ci	return mlx4_mirror_fs_rules(dev, false);
506162306a36Sopenharmony_ci}
506262306a36Sopenharmony_ci
506362306a36Sopenharmony_cistatic void rem_slave_fs_rule(struct mlx4_dev *dev, int slave)
506462306a36Sopenharmony_ci{
506562306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
506662306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker =
506762306a36Sopenharmony_ci		&priv->mfunc.master.res_tracker;
506862306a36Sopenharmony_ci	struct list_head *fs_rule_list =
506962306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_FS_RULE];
507062306a36Sopenharmony_ci	struct res_fs_rule *fs_rule;
507162306a36Sopenharmony_ci	struct res_fs_rule *tmp;
507262306a36Sopenharmony_ci	int state;
507362306a36Sopenharmony_ci	u64 base;
507462306a36Sopenharmony_ci	int err;
507562306a36Sopenharmony_ci
507662306a36Sopenharmony_ci	err = move_all_busy(dev, slave, RES_FS_RULE);
507762306a36Sopenharmony_ci	if (err)
507862306a36Sopenharmony_ci		mlx4_warn(dev, "rem_slave_fs_rule: Could not move all mtts to busy for slave %d\n",
507962306a36Sopenharmony_ci			  slave);
508062306a36Sopenharmony_ci
508162306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
508262306a36Sopenharmony_ci	list_for_each_entry_safe(fs_rule, tmp, fs_rule_list, com.list) {
508362306a36Sopenharmony_ci		spin_unlock_irq(mlx4_tlock(dev));
508462306a36Sopenharmony_ci		if (fs_rule->com.owner == slave) {
508562306a36Sopenharmony_ci			base = fs_rule->com.res_id;
508662306a36Sopenharmony_ci			state = fs_rule->com.from_state;
508762306a36Sopenharmony_ci			while (state != 0) {
508862306a36Sopenharmony_ci				switch (state) {
508962306a36Sopenharmony_ci				case RES_FS_RULE_ALLOCATED:
509062306a36Sopenharmony_ci					/* detach rule */
509162306a36Sopenharmony_ci					err = mlx4_cmd(dev, base, 0, 0,
509262306a36Sopenharmony_ci						       MLX4_QP_FLOW_STEERING_DETACH,
509362306a36Sopenharmony_ci						       MLX4_CMD_TIME_CLASS_A,
509462306a36Sopenharmony_ci						       MLX4_CMD_NATIVE);
509562306a36Sopenharmony_ci
509662306a36Sopenharmony_ci					spin_lock_irq(mlx4_tlock(dev));
509762306a36Sopenharmony_ci					rb_erase(&fs_rule->com.node,
509862306a36Sopenharmony_ci						 &tracker->res_tree[RES_FS_RULE]);
509962306a36Sopenharmony_ci					list_del(&fs_rule->com.list);
510062306a36Sopenharmony_ci					spin_unlock_irq(mlx4_tlock(dev));
510162306a36Sopenharmony_ci					kfree(fs_rule->mirr_mbox);
510262306a36Sopenharmony_ci					kfree(fs_rule);
510362306a36Sopenharmony_ci					state = 0;
510462306a36Sopenharmony_ci					break;
510562306a36Sopenharmony_ci
510662306a36Sopenharmony_ci				default:
510762306a36Sopenharmony_ci					state = 0;
510862306a36Sopenharmony_ci				}
510962306a36Sopenharmony_ci			}
511062306a36Sopenharmony_ci		}
511162306a36Sopenharmony_ci		spin_lock_irq(mlx4_tlock(dev));
511262306a36Sopenharmony_ci	}
511362306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
511462306a36Sopenharmony_ci}
511562306a36Sopenharmony_ci
511662306a36Sopenharmony_cistatic void rem_slave_eqs(struct mlx4_dev *dev, int slave)
511762306a36Sopenharmony_ci{
511862306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
511962306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
512062306a36Sopenharmony_ci	struct list_head *eq_list =
512162306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_EQ];
512262306a36Sopenharmony_ci	struct res_eq *eq;
512362306a36Sopenharmony_ci	struct res_eq *tmp;
512462306a36Sopenharmony_ci	int err;
512562306a36Sopenharmony_ci	int state;
512662306a36Sopenharmony_ci	int eqn;
512762306a36Sopenharmony_ci
512862306a36Sopenharmony_ci	err = move_all_busy(dev, slave, RES_EQ);
512962306a36Sopenharmony_ci	if (err)
513062306a36Sopenharmony_ci		mlx4_warn(dev, "rem_slave_eqs: Could not move all eqs - too busy for slave %d\n",
513162306a36Sopenharmony_ci			  slave);
513262306a36Sopenharmony_ci
513362306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
513462306a36Sopenharmony_ci	list_for_each_entry_safe(eq, tmp, eq_list, com.list) {
513562306a36Sopenharmony_ci		spin_unlock_irq(mlx4_tlock(dev));
513662306a36Sopenharmony_ci		if (eq->com.owner == slave) {
513762306a36Sopenharmony_ci			eqn = eq->com.res_id;
513862306a36Sopenharmony_ci			state = eq->com.from_state;
513962306a36Sopenharmony_ci			while (state != 0) {
514062306a36Sopenharmony_ci				switch (state) {
514162306a36Sopenharmony_ci				case RES_EQ_RESERVED:
514262306a36Sopenharmony_ci					spin_lock_irq(mlx4_tlock(dev));
514362306a36Sopenharmony_ci					rb_erase(&eq->com.node,
514462306a36Sopenharmony_ci						 &tracker->res_tree[RES_EQ]);
514562306a36Sopenharmony_ci					list_del(&eq->com.list);
514662306a36Sopenharmony_ci					spin_unlock_irq(mlx4_tlock(dev));
514762306a36Sopenharmony_ci					kfree(eq);
514862306a36Sopenharmony_ci					state = 0;
514962306a36Sopenharmony_ci					break;
515062306a36Sopenharmony_ci
515162306a36Sopenharmony_ci				case RES_EQ_HW:
515262306a36Sopenharmony_ci					err = mlx4_cmd(dev, slave, eqn & 0x3ff,
515362306a36Sopenharmony_ci						       1, MLX4_CMD_HW2SW_EQ,
515462306a36Sopenharmony_ci						       MLX4_CMD_TIME_CLASS_A,
515562306a36Sopenharmony_ci						       MLX4_CMD_NATIVE);
515662306a36Sopenharmony_ci					if (err)
515762306a36Sopenharmony_ci						mlx4_dbg(dev, "rem_slave_eqs: failed to move slave %d eqs %d to SW ownership\n",
515862306a36Sopenharmony_ci							 slave, eqn & 0x3ff);
515962306a36Sopenharmony_ci					atomic_dec(&eq->mtt->ref_count);
516062306a36Sopenharmony_ci					state = RES_EQ_RESERVED;
516162306a36Sopenharmony_ci					break;
516262306a36Sopenharmony_ci
516362306a36Sopenharmony_ci				default:
516462306a36Sopenharmony_ci					state = 0;
516562306a36Sopenharmony_ci				}
516662306a36Sopenharmony_ci			}
516762306a36Sopenharmony_ci		}
516862306a36Sopenharmony_ci		spin_lock_irq(mlx4_tlock(dev));
516962306a36Sopenharmony_ci	}
517062306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
517162306a36Sopenharmony_ci}
517262306a36Sopenharmony_ci
517362306a36Sopenharmony_cistatic void rem_slave_counters(struct mlx4_dev *dev, int slave)
517462306a36Sopenharmony_ci{
517562306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
517662306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
517762306a36Sopenharmony_ci	struct list_head *counter_list =
517862306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_COUNTER];
517962306a36Sopenharmony_ci	struct res_counter *counter;
518062306a36Sopenharmony_ci	struct res_counter *tmp;
518162306a36Sopenharmony_ci	int err;
518262306a36Sopenharmony_ci	int *counters_arr = NULL;
518362306a36Sopenharmony_ci	int i, j;
518462306a36Sopenharmony_ci
518562306a36Sopenharmony_ci	err = move_all_busy(dev, slave, RES_COUNTER);
518662306a36Sopenharmony_ci	if (err)
518762306a36Sopenharmony_ci		mlx4_warn(dev, "rem_slave_counters: Could not move all counters - too busy for slave %d\n",
518862306a36Sopenharmony_ci			  slave);
518962306a36Sopenharmony_ci
519062306a36Sopenharmony_ci	counters_arr = kmalloc_array(dev->caps.max_counters,
519162306a36Sopenharmony_ci				     sizeof(*counters_arr), GFP_KERNEL);
519262306a36Sopenharmony_ci	if (!counters_arr)
519362306a36Sopenharmony_ci		return;
519462306a36Sopenharmony_ci
519562306a36Sopenharmony_ci	do {
519662306a36Sopenharmony_ci		i = 0;
519762306a36Sopenharmony_ci		j = 0;
519862306a36Sopenharmony_ci		spin_lock_irq(mlx4_tlock(dev));
519962306a36Sopenharmony_ci		list_for_each_entry_safe(counter, tmp, counter_list, com.list) {
520062306a36Sopenharmony_ci			if (counter->com.owner == slave) {
520162306a36Sopenharmony_ci				counters_arr[i++] = counter->com.res_id;
520262306a36Sopenharmony_ci				rb_erase(&counter->com.node,
520362306a36Sopenharmony_ci					 &tracker->res_tree[RES_COUNTER]);
520462306a36Sopenharmony_ci				list_del(&counter->com.list);
520562306a36Sopenharmony_ci				kfree(counter);
520662306a36Sopenharmony_ci			}
520762306a36Sopenharmony_ci		}
520862306a36Sopenharmony_ci		spin_unlock_irq(mlx4_tlock(dev));
520962306a36Sopenharmony_ci
521062306a36Sopenharmony_ci		while (j < i) {
521162306a36Sopenharmony_ci			__mlx4_counter_free(dev, counters_arr[j++]);
521262306a36Sopenharmony_ci			mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
521362306a36Sopenharmony_ci		}
521462306a36Sopenharmony_ci	} while (i);
521562306a36Sopenharmony_ci
521662306a36Sopenharmony_ci	kfree(counters_arr);
521762306a36Sopenharmony_ci}
521862306a36Sopenharmony_ci
521962306a36Sopenharmony_cistatic void rem_slave_xrcdns(struct mlx4_dev *dev, int slave)
522062306a36Sopenharmony_ci{
522162306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
522262306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
522362306a36Sopenharmony_ci	struct list_head *xrcdn_list =
522462306a36Sopenharmony_ci		&tracker->slave_list[slave].res_list[RES_XRCD];
522562306a36Sopenharmony_ci	struct res_xrcdn *xrcd;
522662306a36Sopenharmony_ci	struct res_xrcdn *tmp;
522762306a36Sopenharmony_ci	int err;
522862306a36Sopenharmony_ci	int xrcdn;
522962306a36Sopenharmony_ci
523062306a36Sopenharmony_ci	err = move_all_busy(dev, slave, RES_XRCD);
523162306a36Sopenharmony_ci	if (err)
523262306a36Sopenharmony_ci		mlx4_warn(dev, "rem_slave_xrcdns: Could not move all xrcdns - too busy for slave %d\n",
523362306a36Sopenharmony_ci			  slave);
523462306a36Sopenharmony_ci
523562306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
523662306a36Sopenharmony_ci	list_for_each_entry_safe(xrcd, tmp, xrcdn_list, com.list) {
523762306a36Sopenharmony_ci		if (xrcd->com.owner == slave) {
523862306a36Sopenharmony_ci			xrcdn = xrcd->com.res_id;
523962306a36Sopenharmony_ci			rb_erase(&xrcd->com.node, &tracker->res_tree[RES_XRCD]);
524062306a36Sopenharmony_ci			list_del(&xrcd->com.list);
524162306a36Sopenharmony_ci			kfree(xrcd);
524262306a36Sopenharmony_ci			__mlx4_xrcd_free(dev, xrcdn);
524362306a36Sopenharmony_ci		}
524462306a36Sopenharmony_ci	}
524562306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
524662306a36Sopenharmony_ci}
524762306a36Sopenharmony_ci
524862306a36Sopenharmony_civoid mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave)
524962306a36Sopenharmony_ci{
525062306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
525162306a36Sopenharmony_ci	mlx4_reset_roce_gids(dev, slave);
525262306a36Sopenharmony_ci	mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
525362306a36Sopenharmony_ci	rem_slave_vlans(dev, slave);
525462306a36Sopenharmony_ci	rem_slave_macs(dev, slave);
525562306a36Sopenharmony_ci	rem_slave_fs_rule(dev, slave);
525662306a36Sopenharmony_ci	rem_slave_qps(dev, slave);
525762306a36Sopenharmony_ci	rem_slave_srqs(dev, slave);
525862306a36Sopenharmony_ci	rem_slave_cqs(dev, slave);
525962306a36Sopenharmony_ci	rem_slave_mrs(dev, slave);
526062306a36Sopenharmony_ci	rem_slave_eqs(dev, slave);
526162306a36Sopenharmony_ci	rem_slave_mtts(dev, slave);
526262306a36Sopenharmony_ci	rem_slave_counters(dev, slave);
526362306a36Sopenharmony_ci	rem_slave_xrcdns(dev, slave);
526462306a36Sopenharmony_ci	mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
526562306a36Sopenharmony_ci}
526662306a36Sopenharmony_ci
526762306a36Sopenharmony_cistatic void update_qos_vpp(struct mlx4_update_qp_context *ctx,
526862306a36Sopenharmony_ci			   struct mlx4_vf_immed_vlan_work *work)
526962306a36Sopenharmony_ci{
527062306a36Sopenharmony_ci	ctx->qp_mask |= cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_QOS_VPP);
527162306a36Sopenharmony_ci	ctx->qp_context.qos_vport = work->qos_vport;
527262306a36Sopenharmony_ci}
527362306a36Sopenharmony_ci
527462306a36Sopenharmony_civoid mlx4_vf_immed_vlan_work_handler(struct work_struct *_work)
527562306a36Sopenharmony_ci{
527662306a36Sopenharmony_ci	struct mlx4_vf_immed_vlan_work *work =
527762306a36Sopenharmony_ci		container_of(_work, struct mlx4_vf_immed_vlan_work, work);
527862306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
527962306a36Sopenharmony_ci	struct mlx4_update_qp_context *upd_context;
528062306a36Sopenharmony_ci	struct mlx4_dev *dev = &work->priv->dev;
528162306a36Sopenharmony_ci	struct mlx4_resource_tracker *tracker =
528262306a36Sopenharmony_ci		&work->priv->mfunc.master.res_tracker;
528362306a36Sopenharmony_ci	struct list_head *qp_list =
528462306a36Sopenharmony_ci		&tracker->slave_list[work->slave].res_list[RES_QP];
528562306a36Sopenharmony_ci	struct res_qp *qp;
528662306a36Sopenharmony_ci	struct res_qp *tmp;
528762306a36Sopenharmony_ci	u64 qp_path_mask_vlan_ctrl =
528862306a36Sopenharmony_ci		       ((1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_UNTAGGED) |
528962306a36Sopenharmony_ci		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_1P) |
529062306a36Sopenharmony_ci		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_TAGGED) |
529162306a36Sopenharmony_ci		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_UNTAGGED) |
529262306a36Sopenharmony_ci		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_1P) |
529362306a36Sopenharmony_ci		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_TAGGED));
529462306a36Sopenharmony_ci
529562306a36Sopenharmony_ci	u64 qp_path_mask = ((1ULL << MLX4_UPD_QP_PATH_MASK_VLAN_INDEX) |
529662306a36Sopenharmony_ci		       (1ULL << MLX4_UPD_QP_PATH_MASK_FVL) |
529762306a36Sopenharmony_ci		       (1ULL << MLX4_UPD_QP_PATH_MASK_CV) |
529862306a36Sopenharmony_ci		       (1ULL << MLX4_UPD_QP_PATH_MASK_SV) |
529962306a36Sopenharmony_ci		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_HIDE_CQE_VLAN) |
530062306a36Sopenharmony_ci		       (1ULL << MLX4_UPD_QP_PATH_MASK_FEUP) |
530162306a36Sopenharmony_ci		       (1ULL << MLX4_UPD_QP_PATH_MASK_FVL_RX) |
530262306a36Sopenharmony_ci		       (1ULL << MLX4_UPD_QP_PATH_MASK_SCHED_QUEUE));
530362306a36Sopenharmony_ci
530462306a36Sopenharmony_ci	int err;
530562306a36Sopenharmony_ci	int port, errors = 0;
530662306a36Sopenharmony_ci	u8 vlan_control;
530762306a36Sopenharmony_ci
530862306a36Sopenharmony_ci	if (mlx4_is_slave(dev)) {
530962306a36Sopenharmony_ci		mlx4_warn(dev, "Trying to update-qp in slave %d\n",
531062306a36Sopenharmony_ci			  work->slave);
531162306a36Sopenharmony_ci		goto out;
531262306a36Sopenharmony_ci	}
531362306a36Sopenharmony_ci
531462306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
531562306a36Sopenharmony_ci	if (IS_ERR(mailbox))
531662306a36Sopenharmony_ci		goto out;
531762306a36Sopenharmony_ci	if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE) /* block all */
531862306a36Sopenharmony_ci		vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
531962306a36Sopenharmony_ci			MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
532062306a36Sopenharmony_ci			MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED |
532162306a36Sopenharmony_ci			MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
532262306a36Sopenharmony_ci			MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED |
532362306a36Sopenharmony_ci			MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
532462306a36Sopenharmony_ci	else if (!work->vlan_id)
532562306a36Sopenharmony_ci		vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
532662306a36Sopenharmony_ci			MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
532762306a36Sopenharmony_ci	else if (work->vlan_proto == htons(ETH_P_8021AD))
532862306a36Sopenharmony_ci		vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
532962306a36Sopenharmony_ci			MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
533062306a36Sopenharmony_ci			MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
533162306a36Sopenharmony_ci			MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
533262306a36Sopenharmony_ci	else  /* vst 802.1Q */
533362306a36Sopenharmony_ci		vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
533462306a36Sopenharmony_ci			MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
533562306a36Sopenharmony_ci			MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
533662306a36Sopenharmony_ci
533762306a36Sopenharmony_ci	upd_context = mailbox->buf;
533862306a36Sopenharmony_ci	upd_context->qp_mask = cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_VSD);
533962306a36Sopenharmony_ci
534062306a36Sopenharmony_ci	spin_lock_irq(mlx4_tlock(dev));
534162306a36Sopenharmony_ci	list_for_each_entry_safe(qp, tmp, qp_list, com.list) {
534262306a36Sopenharmony_ci		spin_unlock_irq(mlx4_tlock(dev));
534362306a36Sopenharmony_ci		if (qp->com.owner == work->slave) {
534462306a36Sopenharmony_ci			if (qp->com.from_state != RES_QP_HW ||
534562306a36Sopenharmony_ci			    !qp->sched_queue ||  /* no INIT2RTR trans yet */
534662306a36Sopenharmony_ci			    mlx4_is_qp_reserved(dev, qp->local_qpn) ||
534762306a36Sopenharmony_ci			    qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET)) {
534862306a36Sopenharmony_ci				spin_lock_irq(mlx4_tlock(dev));
534962306a36Sopenharmony_ci				continue;
535062306a36Sopenharmony_ci			}
535162306a36Sopenharmony_ci			port = (qp->sched_queue >> 6 & 1) + 1;
535262306a36Sopenharmony_ci			if (port != work->port) {
535362306a36Sopenharmony_ci				spin_lock_irq(mlx4_tlock(dev));
535462306a36Sopenharmony_ci				continue;
535562306a36Sopenharmony_ci			}
535662306a36Sopenharmony_ci			if (MLX4_QP_ST_RC == ((qp->qpc_flags >> 16) & 0xff))
535762306a36Sopenharmony_ci				upd_context->primary_addr_path_mask = cpu_to_be64(qp_path_mask);
535862306a36Sopenharmony_ci			else
535962306a36Sopenharmony_ci				upd_context->primary_addr_path_mask =
536062306a36Sopenharmony_ci					cpu_to_be64(qp_path_mask | qp_path_mask_vlan_ctrl);
536162306a36Sopenharmony_ci			if (work->vlan_id == MLX4_VGT) {
536262306a36Sopenharmony_ci				upd_context->qp_context.param3 = qp->param3;
536362306a36Sopenharmony_ci				upd_context->qp_context.pri_path.vlan_control = qp->vlan_control;
536462306a36Sopenharmony_ci				upd_context->qp_context.pri_path.fvl_rx = qp->fvl_rx;
536562306a36Sopenharmony_ci				upd_context->qp_context.pri_path.vlan_index = qp->vlan_index;
536662306a36Sopenharmony_ci				upd_context->qp_context.pri_path.fl = qp->pri_path_fl;
536762306a36Sopenharmony_ci				upd_context->qp_context.pri_path.feup = qp->feup;
536862306a36Sopenharmony_ci				upd_context->qp_context.pri_path.sched_queue =
536962306a36Sopenharmony_ci					qp->sched_queue;
537062306a36Sopenharmony_ci			} else {
537162306a36Sopenharmony_ci				upd_context->qp_context.param3 = qp->param3 & ~cpu_to_be32(MLX4_STRIP_VLAN);
537262306a36Sopenharmony_ci				upd_context->qp_context.pri_path.vlan_control = vlan_control;
537362306a36Sopenharmony_ci				upd_context->qp_context.pri_path.vlan_index = work->vlan_ix;
537462306a36Sopenharmony_ci				upd_context->qp_context.pri_path.fvl_rx =
537562306a36Sopenharmony_ci					qp->fvl_rx | MLX4_FVL_RX_FORCE_ETH_VLAN;
537662306a36Sopenharmony_ci				upd_context->qp_context.pri_path.fl =
537762306a36Sopenharmony_ci					qp->pri_path_fl | MLX4_FL_ETH_HIDE_CQE_VLAN;
537862306a36Sopenharmony_ci				if (work->vlan_proto == htons(ETH_P_8021AD))
537962306a36Sopenharmony_ci					upd_context->qp_context.pri_path.fl |= MLX4_FL_SV;
538062306a36Sopenharmony_ci				else
538162306a36Sopenharmony_ci					upd_context->qp_context.pri_path.fl |= MLX4_FL_CV;
538262306a36Sopenharmony_ci				upd_context->qp_context.pri_path.feup =
538362306a36Sopenharmony_ci					qp->feup | MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN;
538462306a36Sopenharmony_ci				upd_context->qp_context.pri_path.sched_queue =
538562306a36Sopenharmony_ci					qp->sched_queue & 0xC7;
538662306a36Sopenharmony_ci				upd_context->qp_context.pri_path.sched_queue |=
538762306a36Sopenharmony_ci					((work->qos & 0x7) << 3);
538862306a36Sopenharmony_ci
538962306a36Sopenharmony_ci				if (dev->caps.flags2 &
539062306a36Sopenharmony_ci				    MLX4_DEV_CAP_FLAG2_QOS_VPP)
539162306a36Sopenharmony_ci					update_qos_vpp(upd_context, work);
539262306a36Sopenharmony_ci			}
539362306a36Sopenharmony_ci
539462306a36Sopenharmony_ci			err = mlx4_cmd(dev, mailbox->dma,
539562306a36Sopenharmony_ci				       qp->local_qpn & 0xffffff,
539662306a36Sopenharmony_ci				       0, MLX4_CMD_UPDATE_QP,
539762306a36Sopenharmony_ci				       MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
539862306a36Sopenharmony_ci			if (err) {
539962306a36Sopenharmony_ci				mlx4_info(dev, "UPDATE_QP failed for slave %d, port %d, qpn %d (%d)\n",
540062306a36Sopenharmony_ci					  work->slave, port, qp->local_qpn, err);
540162306a36Sopenharmony_ci				errors++;
540262306a36Sopenharmony_ci			}
540362306a36Sopenharmony_ci		}
540462306a36Sopenharmony_ci		spin_lock_irq(mlx4_tlock(dev));
540562306a36Sopenharmony_ci	}
540662306a36Sopenharmony_ci	spin_unlock_irq(mlx4_tlock(dev));
540762306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
540862306a36Sopenharmony_ci
540962306a36Sopenharmony_ci	if (errors)
541062306a36Sopenharmony_ci		mlx4_err(dev, "%d UPDATE_QP failures for slave %d, port %d\n",
541162306a36Sopenharmony_ci			 errors, work->slave, work->port);
541262306a36Sopenharmony_ci
541362306a36Sopenharmony_ci	/* unregister previous vlan_id if needed and we had no errors
541462306a36Sopenharmony_ci	 * while updating the QPs
541562306a36Sopenharmony_ci	 */
541662306a36Sopenharmony_ci	if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN && !errors &&
541762306a36Sopenharmony_ci	    NO_INDX != work->orig_vlan_ix)
541862306a36Sopenharmony_ci		__mlx4_unregister_vlan(&work->priv->dev, work->port,
541962306a36Sopenharmony_ci				       work->orig_vlan_id);
542062306a36Sopenharmony_ciout:
542162306a36Sopenharmony_ci	kfree(work);
542262306a36Sopenharmony_ci	return;
542362306a36Sopenharmony_ci}
5424