xref: /openbmc/linux/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1c82e9aa0SEli Cohen /*
2c82e9aa0SEli Cohen  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
3c82e9aa0SEli Cohen  * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies.
4c82e9aa0SEli Cohen  * All rights reserved.
5c82e9aa0SEli Cohen  * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc.  All rights reserved.
6c82e9aa0SEli Cohen  *
7c82e9aa0SEli Cohen  * This software is available to you under a choice of one of two
8c82e9aa0SEli Cohen  * licenses.  You may choose to be licensed under the terms of the GNU
9c82e9aa0SEli Cohen  * General Public License (GPL) Version 2, available from the file
10c82e9aa0SEli Cohen  * COPYING in the main directory of this source tree, or the
11c82e9aa0SEli Cohen  * OpenIB.org BSD license below:
12c82e9aa0SEli Cohen  *
13c82e9aa0SEli Cohen  *     Redistribution and use in source and binary forms, with or
14c82e9aa0SEli Cohen  *     without modification, are permitted provided that the following
15c82e9aa0SEli Cohen  *     conditions are met:
16c82e9aa0SEli Cohen  *
17c82e9aa0SEli Cohen  *      - Redistributions of source code must retain the above
18c82e9aa0SEli Cohen  *        copyright notice, this list of conditions and the following
19c82e9aa0SEli Cohen  *        disclaimer.
20c82e9aa0SEli Cohen  *
21c82e9aa0SEli Cohen  *      - Redistributions in binary form must reproduce the above
22c82e9aa0SEli Cohen  *        copyright notice, this list of conditions and the following
23c82e9aa0SEli Cohen  *        disclaimer in the documentation and/or other materials
24c82e9aa0SEli Cohen  *        provided with the distribution.
25c82e9aa0SEli Cohen  *
26c82e9aa0SEli Cohen  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27c82e9aa0SEli Cohen  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28c82e9aa0SEli Cohen  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29c82e9aa0SEli Cohen  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30c82e9aa0SEli Cohen  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31c82e9aa0SEli Cohen  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32c82e9aa0SEli Cohen  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33c82e9aa0SEli Cohen  * SOFTWARE.
34c82e9aa0SEli Cohen  */
35c82e9aa0SEli Cohen 
36c82e9aa0SEli Cohen #include <linux/sched.h>
37c82e9aa0SEli Cohen #include <linux/pci.h>
38c82e9aa0SEli Cohen #include <linux/errno.h>
39c82e9aa0SEli Cohen #include <linux/kernel.h>
40c82e9aa0SEli Cohen #include <linux/io.h>
41e143a1adSAxel Lin #include <linux/slab.h>
42c82e9aa0SEli Cohen #include <linux/mlx4/cmd.h>
43c82e9aa0SEli Cohen #include <linux/mlx4/qp.h>
44af22d9deSAmir Vadai #include <linux/if_ether.h>
457fb40f87SHadar Hen Zion #include <linux/etherdevice.h>
46c82e9aa0SEli Cohen 
47c82e9aa0SEli Cohen #include "mlx4.h"
48c82e9aa0SEli Cohen #include "fw.h"
4962a89055SEran Ben Elisha #include "mlx4_stats.h"
50c82e9aa0SEli Cohen 
51c82e9aa0SEli Cohen #define MLX4_MAC_VALID		(1ull << 63)
529de92c60SEran Ben Elisha #define MLX4_PF_COUNTERS_PER_PORT	2
539de92c60SEran Ben Elisha #define MLX4_VF_COUNTERS_PER_PORT	1
54c82e9aa0SEli Cohen 
55c82e9aa0SEli Cohen struct mac_res {
56c82e9aa0SEli Cohen 	struct list_head list;
57c82e9aa0SEli Cohen 	u64 mac;
582f5bb473SJack Morgenstein 	int ref_count;
592f5bb473SJack Morgenstein 	u8 smac_index;
60c82e9aa0SEli Cohen 	u8 port;
61c82e9aa0SEli Cohen };
62c82e9aa0SEli Cohen 
634874080dSJack Morgenstein struct vlan_res {
644874080dSJack Morgenstein 	struct list_head list;
654874080dSJack Morgenstein 	u16 vlan;
664874080dSJack Morgenstein 	int ref_count;
674874080dSJack Morgenstein 	int vlan_index;
684874080dSJack Morgenstein 	u8 port;
694874080dSJack Morgenstein };
704874080dSJack Morgenstein 
71c82e9aa0SEli Cohen struct res_common {
72c82e9aa0SEli Cohen 	struct list_head	list;
734af1c048SHadar Hen Zion 	struct rb_node		node;
74aa1ec3ddSHadar Hen Zion 	u64		        res_id;
75c82e9aa0SEli Cohen 	int			owner;
76c82e9aa0SEli Cohen 	int			state;
77c82e9aa0SEli Cohen 	int			from_state;
78c82e9aa0SEli Cohen 	int			to_state;
79c82e9aa0SEli Cohen 	int			removing;
80ae5a2e29SMatan Barak 	const char		*func_name;
81c82e9aa0SEli Cohen };
82c82e9aa0SEli Cohen 
83c82e9aa0SEli Cohen enum {
84c82e9aa0SEli Cohen 	RES_ANY_BUSY = 1
85c82e9aa0SEli Cohen };
86c82e9aa0SEli Cohen 
87c82e9aa0SEli Cohen struct res_gid {
88c82e9aa0SEli Cohen 	struct list_head	list;
89c82e9aa0SEli Cohen 	u8			gid[16];
90c82e9aa0SEli Cohen 	enum mlx4_protocol	prot;
919f5b6c63SEugenia Emantayev 	enum mlx4_steer_type	steer;
92fab1e24aSHadar Hen Zion 	u64			reg_id;
93c82e9aa0SEli Cohen };
94c82e9aa0SEli Cohen 
95c82e9aa0SEli Cohen enum res_qp_states {
96c82e9aa0SEli Cohen 	RES_QP_BUSY = RES_ANY_BUSY,
97c82e9aa0SEli Cohen 
98c82e9aa0SEli Cohen 	/* QP number was allocated */
99c82e9aa0SEli Cohen 	RES_QP_RESERVED,
100c82e9aa0SEli Cohen 
101c82e9aa0SEli Cohen 	/* ICM memory for QP context was mapped */
102c82e9aa0SEli Cohen 	RES_QP_MAPPED,
103c82e9aa0SEli Cohen 
104c82e9aa0SEli Cohen 	/* QP is in hw ownership */
105c82e9aa0SEli Cohen 	RES_QP_HW
106c82e9aa0SEli Cohen };
107c82e9aa0SEli Cohen 
108c82e9aa0SEli Cohen struct res_qp {
109c82e9aa0SEli Cohen 	struct res_common	com;
110c82e9aa0SEli Cohen 	struct res_mtt	       *mtt;
111c82e9aa0SEli Cohen 	struct res_cq	       *rcq;
112c82e9aa0SEli Cohen 	struct res_cq	       *scq;
113c82e9aa0SEli Cohen 	struct res_srq	       *srq;
114c82e9aa0SEli Cohen 	struct list_head	mcg_list;
115c82e9aa0SEli Cohen 	spinlock_t		mcg_spl;
116c82e9aa0SEli Cohen 	int			local_qpn;
1172c473ae7SHadar Hen Zion 	atomic_t		ref_count;
118b01978caSJack Morgenstein 	u32			qpc_flags;
119f0f829bfSRony Efraim 	/* saved qp params before VST enforcement in order to restore on VGT */
120b01978caSJack Morgenstein 	u8			sched_queue;
121f0f829bfSRony Efraim 	__be32			param3;
122f0f829bfSRony Efraim 	u8			vlan_control;
123f0f829bfSRony Efraim 	u8			fvl_rx;
124f0f829bfSRony Efraim 	u8			pri_path_fl;
125f0f829bfSRony Efraim 	u8			vlan_index;
126f0f829bfSRony Efraim 	u8			feup;
127c82e9aa0SEli Cohen };
128c82e9aa0SEli Cohen 
129c82e9aa0SEli Cohen enum res_mtt_states {
130c82e9aa0SEli Cohen 	RES_MTT_BUSY = RES_ANY_BUSY,
131c82e9aa0SEli Cohen 	RES_MTT_ALLOCATED,
132c82e9aa0SEli Cohen };
133c82e9aa0SEli Cohen 
mtt_states_str(enum res_mtt_states state)134c82e9aa0SEli Cohen static inline const char *mtt_states_str(enum res_mtt_states state)
135c82e9aa0SEli Cohen {
136c82e9aa0SEli Cohen 	switch (state) {
137c82e9aa0SEli Cohen 	case RES_MTT_BUSY: return "RES_MTT_BUSY";
138c82e9aa0SEli Cohen 	case RES_MTT_ALLOCATED: return "RES_MTT_ALLOCATED";
139c82e9aa0SEli Cohen 	default: return "Unknown";
140c82e9aa0SEli Cohen 	}
141c82e9aa0SEli Cohen }
142c82e9aa0SEli Cohen 
143c82e9aa0SEli Cohen struct res_mtt {
144c82e9aa0SEli Cohen 	struct res_common	com;
145c82e9aa0SEli Cohen 	int			order;
146c82e9aa0SEli Cohen 	atomic_t		ref_count;
147c82e9aa0SEli Cohen };
148c82e9aa0SEli Cohen 
149c82e9aa0SEli Cohen enum res_mpt_states {
150c82e9aa0SEli Cohen 	RES_MPT_BUSY = RES_ANY_BUSY,
151c82e9aa0SEli Cohen 	RES_MPT_RESERVED,
152c82e9aa0SEli Cohen 	RES_MPT_MAPPED,
153c82e9aa0SEli Cohen 	RES_MPT_HW,
154c82e9aa0SEli Cohen };
155c82e9aa0SEli Cohen 
156c82e9aa0SEli Cohen struct res_mpt {
157c82e9aa0SEli Cohen 	struct res_common	com;
158c82e9aa0SEli Cohen 	struct res_mtt	       *mtt;
159c82e9aa0SEli Cohen 	int			key;
160c82e9aa0SEli Cohen };
161c82e9aa0SEli Cohen 
162c82e9aa0SEli Cohen enum res_eq_states {
163c82e9aa0SEli Cohen 	RES_EQ_BUSY = RES_ANY_BUSY,
164c82e9aa0SEli Cohen 	RES_EQ_RESERVED,
165c82e9aa0SEli Cohen 	RES_EQ_HW,
166c82e9aa0SEli Cohen };
167c82e9aa0SEli Cohen 
168c82e9aa0SEli Cohen struct res_eq {
169c82e9aa0SEli Cohen 	struct res_common	com;
170c82e9aa0SEli Cohen 	struct res_mtt	       *mtt;
171c82e9aa0SEli Cohen };
172c82e9aa0SEli Cohen 
173c82e9aa0SEli Cohen enum res_cq_states {
174c82e9aa0SEli Cohen 	RES_CQ_BUSY = RES_ANY_BUSY,
175c82e9aa0SEli Cohen 	RES_CQ_ALLOCATED,
176c82e9aa0SEli Cohen 	RES_CQ_HW,
177c82e9aa0SEli Cohen };
178c82e9aa0SEli Cohen 
179c82e9aa0SEli Cohen struct res_cq {
180c82e9aa0SEli Cohen 	struct res_common	com;
181c82e9aa0SEli Cohen 	struct res_mtt	       *mtt;
182c82e9aa0SEli Cohen 	atomic_t		ref_count;
183c82e9aa0SEli Cohen };
184c82e9aa0SEli Cohen 
185c82e9aa0SEli Cohen enum res_srq_states {
186c82e9aa0SEli Cohen 	RES_SRQ_BUSY = RES_ANY_BUSY,
187c82e9aa0SEli Cohen 	RES_SRQ_ALLOCATED,
188c82e9aa0SEli Cohen 	RES_SRQ_HW,
189c82e9aa0SEli Cohen };
190c82e9aa0SEli Cohen 
191c82e9aa0SEli Cohen struct res_srq {
192c82e9aa0SEli Cohen 	struct res_common	com;
193c82e9aa0SEli Cohen 	struct res_mtt	       *mtt;
194c82e9aa0SEli Cohen 	struct res_cq	       *cq;
195c82e9aa0SEli Cohen 	atomic_t		ref_count;
196c82e9aa0SEli Cohen };
197c82e9aa0SEli Cohen 
198c82e9aa0SEli Cohen enum res_counter_states {
199c82e9aa0SEli Cohen 	RES_COUNTER_BUSY = RES_ANY_BUSY,
200c82e9aa0SEli Cohen 	RES_COUNTER_ALLOCATED,
201c82e9aa0SEli Cohen };
202c82e9aa0SEli Cohen 
203c82e9aa0SEli Cohen struct res_counter {
204c82e9aa0SEli Cohen 	struct res_common	com;
205c82e9aa0SEli Cohen 	int			port;
206c82e9aa0SEli Cohen };
207c82e9aa0SEli Cohen 
208ba062d52SJack Morgenstein enum res_xrcdn_states {
209ba062d52SJack Morgenstein 	RES_XRCD_BUSY = RES_ANY_BUSY,
210ba062d52SJack Morgenstein 	RES_XRCD_ALLOCATED,
211ba062d52SJack Morgenstein };
212ba062d52SJack Morgenstein 
213ba062d52SJack Morgenstein struct res_xrcdn {
214ba062d52SJack Morgenstein 	struct res_common	com;
215ba062d52SJack Morgenstein 	int			port;
216ba062d52SJack Morgenstein };
217ba062d52SJack Morgenstein 
2181b9c6b06SHadar Hen Zion enum res_fs_rule_states {
2191b9c6b06SHadar Hen Zion 	RES_FS_RULE_BUSY = RES_ANY_BUSY,
2201b9c6b06SHadar Hen Zion 	RES_FS_RULE_ALLOCATED,
2211b9c6b06SHadar Hen Zion };
2221b9c6b06SHadar Hen Zion 
2231b9c6b06SHadar Hen Zion struct res_fs_rule {
2241b9c6b06SHadar Hen Zion 	struct res_common	com;
2252c473ae7SHadar Hen Zion 	int			qpn;
22678efed27SMoni Shoua 	/* VF DMFS mbox with port flipped */
22778efed27SMoni Shoua 	void			*mirr_mbox;
22878efed27SMoni Shoua 	/* > 0 --> apply mirror when getting into HA mode      */
22978efed27SMoni Shoua 	/* = 0 --> un-apply mirror when getting out of HA mode */
23078efed27SMoni Shoua 	u32			mirr_mbox_size;
23178efed27SMoni Shoua 	struct list_head	mirr_list;
23278efed27SMoni Shoua 	u64			mirr_rule_id;
2331b9c6b06SHadar Hen Zion };
2341b9c6b06SHadar Hen Zion 
res_tracker_lookup(struct rb_root * root,u64 res_id)2354af1c048SHadar Hen Zion static void *res_tracker_lookup(struct rb_root *root, u64 res_id)
2364af1c048SHadar Hen Zion {
2374af1c048SHadar Hen Zion 	struct rb_node *node = root->rb_node;
2384af1c048SHadar Hen Zion 
2394af1c048SHadar Hen Zion 	while (node) {
2403704eb6fSGeliang Tang 		struct res_common *res = rb_entry(node, struct res_common,
2414af1c048SHadar Hen Zion 						  node);
2424af1c048SHadar Hen Zion 
2434af1c048SHadar Hen Zion 		if (res_id < res->res_id)
2444af1c048SHadar Hen Zion 			node = node->rb_left;
2454af1c048SHadar Hen Zion 		else if (res_id > res->res_id)
2464af1c048SHadar Hen Zion 			node = node->rb_right;
2474af1c048SHadar Hen Zion 		else
2484af1c048SHadar Hen Zion 			return res;
2494af1c048SHadar Hen Zion 	}
2504af1c048SHadar Hen Zion 	return NULL;
2514af1c048SHadar Hen Zion }
2524af1c048SHadar Hen Zion 
res_tracker_insert(struct rb_root * root,struct res_common * res)2534af1c048SHadar Hen Zion static int res_tracker_insert(struct rb_root *root, struct res_common *res)
2544af1c048SHadar Hen Zion {
2554af1c048SHadar Hen Zion 	struct rb_node **new = &(root->rb_node), *parent = NULL;
2564af1c048SHadar Hen Zion 
2574af1c048SHadar Hen Zion 	/* Figure out where to put new node */
2584af1c048SHadar Hen Zion 	while (*new) {
2593704eb6fSGeliang Tang 		struct res_common *this = rb_entry(*new, struct res_common,
2604af1c048SHadar Hen Zion 						   node);
2614af1c048SHadar Hen Zion 
2624af1c048SHadar Hen Zion 		parent = *new;
2634af1c048SHadar Hen Zion 		if (res->res_id < this->res_id)
2644af1c048SHadar Hen Zion 			new = &((*new)->rb_left);
2654af1c048SHadar Hen Zion 		else if (res->res_id > this->res_id)
2664af1c048SHadar Hen Zion 			new = &((*new)->rb_right);
2674af1c048SHadar Hen Zion 		else
2684af1c048SHadar Hen Zion 			return -EEXIST;
2694af1c048SHadar Hen Zion 	}
2704af1c048SHadar Hen Zion 
2714af1c048SHadar Hen Zion 	/* Add new node and rebalance tree. */
2724af1c048SHadar Hen Zion 	rb_link_node(&res->node, parent, new);
2734af1c048SHadar Hen Zion 	rb_insert_color(&res->node, root);
2744af1c048SHadar Hen Zion 
2754af1c048SHadar Hen Zion 	return 0;
2764af1c048SHadar Hen Zion }
2774af1c048SHadar Hen Zion 
27854679e14SJack Morgenstein enum qp_transition {
27954679e14SJack Morgenstein 	QP_TRANS_INIT2RTR,
28054679e14SJack Morgenstein 	QP_TRANS_RTR2RTS,
28154679e14SJack Morgenstein 	QP_TRANS_RTS2RTS,
28254679e14SJack Morgenstein 	QP_TRANS_SQERR2RTS,
28354679e14SJack Morgenstein 	QP_TRANS_SQD2SQD,
28454679e14SJack Morgenstein 	QP_TRANS_SQD2RTS
28554679e14SJack Morgenstein };
28654679e14SJack Morgenstein 
287c82e9aa0SEli Cohen /* For Debug uses */
resource_str(enum mlx4_resource rt)28895646373SJack Morgenstein static const char *resource_str(enum mlx4_resource rt)
289c82e9aa0SEli Cohen {
290c82e9aa0SEli Cohen 	switch (rt) {
291c82e9aa0SEli Cohen 	case RES_QP: return "RES_QP";
292c82e9aa0SEli Cohen 	case RES_CQ: return "RES_CQ";
293c82e9aa0SEli Cohen 	case RES_SRQ: return "RES_SRQ";
294c82e9aa0SEli Cohen 	case RES_MPT: return "RES_MPT";
295c82e9aa0SEli Cohen 	case RES_MTT: return "RES_MTT";
296c82e9aa0SEli Cohen 	case RES_MAC: return  "RES_MAC";
2974874080dSJack Morgenstein 	case RES_VLAN: return  "RES_VLAN";
298c82e9aa0SEli Cohen 	case RES_EQ: return "RES_EQ";
299c82e9aa0SEli Cohen 	case RES_COUNTER: return "RES_COUNTER";
3001b9c6b06SHadar Hen Zion 	case RES_FS_RULE: return "RES_FS_RULE";
301ba062d52SJack Morgenstein 	case RES_XRCD: return "RES_XRCD";
302c82e9aa0SEli Cohen 	default: return "Unknown resource type !!!";
303c568db7fSTom Rix 	}
304c82e9aa0SEli Cohen }
305c82e9aa0SEli Cohen 
3064874080dSJack Morgenstein static void rem_slave_vlans(struct mlx4_dev *dev, int slave);
mlx4_grant_resource(struct mlx4_dev * dev,int slave,enum mlx4_resource res_type,int count,int port)307146f3ef4SJack Morgenstein static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave,
308146f3ef4SJack Morgenstein 				      enum mlx4_resource res_type, int count,
309146f3ef4SJack Morgenstein 				      int port)
310146f3ef4SJack Morgenstein {
311146f3ef4SJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
312146f3ef4SJack Morgenstein 	struct resource_allocator *res_alloc =
313146f3ef4SJack Morgenstein 		&priv->mfunc.master.res_tracker.res_alloc[res_type];
31483bd5118SJack Morgenstein 	int err = -EDQUOT;
315146f3ef4SJack Morgenstein 	int allocated, free, reserved, guaranteed, from_free;
31695646373SJack Morgenstein 	int from_rsvd;
317146f3ef4SJack Morgenstein 
318872bf2fbSYishai Hadas 	if (slave > dev->persist->num_vfs)
319146f3ef4SJack Morgenstein 		return -EINVAL;
320146f3ef4SJack Morgenstein 
321146f3ef4SJack Morgenstein 	spin_lock(&res_alloc->alloc_lock);
322146f3ef4SJack Morgenstein 	allocated = (port > 0) ?
323872bf2fbSYishai Hadas 		res_alloc->allocated[(port - 1) *
324872bf2fbSYishai Hadas 		(dev->persist->num_vfs + 1) + slave] :
325146f3ef4SJack Morgenstein 		res_alloc->allocated[slave];
326146f3ef4SJack Morgenstein 	free = (port > 0) ? res_alloc->res_port_free[port - 1] :
327146f3ef4SJack Morgenstein 		res_alloc->res_free;
328146f3ef4SJack Morgenstein 	reserved = (port > 0) ? res_alloc->res_port_rsvd[port - 1] :
329146f3ef4SJack Morgenstein 		res_alloc->res_reserved;
330146f3ef4SJack Morgenstein 	guaranteed = res_alloc->guaranteed[slave];
331146f3ef4SJack Morgenstein 
33295646373SJack Morgenstein 	if (allocated + count > res_alloc->quota[slave]) {
33395646373SJack Morgenstein 		mlx4_warn(dev, "VF %d port %d res %s: quota exceeded, count %d alloc %d quota %d\n",
33495646373SJack Morgenstein 			  slave, port, resource_str(res_type), count,
33595646373SJack Morgenstein 			  allocated, res_alloc->quota[slave]);
336146f3ef4SJack Morgenstein 		goto out;
33795646373SJack Morgenstein 	}
338146f3ef4SJack Morgenstein 
339146f3ef4SJack Morgenstein 	if (allocated + count <= guaranteed) {
340146f3ef4SJack Morgenstein 		err = 0;
34195646373SJack Morgenstein 		from_rsvd = count;
342146f3ef4SJack Morgenstein 	} else {
343146f3ef4SJack Morgenstein 		/* portion may need to be obtained from free area */
344146f3ef4SJack Morgenstein 		if (guaranteed - allocated > 0)
345146f3ef4SJack Morgenstein 			from_free = count - (guaranteed - allocated);
346146f3ef4SJack Morgenstein 		else
347146f3ef4SJack Morgenstein 			from_free = count;
348146f3ef4SJack Morgenstein 
34995646373SJack Morgenstein 		from_rsvd = count - from_free;
35095646373SJack Morgenstein 
35195646373SJack Morgenstein 		if (free - from_free >= reserved)
352146f3ef4SJack Morgenstein 			err = 0;
35395646373SJack Morgenstein 		else
35495646373SJack Morgenstein 			mlx4_warn(dev, "VF %d port %d res %s: free pool empty, free %d from_free %d rsvd %d\n",
35595646373SJack Morgenstein 				  slave, port, resource_str(res_type), free,
35695646373SJack Morgenstein 				  from_free, reserved);
357146f3ef4SJack Morgenstein 	}
358146f3ef4SJack Morgenstein 
359146f3ef4SJack Morgenstein 	if (!err) {
360146f3ef4SJack Morgenstein 		/* grant the request */
361146f3ef4SJack Morgenstein 		if (port > 0) {
362872bf2fbSYishai Hadas 			res_alloc->allocated[(port - 1) *
363872bf2fbSYishai Hadas 			(dev->persist->num_vfs + 1) + slave] += count;
364146f3ef4SJack Morgenstein 			res_alloc->res_port_free[port - 1] -= count;
36595646373SJack Morgenstein 			res_alloc->res_port_rsvd[port - 1] -= from_rsvd;
366146f3ef4SJack Morgenstein 		} else {
367146f3ef4SJack Morgenstein 			res_alloc->allocated[slave] += count;
368146f3ef4SJack Morgenstein 			res_alloc->res_free -= count;
36995646373SJack Morgenstein 			res_alloc->res_reserved -= from_rsvd;
370146f3ef4SJack Morgenstein 		}
371146f3ef4SJack Morgenstein 	}
372146f3ef4SJack Morgenstein 
373146f3ef4SJack Morgenstein out:
374146f3ef4SJack Morgenstein 	spin_unlock(&res_alloc->alloc_lock);
375146f3ef4SJack Morgenstein 	return err;
376146f3ef4SJack Morgenstein }
377146f3ef4SJack Morgenstein 
mlx4_release_resource(struct mlx4_dev * dev,int slave,enum mlx4_resource res_type,int count,int port)378146f3ef4SJack Morgenstein static inline void mlx4_release_resource(struct mlx4_dev *dev, int slave,
379146f3ef4SJack Morgenstein 				    enum mlx4_resource res_type, int count,
380146f3ef4SJack Morgenstein 				    int port)
381146f3ef4SJack Morgenstein {
382146f3ef4SJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
383146f3ef4SJack Morgenstein 	struct resource_allocator *res_alloc =
384146f3ef4SJack Morgenstein 		&priv->mfunc.master.res_tracker.res_alloc[res_type];
38595646373SJack Morgenstein 	int allocated, guaranteed, from_rsvd;
386146f3ef4SJack Morgenstein 
387872bf2fbSYishai Hadas 	if (slave > dev->persist->num_vfs)
388146f3ef4SJack Morgenstein 		return;
389146f3ef4SJack Morgenstein 
390146f3ef4SJack Morgenstein 	spin_lock(&res_alloc->alloc_lock);
39195646373SJack Morgenstein 
39295646373SJack Morgenstein 	allocated = (port > 0) ?
393872bf2fbSYishai Hadas 		res_alloc->allocated[(port - 1) *
394872bf2fbSYishai Hadas 		(dev->persist->num_vfs + 1) + slave] :
39595646373SJack Morgenstein 		res_alloc->allocated[slave];
39695646373SJack Morgenstein 	guaranteed = res_alloc->guaranteed[slave];
39795646373SJack Morgenstein 
39895646373SJack Morgenstein 	if (allocated - count >= guaranteed) {
39995646373SJack Morgenstein 		from_rsvd = 0;
40095646373SJack Morgenstein 	} else {
40195646373SJack Morgenstein 		/* portion may need to be returned to reserved area */
40295646373SJack Morgenstein 		if (allocated - guaranteed > 0)
40395646373SJack Morgenstein 			from_rsvd = count - (allocated - guaranteed);
40495646373SJack Morgenstein 		else
40595646373SJack Morgenstein 			from_rsvd = count;
40695646373SJack Morgenstein 	}
40795646373SJack Morgenstein 
408146f3ef4SJack Morgenstein 	if (port > 0) {
409872bf2fbSYishai Hadas 		res_alloc->allocated[(port - 1) *
410872bf2fbSYishai Hadas 		(dev->persist->num_vfs + 1) + slave] -= count;
411146f3ef4SJack Morgenstein 		res_alloc->res_port_free[port - 1] += count;
41295646373SJack Morgenstein 		res_alloc->res_port_rsvd[port - 1] += from_rsvd;
413146f3ef4SJack Morgenstein 	} else {
414146f3ef4SJack Morgenstein 		res_alloc->allocated[slave] -= count;
415146f3ef4SJack Morgenstein 		res_alloc->res_free += count;
41695646373SJack Morgenstein 		res_alloc->res_reserved += from_rsvd;
417146f3ef4SJack Morgenstein 	}
418146f3ef4SJack Morgenstein 
419146f3ef4SJack Morgenstein 	spin_unlock(&res_alloc->alloc_lock);
420146f3ef4SJack Morgenstein 	return;
421146f3ef4SJack Morgenstein }
422146f3ef4SJack Morgenstein 
initialize_res_quotas(struct mlx4_dev * dev,struct resource_allocator * res_alloc,enum mlx4_resource res_type,int vf,int num_instances)4235a0d0a61SJack Morgenstein static inline void initialize_res_quotas(struct mlx4_dev *dev,
4245a0d0a61SJack Morgenstein 					 struct resource_allocator *res_alloc,
4255a0d0a61SJack Morgenstein 					 enum mlx4_resource res_type,
4265a0d0a61SJack Morgenstein 					 int vf, int num_instances)
4275a0d0a61SJack Morgenstein {
428872bf2fbSYishai Hadas 	res_alloc->guaranteed[vf] = num_instances /
429872bf2fbSYishai Hadas 				    (2 * (dev->persist->num_vfs + 1));
4305a0d0a61SJack Morgenstein 	res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf];
4315a0d0a61SJack Morgenstein 	if (vf == mlx4_master_func_num(dev)) {
4325a0d0a61SJack Morgenstein 		res_alloc->res_free = num_instances;
4335a0d0a61SJack Morgenstein 		if (res_type == RES_MTT) {
4345a0d0a61SJack Morgenstein 			/* reserved mtts will be taken out of the PF allocation */
4355a0d0a61SJack Morgenstein 			res_alloc->res_free += dev->caps.reserved_mtts;
4365a0d0a61SJack Morgenstein 			res_alloc->guaranteed[vf] += dev->caps.reserved_mtts;
4375a0d0a61SJack Morgenstein 			res_alloc->quota[vf] += dev->caps.reserved_mtts;
4385a0d0a61SJack Morgenstein 		}
4395a0d0a61SJack Morgenstein 	}
4405a0d0a61SJack Morgenstein }
4415a0d0a61SJack Morgenstein 
mlx4_init_quotas(struct mlx4_dev * dev)4425a0d0a61SJack Morgenstein void mlx4_init_quotas(struct mlx4_dev *dev)
4435a0d0a61SJack Morgenstein {
4445a0d0a61SJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
4455a0d0a61SJack Morgenstein 	int pf;
4465a0d0a61SJack Morgenstein 
4475a0d0a61SJack Morgenstein 	/* quotas for VFs are initialized in mlx4_slave_cap */
4485a0d0a61SJack Morgenstein 	if (mlx4_is_slave(dev))
4495a0d0a61SJack Morgenstein 		return;
4505a0d0a61SJack Morgenstein 
4515a0d0a61SJack Morgenstein 	if (!mlx4_is_mfunc(dev)) {
4525a0d0a61SJack Morgenstein 		dev->quotas.qp = dev->caps.num_qps - dev->caps.reserved_qps -
4535a0d0a61SJack Morgenstein 			mlx4_num_reserved_sqps(dev);
4545a0d0a61SJack Morgenstein 		dev->quotas.cq = dev->caps.num_cqs - dev->caps.reserved_cqs;
4555a0d0a61SJack Morgenstein 		dev->quotas.srq = dev->caps.num_srqs - dev->caps.reserved_srqs;
4565a0d0a61SJack Morgenstein 		dev->quotas.mtt = dev->caps.num_mtts - dev->caps.reserved_mtts;
4575a0d0a61SJack Morgenstein 		dev->quotas.mpt = dev->caps.num_mpts - dev->caps.reserved_mrws;
4585a0d0a61SJack Morgenstein 		return;
4595a0d0a61SJack Morgenstein 	}
4605a0d0a61SJack Morgenstein 
4615a0d0a61SJack Morgenstein 	pf = mlx4_master_func_num(dev);
4625a0d0a61SJack Morgenstein 	dev->quotas.qp =
4635a0d0a61SJack Morgenstein 		priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[pf];
4645a0d0a61SJack Morgenstein 	dev->quotas.cq =
4655a0d0a61SJack Morgenstein 		priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[pf];
4665a0d0a61SJack Morgenstein 	dev->quotas.srq =
4675a0d0a61SJack Morgenstein 		priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[pf];
4685a0d0a61SJack Morgenstein 	dev->quotas.mtt =
4695a0d0a61SJack Morgenstein 		priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[pf];
4705a0d0a61SJack Morgenstein 	dev->quotas.mpt =
4715a0d0a61SJack Morgenstein 		priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf];
4725a0d0a61SJack Morgenstein }
4739de92c60SEran Ben Elisha 
474e19868efSEran Ben Elisha static int
mlx4_calc_res_counter_guaranteed(struct mlx4_dev * dev,struct resource_allocator * res_alloc,int vf)475e19868efSEran Ben Elisha mlx4_calc_res_counter_guaranteed(struct mlx4_dev *dev,
476e19868efSEran Ben Elisha 				 struct resource_allocator *res_alloc,
477e19868efSEran Ben Elisha 				 int vf)
4789de92c60SEran Ben Elisha {
479e19868efSEran Ben Elisha 	struct mlx4_active_ports actv_ports;
480e19868efSEran Ben Elisha 	int ports, counters_guaranteed;
481e19868efSEran Ben Elisha 
482e19868efSEran Ben Elisha 	/* For master, only allocate according to the number of phys ports */
483e19868efSEran Ben Elisha 	if (vf == mlx4_master_func_num(dev))
484e19868efSEran Ben Elisha 		return MLX4_PF_COUNTERS_PER_PORT * dev->caps.num_ports;
485e19868efSEran Ben Elisha 
486e19868efSEran Ben Elisha 	/* calculate real number of ports for the VF */
487e19868efSEran Ben Elisha 	actv_ports = mlx4_get_active_ports(dev, vf);
488e19868efSEran Ben Elisha 	ports = bitmap_weight(actv_ports.ports, dev->caps.num_ports);
489e19868efSEran Ben Elisha 	counters_guaranteed = ports * MLX4_VF_COUNTERS_PER_PORT;
490e19868efSEran Ben Elisha 
491e19868efSEran Ben Elisha 	/* If we do not have enough counters for this VF, do not
492e19868efSEran Ben Elisha 	 * allocate any for it. '-1' to reduce the sink counter.
493e19868efSEran Ben Elisha 	 */
494e19868efSEran Ben Elisha 	if ((res_alloc->res_reserved + counters_guaranteed) >
495e19868efSEran Ben Elisha 	    (dev->caps.max_counters - 1))
496e19868efSEran Ben Elisha 		return 0;
497e19868efSEran Ben Elisha 
498e19868efSEran Ben Elisha 	return counters_guaranteed;
4999de92c60SEran Ben Elisha }
5009de92c60SEran Ben Elisha 
mlx4_init_resource_tracker(struct mlx4_dev * dev)501c82e9aa0SEli Cohen int mlx4_init_resource_tracker(struct mlx4_dev *dev)
502c82e9aa0SEli Cohen {
503c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
5045a0d0a61SJack Morgenstein 	int i, j;
505c82e9aa0SEli Cohen 	int t;
506c82e9aa0SEli Cohen 
507c82e9aa0SEli Cohen 	priv->mfunc.master.res_tracker.slave_list =
5086396bb22SKees Cook 		kcalloc(dev->num_slaves, sizeof(struct slave_list),
509c82e9aa0SEli Cohen 			GFP_KERNEL);
510c82e9aa0SEli Cohen 	if (!priv->mfunc.master.res_tracker.slave_list)
511c82e9aa0SEli Cohen 		return -ENOMEM;
512c82e9aa0SEli Cohen 
513c82e9aa0SEli Cohen 	for (i = 0 ; i < dev->num_slaves; i++) {
514c82e9aa0SEli Cohen 		for (t = 0; t < MLX4_NUM_OF_RESOURCE_TYPE; ++t)
515c82e9aa0SEli Cohen 			INIT_LIST_HEAD(&priv->mfunc.master.res_tracker.
516c82e9aa0SEli Cohen 				       slave_list[i].res_list[t]);
517c82e9aa0SEli Cohen 		mutex_init(&priv->mfunc.master.res_tracker.slave_list[i].mutex);
518c82e9aa0SEli Cohen 	}
519c82e9aa0SEli Cohen 
520c82e9aa0SEli Cohen 	mlx4_dbg(dev, "Started init_resource_tracker: %ld slaves\n",
521c82e9aa0SEli Cohen 		 dev->num_slaves);
522c82e9aa0SEli Cohen 	for (i = 0 ; i < MLX4_NUM_OF_RESOURCE_TYPE; i++)
5234af1c048SHadar Hen Zion 		priv->mfunc.master.res_tracker.res_tree[i] = RB_ROOT;
524c82e9aa0SEli Cohen 
5255a0d0a61SJack Morgenstein 	for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {
5265a0d0a61SJack Morgenstein 		struct resource_allocator *res_alloc =
5275a0d0a61SJack Morgenstein 			&priv->mfunc.master.res_tracker.res_alloc[i];
5286da2ec56SKees Cook 		res_alloc->quota = kmalloc_array(dev->persist->num_vfs + 1,
5296da2ec56SKees Cook 						 sizeof(int),
5306da2ec56SKees Cook 						 GFP_KERNEL);
5316da2ec56SKees Cook 		res_alloc->guaranteed = kmalloc_array(dev->persist->num_vfs + 1,
5326da2ec56SKees Cook 						      sizeof(int),
5336da2ec56SKees Cook 						      GFP_KERNEL);
5345a0d0a61SJack Morgenstein 		if (i == RES_MAC || i == RES_VLAN)
5356396bb22SKees Cook 			res_alloc->allocated =
5366396bb22SKees Cook 				kcalloc(MLX4_MAX_PORTS *
5376396bb22SKees Cook 						(dev->persist->num_vfs + 1),
538872bf2fbSYishai Hadas 					sizeof(int), GFP_KERNEL);
5395a0d0a61SJack Morgenstein 		else
5406396bb22SKees Cook 			res_alloc->allocated =
5416396bb22SKees Cook 				kcalloc(dev->persist->num_vfs + 1,
542872bf2fbSYishai Hadas 					sizeof(int), GFP_KERNEL);
5439de92c60SEran Ben Elisha 		/* Reduce the sink counter */
5449de92c60SEran Ben Elisha 		if (i == RES_COUNTER)
5459de92c60SEran Ben Elisha 			res_alloc->res_free = dev->caps.max_counters - 1;
5465a0d0a61SJack Morgenstein 
5475a0d0a61SJack Morgenstein 		if (!res_alloc->quota || !res_alloc->guaranteed ||
5485a0d0a61SJack Morgenstein 		    !res_alloc->allocated)
5495a0d0a61SJack Morgenstein 			goto no_mem_err;
5505a0d0a61SJack Morgenstein 
551146f3ef4SJack Morgenstein 		spin_lock_init(&res_alloc->alloc_lock);
552872bf2fbSYishai Hadas 		for (t = 0; t < dev->persist->num_vfs + 1; t++) {
553449fc488SMatan Barak 			struct mlx4_active_ports actv_ports =
554449fc488SMatan Barak 				mlx4_get_active_ports(dev, t);
5555a0d0a61SJack Morgenstein 			switch (i) {
5565a0d0a61SJack Morgenstein 			case RES_QP:
5575a0d0a61SJack Morgenstein 				initialize_res_quotas(dev, res_alloc, RES_QP,
5585a0d0a61SJack Morgenstein 						      t, dev->caps.num_qps -
5595a0d0a61SJack Morgenstein 						      dev->caps.reserved_qps -
5605a0d0a61SJack Morgenstein 						      mlx4_num_reserved_sqps(dev));
5615a0d0a61SJack Morgenstein 				break;
5625a0d0a61SJack Morgenstein 			case RES_CQ:
5635a0d0a61SJack Morgenstein 				initialize_res_quotas(dev, res_alloc, RES_CQ,
5645a0d0a61SJack Morgenstein 						      t, dev->caps.num_cqs -
5655a0d0a61SJack Morgenstein 						      dev->caps.reserved_cqs);
5665a0d0a61SJack Morgenstein 				break;
5675a0d0a61SJack Morgenstein 			case RES_SRQ:
5685a0d0a61SJack Morgenstein 				initialize_res_quotas(dev, res_alloc, RES_SRQ,
5695a0d0a61SJack Morgenstein 						      t, dev->caps.num_srqs -
5705a0d0a61SJack Morgenstein 						      dev->caps.reserved_srqs);
5715a0d0a61SJack Morgenstein 				break;
5725a0d0a61SJack Morgenstein 			case RES_MPT:
5735a0d0a61SJack Morgenstein 				initialize_res_quotas(dev, res_alloc, RES_MPT,
5745a0d0a61SJack Morgenstein 						      t, dev->caps.num_mpts -
5755a0d0a61SJack Morgenstein 						      dev->caps.reserved_mrws);
5765a0d0a61SJack Morgenstein 				break;
5775a0d0a61SJack Morgenstein 			case RES_MTT:
5785a0d0a61SJack Morgenstein 				initialize_res_quotas(dev, res_alloc, RES_MTT,
5795a0d0a61SJack Morgenstein 						      t, dev->caps.num_mtts -
5805a0d0a61SJack Morgenstein 						      dev->caps.reserved_mtts);
5815a0d0a61SJack Morgenstein 				break;
5825a0d0a61SJack Morgenstein 			case RES_MAC:
5835a0d0a61SJack Morgenstein 				if (t == mlx4_master_func_num(dev)) {
584449fc488SMatan Barak 					int max_vfs_pport = 0;
585449fc488SMatan Barak 					/* Calculate the max vfs per port for */
586449fc488SMatan Barak 					/* both ports.			      */
587449fc488SMatan Barak 					for (j = 0; j < dev->caps.num_ports;
588449fc488SMatan Barak 					     j++) {
589449fc488SMatan Barak 						struct mlx4_slaves_pport slaves_pport =
590449fc488SMatan Barak 							mlx4_phys_to_slaves_pport(dev, j + 1);
591449fc488SMatan Barak 						unsigned current_slaves =
592449fc488SMatan Barak 							bitmap_weight(slaves_pport.slaves,
593449fc488SMatan Barak 								      dev->caps.num_ports) - 1;
594449fc488SMatan Barak 						if (max_vfs_pport < current_slaves)
595449fc488SMatan Barak 							max_vfs_pport =
596449fc488SMatan Barak 								current_slaves;
597449fc488SMatan Barak 					}
598449fc488SMatan Barak 					res_alloc->quota[t] =
599449fc488SMatan Barak 						MLX4_MAX_MAC_NUM -
600449fc488SMatan Barak 						2 * max_vfs_pport;
6015a0d0a61SJack Morgenstein 					res_alloc->guaranteed[t] = 2;
6025a0d0a61SJack Morgenstein 					for (j = 0; j < MLX4_MAX_PORTS; j++)
603449fc488SMatan Barak 						res_alloc->res_port_free[j] =
604449fc488SMatan Barak 							MLX4_MAX_MAC_NUM;
6055a0d0a61SJack Morgenstein 				} else {
6065a0d0a61SJack Morgenstein 					res_alloc->quota[t] = MLX4_MAX_MAC_NUM;
6075a0d0a61SJack Morgenstein 					res_alloc->guaranteed[t] = 2;
6085a0d0a61SJack Morgenstein 				}
6095a0d0a61SJack Morgenstein 				break;
6105a0d0a61SJack Morgenstein 			case RES_VLAN:
6115a0d0a61SJack Morgenstein 				if (t == mlx4_master_func_num(dev)) {
6125a0d0a61SJack Morgenstein 					res_alloc->quota[t] = MLX4_MAX_VLAN_NUM;
6135a0d0a61SJack Morgenstein 					res_alloc->guaranteed[t] = MLX4_MAX_VLAN_NUM / 2;
6145a0d0a61SJack Morgenstein 					for (j = 0; j < MLX4_MAX_PORTS; j++)
6155a0d0a61SJack Morgenstein 						res_alloc->res_port_free[j] =
6165a0d0a61SJack Morgenstein 							res_alloc->quota[t];
6175a0d0a61SJack Morgenstein 				} else {
6185a0d0a61SJack Morgenstein 					res_alloc->quota[t] = MLX4_MAX_VLAN_NUM / 2;
6195a0d0a61SJack Morgenstein 					res_alloc->guaranteed[t] = 0;
6205a0d0a61SJack Morgenstein 				}
6215a0d0a61SJack Morgenstein 				break;
6225a0d0a61SJack Morgenstein 			case RES_COUNTER:
6235a0d0a61SJack Morgenstein 				res_alloc->quota[t] = dev->caps.max_counters;
6249de92c60SEran Ben Elisha 				res_alloc->guaranteed[t] =
625e19868efSEran Ben Elisha 					mlx4_calc_res_counter_guaranteed(dev, res_alloc, t);
6265a0d0a61SJack Morgenstein 				break;
6275a0d0a61SJack Morgenstein 			default:
6285a0d0a61SJack Morgenstein 				break;
6295a0d0a61SJack Morgenstein 			}
6305a0d0a61SJack Morgenstein 			if (i == RES_MAC || i == RES_VLAN) {
631449fc488SMatan Barak 				for (j = 0; j < dev->caps.num_ports; j++)
632449fc488SMatan Barak 					if (test_bit(j, actv_ports.ports))
6335a0d0a61SJack Morgenstein 						res_alloc->res_port_rsvd[j] +=
6345a0d0a61SJack Morgenstein 							res_alloc->guaranteed[t];
6355a0d0a61SJack Morgenstein 			} else {
6365a0d0a61SJack Morgenstein 				res_alloc->res_reserved += res_alloc->guaranteed[t];
6375a0d0a61SJack Morgenstein 			}
6385a0d0a61SJack Morgenstein 		}
6395a0d0a61SJack Morgenstein 	}
640c82e9aa0SEli Cohen 	spin_lock_init(&priv->mfunc.master.res_tracker.lock);
641c82e9aa0SEli Cohen 	return 0;
6425a0d0a61SJack Morgenstein 
6435a0d0a61SJack Morgenstein no_mem_err:
6445a0d0a61SJack Morgenstein 	for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {
6455a0d0a61SJack Morgenstein 		kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated);
6465a0d0a61SJack Morgenstein 		priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL;
6475a0d0a61SJack Morgenstein 		kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed);
6485a0d0a61SJack Morgenstein 		priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL;
6495a0d0a61SJack Morgenstein 		kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota);
6505a0d0a61SJack Morgenstein 		priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL;
6515a0d0a61SJack Morgenstein 	}
6525a0d0a61SJack Morgenstein 	return -ENOMEM;
653c82e9aa0SEli Cohen }
654c82e9aa0SEli Cohen 
mlx4_free_resource_tracker(struct mlx4_dev * dev,enum mlx4_res_tracker_free_type type)655b8924951SJack Morgenstein void mlx4_free_resource_tracker(struct mlx4_dev *dev,
656b8924951SJack Morgenstein 				enum mlx4_res_tracker_free_type type)
657c82e9aa0SEli Cohen {
658c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
659c82e9aa0SEli Cohen 	int i;
660c82e9aa0SEli Cohen 
661c82e9aa0SEli Cohen 	if (priv->mfunc.master.res_tracker.slave_list) {
6624874080dSJack Morgenstein 		if (type != RES_TR_FREE_STRUCTS_ONLY) {
6634874080dSJack Morgenstein 			for (i = 0; i < dev->num_slaves; i++) {
664b8924951SJack Morgenstein 				if (type == RES_TR_FREE_ALL ||
665b8924951SJack Morgenstein 				    dev->caps.function != i)
666c82e9aa0SEli Cohen 					mlx4_delete_all_resources_for_slave(dev, i);
6674874080dSJack Morgenstein 			}
6684874080dSJack Morgenstein 			/* free master's vlans */
6694874080dSJack Morgenstein 			i = dev->caps.function;
670111c6094SJack Morgenstein 			mlx4_reset_roce_gids(dev, i);
6714874080dSJack Morgenstein 			mutex_lock(&priv->mfunc.master.res_tracker.slave_list[i].mutex);
6724874080dSJack Morgenstein 			rem_slave_vlans(dev, i);
6734874080dSJack Morgenstein 			mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[i].mutex);
6744874080dSJack Morgenstein 		}
675c82e9aa0SEli Cohen 
676b8924951SJack Morgenstein 		if (type != RES_TR_FREE_SLAVES_ONLY) {
6775a0d0a61SJack Morgenstein 			for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {
6785a0d0a61SJack Morgenstein 				kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated);
6795a0d0a61SJack Morgenstein 				priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL;
6805a0d0a61SJack Morgenstein 				kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed);
6815a0d0a61SJack Morgenstein 				priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL;
6825a0d0a61SJack Morgenstein 				kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota);
6835a0d0a61SJack Morgenstein 				priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL;
6845a0d0a61SJack Morgenstein 			}
685c82e9aa0SEli Cohen 			kfree(priv->mfunc.master.res_tracker.slave_list);
686b8924951SJack Morgenstein 			priv->mfunc.master.res_tracker.slave_list = NULL;
687b8924951SJack Morgenstein 		}
688c82e9aa0SEli Cohen 	}
689c82e9aa0SEli Cohen }
690c82e9aa0SEli Cohen 
update_pkey_index(struct mlx4_dev * dev,int slave,struct mlx4_cmd_mailbox * inbox)69154679e14SJack Morgenstein static void update_pkey_index(struct mlx4_dev *dev, int slave,
69254679e14SJack Morgenstein 			      struct mlx4_cmd_mailbox *inbox)
693c82e9aa0SEli Cohen {
69454679e14SJack Morgenstein 	u8 sched = *(u8 *)(inbox->buf + 64);
69554679e14SJack Morgenstein 	u8 orig_index = *(u8 *)(inbox->buf + 35);
69654679e14SJack Morgenstein 	u8 new_index;
69754679e14SJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
69854679e14SJack Morgenstein 	int port;
69954679e14SJack Morgenstein 
70054679e14SJack Morgenstein 	port = (sched >> 6 & 1) + 1;
70154679e14SJack Morgenstein 
70254679e14SJack Morgenstein 	new_index = priv->virt2phys_pkey[slave][port - 1][orig_index];
70354679e14SJack Morgenstein 	*(u8 *)(inbox->buf + 35) = new_index;
70454679e14SJack Morgenstein }
70554679e14SJack Morgenstein 
update_gid(struct mlx4_dev * dev,struct mlx4_cmd_mailbox * inbox,u8 slave)70654679e14SJack Morgenstein static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,
70754679e14SJack Morgenstein 		       u8 slave)
70854679e14SJack Morgenstein {
70954679e14SJack Morgenstein 	struct mlx4_qp_context	*qp_ctx = inbox->buf + 8;
71054679e14SJack Morgenstein 	enum mlx4_qp_optpar	optpar = be32_to_cpu(*(__be32 *) inbox->buf);
711c82e9aa0SEli Cohen 	u32			ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;
712b6ffaeffSJack Morgenstein 	int port;
713c82e9aa0SEli Cohen 
714b6ffaeffSJack Morgenstein 	if (MLX4_QP_ST_UD == ts) {
715b6ffaeffSJack Morgenstein 		port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
716b6ffaeffSJack Morgenstein 		if (mlx4_is_eth(dev, port))
717449fc488SMatan Barak 			qp_ctx->pri_path.mgid_index =
718449fc488SMatan Barak 				mlx4_get_base_gid_ix(dev, slave, port) | 0x80;
719b6ffaeffSJack Morgenstein 		else
720b6ffaeffSJack Morgenstein 			qp_ctx->pri_path.mgid_index = slave | 0x80;
721c82e9aa0SEli Cohen 
722b6ffaeffSJack Morgenstein 	} else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_XRC == ts || MLX4_QP_ST_UC == ts) {
723b6ffaeffSJack Morgenstein 		if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {
724b6ffaeffSJack Morgenstein 			port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
725b6ffaeffSJack Morgenstein 			if (mlx4_is_eth(dev, port)) {
726449fc488SMatan Barak 				qp_ctx->pri_path.mgid_index +=
727449fc488SMatan Barak 					mlx4_get_base_gid_ix(dev, slave, port);
728b6ffaeffSJack Morgenstein 				qp_ctx->pri_path.mgid_index &= 0x7f;
729b6ffaeffSJack Morgenstein 			} else {
73054679e14SJack Morgenstein 				qp_ctx->pri_path.mgid_index = slave & 0x7F;
731b6ffaeffSJack Morgenstein 			}
732b6ffaeffSJack Morgenstein 		}
733b6ffaeffSJack Morgenstein 		if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
734b6ffaeffSJack Morgenstein 			port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1;
735b6ffaeffSJack Morgenstein 			if (mlx4_is_eth(dev, port)) {
736449fc488SMatan Barak 				qp_ctx->alt_path.mgid_index +=
737449fc488SMatan Barak 					mlx4_get_base_gid_ix(dev, slave, port);
738b6ffaeffSJack Morgenstein 				qp_ctx->alt_path.mgid_index &= 0x7f;
739b6ffaeffSJack Morgenstein 			} else {
74054679e14SJack Morgenstein 				qp_ctx->alt_path.mgid_index = slave & 0x7F;
74154679e14SJack Morgenstein 			}
742c82e9aa0SEli Cohen 		}
743b6ffaeffSJack Morgenstein 	}
744b6ffaeffSJack Morgenstein }
745c82e9aa0SEli Cohen 
74668230242SEran Ben Elisha static int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc,
74768230242SEran Ben Elisha 			  u8 slave, int port);
74868230242SEran Ben Elisha 
update_vport_qp_param(struct mlx4_dev * dev,struct mlx4_cmd_mailbox * inbox,u8 slave,u32 qpn)7493f7fb021SRony Efraim static int update_vport_qp_param(struct mlx4_dev *dev,
7503f7fb021SRony Efraim 				 struct mlx4_cmd_mailbox *inbox,
751b01978caSJack Morgenstein 				 u8 slave, u32 qpn)
7523f7fb021SRony Efraim {
7533f7fb021SRony Efraim 	struct mlx4_qp_context	*qpc = inbox->buf + 8;
7543f7fb021SRony Efraim 	struct mlx4_vport_oper_state *vp_oper;
7553f7fb021SRony Efraim 	struct mlx4_priv *priv;
75609e05c3fSMatan Barak 	u32 qp_type;
757f5956fafSOr Gerlitz 	int port, err = 0;
7583f7fb021SRony Efraim 
7593f7fb021SRony Efraim 	port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1;
7603f7fb021SRony Efraim 	priv = mlx4_priv(dev);
7613f7fb021SRony Efraim 	vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
76209e05c3fSMatan Barak 	qp_type	= (be32_to_cpu(qpc->flags) >> 16) & 0xff;
7633f7fb021SRony Efraim 
76468230242SEran Ben Elisha 	err = handle_counter(dev, qpc, slave, port);
76568230242SEran Ben Elisha 	if (err)
76668230242SEran Ben Elisha 		goto out;
76768230242SEran Ben Elisha 
7683f7fb021SRony Efraim 	if (MLX4_VGT != vp_oper->state.default_vlan) {
769b01978caSJack Morgenstein 		/* the reserved QPs (special, proxy, tunnel)
770b01978caSJack Morgenstein 		 * do not operate over vlans
771b01978caSJack Morgenstein 		 */
772b01978caSJack Morgenstein 		if (mlx4_is_qp_reserved(dev, qpn))
773b01978caSJack Morgenstein 			return 0;
774b01978caSJack Morgenstein 
77509e05c3fSMatan Barak 		/* force strip vlan by clear vsd, MLX QP refers to Raw Ethernet */
77609e05c3fSMatan Barak 		if (qp_type == MLX4_QP_ST_UD ||
77709e05c3fSMatan Barak 		    (qp_type == MLX4_QP_ST_MLX && mlx4_is_eth(dev, port))) {
77809e05c3fSMatan Barak 			if (dev->caps.bmme_flags & MLX4_BMME_FLAG_VSD_INIT2RTR) {
77909e05c3fSMatan Barak 				*(__be32 *)inbox->buf =
78009e05c3fSMatan Barak 					cpu_to_be32(be32_to_cpu(*(__be32 *)inbox->buf) |
78109e05c3fSMatan Barak 					MLX4_QP_OPTPAR_VLAN_STRIPPING);
7827677fc96SRony Efraim 				qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN);
78309e05c3fSMatan Barak 			} else {
78409e05c3fSMatan Barak 				struct mlx4_update_qp_params params = {.flags = 0};
78509e05c3fSMatan Barak 
786f5956fafSOr Gerlitz 				err = mlx4_update_qp(dev, qpn, MLX4_UPDATE_QP_VSD, &params);
787f5956fafSOr Gerlitz 				if (err)
788f5956fafSOr Gerlitz 					goto out;
78909e05c3fSMatan Barak 			}
79009e05c3fSMatan Barak 		}
7910a6eac24SRony Efraim 
7929a892835SMaor Gottlieb 		/* preserve IF_COUNTER flag */
7939a892835SMaor Gottlieb 		qpc->pri_path.vlan_control &=
7949a892835SMaor Gottlieb 			MLX4_CTRL_ETH_SRC_CHECK_IF_COUNTER;
7950a6eac24SRony Efraim 		if (vp_oper->state.link_state == IFLA_VF_LINK_STATE_DISABLE &&
7960a6eac24SRony Efraim 		    dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) {
7979a892835SMaor Gottlieb 			qpc->pri_path.vlan_control |=
7980a6eac24SRony Efraim 				MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
7990a6eac24SRony Efraim 				MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
8000a6eac24SRony Efraim 				MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED |
8010a6eac24SRony Efraim 				MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
8020a6eac24SRony Efraim 				MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED |
8030a6eac24SRony Efraim 				MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
8040a6eac24SRony Efraim 		} else if (0 != vp_oper->state.default_vlan) {
8057c3d21c8SMoshe Shemesh 			if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD)) {
8067c3d21c8SMoshe Shemesh 				/* vst QinQ should block untagged on TX,
8077c3d21c8SMoshe Shemesh 				 * but cvlan is in payload and phv is set so
8087c3d21c8SMoshe Shemesh 				 * hw see it as untagged. Block tagged instead.
8097c3d21c8SMoshe Shemesh 				 */
8107c3d21c8SMoshe Shemesh 				qpc->pri_path.vlan_control |=
8117c3d21c8SMoshe Shemesh 					MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
8127c3d21c8SMoshe Shemesh 					MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
8137c3d21c8SMoshe Shemesh 					MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
8147c3d21c8SMoshe Shemesh 					MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
8157c3d21c8SMoshe Shemesh 			} else { /* vst 802.1Q */
8169a892835SMaor Gottlieb 				qpc->pri_path.vlan_control |=
8177677fc96SRony Efraim 					MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
8187677fc96SRony Efraim 					MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
8197677fc96SRony Efraim 					MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
8207c3d21c8SMoshe Shemesh 			}
8217677fc96SRony Efraim 		} else { /* priority tagged */
8229a892835SMaor Gottlieb 			qpc->pri_path.vlan_control |=
8237677fc96SRony Efraim 				MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
8247677fc96SRony Efraim 				MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
8257677fc96SRony Efraim 		}
8267677fc96SRony Efraim 
8277677fc96SRony Efraim 		qpc->pri_path.fvl_rx |= MLX4_FVL_RX_FORCE_ETH_VLAN;
8283f7fb021SRony Efraim 		qpc->pri_path.vlan_index = vp_oper->vlan_idx;
8297c3d21c8SMoshe Shemesh 		qpc->pri_path.fl |= MLX4_FL_ETH_HIDE_CQE_VLAN;
8307c3d21c8SMoshe Shemesh 		if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD))
8317c3d21c8SMoshe Shemesh 			qpc->pri_path.fl |= MLX4_FL_SV;
8327c3d21c8SMoshe Shemesh 		else
8337c3d21c8SMoshe Shemesh 			qpc->pri_path.fl |= MLX4_FL_CV;
8347677fc96SRony Efraim 		qpc->pri_path.feup |= MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN;
8353f7fb021SRony Efraim 		qpc->pri_path.sched_queue &= 0xC7;
8363f7fb021SRony Efraim 		qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3;
83708068cd5SIdo Shamay 		qpc->qos_vport = vp_oper->state.qos_vport;
8383f7fb021SRony Efraim 	}
839e6b6a231SRony Efraim 	if (vp_oper->state.spoofchk) {
8407677fc96SRony Efraim 		qpc->pri_path.feup |= MLX4_FSM_FORCE_ETH_SRC_MAC;
841e6b6a231SRony Efraim 		qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx;
842e6b6a231SRony Efraim 	}
843f5956fafSOr Gerlitz out:
844f5956fafSOr Gerlitz 	return err;
8453f7fb021SRony Efraim }
8463f7fb021SRony Efraim 
mpt_mask(struct mlx4_dev * dev)847c82e9aa0SEli Cohen static int mpt_mask(struct mlx4_dev *dev)
848c82e9aa0SEli Cohen {
849c82e9aa0SEli Cohen 	return dev->caps.num_mpts - 1;
850c82e9aa0SEli Cohen }
851c82e9aa0SEli Cohen 
mlx4_resource_type_to_str(enum mlx4_resource t)852ae5a2e29SMatan Barak static const char *mlx4_resource_type_to_str(enum mlx4_resource t)
853ae5a2e29SMatan Barak {
854ae5a2e29SMatan Barak 	switch (t) {
855ae5a2e29SMatan Barak 	case RES_QP:
856ae5a2e29SMatan Barak 		return "QP";
857ae5a2e29SMatan Barak 	case RES_CQ:
858ae5a2e29SMatan Barak 		return "CQ";
859ae5a2e29SMatan Barak 	case RES_SRQ:
860ae5a2e29SMatan Barak 		return "SRQ";
861ae5a2e29SMatan Barak 	case RES_XRCD:
862ae5a2e29SMatan Barak 		return "XRCD";
863ae5a2e29SMatan Barak 	case RES_MPT:
864ae5a2e29SMatan Barak 		return "MPT";
865ae5a2e29SMatan Barak 	case RES_MTT:
866ae5a2e29SMatan Barak 		return "MTT";
867ae5a2e29SMatan Barak 	case RES_MAC:
868ae5a2e29SMatan Barak 		return "MAC";
869ae5a2e29SMatan Barak 	case RES_VLAN:
870ae5a2e29SMatan Barak 		return "VLAN";
871ae5a2e29SMatan Barak 	case RES_COUNTER:
872ae5a2e29SMatan Barak 		return "COUNTER";
873ae5a2e29SMatan Barak 	case RES_FS_RULE:
874ae5a2e29SMatan Barak 		return "FS_RULE";
875ae5a2e29SMatan Barak 	case RES_EQ:
876ae5a2e29SMatan Barak 		return "EQ";
877ae5a2e29SMatan Barak 	default:
878ae5a2e29SMatan Barak 		return "INVALID RESOURCE";
879ae5a2e29SMatan Barak 	}
880ae5a2e29SMatan Barak }
881ae5a2e29SMatan Barak 
find_res(struct mlx4_dev * dev,u64 res_id,enum mlx4_resource type)8821e3f7b32SHadar Hen Zion static void *find_res(struct mlx4_dev *dev, u64 res_id,
883c82e9aa0SEli Cohen 		      enum mlx4_resource type)
884c82e9aa0SEli Cohen {
885c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
886c82e9aa0SEli Cohen 
8874af1c048SHadar Hen Zion 	return res_tracker_lookup(&priv->mfunc.master.res_tracker.res_tree[type],
888c82e9aa0SEli Cohen 				  res_id);
889c82e9aa0SEli Cohen }
890c82e9aa0SEli Cohen 
_get_res(struct mlx4_dev * dev,int slave,u64 res_id,enum mlx4_resource type,void * res,const char * func_name)891ae5a2e29SMatan Barak static int _get_res(struct mlx4_dev *dev, int slave, u64 res_id,
892c82e9aa0SEli Cohen 		    enum mlx4_resource type,
893ae5a2e29SMatan Barak 		    void *res, const char *func_name)
894c82e9aa0SEli Cohen {
895c82e9aa0SEli Cohen 	struct res_common *r;
896c82e9aa0SEli Cohen 	int err = 0;
897c82e9aa0SEli Cohen 
898c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
899c82e9aa0SEli Cohen 	r = find_res(dev, res_id, type);
900c82e9aa0SEli Cohen 	if (!r) {
901c82e9aa0SEli Cohen 		err = -ENONET;
902c82e9aa0SEli Cohen 		goto exit;
903c82e9aa0SEli Cohen 	}
904c82e9aa0SEli Cohen 
905c82e9aa0SEli Cohen 	if (r->state == RES_ANY_BUSY) {
906ae5a2e29SMatan Barak 		mlx4_warn(dev,
907ae5a2e29SMatan Barak 			  "%s(%d) trying to get resource %llx of type %s, but it's already taken by %s\n",
908ae5a2e29SMatan Barak 			  func_name, slave, res_id, mlx4_resource_type_to_str(type),
909ae5a2e29SMatan Barak 			  r->func_name);
910c82e9aa0SEli Cohen 		err = -EBUSY;
911c82e9aa0SEli Cohen 		goto exit;
912c82e9aa0SEli Cohen 	}
913c82e9aa0SEli Cohen 
914c82e9aa0SEli Cohen 	if (r->owner != slave) {
915c82e9aa0SEli Cohen 		err = -EPERM;
916c82e9aa0SEli Cohen 		goto exit;
917c82e9aa0SEli Cohen 	}
918c82e9aa0SEli Cohen 
919c82e9aa0SEli Cohen 	r->from_state = r->state;
920c82e9aa0SEli Cohen 	r->state = RES_ANY_BUSY;
921ae5a2e29SMatan Barak 	r->func_name = func_name;
922c82e9aa0SEli Cohen 
923c82e9aa0SEli Cohen 	if (res)
924c82e9aa0SEli Cohen 		*((struct res_common **)res) = r;
925c82e9aa0SEli Cohen 
926c82e9aa0SEli Cohen exit:
927c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
928c82e9aa0SEli Cohen 	return err;
929c82e9aa0SEli Cohen }
930c82e9aa0SEli Cohen 
931ae5a2e29SMatan Barak #define get_res(dev, slave, res_id, type, res) \
932ae5a2e29SMatan Barak 	_get_res((dev), (slave), (res_id), (type), (res), __func__)
933ae5a2e29SMatan Barak 
mlx4_get_slave_from_resource_id(struct mlx4_dev * dev,enum mlx4_resource type,u64 res_id,int * slave)934c82e9aa0SEli Cohen int mlx4_get_slave_from_resource_id(struct mlx4_dev *dev,
935c82e9aa0SEli Cohen 				    enum mlx4_resource type,
936aa1ec3ddSHadar Hen Zion 				    u64 res_id, int *slave)
937c82e9aa0SEli Cohen {
938c82e9aa0SEli Cohen 
939c82e9aa0SEli Cohen 	struct res_common *r;
940c82e9aa0SEli Cohen 	int err = -ENOENT;
941c82e9aa0SEli Cohen 	int id = res_id;
942c82e9aa0SEli Cohen 
943c82e9aa0SEli Cohen 	if (type == RES_QP)
944c82e9aa0SEli Cohen 		id &= 0x7fffff;
945996b0541SYevgeny Petrilin 	spin_lock(mlx4_tlock(dev));
946c82e9aa0SEli Cohen 
947c82e9aa0SEli Cohen 	r = find_res(dev, id, type);
948c82e9aa0SEli Cohen 	if (r) {
949c82e9aa0SEli Cohen 		*slave = r->owner;
950c82e9aa0SEli Cohen 		err = 0;
951c82e9aa0SEli Cohen 	}
952996b0541SYevgeny Petrilin 	spin_unlock(mlx4_tlock(dev));
953c82e9aa0SEli Cohen 
954c82e9aa0SEli Cohen 	return err;
955c82e9aa0SEli Cohen }
956c82e9aa0SEli Cohen 
put_res(struct mlx4_dev * dev,int slave,u64 res_id,enum mlx4_resource type)957aa1ec3ddSHadar Hen Zion static void put_res(struct mlx4_dev *dev, int slave, u64 res_id,
958c82e9aa0SEli Cohen 		    enum mlx4_resource type)
959c82e9aa0SEli Cohen {
960c82e9aa0SEli Cohen 	struct res_common *r;
961c82e9aa0SEli Cohen 
962c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
963c82e9aa0SEli Cohen 	r = find_res(dev, res_id, type);
964ae5a2e29SMatan Barak 	if (r) {
965c82e9aa0SEli Cohen 		r->state = r->from_state;
966ae5a2e29SMatan Barak 		r->func_name = "";
967ae5a2e29SMatan Barak 	}
968c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
969c82e9aa0SEli Cohen }
970c82e9aa0SEli Cohen 
97168230242SEran Ben Elisha static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
97268230242SEran Ben Elisha 			     u64 in_param, u64 *out_param, int port);
97368230242SEran Ben Elisha 
handle_existing_counter(struct mlx4_dev * dev,u8 slave,int port,int counter_index)97468230242SEran Ben Elisha static int handle_existing_counter(struct mlx4_dev *dev, u8 slave, int port,
97568230242SEran Ben Elisha 				   int counter_index)
97668230242SEran Ben Elisha {
97768230242SEran Ben Elisha 	struct res_common *r;
97868230242SEran Ben Elisha 	struct res_counter *counter;
97968230242SEran Ben Elisha 	int ret = 0;
98068230242SEran Ben Elisha 
98168230242SEran Ben Elisha 	if (counter_index == MLX4_SINK_COUNTER_INDEX(dev))
98268230242SEran Ben Elisha 		return ret;
98368230242SEran Ben Elisha 
98468230242SEran Ben Elisha 	spin_lock_irq(mlx4_tlock(dev));
98568230242SEran Ben Elisha 	r = find_res(dev, counter_index, RES_COUNTER);
9866b94bab0SEran Ben Elisha 	if (!r || r->owner != slave) {
98768230242SEran Ben Elisha 		ret = -EINVAL;
9886b94bab0SEran Ben Elisha 	} else {
98968230242SEran Ben Elisha 		counter = container_of(r, struct res_counter, com);
99068230242SEran Ben Elisha 		if (!counter->port)
99168230242SEran Ben Elisha 			counter->port = port;
9926b94bab0SEran Ben Elisha 	}
99368230242SEran Ben Elisha 
99468230242SEran Ben Elisha 	spin_unlock_irq(mlx4_tlock(dev));
99568230242SEran Ben Elisha 	return ret;
99668230242SEran Ben Elisha }
99768230242SEran Ben Elisha 
handle_unexisting_counter(struct mlx4_dev * dev,struct mlx4_qp_context * qpc,u8 slave,int port)99868230242SEran Ben Elisha static int handle_unexisting_counter(struct mlx4_dev *dev,
99968230242SEran Ben Elisha 				     struct mlx4_qp_context *qpc, u8 slave,
100068230242SEran Ben Elisha 				     int port)
100168230242SEran Ben Elisha {
100268230242SEran Ben Elisha 	struct mlx4_priv *priv = mlx4_priv(dev);
100368230242SEran Ben Elisha 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
100468230242SEran Ben Elisha 	struct res_common *tmp;
100568230242SEran Ben Elisha 	struct res_counter *counter;
100668230242SEran Ben Elisha 	u64 counter_idx = MLX4_SINK_COUNTER_INDEX(dev);
100768230242SEran Ben Elisha 	int err = 0;
100868230242SEran Ben Elisha 
100968230242SEran Ben Elisha 	spin_lock_irq(mlx4_tlock(dev));
101068230242SEran Ben Elisha 	list_for_each_entry(tmp,
101168230242SEran Ben Elisha 			    &tracker->slave_list[slave].res_list[RES_COUNTER],
101268230242SEran Ben Elisha 			    list) {
101368230242SEran Ben Elisha 		counter = container_of(tmp, struct res_counter, com);
101468230242SEran Ben Elisha 		if (port == counter->port) {
101568230242SEran Ben Elisha 			qpc->pri_path.counter_index  = counter->com.res_id;
101668230242SEran Ben Elisha 			spin_unlock_irq(mlx4_tlock(dev));
101768230242SEran Ben Elisha 			return 0;
101868230242SEran Ben Elisha 		}
101968230242SEran Ben Elisha 	}
102068230242SEran Ben Elisha 	spin_unlock_irq(mlx4_tlock(dev));
102168230242SEran Ben Elisha 
102268230242SEran Ben Elisha 	/* No existing counter, need to allocate a new counter */
102368230242SEran Ben Elisha 	err = counter_alloc_res(dev, slave, RES_OP_RESERVE, 0, 0, &counter_idx,
102468230242SEran Ben Elisha 				port);
102568230242SEran Ben Elisha 	if (err == -ENOENT) {
102668230242SEran Ben Elisha 		err = 0;
102768230242SEran Ben Elisha 	} else if (err && err != -ENOSPC) {
102868230242SEran Ben Elisha 		mlx4_err(dev, "%s: failed to create new counter for slave %d err %d\n",
102968230242SEran Ben Elisha 			 __func__, slave, err);
103068230242SEran Ben Elisha 	} else {
103168230242SEran Ben Elisha 		qpc->pri_path.counter_index = counter_idx;
103268230242SEran Ben Elisha 		mlx4_dbg(dev, "%s: alloc new counter for slave %d index %d\n",
103368230242SEran Ben Elisha 			 __func__, slave, qpc->pri_path.counter_index);
103468230242SEran Ben Elisha 		err = 0;
103568230242SEran Ben Elisha 	}
103668230242SEran Ben Elisha 
103768230242SEran Ben Elisha 	return err;
103868230242SEran Ben Elisha }
103968230242SEran Ben Elisha 
handle_counter(struct mlx4_dev * dev,struct mlx4_qp_context * qpc,u8 slave,int port)104068230242SEran Ben Elisha static int handle_counter(struct mlx4_dev *dev, struct mlx4_qp_context *qpc,
104168230242SEran Ben Elisha 			  u8 slave, int port)
104268230242SEran Ben Elisha {
104368230242SEran Ben Elisha 	if (qpc->pri_path.counter_index != MLX4_SINK_COUNTER_INDEX(dev))
104468230242SEran Ben Elisha 		return handle_existing_counter(dev, slave, port,
104568230242SEran Ben Elisha 					       qpc->pri_path.counter_index);
104668230242SEran Ben Elisha 
104768230242SEran Ben Elisha 	return handle_unexisting_counter(dev, qpc, slave, port);
104868230242SEran Ben Elisha }
104968230242SEran Ben Elisha 
alloc_qp_tr(int id)1050c82e9aa0SEli Cohen static struct res_common *alloc_qp_tr(int id)
1051c82e9aa0SEli Cohen {
1052c82e9aa0SEli Cohen 	struct res_qp *ret;
1053c82e9aa0SEli Cohen 
105431975e27Sstephen hemminger 	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
1055c82e9aa0SEli Cohen 	if (!ret)
1056c82e9aa0SEli Cohen 		return NULL;
1057c82e9aa0SEli Cohen 
1058c82e9aa0SEli Cohen 	ret->com.res_id = id;
1059c82e9aa0SEli Cohen 	ret->com.state = RES_QP_RESERVED;
10602531188bSEugenia Emantayev 	ret->local_qpn = id;
1061c82e9aa0SEli Cohen 	INIT_LIST_HEAD(&ret->mcg_list);
1062c82e9aa0SEli Cohen 	spin_lock_init(&ret->mcg_spl);
10632c473ae7SHadar Hen Zion 	atomic_set(&ret->ref_count, 0);
1064c82e9aa0SEli Cohen 
1065c82e9aa0SEli Cohen 	return &ret->com;
1066c82e9aa0SEli Cohen }
1067c82e9aa0SEli Cohen 
alloc_mtt_tr(int id,int order)1068c82e9aa0SEli Cohen static struct res_common *alloc_mtt_tr(int id, int order)
1069c82e9aa0SEli Cohen {
1070c82e9aa0SEli Cohen 	struct res_mtt *ret;
1071c82e9aa0SEli Cohen 
107231975e27Sstephen hemminger 	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
1073c82e9aa0SEli Cohen 	if (!ret)
1074c82e9aa0SEli Cohen 		return NULL;
1075c82e9aa0SEli Cohen 
1076c82e9aa0SEli Cohen 	ret->com.res_id = id;
1077c82e9aa0SEli Cohen 	ret->order = order;
1078c82e9aa0SEli Cohen 	ret->com.state = RES_MTT_ALLOCATED;
1079c82e9aa0SEli Cohen 	atomic_set(&ret->ref_count, 0);
1080c82e9aa0SEli Cohen 
1081c82e9aa0SEli Cohen 	return &ret->com;
1082c82e9aa0SEli Cohen }
1083c82e9aa0SEli Cohen 
alloc_mpt_tr(int id,int key)1084c82e9aa0SEli Cohen static struct res_common *alloc_mpt_tr(int id, int key)
1085c82e9aa0SEli Cohen {
1086c82e9aa0SEli Cohen 	struct res_mpt *ret;
1087c82e9aa0SEli Cohen 
108831975e27Sstephen hemminger 	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
1089c82e9aa0SEli Cohen 	if (!ret)
1090c82e9aa0SEli Cohen 		return NULL;
1091c82e9aa0SEli Cohen 
1092c82e9aa0SEli Cohen 	ret->com.res_id = id;
1093c82e9aa0SEli Cohen 	ret->com.state = RES_MPT_RESERVED;
1094c82e9aa0SEli Cohen 	ret->key = key;
1095c82e9aa0SEli Cohen 
1096c82e9aa0SEli Cohen 	return &ret->com;
1097c82e9aa0SEli Cohen }
1098c82e9aa0SEli Cohen 
alloc_eq_tr(int id)1099c82e9aa0SEli Cohen static struct res_common *alloc_eq_tr(int id)
1100c82e9aa0SEli Cohen {
1101c82e9aa0SEli Cohen 	struct res_eq *ret;
1102c82e9aa0SEli Cohen 
110331975e27Sstephen hemminger 	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
1104c82e9aa0SEli Cohen 	if (!ret)
1105c82e9aa0SEli Cohen 		return NULL;
1106c82e9aa0SEli Cohen 
1107c82e9aa0SEli Cohen 	ret->com.res_id = id;
1108c82e9aa0SEli Cohen 	ret->com.state = RES_EQ_RESERVED;
1109c82e9aa0SEli Cohen 
1110c82e9aa0SEli Cohen 	return &ret->com;
1111c82e9aa0SEli Cohen }
1112c82e9aa0SEli Cohen 
alloc_cq_tr(int id)1113c82e9aa0SEli Cohen static struct res_common *alloc_cq_tr(int id)
1114c82e9aa0SEli Cohen {
1115c82e9aa0SEli Cohen 	struct res_cq *ret;
1116c82e9aa0SEli Cohen 
111731975e27Sstephen hemminger 	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
1118c82e9aa0SEli Cohen 	if (!ret)
1119c82e9aa0SEli Cohen 		return NULL;
1120c82e9aa0SEli Cohen 
1121c82e9aa0SEli Cohen 	ret->com.res_id = id;
1122c82e9aa0SEli Cohen 	ret->com.state = RES_CQ_ALLOCATED;
1123c82e9aa0SEli Cohen 	atomic_set(&ret->ref_count, 0);
1124c82e9aa0SEli Cohen 
1125c82e9aa0SEli Cohen 	return &ret->com;
1126c82e9aa0SEli Cohen }
1127c82e9aa0SEli Cohen 
alloc_srq_tr(int id)1128c82e9aa0SEli Cohen static struct res_common *alloc_srq_tr(int id)
1129c82e9aa0SEli Cohen {
1130c82e9aa0SEli Cohen 	struct res_srq *ret;
1131c82e9aa0SEli Cohen 
113231975e27Sstephen hemminger 	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
1133c82e9aa0SEli Cohen 	if (!ret)
1134c82e9aa0SEli Cohen 		return NULL;
1135c82e9aa0SEli Cohen 
1136c82e9aa0SEli Cohen 	ret->com.res_id = id;
1137c82e9aa0SEli Cohen 	ret->com.state = RES_SRQ_ALLOCATED;
1138c82e9aa0SEli Cohen 	atomic_set(&ret->ref_count, 0);
1139c82e9aa0SEli Cohen 
1140c82e9aa0SEli Cohen 	return &ret->com;
1141c82e9aa0SEli Cohen }
1142c82e9aa0SEli Cohen 
alloc_counter_tr(int id,int port)11439de92c60SEran Ben Elisha static struct res_common *alloc_counter_tr(int id, int port)
1144c82e9aa0SEli Cohen {
1145c82e9aa0SEli Cohen 	struct res_counter *ret;
1146c82e9aa0SEli Cohen 
114731975e27Sstephen hemminger 	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
1148c82e9aa0SEli Cohen 	if (!ret)
1149c82e9aa0SEli Cohen 		return NULL;
1150c82e9aa0SEli Cohen 
1151c82e9aa0SEli Cohen 	ret->com.res_id = id;
1152c82e9aa0SEli Cohen 	ret->com.state = RES_COUNTER_ALLOCATED;
11539de92c60SEran Ben Elisha 	ret->port = port;
1154c82e9aa0SEli Cohen 
1155c82e9aa0SEli Cohen 	return &ret->com;
1156c82e9aa0SEli Cohen }
1157c82e9aa0SEli Cohen 
alloc_xrcdn_tr(int id)1158ba062d52SJack Morgenstein static struct res_common *alloc_xrcdn_tr(int id)
1159ba062d52SJack Morgenstein {
1160ba062d52SJack Morgenstein 	struct res_xrcdn *ret;
1161ba062d52SJack Morgenstein 
116231975e27Sstephen hemminger 	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
1163ba062d52SJack Morgenstein 	if (!ret)
1164ba062d52SJack Morgenstein 		return NULL;
1165ba062d52SJack Morgenstein 
1166ba062d52SJack Morgenstein 	ret->com.res_id = id;
1167ba062d52SJack Morgenstein 	ret->com.state = RES_XRCD_ALLOCATED;
1168ba062d52SJack Morgenstein 
1169ba062d52SJack Morgenstein 	return &ret->com;
1170ba062d52SJack Morgenstein }
1171ba062d52SJack Morgenstein 
alloc_fs_rule_tr(u64 id,int qpn)11722c473ae7SHadar Hen Zion static struct res_common *alloc_fs_rule_tr(u64 id, int qpn)
11731b9c6b06SHadar Hen Zion {
11741b9c6b06SHadar Hen Zion 	struct res_fs_rule *ret;
11751b9c6b06SHadar Hen Zion 
117631975e27Sstephen hemminger 	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
11771b9c6b06SHadar Hen Zion 	if (!ret)
11781b9c6b06SHadar Hen Zion 		return NULL;
11791b9c6b06SHadar Hen Zion 
11801b9c6b06SHadar Hen Zion 	ret->com.res_id = id;
11811b9c6b06SHadar Hen Zion 	ret->com.state = RES_FS_RULE_ALLOCATED;
11822c473ae7SHadar Hen Zion 	ret->qpn = qpn;
11831b9c6b06SHadar Hen Zion 	return &ret->com;
11841b9c6b06SHadar Hen Zion }
11851b9c6b06SHadar Hen Zion 
alloc_tr(u64 id,enum mlx4_resource type,int slave,int extra)1186aa1ec3ddSHadar Hen Zion static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave,
1187c82e9aa0SEli Cohen 				   int extra)
1188c82e9aa0SEli Cohen {
1189c82e9aa0SEli Cohen 	struct res_common *ret;
1190c82e9aa0SEli Cohen 
1191c82e9aa0SEli Cohen 	switch (type) {
1192c82e9aa0SEli Cohen 	case RES_QP:
1193c82e9aa0SEli Cohen 		ret = alloc_qp_tr(id);
1194c82e9aa0SEli Cohen 		break;
1195c82e9aa0SEli Cohen 	case RES_MPT:
1196c82e9aa0SEli Cohen 		ret = alloc_mpt_tr(id, extra);
1197c82e9aa0SEli Cohen 		break;
1198c82e9aa0SEli Cohen 	case RES_MTT:
1199c82e9aa0SEli Cohen 		ret = alloc_mtt_tr(id, extra);
1200c82e9aa0SEli Cohen 		break;
1201c82e9aa0SEli Cohen 	case RES_EQ:
1202c82e9aa0SEli Cohen 		ret = alloc_eq_tr(id);
1203c82e9aa0SEli Cohen 		break;
1204c82e9aa0SEli Cohen 	case RES_CQ:
1205c82e9aa0SEli Cohen 		ret = alloc_cq_tr(id);
1206c82e9aa0SEli Cohen 		break;
1207c82e9aa0SEli Cohen 	case RES_SRQ:
1208c82e9aa0SEli Cohen 		ret = alloc_srq_tr(id);
1209c82e9aa0SEli Cohen 		break;
1210c82e9aa0SEli Cohen 	case RES_MAC:
1211c20862c8SAmir Vadai 		pr_err("implementation missing\n");
1212c82e9aa0SEli Cohen 		return NULL;
1213c82e9aa0SEli Cohen 	case RES_COUNTER:
12149de92c60SEran Ben Elisha 		ret = alloc_counter_tr(id, extra);
1215c82e9aa0SEli Cohen 		break;
1216ba062d52SJack Morgenstein 	case RES_XRCD:
1217ba062d52SJack Morgenstein 		ret = alloc_xrcdn_tr(id);
1218ba062d52SJack Morgenstein 		break;
12191b9c6b06SHadar Hen Zion 	case RES_FS_RULE:
12202c473ae7SHadar Hen Zion 		ret = alloc_fs_rule_tr(id, extra);
12211b9c6b06SHadar Hen Zion 		break;
1222c82e9aa0SEli Cohen 	default:
1223c82e9aa0SEli Cohen 		return NULL;
1224c82e9aa0SEli Cohen 	}
1225c82e9aa0SEli Cohen 	if (ret)
1226c82e9aa0SEli Cohen 		ret->owner = slave;
1227c82e9aa0SEli Cohen 
1228c82e9aa0SEli Cohen 	return ret;
1229c82e9aa0SEli Cohen }
1230c82e9aa0SEli Cohen 
mlx4_calc_vf_counters(struct mlx4_dev * dev,int slave,int port,struct mlx4_counter * data)123162a89055SEran Ben Elisha int mlx4_calc_vf_counters(struct mlx4_dev *dev, int slave, int port,
123262a89055SEran Ben Elisha 			  struct mlx4_counter *data)
123362a89055SEran Ben Elisha {
123462a89055SEran Ben Elisha 	struct mlx4_priv *priv = mlx4_priv(dev);
123562a89055SEran Ben Elisha 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
123662a89055SEran Ben Elisha 	struct res_common *tmp;
123762a89055SEran Ben Elisha 	struct res_counter *counter;
123862a89055SEran Ben Elisha 	int *counters_arr;
123962a89055SEran Ben Elisha 	int i = 0, err = 0;
124062a89055SEran Ben Elisha 
124162a89055SEran Ben Elisha 	memset(data, 0, sizeof(*data));
124262a89055SEran Ben Elisha 
124362a89055SEran Ben Elisha 	counters_arr = kmalloc_array(dev->caps.max_counters,
124462a89055SEran Ben Elisha 				     sizeof(*counters_arr), GFP_KERNEL);
124562a89055SEran Ben Elisha 	if (!counters_arr)
124662a89055SEran Ben Elisha 		return -ENOMEM;
124762a89055SEran Ben Elisha 
124862a89055SEran Ben Elisha 	spin_lock_irq(mlx4_tlock(dev));
124962a89055SEran Ben Elisha 	list_for_each_entry(tmp,
125062a89055SEran Ben Elisha 			    &tracker->slave_list[slave].res_list[RES_COUNTER],
125162a89055SEran Ben Elisha 			    list) {
125262a89055SEran Ben Elisha 		counter = container_of(tmp, struct res_counter, com);
125362a89055SEran Ben Elisha 		if (counter->port == port) {
125462a89055SEran Ben Elisha 			counters_arr[i] = (int)tmp->res_id;
125562a89055SEran Ben Elisha 			i++;
125662a89055SEran Ben Elisha 		}
125762a89055SEran Ben Elisha 	}
125862a89055SEran Ben Elisha 	spin_unlock_irq(mlx4_tlock(dev));
125962a89055SEran Ben Elisha 	counters_arr[i] = -1;
126062a89055SEran Ben Elisha 
126162a89055SEran Ben Elisha 	i = 0;
126262a89055SEran Ben Elisha 
126362a89055SEran Ben Elisha 	while (counters_arr[i] != -1) {
126462a89055SEran Ben Elisha 		err = mlx4_get_counter_stats(dev, counters_arr[i], data,
126562a89055SEran Ben Elisha 					     0);
126662a89055SEran Ben Elisha 		if (err) {
126762a89055SEran Ben Elisha 			memset(data, 0, sizeof(*data));
126862a89055SEran Ben Elisha 			goto table_changed;
126962a89055SEran Ben Elisha 		}
127062a89055SEran Ben Elisha 		i++;
127162a89055SEran Ben Elisha 	}
127262a89055SEran Ben Elisha 
127362a89055SEran Ben Elisha table_changed:
127462a89055SEran Ben Elisha 	kfree(counters_arr);
127562a89055SEran Ben Elisha 	return 0;
127662a89055SEran Ben Elisha }
127762a89055SEran Ben Elisha 
add_res_range(struct mlx4_dev * dev,int slave,u64 base,int count,enum mlx4_resource type,int extra)1278aa1ec3ddSHadar Hen Zion static int add_res_range(struct mlx4_dev *dev, int slave, u64 base, int count,
1279c82e9aa0SEli Cohen 			 enum mlx4_resource type, int extra)
1280c82e9aa0SEli Cohen {
1281c82e9aa0SEli Cohen 	int i;
1282c82e9aa0SEli Cohen 	int err;
1283c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
1284c82e9aa0SEli Cohen 	struct res_common **res_arr;
1285c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
12864af1c048SHadar Hen Zion 	struct rb_root *root = &tracker->res_tree[type];
1287c82e9aa0SEli Cohen 
128831975e27Sstephen hemminger 	res_arr = kcalloc(count, sizeof(*res_arr), GFP_KERNEL);
1289c82e9aa0SEli Cohen 	if (!res_arr)
1290c82e9aa0SEli Cohen 		return -ENOMEM;
1291c82e9aa0SEli Cohen 
1292c82e9aa0SEli Cohen 	for (i = 0; i < count; ++i) {
1293c82e9aa0SEli Cohen 		res_arr[i] = alloc_tr(base + i, type, slave, extra);
1294c82e9aa0SEli Cohen 		if (!res_arr[i]) {
1295c82e9aa0SEli Cohen 			for (--i; i >= 0; --i)
1296c82e9aa0SEli Cohen 				kfree(res_arr[i]);
1297c82e9aa0SEli Cohen 
1298c82e9aa0SEli Cohen 			kfree(res_arr);
1299c82e9aa0SEli Cohen 			return -ENOMEM;
1300c82e9aa0SEli Cohen 		}
1301c82e9aa0SEli Cohen 	}
1302c82e9aa0SEli Cohen 
1303c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
1304c82e9aa0SEli Cohen 	for (i = 0; i < count; ++i) {
1305c82e9aa0SEli Cohen 		if (find_res(dev, base + i, type)) {
1306c82e9aa0SEli Cohen 			err = -EEXIST;
1307c82e9aa0SEli Cohen 			goto undo;
1308c82e9aa0SEli Cohen 		}
13094af1c048SHadar Hen Zion 		err = res_tracker_insert(root, res_arr[i]);
1310c82e9aa0SEli Cohen 		if (err)
1311c82e9aa0SEli Cohen 			goto undo;
1312c82e9aa0SEli Cohen 		list_add_tail(&res_arr[i]->list,
1313c82e9aa0SEli Cohen 			      &tracker->slave_list[slave].res_list[type]);
1314c82e9aa0SEli Cohen 	}
1315c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
1316c82e9aa0SEli Cohen 	kfree(res_arr);
1317c82e9aa0SEli Cohen 
1318c82e9aa0SEli Cohen 	return 0;
1319c82e9aa0SEli Cohen 
1320c82e9aa0SEli Cohen undo:
132195e19633SSaeed Mahameed 	for (--i; i >= 0; --i) {
13224af1c048SHadar Hen Zion 		rb_erase(&res_arr[i]->node, root);
132395e19633SSaeed Mahameed 		list_del_init(&res_arr[i]->list);
132495e19633SSaeed Mahameed 	}
1325c82e9aa0SEli Cohen 
1326c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
1327c82e9aa0SEli Cohen 
1328c82e9aa0SEli Cohen 	for (i = 0; i < count; ++i)
1329c82e9aa0SEli Cohen 		kfree(res_arr[i]);
1330c82e9aa0SEli Cohen 
1331c82e9aa0SEli Cohen 	kfree(res_arr);
1332c82e9aa0SEli Cohen 
1333c82e9aa0SEli Cohen 	return err;
1334c82e9aa0SEli Cohen }
1335c82e9aa0SEli Cohen 
remove_qp_ok(struct res_qp * res)1336c82e9aa0SEli Cohen static int remove_qp_ok(struct res_qp *res)
1337c82e9aa0SEli Cohen {
13382c473ae7SHadar Hen Zion 	if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) ||
13392c473ae7SHadar Hen Zion 	    !list_empty(&res->mcg_list)) {
13402c473ae7SHadar Hen Zion 		pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n",
13412c473ae7SHadar Hen Zion 		       res->com.state, atomic_read(&res->ref_count));
1342c82e9aa0SEli Cohen 		return -EBUSY;
13432c473ae7SHadar Hen Zion 	} else if (res->com.state != RES_QP_RESERVED) {
1344c82e9aa0SEli Cohen 		return -EPERM;
13452c473ae7SHadar Hen Zion 	}
1346c82e9aa0SEli Cohen 
1347c82e9aa0SEli Cohen 	return 0;
1348c82e9aa0SEli Cohen }
1349c82e9aa0SEli Cohen 
remove_mtt_ok(struct res_mtt * res,int order)1350c82e9aa0SEli Cohen static int remove_mtt_ok(struct res_mtt *res, int order)
1351c82e9aa0SEli Cohen {
1352c82e9aa0SEli Cohen 	if (res->com.state == RES_MTT_BUSY ||
1353c82e9aa0SEli Cohen 	    atomic_read(&res->ref_count)) {
1354c20862c8SAmir Vadai 		pr_devel("%s-%d: state %s, ref_count %d\n",
1355c82e9aa0SEli Cohen 			 __func__, __LINE__,
1356c82e9aa0SEli Cohen 			 mtt_states_str(res->com.state),
1357c82e9aa0SEli Cohen 			 atomic_read(&res->ref_count));
1358c82e9aa0SEli Cohen 		return -EBUSY;
1359c82e9aa0SEli Cohen 	} else if (res->com.state != RES_MTT_ALLOCATED)
1360c82e9aa0SEli Cohen 		return -EPERM;
1361c82e9aa0SEli Cohen 	else if (res->order != order)
1362c82e9aa0SEli Cohen 		return -EINVAL;
1363c82e9aa0SEli Cohen 
1364c82e9aa0SEli Cohen 	return 0;
1365c82e9aa0SEli Cohen }
1366c82e9aa0SEli Cohen 
remove_mpt_ok(struct res_mpt * res)1367c82e9aa0SEli Cohen static int remove_mpt_ok(struct res_mpt *res)
1368c82e9aa0SEli Cohen {
1369c82e9aa0SEli Cohen 	if (res->com.state == RES_MPT_BUSY)
1370c82e9aa0SEli Cohen 		return -EBUSY;
1371c82e9aa0SEli Cohen 	else if (res->com.state != RES_MPT_RESERVED)
1372c82e9aa0SEli Cohen 		return -EPERM;
1373c82e9aa0SEli Cohen 
1374c82e9aa0SEli Cohen 	return 0;
1375c82e9aa0SEli Cohen }
1376c82e9aa0SEli Cohen 
remove_eq_ok(struct res_eq * res)1377c82e9aa0SEli Cohen static int remove_eq_ok(struct res_eq *res)
1378c82e9aa0SEli Cohen {
1379c82e9aa0SEli Cohen 	if (res->com.state == RES_MPT_BUSY)
1380c82e9aa0SEli Cohen 		return -EBUSY;
1381c82e9aa0SEli Cohen 	else if (res->com.state != RES_MPT_RESERVED)
1382c82e9aa0SEli Cohen 		return -EPERM;
1383c82e9aa0SEli Cohen 
1384c82e9aa0SEli Cohen 	return 0;
1385c82e9aa0SEli Cohen }
1386c82e9aa0SEli Cohen 
remove_counter_ok(struct res_counter * res)1387c82e9aa0SEli Cohen static int remove_counter_ok(struct res_counter *res)
1388c82e9aa0SEli Cohen {
1389c82e9aa0SEli Cohen 	if (res->com.state == RES_COUNTER_BUSY)
1390c82e9aa0SEli Cohen 		return -EBUSY;
1391c82e9aa0SEli Cohen 	else if (res->com.state != RES_COUNTER_ALLOCATED)
1392c82e9aa0SEli Cohen 		return -EPERM;
1393c82e9aa0SEli Cohen 
1394c82e9aa0SEli Cohen 	return 0;
1395c82e9aa0SEli Cohen }
1396c82e9aa0SEli Cohen 
remove_xrcdn_ok(struct res_xrcdn * res)1397ba062d52SJack Morgenstein static int remove_xrcdn_ok(struct res_xrcdn *res)
1398ba062d52SJack Morgenstein {
1399ba062d52SJack Morgenstein 	if (res->com.state == RES_XRCD_BUSY)
1400ba062d52SJack Morgenstein 		return -EBUSY;
1401ba062d52SJack Morgenstein 	else if (res->com.state != RES_XRCD_ALLOCATED)
1402ba062d52SJack Morgenstein 		return -EPERM;
1403ba062d52SJack Morgenstein 
1404ba062d52SJack Morgenstein 	return 0;
1405ba062d52SJack Morgenstein }
1406ba062d52SJack Morgenstein 
remove_fs_rule_ok(struct res_fs_rule * res)14071b9c6b06SHadar Hen Zion static int remove_fs_rule_ok(struct res_fs_rule *res)
14081b9c6b06SHadar Hen Zion {
14091b9c6b06SHadar Hen Zion 	if (res->com.state == RES_FS_RULE_BUSY)
14101b9c6b06SHadar Hen Zion 		return -EBUSY;
14111b9c6b06SHadar Hen Zion 	else if (res->com.state != RES_FS_RULE_ALLOCATED)
14121b9c6b06SHadar Hen Zion 		return -EPERM;
14131b9c6b06SHadar Hen Zion 
14141b9c6b06SHadar Hen Zion 	return 0;
14151b9c6b06SHadar Hen Zion }
14161b9c6b06SHadar Hen Zion 
remove_cq_ok(struct res_cq * res)1417c82e9aa0SEli Cohen static int remove_cq_ok(struct res_cq *res)
1418c82e9aa0SEli Cohen {
1419c82e9aa0SEli Cohen 	if (res->com.state == RES_CQ_BUSY)
1420c82e9aa0SEli Cohen 		return -EBUSY;
1421c82e9aa0SEli Cohen 	else if (res->com.state != RES_CQ_ALLOCATED)
1422c82e9aa0SEli Cohen 		return -EPERM;
1423c82e9aa0SEli Cohen 
1424c82e9aa0SEli Cohen 	return 0;
1425c82e9aa0SEli Cohen }
1426c82e9aa0SEli Cohen 
remove_srq_ok(struct res_srq * res)1427c82e9aa0SEli Cohen static int remove_srq_ok(struct res_srq *res)
1428c82e9aa0SEli Cohen {
1429c82e9aa0SEli Cohen 	if (res->com.state == RES_SRQ_BUSY)
1430c82e9aa0SEli Cohen 		return -EBUSY;
1431c82e9aa0SEli Cohen 	else if (res->com.state != RES_SRQ_ALLOCATED)
1432c82e9aa0SEli Cohen 		return -EPERM;
1433c82e9aa0SEli Cohen 
1434c82e9aa0SEli Cohen 	return 0;
1435c82e9aa0SEli Cohen }
1436c82e9aa0SEli Cohen 
remove_ok(struct res_common * res,enum mlx4_resource type,int extra)1437c82e9aa0SEli Cohen static int remove_ok(struct res_common *res, enum mlx4_resource type, int extra)
1438c82e9aa0SEli Cohen {
1439c82e9aa0SEli Cohen 	switch (type) {
1440c82e9aa0SEli Cohen 	case RES_QP:
1441c82e9aa0SEli Cohen 		return remove_qp_ok((struct res_qp *)res);
1442c82e9aa0SEli Cohen 	case RES_CQ:
1443c82e9aa0SEli Cohen 		return remove_cq_ok((struct res_cq *)res);
1444c82e9aa0SEli Cohen 	case RES_SRQ:
1445c82e9aa0SEli Cohen 		return remove_srq_ok((struct res_srq *)res);
1446c82e9aa0SEli Cohen 	case RES_MPT:
1447c82e9aa0SEli Cohen 		return remove_mpt_ok((struct res_mpt *)res);
1448c82e9aa0SEli Cohen 	case RES_MTT:
1449c82e9aa0SEli Cohen 		return remove_mtt_ok((struct res_mtt *)res, extra);
1450c82e9aa0SEli Cohen 	case RES_MAC:
145172b8eaabSTariq Toukan 		return -EOPNOTSUPP;
1452c82e9aa0SEli Cohen 	case RES_EQ:
1453c82e9aa0SEli Cohen 		return remove_eq_ok((struct res_eq *)res);
1454c82e9aa0SEli Cohen 	case RES_COUNTER:
1455c82e9aa0SEli Cohen 		return remove_counter_ok((struct res_counter *)res);
1456ba062d52SJack Morgenstein 	case RES_XRCD:
1457ba062d52SJack Morgenstein 		return remove_xrcdn_ok((struct res_xrcdn *)res);
14581b9c6b06SHadar Hen Zion 	case RES_FS_RULE:
14591b9c6b06SHadar Hen Zion 		return remove_fs_rule_ok((struct res_fs_rule *)res);
1460c82e9aa0SEli Cohen 	default:
1461c82e9aa0SEli Cohen 		return -EINVAL;
1462c82e9aa0SEli Cohen 	}
1463c82e9aa0SEli Cohen }
1464c82e9aa0SEli Cohen 
rem_res_range(struct mlx4_dev * dev,int slave,u64 base,int count,enum mlx4_resource type,int extra)1465aa1ec3ddSHadar Hen Zion static int rem_res_range(struct mlx4_dev *dev, int slave, u64 base, int count,
1466c82e9aa0SEli Cohen 			 enum mlx4_resource type, int extra)
1467c82e9aa0SEli Cohen {
1468aa1ec3ddSHadar Hen Zion 	u64 i;
1469c82e9aa0SEli Cohen 	int err;
1470c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
1471c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
1472c82e9aa0SEli Cohen 	struct res_common *r;
1473c82e9aa0SEli Cohen 
1474c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
1475c82e9aa0SEli Cohen 	for (i = base; i < base + count; ++i) {
14764af1c048SHadar Hen Zion 		r = res_tracker_lookup(&tracker->res_tree[type], i);
1477c82e9aa0SEli Cohen 		if (!r) {
1478c82e9aa0SEli Cohen 			err = -ENOENT;
1479c82e9aa0SEli Cohen 			goto out;
1480c82e9aa0SEli Cohen 		}
1481c82e9aa0SEli Cohen 		if (r->owner != slave) {
1482c82e9aa0SEli Cohen 			err = -EPERM;
1483c82e9aa0SEli Cohen 			goto out;
1484c82e9aa0SEli Cohen 		}
1485c82e9aa0SEli Cohen 		err = remove_ok(r, type, extra);
1486c82e9aa0SEli Cohen 		if (err)
1487c82e9aa0SEli Cohen 			goto out;
1488c82e9aa0SEli Cohen 	}
1489c82e9aa0SEli Cohen 
1490c82e9aa0SEli Cohen 	for (i = base; i < base + count; ++i) {
14914af1c048SHadar Hen Zion 		r = res_tracker_lookup(&tracker->res_tree[type], i);
14924af1c048SHadar Hen Zion 		rb_erase(&r->node, &tracker->res_tree[type]);
1493c82e9aa0SEli Cohen 		list_del(&r->list);
1494c82e9aa0SEli Cohen 		kfree(r);
1495c82e9aa0SEli Cohen 	}
1496c82e9aa0SEli Cohen 	err = 0;
1497c82e9aa0SEli Cohen 
1498c82e9aa0SEli Cohen out:
1499c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
1500c82e9aa0SEli Cohen 
1501c82e9aa0SEli Cohen 	return err;
1502c82e9aa0SEli Cohen }
1503c82e9aa0SEli Cohen 
qp_res_start_move_to(struct mlx4_dev * dev,int slave,int qpn,enum res_qp_states state,struct res_qp ** qp,int alloc)1504c82e9aa0SEli Cohen static int qp_res_start_move_to(struct mlx4_dev *dev, int slave, int qpn,
1505c82e9aa0SEli Cohen 				enum res_qp_states state, struct res_qp **qp,
1506c82e9aa0SEli Cohen 				int alloc)
1507c82e9aa0SEli Cohen {
1508c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
1509c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
1510c82e9aa0SEli Cohen 	struct res_qp *r;
1511c82e9aa0SEli Cohen 	int err = 0;
1512c82e9aa0SEli Cohen 
1513c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
15144af1c048SHadar Hen Zion 	r = res_tracker_lookup(&tracker->res_tree[RES_QP], qpn);
1515c82e9aa0SEli Cohen 	if (!r)
1516c82e9aa0SEli Cohen 		err = -ENOENT;
1517c82e9aa0SEli Cohen 	else if (r->com.owner != slave)
1518c82e9aa0SEli Cohen 		err = -EPERM;
1519c82e9aa0SEli Cohen 	else {
1520c82e9aa0SEli Cohen 		switch (state) {
1521c82e9aa0SEli Cohen 		case RES_QP_BUSY:
1522aa1ec3ddSHadar Hen Zion 			mlx4_dbg(dev, "%s: failed RES_QP, 0x%llx\n",
1523c82e9aa0SEli Cohen 				 __func__, r->com.res_id);
1524c82e9aa0SEli Cohen 			err = -EBUSY;
1525c82e9aa0SEli Cohen 			break;
1526c82e9aa0SEli Cohen 
1527c82e9aa0SEli Cohen 		case RES_QP_RESERVED:
1528c82e9aa0SEli Cohen 			if (r->com.state == RES_QP_MAPPED && !alloc)
1529c82e9aa0SEli Cohen 				break;
1530c82e9aa0SEli Cohen 
1531aa1ec3ddSHadar Hen Zion 			mlx4_dbg(dev, "failed RES_QP, 0x%llx\n", r->com.res_id);
1532c82e9aa0SEli Cohen 			err = -EINVAL;
1533c82e9aa0SEli Cohen 			break;
1534c82e9aa0SEli Cohen 
1535c82e9aa0SEli Cohen 		case RES_QP_MAPPED:
1536c82e9aa0SEli Cohen 			if ((r->com.state == RES_QP_RESERVED && alloc) ||
1537c82e9aa0SEli Cohen 			    r->com.state == RES_QP_HW)
1538c82e9aa0SEli Cohen 				break;
1539c82e9aa0SEli Cohen 			else {
1540aa1ec3ddSHadar Hen Zion 				mlx4_dbg(dev, "failed RES_QP, 0x%llx\n",
1541c82e9aa0SEli Cohen 					  r->com.res_id);
1542c82e9aa0SEli Cohen 				err = -EINVAL;
1543c82e9aa0SEli Cohen 			}
1544c82e9aa0SEli Cohen 
1545c82e9aa0SEli Cohen 			break;
1546c82e9aa0SEli Cohen 
1547c82e9aa0SEli Cohen 		case RES_QP_HW:
1548c82e9aa0SEli Cohen 			if (r->com.state != RES_QP_MAPPED)
1549c82e9aa0SEli Cohen 				err = -EINVAL;
1550c82e9aa0SEli Cohen 			break;
1551c82e9aa0SEli Cohen 		default:
1552c82e9aa0SEli Cohen 			err = -EINVAL;
1553c82e9aa0SEli Cohen 		}
1554c82e9aa0SEli Cohen 
1555c82e9aa0SEli Cohen 		if (!err) {
1556c82e9aa0SEli Cohen 			r->com.from_state = r->com.state;
1557c82e9aa0SEli Cohen 			r->com.to_state = state;
1558c82e9aa0SEli Cohen 			r->com.state = RES_QP_BUSY;
1559c82e9aa0SEli Cohen 			if (qp)
156064699336SJoe Perches 				*qp = r;
1561c82e9aa0SEli Cohen 		}
1562c82e9aa0SEli Cohen 	}
1563c82e9aa0SEli Cohen 
1564c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
1565c82e9aa0SEli Cohen 
1566c82e9aa0SEli Cohen 	return err;
1567c82e9aa0SEli Cohen }
1568c82e9aa0SEli Cohen 
mr_res_start_move_to(struct mlx4_dev * dev,int slave,int index,enum res_mpt_states state,struct res_mpt ** mpt)1569c82e9aa0SEli Cohen static int mr_res_start_move_to(struct mlx4_dev *dev, int slave, int index,
1570c82e9aa0SEli Cohen 				enum res_mpt_states state, struct res_mpt **mpt)
1571c82e9aa0SEli Cohen {
1572c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
1573c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
1574c82e9aa0SEli Cohen 	struct res_mpt *r;
1575c82e9aa0SEli Cohen 	int err = 0;
1576c82e9aa0SEli Cohen 
1577c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
15784af1c048SHadar Hen Zion 	r = res_tracker_lookup(&tracker->res_tree[RES_MPT], index);
1579c82e9aa0SEli Cohen 	if (!r)
1580c82e9aa0SEli Cohen 		err = -ENOENT;
1581c82e9aa0SEli Cohen 	else if (r->com.owner != slave)
1582c82e9aa0SEli Cohen 		err = -EPERM;
1583c82e9aa0SEli Cohen 	else {
1584c82e9aa0SEli Cohen 		switch (state) {
1585c82e9aa0SEli Cohen 		case RES_MPT_BUSY:
1586c82e9aa0SEli Cohen 			err = -EINVAL;
1587c82e9aa0SEli Cohen 			break;
1588c82e9aa0SEli Cohen 
1589c82e9aa0SEli Cohen 		case RES_MPT_RESERVED:
1590c82e9aa0SEli Cohen 			if (r->com.state != RES_MPT_MAPPED)
1591c82e9aa0SEli Cohen 				err = -EINVAL;
1592c82e9aa0SEli Cohen 			break;
1593c82e9aa0SEli Cohen 
1594c82e9aa0SEli Cohen 		case RES_MPT_MAPPED:
1595c82e9aa0SEli Cohen 			if (r->com.state != RES_MPT_RESERVED &&
1596c82e9aa0SEli Cohen 			    r->com.state != RES_MPT_HW)
1597c82e9aa0SEli Cohen 				err = -EINVAL;
1598c82e9aa0SEli Cohen 			break;
1599c82e9aa0SEli Cohen 
1600c82e9aa0SEli Cohen 		case RES_MPT_HW:
1601c82e9aa0SEli Cohen 			if (r->com.state != RES_MPT_MAPPED)
1602c82e9aa0SEli Cohen 				err = -EINVAL;
1603c82e9aa0SEli Cohen 			break;
1604c82e9aa0SEli Cohen 		default:
1605c82e9aa0SEli Cohen 			err = -EINVAL;
1606c82e9aa0SEli Cohen 		}
1607c82e9aa0SEli Cohen 
1608c82e9aa0SEli Cohen 		if (!err) {
1609c82e9aa0SEli Cohen 			r->com.from_state = r->com.state;
1610c82e9aa0SEli Cohen 			r->com.to_state = state;
1611c82e9aa0SEli Cohen 			r->com.state = RES_MPT_BUSY;
1612c82e9aa0SEli Cohen 			if (mpt)
161364699336SJoe Perches 				*mpt = r;
1614c82e9aa0SEli Cohen 		}
1615c82e9aa0SEli Cohen 	}
1616c82e9aa0SEli Cohen 
1617c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
1618c82e9aa0SEli Cohen 
1619c82e9aa0SEli Cohen 	return err;
1620c82e9aa0SEli Cohen }
1621c82e9aa0SEli Cohen 
eq_res_start_move_to(struct mlx4_dev * dev,int slave,int index,enum res_eq_states state,struct res_eq ** eq)1622c82e9aa0SEli Cohen static int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index,
1623c82e9aa0SEli Cohen 				enum res_eq_states state, struct res_eq **eq)
1624c82e9aa0SEli Cohen {
1625c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
1626c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
1627c82e9aa0SEli Cohen 	struct res_eq *r;
1628c82e9aa0SEli Cohen 	int err = 0;
1629c82e9aa0SEli Cohen 
1630c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
16314af1c048SHadar Hen Zion 	r = res_tracker_lookup(&tracker->res_tree[RES_EQ], index);
1632c82e9aa0SEli Cohen 	if (!r)
1633c82e9aa0SEli Cohen 		err = -ENOENT;
1634c82e9aa0SEli Cohen 	else if (r->com.owner != slave)
1635c82e9aa0SEli Cohen 		err = -EPERM;
1636c82e9aa0SEli Cohen 	else {
1637c82e9aa0SEli Cohen 		switch (state) {
1638c82e9aa0SEli Cohen 		case RES_EQ_BUSY:
1639c82e9aa0SEli Cohen 			err = -EINVAL;
1640c82e9aa0SEli Cohen 			break;
1641c82e9aa0SEli Cohen 
1642c82e9aa0SEli Cohen 		case RES_EQ_RESERVED:
1643c82e9aa0SEli Cohen 			if (r->com.state != RES_EQ_HW)
1644c82e9aa0SEli Cohen 				err = -EINVAL;
1645c82e9aa0SEli Cohen 			break;
1646c82e9aa0SEli Cohen 
1647c82e9aa0SEli Cohen 		case RES_EQ_HW:
1648c82e9aa0SEli Cohen 			if (r->com.state != RES_EQ_RESERVED)
1649c82e9aa0SEli Cohen 				err = -EINVAL;
1650c82e9aa0SEli Cohen 			break;
1651c82e9aa0SEli Cohen 
1652c82e9aa0SEli Cohen 		default:
1653c82e9aa0SEli Cohen 			err = -EINVAL;
1654c82e9aa0SEli Cohen 		}
1655c82e9aa0SEli Cohen 
1656c82e9aa0SEli Cohen 		if (!err) {
1657c82e9aa0SEli Cohen 			r->com.from_state = r->com.state;
1658c82e9aa0SEli Cohen 			r->com.to_state = state;
1659c82e9aa0SEli Cohen 			r->com.state = RES_EQ_BUSY;
1660c82e9aa0SEli Cohen 		}
1661c82e9aa0SEli Cohen 	}
1662c82e9aa0SEli Cohen 
1663c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
1664c82e9aa0SEli Cohen 
1665a4256bc9SArnd Bergmann 	if (!err && eq)
1666a4256bc9SArnd Bergmann 		*eq = r;
1667a4256bc9SArnd Bergmann 
1668c82e9aa0SEli Cohen 	return err;
1669c82e9aa0SEli Cohen }
1670c82e9aa0SEli Cohen 
cq_res_start_move_to(struct mlx4_dev * dev,int slave,int cqn,enum res_cq_states state,struct res_cq ** cq)1671c82e9aa0SEli Cohen static int cq_res_start_move_to(struct mlx4_dev *dev, int slave, int cqn,
1672c82e9aa0SEli Cohen 				enum res_cq_states state, struct res_cq **cq)
1673c82e9aa0SEli Cohen {
1674c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
1675c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
1676c82e9aa0SEli Cohen 	struct res_cq *r;
1677c82e9aa0SEli Cohen 	int err;
1678c82e9aa0SEli Cohen 
1679c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
16804af1c048SHadar Hen Zion 	r = res_tracker_lookup(&tracker->res_tree[RES_CQ], cqn);
1681c9218a9eSPaul Bolle 	if (!r) {
1682c82e9aa0SEli Cohen 		err = -ENOENT;
1683c9218a9eSPaul Bolle 	} else if (r->com.owner != slave) {
1684c82e9aa0SEli Cohen 		err = -EPERM;
1685c9218a9eSPaul Bolle 	} else if (state == RES_CQ_ALLOCATED) {
1686c82e9aa0SEli Cohen 		if (r->com.state != RES_CQ_HW)
1687c82e9aa0SEli Cohen 			err = -EINVAL;
1688c82e9aa0SEli Cohen 		else if (atomic_read(&r->ref_count))
1689c82e9aa0SEli Cohen 			err = -EBUSY;
1690c82e9aa0SEli Cohen 		else
1691c82e9aa0SEli Cohen 			err = 0;
1692c9218a9eSPaul Bolle 	} else if (state != RES_CQ_HW || r->com.state != RES_CQ_ALLOCATED) {
1693c82e9aa0SEli Cohen 		err = -EINVAL;
1694c9218a9eSPaul Bolle 	} else {
1695c82e9aa0SEli Cohen 		err = 0;
1696c82e9aa0SEli Cohen 	}
1697c82e9aa0SEli Cohen 
1698c82e9aa0SEli Cohen 	if (!err) {
1699c82e9aa0SEli Cohen 		r->com.from_state = r->com.state;
1700c82e9aa0SEli Cohen 		r->com.to_state = state;
1701c82e9aa0SEli Cohen 		r->com.state = RES_CQ_BUSY;
1702c82e9aa0SEli Cohen 		if (cq)
1703c82e9aa0SEli Cohen 			*cq = r;
1704c82e9aa0SEli Cohen 	}
1705c82e9aa0SEli Cohen 
1706c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
1707c82e9aa0SEli Cohen 
1708c82e9aa0SEli Cohen 	return err;
1709c82e9aa0SEli Cohen }
1710c82e9aa0SEli Cohen 
srq_res_start_move_to(struct mlx4_dev * dev,int slave,int index,enum res_srq_states state,struct res_srq ** srq)1711c82e9aa0SEli Cohen static int srq_res_start_move_to(struct mlx4_dev *dev, int slave, int index,
1712f088cbb8SPaul Bolle 				 enum res_srq_states state, struct res_srq **srq)
1713c82e9aa0SEli Cohen {
1714c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
1715c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
1716c82e9aa0SEli Cohen 	struct res_srq *r;
1717c82e9aa0SEli Cohen 	int err = 0;
1718c82e9aa0SEli Cohen 
1719c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
17204af1c048SHadar Hen Zion 	r = res_tracker_lookup(&tracker->res_tree[RES_SRQ], index);
1721f088cbb8SPaul Bolle 	if (!r) {
1722c82e9aa0SEli Cohen 		err = -ENOENT;
1723f088cbb8SPaul Bolle 	} else if (r->com.owner != slave) {
1724c82e9aa0SEli Cohen 		err = -EPERM;
1725f088cbb8SPaul Bolle 	} else if (state == RES_SRQ_ALLOCATED) {
1726c82e9aa0SEli Cohen 		if (r->com.state != RES_SRQ_HW)
1727c82e9aa0SEli Cohen 			err = -EINVAL;
1728c82e9aa0SEli Cohen 		else if (atomic_read(&r->ref_count))
1729c82e9aa0SEli Cohen 			err = -EBUSY;
1730f088cbb8SPaul Bolle 	} else if (state != RES_SRQ_HW || r->com.state != RES_SRQ_ALLOCATED) {
1731c82e9aa0SEli Cohen 		err = -EINVAL;
1732c82e9aa0SEli Cohen 	}
1733c82e9aa0SEli Cohen 
1734c82e9aa0SEli Cohen 	if (!err) {
1735c82e9aa0SEli Cohen 		r->com.from_state = r->com.state;
1736c82e9aa0SEli Cohen 		r->com.to_state = state;
1737c82e9aa0SEli Cohen 		r->com.state = RES_SRQ_BUSY;
1738c82e9aa0SEli Cohen 		if (srq)
1739c82e9aa0SEli Cohen 			*srq = r;
1740c82e9aa0SEli Cohen 	}
1741c82e9aa0SEli Cohen 
1742c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
1743c82e9aa0SEli Cohen 
1744c82e9aa0SEli Cohen 	return err;
1745c82e9aa0SEli Cohen }
1746c82e9aa0SEli Cohen 
res_abort_move(struct mlx4_dev * dev,int slave,enum mlx4_resource type,int id)1747c82e9aa0SEli Cohen static void res_abort_move(struct mlx4_dev *dev, int slave,
1748c82e9aa0SEli Cohen 			   enum mlx4_resource type, int id)
1749c82e9aa0SEli Cohen {
1750c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
1751c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
1752c82e9aa0SEli Cohen 	struct res_common *r;
1753c82e9aa0SEli Cohen 
1754c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
17554af1c048SHadar Hen Zion 	r = res_tracker_lookup(&tracker->res_tree[type], id);
1756c82e9aa0SEli Cohen 	if (r && (r->owner == slave))
1757c82e9aa0SEli Cohen 		r->state = r->from_state;
1758c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
1759c82e9aa0SEli Cohen }
1760c82e9aa0SEli Cohen 
res_end_move(struct mlx4_dev * dev,int slave,enum mlx4_resource type,int id)1761c82e9aa0SEli Cohen static void res_end_move(struct mlx4_dev *dev, int slave,
1762c82e9aa0SEli Cohen 			 enum mlx4_resource type, int id)
1763c82e9aa0SEli Cohen {
1764c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
1765c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
1766c82e9aa0SEli Cohen 	struct res_common *r;
1767c82e9aa0SEli Cohen 
1768c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
17694af1c048SHadar Hen Zion 	r = res_tracker_lookup(&tracker->res_tree[type], id);
1770c82e9aa0SEli Cohen 	if (r && (r->owner == slave))
1771c82e9aa0SEli Cohen 		r->state = r->to_state;
1772c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
1773c82e9aa0SEli Cohen }
1774c82e9aa0SEli Cohen 
valid_reserved(struct mlx4_dev * dev,int slave,int qpn)1775c82e9aa0SEli Cohen static int valid_reserved(struct mlx4_dev *dev, int slave, int qpn)
1776c82e9aa0SEli Cohen {
1777e2c76824SJack Morgenstein 	return mlx4_is_qp_reserved(dev, qpn) &&
1778e2c76824SJack Morgenstein 		(mlx4_is_master(dev) || mlx4_is_guest_proxy(dev, slave, qpn));
1779c82e9aa0SEli Cohen }
1780c82e9aa0SEli Cohen 
fw_reserved(struct mlx4_dev * dev,int qpn)178154679e14SJack Morgenstein static int fw_reserved(struct mlx4_dev *dev, int qpn)
178254679e14SJack Morgenstein {
178354679e14SJack Morgenstein 	return qpn < dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW];
1784c82e9aa0SEli Cohen }
1785c82e9aa0SEli Cohen 
qp_alloc_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param)1786c82e9aa0SEli Cohen static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
1787c82e9aa0SEli Cohen 			u64 in_param, u64 *out_param)
1788c82e9aa0SEli Cohen {
1789c82e9aa0SEli Cohen 	int err;
1790c82e9aa0SEli Cohen 	int count;
1791c82e9aa0SEli Cohen 	int align;
1792c82e9aa0SEli Cohen 	int base;
1793c82e9aa0SEli Cohen 	int qpn;
1794ddae0349SEugenia Emantayev 	u8 flags;
1795c82e9aa0SEli Cohen 
1796c82e9aa0SEli Cohen 	switch (op) {
1797c82e9aa0SEli Cohen 	case RES_OP_RESERVE:
17982d5c57d7SJack Morgenstein 		count = get_param_l(&in_param) & 0xffffff;
1799ddae0349SEugenia Emantayev 		/* Turn off all unsupported QP allocation flags that the
1800ddae0349SEugenia Emantayev 		 * slave tries to set.
1801ddae0349SEugenia Emantayev 		 */
1802ddae0349SEugenia Emantayev 		flags = (get_param_l(&in_param) >> 24) & dev->caps.alloc_res_qp_mask;
1803c82e9aa0SEli Cohen 		align = get_param_h(&in_param);
1804146f3ef4SJack Morgenstein 		err = mlx4_grant_resource(dev, slave, RES_QP, count, 0);
1805c82e9aa0SEli Cohen 		if (err)
1806c82e9aa0SEli Cohen 			return err;
1807c82e9aa0SEli Cohen 
1808ddae0349SEugenia Emantayev 		err = __mlx4_qp_reserve_range(dev, count, align, &base, flags);
1809146f3ef4SJack Morgenstein 		if (err) {
1810146f3ef4SJack Morgenstein 			mlx4_release_resource(dev, slave, RES_QP, count, 0);
1811146f3ef4SJack Morgenstein 			return err;
1812146f3ef4SJack Morgenstein 		}
1813146f3ef4SJack Morgenstein 
1814c82e9aa0SEli Cohen 		err = add_res_range(dev, slave, base, count, RES_QP, 0);
1815c82e9aa0SEli Cohen 		if (err) {
1816146f3ef4SJack Morgenstein 			mlx4_release_resource(dev, slave, RES_QP, count, 0);
1817c82e9aa0SEli Cohen 			__mlx4_qp_release_range(dev, base, count);
1818c82e9aa0SEli Cohen 			return err;
1819c82e9aa0SEli Cohen 		}
1820c82e9aa0SEli Cohen 		set_param_l(out_param, base);
1821c82e9aa0SEli Cohen 		break;
1822c82e9aa0SEli Cohen 	case RES_OP_MAP_ICM:
1823c82e9aa0SEli Cohen 		qpn = get_param_l(&in_param) & 0x7fffff;
1824c82e9aa0SEli Cohen 		if (valid_reserved(dev, slave, qpn)) {
1825c82e9aa0SEli Cohen 			err = add_res_range(dev, slave, qpn, 1, RES_QP, 0);
1826c82e9aa0SEli Cohen 			if (err)
1827c82e9aa0SEli Cohen 				return err;
1828c82e9aa0SEli Cohen 		}
1829c82e9aa0SEli Cohen 
1830c82e9aa0SEli Cohen 		err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED,
1831c82e9aa0SEli Cohen 					   NULL, 1);
1832c82e9aa0SEli Cohen 		if (err)
1833c82e9aa0SEli Cohen 			return err;
1834c82e9aa0SEli Cohen 
183554679e14SJack Morgenstein 		if (!fw_reserved(dev, qpn)) {
18368900b894SLeon Romanovsky 			err = __mlx4_qp_alloc_icm(dev, qpn);
1837c82e9aa0SEli Cohen 			if (err) {
1838c82e9aa0SEli Cohen 				res_abort_move(dev, slave, RES_QP, qpn);
1839c82e9aa0SEli Cohen 				return err;
1840c82e9aa0SEli Cohen 			}
1841c82e9aa0SEli Cohen 		}
1842c82e9aa0SEli Cohen 
1843c82e9aa0SEli Cohen 		res_end_move(dev, slave, RES_QP, qpn);
1844c82e9aa0SEli Cohen 		break;
1845c82e9aa0SEli Cohen 
1846c82e9aa0SEli Cohen 	default:
1847c82e9aa0SEli Cohen 		err = -EINVAL;
1848c82e9aa0SEli Cohen 		break;
1849c82e9aa0SEli Cohen 	}
1850c82e9aa0SEli Cohen 	return err;
1851c82e9aa0SEli Cohen }
1852c82e9aa0SEli Cohen 
mtt_alloc_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param)1853c82e9aa0SEli Cohen static int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
1854c82e9aa0SEli Cohen 			 u64 in_param, u64 *out_param)
1855c82e9aa0SEli Cohen {
1856c82e9aa0SEli Cohen 	int err = -EINVAL;
1857c82e9aa0SEli Cohen 	int base;
1858c82e9aa0SEli Cohen 	int order;
1859c82e9aa0SEli Cohen 
1860c82e9aa0SEli Cohen 	if (op != RES_OP_RESERVE_AND_MAP)
1861c82e9aa0SEli Cohen 		return err;
1862c82e9aa0SEli Cohen 
1863c82e9aa0SEli Cohen 	order = get_param_l(&in_param);
1864146f3ef4SJack Morgenstein 
1865146f3ef4SJack Morgenstein 	err = mlx4_grant_resource(dev, slave, RES_MTT, 1 << order, 0);
1866146f3ef4SJack Morgenstein 	if (err)
1867146f3ef4SJack Morgenstein 		return err;
1868146f3ef4SJack Morgenstein 
1869c82e9aa0SEli Cohen 	base = __mlx4_alloc_mtt_range(dev, order);
1870146f3ef4SJack Morgenstein 	if (base == -1) {
1871146f3ef4SJack Morgenstein 		mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
1872c82e9aa0SEli Cohen 		return -ENOMEM;
1873146f3ef4SJack Morgenstein 	}
1874c82e9aa0SEli Cohen 
1875c82e9aa0SEli Cohen 	err = add_res_range(dev, slave, base, 1, RES_MTT, order);
1876146f3ef4SJack Morgenstein 	if (err) {
1877146f3ef4SJack Morgenstein 		mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
1878c82e9aa0SEli Cohen 		__mlx4_free_mtt_range(dev, base, order);
1879146f3ef4SJack Morgenstein 	} else {
1880c82e9aa0SEli Cohen 		set_param_l(out_param, base);
1881146f3ef4SJack Morgenstein 	}
1882c82e9aa0SEli Cohen 
1883c82e9aa0SEli Cohen 	return err;
1884c82e9aa0SEli Cohen }
1885c82e9aa0SEli Cohen 
mpt_alloc_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param)1886c82e9aa0SEli Cohen static int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
1887c82e9aa0SEli Cohen 			 u64 in_param, u64 *out_param)
1888c82e9aa0SEli Cohen {
1889c82e9aa0SEli Cohen 	int err = -EINVAL;
1890c82e9aa0SEli Cohen 	int index;
1891c82e9aa0SEli Cohen 	int id;
1892c82e9aa0SEli Cohen 	struct res_mpt *mpt;
1893c82e9aa0SEli Cohen 
1894c82e9aa0SEli Cohen 	switch (op) {
1895c82e9aa0SEli Cohen 	case RES_OP_RESERVE:
1896146f3ef4SJack Morgenstein 		err = mlx4_grant_resource(dev, slave, RES_MPT, 1, 0);
1897146f3ef4SJack Morgenstein 		if (err)
1898c82e9aa0SEli Cohen 			break;
1899146f3ef4SJack Morgenstein 
1900146f3ef4SJack Morgenstein 		index = __mlx4_mpt_reserve(dev);
1901146f3ef4SJack Morgenstein 		if (index == -1) {
1902146f3ef4SJack Morgenstein 			mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
1903146f3ef4SJack Morgenstein 			break;
1904146f3ef4SJack Morgenstein 		}
1905c82e9aa0SEli Cohen 		id = index & mpt_mask(dev);
1906c82e9aa0SEli Cohen 
1907c82e9aa0SEli Cohen 		err = add_res_range(dev, slave, id, 1, RES_MPT, index);
1908c82e9aa0SEli Cohen 		if (err) {
1909146f3ef4SJack Morgenstein 			mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
1910b20e519aSShani Michaeli 			__mlx4_mpt_release(dev, index);
1911c82e9aa0SEli Cohen 			break;
1912c82e9aa0SEli Cohen 		}
1913c82e9aa0SEli Cohen 		set_param_l(out_param, index);
1914c82e9aa0SEli Cohen 		break;
1915c82e9aa0SEli Cohen 	case RES_OP_MAP_ICM:
1916c82e9aa0SEli Cohen 		index = get_param_l(&in_param);
1917c82e9aa0SEli Cohen 		id = index & mpt_mask(dev);
1918c82e9aa0SEli Cohen 		err = mr_res_start_move_to(dev, slave, id,
1919c82e9aa0SEli Cohen 					   RES_MPT_MAPPED, &mpt);
1920c82e9aa0SEli Cohen 		if (err)
1921c82e9aa0SEli Cohen 			return err;
1922c82e9aa0SEli Cohen 
19238900b894SLeon Romanovsky 		err = __mlx4_mpt_alloc_icm(dev, mpt->key);
1924c82e9aa0SEli Cohen 		if (err) {
1925c82e9aa0SEli Cohen 			res_abort_move(dev, slave, RES_MPT, id);
1926c82e9aa0SEli Cohen 			return err;
1927c82e9aa0SEli Cohen 		}
1928c82e9aa0SEli Cohen 
1929c82e9aa0SEli Cohen 		res_end_move(dev, slave, RES_MPT, id);
1930c82e9aa0SEli Cohen 		break;
1931c82e9aa0SEli Cohen 	}
1932c82e9aa0SEli Cohen 	return err;
1933c82e9aa0SEli Cohen }
1934c82e9aa0SEli Cohen 
cq_alloc_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param)1935c82e9aa0SEli Cohen static int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
1936c82e9aa0SEli Cohen 			u64 in_param, u64 *out_param)
1937c82e9aa0SEli Cohen {
1938c82e9aa0SEli Cohen 	int cqn;
1939c82e9aa0SEli Cohen 	int err;
1940c82e9aa0SEli Cohen 
1941c82e9aa0SEli Cohen 	switch (op) {
1942c82e9aa0SEli Cohen 	case RES_OP_RESERVE_AND_MAP:
1943146f3ef4SJack Morgenstein 		err = mlx4_grant_resource(dev, slave, RES_CQ, 1, 0);
1944c82e9aa0SEli Cohen 		if (err)
1945c82e9aa0SEli Cohen 			break;
1946c82e9aa0SEli Cohen 
1947146f3ef4SJack Morgenstein 		err = __mlx4_cq_alloc_icm(dev, &cqn);
1948146f3ef4SJack Morgenstein 		if (err) {
1949146f3ef4SJack Morgenstein 			mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
1950146f3ef4SJack Morgenstein 			break;
1951146f3ef4SJack Morgenstein 		}
1952146f3ef4SJack Morgenstein 
1953c82e9aa0SEli Cohen 		err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0);
1954c82e9aa0SEli Cohen 		if (err) {
1955146f3ef4SJack Morgenstein 			mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
1956c82e9aa0SEli Cohen 			__mlx4_cq_free_icm(dev, cqn);
1957c82e9aa0SEli Cohen 			break;
1958c82e9aa0SEli Cohen 		}
1959c82e9aa0SEli Cohen 
1960c82e9aa0SEli Cohen 		set_param_l(out_param, cqn);
1961c82e9aa0SEli Cohen 		break;
1962c82e9aa0SEli Cohen 
1963c82e9aa0SEli Cohen 	default:
1964c82e9aa0SEli Cohen 		err = -EINVAL;
1965c82e9aa0SEli Cohen 	}
1966c82e9aa0SEli Cohen 
1967c82e9aa0SEli Cohen 	return err;
1968c82e9aa0SEli Cohen }
1969c82e9aa0SEli Cohen 
srq_alloc_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param)1970c82e9aa0SEli Cohen static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
1971c82e9aa0SEli Cohen 			 u64 in_param, u64 *out_param)
1972c82e9aa0SEli Cohen {
1973c82e9aa0SEli Cohen 	int srqn;
1974c82e9aa0SEli Cohen 	int err;
1975c82e9aa0SEli Cohen 
1976c82e9aa0SEli Cohen 	switch (op) {
1977c82e9aa0SEli Cohen 	case RES_OP_RESERVE_AND_MAP:
1978146f3ef4SJack Morgenstein 		err = mlx4_grant_resource(dev, slave, RES_SRQ, 1, 0);
1979c82e9aa0SEli Cohen 		if (err)
1980c82e9aa0SEli Cohen 			break;
1981c82e9aa0SEli Cohen 
1982146f3ef4SJack Morgenstein 		err = __mlx4_srq_alloc_icm(dev, &srqn);
1983146f3ef4SJack Morgenstein 		if (err) {
1984146f3ef4SJack Morgenstein 			mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
1985146f3ef4SJack Morgenstein 			break;
1986146f3ef4SJack Morgenstein 		}
1987146f3ef4SJack Morgenstein 
1988c82e9aa0SEli Cohen 		err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0);
1989c82e9aa0SEli Cohen 		if (err) {
1990146f3ef4SJack Morgenstein 			mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
1991c82e9aa0SEli Cohen 			__mlx4_srq_free_icm(dev, srqn);
1992c82e9aa0SEli Cohen 			break;
1993c82e9aa0SEli Cohen 		}
1994c82e9aa0SEli Cohen 
1995c82e9aa0SEli Cohen 		set_param_l(out_param, srqn);
1996c82e9aa0SEli Cohen 		break;
1997c82e9aa0SEli Cohen 
1998c82e9aa0SEli Cohen 	default:
1999c82e9aa0SEli Cohen 		err = -EINVAL;
2000c82e9aa0SEli Cohen 	}
2001c82e9aa0SEli Cohen 
2002c82e9aa0SEli Cohen 	return err;
2003c82e9aa0SEli Cohen }
2004c82e9aa0SEli Cohen 
mac_find_smac_ix_in_slave(struct mlx4_dev * dev,int slave,int port,u8 smac_index,u64 * mac)20052f5bb473SJack Morgenstein static int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port,
20062f5bb473SJack Morgenstein 				     u8 smac_index, u64 *mac)
2007c82e9aa0SEli Cohen {
2008c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
2009c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
20102f5bb473SJack Morgenstein 	struct list_head *mac_list =
20112f5bb473SJack Morgenstein 		&tracker->slave_list[slave].res_list[RES_MAC];
20122f5bb473SJack Morgenstein 	struct mac_res *res, *tmp;
20132f5bb473SJack Morgenstein 
20142f5bb473SJack Morgenstein 	list_for_each_entry_safe(res, tmp, mac_list, list) {
20152f5bb473SJack Morgenstein 		if (res->smac_index == smac_index && res->port == (u8) port) {
20162f5bb473SJack Morgenstein 			*mac = res->mac;
20172f5bb473SJack Morgenstein 			return 0;
20182f5bb473SJack Morgenstein 		}
20192f5bb473SJack Morgenstein 	}
20202f5bb473SJack Morgenstein 	return -ENOENT;
20212f5bb473SJack Morgenstein }
20222f5bb473SJack Morgenstein 
mac_add_to_slave(struct mlx4_dev * dev,int slave,u64 mac,int port,u8 smac_index)20232f5bb473SJack Morgenstein static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index)
20242f5bb473SJack Morgenstein {
20252f5bb473SJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
20262f5bb473SJack Morgenstein 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
20272f5bb473SJack Morgenstein 	struct list_head *mac_list =
20282f5bb473SJack Morgenstein 		&tracker->slave_list[slave].res_list[RES_MAC];
20292f5bb473SJack Morgenstein 	struct mac_res *res, *tmp;
20302f5bb473SJack Morgenstein 
20312f5bb473SJack Morgenstein 	list_for_each_entry_safe(res, tmp, mac_list, list) {
20322f5bb473SJack Morgenstein 		if (res->mac == mac && res->port == (u8) port) {
20332f5bb473SJack Morgenstein 			/* mac found. update ref count */
20342f5bb473SJack Morgenstein 			++res->ref_count;
20352f5bb473SJack Morgenstein 			return 0;
20362f5bb473SJack Morgenstein 		}
20372f5bb473SJack Morgenstein 	}
2038c82e9aa0SEli Cohen 
2039146f3ef4SJack Morgenstein 	if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port))
2040146f3ef4SJack Morgenstein 		return -EINVAL;
204131975e27Sstephen hemminger 	res = kzalloc(sizeof(*res), GFP_KERNEL);
2042146f3ef4SJack Morgenstein 	if (!res) {
2043146f3ef4SJack Morgenstein 		mlx4_release_resource(dev, slave, RES_MAC, 1, port);
2044c82e9aa0SEli Cohen 		return -ENOMEM;
2045146f3ef4SJack Morgenstein 	}
2046c82e9aa0SEli Cohen 	res->mac = mac;
2047c82e9aa0SEli Cohen 	res->port = (u8) port;
20482f5bb473SJack Morgenstein 	res->smac_index = smac_index;
20492f5bb473SJack Morgenstein 	res->ref_count = 1;
2050c82e9aa0SEli Cohen 	list_add_tail(&res->list,
2051c82e9aa0SEli Cohen 		      &tracker->slave_list[slave].res_list[RES_MAC]);
2052c82e9aa0SEli Cohen 	return 0;
2053c82e9aa0SEli Cohen }
2054c82e9aa0SEli Cohen 
mac_del_from_slave(struct mlx4_dev * dev,int slave,u64 mac,int port)2055c82e9aa0SEli Cohen static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac,
2056c82e9aa0SEli Cohen 			       int port)
2057c82e9aa0SEli Cohen {
2058c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
2059c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
2060c82e9aa0SEli Cohen 	struct list_head *mac_list =
2061c82e9aa0SEli Cohen 		&tracker->slave_list[slave].res_list[RES_MAC];
2062c82e9aa0SEli Cohen 	struct mac_res *res, *tmp;
2063c82e9aa0SEli Cohen 
2064c82e9aa0SEli Cohen 	list_for_each_entry_safe(res, tmp, mac_list, list) {
2065c82e9aa0SEli Cohen 		if (res->mac == mac && res->port == (u8) port) {
20662f5bb473SJack Morgenstein 			if (!--res->ref_count) {
2067c82e9aa0SEli Cohen 				list_del(&res->list);
2068146f3ef4SJack Morgenstein 				mlx4_release_resource(dev, slave, RES_MAC, 1, port);
2069c82e9aa0SEli Cohen 				kfree(res);
20702f5bb473SJack Morgenstein 			}
2071c82e9aa0SEli Cohen 			break;
2072c82e9aa0SEli Cohen 		}
2073c82e9aa0SEli Cohen 	}
2074c82e9aa0SEli Cohen }
2075c82e9aa0SEli Cohen 
rem_slave_macs(struct mlx4_dev * dev,int slave)2076c82e9aa0SEli Cohen static void rem_slave_macs(struct mlx4_dev *dev, int slave)
2077c82e9aa0SEli Cohen {
2078c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
2079c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
2080c82e9aa0SEli Cohen 	struct list_head *mac_list =
2081c82e9aa0SEli Cohen 		&tracker->slave_list[slave].res_list[RES_MAC];
2082c82e9aa0SEli Cohen 	struct mac_res *res, *tmp;
20832f5bb473SJack Morgenstein 	int i;
2084c82e9aa0SEli Cohen 
2085c82e9aa0SEli Cohen 	list_for_each_entry_safe(res, tmp, mac_list, list) {
2086c82e9aa0SEli Cohen 		list_del(&res->list);
20872f5bb473SJack Morgenstein 		/* dereference the mac the num times the slave referenced it */
20882f5bb473SJack Morgenstein 		for (i = 0; i < res->ref_count; i++)
2089c82e9aa0SEli Cohen 			__mlx4_unregister_mac(dev, res->port, res->mac);
2090146f3ef4SJack Morgenstein 		mlx4_release_resource(dev, slave, RES_MAC, 1, res->port);
2091c82e9aa0SEli Cohen 		kfree(res);
2092c82e9aa0SEli Cohen 	}
2093c82e9aa0SEli Cohen }
2094c82e9aa0SEli Cohen 
mac_alloc_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param,int in_port)2095c82e9aa0SEli Cohen static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
2096acddd5ddSJack Morgenstein 			 u64 in_param, u64 *out_param, int in_port)
2097c82e9aa0SEli Cohen {
2098c82e9aa0SEli Cohen 	int err = -EINVAL;
2099c82e9aa0SEli Cohen 	int port;
2100c82e9aa0SEli Cohen 	u64 mac;
21012f5bb473SJack Morgenstein 	u8 smac_index;
2102c82e9aa0SEli Cohen 
2103c82e9aa0SEli Cohen 	if (op != RES_OP_RESERVE_AND_MAP)
2104c82e9aa0SEli Cohen 		return err;
2105c82e9aa0SEli Cohen 
2106acddd5ddSJack Morgenstein 	port = !in_port ? get_param_l(out_param) : in_port;
2107449fc488SMatan Barak 	port = mlx4_slave_convert_port(
2108449fc488SMatan Barak 			dev, slave, port);
2109449fc488SMatan Barak 
2110449fc488SMatan Barak 	if (port < 0)
2111449fc488SMatan Barak 		return -EINVAL;
2112c82e9aa0SEli Cohen 	mac = in_param;
2113c82e9aa0SEli Cohen 
2114c82e9aa0SEli Cohen 	err = __mlx4_register_mac(dev, port, mac);
2115c82e9aa0SEli Cohen 	if (err >= 0) {
21162f5bb473SJack Morgenstein 		smac_index = err;
2117c82e9aa0SEli Cohen 		set_param_l(out_param, err);
2118c82e9aa0SEli Cohen 		err = 0;
2119c82e9aa0SEli Cohen 	}
2120c82e9aa0SEli Cohen 
2121c82e9aa0SEli Cohen 	if (!err) {
21222f5bb473SJack Morgenstein 		err = mac_add_to_slave(dev, slave, mac, port, smac_index);
2123c82e9aa0SEli Cohen 		if (err)
2124c82e9aa0SEli Cohen 			__mlx4_unregister_mac(dev, port, mac);
2125c82e9aa0SEli Cohen 	}
2126c82e9aa0SEli Cohen 	return err;
2127c82e9aa0SEli Cohen }
2128c82e9aa0SEli Cohen 
vlan_add_to_slave(struct mlx4_dev * dev,int slave,u16 vlan,int port,int vlan_index)21294874080dSJack Morgenstein static int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan,
21304874080dSJack Morgenstein 			     int port, int vlan_index)
21314874080dSJack Morgenstein {
21324874080dSJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
21334874080dSJack Morgenstein 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
21344874080dSJack Morgenstein 	struct list_head *vlan_list =
21354874080dSJack Morgenstein 		&tracker->slave_list[slave].res_list[RES_VLAN];
21364874080dSJack Morgenstein 	struct vlan_res *res, *tmp;
21374874080dSJack Morgenstein 
21384874080dSJack Morgenstein 	list_for_each_entry_safe(res, tmp, vlan_list, list) {
21394874080dSJack Morgenstein 		if (res->vlan == vlan && res->port == (u8) port) {
21404874080dSJack Morgenstein 			/* vlan found. update ref count */
21414874080dSJack Morgenstein 			++res->ref_count;
21424874080dSJack Morgenstein 			return 0;
21434874080dSJack Morgenstein 		}
21444874080dSJack Morgenstein 	}
21454874080dSJack Morgenstein 
2146146f3ef4SJack Morgenstein 	if (mlx4_grant_resource(dev, slave, RES_VLAN, 1, port))
2147146f3ef4SJack Morgenstein 		return -EINVAL;
21484874080dSJack Morgenstein 	res = kzalloc(sizeof(*res), GFP_KERNEL);
2149146f3ef4SJack Morgenstein 	if (!res) {
2150146f3ef4SJack Morgenstein 		mlx4_release_resource(dev, slave, RES_VLAN, 1, port);
21514874080dSJack Morgenstein 		return -ENOMEM;
2152146f3ef4SJack Morgenstein 	}
21534874080dSJack Morgenstein 	res->vlan = vlan;
21544874080dSJack Morgenstein 	res->port = (u8) port;
21554874080dSJack Morgenstein 	res->vlan_index = vlan_index;
21564874080dSJack Morgenstein 	res->ref_count = 1;
21574874080dSJack Morgenstein 	list_add_tail(&res->list,
21584874080dSJack Morgenstein 		      &tracker->slave_list[slave].res_list[RES_VLAN]);
21594874080dSJack Morgenstein 	return 0;
21604874080dSJack Morgenstein }
21614874080dSJack Morgenstein 
21624874080dSJack Morgenstein 
vlan_del_from_slave(struct mlx4_dev * dev,int slave,u16 vlan,int port)21634874080dSJack Morgenstein static void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan,
21644874080dSJack Morgenstein 				int port)
21654874080dSJack Morgenstein {
21664874080dSJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
21674874080dSJack Morgenstein 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
21684874080dSJack Morgenstein 	struct list_head *vlan_list =
21694874080dSJack Morgenstein 		&tracker->slave_list[slave].res_list[RES_VLAN];
21704874080dSJack Morgenstein 	struct vlan_res *res, *tmp;
21714874080dSJack Morgenstein 
21724874080dSJack Morgenstein 	list_for_each_entry_safe(res, tmp, vlan_list, list) {
21734874080dSJack Morgenstein 		if (res->vlan == vlan && res->port == (u8) port) {
21744874080dSJack Morgenstein 			if (!--res->ref_count) {
21754874080dSJack Morgenstein 				list_del(&res->list);
2176146f3ef4SJack Morgenstein 				mlx4_release_resource(dev, slave, RES_VLAN,
2177146f3ef4SJack Morgenstein 						      1, port);
21784874080dSJack Morgenstein 				kfree(res);
21794874080dSJack Morgenstein 			}
21804874080dSJack Morgenstein 			break;
21814874080dSJack Morgenstein 		}
21824874080dSJack Morgenstein 	}
21834874080dSJack Morgenstein }
21844874080dSJack Morgenstein 
rem_slave_vlans(struct mlx4_dev * dev,int slave)21854874080dSJack Morgenstein static void rem_slave_vlans(struct mlx4_dev *dev, int slave)
21864874080dSJack Morgenstein {
21874874080dSJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
21884874080dSJack Morgenstein 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
21894874080dSJack Morgenstein 	struct list_head *vlan_list =
21904874080dSJack Morgenstein 		&tracker->slave_list[slave].res_list[RES_VLAN];
21914874080dSJack Morgenstein 	struct vlan_res *res, *tmp;
21924874080dSJack Morgenstein 	int i;
21934874080dSJack Morgenstein 
21944874080dSJack Morgenstein 	list_for_each_entry_safe(res, tmp, vlan_list, list) {
21954874080dSJack Morgenstein 		list_del(&res->list);
21964874080dSJack Morgenstein 		/* dereference the vlan the num times the slave referenced it */
21974874080dSJack Morgenstein 		for (i = 0; i < res->ref_count; i++)
21984874080dSJack Morgenstein 			__mlx4_unregister_vlan(dev, res->port, res->vlan);
2199146f3ef4SJack Morgenstein 		mlx4_release_resource(dev, slave, RES_VLAN, 1, res->port);
22004874080dSJack Morgenstein 		kfree(res);
22014874080dSJack Morgenstein 	}
22024874080dSJack Morgenstein }
22034874080dSJack Morgenstein 
vlan_alloc_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param,int in_port)2204ffe455adSEugenia Emantayev static int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
22052c957ff2SJack Morgenstein 			  u64 in_param, u64 *out_param, int in_port)
2206ffe455adSEugenia Emantayev {
22072c957ff2SJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
22082c957ff2SJack Morgenstein 	struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
22094874080dSJack Morgenstein 	int err;
22104874080dSJack Morgenstein 	u16 vlan;
22114874080dSJack Morgenstein 	int vlan_index;
22122c957ff2SJack Morgenstein 	int port;
22132c957ff2SJack Morgenstein 
22142c957ff2SJack Morgenstein 	port = !in_port ? get_param_l(out_param) : in_port;
22154874080dSJack Morgenstein 
22164874080dSJack Morgenstein 	if (!port || op != RES_OP_RESERVE_AND_MAP)
22174874080dSJack Morgenstein 		return -EINVAL;
22184874080dSJack Morgenstein 
2219449fc488SMatan Barak 	port = mlx4_slave_convert_port(
2220449fc488SMatan Barak 			dev, slave, port);
2221449fc488SMatan Barak 
2222449fc488SMatan Barak 	if (port < 0)
2223449fc488SMatan Barak 		return -EINVAL;
22242c957ff2SJack Morgenstein 	/* upstream kernels had NOP for reg/unreg vlan. Continue this. */
22252c957ff2SJack Morgenstein 	if (!in_port && port > 0 && port <= dev->caps.num_ports) {
22262c957ff2SJack Morgenstein 		slave_state[slave].old_vlan_api = true;
22272c957ff2SJack Morgenstein 		return 0;
22282c957ff2SJack Morgenstein 	}
22292c957ff2SJack Morgenstein 
22304874080dSJack Morgenstein 	vlan = (u16) in_param;
22314874080dSJack Morgenstein 
22324874080dSJack Morgenstein 	err = __mlx4_register_vlan(dev, port, vlan, &vlan_index);
22334874080dSJack Morgenstein 	if (!err) {
22344874080dSJack Morgenstein 		set_param_l(out_param, (u32) vlan_index);
22354874080dSJack Morgenstein 		err = vlan_add_to_slave(dev, slave, vlan, port, vlan_index);
22364874080dSJack Morgenstein 		if (err)
22374874080dSJack Morgenstein 			__mlx4_unregister_vlan(dev, port, vlan);
22384874080dSJack Morgenstein 	}
22394874080dSJack Morgenstein 	return err;
2240ffe455adSEugenia Emantayev }
2241ffe455adSEugenia Emantayev 
counter_alloc_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param,int port)2242ba062d52SJack Morgenstein static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
224368230242SEran Ben Elisha 			     u64 in_param, u64 *out_param, int port)
2244ba062d52SJack Morgenstein {
2245ba062d52SJack Morgenstein 	u32 index;
2246ba062d52SJack Morgenstein 	int err;
2247ba062d52SJack Morgenstein 
2248ba062d52SJack Morgenstein 	if (op != RES_OP_RESERVE)
2249ba062d52SJack Morgenstein 		return -EINVAL;
2250ba062d52SJack Morgenstein 
2251146f3ef4SJack Morgenstein 	err = mlx4_grant_resource(dev, slave, RES_COUNTER, 1, 0);
2252ba062d52SJack Morgenstein 	if (err)
2253ba062d52SJack Morgenstein 		return err;
2254ba062d52SJack Morgenstein 
2255146f3ef4SJack Morgenstein 	err = __mlx4_counter_alloc(dev, &index);
2256146f3ef4SJack Morgenstein 	if (err) {
2257146f3ef4SJack Morgenstein 		mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
2258146f3ef4SJack Morgenstein 		return err;
2259146f3ef4SJack Morgenstein 	}
2260146f3ef4SJack Morgenstein 
226168230242SEran Ben Elisha 	err = add_res_range(dev, slave, index, 1, RES_COUNTER, port);
2262146f3ef4SJack Morgenstein 	if (err) {
2263ba062d52SJack Morgenstein 		__mlx4_counter_free(dev, index);
2264146f3ef4SJack Morgenstein 		mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
2265146f3ef4SJack Morgenstein 	} else {
2266ba062d52SJack Morgenstein 		set_param_l(out_param, index);
2267146f3ef4SJack Morgenstein 	}
2268ba062d52SJack Morgenstein 
2269ba062d52SJack Morgenstein 	return err;
2270ba062d52SJack Morgenstein }
2271ba062d52SJack Morgenstein 
xrcdn_alloc_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param)2272ba062d52SJack Morgenstein static int xrcdn_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
2273ba062d52SJack Morgenstein 			   u64 in_param, u64 *out_param)
2274ba062d52SJack Morgenstein {
2275ba062d52SJack Morgenstein 	u32 xrcdn;
2276ba062d52SJack Morgenstein 	int err;
2277ba062d52SJack Morgenstein 
2278ba062d52SJack Morgenstein 	if (op != RES_OP_RESERVE)
2279ba062d52SJack Morgenstein 		return -EINVAL;
2280ba062d52SJack Morgenstein 
2281ba062d52SJack Morgenstein 	err = __mlx4_xrcd_alloc(dev, &xrcdn);
2282ba062d52SJack Morgenstein 	if (err)
2283ba062d52SJack Morgenstein 		return err;
2284ba062d52SJack Morgenstein 
2285ba062d52SJack Morgenstein 	err = add_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0);
2286ba062d52SJack Morgenstein 	if (err)
2287ba062d52SJack Morgenstein 		__mlx4_xrcd_free(dev, xrcdn);
2288ba062d52SJack Morgenstein 	else
2289ba062d52SJack Morgenstein 		set_param_l(out_param, xrcdn);
2290ba062d52SJack Morgenstein 
2291ba062d52SJack Morgenstein 	return err;
2292ba062d52SJack Morgenstein }
2293ba062d52SJack Morgenstein 
mlx4_ALLOC_RES_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)2294c82e9aa0SEli Cohen int mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave,
2295c82e9aa0SEli Cohen 			   struct mlx4_vhcr *vhcr,
2296c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *inbox,
2297c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *outbox,
2298c82e9aa0SEli Cohen 			   struct mlx4_cmd_info *cmd)
2299c82e9aa0SEli Cohen {
2300c82e9aa0SEli Cohen 	int err;
2301c82e9aa0SEli Cohen 	int alop = vhcr->op_modifier;
2302c82e9aa0SEli Cohen 
2303acddd5ddSJack Morgenstein 	switch (vhcr->in_modifier & 0xFF) {
2304c82e9aa0SEli Cohen 	case RES_QP:
2305c82e9aa0SEli Cohen 		err = qp_alloc_res(dev, slave, vhcr->op_modifier, alop,
2306c82e9aa0SEli Cohen 				   vhcr->in_param, &vhcr->out_param);
2307c82e9aa0SEli Cohen 		break;
2308c82e9aa0SEli Cohen 
2309c82e9aa0SEli Cohen 	case RES_MTT:
2310c82e9aa0SEli Cohen 		err = mtt_alloc_res(dev, slave, vhcr->op_modifier, alop,
2311c82e9aa0SEli Cohen 				    vhcr->in_param, &vhcr->out_param);
2312c82e9aa0SEli Cohen 		break;
2313c82e9aa0SEli Cohen 
2314c82e9aa0SEli Cohen 	case RES_MPT:
2315c82e9aa0SEli Cohen 		err = mpt_alloc_res(dev, slave, vhcr->op_modifier, alop,
2316c82e9aa0SEli Cohen 				    vhcr->in_param, &vhcr->out_param);
2317c82e9aa0SEli Cohen 		break;
2318c82e9aa0SEli Cohen 
2319c82e9aa0SEli Cohen 	case RES_CQ:
2320c82e9aa0SEli Cohen 		err = cq_alloc_res(dev, slave, vhcr->op_modifier, alop,
2321c82e9aa0SEli Cohen 				   vhcr->in_param, &vhcr->out_param);
2322c82e9aa0SEli Cohen 		break;
2323c82e9aa0SEli Cohen 
2324c82e9aa0SEli Cohen 	case RES_SRQ:
2325c82e9aa0SEli Cohen 		err = srq_alloc_res(dev, slave, vhcr->op_modifier, alop,
2326c82e9aa0SEli Cohen 				    vhcr->in_param, &vhcr->out_param);
2327c82e9aa0SEli Cohen 		break;
2328c82e9aa0SEli Cohen 
2329c82e9aa0SEli Cohen 	case RES_MAC:
2330c82e9aa0SEli Cohen 		err = mac_alloc_res(dev, slave, vhcr->op_modifier, alop,
2331acddd5ddSJack Morgenstein 				    vhcr->in_param, &vhcr->out_param,
2332acddd5ddSJack Morgenstein 				    (vhcr->in_modifier >> 8) & 0xFF);
2333c82e9aa0SEli Cohen 		break;
2334c82e9aa0SEli Cohen 
2335ffe455adSEugenia Emantayev 	case RES_VLAN:
2336ffe455adSEugenia Emantayev 		err = vlan_alloc_res(dev, slave, vhcr->op_modifier, alop,
2337acddd5ddSJack Morgenstein 				     vhcr->in_param, &vhcr->out_param,
2338acddd5ddSJack Morgenstein 				     (vhcr->in_modifier >> 8) & 0xFF);
2339ffe455adSEugenia Emantayev 		break;
2340ffe455adSEugenia Emantayev 
2341ba062d52SJack Morgenstein 	case RES_COUNTER:
2342ba062d52SJack Morgenstein 		err = counter_alloc_res(dev, slave, vhcr->op_modifier, alop,
234368230242SEran Ben Elisha 					vhcr->in_param, &vhcr->out_param, 0);
2344ba062d52SJack Morgenstein 		break;
2345ba062d52SJack Morgenstein 
2346ba062d52SJack Morgenstein 	case RES_XRCD:
2347ba062d52SJack Morgenstein 		err = xrcdn_alloc_res(dev, slave, vhcr->op_modifier, alop,
2348ba062d52SJack Morgenstein 				      vhcr->in_param, &vhcr->out_param);
2349ba062d52SJack Morgenstein 		break;
2350ba062d52SJack Morgenstein 
2351c82e9aa0SEli Cohen 	default:
2352c82e9aa0SEli Cohen 		err = -EINVAL;
2353c82e9aa0SEli Cohen 		break;
2354c82e9aa0SEli Cohen 	}
2355c82e9aa0SEli Cohen 
2356c82e9aa0SEli Cohen 	return err;
2357c82e9aa0SEli Cohen }
2358c82e9aa0SEli Cohen 
qp_free_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param)2359c82e9aa0SEli Cohen static int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
2360c82e9aa0SEli Cohen 		       u64 in_param)
2361c82e9aa0SEli Cohen {
2362c82e9aa0SEli Cohen 	int err;
2363c82e9aa0SEli Cohen 	int count;
2364c82e9aa0SEli Cohen 	int base;
2365c82e9aa0SEli Cohen 	int qpn;
2366c82e9aa0SEli Cohen 
2367c82e9aa0SEli Cohen 	switch (op) {
2368c82e9aa0SEli Cohen 	case RES_OP_RESERVE:
2369c82e9aa0SEli Cohen 		base = get_param_l(&in_param) & 0x7fffff;
2370c82e9aa0SEli Cohen 		count = get_param_h(&in_param);
2371c82e9aa0SEli Cohen 		err = rem_res_range(dev, slave, base, count, RES_QP, 0);
2372c82e9aa0SEli Cohen 		if (err)
2373c82e9aa0SEli Cohen 			break;
2374146f3ef4SJack Morgenstein 		mlx4_release_resource(dev, slave, RES_QP, count, 0);
2375c82e9aa0SEli Cohen 		__mlx4_qp_release_range(dev, base, count);
2376c82e9aa0SEli Cohen 		break;
2377c82e9aa0SEli Cohen 	case RES_OP_MAP_ICM:
2378c82e9aa0SEli Cohen 		qpn = get_param_l(&in_param) & 0x7fffff;
2379c82e9aa0SEli Cohen 		err = qp_res_start_move_to(dev, slave, qpn, RES_QP_RESERVED,
2380c82e9aa0SEli Cohen 					   NULL, 0);
2381c82e9aa0SEli Cohen 		if (err)
2382c82e9aa0SEli Cohen 			return err;
2383c82e9aa0SEli Cohen 
238454679e14SJack Morgenstein 		if (!fw_reserved(dev, qpn))
2385c82e9aa0SEli Cohen 			__mlx4_qp_free_icm(dev, qpn);
2386c82e9aa0SEli Cohen 
2387c82e9aa0SEli Cohen 		res_end_move(dev, slave, RES_QP, qpn);
2388c82e9aa0SEli Cohen 
2389c82e9aa0SEli Cohen 		if (valid_reserved(dev, slave, qpn))
2390c82e9aa0SEli Cohen 			err = rem_res_range(dev, slave, qpn, 1, RES_QP, 0);
2391c82e9aa0SEli Cohen 		break;
2392c82e9aa0SEli Cohen 	default:
2393c82e9aa0SEli Cohen 		err = -EINVAL;
2394c82e9aa0SEli Cohen 		break;
2395c82e9aa0SEli Cohen 	}
2396c82e9aa0SEli Cohen 	return err;
2397c82e9aa0SEli Cohen }
2398c82e9aa0SEli Cohen 
mtt_free_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param)2399c82e9aa0SEli Cohen static int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
2400c82e9aa0SEli Cohen 			u64 in_param, u64 *out_param)
2401c82e9aa0SEli Cohen {
2402c82e9aa0SEli Cohen 	int err = -EINVAL;
2403c82e9aa0SEli Cohen 	int base;
2404c82e9aa0SEli Cohen 	int order;
2405c82e9aa0SEli Cohen 
2406c82e9aa0SEli Cohen 	if (op != RES_OP_RESERVE_AND_MAP)
2407c82e9aa0SEli Cohen 		return err;
2408c82e9aa0SEli Cohen 
2409c82e9aa0SEli Cohen 	base = get_param_l(&in_param);
2410c82e9aa0SEli Cohen 	order = get_param_h(&in_param);
2411c82e9aa0SEli Cohen 	err = rem_res_range(dev, slave, base, 1, RES_MTT, order);
2412146f3ef4SJack Morgenstein 	if (!err) {
2413146f3ef4SJack Morgenstein 		mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
2414c82e9aa0SEli Cohen 		__mlx4_free_mtt_range(dev, base, order);
2415146f3ef4SJack Morgenstein 	}
2416c82e9aa0SEli Cohen 	return err;
2417c82e9aa0SEli Cohen }
2418c82e9aa0SEli Cohen 
mpt_free_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param)2419c82e9aa0SEli Cohen static int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
2420c82e9aa0SEli Cohen 			u64 in_param)
2421c82e9aa0SEli Cohen {
2422c82e9aa0SEli Cohen 	int err = -EINVAL;
2423c82e9aa0SEli Cohen 	int index;
2424c82e9aa0SEli Cohen 	int id;
2425c82e9aa0SEli Cohen 	struct res_mpt *mpt;
2426c82e9aa0SEli Cohen 
2427c82e9aa0SEli Cohen 	switch (op) {
2428c82e9aa0SEli Cohen 	case RES_OP_RESERVE:
2429c82e9aa0SEli Cohen 		index = get_param_l(&in_param);
2430c82e9aa0SEli Cohen 		id = index & mpt_mask(dev);
2431c82e9aa0SEli Cohen 		err = get_res(dev, slave, id, RES_MPT, &mpt);
2432c82e9aa0SEli Cohen 		if (err)
2433c82e9aa0SEli Cohen 			break;
2434c82e9aa0SEli Cohen 		index = mpt->key;
2435c82e9aa0SEli Cohen 		put_res(dev, slave, id, RES_MPT);
2436c82e9aa0SEli Cohen 
2437c82e9aa0SEli Cohen 		err = rem_res_range(dev, slave, id, 1, RES_MPT, 0);
2438c82e9aa0SEli Cohen 		if (err)
2439c82e9aa0SEli Cohen 			break;
2440146f3ef4SJack Morgenstein 		mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
2441b20e519aSShani Michaeli 		__mlx4_mpt_release(dev, index);
2442c82e9aa0SEli Cohen 		break;
2443c82e9aa0SEli Cohen 	case RES_OP_MAP_ICM:
2444c82e9aa0SEli Cohen 		index = get_param_l(&in_param);
2445c82e9aa0SEli Cohen 		id = index & mpt_mask(dev);
2446c82e9aa0SEli Cohen 		err = mr_res_start_move_to(dev, slave, id,
2447c82e9aa0SEli Cohen 					   RES_MPT_RESERVED, &mpt);
2448c82e9aa0SEli Cohen 		if (err)
2449c82e9aa0SEli Cohen 			return err;
2450c82e9aa0SEli Cohen 
2451b20e519aSShani Michaeli 		__mlx4_mpt_free_icm(dev, mpt->key);
2452c82e9aa0SEli Cohen 		res_end_move(dev, slave, RES_MPT, id);
2453c82e9aa0SEli Cohen 		break;
2454c82e9aa0SEli Cohen 	default:
2455c82e9aa0SEli Cohen 		err = -EINVAL;
2456c82e9aa0SEli Cohen 		break;
2457c82e9aa0SEli Cohen 	}
2458c82e9aa0SEli Cohen 	return err;
2459c82e9aa0SEli Cohen }
2460c82e9aa0SEli Cohen 
cq_free_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param)2461c82e9aa0SEli Cohen static int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
2462c82e9aa0SEli Cohen 		       u64 in_param, u64 *out_param)
2463c82e9aa0SEli Cohen {
2464c82e9aa0SEli Cohen 	int cqn;
2465c82e9aa0SEli Cohen 	int err;
2466c82e9aa0SEli Cohen 
2467c82e9aa0SEli Cohen 	switch (op) {
2468c82e9aa0SEli Cohen 	case RES_OP_RESERVE_AND_MAP:
2469c82e9aa0SEli Cohen 		cqn = get_param_l(&in_param);
2470c82e9aa0SEli Cohen 		err = rem_res_range(dev, slave, cqn, 1, RES_CQ, 0);
2471c82e9aa0SEli Cohen 		if (err)
2472c82e9aa0SEli Cohen 			break;
2473c82e9aa0SEli Cohen 
2474146f3ef4SJack Morgenstein 		mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
2475c82e9aa0SEli Cohen 		__mlx4_cq_free_icm(dev, cqn);
2476c82e9aa0SEli Cohen 		break;
2477c82e9aa0SEli Cohen 
2478c82e9aa0SEli Cohen 	default:
2479c82e9aa0SEli Cohen 		err = -EINVAL;
2480c82e9aa0SEli Cohen 		break;
2481c82e9aa0SEli Cohen 	}
2482c82e9aa0SEli Cohen 
2483c82e9aa0SEli Cohen 	return err;
2484c82e9aa0SEli Cohen }
2485c82e9aa0SEli Cohen 
srq_free_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param)2486c82e9aa0SEli Cohen static int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
2487c82e9aa0SEli Cohen 			u64 in_param, u64 *out_param)
2488c82e9aa0SEli Cohen {
2489c82e9aa0SEli Cohen 	int srqn;
2490c82e9aa0SEli Cohen 	int err;
2491c82e9aa0SEli Cohen 
2492c82e9aa0SEli Cohen 	switch (op) {
2493c82e9aa0SEli Cohen 	case RES_OP_RESERVE_AND_MAP:
2494c82e9aa0SEli Cohen 		srqn = get_param_l(&in_param);
2495c82e9aa0SEli Cohen 		err = rem_res_range(dev, slave, srqn, 1, RES_SRQ, 0);
2496c82e9aa0SEli Cohen 		if (err)
2497c82e9aa0SEli Cohen 			break;
2498c82e9aa0SEli Cohen 
2499146f3ef4SJack Morgenstein 		mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
2500c82e9aa0SEli Cohen 		__mlx4_srq_free_icm(dev, srqn);
2501c82e9aa0SEli Cohen 		break;
2502c82e9aa0SEli Cohen 
2503c82e9aa0SEli Cohen 	default:
2504c82e9aa0SEli Cohen 		err = -EINVAL;
2505c82e9aa0SEli Cohen 		break;
2506c82e9aa0SEli Cohen 	}
2507c82e9aa0SEli Cohen 
2508c82e9aa0SEli Cohen 	return err;
2509c82e9aa0SEli Cohen }
2510c82e9aa0SEli Cohen 
mac_free_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param,int in_port)2511c82e9aa0SEli Cohen static int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
2512acddd5ddSJack Morgenstein 			    u64 in_param, u64 *out_param, int in_port)
2513c82e9aa0SEli Cohen {
2514c82e9aa0SEli Cohen 	int port;
2515c82e9aa0SEli Cohen 	int err = 0;
2516c82e9aa0SEli Cohen 
2517c82e9aa0SEli Cohen 	switch (op) {
2518c82e9aa0SEli Cohen 	case RES_OP_RESERVE_AND_MAP:
2519acddd5ddSJack Morgenstein 		port = !in_port ? get_param_l(out_param) : in_port;
2520449fc488SMatan Barak 		port = mlx4_slave_convert_port(
2521449fc488SMatan Barak 				dev, slave, port);
2522449fc488SMatan Barak 
2523449fc488SMatan Barak 		if (port < 0)
2524449fc488SMatan Barak 			return -EINVAL;
2525c82e9aa0SEli Cohen 		mac_del_from_slave(dev, slave, in_param, port);
2526c82e9aa0SEli Cohen 		__mlx4_unregister_mac(dev, port, in_param);
2527c82e9aa0SEli Cohen 		break;
2528c82e9aa0SEli Cohen 	default:
2529c82e9aa0SEli Cohen 		err = -EINVAL;
2530c82e9aa0SEli Cohen 		break;
2531c82e9aa0SEli Cohen 	}
2532c82e9aa0SEli Cohen 
2533c82e9aa0SEli Cohen 	return err;
2534c82e9aa0SEli Cohen 
2535c82e9aa0SEli Cohen }
2536c82e9aa0SEli Cohen 
vlan_free_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param,int port)2537ffe455adSEugenia Emantayev static int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
2538acddd5ddSJack Morgenstein 			    u64 in_param, u64 *out_param, int port)
2539ffe455adSEugenia Emantayev {
25402c957ff2SJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
25412c957ff2SJack Morgenstein 	struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
25424874080dSJack Morgenstein 	int err = 0;
25434874080dSJack Morgenstein 
2544449fc488SMatan Barak 	port = mlx4_slave_convert_port(
2545449fc488SMatan Barak 			dev, slave, port);
2546449fc488SMatan Barak 
2547449fc488SMatan Barak 	if (port < 0)
2548449fc488SMatan Barak 		return -EINVAL;
25494874080dSJack Morgenstein 	switch (op) {
25504874080dSJack Morgenstein 	case RES_OP_RESERVE_AND_MAP:
25512c957ff2SJack Morgenstein 		if (slave_state[slave].old_vlan_api)
25522c957ff2SJack Morgenstein 			return 0;
25534874080dSJack Morgenstein 		if (!port)
25544874080dSJack Morgenstein 			return -EINVAL;
25554874080dSJack Morgenstein 		vlan_del_from_slave(dev, slave, in_param, port);
25564874080dSJack Morgenstein 		__mlx4_unregister_vlan(dev, port, in_param);
25574874080dSJack Morgenstein 		break;
25584874080dSJack Morgenstein 	default:
25594874080dSJack Morgenstein 		err = -EINVAL;
25604874080dSJack Morgenstein 		break;
25614874080dSJack Morgenstein 	}
25624874080dSJack Morgenstein 
25634874080dSJack Morgenstein 	return err;
2564ffe455adSEugenia Emantayev }
2565ffe455adSEugenia Emantayev 
counter_free_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param)2566ba062d52SJack Morgenstein static int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
2567ba062d52SJack Morgenstein 			    u64 in_param, u64 *out_param)
2568ba062d52SJack Morgenstein {
2569ba062d52SJack Morgenstein 	int index;
2570ba062d52SJack Morgenstein 	int err;
2571ba062d52SJack Morgenstein 
2572ba062d52SJack Morgenstein 	if (op != RES_OP_RESERVE)
2573ba062d52SJack Morgenstein 		return -EINVAL;
2574ba062d52SJack Morgenstein 
2575ba062d52SJack Morgenstein 	index = get_param_l(&in_param);
25769de92c60SEran Ben Elisha 	if (index == MLX4_SINK_COUNTER_INDEX(dev))
25779de92c60SEran Ben Elisha 		return 0;
25789de92c60SEran Ben Elisha 
2579ba062d52SJack Morgenstein 	err = rem_res_range(dev, slave, index, 1, RES_COUNTER, 0);
2580ba062d52SJack Morgenstein 	if (err)
2581ba062d52SJack Morgenstein 		return err;
2582ba062d52SJack Morgenstein 
2583ba062d52SJack Morgenstein 	__mlx4_counter_free(dev, index);
2584146f3ef4SJack Morgenstein 	mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
2585ba062d52SJack Morgenstein 
2586ba062d52SJack Morgenstein 	return err;
2587ba062d52SJack Morgenstein }
2588ba062d52SJack Morgenstein 
xrcdn_free_res(struct mlx4_dev * dev,int slave,int op,int cmd,u64 in_param,u64 * out_param)2589ba062d52SJack Morgenstein static int xrcdn_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
2590ba062d52SJack Morgenstein 			  u64 in_param, u64 *out_param)
2591ba062d52SJack Morgenstein {
2592ba062d52SJack Morgenstein 	int xrcdn;
2593ba062d52SJack Morgenstein 	int err;
2594ba062d52SJack Morgenstein 
2595ba062d52SJack Morgenstein 	if (op != RES_OP_RESERVE)
2596ba062d52SJack Morgenstein 		return -EINVAL;
2597ba062d52SJack Morgenstein 
2598ba062d52SJack Morgenstein 	xrcdn = get_param_l(&in_param);
2599ba062d52SJack Morgenstein 	err = rem_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0);
2600ba062d52SJack Morgenstein 	if (err)
2601ba062d52SJack Morgenstein 		return err;
2602ba062d52SJack Morgenstein 
2603ba062d52SJack Morgenstein 	__mlx4_xrcd_free(dev, xrcdn);
2604ba062d52SJack Morgenstein 
2605ba062d52SJack Morgenstein 	return err;
2606ba062d52SJack Morgenstein }
2607ba062d52SJack Morgenstein 
mlx4_FREE_RES_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)2608c82e9aa0SEli Cohen int mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave,
2609c82e9aa0SEli Cohen 			  struct mlx4_vhcr *vhcr,
2610c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *inbox,
2611c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *outbox,
2612c82e9aa0SEli Cohen 			  struct mlx4_cmd_info *cmd)
2613c82e9aa0SEli Cohen {
2614c82e9aa0SEli Cohen 	int err = -EINVAL;
2615c82e9aa0SEli Cohen 	int alop = vhcr->op_modifier;
2616c82e9aa0SEli Cohen 
2617acddd5ddSJack Morgenstein 	switch (vhcr->in_modifier & 0xFF) {
2618c82e9aa0SEli Cohen 	case RES_QP:
2619c82e9aa0SEli Cohen 		err = qp_free_res(dev, slave, vhcr->op_modifier, alop,
2620c82e9aa0SEli Cohen 				  vhcr->in_param);
2621c82e9aa0SEli Cohen 		break;
2622c82e9aa0SEli Cohen 
2623c82e9aa0SEli Cohen 	case RES_MTT:
2624c82e9aa0SEli Cohen 		err = mtt_free_res(dev, slave, vhcr->op_modifier, alop,
2625c82e9aa0SEli Cohen 				   vhcr->in_param, &vhcr->out_param);
2626c82e9aa0SEli Cohen 		break;
2627c82e9aa0SEli Cohen 
2628c82e9aa0SEli Cohen 	case RES_MPT:
2629c82e9aa0SEli Cohen 		err = mpt_free_res(dev, slave, vhcr->op_modifier, alop,
2630c82e9aa0SEli Cohen 				   vhcr->in_param);
2631c82e9aa0SEli Cohen 		break;
2632c82e9aa0SEli Cohen 
2633c82e9aa0SEli Cohen 	case RES_CQ:
2634c82e9aa0SEli Cohen 		err = cq_free_res(dev, slave, vhcr->op_modifier, alop,
2635c82e9aa0SEli Cohen 				  vhcr->in_param, &vhcr->out_param);
2636c82e9aa0SEli Cohen 		break;
2637c82e9aa0SEli Cohen 
2638c82e9aa0SEli Cohen 	case RES_SRQ:
2639c82e9aa0SEli Cohen 		err = srq_free_res(dev, slave, vhcr->op_modifier, alop,
2640c82e9aa0SEli Cohen 				   vhcr->in_param, &vhcr->out_param);
2641c82e9aa0SEli Cohen 		break;
2642c82e9aa0SEli Cohen 
2643c82e9aa0SEli Cohen 	case RES_MAC:
2644c82e9aa0SEli Cohen 		err = mac_free_res(dev, slave, vhcr->op_modifier, alop,
2645acddd5ddSJack Morgenstein 				   vhcr->in_param, &vhcr->out_param,
2646acddd5ddSJack Morgenstein 				   (vhcr->in_modifier >> 8) & 0xFF);
2647c82e9aa0SEli Cohen 		break;
2648c82e9aa0SEli Cohen 
2649ffe455adSEugenia Emantayev 	case RES_VLAN:
2650ffe455adSEugenia Emantayev 		err = vlan_free_res(dev, slave, vhcr->op_modifier, alop,
2651acddd5ddSJack Morgenstein 				    vhcr->in_param, &vhcr->out_param,
2652acddd5ddSJack Morgenstein 				    (vhcr->in_modifier >> 8) & 0xFF);
2653ffe455adSEugenia Emantayev 		break;
2654ffe455adSEugenia Emantayev 
2655ba062d52SJack Morgenstein 	case RES_COUNTER:
2656ba062d52SJack Morgenstein 		err = counter_free_res(dev, slave, vhcr->op_modifier, alop,
2657ba062d52SJack Morgenstein 				       vhcr->in_param, &vhcr->out_param);
2658ba062d52SJack Morgenstein 		break;
2659ba062d52SJack Morgenstein 
2660ba062d52SJack Morgenstein 	case RES_XRCD:
2661ba062d52SJack Morgenstein 		err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop,
2662ba062d52SJack Morgenstein 				     vhcr->in_param, &vhcr->out_param);
2663*6ca24c65SGustavo A. R. Silva 		break;
2664ba062d52SJack Morgenstein 
2665c82e9aa0SEli Cohen 	default:
2666c82e9aa0SEli Cohen 		break;
2667c82e9aa0SEli Cohen 	}
2668c82e9aa0SEli Cohen 	return err;
2669c82e9aa0SEli Cohen }
2670c82e9aa0SEli Cohen 
2671c82e9aa0SEli Cohen /* ugly but other choices are uglier */
mr_phys_mpt(struct mlx4_mpt_entry * mpt)2672c82e9aa0SEli Cohen static int mr_phys_mpt(struct mlx4_mpt_entry *mpt)
2673c82e9aa0SEli Cohen {
2674c82e9aa0SEli Cohen 	return (be32_to_cpu(mpt->flags) >> 9) & 1;
2675c82e9aa0SEli Cohen }
2676c82e9aa0SEli Cohen 
mr_get_mtt_addr(struct mlx4_mpt_entry * mpt)26772b8fb286SMarcel Apfelbaum static int mr_get_mtt_addr(struct mlx4_mpt_entry *mpt)
2678c82e9aa0SEli Cohen {
26792b8fb286SMarcel Apfelbaum 	return (int)be64_to_cpu(mpt->mtt_addr) & 0xfffffff8;
2680c82e9aa0SEli Cohen }
2681c82e9aa0SEli Cohen 
mr_get_mtt_size(struct mlx4_mpt_entry * mpt)2682c82e9aa0SEli Cohen static int mr_get_mtt_size(struct mlx4_mpt_entry *mpt)
2683c82e9aa0SEli Cohen {
2684c82e9aa0SEli Cohen 	return be32_to_cpu(mpt->mtt_sz);
2685c82e9aa0SEli Cohen }
2686c82e9aa0SEli Cohen 
mr_get_pd(struct mlx4_mpt_entry * mpt)2687cc1ade94SShani Michaeli static u32 mr_get_pd(struct mlx4_mpt_entry *mpt)
2688cc1ade94SShani Michaeli {
2689cc1ade94SShani Michaeli 	return be32_to_cpu(mpt->pd_flags) & 0x00ffffff;
2690cc1ade94SShani Michaeli }
2691cc1ade94SShani Michaeli 
mr_is_fmr(struct mlx4_mpt_entry * mpt)2692cc1ade94SShani Michaeli static int mr_is_fmr(struct mlx4_mpt_entry *mpt)
2693cc1ade94SShani Michaeli {
2694cc1ade94SShani Michaeli 	return be32_to_cpu(mpt->pd_flags) & MLX4_MPT_PD_FLAG_FAST_REG;
2695cc1ade94SShani Michaeli }
2696cc1ade94SShani Michaeli 
mr_is_bind_enabled(struct mlx4_mpt_entry * mpt)2697cc1ade94SShani Michaeli static int mr_is_bind_enabled(struct mlx4_mpt_entry *mpt)
2698cc1ade94SShani Michaeli {
2699cc1ade94SShani Michaeli 	return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_BIND_ENABLE;
2700cc1ade94SShani Michaeli }
2701cc1ade94SShani Michaeli 
mr_is_region(struct mlx4_mpt_entry * mpt)2702cc1ade94SShani Michaeli static int mr_is_region(struct mlx4_mpt_entry *mpt)
2703cc1ade94SShani Michaeli {
2704cc1ade94SShani Michaeli 	return be32_to_cpu(mpt->flags) & MLX4_MPT_FLAG_REGION;
2705cc1ade94SShani Michaeli }
2706cc1ade94SShani Michaeli 
qp_get_mtt_addr(struct mlx4_qp_context * qpc)27072b8fb286SMarcel Apfelbaum static int qp_get_mtt_addr(struct mlx4_qp_context *qpc)
2708c82e9aa0SEli Cohen {
2709c82e9aa0SEli Cohen 	return be32_to_cpu(qpc->mtt_base_addr_l) & 0xfffffff8;
2710c82e9aa0SEli Cohen }
2711c82e9aa0SEli Cohen 
srq_get_mtt_addr(struct mlx4_srq_context * srqc)27122b8fb286SMarcel Apfelbaum static int srq_get_mtt_addr(struct mlx4_srq_context *srqc)
2713c82e9aa0SEli Cohen {
2714c82e9aa0SEli Cohen 	return be32_to_cpu(srqc->mtt_base_addr_l) & 0xfffffff8;
2715c82e9aa0SEli Cohen }
2716c82e9aa0SEli Cohen 
qp_get_mtt_size(struct mlx4_qp_context * qpc)2717c82e9aa0SEli Cohen static int qp_get_mtt_size(struct mlx4_qp_context *qpc)
2718c82e9aa0SEli Cohen {
2719c82e9aa0SEli Cohen 	int page_shift = (qpc->log_page_size & 0x3f) + 12;
2720c82e9aa0SEli Cohen 	int log_sq_size = (qpc->sq_size_stride >> 3) & 0xf;
2721c82e9aa0SEli Cohen 	int log_sq_sride = qpc->sq_size_stride & 7;
2722c82e9aa0SEli Cohen 	int log_rq_size = (qpc->rq_size_stride >> 3) & 0xf;
2723c82e9aa0SEli Cohen 	int log_rq_stride = qpc->rq_size_stride & 7;
2724c82e9aa0SEli Cohen 	int srq = (be32_to_cpu(qpc->srqn) >> 24) & 1;
2725c82e9aa0SEli Cohen 	int rss = (be32_to_cpu(qpc->flags) >> 13) & 1;
27265c5f3f0aSYishai Hadas 	u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
27275c5f3f0aSYishai Hadas 	int xrc = (ts == MLX4_QP_ST_XRC) ? 1 : 0;
2728c82e9aa0SEli Cohen 	int sq_size;
2729c82e9aa0SEli Cohen 	int rq_size;
2730c82e9aa0SEli Cohen 	int total_pages;
2731c82e9aa0SEli Cohen 	int total_mem;
2732c82e9aa0SEli Cohen 	int page_offset = (be32_to_cpu(qpc->params2) >> 6) & 0x3f;
27338511a653SJack Morgenstein 	int tot;
2734c82e9aa0SEli Cohen 
2735c82e9aa0SEli Cohen 	sq_size = 1 << (log_sq_size + log_sq_sride + 4);
2736c82e9aa0SEli Cohen 	rq_size = (srq|rss|xrc) ? 0 : (1 << (log_rq_size + log_rq_stride + 4));
2737c82e9aa0SEli Cohen 	total_mem = sq_size + rq_size;
27388511a653SJack Morgenstein 	tot = (total_mem + (page_offset << 6)) >> page_shift;
27398511a653SJack Morgenstein 	total_pages = !tot ? 1 : roundup_pow_of_two(tot);
2740c82e9aa0SEli Cohen 
2741c82e9aa0SEli Cohen 	return total_pages;
2742c82e9aa0SEli Cohen }
2743c82e9aa0SEli Cohen 
check_mtt_range(struct mlx4_dev * dev,int slave,int start,int size,struct res_mtt * mtt)2744c82e9aa0SEli Cohen static int check_mtt_range(struct mlx4_dev *dev, int slave, int start,
2745c82e9aa0SEli Cohen 			   int size, struct res_mtt *mtt)
2746c82e9aa0SEli Cohen {
27472b8fb286SMarcel Apfelbaum 	int res_start = mtt->com.res_id;
27482b8fb286SMarcel Apfelbaum 	int res_size = (1 << mtt->order);
2749c82e9aa0SEli Cohen 
2750c82e9aa0SEli Cohen 	if (start < res_start || start + size > res_start + res_size)
2751c82e9aa0SEli Cohen 		return -EPERM;
2752c82e9aa0SEli Cohen 	return 0;
2753c82e9aa0SEli Cohen }
2754c82e9aa0SEli Cohen 
mlx4_SW2HW_MPT_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)2755c82e9aa0SEli Cohen int mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave,
2756c82e9aa0SEli Cohen 			   struct mlx4_vhcr *vhcr,
2757c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *inbox,
2758c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *outbox,
2759c82e9aa0SEli Cohen 			   struct mlx4_cmd_info *cmd)
2760c82e9aa0SEli Cohen {
2761c82e9aa0SEli Cohen 	int err;
2762c82e9aa0SEli Cohen 	int index = vhcr->in_modifier;
2763c82e9aa0SEli Cohen 	struct res_mtt *mtt;
27648dc7d11fSGreg Thelen 	struct res_mpt *mpt = NULL;
27652b8fb286SMarcel Apfelbaum 	int mtt_base = mr_get_mtt_addr(inbox->buf) / dev->caps.mtt_entry_sz;
2766c82e9aa0SEli Cohen 	int phys;
2767c82e9aa0SEli Cohen 	int id;
2768cc1ade94SShani Michaeli 	u32 pd;
2769cc1ade94SShani Michaeli 	int pd_slave;
2770c82e9aa0SEli Cohen 
2771c82e9aa0SEli Cohen 	id = index & mpt_mask(dev);
2772c82e9aa0SEli Cohen 	err = mr_res_start_move_to(dev, slave, id, RES_MPT_HW, &mpt);
2773c82e9aa0SEli Cohen 	if (err)
2774c82e9aa0SEli Cohen 		return err;
2775c82e9aa0SEli Cohen 
2776cc1ade94SShani Michaeli 	/* Disable memory windows for VFs. */
2777cc1ade94SShani Michaeli 	if (!mr_is_region(inbox->buf)) {
2778cc1ade94SShani Michaeli 		err = -EPERM;
2779cc1ade94SShani Michaeli 		goto ex_abort;
2780cc1ade94SShani Michaeli 	}
2781cc1ade94SShani Michaeli 
2782cc1ade94SShani Michaeli 	/* Make sure that the PD bits related to the slave id are zeros. */
2783cc1ade94SShani Michaeli 	pd = mr_get_pd(inbox->buf);
2784cc1ade94SShani Michaeli 	pd_slave = (pd >> 17) & 0x7f;
2785b332068cSMaor Gottlieb 	if (pd_slave != 0 && --pd_slave != slave) {
2786cc1ade94SShani Michaeli 		err = -EPERM;
2787cc1ade94SShani Michaeli 		goto ex_abort;
2788cc1ade94SShani Michaeli 	}
2789cc1ade94SShani Michaeli 
2790cc1ade94SShani Michaeli 	if (mr_is_fmr(inbox->buf)) {
2791cc1ade94SShani Michaeli 		/* FMR and Bind Enable are forbidden in slave devices. */
2792cc1ade94SShani Michaeli 		if (mr_is_bind_enabled(inbox->buf)) {
2793cc1ade94SShani Michaeli 			err = -EPERM;
2794cc1ade94SShani Michaeli 			goto ex_abort;
2795cc1ade94SShani Michaeli 		}
2796cc1ade94SShani Michaeli 		/* FMR and Memory Windows are also forbidden. */
2797cc1ade94SShani Michaeli 		if (!mr_is_region(inbox->buf)) {
2798cc1ade94SShani Michaeli 			err = -EPERM;
2799cc1ade94SShani Michaeli 			goto ex_abort;
2800cc1ade94SShani Michaeli 		}
2801cc1ade94SShani Michaeli 	}
2802cc1ade94SShani Michaeli 
2803c82e9aa0SEli Cohen 	phys = mr_phys_mpt(inbox->buf);
2804c82e9aa0SEli Cohen 	if (!phys) {
28052b8fb286SMarcel Apfelbaum 		err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);
2806c82e9aa0SEli Cohen 		if (err)
2807c82e9aa0SEli Cohen 			goto ex_abort;
2808c82e9aa0SEli Cohen 
2809c82e9aa0SEli Cohen 		err = check_mtt_range(dev, slave, mtt_base,
2810c82e9aa0SEli Cohen 				      mr_get_mtt_size(inbox->buf), mtt);
2811c82e9aa0SEli Cohen 		if (err)
2812c82e9aa0SEli Cohen 			goto ex_put;
2813c82e9aa0SEli Cohen 
2814c82e9aa0SEli Cohen 		mpt->mtt = mtt;
2815c82e9aa0SEli Cohen 	}
2816c82e9aa0SEli Cohen 
2817c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
2818c82e9aa0SEli Cohen 	if (err)
2819c82e9aa0SEli Cohen 		goto ex_put;
2820c82e9aa0SEli Cohen 
2821c82e9aa0SEli Cohen 	if (!phys) {
2822c82e9aa0SEli Cohen 		atomic_inc(&mtt->ref_count);
2823c82e9aa0SEli Cohen 		put_res(dev, slave, mtt->com.res_id, RES_MTT);
2824c82e9aa0SEli Cohen 	}
2825c82e9aa0SEli Cohen 
2826c82e9aa0SEli Cohen 	res_end_move(dev, slave, RES_MPT, id);
2827c82e9aa0SEli Cohen 	return 0;
2828c82e9aa0SEli Cohen 
2829c82e9aa0SEli Cohen ex_put:
2830c82e9aa0SEli Cohen 	if (!phys)
2831c82e9aa0SEli Cohen 		put_res(dev, slave, mtt->com.res_id, RES_MTT);
2832c82e9aa0SEli Cohen ex_abort:
2833c82e9aa0SEli Cohen 	res_abort_move(dev, slave, RES_MPT, id);
2834c82e9aa0SEli Cohen 
2835c82e9aa0SEli Cohen 	return err;
2836c82e9aa0SEli Cohen }
2837c82e9aa0SEli Cohen 
mlx4_HW2SW_MPT_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)2838c82e9aa0SEli Cohen int mlx4_HW2SW_MPT_wrapper(struct mlx4_dev *dev, int slave,
2839c82e9aa0SEli Cohen 			   struct mlx4_vhcr *vhcr,
2840c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *inbox,
2841c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *outbox,
2842c82e9aa0SEli Cohen 			   struct mlx4_cmd_info *cmd)
2843c82e9aa0SEli Cohen {
2844c82e9aa0SEli Cohen 	int err;
2845c82e9aa0SEli Cohen 	int index = vhcr->in_modifier;
2846c82e9aa0SEli Cohen 	struct res_mpt *mpt;
2847c82e9aa0SEli Cohen 	int id;
2848c82e9aa0SEli Cohen 
2849c82e9aa0SEli Cohen 	id = index & mpt_mask(dev);
2850c82e9aa0SEli Cohen 	err = mr_res_start_move_to(dev, slave, id, RES_MPT_MAPPED, &mpt);
2851c82e9aa0SEli Cohen 	if (err)
2852c82e9aa0SEli Cohen 		return err;
2853c82e9aa0SEli Cohen 
2854c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
2855c82e9aa0SEli Cohen 	if (err)
2856c82e9aa0SEli Cohen 		goto ex_abort;
2857c82e9aa0SEli Cohen 
2858c82e9aa0SEli Cohen 	if (mpt->mtt)
2859c82e9aa0SEli Cohen 		atomic_dec(&mpt->mtt->ref_count);
2860c82e9aa0SEli Cohen 
2861c82e9aa0SEli Cohen 	res_end_move(dev, slave, RES_MPT, id);
2862c82e9aa0SEli Cohen 	return 0;
2863c82e9aa0SEli Cohen 
2864c82e9aa0SEli Cohen ex_abort:
2865c82e9aa0SEli Cohen 	res_abort_move(dev, slave, RES_MPT, id);
2866c82e9aa0SEli Cohen 
2867c82e9aa0SEli Cohen 	return err;
2868c82e9aa0SEli Cohen }
2869c82e9aa0SEli Cohen 
mlx4_QUERY_MPT_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)2870c82e9aa0SEli Cohen int mlx4_QUERY_MPT_wrapper(struct mlx4_dev *dev, int slave,
2871c82e9aa0SEli Cohen 			   struct mlx4_vhcr *vhcr,
2872c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *inbox,
2873c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *outbox,
2874c82e9aa0SEli Cohen 			   struct mlx4_cmd_info *cmd)
2875c82e9aa0SEli Cohen {
2876c82e9aa0SEli Cohen 	int err;
2877c82e9aa0SEli Cohen 	int index = vhcr->in_modifier;
2878c82e9aa0SEli Cohen 	struct res_mpt *mpt;
2879c82e9aa0SEli Cohen 	int id;
2880c82e9aa0SEli Cohen 
2881c82e9aa0SEli Cohen 	id = index & mpt_mask(dev);
2882c82e9aa0SEli Cohen 	err = get_res(dev, slave, id, RES_MPT, &mpt);
2883c82e9aa0SEli Cohen 	if (err)
2884c82e9aa0SEli Cohen 		return err;
2885c82e9aa0SEli Cohen 
2886e630664cSMatan Barak 	if (mpt->com.from_state == RES_MPT_MAPPED) {
2887e630664cSMatan Barak 		/* In order to allow rereg in SRIOV, we need to alter the MPT entry. To do
2888e630664cSMatan Barak 		 * that, the VF must read the MPT. But since the MPT entry memory is not
2889e630664cSMatan Barak 		 * in the VF's virtual memory space, it must use QUERY_MPT to obtain the
2890e630664cSMatan Barak 		 * entry contents. To guarantee that the MPT cannot be changed, the driver
2891e630664cSMatan Barak 		 * must perform HW2SW_MPT before this query and return the MPT entry to HW
2892e630664cSMatan Barak 		 * ownership fofollowing the change. The change here allows the VF to
2893e630664cSMatan Barak 		 * perform QUERY_MPT also when the entry is in SW ownership.
2894e630664cSMatan Barak 		 */
2895e630664cSMatan Barak 		struct mlx4_mpt_entry *mpt_entry = mlx4_table_find(
2896e630664cSMatan Barak 					&mlx4_priv(dev)->mr_table.dmpt_table,
2897e630664cSMatan Barak 					mpt->key, NULL);
2898e630664cSMatan Barak 
2899e630664cSMatan Barak 		if (NULL == mpt_entry || NULL == outbox->buf) {
2900e630664cSMatan Barak 			err = -EINVAL;
2901e630664cSMatan Barak 			goto out;
2902e630664cSMatan Barak 		}
2903e630664cSMatan Barak 
2904e630664cSMatan Barak 		memcpy(outbox->buf, mpt_entry, sizeof(*mpt_entry));
2905e630664cSMatan Barak 
2906e630664cSMatan Barak 		err = 0;
2907e630664cSMatan Barak 	} else if (mpt->com.from_state == RES_MPT_HW) {
2908e630664cSMatan Barak 		err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
2909e630664cSMatan Barak 	} else {
2910c82e9aa0SEli Cohen 		err = -EBUSY;
2911c82e9aa0SEli Cohen 		goto out;
2912c82e9aa0SEli Cohen 	}
2913c82e9aa0SEli Cohen 
2914c82e9aa0SEli Cohen 
2915c82e9aa0SEli Cohen out:
2916c82e9aa0SEli Cohen 	put_res(dev, slave, id, RES_MPT);
2917c82e9aa0SEli Cohen 	return err;
2918c82e9aa0SEli Cohen }
2919c82e9aa0SEli Cohen 
qp_get_rcqn(struct mlx4_qp_context * qpc)2920c82e9aa0SEli Cohen static int qp_get_rcqn(struct mlx4_qp_context *qpc)
2921c82e9aa0SEli Cohen {
2922c82e9aa0SEli Cohen 	return be32_to_cpu(qpc->cqn_recv) & 0xffffff;
2923c82e9aa0SEli Cohen }
2924c82e9aa0SEli Cohen 
qp_get_scqn(struct mlx4_qp_context * qpc)2925c82e9aa0SEli Cohen static int qp_get_scqn(struct mlx4_qp_context *qpc)
2926c82e9aa0SEli Cohen {
2927c82e9aa0SEli Cohen 	return be32_to_cpu(qpc->cqn_send) & 0xffffff;
2928c82e9aa0SEli Cohen }
2929c82e9aa0SEli Cohen 
qp_get_srqn(struct mlx4_qp_context * qpc)2930c82e9aa0SEli Cohen static u32 qp_get_srqn(struct mlx4_qp_context *qpc)
2931c82e9aa0SEli Cohen {
2932c82e9aa0SEli Cohen 	return be32_to_cpu(qpc->srqn) & 0x1ffffff;
2933c82e9aa0SEli Cohen }
2934c82e9aa0SEli Cohen 
adjust_proxy_tun_qkey(struct mlx4_dev * dev,struct mlx4_vhcr * vhcr,struct mlx4_qp_context * context)293554679e14SJack Morgenstein static void adjust_proxy_tun_qkey(struct mlx4_dev *dev, struct mlx4_vhcr *vhcr,
293654679e14SJack Morgenstein 				  struct mlx4_qp_context *context)
293754679e14SJack Morgenstein {
293854679e14SJack Morgenstein 	u32 qpn = vhcr->in_modifier & 0xffffff;
293954679e14SJack Morgenstein 	u32 qkey = 0;
294054679e14SJack Morgenstein 
294154679e14SJack Morgenstein 	if (mlx4_get_parav_qkey(dev, qpn, &qkey))
294254679e14SJack Morgenstein 		return;
294354679e14SJack Morgenstein 
294454679e14SJack Morgenstein 	/* adjust qkey in qp context */
294554679e14SJack Morgenstein 	context->qkey = cpu_to_be32(qkey);
294654679e14SJack Morgenstein }
294754679e14SJack Morgenstein 
2948e5dfbf9aSOr Gerlitz static int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave,
2949e5dfbf9aSOr Gerlitz 				 struct mlx4_qp_context *qpc,
2950e5dfbf9aSOr Gerlitz 				 struct mlx4_cmd_mailbox *inbox);
2951e5dfbf9aSOr Gerlitz 
mlx4_RST2INIT_QP_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)2952c82e9aa0SEli Cohen int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,
2953c82e9aa0SEli Cohen 			     struct mlx4_vhcr *vhcr,
2954c82e9aa0SEli Cohen 			     struct mlx4_cmd_mailbox *inbox,
2955c82e9aa0SEli Cohen 			     struct mlx4_cmd_mailbox *outbox,
2956c82e9aa0SEli Cohen 			     struct mlx4_cmd_info *cmd)
2957c82e9aa0SEli Cohen {
2958c82e9aa0SEli Cohen 	int err;
2959c82e9aa0SEli Cohen 	int qpn = vhcr->in_modifier & 0x7fffff;
2960c82e9aa0SEli Cohen 	struct res_mtt *mtt;
2961c82e9aa0SEli Cohen 	struct res_qp *qp;
2962c82e9aa0SEli Cohen 	struct mlx4_qp_context *qpc = inbox->buf + 8;
29632b8fb286SMarcel Apfelbaum 	int mtt_base = qp_get_mtt_addr(qpc) / dev->caps.mtt_entry_sz;
2964c82e9aa0SEli Cohen 	int mtt_size = qp_get_mtt_size(qpc);
2965c82e9aa0SEli Cohen 	struct res_cq *rcq;
2966c82e9aa0SEli Cohen 	struct res_cq *scq;
2967c82e9aa0SEli Cohen 	int rcqn = qp_get_rcqn(qpc);
2968c82e9aa0SEli Cohen 	int scqn = qp_get_scqn(qpc);
2969c82e9aa0SEli Cohen 	u32 srqn = qp_get_srqn(qpc) & 0xffffff;
2970c82e9aa0SEli Cohen 	int use_srq = (qp_get_srqn(qpc) >> 24) & 1;
2971c82e9aa0SEli Cohen 	struct res_srq *srq;
2972958c696fSJack Morgenstein 	int local_qpn = vhcr->in_modifier & 0xffffff;
2973c82e9aa0SEli Cohen 
2974e5dfbf9aSOr Gerlitz 	err = adjust_qp_sched_queue(dev, slave, qpc, inbox);
2975e5dfbf9aSOr Gerlitz 	if (err)
2976e5dfbf9aSOr Gerlitz 		return err;
2977e5dfbf9aSOr Gerlitz 
2978c82e9aa0SEli Cohen 	err = qp_res_start_move_to(dev, slave, qpn, RES_QP_HW, &qp, 0);
2979c82e9aa0SEli Cohen 	if (err)
2980c82e9aa0SEli Cohen 		return err;
2981c82e9aa0SEli Cohen 	qp->local_qpn = local_qpn;
2982b01978caSJack Morgenstein 	qp->sched_queue = 0;
2983f0f829bfSRony Efraim 	qp->param3 = 0;
2984f0f829bfSRony Efraim 	qp->vlan_control = 0;
2985f0f829bfSRony Efraim 	qp->fvl_rx = 0;
2986f0f829bfSRony Efraim 	qp->pri_path_fl = 0;
2987f0f829bfSRony Efraim 	qp->vlan_index = 0;
2988f0f829bfSRony Efraim 	qp->feup = 0;
2989b01978caSJack Morgenstein 	qp->qpc_flags = be32_to_cpu(qpc->flags);
2990c82e9aa0SEli Cohen 
29912b8fb286SMarcel Apfelbaum 	err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);
2992c82e9aa0SEli Cohen 	if (err)
2993c82e9aa0SEli Cohen 		goto ex_abort;
2994c82e9aa0SEli Cohen 
2995c82e9aa0SEli Cohen 	err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt);
2996c82e9aa0SEli Cohen 	if (err)
2997c82e9aa0SEli Cohen 		goto ex_put_mtt;
2998c82e9aa0SEli Cohen 
2999c82e9aa0SEli Cohen 	err = get_res(dev, slave, rcqn, RES_CQ, &rcq);
3000c82e9aa0SEli Cohen 	if (err)
3001c82e9aa0SEli Cohen 		goto ex_put_mtt;
3002c82e9aa0SEli Cohen 
3003c82e9aa0SEli Cohen 	if (scqn != rcqn) {
3004c82e9aa0SEli Cohen 		err = get_res(dev, slave, scqn, RES_CQ, &scq);
3005c82e9aa0SEli Cohen 		if (err)
3006c82e9aa0SEli Cohen 			goto ex_put_rcq;
3007c82e9aa0SEli Cohen 	} else
3008c82e9aa0SEli Cohen 		scq = rcq;
3009c82e9aa0SEli Cohen 
3010c82e9aa0SEli Cohen 	if (use_srq) {
3011c82e9aa0SEli Cohen 		err = get_res(dev, slave, srqn, RES_SRQ, &srq);
3012c82e9aa0SEli Cohen 		if (err)
3013c82e9aa0SEli Cohen 			goto ex_put_scq;
3014c82e9aa0SEli Cohen 	}
3015c82e9aa0SEli Cohen 
301654679e14SJack Morgenstein 	adjust_proxy_tun_qkey(dev, vhcr, qpc);
301754679e14SJack Morgenstein 	update_pkey_index(dev, slave, inbox);
3018c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3019c82e9aa0SEli Cohen 	if (err)
3020c82e9aa0SEli Cohen 		goto ex_put_srq;
3021c82e9aa0SEli Cohen 	atomic_inc(&mtt->ref_count);
3022c82e9aa0SEli Cohen 	qp->mtt = mtt;
3023c82e9aa0SEli Cohen 	atomic_inc(&rcq->ref_count);
3024c82e9aa0SEli Cohen 	qp->rcq = rcq;
3025c82e9aa0SEli Cohen 	atomic_inc(&scq->ref_count);
3026c82e9aa0SEli Cohen 	qp->scq = scq;
3027c82e9aa0SEli Cohen 
3028c82e9aa0SEli Cohen 	if (scqn != rcqn)
3029c82e9aa0SEli Cohen 		put_res(dev, slave, scqn, RES_CQ);
3030c82e9aa0SEli Cohen 
3031c82e9aa0SEli Cohen 	if (use_srq) {
3032c82e9aa0SEli Cohen 		atomic_inc(&srq->ref_count);
3033c82e9aa0SEli Cohen 		put_res(dev, slave, srqn, RES_SRQ);
3034c82e9aa0SEli Cohen 		qp->srq = srq;
3035c82e9aa0SEli Cohen 	}
30367c3945bcSJack Morgenstein 
30377c3945bcSJack Morgenstein 	/* Save param3 for dynamic changes from VST back to VGT */
30387c3945bcSJack Morgenstein 	qp->param3 = qpc->param3;
3039c82e9aa0SEli Cohen 	put_res(dev, slave, rcqn, RES_CQ);
30402b8fb286SMarcel Apfelbaum 	put_res(dev, slave, mtt_base, RES_MTT);
3041c82e9aa0SEli Cohen 	res_end_move(dev, slave, RES_QP, qpn);
3042c82e9aa0SEli Cohen 
3043c82e9aa0SEli Cohen 	return 0;
3044c82e9aa0SEli Cohen 
3045c82e9aa0SEli Cohen ex_put_srq:
3046c82e9aa0SEli Cohen 	if (use_srq)
3047c82e9aa0SEli Cohen 		put_res(dev, slave, srqn, RES_SRQ);
3048c82e9aa0SEli Cohen ex_put_scq:
3049c82e9aa0SEli Cohen 	if (scqn != rcqn)
3050c82e9aa0SEli Cohen 		put_res(dev, slave, scqn, RES_CQ);
3051c82e9aa0SEli Cohen ex_put_rcq:
3052c82e9aa0SEli Cohen 	put_res(dev, slave, rcqn, RES_CQ);
3053c82e9aa0SEli Cohen ex_put_mtt:
30542b8fb286SMarcel Apfelbaum 	put_res(dev, slave, mtt_base, RES_MTT);
3055c82e9aa0SEli Cohen ex_abort:
3056c82e9aa0SEli Cohen 	res_abort_move(dev, slave, RES_QP, qpn);
3057c82e9aa0SEli Cohen 
3058c82e9aa0SEli Cohen 	return err;
3059c82e9aa0SEli Cohen }
3060c82e9aa0SEli Cohen 
eq_get_mtt_addr(struct mlx4_eq_context * eqc)30612b8fb286SMarcel Apfelbaum static int eq_get_mtt_addr(struct mlx4_eq_context *eqc)
3062c82e9aa0SEli Cohen {
3063c82e9aa0SEli Cohen 	return be32_to_cpu(eqc->mtt_base_addr_l) & 0xfffffff8;
3064c82e9aa0SEli Cohen }
3065c82e9aa0SEli Cohen 
eq_get_mtt_size(struct mlx4_eq_context * eqc)3066c82e9aa0SEli Cohen static int eq_get_mtt_size(struct mlx4_eq_context *eqc)
3067c82e9aa0SEli Cohen {
3068c82e9aa0SEli Cohen 	int log_eq_size = eqc->log_eq_size & 0x1f;
3069c82e9aa0SEli Cohen 	int page_shift = (eqc->log_page_size & 0x3f) + 12;
3070c82e9aa0SEli Cohen 
3071c82e9aa0SEli Cohen 	if (log_eq_size + 5 < page_shift)
3072c82e9aa0SEli Cohen 		return 1;
3073c82e9aa0SEli Cohen 
3074c82e9aa0SEli Cohen 	return 1 << (log_eq_size + 5 - page_shift);
3075c82e9aa0SEli Cohen }
3076c82e9aa0SEli Cohen 
cq_get_mtt_addr(struct mlx4_cq_context * cqc)30772b8fb286SMarcel Apfelbaum static int cq_get_mtt_addr(struct mlx4_cq_context *cqc)
3078c82e9aa0SEli Cohen {
3079c82e9aa0SEli Cohen 	return be32_to_cpu(cqc->mtt_base_addr_l) & 0xfffffff8;
3080c82e9aa0SEli Cohen }
3081c82e9aa0SEli Cohen 
cq_get_mtt_size(struct mlx4_cq_context * cqc)3082c82e9aa0SEli Cohen static int cq_get_mtt_size(struct mlx4_cq_context *cqc)
3083c82e9aa0SEli Cohen {
3084c82e9aa0SEli Cohen 	int log_cq_size = (be32_to_cpu(cqc->logsize_usrpage) >> 24) & 0x1f;
3085c82e9aa0SEli Cohen 	int page_shift = (cqc->log_page_size & 0x3f) + 12;
3086c82e9aa0SEli Cohen 
3087c82e9aa0SEli Cohen 	if (log_cq_size + 5 < page_shift)
3088c82e9aa0SEli Cohen 		return 1;
3089c82e9aa0SEli Cohen 
3090c82e9aa0SEli Cohen 	return 1 << (log_cq_size + 5 - page_shift);
3091c82e9aa0SEli Cohen }
3092c82e9aa0SEli Cohen 
mlx4_SW2HW_EQ_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3093c82e9aa0SEli Cohen int mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave,
3094c82e9aa0SEli Cohen 			  struct mlx4_vhcr *vhcr,
3095c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *inbox,
3096c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *outbox,
3097c82e9aa0SEli Cohen 			  struct mlx4_cmd_info *cmd)
3098c82e9aa0SEli Cohen {
3099c82e9aa0SEli Cohen 	int err;
3100c82e9aa0SEli Cohen 	int eqn = vhcr->in_modifier;
31012d3c7397SYishai Hadas 	int res_id = (slave << 10) | eqn;
3102c82e9aa0SEli Cohen 	struct mlx4_eq_context *eqc = inbox->buf;
31032b8fb286SMarcel Apfelbaum 	int mtt_base = eq_get_mtt_addr(eqc) / dev->caps.mtt_entry_sz;
3104c82e9aa0SEli Cohen 	int mtt_size = eq_get_mtt_size(eqc);
3105c82e9aa0SEli Cohen 	struct res_eq *eq;
3106c82e9aa0SEli Cohen 	struct res_mtt *mtt;
3107c82e9aa0SEli Cohen 
3108c82e9aa0SEli Cohen 	err = add_res_range(dev, slave, res_id, 1, RES_EQ, 0);
3109c82e9aa0SEli Cohen 	if (err)
3110c82e9aa0SEli Cohen 		return err;
3111c82e9aa0SEli Cohen 	err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_HW, &eq);
3112c82e9aa0SEli Cohen 	if (err)
3113c82e9aa0SEli Cohen 		goto out_add;
3114c82e9aa0SEli Cohen 
31152b8fb286SMarcel Apfelbaum 	err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);
3116c82e9aa0SEli Cohen 	if (err)
3117c82e9aa0SEli Cohen 		goto out_move;
3118c82e9aa0SEli Cohen 
3119c82e9aa0SEli Cohen 	err = check_mtt_range(dev, slave, mtt_base, mtt_size, mtt);
3120c82e9aa0SEli Cohen 	if (err)
3121c82e9aa0SEli Cohen 		goto out_put;
3122c82e9aa0SEli Cohen 
3123c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3124c82e9aa0SEli Cohen 	if (err)
3125c82e9aa0SEli Cohen 		goto out_put;
3126c82e9aa0SEli Cohen 
3127c82e9aa0SEli Cohen 	atomic_inc(&mtt->ref_count);
3128c82e9aa0SEli Cohen 	eq->mtt = mtt;
3129c82e9aa0SEli Cohen 	put_res(dev, slave, mtt->com.res_id, RES_MTT);
3130c82e9aa0SEli Cohen 	res_end_move(dev, slave, RES_EQ, res_id);
3131c82e9aa0SEli Cohen 	return 0;
3132c82e9aa0SEli Cohen 
3133c82e9aa0SEli Cohen out_put:
3134c82e9aa0SEli Cohen 	put_res(dev, slave, mtt->com.res_id, RES_MTT);
3135c82e9aa0SEli Cohen out_move:
3136c82e9aa0SEli Cohen 	res_abort_move(dev, slave, RES_EQ, res_id);
3137c82e9aa0SEli Cohen out_add:
3138c82e9aa0SEli Cohen 	rem_res_range(dev, slave, res_id, 1, RES_EQ, 0);
3139c82e9aa0SEli Cohen 	return err;
3140c82e9aa0SEli Cohen }
3141c82e9aa0SEli Cohen 
mlx4_CONFIG_DEV_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3142d475c95bSMatan Barak int mlx4_CONFIG_DEV_wrapper(struct mlx4_dev *dev, int slave,
3143d475c95bSMatan Barak 			    struct mlx4_vhcr *vhcr,
3144d475c95bSMatan Barak 			    struct mlx4_cmd_mailbox *inbox,
3145d475c95bSMatan Barak 			    struct mlx4_cmd_mailbox *outbox,
3146d475c95bSMatan Barak 			    struct mlx4_cmd_info *cmd)
3147d475c95bSMatan Barak {
3148d475c95bSMatan Barak 	int err;
3149d475c95bSMatan Barak 	u8 get = vhcr->op_modifier;
3150d475c95bSMatan Barak 
3151d475c95bSMatan Barak 	if (get != 1)
3152d475c95bSMatan Barak 		return -EPERM;
3153d475c95bSMatan Barak 
3154d475c95bSMatan Barak 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3155d475c95bSMatan Barak 
3156d475c95bSMatan Barak 	return err;
3157d475c95bSMatan Barak }
3158d475c95bSMatan Barak 
get_containing_mtt(struct mlx4_dev * dev,int slave,int start,int len,struct res_mtt ** res)3159c82e9aa0SEli Cohen static int get_containing_mtt(struct mlx4_dev *dev, int slave, int start,
3160c82e9aa0SEli Cohen 			      int len, struct res_mtt **res)
3161c82e9aa0SEli Cohen {
3162c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
3163c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
3164c82e9aa0SEli Cohen 	struct res_mtt *mtt;
3165c82e9aa0SEli Cohen 	int err = -EINVAL;
3166c82e9aa0SEli Cohen 
3167c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
3168c82e9aa0SEli Cohen 	list_for_each_entry(mtt, &tracker->slave_list[slave].res_list[RES_MTT],
3169c82e9aa0SEli Cohen 			    com.list) {
3170c82e9aa0SEli Cohen 		if (!check_mtt_range(dev, slave, start, len, mtt)) {
3171c82e9aa0SEli Cohen 			*res = mtt;
3172c82e9aa0SEli Cohen 			mtt->com.from_state = mtt->com.state;
3173c82e9aa0SEli Cohen 			mtt->com.state = RES_MTT_BUSY;
3174c82e9aa0SEli Cohen 			err = 0;
3175c82e9aa0SEli Cohen 			break;
3176c82e9aa0SEli Cohen 		}
3177c82e9aa0SEli Cohen 	}
3178c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
3179c82e9aa0SEli Cohen 
3180c82e9aa0SEli Cohen 	return err;
3181c82e9aa0SEli Cohen }
3182c82e9aa0SEli Cohen 
verify_qp_parameters(struct mlx4_dev * dev,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,enum qp_transition transition,u8 slave)318354679e14SJack Morgenstein static int verify_qp_parameters(struct mlx4_dev *dev,
318499ec41d0SJack Morgenstein 				struct mlx4_vhcr *vhcr,
318554679e14SJack Morgenstein 				struct mlx4_cmd_mailbox *inbox,
318654679e14SJack Morgenstein 				enum qp_transition transition, u8 slave)
318754679e14SJack Morgenstein {
318854679e14SJack Morgenstein 	u32			qp_type;
318999ec41d0SJack Morgenstein 	u32			qpn;
319054679e14SJack Morgenstein 	struct mlx4_qp_context	*qp_ctx;
319154679e14SJack Morgenstein 	enum mlx4_qp_optpar	optpar;
3192b6ffaeffSJack Morgenstein 	int port;
3193b6ffaeffSJack Morgenstein 	int num_gids;
319454679e14SJack Morgenstein 
319554679e14SJack Morgenstein 	qp_ctx  = inbox->buf + 8;
319654679e14SJack Morgenstein 	qp_type	= (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;
319754679e14SJack Morgenstein 	optpar	= be32_to_cpu(*(__be32 *) inbox->buf);
319854679e14SJack Morgenstein 
3199fc31e256SOr Gerlitz 	if (slave != mlx4_master_func_num(dev)) {
3200bb428a5cSTariq Toukan 		qp_ctx->params2 &= ~cpu_to_be32(MLX4_QP_BIT_FPP);
3201fc31e256SOr Gerlitz 		/* setting QP rate-limit is disallowed for VFs */
3202fc31e256SOr Gerlitz 		if (qp_ctx->rate_limit_params)
3203fc31e256SOr Gerlitz 			return -EPERM;
3204fc31e256SOr Gerlitz 	}
320553f33ae2SMoni Shoua 
320654679e14SJack Morgenstein 	switch (qp_type) {
320754679e14SJack Morgenstein 	case MLX4_QP_ST_RC:
3208b6ffaeffSJack Morgenstein 	case MLX4_QP_ST_XRC:
320954679e14SJack Morgenstein 	case MLX4_QP_ST_UC:
321054679e14SJack Morgenstein 		switch (transition) {
321154679e14SJack Morgenstein 		case QP_TRANS_INIT2RTR:
321254679e14SJack Morgenstein 		case QP_TRANS_RTR2RTS:
321354679e14SJack Morgenstein 		case QP_TRANS_RTS2RTS:
321454679e14SJack Morgenstein 		case QP_TRANS_SQD2SQD:
321554679e14SJack Morgenstein 		case QP_TRANS_SQD2RTS:
3216baefd701SArnd Bergmann 			if (slave != mlx4_master_func_num(dev)) {
3217b6ffaeffSJack Morgenstein 				if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {
3218b6ffaeffSJack Morgenstein 					port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
3219b6ffaeffSJack Morgenstein 					if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)
3220449fc488SMatan Barak 						num_gids = mlx4_get_slave_num_gids(dev, slave, port);
3221b6ffaeffSJack Morgenstein 					else
3222b6ffaeffSJack Morgenstein 						num_gids = 1;
3223b6ffaeffSJack Morgenstein 					if (qp_ctx->pri_path.mgid_index >= num_gids)
322454679e14SJack Morgenstein 						return -EINVAL;
3225b6ffaeffSJack Morgenstein 				}
3226b6ffaeffSJack Morgenstein 				if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
3227b6ffaeffSJack Morgenstein 					port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1;
3228b6ffaeffSJack Morgenstein 					if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)
3229449fc488SMatan Barak 						num_gids = mlx4_get_slave_num_gids(dev, slave, port);
3230b6ffaeffSJack Morgenstein 					else
3231b6ffaeffSJack Morgenstein 						num_gids = 1;
3232b6ffaeffSJack Morgenstein 					if (qp_ctx->alt_path.mgid_index >= num_gids)
323354679e14SJack Morgenstein 						return -EINVAL;
3234b6ffaeffSJack Morgenstein 				}
3235baefd701SArnd Bergmann 			}
323654679e14SJack Morgenstein 			break;
323754679e14SJack Morgenstein 		default:
323854679e14SJack Morgenstein 			break;
323954679e14SJack Morgenstein 		}
324054679e14SJack Morgenstein 		break;
3241165cb465SRoland Dreier 
324299ec41d0SJack Morgenstein 	case MLX4_QP_ST_MLX:
324399ec41d0SJack Morgenstein 		qpn = vhcr->in_modifier & 0x7fffff;
324499ec41d0SJack Morgenstein 		port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
324599ec41d0SJack Morgenstein 		if (transition == QP_TRANS_INIT2RTR &&
324699ec41d0SJack Morgenstein 		    slave != mlx4_master_func_num(dev) &&
324799ec41d0SJack Morgenstein 		    mlx4_is_qp_reserved(dev, qpn) &&
324899ec41d0SJack Morgenstein 		    !mlx4_vf_smi_enabled(dev, slave, port)) {
324999ec41d0SJack Morgenstein 			/* only enabled VFs may create MLX proxy QPs */
325099ec41d0SJack Morgenstein 			mlx4_err(dev, "%s: unprivileged slave %d attempting to create an MLX proxy special QP on port %d\n",
325199ec41d0SJack Morgenstein 				 __func__, slave, port);
325299ec41d0SJack Morgenstein 			return -EPERM;
325399ec41d0SJack Morgenstein 		}
325499ec41d0SJack Morgenstein 		break;
325599ec41d0SJack Morgenstein 
325654679e14SJack Morgenstein 	default:
325754679e14SJack Morgenstein 		break;
325854679e14SJack Morgenstein 	}
325954679e14SJack Morgenstein 
326054679e14SJack Morgenstein 	return 0;
326154679e14SJack Morgenstein }
326254679e14SJack Morgenstein 
mlx4_WRITE_MTT_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3263c82e9aa0SEli Cohen int mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave,
3264c82e9aa0SEli Cohen 			   struct mlx4_vhcr *vhcr,
3265c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *inbox,
3266c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *outbox,
3267c82e9aa0SEli Cohen 			   struct mlx4_cmd_info *cmd)
3268c82e9aa0SEli Cohen {
3269c82e9aa0SEli Cohen 	struct mlx4_mtt mtt;
3270c82e9aa0SEli Cohen 	__be64 *page_list = inbox->buf;
3271c82e9aa0SEli Cohen 	u64 *pg_list = (u64 *)page_list;
3272c82e9aa0SEli Cohen 	int i;
3273c82e9aa0SEli Cohen 	struct res_mtt *rmtt = NULL;
3274c82e9aa0SEli Cohen 	int start = be64_to_cpu(page_list[0]);
3275c82e9aa0SEli Cohen 	int npages = vhcr->in_modifier;
3276c82e9aa0SEli Cohen 	int err;
3277c82e9aa0SEli Cohen 
3278c82e9aa0SEli Cohen 	err = get_containing_mtt(dev, slave, start, npages, &rmtt);
3279c82e9aa0SEli Cohen 	if (err)
3280c82e9aa0SEli Cohen 		return err;
3281c82e9aa0SEli Cohen 
3282c82e9aa0SEli Cohen 	/* Call the SW implementation of write_mtt:
3283c82e9aa0SEli Cohen 	 * - Prepare a dummy mtt struct
3284dbedd44eSJoe Perches 	 * - Translate inbox contents to simple addresses in host endianness */
32852b8fb286SMarcel Apfelbaum 	mtt.offset = 0;  /* TBD this is broken but I don't handle it since
32862b8fb286SMarcel Apfelbaum 			    we don't really use it */
3287c82e9aa0SEli Cohen 	mtt.order = 0;
3288c82e9aa0SEli Cohen 	mtt.page_shift = 0;
3289c82e9aa0SEli Cohen 	for (i = 0; i < npages; ++i)
3290c82e9aa0SEli Cohen 		pg_list[i + 2] = (be64_to_cpu(page_list[i + 2]) & ~1ULL);
3291c82e9aa0SEli Cohen 
3292c82e9aa0SEli Cohen 	err = __mlx4_write_mtt(dev, &mtt, be64_to_cpu(page_list[0]), npages,
3293c82e9aa0SEli Cohen 			       ((u64 *)page_list + 2));
3294c82e9aa0SEli Cohen 
3295c82e9aa0SEli Cohen 	if (rmtt)
3296c82e9aa0SEli Cohen 		put_res(dev, slave, rmtt->com.res_id, RES_MTT);
3297c82e9aa0SEli Cohen 
3298c82e9aa0SEli Cohen 	return err;
3299c82e9aa0SEli Cohen }
3300c82e9aa0SEli Cohen 
mlx4_HW2SW_EQ_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3301c82e9aa0SEli Cohen int mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave,
3302c82e9aa0SEli Cohen 			  struct mlx4_vhcr *vhcr,
3303c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *inbox,
3304c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *outbox,
3305c82e9aa0SEli Cohen 			  struct mlx4_cmd_info *cmd)
3306c82e9aa0SEli Cohen {
3307c82e9aa0SEli Cohen 	int eqn = vhcr->in_modifier;
33082d3c7397SYishai Hadas 	int res_id = eqn | (slave << 10);
3309c82e9aa0SEli Cohen 	struct res_eq *eq;
3310c82e9aa0SEli Cohen 	int err;
3311c82e9aa0SEli Cohen 
3312c82e9aa0SEli Cohen 	err = eq_res_start_move_to(dev, slave, res_id, RES_EQ_RESERVED, &eq);
3313c82e9aa0SEli Cohen 	if (err)
3314c82e9aa0SEli Cohen 		return err;
3315c82e9aa0SEli Cohen 
3316c82e9aa0SEli Cohen 	err = get_res(dev, slave, eq->mtt->com.res_id, RES_MTT, NULL);
3317c82e9aa0SEli Cohen 	if (err)
3318c82e9aa0SEli Cohen 		goto ex_abort;
3319c82e9aa0SEli Cohen 
3320c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3321c82e9aa0SEli Cohen 	if (err)
3322c82e9aa0SEli Cohen 		goto ex_put;
3323c82e9aa0SEli Cohen 
3324c82e9aa0SEli Cohen 	atomic_dec(&eq->mtt->ref_count);
3325c82e9aa0SEli Cohen 	put_res(dev, slave, eq->mtt->com.res_id, RES_MTT);
3326c82e9aa0SEli Cohen 	res_end_move(dev, slave, RES_EQ, res_id);
3327c82e9aa0SEli Cohen 	rem_res_range(dev, slave, res_id, 1, RES_EQ, 0);
3328c82e9aa0SEli Cohen 
3329c82e9aa0SEli Cohen 	return 0;
3330c82e9aa0SEli Cohen 
3331c82e9aa0SEli Cohen ex_put:
3332c82e9aa0SEli Cohen 	put_res(dev, slave, eq->mtt->com.res_id, RES_MTT);
3333c82e9aa0SEli Cohen ex_abort:
3334c82e9aa0SEli Cohen 	res_abort_move(dev, slave, RES_EQ, res_id);
3335c82e9aa0SEli Cohen 
3336c82e9aa0SEli Cohen 	return err;
3337c82e9aa0SEli Cohen }
3338c82e9aa0SEli Cohen 
mlx4_GEN_EQE(struct mlx4_dev * dev,int slave,struct mlx4_eqe * eqe)3339c82e9aa0SEli Cohen int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe)
3340c82e9aa0SEli Cohen {
3341c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
3342c82e9aa0SEli Cohen 	struct mlx4_slave_event_eq_info *event_eq;
3343c82e9aa0SEli Cohen 	struct mlx4_cmd_mailbox *mailbox;
3344c82e9aa0SEli Cohen 	u32 in_modifier = 0;
3345c82e9aa0SEli Cohen 	int err;
3346c82e9aa0SEli Cohen 	int res_id;
3347c82e9aa0SEli Cohen 	struct res_eq *req;
3348c82e9aa0SEli Cohen 
3349c82e9aa0SEli Cohen 	if (!priv->mfunc.master.slave_state)
3350c82e9aa0SEli Cohen 		return -EINVAL;
3351c82e9aa0SEli Cohen 
3352bffb023aSJack Morgenstein 	/* check for slave valid, slave not PF, and slave active */
3353bffb023aSJack Morgenstein 	if (slave < 0 || slave > dev->persist->num_vfs ||
3354bffb023aSJack Morgenstein 	    slave == dev->caps.function ||
3355bffb023aSJack Morgenstein 	    !priv->mfunc.master.slave_state[slave].active)
3356bffb023aSJack Morgenstein 		return 0;
3357bffb023aSJack Morgenstein 
3358803143fbSMarcel Apfelbaum 	event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type];
3359c82e9aa0SEli Cohen 
3360c82e9aa0SEli Cohen 	/* Create the event only if the slave is registered */
3361803143fbSMarcel Apfelbaum 	if (event_eq->eqn < 0)
3362c82e9aa0SEli Cohen 		return 0;
3363c82e9aa0SEli Cohen 
3364c82e9aa0SEli Cohen 	mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]);
33652d3c7397SYishai Hadas 	res_id = (slave << 10) | event_eq->eqn;
3366c82e9aa0SEli Cohen 	err = get_res(dev, slave, res_id, RES_EQ, &req);
3367c82e9aa0SEli Cohen 	if (err)
3368c82e9aa0SEli Cohen 		goto unlock;
3369c82e9aa0SEli Cohen 
3370c82e9aa0SEli Cohen 	if (req->com.from_state != RES_EQ_HW) {
3371c82e9aa0SEli Cohen 		err = -EINVAL;
3372c82e9aa0SEli Cohen 		goto put;
3373c82e9aa0SEli Cohen 	}
3374c82e9aa0SEli Cohen 
3375c82e9aa0SEli Cohen 	mailbox = mlx4_alloc_cmd_mailbox(dev);
3376c82e9aa0SEli Cohen 	if (IS_ERR(mailbox)) {
3377c82e9aa0SEli Cohen 		err = PTR_ERR(mailbox);
3378c82e9aa0SEli Cohen 		goto put;
3379c82e9aa0SEli Cohen 	}
3380c82e9aa0SEli Cohen 
3381c82e9aa0SEli Cohen 	if (eqe->type == MLX4_EVENT_TYPE_CMD) {
3382c82e9aa0SEli Cohen 		++event_eq->token;
3383c82e9aa0SEli Cohen 		eqe->event.cmd.token = cpu_to_be16(event_eq->token);
3384c82e9aa0SEli Cohen 	}
3385c82e9aa0SEli Cohen 
3386c82e9aa0SEli Cohen 	memcpy(mailbox->buf, (u8 *) eqe, 28);
3387c82e9aa0SEli Cohen 
33882d3c7397SYishai Hadas 	in_modifier = (slave & 0xff) | ((event_eq->eqn & 0x3ff) << 16);
3389c82e9aa0SEli Cohen 
3390c82e9aa0SEli Cohen 	err = mlx4_cmd(dev, mailbox->dma, in_modifier, 0,
3391c82e9aa0SEli Cohen 		       MLX4_CMD_GEN_EQE, MLX4_CMD_TIME_CLASS_B,
3392c82e9aa0SEli Cohen 		       MLX4_CMD_NATIVE);
3393c82e9aa0SEli Cohen 
3394c82e9aa0SEli Cohen 	put_res(dev, slave, res_id, RES_EQ);
3395c82e9aa0SEli Cohen 	mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]);
3396c82e9aa0SEli Cohen 	mlx4_free_cmd_mailbox(dev, mailbox);
3397c82e9aa0SEli Cohen 	return err;
3398c82e9aa0SEli Cohen 
3399c82e9aa0SEli Cohen put:
3400c82e9aa0SEli Cohen 	put_res(dev, slave, res_id, RES_EQ);
3401c82e9aa0SEli Cohen 
3402c82e9aa0SEli Cohen unlock:
3403c82e9aa0SEli Cohen 	mutex_unlock(&priv->mfunc.master.gen_eqe_mutex[slave]);
3404c82e9aa0SEli Cohen 	return err;
3405c82e9aa0SEli Cohen }
3406c82e9aa0SEli Cohen 
mlx4_QUERY_EQ_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3407c82e9aa0SEli Cohen int mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave,
3408c82e9aa0SEli Cohen 			  struct mlx4_vhcr *vhcr,
3409c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *inbox,
3410c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *outbox,
3411c82e9aa0SEli Cohen 			  struct mlx4_cmd_info *cmd)
3412c82e9aa0SEli Cohen {
3413c82e9aa0SEli Cohen 	int eqn = vhcr->in_modifier;
34142d3c7397SYishai Hadas 	int res_id = eqn | (slave << 10);
3415c82e9aa0SEli Cohen 	struct res_eq *eq;
3416c82e9aa0SEli Cohen 	int err;
3417c82e9aa0SEli Cohen 
3418c82e9aa0SEli Cohen 	err = get_res(dev, slave, res_id, RES_EQ, &eq);
3419c82e9aa0SEli Cohen 	if (err)
3420c82e9aa0SEli Cohen 		return err;
3421c82e9aa0SEli Cohen 
3422c82e9aa0SEli Cohen 	if (eq->com.from_state != RES_EQ_HW) {
3423c82e9aa0SEli Cohen 		err = -EINVAL;
3424c82e9aa0SEli Cohen 		goto ex_put;
3425c82e9aa0SEli Cohen 	}
3426c82e9aa0SEli Cohen 
3427c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3428c82e9aa0SEli Cohen 
3429c82e9aa0SEli Cohen ex_put:
3430c82e9aa0SEli Cohen 	put_res(dev, slave, res_id, RES_EQ);
3431c82e9aa0SEli Cohen 	return err;
3432c82e9aa0SEli Cohen }
3433c82e9aa0SEli Cohen 
mlx4_SW2HW_CQ_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3434c82e9aa0SEli Cohen int mlx4_SW2HW_CQ_wrapper(struct mlx4_dev *dev, int slave,
3435c82e9aa0SEli Cohen 			  struct mlx4_vhcr *vhcr,
3436c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *inbox,
3437c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *outbox,
3438c82e9aa0SEli Cohen 			  struct mlx4_cmd_info *cmd)
3439c82e9aa0SEli Cohen {
3440c82e9aa0SEli Cohen 	int err;
3441c82e9aa0SEli Cohen 	int cqn = vhcr->in_modifier;
3442c82e9aa0SEli Cohen 	struct mlx4_cq_context *cqc = inbox->buf;
34432b8fb286SMarcel Apfelbaum 	int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz;
3444c1c52db1SBjorn Helgaas 	struct res_cq *cq = NULL;
3445c82e9aa0SEli Cohen 	struct res_mtt *mtt;
3446c82e9aa0SEli Cohen 
3447c82e9aa0SEli Cohen 	err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_HW, &cq);
3448c82e9aa0SEli Cohen 	if (err)
3449c82e9aa0SEli Cohen 		return err;
34502b8fb286SMarcel Apfelbaum 	err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);
3451c82e9aa0SEli Cohen 	if (err)
3452c82e9aa0SEli Cohen 		goto out_move;
3453c82e9aa0SEli Cohen 	err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt);
3454c82e9aa0SEli Cohen 	if (err)
3455c82e9aa0SEli Cohen 		goto out_put;
3456c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3457c82e9aa0SEli Cohen 	if (err)
3458c82e9aa0SEli Cohen 		goto out_put;
3459c82e9aa0SEli Cohen 	atomic_inc(&mtt->ref_count);
3460c82e9aa0SEli Cohen 	cq->mtt = mtt;
3461c82e9aa0SEli Cohen 	put_res(dev, slave, mtt->com.res_id, RES_MTT);
3462c82e9aa0SEli Cohen 	res_end_move(dev, slave, RES_CQ, cqn);
3463c82e9aa0SEli Cohen 	return 0;
3464c82e9aa0SEli Cohen 
3465c82e9aa0SEli Cohen out_put:
3466c82e9aa0SEli Cohen 	put_res(dev, slave, mtt->com.res_id, RES_MTT);
3467c82e9aa0SEli Cohen out_move:
3468c82e9aa0SEli Cohen 	res_abort_move(dev, slave, RES_CQ, cqn);
3469c82e9aa0SEli Cohen 	return err;
3470c82e9aa0SEli Cohen }
3471c82e9aa0SEli Cohen 
mlx4_HW2SW_CQ_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3472c82e9aa0SEli Cohen int mlx4_HW2SW_CQ_wrapper(struct mlx4_dev *dev, int slave,
3473c82e9aa0SEli Cohen 			  struct mlx4_vhcr *vhcr,
3474c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *inbox,
3475c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *outbox,
3476c82e9aa0SEli Cohen 			  struct mlx4_cmd_info *cmd)
3477c82e9aa0SEli Cohen {
3478c82e9aa0SEli Cohen 	int err;
3479c82e9aa0SEli Cohen 	int cqn = vhcr->in_modifier;
3480c1c52db1SBjorn Helgaas 	struct res_cq *cq = NULL;
3481c82e9aa0SEli Cohen 
3482c82e9aa0SEli Cohen 	err = cq_res_start_move_to(dev, slave, cqn, RES_CQ_ALLOCATED, &cq);
3483c82e9aa0SEli Cohen 	if (err)
3484c82e9aa0SEli Cohen 		return err;
3485c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3486c82e9aa0SEli Cohen 	if (err)
3487c82e9aa0SEli Cohen 		goto out_move;
3488c82e9aa0SEli Cohen 	atomic_dec(&cq->mtt->ref_count);
3489c82e9aa0SEli Cohen 	res_end_move(dev, slave, RES_CQ, cqn);
3490c82e9aa0SEli Cohen 	return 0;
3491c82e9aa0SEli Cohen 
3492c82e9aa0SEli Cohen out_move:
3493c82e9aa0SEli Cohen 	res_abort_move(dev, slave, RES_CQ, cqn);
3494c82e9aa0SEli Cohen 	return err;
3495c82e9aa0SEli Cohen }
3496c82e9aa0SEli Cohen 
mlx4_QUERY_CQ_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3497c82e9aa0SEli Cohen int mlx4_QUERY_CQ_wrapper(struct mlx4_dev *dev, int slave,
3498c82e9aa0SEli Cohen 			  struct mlx4_vhcr *vhcr,
3499c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *inbox,
3500c82e9aa0SEli Cohen 			  struct mlx4_cmd_mailbox *outbox,
3501c82e9aa0SEli Cohen 			  struct mlx4_cmd_info *cmd)
3502c82e9aa0SEli Cohen {
3503c82e9aa0SEli Cohen 	int cqn = vhcr->in_modifier;
3504c82e9aa0SEli Cohen 	struct res_cq *cq;
3505c82e9aa0SEli Cohen 	int err;
3506c82e9aa0SEli Cohen 
3507c82e9aa0SEli Cohen 	err = get_res(dev, slave, cqn, RES_CQ, &cq);
3508c82e9aa0SEli Cohen 	if (err)
3509c82e9aa0SEli Cohen 		return err;
3510c82e9aa0SEli Cohen 
3511c82e9aa0SEli Cohen 	if (cq->com.from_state != RES_CQ_HW)
3512c82e9aa0SEli Cohen 		goto ex_put;
3513c82e9aa0SEli Cohen 
3514c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3515c82e9aa0SEli Cohen ex_put:
3516c82e9aa0SEli Cohen 	put_res(dev, slave, cqn, RES_CQ);
3517c82e9aa0SEli Cohen 
3518c82e9aa0SEli Cohen 	return err;
3519c82e9aa0SEli Cohen }
3520c82e9aa0SEli Cohen 
handle_resize(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd,struct res_cq * cq)3521c82e9aa0SEli Cohen static int handle_resize(struct mlx4_dev *dev, int slave,
3522c82e9aa0SEli Cohen 			 struct mlx4_vhcr *vhcr,
3523c82e9aa0SEli Cohen 			 struct mlx4_cmd_mailbox *inbox,
3524c82e9aa0SEli Cohen 			 struct mlx4_cmd_mailbox *outbox,
3525c82e9aa0SEli Cohen 			 struct mlx4_cmd_info *cmd,
3526c82e9aa0SEli Cohen 			 struct res_cq *cq)
3527c82e9aa0SEli Cohen {
3528c82e9aa0SEli Cohen 	int err;
3529c82e9aa0SEli Cohen 	struct res_mtt *orig_mtt;
3530c82e9aa0SEli Cohen 	struct res_mtt *mtt;
3531c82e9aa0SEli Cohen 	struct mlx4_cq_context *cqc = inbox->buf;
35322b8fb286SMarcel Apfelbaum 	int mtt_base = cq_get_mtt_addr(cqc) / dev->caps.mtt_entry_sz;
3533c82e9aa0SEli Cohen 
3534c82e9aa0SEli Cohen 	err = get_res(dev, slave, cq->mtt->com.res_id, RES_MTT, &orig_mtt);
3535c82e9aa0SEli Cohen 	if (err)
3536c82e9aa0SEli Cohen 		return err;
3537c82e9aa0SEli Cohen 
3538c82e9aa0SEli Cohen 	if (orig_mtt != cq->mtt) {
3539c82e9aa0SEli Cohen 		err = -EINVAL;
3540c82e9aa0SEli Cohen 		goto ex_put;
3541c82e9aa0SEli Cohen 	}
3542c82e9aa0SEli Cohen 
35432b8fb286SMarcel Apfelbaum 	err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);
3544c82e9aa0SEli Cohen 	if (err)
3545c82e9aa0SEli Cohen 		goto ex_put;
3546c82e9aa0SEli Cohen 
3547c82e9aa0SEli Cohen 	err = check_mtt_range(dev, slave, mtt_base, cq_get_mtt_size(cqc), mtt);
3548c82e9aa0SEli Cohen 	if (err)
3549c82e9aa0SEli Cohen 		goto ex_put1;
3550c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3551c82e9aa0SEli Cohen 	if (err)
3552c82e9aa0SEli Cohen 		goto ex_put1;
3553c82e9aa0SEli Cohen 	atomic_dec(&orig_mtt->ref_count);
3554c82e9aa0SEli Cohen 	put_res(dev, slave, orig_mtt->com.res_id, RES_MTT);
3555c82e9aa0SEli Cohen 	atomic_inc(&mtt->ref_count);
3556c82e9aa0SEli Cohen 	cq->mtt = mtt;
3557c82e9aa0SEli Cohen 	put_res(dev, slave, mtt->com.res_id, RES_MTT);
3558c82e9aa0SEli Cohen 	return 0;
3559c82e9aa0SEli Cohen 
3560c82e9aa0SEli Cohen ex_put1:
3561c82e9aa0SEli Cohen 	put_res(dev, slave, mtt->com.res_id, RES_MTT);
3562c82e9aa0SEli Cohen ex_put:
3563c82e9aa0SEli Cohen 	put_res(dev, slave, orig_mtt->com.res_id, RES_MTT);
3564c82e9aa0SEli Cohen 
3565c82e9aa0SEli Cohen 	return err;
3566c82e9aa0SEli Cohen 
3567c82e9aa0SEli Cohen }
3568c82e9aa0SEli Cohen 
mlx4_MODIFY_CQ_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3569c82e9aa0SEli Cohen int mlx4_MODIFY_CQ_wrapper(struct mlx4_dev *dev, int slave,
3570c82e9aa0SEli Cohen 			   struct mlx4_vhcr *vhcr,
3571c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *inbox,
3572c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *outbox,
3573c82e9aa0SEli Cohen 			   struct mlx4_cmd_info *cmd)
3574c82e9aa0SEli Cohen {
3575c82e9aa0SEli Cohen 	int cqn = vhcr->in_modifier;
3576c82e9aa0SEli Cohen 	struct res_cq *cq;
3577c82e9aa0SEli Cohen 	int err;
3578c82e9aa0SEli Cohen 
3579c82e9aa0SEli Cohen 	err = get_res(dev, slave, cqn, RES_CQ, &cq);
3580c82e9aa0SEli Cohen 	if (err)
3581c82e9aa0SEli Cohen 		return err;
3582c82e9aa0SEli Cohen 
3583c82e9aa0SEli Cohen 	if (cq->com.from_state != RES_CQ_HW)
3584c82e9aa0SEli Cohen 		goto ex_put;
3585c82e9aa0SEli Cohen 
3586c82e9aa0SEli Cohen 	if (vhcr->op_modifier == 0) {
3587c82e9aa0SEli Cohen 		err = handle_resize(dev, slave, vhcr, inbox, outbox, cmd, cq);
3588c82e9aa0SEli Cohen 		goto ex_put;
3589c82e9aa0SEli Cohen 	}
3590c82e9aa0SEli Cohen 
3591c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3592c82e9aa0SEli Cohen ex_put:
3593c82e9aa0SEli Cohen 	put_res(dev, slave, cqn, RES_CQ);
3594c82e9aa0SEli Cohen 
3595c82e9aa0SEli Cohen 	return err;
3596c82e9aa0SEli Cohen }
3597c82e9aa0SEli Cohen 
srq_get_mtt_size(struct mlx4_srq_context * srqc)3598c82e9aa0SEli Cohen static int srq_get_mtt_size(struct mlx4_srq_context *srqc)
3599c82e9aa0SEli Cohen {
3600c82e9aa0SEli Cohen 	int log_srq_size = (be32_to_cpu(srqc->state_logsize_srqn) >> 24) & 0xf;
3601c82e9aa0SEli Cohen 	int log_rq_stride = srqc->logstride & 7;
3602c82e9aa0SEli Cohen 	int page_shift = (srqc->log_page_size & 0x3f) + 12;
3603c82e9aa0SEli Cohen 
3604c82e9aa0SEli Cohen 	if (log_srq_size + log_rq_stride + 4 < page_shift)
3605c82e9aa0SEli Cohen 		return 1;
3606c82e9aa0SEli Cohen 
3607c82e9aa0SEli Cohen 	return 1 << (log_srq_size + log_rq_stride + 4 - page_shift);
3608c82e9aa0SEli Cohen }
3609c82e9aa0SEli Cohen 
mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3610c82e9aa0SEli Cohen int mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave,
3611c82e9aa0SEli Cohen 			   struct mlx4_vhcr *vhcr,
3612c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *inbox,
3613c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *outbox,
3614c82e9aa0SEli Cohen 			   struct mlx4_cmd_info *cmd)
3615c82e9aa0SEli Cohen {
3616c82e9aa0SEli Cohen 	int err;
3617c82e9aa0SEli Cohen 	int srqn = vhcr->in_modifier;
3618c82e9aa0SEli Cohen 	struct res_mtt *mtt;
3619c1c52db1SBjorn Helgaas 	struct res_srq *srq = NULL;
3620c82e9aa0SEli Cohen 	struct mlx4_srq_context *srqc = inbox->buf;
36212b8fb286SMarcel Apfelbaum 	int mtt_base = srq_get_mtt_addr(srqc) / dev->caps.mtt_entry_sz;
3622c82e9aa0SEli Cohen 
3623c82e9aa0SEli Cohen 	if (srqn != (be32_to_cpu(srqc->state_logsize_srqn) & 0xffffff))
3624c82e9aa0SEli Cohen 		return -EINVAL;
3625c82e9aa0SEli Cohen 
3626c82e9aa0SEli Cohen 	err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_HW, &srq);
3627c82e9aa0SEli Cohen 	if (err)
3628c82e9aa0SEli Cohen 		return err;
36292b8fb286SMarcel Apfelbaum 	err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);
3630c82e9aa0SEli Cohen 	if (err)
3631c82e9aa0SEli Cohen 		goto ex_abort;
3632c82e9aa0SEli Cohen 	err = check_mtt_range(dev, slave, mtt_base, srq_get_mtt_size(srqc),
3633c82e9aa0SEli Cohen 			      mtt);
3634c82e9aa0SEli Cohen 	if (err)
3635c82e9aa0SEli Cohen 		goto ex_put_mtt;
3636c82e9aa0SEli Cohen 
3637c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3638c82e9aa0SEli Cohen 	if (err)
3639c82e9aa0SEli Cohen 		goto ex_put_mtt;
3640c82e9aa0SEli Cohen 
3641c82e9aa0SEli Cohen 	atomic_inc(&mtt->ref_count);
3642c82e9aa0SEli Cohen 	srq->mtt = mtt;
3643c82e9aa0SEli Cohen 	put_res(dev, slave, mtt->com.res_id, RES_MTT);
3644c82e9aa0SEli Cohen 	res_end_move(dev, slave, RES_SRQ, srqn);
3645c82e9aa0SEli Cohen 	return 0;
3646c82e9aa0SEli Cohen 
3647c82e9aa0SEli Cohen ex_put_mtt:
3648c82e9aa0SEli Cohen 	put_res(dev, slave, mtt->com.res_id, RES_MTT);
3649c82e9aa0SEli Cohen ex_abort:
3650c82e9aa0SEli Cohen 	res_abort_move(dev, slave, RES_SRQ, srqn);
3651c82e9aa0SEli Cohen 
3652c82e9aa0SEli Cohen 	return err;
3653c82e9aa0SEli Cohen }
3654c82e9aa0SEli Cohen 
mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3655c82e9aa0SEli Cohen int mlx4_HW2SW_SRQ_wrapper(struct mlx4_dev *dev, int slave,
3656c82e9aa0SEli Cohen 			   struct mlx4_vhcr *vhcr,
3657c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *inbox,
3658c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *outbox,
3659c82e9aa0SEli Cohen 			   struct mlx4_cmd_info *cmd)
3660c82e9aa0SEli Cohen {
3661c82e9aa0SEli Cohen 	int err;
3662c82e9aa0SEli Cohen 	int srqn = vhcr->in_modifier;
3663c1c52db1SBjorn Helgaas 	struct res_srq *srq = NULL;
3664c82e9aa0SEli Cohen 
3665c82e9aa0SEli Cohen 	err = srq_res_start_move_to(dev, slave, srqn, RES_SRQ_ALLOCATED, &srq);
3666c82e9aa0SEli Cohen 	if (err)
3667c82e9aa0SEli Cohen 		return err;
3668c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3669c82e9aa0SEli Cohen 	if (err)
3670c82e9aa0SEli Cohen 		goto ex_abort;
3671c82e9aa0SEli Cohen 	atomic_dec(&srq->mtt->ref_count);
3672c82e9aa0SEli Cohen 	if (srq->cq)
3673c82e9aa0SEli Cohen 		atomic_dec(&srq->cq->ref_count);
3674c82e9aa0SEli Cohen 	res_end_move(dev, slave, RES_SRQ, srqn);
3675c82e9aa0SEli Cohen 
3676c82e9aa0SEli Cohen 	return 0;
3677c82e9aa0SEli Cohen 
3678c82e9aa0SEli Cohen ex_abort:
3679c82e9aa0SEli Cohen 	res_abort_move(dev, slave, RES_SRQ, srqn);
3680c82e9aa0SEli Cohen 
3681c82e9aa0SEli Cohen 	return err;
3682c82e9aa0SEli Cohen }
3683c82e9aa0SEli Cohen 
mlx4_QUERY_SRQ_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3684c82e9aa0SEli Cohen int mlx4_QUERY_SRQ_wrapper(struct mlx4_dev *dev, int slave,
3685c82e9aa0SEli Cohen 			   struct mlx4_vhcr *vhcr,
3686c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *inbox,
3687c82e9aa0SEli Cohen 			   struct mlx4_cmd_mailbox *outbox,
3688c82e9aa0SEli Cohen 			   struct mlx4_cmd_info *cmd)
3689c82e9aa0SEli Cohen {
3690c82e9aa0SEli Cohen 	int err;
3691c82e9aa0SEli Cohen 	int srqn = vhcr->in_modifier;
3692c82e9aa0SEli Cohen 	struct res_srq *srq;
3693c82e9aa0SEli Cohen 
3694c82e9aa0SEli Cohen 	err = get_res(dev, slave, srqn, RES_SRQ, &srq);
3695c82e9aa0SEli Cohen 	if (err)
3696c82e9aa0SEli Cohen 		return err;
3697c82e9aa0SEli Cohen 	if (srq->com.from_state != RES_SRQ_HW) {
3698c82e9aa0SEli Cohen 		err = -EBUSY;
3699c82e9aa0SEli Cohen 		goto out;
3700c82e9aa0SEli Cohen 	}
3701c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3702c82e9aa0SEli Cohen out:
3703c82e9aa0SEli Cohen 	put_res(dev, slave, srqn, RES_SRQ);
3704c82e9aa0SEli Cohen 	return err;
3705c82e9aa0SEli Cohen }
3706c82e9aa0SEli Cohen 
mlx4_ARM_SRQ_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3707c82e9aa0SEli Cohen int mlx4_ARM_SRQ_wrapper(struct mlx4_dev *dev, int slave,
3708c82e9aa0SEli Cohen 			 struct mlx4_vhcr *vhcr,
3709c82e9aa0SEli Cohen 			 struct mlx4_cmd_mailbox *inbox,
3710c82e9aa0SEli Cohen 			 struct mlx4_cmd_mailbox *outbox,
3711c82e9aa0SEli Cohen 			 struct mlx4_cmd_info *cmd)
3712c82e9aa0SEli Cohen {
3713c82e9aa0SEli Cohen 	int err;
3714c82e9aa0SEli Cohen 	int srqn = vhcr->in_modifier;
3715c82e9aa0SEli Cohen 	struct res_srq *srq;
3716c82e9aa0SEli Cohen 
3717c82e9aa0SEli Cohen 	err = get_res(dev, slave, srqn, RES_SRQ, &srq);
3718c82e9aa0SEli Cohen 	if (err)
3719c82e9aa0SEli Cohen 		return err;
3720c82e9aa0SEli Cohen 
3721c82e9aa0SEli Cohen 	if (srq->com.from_state != RES_SRQ_HW) {
3722c82e9aa0SEli Cohen 		err = -EBUSY;
3723c82e9aa0SEli Cohen 		goto out;
3724c82e9aa0SEli Cohen 	}
3725c82e9aa0SEli Cohen 
3726c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3727c82e9aa0SEli Cohen out:
3728c82e9aa0SEli Cohen 	put_res(dev, slave, srqn, RES_SRQ);
3729c82e9aa0SEli Cohen 	return err;
3730c82e9aa0SEli Cohen }
3731c82e9aa0SEli Cohen 
mlx4_GEN_QP_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3732c82e9aa0SEli Cohen int mlx4_GEN_QP_wrapper(struct mlx4_dev *dev, int slave,
3733c82e9aa0SEli Cohen 			struct mlx4_vhcr *vhcr,
3734c82e9aa0SEli Cohen 			struct mlx4_cmd_mailbox *inbox,
3735c82e9aa0SEli Cohen 			struct mlx4_cmd_mailbox *outbox,
3736c82e9aa0SEli Cohen 			struct mlx4_cmd_info *cmd)
3737c82e9aa0SEli Cohen {
3738c82e9aa0SEli Cohen 	int err;
3739c82e9aa0SEli Cohen 	int qpn = vhcr->in_modifier & 0x7fffff;
3740c82e9aa0SEli Cohen 	struct res_qp *qp;
3741c82e9aa0SEli Cohen 
3742c82e9aa0SEli Cohen 	err = get_res(dev, slave, qpn, RES_QP, &qp);
3743c82e9aa0SEli Cohen 	if (err)
3744c82e9aa0SEli Cohen 		return err;
3745c82e9aa0SEli Cohen 	if (qp->com.from_state != RES_QP_HW) {
3746c82e9aa0SEli Cohen 		err = -EBUSY;
3747c82e9aa0SEli Cohen 		goto out;
3748c82e9aa0SEli Cohen 	}
3749c82e9aa0SEli Cohen 
3750c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3751c82e9aa0SEli Cohen out:
3752c82e9aa0SEli Cohen 	put_res(dev, slave, qpn, RES_QP);
3753c82e9aa0SEli Cohen 	return err;
3754c82e9aa0SEli Cohen }
3755c82e9aa0SEli Cohen 
mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)375654679e14SJack Morgenstein int mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,
375754679e14SJack Morgenstein 			      struct mlx4_vhcr *vhcr,
375854679e14SJack Morgenstein 			      struct mlx4_cmd_mailbox *inbox,
375954679e14SJack Morgenstein 			      struct mlx4_cmd_mailbox *outbox,
376054679e14SJack Morgenstein 			      struct mlx4_cmd_info *cmd)
376154679e14SJack Morgenstein {
376254679e14SJack Morgenstein 	struct mlx4_qp_context *context = inbox->buf + 8;
376354679e14SJack Morgenstein 	adjust_proxy_tun_qkey(dev, vhcr, context);
376454679e14SJack Morgenstein 	update_pkey_index(dev, slave, inbox);
376554679e14SJack Morgenstein 	return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
376654679e14SJack Morgenstein }
376754679e14SJack Morgenstein 
adjust_qp_sched_queue(struct mlx4_dev * dev,int slave,struct mlx4_qp_context * qpc,struct mlx4_cmd_mailbox * inbox)3768449fc488SMatan Barak static int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave,
3769449fc488SMatan Barak 				  struct mlx4_qp_context *qpc,
3770449fc488SMatan Barak 				  struct mlx4_cmd_mailbox *inbox)
3771449fc488SMatan Barak {
3772449fc488SMatan Barak 	enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *)inbox->buf);
3773449fc488SMatan Barak 	u8 pri_sched_queue;
3774449fc488SMatan Barak 	int port = mlx4_slave_convert_port(
3775449fc488SMatan Barak 		   dev, slave, (qpc->pri_path.sched_queue >> 6 & 1) + 1) - 1;
3776449fc488SMatan Barak 
3777449fc488SMatan Barak 	if (port < 0)
3778449fc488SMatan Barak 		return -EINVAL;
3779449fc488SMatan Barak 
3780449fc488SMatan Barak 	pri_sched_queue = (qpc->pri_path.sched_queue & ~(1 << 6)) |
3781449fc488SMatan Barak 			  ((port & 1) << 6);
3782449fc488SMatan Barak 
3783f40e99e9SOr Gerlitz 	if (optpar & (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH | MLX4_QP_OPTPAR_SCHED_QUEUE) ||
3784f40e99e9SOr Gerlitz 	    qpc->pri_path.sched_queue || mlx4_is_eth(dev, port + 1)) {
3785449fc488SMatan Barak 		qpc->pri_path.sched_queue = pri_sched_queue;
3786449fc488SMatan Barak 	}
3787449fc488SMatan Barak 
3788449fc488SMatan Barak 	if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
3789449fc488SMatan Barak 		port = mlx4_slave_convert_port(
3790449fc488SMatan Barak 				dev, slave, (qpc->alt_path.sched_queue >> 6 & 1)
3791449fc488SMatan Barak 				+ 1) - 1;
3792449fc488SMatan Barak 		if (port < 0)
3793449fc488SMatan Barak 			return -EINVAL;
3794449fc488SMatan Barak 		qpc->alt_path.sched_queue =
3795449fc488SMatan Barak 			(qpc->alt_path.sched_queue & ~(1 << 6)) |
3796449fc488SMatan Barak 			(port & 1) << 6;
3797449fc488SMatan Barak 	}
3798449fc488SMatan Barak 	return 0;
3799449fc488SMatan Barak }
3800449fc488SMatan Barak 
roce_verify_mac(struct mlx4_dev * dev,int slave,struct mlx4_qp_context * qpc,struct mlx4_cmd_mailbox * inbox)38012f5bb473SJack Morgenstein static int roce_verify_mac(struct mlx4_dev *dev, int slave,
38022f5bb473SJack Morgenstein 				struct mlx4_qp_context *qpc,
38032f5bb473SJack Morgenstein 				struct mlx4_cmd_mailbox *inbox)
38042f5bb473SJack Morgenstein {
38052f5bb473SJack Morgenstein 	u64 mac;
38062f5bb473SJack Morgenstein 	int port;
38072f5bb473SJack Morgenstein 	u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
38082f5bb473SJack Morgenstein 	u8 sched = *(u8 *)(inbox->buf + 64);
38092f5bb473SJack Morgenstein 	u8 smac_ix;
38102f5bb473SJack Morgenstein 
38112f5bb473SJack Morgenstein 	port = (sched >> 6 & 1) + 1;
38122f5bb473SJack Morgenstein 	if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) {
38132f5bb473SJack Morgenstein 		smac_ix = qpc->pri_path.grh_mylmc & 0x7f;
38142f5bb473SJack Morgenstein 		if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac))
38152f5bb473SJack Morgenstein 			return -ENOENT;
38162f5bb473SJack Morgenstein 	}
38172f5bb473SJack Morgenstein 	return 0;
38182f5bb473SJack Morgenstein }
38192f5bb473SJack Morgenstein 
mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3820c82e9aa0SEli Cohen int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
3821c82e9aa0SEli Cohen 			     struct mlx4_vhcr *vhcr,
3822c82e9aa0SEli Cohen 			     struct mlx4_cmd_mailbox *inbox,
3823c82e9aa0SEli Cohen 			     struct mlx4_cmd_mailbox *outbox,
3824c82e9aa0SEli Cohen 			     struct mlx4_cmd_info *cmd)
3825c82e9aa0SEli Cohen {
382654679e14SJack Morgenstein 	int err;
3827c82e9aa0SEli Cohen 	struct mlx4_qp_context *qpc = inbox->buf + 8;
3828b01978caSJack Morgenstein 	int qpn = vhcr->in_modifier & 0x7fffff;
3829b01978caSJack Morgenstein 	struct res_qp *qp;
3830b01978caSJack Morgenstein 	u8 orig_sched_queue;
3831f0f829bfSRony Efraim 	u8 orig_vlan_control = qpc->pri_path.vlan_control;
3832f0f829bfSRony Efraim 	u8 orig_fvl_rx = qpc->pri_path.fvl_rx;
3833f0f829bfSRony Efraim 	u8 orig_pri_path_fl = qpc->pri_path.fl;
3834f0f829bfSRony Efraim 	u8 orig_vlan_index = qpc->pri_path.vlan_index;
3835f0f829bfSRony Efraim 	u8 orig_feup = qpc->pri_path.feup;
3836c82e9aa0SEli Cohen 
3837449fc488SMatan Barak 	err = adjust_qp_sched_queue(dev, slave, qpc, inbox);
3838449fc488SMatan Barak 	if (err)
3839449fc488SMatan Barak 		return err;
384099ec41d0SJack Morgenstein 	err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_INIT2RTR, slave);
384154679e14SJack Morgenstein 	if (err)
384254679e14SJack Morgenstein 		return err;
3843c82e9aa0SEli Cohen 
38442f5bb473SJack Morgenstein 	if (roce_verify_mac(dev, slave, qpc, inbox))
38452f5bb473SJack Morgenstein 		return -EINVAL;
38462f5bb473SJack Morgenstein 
384754679e14SJack Morgenstein 	update_pkey_index(dev, slave, inbox);
384854679e14SJack Morgenstein 	update_gid(dev, inbox, (u8)slave);
384954679e14SJack Morgenstein 	adjust_proxy_tun_qkey(dev, vhcr, qpc);
3850b01978caSJack Morgenstein 	orig_sched_queue = qpc->pri_path.sched_queue;
385154679e14SJack Morgenstein 
3852b01978caSJack Morgenstein 	err = get_res(dev, slave, qpn, RES_QP, &qp);
3853b01978caSJack Morgenstein 	if (err)
3854b01978caSJack Morgenstein 		return err;
3855b01978caSJack Morgenstein 	if (qp->com.from_state != RES_QP_HW) {
3856b01978caSJack Morgenstein 		err = -EBUSY;
3857b01978caSJack Morgenstein 		goto out;
3858b01978caSJack Morgenstein 	}
3859b01978caSJack Morgenstein 
38609a892835SMaor Gottlieb 	err = update_vport_qp_param(dev, inbox, slave, qpn);
38619a892835SMaor Gottlieb 	if (err)
38629a892835SMaor Gottlieb 		goto out;
38639a892835SMaor Gottlieb 
3864b01978caSJack Morgenstein 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3865b01978caSJack Morgenstein out:
3866b01978caSJack Morgenstein 	/* if no error, save sched queue value passed in by VF. This is
3867b01978caSJack Morgenstein 	 * essentially the QOS value provided by the VF. This will be useful
3868b01978caSJack Morgenstein 	 * if we allow dynamic changes from VST back to VGT
3869b01978caSJack Morgenstein 	 */
3870f0f829bfSRony Efraim 	if (!err) {
3871b01978caSJack Morgenstein 		qp->sched_queue = orig_sched_queue;
3872f0f829bfSRony Efraim 		qp->vlan_control = orig_vlan_control;
3873f0f829bfSRony Efraim 		qp->fvl_rx	=  orig_fvl_rx;
3874f0f829bfSRony Efraim 		qp->pri_path_fl = orig_pri_path_fl;
3875f0f829bfSRony Efraim 		qp->vlan_index  = orig_vlan_index;
3876f0f829bfSRony Efraim 		qp->feup	= orig_feup;
3877f0f829bfSRony Efraim 	}
3878b01978caSJack Morgenstein 	put_res(dev, slave, qpn, RES_QP);
3879b01978caSJack Morgenstein 	return err;
388054679e14SJack Morgenstein }
388154679e14SJack Morgenstein 
mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)388254679e14SJack Morgenstein int mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
388354679e14SJack Morgenstein 			    struct mlx4_vhcr *vhcr,
388454679e14SJack Morgenstein 			    struct mlx4_cmd_mailbox *inbox,
388554679e14SJack Morgenstein 			    struct mlx4_cmd_mailbox *outbox,
388654679e14SJack Morgenstein 			    struct mlx4_cmd_info *cmd)
388754679e14SJack Morgenstein {
388854679e14SJack Morgenstein 	int err;
388954679e14SJack Morgenstein 	struct mlx4_qp_context *context = inbox->buf + 8;
389054679e14SJack Morgenstein 
3891449fc488SMatan Barak 	err = adjust_qp_sched_queue(dev, slave, context, inbox);
3892449fc488SMatan Barak 	if (err)
3893449fc488SMatan Barak 		return err;
389499ec41d0SJack Morgenstein 	err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTR2RTS, slave);
389554679e14SJack Morgenstein 	if (err)
389654679e14SJack Morgenstein 		return err;
389754679e14SJack Morgenstein 
389854679e14SJack Morgenstein 	update_pkey_index(dev, slave, inbox);
389954679e14SJack Morgenstein 	update_gid(dev, inbox, (u8)slave);
390054679e14SJack Morgenstein 	adjust_proxy_tun_qkey(dev, vhcr, context);
390154679e14SJack Morgenstein 	return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
390254679e14SJack Morgenstein }
390354679e14SJack Morgenstein 
mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)390454679e14SJack Morgenstein int mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
390554679e14SJack Morgenstein 			    struct mlx4_vhcr *vhcr,
390654679e14SJack Morgenstein 			    struct mlx4_cmd_mailbox *inbox,
390754679e14SJack Morgenstein 			    struct mlx4_cmd_mailbox *outbox,
390854679e14SJack Morgenstein 			    struct mlx4_cmd_info *cmd)
390954679e14SJack Morgenstein {
391054679e14SJack Morgenstein 	int err;
391154679e14SJack Morgenstein 	struct mlx4_qp_context *context = inbox->buf + 8;
391254679e14SJack Morgenstein 
3913449fc488SMatan Barak 	err = adjust_qp_sched_queue(dev, slave, context, inbox);
3914449fc488SMatan Barak 	if (err)
3915449fc488SMatan Barak 		return err;
391699ec41d0SJack Morgenstein 	err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_RTS2RTS, slave);
391754679e14SJack Morgenstein 	if (err)
391854679e14SJack Morgenstein 		return err;
391954679e14SJack Morgenstein 
392054679e14SJack Morgenstein 	update_pkey_index(dev, slave, inbox);
392154679e14SJack Morgenstein 	update_gid(dev, inbox, (u8)slave);
392254679e14SJack Morgenstein 	adjust_proxy_tun_qkey(dev, vhcr, context);
392354679e14SJack Morgenstein 	return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
392454679e14SJack Morgenstein }
392554679e14SJack Morgenstein 
392654679e14SJack Morgenstein 
mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)392754679e14SJack Morgenstein int mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
392854679e14SJack Morgenstein 			      struct mlx4_vhcr *vhcr,
392954679e14SJack Morgenstein 			      struct mlx4_cmd_mailbox *inbox,
393054679e14SJack Morgenstein 			      struct mlx4_cmd_mailbox *outbox,
393154679e14SJack Morgenstein 			      struct mlx4_cmd_info *cmd)
393254679e14SJack Morgenstein {
393354679e14SJack Morgenstein 	struct mlx4_qp_context *context = inbox->buf + 8;
3934449fc488SMatan Barak 	int err = adjust_qp_sched_queue(dev, slave, context, inbox);
3935449fc488SMatan Barak 	if (err)
3936449fc488SMatan Barak 		return err;
393754679e14SJack Morgenstein 	adjust_proxy_tun_qkey(dev, vhcr, context);
393854679e14SJack Morgenstein 	return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
393954679e14SJack Morgenstein }
394054679e14SJack Morgenstein 
mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)394154679e14SJack Morgenstein int mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave,
394254679e14SJack Morgenstein 			    struct mlx4_vhcr *vhcr,
394354679e14SJack Morgenstein 			    struct mlx4_cmd_mailbox *inbox,
394454679e14SJack Morgenstein 			    struct mlx4_cmd_mailbox *outbox,
394554679e14SJack Morgenstein 			    struct mlx4_cmd_info *cmd)
394654679e14SJack Morgenstein {
394754679e14SJack Morgenstein 	int err;
394854679e14SJack Morgenstein 	struct mlx4_qp_context *context = inbox->buf + 8;
394954679e14SJack Morgenstein 
3950449fc488SMatan Barak 	err = adjust_qp_sched_queue(dev, slave, context, inbox);
3951449fc488SMatan Barak 	if (err)
3952449fc488SMatan Barak 		return err;
395399ec41d0SJack Morgenstein 	err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2SQD, slave);
395454679e14SJack Morgenstein 	if (err)
395554679e14SJack Morgenstein 		return err;
395654679e14SJack Morgenstein 
395754679e14SJack Morgenstein 	adjust_proxy_tun_qkey(dev, vhcr, context);
395854679e14SJack Morgenstein 	update_gid(dev, inbox, (u8)slave);
395954679e14SJack Morgenstein 	update_pkey_index(dev, slave, inbox);
396054679e14SJack Morgenstein 	return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
396154679e14SJack Morgenstein }
396254679e14SJack Morgenstein 
mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)396354679e14SJack Morgenstein int mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
396454679e14SJack Morgenstein 			    struct mlx4_vhcr *vhcr,
396554679e14SJack Morgenstein 			    struct mlx4_cmd_mailbox *inbox,
396654679e14SJack Morgenstein 			    struct mlx4_cmd_mailbox *outbox,
396754679e14SJack Morgenstein 			    struct mlx4_cmd_info *cmd)
396854679e14SJack Morgenstein {
396954679e14SJack Morgenstein 	int err;
397054679e14SJack Morgenstein 	struct mlx4_qp_context *context = inbox->buf + 8;
397154679e14SJack Morgenstein 
3972449fc488SMatan Barak 	err = adjust_qp_sched_queue(dev, slave, context, inbox);
3973449fc488SMatan Barak 	if (err)
3974449fc488SMatan Barak 		return err;
397599ec41d0SJack Morgenstein 	err = verify_qp_parameters(dev, vhcr, inbox, QP_TRANS_SQD2RTS, slave);
397654679e14SJack Morgenstein 	if (err)
397754679e14SJack Morgenstein 		return err;
397854679e14SJack Morgenstein 
397954679e14SJack Morgenstein 	adjust_proxy_tun_qkey(dev, vhcr, context);
398054679e14SJack Morgenstein 	update_gid(dev, inbox, (u8)slave);
398154679e14SJack Morgenstein 	update_pkey_index(dev, slave, inbox);
3982c82e9aa0SEli Cohen 	return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3983c82e9aa0SEli Cohen }
3984c82e9aa0SEli Cohen 
mlx4_2RST_QP_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)3985c82e9aa0SEli Cohen int mlx4_2RST_QP_wrapper(struct mlx4_dev *dev, int slave,
3986c82e9aa0SEli Cohen 			 struct mlx4_vhcr *vhcr,
3987c82e9aa0SEli Cohen 			 struct mlx4_cmd_mailbox *inbox,
3988c82e9aa0SEli Cohen 			 struct mlx4_cmd_mailbox *outbox,
3989c82e9aa0SEli Cohen 			 struct mlx4_cmd_info *cmd)
3990c82e9aa0SEli Cohen {
3991c82e9aa0SEli Cohen 	int err;
3992c82e9aa0SEli Cohen 	int qpn = vhcr->in_modifier & 0x7fffff;
3993c82e9aa0SEli Cohen 	struct res_qp *qp;
3994c82e9aa0SEli Cohen 
3995c82e9aa0SEli Cohen 	err = qp_res_start_move_to(dev, slave, qpn, RES_QP_MAPPED, &qp, 0);
3996c82e9aa0SEli Cohen 	if (err)
3997c82e9aa0SEli Cohen 		return err;
3998c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
3999c82e9aa0SEli Cohen 	if (err)
4000c82e9aa0SEli Cohen 		goto ex_abort;
4001c82e9aa0SEli Cohen 
4002c82e9aa0SEli Cohen 	atomic_dec(&qp->mtt->ref_count);
4003c82e9aa0SEli Cohen 	atomic_dec(&qp->rcq->ref_count);
4004c82e9aa0SEli Cohen 	atomic_dec(&qp->scq->ref_count);
4005c82e9aa0SEli Cohen 	if (qp->srq)
4006c82e9aa0SEli Cohen 		atomic_dec(&qp->srq->ref_count);
4007c82e9aa0SEli Cohen 	res_end_move(dev, slave, RES_QP, qpn);
4008c82e9aa0SEli Cohen 	return 0;
4009c82e9aa0SEli Cohen 
4010c82e9aa0SEli Cohen ex_abort:
4011c82e9aa0SEli Cohen 	res_abort_move(dev, slave, RES_QP, qpn);
4012c82e9aa0SEli Cohen 
4013c82e9aa0SEli Cohen 	return err;
4014c82e9aa0SEli Cohen }
4015c82e9aa0SEli Cohen 
find_gid(struct mlx4_dev * dev,int slave,struct res_qp * rqp,u8 * gid)4016c82e9aa0SEli Cohen static struct res_gid *find_gid(struct mlx4_dev *dev, int slave,
4017c82e9aa0SEli Cohen 				struct res_qp *rqp, u8 *gid)
4018c82e9aa0SEli Cohen {
4019c82e9aa0SEli Cohen 	struct res_gid *res;
4020c82e9aa0SEli Cohen 
4021c82e9aa0SEli Cohen 	list_for_each_entry(res, &rqp->mcg_list, list) {
4022c82e9aa0SEli Cohen 		if (!memcmp(res->gid, gid, 16))
4023c82e9aa0SEli Cohen 			return res;
4024c82e9aa0SEli Cohen 	}
4025c82e9aa0SEli Cohen 	return NULL;
4026c82e9aa0SEli Cohen }
4027c82e9aa0SEli Cohen 
add_mcg_res(struct mlx4_dev * dev,int slave,struct res_qp * rqp,u8 * gid,enum mlx4_protocol prot,enum mlx4_steer_type steer,u64 reg_id)4028c82e9aa0SEli Cohen static int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
40299f5b6c63SEugenia Emantayev 		       u8 *gid, enum mlx4_protocol prot,
4030fab1e24aSHadar Hen Zion 		       enum mlx4_steer_type steer, u64 reg_id)
4031c82e9aa0SEli Cohen {
4032c82e9aa0SEli Cohen 	struct res_gid *res;
4033c82e9aa0SEli Cohen 	int err;
4034c82e9aa0SEli Cohen 
403531975e27Sstephen hemminger 	res = kzalloc(sizeof(*res), GFP_KERNEL);
4036c82e9aa0SEli Cohen 	if (!res)
4037c82e9aa0SEli Cohen 		return -ENOMEM;
4038c82e9aa0SEli Cohen 
4039c82e9aa0SEli Cohen 	spin_lock_irq(&rqp->mcg_spl);
4040c82e9aa0SEli Cohen 	if (find_gid(dev, slave, rqp, gid)) {
4041c82e9aa0SEli Cohen 		kfree(res);
4042c82e9aa0SEli Cohen 		err = -EEXIST;
4043c82e9aa0SEli Cohen 	} else {
4044c82e9aa0SEli Cohen 		memcpy(res->gid, gid, 16);
4045c82e9aa0SEli Cohen 		res->prot = prot;
40469f5b6c63SEugenia Emantayev 		res->steer = steer;
4047fab1e24aSHadar Hen Zion 		res->reg_id = reg_id;
4048c82e9aa0SEli Cohen 		list_add_tail(&res->list, &rqp->mcg_list);
4049c82e9aa0SEli Cohen 		err = 0;
4050c82e9aa0SEli Cohen 	}
4051c82e9aa0SEli Cohen 	spin_unlock_irq(&rqp->mcg_spl);
4052c82e9aa0SEli Cohen 
4053c82e9aa0SEli Cohen 	return err;
4054c82e9aa0SEli Cohen }
4055c82e9aa0SEli Cohen 
rem_mcg_res(struct mlx4_dev * dev,int slave,struct res_qp * rqp,u8 * gid,enum mlx4_protocol prot,enum mlx4_steer_type steer,u64 * reg_id)4056c82e9aa0SEli Cohen static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
40579f5b6c63SEugenia Emantayev 		       u8 *gid, enum mlx4_protocol prot,
4058fab1e24aSHadar Hen Zion 		       enum mlx4_steer_type steer, u64 *reg_id)
4059c82e9aa0SEli Cohen {
4060c82e9aa0SEli Cohen 	struct res_gid *res;
4061c82e9aa0SEli Cohen 	int err;
4062c82e9aa0SEli Cohen 
4063c82e9aa0SEli Cohen 	spin_lock_irq(&rqp->mcg_spl);
4064c82e9aa0SEli Cohen 	res = find_gid(dev, slave, rqp, gid);
40659f5b6c63SEugenia Emantayev 	if (!res || res->prot != prot || res->steer != steer)
4066c82e9aa0SEli Cohen 		err = -EINVAL;
4067c82e9aa0SEli Cohen 	else {
4068fab1e24aSHadar Hen Zion 		*reg_id = res->reg_id;
4069c82e9aa0SEli Cohen 		list_del(&res->list);
4070c82e9aa0SEli Cohen 		kfree(res);
4071c82e9aa0SEli Cohen 		err = 0;
4072c82e9aa0SEli Cohen 	}
4073c82e9aa0SEli Cohen 	spin_unlock_irq(&rqp->mcg_spl);
4074c82e9aa0SEli Cohen 
4075c82e9aa0SEli Cohen 	return err;
4076c82e9aa0SEli Cohen }
4077c82e9aa0SEli Cohen 
qp_attach(struct mlx4_dev * dev,int slave,struct mlx4_qp * qp,u8 gid[16],int block_loopback,enum mlx4_protocol prot,enum mlx4_steer_type type,u64 * reg_id)4078449fc488SMatan Barak static int qp_attach(struct mlx4_dev *dev, int slave, struct mlx4_qp *qp,
4079449fc488SMatan Barak 		     u8 gid[16], int block_loopback, enum mlx4_protocol prot,
4080fab1e24aSHadar Hen Zion 		     enum mlx4_steer_type type, u64 *reg_id)
4081fab1e24aSHadar Hen Zion {
4082fab1e24aSHadar Hen Zion 	switch (dev->caps.steering_mode) {
4083449fc488SMatan Barak 	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
4084449fc488SMatan Barak 		int port = mlx4_slave_convert_port(dev, slave, gid[5]);
4085449fc488SMatan Barak 		if (port < 0)
4086449fc488SMatan Barak 			return port;
4087449fc488SMatan Barak 		return mlx4_trans_to_dmfs_attach(dev, qp, gid, port,
4088fab1e24aSHadar Hen Zion 						block_loopback, prot,
4089fab1e24aSHadar Hen Zion 						reg_id);
4090449fc488SMatan Barak 	}
4091fab1e24aSHadar Hen Zion 	case MLX4_STEERING_MODE_B0:
4092449fc488SMatan Barak 		if (prot == MLX4_PROT_ETH) {
4093449fc488SMatan Barak 			int port = mlx4_slave_convert_port(dev, slave, gid[5]);
4094449fc488SMatan Barak 			if (port < 0)
4095449fc488SMatan Barak 				return port;
4096449fc488SMatan Barak 			gid[5] = port;
4097449fc488SMatan Barak 		}
4098fab1e24aSHadar Hen Zion 		return mlx4_qp_attach_common(dev, qp, gid,
4099fab1e24aSHadar Hen Zion 					    block_loopback, prot, type);
4100fab1e24aSHadar Hen Zion 	default:
4101fab1e24aSHadar Hen Zion 		return -EINVAL;
4102fab1e24aSHadar Hen Zion 	}
4103fab1e24aSHadar Hen Zion }
4104fab1e24aSHadar Hen Zion 
qp_detach(struct mlx4_dev * dev,struct mlx4_qp * qp,u8 gid[16],enum mlx4_protocol prot,enum mlx4_steer_type type,u64 reg_id)4105449fc488SMatan Barak static int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,
4106449fc488SMatan Barak 		     u8 gid[16], enum mlx4_protocol prot,
4107449fc488SMatan Barak 		     enum mlx4_steer_type type, u64 reg_id)
4108fab1e24aSHadar Hen Zion {
4109fab1e24aSHadar Hen Zion 	switch (dev->caps.steering_mode) {
4110fab1e24aSHadar Hen Zion 	case MLX4_STEERING_MODE_DEVICE_MANAGED:
4111fab1e24aSHadar Hen Zion 		return mlx4_flow_detach(dev, reg_id);
4112fab1e24aSHadar Hen Zion 	case MLX4_STEERING_MODE_B0:
4113fab1e24aSHadar Hen Zion 		return mlx4_qp_detach_common(dev, qp, gid, prot, type);
4114fab1e24aSHadar Hen Zion 	default:
4115fab1e24aSHadar Hen Zion 		return -EINVAL;
4116fab1e24aSHadar Hen Zion 	}
4117fab1e24aSHadar Hen Zion }
4118fab1e24aSHadar Hen Zion 
mlx4_adjust_port(struct mlx4_dev * dev,int slave,u8 * gid,enum mlx4_protocol prot)4119531d9014SJack Morgenstein static int mlx4_adjust_port(struct mlx4_dev *dev, int slave,
4120531d9014SJack Morgenstein 			    u8 *gid, enum mlx4_protocol prot)
4121531d9014SJack Morgenstein {
4122531d9014SJack Morgenstein 	int real_port;
4123531d9014SJack Morgenstein 
4124531d9014SJack Morgenstein 	if (prot != MLX4_PROT_ETH)
4125531d9014SJack Morgenstein 		return 0;
4126531d9014SJack Morgenstein 
4127531d9014SJack Morgenstein 	if (dev->caps.steering_mode == MLX4_STEERING_MODE_B0 ||
4128531d9014SJack Morgenstein 	    dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) {
4129531d9014SJack Morgenstein 		real_port = mlx4_slave_convert_port(dev, slave, gid[5]);
4130531d9014SJack Morgenstein 		if (real_port < 0)
4131531d9014SJack Morgenstein 			return -EINVAL;
4132531d9014SJack Morgenstein 		gid[5] = real_port;
4133531d9014SJack Morgenstein 	}
4134531d9014SJack Morgenstein 
4135531d9014SJack Morgenstein 	return 0;
4136531d9014SJack Morgenstein }
4137531d9014SJack Morgenstein 
mlx4_QP_ATTACH_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)4138c82e9aa0SEli Cohen int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
4139c82e9aa0SEli Cohen 			       struct mlx4_vhcr *vhcr,
4140c82e9aa0SEli Cohen 			       struct mlx4_cmd_mailbox *inbox,
4141c82e9aa0SEli Cohen 			       struct mlx4_cmd_mailbox *outbox,
4142c82e9aa0SEli Cohen 			       struct mlx4_cmd_info *cmd)
4143c82e9aa0SEli Cohen {
4144c82e9aa0SEli Cohen 	struct mlx4_qp qp; /* dummy for calling attach/detach */
4145c82e9aa0SEli Cohen 	u8 *gid = inbox->buf;
4146c82e9aa0SEli Cohen 	enum mlx4_protocol prot = (vhcr->in_modifier >> 28) & 0x7;
4147162344edSOr Gerlitz 	int err;
4148c82e9aa0SEli Cohen 	int qpn;
4149c82e9aa0SEli Cohen 	struct res_qp *rqp;
4150fab1e24aSHadar Hen Zion 	u64 reg_id = 0;
4151c82e9aa0SEli Cohen 	int attach = vhcr->op_modifier;
4152c82e9aa0SEli Cohen 	int block_loopback = vhcr->in_modifier >> 31;
4153c82e9aa0SEli Cohen 	u8 steer_type_mask = 2;
415475c6062cSEugenia Emantayev 	enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1;
4155c82e9aa0SEli Cohen 
4156c82e9aa0SEli Cohen 	qpn = vhcr->in_modifier & 0xffffff;
4157c82e9aa0SEli Cohen 	err = get_res(dev, slave, qpn, RES_QP, &rqp);
4158c82e9aa0SEli Cohen 	if (err)
4159c82e9aa0SEli Cohen 		return err;
4160c82e9aa0SEli Cohen 
4161c82e9aa0SEli Cohen 	qp.qpn = qpn;
4162c82e9aa0SEli Cohen 	if (attach) {
4163449fc488SMatan Barak 		err = qp_attach(dev, slave, &qp, gid, block_loopback, prot,
4164fab1e24aSHadar Hen Zion 				type, &reg_id);
4165fab1e24aSHadar Hen Zion 		if (err) {
4166fab1e24aSHadar Hen Zion 			pr_err("Fail to attach rule to qp 0x%x\n", qpn);
4167c82e9aa0SEli Cohen 			goto ex_put;
4168c82e9aa0SEli Cohen 		}
4169fab1e24aSHadar Hen Zion 		err = add_mcg_res(dev, slave, rqp, gid, prot, type, reg_id);
4170fab1e24aSHadar Hen Zion 		if (err)
4171fab1e24aSHadar Hen Zion 			goto ex_detach;
4172fab1e24aSHadar Hen Zion 	} else {
4173531d9014SJack Morgenstein 		err = mlx4_adjust_port(dev, slave, gid, prot);
4174531d9014SJack Morgenstein 		if (err)
4175531d9014SJack Morgenstein 			goto ex_put;
4176531d9014SJack Morgenstein 
4177fab1e24aSHadar Hen Zion 		err = rem_mcg_res(dev, slave, rqp, gid, prot, type, &reg_id);
4178fab1e24aSHadar Hen Zion 		if (err)
4179fab1e24aSHadar Hen Zion 			goto ex_put;
4180c82e9aa0SEli Cohen 
4181fab1e24aSHadar Hen Zion 		err = qp_detach(dev, &qp, gid, prot, type, reg_id);
4182fab1e24aSHadar Hen Zion 		if (err)
4183fab1e24aSHadar Hen Zion 			pr_err("Fail to detach rule from qp 0x%x reg_id = 0x%llx\n",
4184fab1e24aSHadar Hen Zion 			       qpn, reg_id);
4185fab1e24aSHadar Hen Zion 	}
4186c82e9aa0SEli Cohen 	put_res(dev, slave, qpn, RES_QP);
4187fab1e24aSHadar Hen Zion 	return err;
4188c82e9aa0SEli Cohen 
4189fab1e24aSHadar Hen Zion ex_detach:
4190fab1e24aSHadar Hen Zion 	qp_detach(dev, &qp, gid, prot, type, reg_id);
4191c82e9aa0SEli Cohen ex_put:
4192c82e9aa0SEli Cohen 	put_res(dev, slave, qpn, RES_QP);
4193c82e9aa0SEli Cohen 	return err;
4194c82e9aa0SEli Cohen }
4195c82e9aa0SEli Cohen 
41967fb40f87SHadar Hen Zion /*
41977fb40f87SHadar Hen Zion  * MAC validation for Flow Steering rules.
41987fb40f87SHadar Hen Zion  * VF can attach rules only with a mac address which is assigned to it.
41997fb40f87SHadar Hen Zion  */
validate_eth_header_mac(int slave,struct _rule_hw * eth_header,struct list_head * rlist)42007fb40f87SHadar Hen Zion static int validate_eth_header_mac(int slave, struct _rule_hw *eth_header,
42017fb40f87SHadar Hen Zion 				   struct list_head *rlist)
42027fb40f87SHadar Hen Zion {
42037fb40f87SHadar Hen Zion 	struct mac_res *res, *tmp;
42047fb40f87SHadar Hen Zion 	__be64 be_mac;
42057fb40f87SHadar Hen Zion 
42067fb40f87SHadar Hen Zion 	/* make sure it isn't multicast or broadcast mac*/
42077fb40f87SHadar Hen Zion 	if (!is_multicast_ether_addr(eth_header->eth.dst_mac) &&
42087fb40f87SHadar Hen Zion 	    !is_broadcast_ether_addr(eth_header->eth.dst_mac)) {
42097fb40f87SHadar Hen Zion 		list_for_each_entry_safe(res, tmp, rlist, list) {
42107fb40f87SHadar Hen Zion 			be_mac = cpu_to_be64(res->mac << 16);
4211c0623e58Sdingtianhong 			if (ether_addr_equal((u8 *)&be_mac, eth_header->eth.dst_mac))
42127fb40f87SHadar Hen Zion 				return 0;
42137fb40f87SHadar Hen Zion 		}
42147fb40f87SHadar Hen Zion 		pr_err("MAC %pM doesn't belong to VF %d, Steering rule rejected\n",
42157fb40f87SHadar Hen Zion 		       eth_header->eth.dst_mac, slave);
42167fb40f87SHadar Hen Zion 		return -EINVAL;
42177fb40f87SHadar Hen Zion 	}
42187fb40f87SHadar Hen Zion 	return 0;
42197fb40f87SHadar Hen Zion }
42207fb40f87SHadar Hen Zion 
42217fb40f87SHadar Hen Zion /*
42227fb40f87SHadar Hen Zion  * In case of missing eth header, append eth header with a MAC address
42237fb40f87SHadar Hen Zion  * assigned to the VF.
42247fb40f87SHadar Hen Zion  */
add_eth_header(struct mlx4_dev * dev,int slave,struct mlx4_cmd_mailbox * inbox,struct list_head * rlist,int header_id)42257fb40f87SHadar Hen Zion static int add_eth_header(struct mlx4_dev *dev, int slave,
42267fb40f87SHadar Hen Zion 			  struct mlx4_cmd_mailbox *inbox,
42277fb40f87SHadar Hen Zion 			  struct list_head *rlist, int header_id)
42287fb40f87SHadar Hen Zion {
42297fb40f87SHadar Hen Zion 	struct mac_res *res, *tmp;
42307fb40f87SHadar Hen Zion 	u8 port;
42317fb40f87SHadar Hen Zion 	struct mlx4_net_trans_rule_hw_ctrl *ctrl;
42327fb40f87SHadar Hen Zion 	struct mlx4_net_trans_rule_hw_eth *eth_header;
42337fb40f87SHadar Hen Zion 	struct mlx4_net_trans_rule_hw_ipv4 *ip_header;
42347fb40f87SHadar Hen Zion 	struct mlx4_net_trans_rule_hw_tcp_udp *l4_header;
42357fb40f87SHadar Hen Zion 	__be64 be_mac = 0;
42367fb40f87SHadar Hen Zion 	__be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16);
42377fb40f87SHadar Hen Zion 
42387fb40f87SHadar Hen Zion 	ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
4239015465f8SHadar Hen Zion 	port = ctrl->port;
42407fb40f87SHadar Hen Zion 	eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1);
42417fb40f87SHadar Hen Zion 
42427fb40f87SHadar Hen Zion 	/* Clear a space in the inbox for eth header */
42437fb40f87SHadar Hen Zion 	switch (header_id) {
42447fb40f87SHadar Hen Zion 	case MLX4_NET_TRANS_RULE_ID_IPV4:
42457fb40f87SHadar Hen Zion 		ip_header =
42467fb40f87SHadar Hen Zion 			(struct mlx4_net_trans_rule_hw_ipv4 *)(eth_header + 1);
42477fb40f87SHadar Hen Zion 		memmove(ip_header, eth_header,
42487fb40f87SHadar Hen Zion 			sizeof(*ip_header) + sizeof(*l4_header));
42497fb40f87SHadar Hen Zion 		break;
42507fb40f87SHadar Hen Zion 	case MLX4_NET_TRANS_RULE_ID_TCP:
42517fb40f87SHadar Hen Zion 	case MLX4_NET_TRANS_RULE_ID_UDP:
42527fb40f87SHadar Hen Zion 		l4_header = (struct mlx4_net_trans_rule_hw_tcp_udp *)
42537fb40f87SHadar Hen Zion 			    (eth_header + 1);
42547fb40f87SHadar Hen Zion 		memmove(l4_header, eth_header, sizeof(*l4_header));
42557fb40f87SHadar Hen Zion 		break;
42567fb40f87SHadar Hen Zion 	default:
42577fb40f87SHadar Hen Zion 		return -EINVAL;
42587fb40f87SHadar Hen Zion 	}
42597fb40f87SHadar Hen Zion 	list_for_each_entry_safe(res, tmp, rlist, list) {
42607fb40f87SHadar Hen Zion 		if (port == res->port) {
42617fb40f87SHadar Hen Zion 			be_mac = cpu_to_be64(res->mac << 16);
42627fb40f87SHadar Hen Zion 			break;
42637fb40f87SHadar Hen Zion 		}
42647fb40f87SHadar Hen Zion 	}
42657fb40f87SHadar Hen Zion 	if (!be_mac) {
42661a91de28SJoe Perches 		pr_err("Failed adding eth header to FS rule, Can't find matching MAC for port %d\n",
42677fb40f87SHadar Hen Zion 		       port);
42687fb40f87SHadar Hen Zion 		return -EINVAL;
42697fb40f87SHadar Hen Zion 	}
42707fb40f87SHadar Hen Zion 
42717fb40f87SHadar Hen Zion 	memset(eth_header, 0, sizeof(*eth_header));
42727fb40f87SHadar Hen Zion 	eth_header->size = sizeof(*eth_header) >> 2;
42737fb40f87SHadar Hen Zion 	eth_header->id = cpu_to_be16(__sw_id_hw[MLX4_NET_TRANS_RULE_ID_ETH]);
42747fb40f87SHadar Hen Zion 	memcpy(eth_header->dst_mac, &be_mac, ETH_ALEN);
42757fb40f87SHadar Hen Zion 	memcpy(eth_header->dst_mac_msk, &mac_msk, ETH_ALEN);
42767fb40f87SHadar Hen Zion 
42777fb40f87SHadar Hen Zion 	return 0;
42787fb40f87SHadar Hen Zion 
42797fb40f87SHadar Hen Zion }
42807fb40f87SHadar Hen Zion 
42819a892835SMaor Gottlieb #define MLX4_UPD_QP_PATH_MASK_SUPPORTED      (                                \
42829a892835SMaor Gottlieb 	1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX                     |\
42839a892835SMaor Gottlieb 	1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB)
mlx4_UPDATE_QP_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd_info)4284ce8d9e0dSMatan Barak int mlx4_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave,
4285ce8d9e0dSMatan Barak 			   struct mlx4_vhcr *vhcr,
4286ce8d9e0dSMatan Barak 			   struct mlx4_cmd_mailbox *inbox,
4287ce8d9e0dSMatan Barak 			   struct mlx4_cmd_mailbox *outbox,
4288ce8d9e0dSMatan Barak 			   struct mlx4_cmd_info *cmd_info)
4289ce8d9e0dSMatan Barak {
4290ce8d9e0dSMatan Barak 	int err;
4291ce8d9e0dSMatan Barak 	u32 qpn = vhcr->in_modifier & 0xffffff;
4292ce8d9e0dSMatan Barak 	struct res_qp *rqp;
4293ce8d9e0dSMatan Barak 	u64 mac;
4294ce8d9e0dSMatan Barak 	unsigned port;
4295ce8d9e0dSMatan Barak 	u64 pri_addr_path_mask;
4296ce8d9e0dSMatan Barak 	struct mlx4_update_qp_context *cmd;
4297ce8d9e0dSMatan Barak 	int smac_index;
4298ce8d9e0dSMatan Barak 
4299ce8d9e0dSMatan Barak 	cmd = (struct mlx4_update_qp_context *)inbox->buf;
4300ce8d9e0dSMatan Barak 
4301ce8d9e0dSMatan Barak 	pri_addr_path_mask = be64_to_cpu(cmd->primary_addr_path_mask);
4302ce8d9e0dSMatan Barak 	if (cmd->qp_mask || cmd->secondary_addr_path_mask ||
4303ce8d9e0dSMatan Barak 	    (pri_addr_path_mask & ~MLX4_UPD_QP_PATH_MASK_SUPPORTED))
4304ce8d9e0dSMatan Barak 		return -EPERM;
4305ce8d9e0dSMatan Barak 
43069a892835SMaor Gottlieb 	if ((pri_addr_path_mask &
43079a892835SMaor Gottlieb 	     (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB)) &&
43089a892835SMaor Gottlieb 		!(dev->caps.flags2 &
43099a892835SMaor Gottlieb 		  MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB)) {
43105d4de16cSChristophe Jaillet 		mlx4_warn(dev, "Src check LB for slave %d isn't supported\n",
43119a892835SMaor Gottlieb 			  slave);
4312423b3aecSOr Gerlitz 		return -EOPNOTSUPP;
43139a892835SMaor Gottlieb 	}
43149a892835SMaor Gottlieb 
4315ce8d9e0dSMatan Barak 	/* Just change the smac for the QP */
4316ce8d9e0dSMatan Barak 	err = get_res(dev, slave, qpn, RES_QP, &rqp);
4317ce8d9e0dSMatan Barak 	if (err) {
4318ce8d9e0dSMatan Barak 		mlx4_err(dev, "Updating qpn 0x%x for slave %d rejected\n", qpn, slave);
4319ce8d9e0dSMatan Barak 		return err;
4320ce8d9e0dSMatan Barak 	}
4321ce8d9e0dSMatan Barak 
4322ce8d9e0dSMatan Barak 	port = (rqp->sched_queue >> 6 & 1) + 1;
4323b7834758SMatan Barak 
4324b7834758SMatan Barak 	if (pri_addr_path_mask & (1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX)) {
4325ce8d9e0dSMatan Barak 		smac_index = cmd->qp_context.pri_path.grh_mylmc;
4326ce8d9e0dSMatan Barak 		err = mac_find_smac_ix_in_slave(dev, slave, port,
4327ce8d9e0dSMatan Barak 						smac_index, &mac);
4328b7834758SMatan Barak 
4329ce8d9e0dSMatan Barak 		if (err) {
4330ce8d9e0dSMatan Barak 			mlx4_err(dev, "Failed to update qpn 0x%x, MAC is invalid. smac_ix: %d\n",
4331ce8d9e0dSMatan Barak 				 qpn, smac_index);
4332ce8d9e0dSMatan Barak 			goto err_mac;
4333ce8d9e0dSMatan Barak 		}
4334b7834758SMatan Barak 	}
4335ce8d9e0dSMatan Barak 
4336ce8d9e0dSMatan Barak 	err = mlx4_cmd(dev, inbox->dma,
4337ce8d9e0dSMatan Barak 		       vhcr->in_modifier, 0,
4338ce8d9e0dSMatan Barak 		       MLX4_CMD_UPDATE_QP, MLX4_CMD_TIME_CLASS_A,
4339ce8d9e0dSMatan Barak 		       MLX4_CMD_NATIVE);
4340ce8d9e0dSMatan Barak 	if (err) {
4341ce8d9e0dSMatan Barak 		mlx4_err(dev, "Failed to update qpn on qpn 0x%x, command failed\n", qpn);
4342ce8d9e0dSMatan Barak 		goto err_mac;
4343ce8d9e0dSMatan Barak 	}
4344ce8d9e0dSMatan Barak 
4345ce8d9e0dSMatan Barak err_mac:
4346ce8d9e0dSMatan Barak 	put_res(dev, slave, qpn, RES_QP);
4347ce8d9e0dSMatan Barak 	return err;
4348ce8d9e0dSMatan Barak }
4349ce8d9e0dSMatan Barak 
qp_attach_mbox_size(void * mbox)435078efed27SMoni Shoua static u32 qp_attach_mbox_size(void *mbox)
435178efed27SMoni Shoua {
435278efed27SMoni Shoua 	u32 size = sizeof(struct mlx4_net_trans_rule_hw_ctrl);
435378efed27SMoni Shoua 	struct _rule_hw  *rule_header;
435478efed27SMoni Shoua 
435578efed27SMoni Shoua 	rule_header = (struct _rule_hw *)(mbox + size);
435678efed27SMoni Shoua 
435778efed27SMoni Shoua 	while (rule_header->size) {
435878efed27SMoni Shoua 		size += rule_header->size * sizeof(u32);
435978efed27SMoni Shoua 		rule_header += 1;
436078efed27SMoni Shoua 	}
436178efed27SMoni Shoua 	return size;
436278efed27SMoni Shoua }
436378efed27SMoni Shoua 
436478efed27SMoni Shoua static int mlx4_do_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule);
436578efed27SMoni Shoua 
mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)43668fcfb4dbSHadar Hen Zion int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
43678fcfb4dbSHadar Hen Zion 					 struct mlx4_vhcr *vhcr,
43688fcfb4dbSHadar Hen Zion 					 struct mlx4_cmd_mailbox *inbox,
43698fcfb4dbSHadar Hen Zion 					 struct mlx4_cmd_mailbox *outbox,
43708fcfb4dbSHadar Hen Zion 					 struct mlx4_cmd_info *cmd)
43718fcfb4dbSHadar Hen Zion {
43727fb40f87SHadar Hen Zion 
43737fb40f87SHadar Hen Zion 	struct mlx4_priv *priv = mlx4_priv(dev);
43747fb40f87SHadar Hen Zion 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
43757fb40f87SHadar Hen Zion 	struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC];
43761b9c6b06SHadar Hen Zion 	int err;
4377a9c01e7aSHadar Hen Zion 	int qpn;
43782c473ae7SHadar Hen Zion 	struct res_qp *rqp;
43797fb40f87SHadar Hen Zion 	struct mlx4_net_trans_rule_hw_ctrl *ctrl;
43807fb40f87SHadar Hen Zion 	struct _rule_hw  *rule_header;
43817fb40f87SHadar Hen Zion 	int header_id;
438278efed27SMoni Shoua 	struct res_fs_rule *rrule;
438378efed27SMoni Shoua 	u32 mbox_size;
43841b9c6b06SHadar Hen Zion 
43850ff1fb65SHadar Hen Zion 	if (dev->caps.steering_mode !=
43860ff1fb65SHadar Hen Zion 	    MLX4_STEERING_MODE_DEVICE_MANAGED)
43870ff1fb65SHadar Hen Zion 		return -EOPNOTSUPP;
43881b9c6b06SHadar Hen Zion 
43897fb40f87SHadar Hen Zion 	ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
43902b2b31c8SAndrzej Hajda 	err = mlx4_slave_convert_port(dev, slave, ctrl->port);
43912b2b31c8SAndrzej Hajda 	if (err <= 0)
4392449fc488SMatan Barak 		return -EINVAL;
43932b2b31c8SAndrzej Hajda 	ctrl->port = err;
4394a9c01e7aSHadar Hen Zion 	qpn = be32_to_cpu(ctrl->qpn) & 0xffffff;
43952c473ae7SHadar Hen Zion 	err = get_res(dev, slave, qpn, RES_QP, &rqp);
4396a9c01e7aSHadar Hen Zion 	if (err) {
43971a91de28SJoe Perches 		pr_err("Steering rule with qpn 0x%x rejected\n", qpn);
4398a9c01e7aSHadar Hen Zion 		return err;
4399a9c01e7aSHadar Hen Zion 	}
44007fb40f87SHadar Hen Zion 	rule_header = (struct _rule_hw *)(ctrl + 1);
44017fb40f87SHadar Hen Zion 	header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id));
44027fb40f87SHadar Hen Zion 
440348564135SMatan Barak 	if (header_id == MLX4_NET_TRANS_RULE_ID_ETH)
440410b1c04eSJack Morgenstein 		mlx4_handle_eth_header_mcast_prio(ctrl, rule_header);
440548564135SMatan Barak 
44067fb40f87SHadar Hen Zion 	switch (header_id) {
44077fb40f87SHadar Hen Zion 	case MLX4_NET_TRANS_RULE_ID_ETH:
4408a9c01e7aSHadar Hen Zion 		if (validate_eth_header_mac(slave, rule_header, rlist)) {
4409a9c01e7aSHadar Hen Zion 			err = -EINVAL;
441078efed27SMoni Shoua 			goto err_put_qp;
4411a9c01e7aSHadar Hen Zion 		}
44127fb40f87SHadar Hen Zion 		break;
441360396683SJack Morgenstein 	case MLX4_NET_TRANS_RULE_ID_IB:
441460396683SJack Morgenstein 		break;
44157fb40f87SHadar Hen Zion 	case MLX4_NET_TRANS_RULE_ID_IPV4:
44167fb40f87SHadar Hen Zion 	case MLX4_NET_TRANS_RULE_ID_TCP:
44177fb40f87SHadar Hen Zion 	case MLX4_NET_TRANS_RULE_ID_UDP:
44181a91de28SJoe Perches 		pr_warn("Can't attach FS rule without L2 headers, adding L2 header\n");
4419a9c01e7aSHadar Hen Zion 		if (add_eth_header(dev, slave, inbox, rlist, header_id)) {
4420a9c01e7aSHadar Hen Zion 			err = -EINVAL;
442178efed27SMoni Shoua 			goto err_put_qp;
4422a9c01e7aSHadar Hen Zion 		}
44237fb40f87SHadar Hen Zion 		vhcr->in_modifier +=
44247fb40f87SHadar Hen Zion 			sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2;
44257fb40f87SHadar Hen Zion 		break;
44267fb40f87SHadar Hen Zion 	default:
44271a91de28SJoe Perches 		pr_err("Corrupted mailbox\n");
4428a9c01e7aSHadar Hen Zion 		err = -EINVAL;
442978efed27SMoni Shoua 		goto err_put_qp;
44307fb40f87SHadar Hen Zion 	}
44317fb40f87SHadar Hen Zion 
44321b9c6b06SHadar Hen Zion 	err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param,
44338fcfb4dbSHadar Hen Zion 			   vhcr->in_modifier, 0,
44341b9c6b06SHadar Hen Zion 			   MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
44358fcfb4dbSHadar Hen Zion 			   MLX4_CMD_NATIVE);
44361b9c6b06SHadar Hen Zion 	if (err)
443778efed27SMoni Shoua 		goto err_put_qp;
443878efed27SMoni Shoua 
44391b9c6b06SHadar Hen Zion 
44402c473ae7SHadar Hen Zion 	err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn);
44411b9c6b06SHadar Hen Zion 	if (err) {
44421a91de28SJoe Perches 		mlx4_err(dev, "Fail to add flow steering resources\n");
444378efed27SMoni Shoua 		goto err_detach;
444478efed27SMoni Shoua 	}
444578efed27SMoni Shoua 
444678efed27SMoni Shoua 	err = get_res(dev, slave, vhcr->out_param, RES_FS_RULE, &rrule);
444778efed27SMoni Shoua 	if (err)
444878efed27SMoni Shoua 		goto err_detach;
444978efed27SMoni Shoua 
445078efed27SMoni Shoua 	mbox_size = qp_attach_mbox_size(inbox->buf);
445178efed27SMoni Shoua 	rrule->mirr_mbox = kmalloc(mbox_size, GFP_KERNEL);
445278efed27SMoni Shoua 	if (!rrule->mirr_mbox) {
445378efed27SMoni Shoua 		err = -ENOMEM;
445478efed27SMoni Shoua 		goto err_put_rule;
445578efed27SMoni Shoua 	}
445678efed27SMoni Shoua 	rrule->mirr_mbox_size = mbox_size;
445778efed27SMoni Shoua 	rrule->mirr_rule_id = 0;
445878efed27SMoni Shoua 	memcpy(rrule->mirr_mbox, inbox->buf, mbox_size);
445978efed27SMoni Shoua 
446078efed27SMoni Shoua 	/* set different port */
446178efed27SMoni Shoua 	ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)rrule->mirr_mbox;
446278efed27SMoni Shoua 	if (ctrl->port == 1)
446378efed27SMoni Shoua 		ctrl->port = 2;
446478efed27SMoni Shoua 	else
446578efed27SMoni Shoua 		ctrl->port = 1;
446678efed27SMoni Shoua 
446778efed27SMoni Shoua 	if (mlx4_is_bonded(dev))
446878efed27SMoni Shoua 		mlx4_do_mirror_rule(dev, rrule);
446978efed27SMoni Shoua 
447078efed27SMoni Shoua 	atomic_inc(&rqp->ref_count);
447178efed27SMoni Shoua 
447278efed27SMoni Shoua err_put_rule:
447378efed27SMoni Shoua 	put_res(dev, slave, vhcr->out_param, RES_FS_RULE);
447478efed27SMoni Shoua err_detach:
447578efed27SMoni Shoua 	/* detach rule on error */
447678efed27SMoni Shoua 	if (err)
44771b9c6b06SHadar Hen Zion 		mlx4_cmd(dev, vhcr->out_param, 0, 0,
44782065b38bSHadar Hen Zion 			 MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
44791b9c6b06SHadar Hen Zion 			 MLX4_CMD_NATIVE);
448078efed27SMoni Shoua err_put_qp:
4481a9c01e7aSHadar Hen Zion 	put_res(dev, slave, qpn, RES_QP);
44821b9c6b06SHadar Hen Zion 	return err;
44838fcfb4dbSHadar Hen Zion }
44848fcfb4dbSHadar Hen Zion 
mlx4_undo_mirror_rule(struct mlx4_dev * dev,struct res_fs_rule * fs_rule)448578efed27SMoni Shoua static int mlx4_undo_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule)
448678efed27SMoni Shoua {
448778efed27SMoni Shoua 	int err;
448878efed27SMoni Shoua 
448978efed27SMoni Shoua 	err = rem_res_range(dev, fs_rule->com.owner, fs_rule->com.res_id, 1, RES_FS_RULE, 0);
449078efed27SMoni Shoua 	if (err) {
449178efed27SMoni Shoua 		mlx4_err(dev, "Fail to remove flow steering resources\n");
449278efed27SMoni Shoua 		return err;
449378efed27SMoni Shoua 	}
449478efed27SMoni Shoua 
449578efed27SMoni Shoua 	mlx4_cmd(dev, fs_rule->com.res_id, 0, 0, MLX4_QP_FLOW_STEERING_DETACH,
449678efed27SMoni Shoua 		 MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
449778efed27SMoni Shoua 	return 0;
449878efed27SMoni Shoua }
449978efed27SMoni Shoua 
mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)45008fcfb4dbSHadar Hen Zion int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave,
45018fcfb4dbSHadar Hen Zion 					 struct mlx4_vhcr *vhcr,
45028fcfb4dbSHadar Hen Zion 					 struct mlx4_cmd_mailbox *inbox,
45038fcfb4dbSHadar Hen Zion 					 struct mlx4_cmd_mailbox *outbox,
45048fcfb4dbSHadar Hen Zion 					 struct mlx4_cmd_info *cmd)
45058fcfb4dbSHadar Hen Zion {
45061b9c6b06SHadar Hen Zion 	int err;
45072c473ae7SHadar Hen Zion 	struct res_qp *rqp;
45082c473ae7SHadar Hen Zion 	struct res_fs_rule *rrule;
450978efed27SMoni Shoua 	u64 mirr_reg_id;
45103b01fe7fSJack Morgenstein 	int qpn;
45111b9c6b06SHadar Hen Zion 
45120ff1fb65SHadar Hen Zion 	if (dev->caps.steering_mode !=
45130ff1fb65SHadar Hen Zion 	    MLX4_STEERING_MODE_DEVICE_MANAGED)
45140ff1fb65SHadar Hen Zion 		return -EOPNOTSUPP;
45151b9c6b06SHadar Hen Zion 
45162c473ae7SHadar Hen Zion 	err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule);
45172c473ae7SHadar Hen Zion 	if (err)
45182c473ae7SHadar Hen Zion 		return err;
451978efed27SMoni Shoua 
452078efed27SMoni Shoua 	if (!rrule->mirr_mbox) {
452178efed27SMoni Shoua 		mlx4_err(dev, "Mirror rules cannot be removed explicitly\n");
452278efed27SMoni Shoua 		put_res(dev, slave, vhcr->in_param, RES_FS_RULE);
452378efed27SMoni Shoua 		return -EINVAL;
452478efed27SMoni Shoua 	}
452578efed27SMoni Shoua 	mirr_reg_id = rrule->mirr_rule_id;
452678efed27SMoni Shoua 	kfree(rrule->mirr_mbox);
45273b01fe7fSJack Morgenstein 	qpn = rrule->qpn;
452878efed27SMoni Shoua 
45292c473ae7SHadar Hen Zion 	/* Release the rule form busy state before removal */
45302c473ae7SHadar Hen Zion 	put_res(dev, slave, vhcr->in_param, RES_FS_RULE);
45313b01fe7fSJack Morgenstein 	err = get_res(dev, slave, qpn, RES_QP, &rqp);
45322c473ae7SHadar Hen Zion 	if (err)
45332c473ae7SHadar Hen Zion 		return err;
45342c473ae7SHadar Hen Zion 
453578efed27SMoni Shoua 	if (mirr_reg_id && mlx4_is_bonded(dev)) {
453678efed27SMoni Shoua 		err = get_res(dev, slave, mirr_reg_id, RES_FS_RULE, &rrule);
453778efed27SMoni Shoua 		if (err) {
453878efed27SMoni Shoua 			mlx4_err(dev, "Fail to get resource of mirror rule\n");
453978efed27SMoni Shoua 		} else {
454078efed27SMoni Shoua 			put_res(dev, slave, mirr_reg_id, RES_FS_RULE);
454178efed27SMoni Shoua 			mlx4_undo_mirror_rule(dev, rrule);
454278efed27SMoni Shoua 		}
454378efed27SMoni Shoua 	}
45441b9c6b06SHadar Hen Zion 	err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 0);
45451b9c6b06SHadar Hen Zion 	if (err) {
45461a91de28SJoe Perches 		mlx4_err(dev, "Fail to remove flow steering resources\n");
45472c473ae7SHadar Hen Zion 		goto out;
45481b9c6b06SHadar Hen Zion 	}
45491b9c6b06SHadar Hen Zion 
45501b9c6b06SHadar Hen Zion 	err = mlx4_cmd(dev, vhcr->in_param, 0, 0,
45518fcfb4dbSHadar Hen Zion 		       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
45528fcfb4dbSHadar Hen Zion 		       MLX4_CMD_NATIVE);
45532c473ae7SHadar Hen Zion 	if (!err)
45542c473ae7SHadar Hen Zion 		atomic_dec(&rqp->ref_count);
45552c473ae7SHadar Hen Zion out:
45563b01fe7fSJack Morgenstein 	put_res(dev, slave, qpn, RES_QP);
45571b9c6b06SHadar Hen Zion 	return err;
45588fcfb4dbSHadar Hen Zion }
45598fcfb4dbSHadar Hen Zion 
4560c82e9aa0SEli Cohen enum {
4561c82e9aa0SEli Cohen 	BUSY_MAX_RETRIES = 10
4562c82e9aa0SEli Cohen };
4563c82e9aa0SEli Cohen 
mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)4564c82e9aa0SEli Cohen int mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave,
4565c82e9aa0SEli Cohen 			       struct mlx4_vhcr *vhcr,
4566c82e9aa0SEli Cohen 			       struct mlx4_cmd_mailbox *inbox,
4567c82e9aa0SEli Cohen 			       struct mlx4_cmd_mailbox *outbox,
4568c82e9aa0SEli Cohen 			       struct mlx4_cmd_info *cmd)
4569c82e9aa0SEli Cohen {
4570c82e9aa0SEli Cohen 	int err;
4571c82e9aa0SEli Cohen 	int index = vhcr->in_modifier & 0xffff;
4572c82e9aa0SEli Cohen 
4573c82e9aa0SEli Cohen 	err = get_res(dev, slave, index, RES_COUNTER, NULL);
4574c82e9aa0SEli Cohen 	if (err)
4575c82e9aa0SEli Cohen 		return err;
4576c82e9aa0SEli Cohen 
4577c82e9aa0SEli Cohen 	err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
4578c82e9aa0SEli Cohen 	put_res(dev, slave, index, RES_COUNTER);
4579c82e9aa0SEli Cohen 	return err;
4580c82e9aa0SEli Cohen }
4581c82e9aa0SEli Cohen 
detach_qp(struct mlx4_dev * dev,int slave,struct res_qp * rqp)4582c82e9aa0SEli Cohen static void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp)
4583c82e9aa0SEli Cohen {
4584c82e9aa0SEli Cohen 	struct res_gid *rgid;
4585c82e9aa0SEli Cohen 	struct res_gid *tmp;
4586c82e9aa0SEli Cohen 	struct mlx4_qp qp; /* dummy for calling attach/detach */
4587c82e9aa0SEli Cohen 
4588c82e9aa0SEli Cohen 	list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) {
4589fab1e24aSHadar Hen Zion 		switch (dev->caps.steering_mode) {
4590fab1e24aSHadar Hen Zion 		case MLX4_STEERING_MODE_DEVICE_MANAGED:
4591fab1e24aSHadar Hen Zion 			mlx4_flow_detach(dev, rgid->reg_id);
4592fab1e24aSHadar Hen Zion 			break;
4593fab1e24aSHadar Hen Zion 		case MLX4_STEERING_MODE_B0:
4594c82e9aa0SEli Cohen 			qp.qpn = rqp->local_qpn;
4595fab1e24aSHadar Hen Zion 			(void) mlx4_qp_detach_common(dev, &qp, rgid->gid,
4596fab1e24aSHadar Hen Zion 						     rgid->prot, rgid->steer);
4597fab1e24aSHadar Hen Zion 			break;
4598fab1e24aSHadar Hen Zion 		}
4599c82e9aa0SEli Cohen 		list_del(&rgid->list);
4600c82e9aa0SEli Cohen 		kfree(rgid);
4601c82e9aa0SEli Cohen 	}
4602c82e9aa0SEli Cohen }
4603c82e9aa0SEli Cohen 
_move_all_busy(struct mlx4_dev * dev,int slave,enum mlx4_resource type,int print)4604c82e9aa0SEli Cohen static int _move_all_busy(struct mlx4_dev *dev, int slave,
4605c82e9aa0SEli Cohen 			  enum mlx4_resource type, int print)
4606c82e9aa0SEli Cohen {
4607c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
4608c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker =
4609c82e9aa0SEli Cohen 		&priv->mfunc.master.res_tracker;
4610c82e9aa0SEli Cohen 	struct list_head *rlist = &tracker->slave_list[slave].res_list[type];
4611c82e9aa0SEli Cohen 	struct res_common *r;
4612c82e9aa0SEli Cohen 	struct res_common *tmp;
4613c82e9aa0SEli Cohen 	int busy;
4614c82e9aa0SEli Cohen 
4615c82e9aa0SEli Cohen 	busy = 0;
4616c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
4617c82e9aa0SEli Cohen 	list_for_each_entry_safe(r, tmp, rlist, list) {
4618c82e9aa0SEli Cohen 		if (r->owner == slave) {
4619c82e9aa0SEli Cohen 			if (!r->removing) {
4620c82e9aa0SEli Cohen 				if (r->state == RES_ANY_BUSY) {
4621c82e9aa0SEli Cohen 					if (print)
4622c82e9aa0SEli Cohen 						mlx4_dbg(dev,
4623aa1ec3ddSHadar Hen Zion 							 "%s id 0x%llx is busy\n",
462495646373SJack Morgenstein 							  resource_str(type),
4625c82e9aa0SEli Cohen 							  r->res_id);
4626c82e9aa0SEli Cohen 					++busy;
4627c82e9aa0SEli Cohen 				} else {
4628c82e9aa0SEli Cohen 					r->from_state = r->state;
4629c82e9aa0SEli Cohen 					r->state = RES_ANY_BUSY;
4630c82e9aa0SEli Cohen 					r->removing = 1;
4631c82e9aa0SEli Cohen 				}
4632c82e9aa0SEli Cohen 			}
4633c82e9aa0SEli Cohen 		}
4634c82e9aa0SEli Cohen 	}
4635c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
4636c82e9aa0SEli Cohen 
4637c82e9aa0SEli Cohen 	return busy;
4638c82e9aa0SEli Cohen }
4639c82e9aa0SEli Cohen 
move_all_busy(struct mlx4_dev * dev,int slave,enum mlx4_resource type)4640c82e9aa0SEli Cohen static int move_all_busy(struct mlx4_dev *dev, int slave,
4641c82e9aa0SEli Cohen 			 enum mlx4_resource type)
4642c82e9aa0SEli Cohen {
4643c82e9aa0SEli Cohen 	unsigned long begin;
4644c82e9aa0SEli Cohen 	int busy;
4645c82e9aa0SEli Cohen 
4646c82e9aa0SEli Cohen 	begin = jiffies;
4647c82e9aa0SEli Cohen 	do {
4648c82e9aa0SEli Cohen 		busy = _move_all_busy(dev, slave, type, 0);
4649c82e9aa0SEli Cohen 		if (time_after(jiffies, begin + 5 * HZ))
4650c82e9aa0SEli Cohen 			break;
4651c82e9aa0SEli Cohen 		if (busy)
4652c82e9aa0SEli Cohen 			cond_resched();
4653c82e9aa0SEli Cohen 	} while (busy);
4654c82e9aa0SEli Cohen 
4655c82e9aa0SEli Cohen 	if (busy)
4656c82e9aa0SEli Cohen 		busy = _move_all_busy(dev, slave, type, 1);
4657c82e9aa0SEli Cohen 
4658c82e9aa0SEli Cohen 	return busy;
4659c82e9aa0SEli Cohen }
rem_slave_qps(struct mlx4_dev * dev,int slave)4660c82e9aa0SEli Cohen static void rem_slave_qps(struct mlx4_dev *dev, int slave)
4661c82e9aa0SEli Cohen {
4662c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
4663c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
4664c82e9aa0SEli Cohen 	struct list_head *qp_list =
4665c82e9aa0SEli Cohen 		&tracker->slave_list[slave].res_list[RES_QP];
4666c82e9aa0SEli Cohen 	struct res_qp *qp;
4667c82e9aa0SEli Cohen 	struct res_qp *tmp;
4668c82e9aa0SEli Cohen 	int state;
4669c82e9aa0SEli Cohen 	u64 in_param;
4670c82e9aa0SEli Cohen 	int qpn;
4671c82e9aa0SEli Cohen 	int err;
4672c82e9aa0SEli Cohen 
4673c82e9aa0SEli Cohen 	err = move_all_busy(dev, slave, RES_QP);
4674c82e9aa0SEli Cohen 	if (err)
46751a91de28SJoe Perches 		mlx4_warn(dev, "rem_slave_qps: Could not move all qps to busy for slave %d\n",
46761a91de28SJoe Perches 			  slave);
4677c82e9aa0SEli Cohen 
4678c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
4679c82e9aa0SEli Cohen 	list_for_each_entry_safe(qp, tmp, qp_list, com.list) {
4680c82e9aa0SEli Cohen 		spin_unlock_irq(mlx4_tlock(dev));
4681c82e9aa0SEli Cohen 		if (qp->com.owner == slave) {
4682c82e9aa0SEli Cohen 			qpn = qp->com.res_id;
4683c82e9aa0SEli Cohen 			detach_qp(dev, slave, qp);
4684c82e9aa0SEli Cohen 			state = qp->com.from_state;
4685c82e9aa0SEli Cohen 			while (state != 0) {
4686c82e9aa0SEli Cohen 				switch (state) {
4687c82e9aa0SEli Cohen 				case RES_QP_RESERVED:
4688c82e9aa0SEli Cohen 					spin_lock_irq(mlx4_tlock(dev));
46894af1c048SHadar Hen Zion 					rb_erase(&qp->com.node,
46904af1c048SHadar Hen Zion 						 &tracker->res_tree[RES_QP]);
4691c82e9aa0SEli Cohen 					list_del(&qp->com.list);
4692c82e9aa0SEli Cohen 					spin_unlock_irq(mlx4_tlock(dev));
4693146f3ef4SJack Morgenstein 					if (!valid_reserved(dev, slave, qpn)) {
4694146f3ef4SJack Morgenstein 						__mlx4_qp_release_range(dev, qpn, 1);
4695146f3ef4SJack Morgenstein 						mlx4_release_resource(dev, slave,
4696146f3ef4SJack Morgenstein 								      RES_QP, 1, 0);
4697146f3ef4SJack Morgenstein 					}
4698c82e9aa0SEli Cohen 					kfree(qp);
4699c82e9aa0SEli Cohen 					state = 0;
4700c82e9aa0SEli Cohen 					break;
4701c82e9aa0SEli Cohen 				case RES_QP_MAPPED:
4702c82e9aa0SEli Cohen 					if (!valid_reserved(dev, slave, qpn))
4703c82e9aa0SEli Cohen 						__mlx4_qp_free_icm(dev, qpn);
4704c82e9aa0SEli Cohen 					state = RES_QP_RESERVED;
4705c82e9aa0SEli Cohen 					break;
4706c82e9aa0SEli Cohen 				case RES_QP_HW:
4707c82e9aa0SEli Cohen 					in_param = slave;
4708c82e9aa0SEli Cohen 					err = mlx4_cmd(dev, in_param,
4709c82e9aa0SEli Cohen 						       qp->local_qpn, 2,
4710c82e9aa0SEli Cohen 						       MLX4_CMD_2RST_QP,
4711c82e9aa0SEli Cohen 						       MLX4_CMD_TIME_CLASS_A,
4712c82e9aa0SEli Cohen 						       MLX4_CMD_NATIVE);
4713c82e9aa0SEli Cohen 					if (err)
47141a91de28SJoe Perches 						mlx4_dbg(dev, "rem_slave_qps: failed to move slave %d qpn %d to reset\n",
47151a91de28SJoe Perches 							 slave, qp->local_qpn);
4716c82e9aa0SEli Cohen 					atomic_dec(&qp->rcq->ref_count);
4717c82e9aa0SEli Cohen 					atomic_dec(&qp->scq->ref_count);
4718c82e9aa0SEli Cohen 					atomic_dec(&qp->mtt->ref_count);
4719c82e9aa0SEli Cohen 					if (qp->srq)
4720c82e9aa0SEli Cohen 						atomic_dec(&qp->srq->ref_count);
4721c82e9aa0SEli Cohen 					state = RES_QP_MAPPED;
4722c82e9aa0SEli Cohen 					break;
4723c82e9aa0SEli Cohen 				default:
4724c82e9aa0SEli Cohen 					state = 0;
4725c82e9aa0SEli Cohen 				}
4726c82e9aa0SEli Cohen 			}
4727c82e9aa0SEli Cohen 		}
4728c82e9aa0SEli Cohen 		spin_lock_irq(mlx4_tlock(dev));
4729c82e9aa0SEli Cohen 	}
4730c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
4731c82e9aa0SEli Cohen }
4732c82e9aa0SEli Cohen 
rem_slave_srqs(struct mlx4_dev * dev,int slave)4733c82e9aa0SEli Cohen static void rem_slave_srqs(struct mlx4_dev *dev, int slave)
4734c82e9aa0SEli Cohen {
4735c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
4736c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
4737c82e9aa0SEli Cohen 	struct list_head *srq_list =
4738c82e9aa0SEli Cohen 		&tracker->slave_list[slave].res_list[RES_SRQ];
4739c82e9aa0SEli Cohen 	struct res_srq *srq;
4740c82e9aa0SEli Cohen 	struct res_srq *tmp;
4741c82e9aa0SEli Cohen 	int state;
4742c82e9aa0SEli Cohen 	u64 in_param;
4743c82e9aa0SEli Cohen 	int srqn;
4744c82e9aa0SEli Cohen 	int err;
4745c82e9aa0SEli Cohen 
4746c82e9aa0SEli Cohen 	err = move_all_busy(dev, slave, RES_SRQ);
4747c82e9aa0SEli Cohen 	if (err)
47481a91de28SJoe Perches 		mlx4_warn(dev, "rem_slave_srqs: Could not move all srqs - too busy for slave %d\n",
47491a91de28SJoe Perches 			  slave);
4750c82e9aa0SEli Cohen 
4751c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
4752c82e9aa0SEli Cohen 	list_for_each_entry_safe(srq, tmp, srq_list, com.list) {
4753c82e9aa0SEli Cohen 		spin_unlock_irq(mlx4_tlock(dev));
4754c82e9aa0SEli Cohen 		if (srq->com.owner == slave) {
4755c82e9aa0SEli Cohen 			srqn = srq->com.res_id;
4756c82e9aa0SEli Cohen 			state = srq->com.from_state;
4757c82e9aa0SEli Cohen 			while (state != 0) {
4758c82e9aa0SEli Cohen 				switch (state) {
4759c82e9aa0SEli Cohen 				case RES_SRQ_ALLOCATED:
4760c82e9aa0SEli Cohen 					__mlx4_srq_free_icm(dev, srqn);
4761c82e9aa0SEli Cohen 					spin_lock_irq(mlx4_tlock(dev));
47624af1c048SHadar Hen Zion 					rb_erase(&srq->com.node,
47634af1c048SHadar Hen Zion 						 &tracker->res_tree[RES_SRQ]);
4764c82e9aa0SEli Cohen 					list_del(&srq->com.list);
4765c82e9aa0SEli Cohen 					spin_unlock_irq(mlx4_tlock(dev));
4766146f3ef4SJack Morgenstein 					mlx4_release_resource(dev, slave,
4767146f3ef4SJack Morgenstein 							      RES_SRQ, 1, 0);
4768c82e9aa0SEli Cohen 					kfree(srq);
4769c82e9aa0SEli Cohen 					state = 0;
4770c82e9aa0SEli Cohen 					break;
4771c82e9aa0SEli Cohen 
4772c82e9aa0SEli Cohen 				case RES_SRQ_HW:
4773c82e9aa0SEli Cohen 					in_param = slave;
4774c82e9aa0SEli Cohen 					err = mlx4_cmd(dev, in_param, srqn, 1,
4775c82e9aa0SEli Cohen 						       MLX4_CMD_HW2SW_SRQ,
4776c82e9aa0SEli Cohen 						       MLX4_CMD_TIME_CLASS_A,
4777c82e9aa0SEli Cohen 						       MLX4_CMD_NATIVE);
4778c82e9aa0SEli Cohen 					if (err)
47791a91de28SJoe Perches 						mlx4_dbg(dev, "rem_slave_srqs: failed to move slave %d srq %d to SW ownership\n",
4780c82e9aa0SEli Cohen 							 slave, srqn);
4781c82e9aa0SEli Cohen 
4782c82e9aa0SEli Cohen 					atomic_dec(&srq->mtt->ref_count);
4783c82e9aa0SEli Cohen 					if (srq->cq)
4784c82e9aa0SEli Cohen 						atomic_dec(&srq->cq->ref_count);
4785c82e9aa0SEli Cohen 					state = RES_SRQ_ALLOCATED;
4786c82e9aa0SEli Cohen 					break;
4787c82e9aa0SEli Cohen 
4788c82e9aa0SEli Cohen 				default:
4789c82e9aa0SEli Cohen 					state = 0;
4790c82e9aa0SEli Cohen 				}
4791c82e9aa0SEli Cohen 			}
4792c82e9aa0SEli Cohen 		}
4793c82e9aa0SEli Cohen 		spin_lock_irq(mlx4_tlock(dev));
4794c82e9aa0SEli Cohen 	}
4795c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
4796c82e9aa0SEli Cohen }
4797c82e9aa0SEli Cohen 
rem_slave_cqs(struct mlx4_dev * dev,int slave)4798c82e9aa0SEli Cohen static void rem_slave_cqs(struct mlx4_dev *dev, int slave)
4799c82e9aa0SEli Cohen {
4800c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
4801c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
4802c82e9aa0SEli Cohen 	struct list_head *cq_list =
4803c82e9aa0SEli Cohen 		&tracker->slave_list[slave].res_list[RES_CQ];
4804c82e9aa0SEli Cohen 	struct res_cq *cq;
4805c82e9aa0SEli Cohen 	struct res_cq *tmp;
4806c82e9aa0SEli Cohen 	int state;
4807c82e9aa0SEli Cohen 	u64 in_param;
4808c82e9aa0SEli Cohen 	int cqn;
4809c82e9aa0SEli Cohen 	int err;
4810c82e9aa0SEli Cohen 
4811c82e9aa0SEli Cohen 	err = move_all_busy(dev, slave, RES_CQ);
4812c82e9aa0SEli Cohen 	if (err)
48131a91de28SJoe Perches 		mlx4_warn(dev, "rem_slave_cqs: Could not move all cqs - too busy for slave %d\n",
48141a91de28SJoe Perches 			  slave);
4815c82e9aa0SEli Cohen 
4816c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
4817c82e9aa0SEli Cohen 	list_for_each_entry_safe(cq, tmp, cq_list, com.list) {
4818c82e9aa0SEli Cohen 		spin_unlock_irq(mlx4_tlock(dev));
4819c82e9aa0SEli Cohen 		if (cq->com.owner == slave && !atomic_read(&cq->ref_count)) {
4820c82e9aa0SEli Cohen 			cqn = cq->com.res_id;
4821c82e9aa0SEli Cohen 			state = cq->com.from_state;
4822c82e9aa0SEli Cohen 			while (state != 0) {
4823c82e9aa0SEli Cohen 				switch (state) {
4824c82e9aa0SEli Cohen 				case RES_CQ_ALLOCATED:
4825c82e9aa0SEli Cohen 					__mlx4_cq_free_icm(dev, cqn);
4826c82e9aa0SEli Cohen 					spin_lock_irq(mlx4_tlock(dev));
48274af1c048SHadar Hen Zion 					rb_erase(&cq->com.node,
48284af1c048SHadar Hen Zion 						 &tracker->res_tree[RES_CQ]);
4829c82e9aa0SEli Cohen 					list_del(&cq->com.list);
4830c82e9aa0SEli Cohen 					spin_unlock_irq(mlx4_tlock(dev));
4831146f3ef4SJack Morgenstein 					mlx4_release_resource(dev, slave,
4832146f3ef4SJack Morgenstein 							      RES_CQ, 1, 0);
4833c82e9aa0SEli Cohen 					kfree(cq);
4834c82e9aa0SEli Cohen 					state = 0;
4835c82e9aa0SEli Cohen 					break;
4836c82e9aa0SEli Cohen 
4837c82e9aa0SEli Cohen 				case RES_CQ_HW:
4838c82e9aa0SEli Cohen 					in_param = slave;
4839c82e9aa0SEli Cohen 					err = mlx4_cmd(dev, in_param, cqn, 1,
4840c82e9aa0SEli Cohen 						       MLX4_CMD_HW2SW_CQ,
4841c82e9aa0SEli Cohen 						       MLX4_CMD_TIME_CLASS_A,
4842c82e9aa0SEli Cohen 						       MLX4_CMD_NATIVE);
4843c82e9aa0SEli Cohen 					if (err)
48441a91de28SJoe Perches 						mlx4_dbg(dev, "rem_slave_cqs: failed to move slave %d cq %d to SW ownership\n",
4845c82e9aa0SEli Cohen 							 slave, cqn);
4846c82e9aa0SEli Cohen 					atomic_dec(&cq->mtt->ref_count);
4847c82e9aa0SEli Cohen 					state = RES_CQ_ALLOCATED;
4848c82e9aa0SEli Cohen 					break;
4849c82e9aa0SEli Cohen 
4850c82e9aa0SEli Cohen 				default:
4851c82e9aa0SEli Cohen 					state = 0;
4852c82e9aa0SEli Cohen 				}
4853c82e9aa0SEli Cohen 			}
4854c82e9aa0SEli Cohen 		}
4855c82e9aa0SEli Cohen 		spin_lock_irq(mlx4_tlock(dev));
4856c82e9aa0SEli Cohen 	}
4857c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
4858c82e9aa0SEli Cohen }
4859c82e9aa0SEli Cohen 
rem_slave_mrs(struct mlx4_dev * dev,int slave)4860c82e9aa0SEli Cohen static void rem_slave_mrs(struct mlx4_dev *dev, int slave)
4861c82e9aa0SEli Cohen {
4862c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
4863c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
4864c82e9aa0SEli Cohen 	struct list_head *mpt_list =
4865c82e9aa0SEli Cohen 		&tracker->slave_list[slave].res_list[RES_MPT];
4866c82e9aa0SEli Cohen 	struct res_mpt *mpt;
4867c82e9aa0SEli Cohen 	struct res_mpt *tmp;
4868c82e9aa0SEli Cohen 	int state;
4869c82e9aa0SEli Cohen 	u64 in_param;
4870c82e9aa0SEli Cohen 	int mptn;
4871c82e9aa0SEli Cohen 	int err;
4872c82e9aa0SEli Cohen 
4873c82e9aa0SEli Cohen 	err = move_all_busy(dev, slave, RES_MPT);
4874c82e9aa0SEli Cohen 	if (err)
48751a91de28SJoe Perches 		mlx4_warn(dev, "rem_slave_mrs: Could not move all mpts - too busy for slave %d\n",
48761a91de28SJoe Perches 			  slave);
4877c82e9aa0SEli Cohen 
4878c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
4879c82e9aa0SEli Cohen 	list_for_each_entry_safe(mpt, tmp, mpt_list, com.list) {
4880c82e9aa0SEli Cohen 		spin_unlock_irq(mlx4_tlock(dev));
4881c82e9aa0SEli Cohen 		if (mpt->com.owner == slave) {
4882c82e9aa0SEli Cohen 			mptn = mpt->com.res_id;
4883c82e9aa0SEli Cohen 			state = mpt->com.from_state;
4884c82e9aa0SEli Cohen 			while (state != 0) {
4885c82e9aa0SEli Cohen 				switch (state) {
4886c82e9aa0SEli Cohen 				case RES_MPT_RESERVED:
4887b20e519aSShani Michaeli 					__mlx4_mpt_release(dev, mpt->key);
4888c82e9aa0SEli Cohen 					spin_lock_irq(mlx4_tlock(dev));
48894af1c048SHadar Hen Zion 					rb_erase(&mpt->com.node,
48904af1c048SHadar Hen Zion 						 &tracker->res_tree[RES_MPT]);
4891c82e9aa0SEli Cohen 					list_del(&mpt->com.list);
4892c82e9aa0SEli Cohen 					spin_unlock_irq(mlx4_tlock(dev));
4893146f3ef4SJack Morgenstein 					mlx4_release_resource(dev, slave,
4894146f3ef4SJack Morgenstein 							      RES_MPT, 1, 0);
4895c82e9aa0SEli Cohen 					kfree(mpt);
4896c82e9aa0SEli Cohen 					state = 0;
4897c82e9aa0SEli Cohen 					break;
4898c82e9aa0SEli Cohen 
4899c82e9aa0SEli Cohen 				case RES_MPT_MAPPED:
4900b20e519aSShani Michaeli 					__mlx4_mpt_free_icm(dev, mpt->key);
4901c82e9aa0SEli Cohen 					state = RES_MPT_RESERVED;
4902c82e9aa0SEli Cohen 					break;
4903c82e9aa0SEli Cohen 
4904c82e9aa0SEli Cohen 				case RES_MPT_HW:
4905c82e9aa0SEli Cohen 					in_param = slave;
4906c82e9aa0SEli Cohen 					err = mlx4_cmd(dev, in_param, mptn, 0,
4907c82e9aa0SEli Cohen 						     MLX4_CMD_HW2SW_MPT,
4908c82e9aa0SEli Cohen 						     MLX4_CMD_TIME_CLASS_A,
4909c82e9aa0SEli Cohen 						     MLX4_CMD_NATIVE);
4910c82e9aa0SEli Cohen 					if (err)
49111a91de28SJoe Perches 						mlx4_dbg(dev, "rem_slave_mrs: failed to move slave %d mpt %d to SW ownership\n",
4912c82e9aa0SEli Cohen 							 slave, mptn);
4913c82e9aa0SEli Cohen 					if (mpt->mtt)
4914c82e9aa0SEli Cohen 						atomic_dec(&mpt->mtt->ref_count);
4915c82e9aa0SEli Cohen 					state = RES_MPT_MAPPED;
4916c82e9aa0SEli Cohen 					break;
4917c82e9aa0SEli Cohen 				default:
4918c82e9aa0SEli Cohen 					state = 0;
4919c82e9aa0SEli Cohen 				}
4920c82e9aa0SEli Cohen 			}
4921c82e9aa0SEli Cohen 		}
4922c82e9aa0SEli Cohen 		spin_lock_irq(mlx4_tlock(dev));
4923c82e9aa0SEli Cohen 	}
4924c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
4925c82e9aa0SEli Cohen }
4926c82e9aa0SEli Cohen 
rem_slave_mtts(struct mlx4_dev * dev,int slave)4927c82e9aa0SEli Cohen static void rem_slave_mtts(struct mlx4_dev *dev, int slave)
4928c82e9aa0SEli Cohen {
4929c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
4930c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker =
4931c82e9aa0SEli Cohen 		&priv->mfunc.master.res_tracker;
4932c82e9aa0SEli Cohen 	struct list_head *mtt_list =
4933c82e9aa0SEli Cohen 		&tracker->slave_list[slave].res_list[RES_MTT];
4934c82e9aa0SEli Cohen 	struct res_mtt *mtt;
4935c82e9aa0SEli Cohen 	struct res_mtt *tmp;
4936c82e9aa0SEli Cohen 	int state;
4937c82e9aa0SEli Cohen 	int base;
4938c82e9aa0SEli Cohen 	int err;
4939c82e9aa0SEli Cohen 
4940c82e9aa0SEli Cohen 	err = move_all_busy(dev, slave, RES_MTT);
4941c82e9aa0SEli Cohen 	if (err)
49421a91de28SJoe Perches 		mlx4_warn(dev, "rem_slave_mtts: Could not move all mtts  - too busy for slave %d\n",
49431a91de28SJoe Perches 			  slave);
4944c82e9aa0SEli Cohen 
4945c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
4946c82e9aa0SEli Cohen 	list_for_each_entry_safe(mtt, tmp, mtt_list, com.list) {
4947c82e9aa0SEli Cohen 		spin_unlock_irq(mlx4_tlock(dev));
4948c82e9aa0SEli Cohen 		if (mtt->com.owner == slave) {
4949c82e9aa0SEli Cohen 			base = mtt->com.res_id;
4950c82e9aa0SEli Cohen 			state = mtt->com.from_state;
4951c82e9aa0SEli Cohen 			while (state != 0) {
4952c82e9aa0SEli Cohen 				switch (state) {
4953c82e9aa0SEli Cohen 				case RES_MTT_ALLOCATED:
4954c82e9aa0SEli Cohen 					__mlx4_free_mtt_range(dev, base,
4955c82e9aa0SEli Cohen 							      mtt->order);
4956c82e9aa0SEli Cohen 					spin_lock_irq(mlx4_tlock(dev));
49574af1c048SHadar Hen Zion 					rb_erase(&mtt->com.node,
49584af1c048SHadar Hen Zion 						 &tracker->res_tree[RES_MTT]);
4959c82e9aa0SEli Cohen 					list_del(&mtt->com.list);
4960c82e9aa0SEli Cohen 					spin_unlock_irq(mlx4_tlock(dev));
4961146f3ef4SJack Morgenstein 					mlx4_release_resource(dev, slave, RES_MTT,
4962146f3ef4SJack Morgenstein 							      1 << mtt->order, 0);
4963c82e9aa0SEli Cohen 					kfree(mtt);
4964c82e9aa0SEli Cohen 					state = 0;
4965c82e9aa0SEli Cohen 					break;
4966c82e9aa0SEli Cohen 
4967c82e9aa0SEli Cohen 				default:
4968c82e9aa0SEli Cohen 					state = 0;
4969c82e9aa0SEli Cohen 				}
4970c82e9aa0SEli Cohen 			}
4971c82e9aa0SEli Cohen 		}
4972c82e9aa0SEli Cohen 		spin_lock_irq(mlx4_tlock(dev));
4973c82e9aa0SEli Cohen 	}
4974c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
4975c82e9aa0SEli Cohen }
4976c82e9aa0SEli Cohen 
mlx4_do_mirror_rule(struct mlx4_dev * dev,struct res_fs_rule * fs_rule)497778efed27SMoni Shoua static int mlx4_do_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule)
497878efed27SMoni Shoua {
497978efed27SMoni Shoua 	struct mlx4_cmd_mailbox *mailbox;
498078efed27SMoni Shoua 	int err;
498178efed27SMoni Shoua 	struct res_fs_rule *mirr_rule;
498278efed27SMoni Shoua 	u64 reg_id;
498378efed27SMoni Shoua 
498478efed27SMoni Shoua 	mailbox = mlx4_alloc_cmd_mailbox(dev);
498578efed27SMoni Shoua 	if (IS_ERR(mailbox))
498678efed27SMoni Shoua 		return PTR_ERR(mailbox);
498778efed27SMoni Shoua 
498878efed27SMoni Shoua 	if (!fs_rule->mirr_mbox) {
498978efed27SMoni Shoua 		mlx4_err(dev, "rule mirroring mailbox is null\n");
49908eb65fdaSChuhong Yuan 		mlx4_free_cmd_mailbox(dev, mailbox);
499178efed27SMoni Shoua 		return -EINVAL;
499278efed27SMoni Shoua 	}
499378efed27SMoni Shoua 	memcpy(mailbox->buf, fs_rule->mirr_mbox, fs_rule->mirr_mbox_size);
499478efed27SMoni Shoua 	err = mlx4_cmd_imm(dev, mailbox->dma, &reg_id, fs_rule->mirr_mbox_size >> 2, 0,
499578efed27SMoni Shoua 			   MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
499678efed27SMoni Shoua 			   MLX4_CMD_NATIVE);
499778efed27SMoni Shoua 	mlx4_free_cmd_mailbox(dev, mailbox);
499878efed27SMoni Shoua 
499978efed27SMoni Shoua 	if (err)
500078efed27SMoni Shoua 		goto err;
500178efed27SMoni Shoua 
500278efed27SMoni Shoua 	err = add_res_range(dev, fs_rule->com.owner, reg_id, 1, RES_FS_RULE, fs_rule->qpn);
500378efed27SMoni Shoua 	if (err)
500478efed27SMoni Shoua 		goto err_detach;
500578efed27SMoni Shoua 
500678efed27SMoni Shoua 	err = get_res(dev, fs_rule->com.owner, reg_id, RES_FS_RULE, &mirr_rule);
500778efed27SMoni Shoua 	if (err)
500878efed27SMoni Shoua 		goto err_rem;
500978efed27SMoni Shoua 
501078efed27SMoni Shoua 	fs_rule->mirr_rule_id = reg_id;
501178efed27SMoni Shoua 	mirr_rule->mirr_rule_id = 0;
501278efed27SMoni Shoua 	mirr_rule->mirr_mbox_size = 0;
501378efed27SMoni Shoua 	mirr_rule->mirr_mbox = NULL;
501478efed27SMoni Shoua 	put_res(dev, fs_rule->com.owner, reg_id, RES_FS_RULE);
501578efed27SMoni Shoua 
501678efed27SMoni Shoua 	return 0;
501778efed27SMoni Shoua err_rem:
501878efed27SMoni Shoua 	rem_res_range(dev, fs_rule->com.owner, reg_id, 1, RES_FS_RULE, 0);
501978efed27SMoni Shoua err_detach:
502078efed27SMoni Shoua 	mlx4_cmd(dev, reg_id, 0, 0, MLX4_QP_FLOW_STEERING_DETACH,
502178efed27SMoni Shoua 		 MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
502278efed27SMoni Shoua err:
502378efed27SMoni Shoua 	return err;
502478efed27SMoni Shoua }
502578efed27SMoni Shoua 
mlx4_mirror_fs_rules(struct mlx4_dev * dev,bool bond)502678efed27SMoni Shoua static int mlx4_mirror_fs_rules(struct mlx4_dev *dev, bool bond)
502778efed27SMoni Shoua {
502878efed27SMoni Shoua 	struct mlx4_priv *priv = mlx4_priv(dev);
502978efed27SMoni Shoua 	struct mlx4_resource_tracker *tracker =
503078efed27SMoni Shoua 		&priv->mfunc.master.res_tracker;
503178efed27SMoni Shoua 	struct rb_root *root = &tracker->res_tree[RES_FS_RULE];
503278efed27SMoni Shoua 	struct rb_node *p;
503378efed27SMoni Shoua 	struct res_fs_rule *fs_rule;
503478efed27SMoni Shoua 	int err = 0;
503578efed27SMoni Shoua 	LIST_HEAD(mirr_list);
503678efed27SMoni Shoua 
503778efed27SMoni Shoua 	for (p = rb_first(root); p; p = rb_next(p)) {
503878efed27SMoni Shoua 		fs_rule = rb_entry(p, struct res_fs_rule, com.node);
503978efed27SMoni Shoua 		if ((bond && fs_rule->mirr_mbox_size) ||
504078efed27SMoni Shoua 		    (!bond && !fs_rule->mirr_mbox_size))
504178efed27SMoni Shoua 			list_add_tail(&fs_rule->mirr_list, &mirr_list);
504278efed27SMoni Shoua 	}
504378efed27SMoni Shoua 
504478efed27SMoni Shoua 	list_for_each_entry(fs_rule, &mirr_list, mirr_list) {
504578efed27SMoni Shoua 		if (bond)
504678efed27SMoni Shoua 			err += mlx4_do_mirror_rule(dev, fs_rule);
504778efed27SMoni Shoua 		else
504878efed27SMoni Shoua 			err += mlx4_undo_mirror_rule(dev, fs_rule);
504978efed27SMoni Shoua 	}
505078efed27SMoni Shoua 	return err;
505178efed27SMoni Shoua }
505278efed27SMoni Shoua 
mlx4_bond_fs_rules(struct mlx4_dev * dev)505378efed27SMoni Shoua int mlx4_bond_fs_rules(struct mlx4_dev *dev)
505478efed27SMoni Shoua {
505578efed27SMoni Shoua 	return mlx4_mirror_fs_rules(dev, true);
505678efed27SMoni Shoua }
505778efed27SMoni Shoua 
mlx4_unbond_fs_rules(struct mlx4_dev * dev)505878efed27SMoni Shoua int mlx4_unbond_fs_rules(struct mlx4_dev *dev)
505978efed27SMoni Shoua {
506078efed27SMoni Shoua 	return mlx4_mirror_fs_rules(dev, false);
506178efed27SMoni Shoua }
506278efed27SMoni Shoua 
rem_slave_fs_rule(struct mlx4_dev * dev,int slave)50631b9c6b06SHadar Hen Zion static void rem_slave_fs_rule(struct mlx4_dev *dev, int slave)
50641b9c6b06SHadar Hen Zion {
50651b9c6b06SHadar Hen Zion 	struct mlx4_priv *priv = mlx4_priv(dev);
50661b9c6b06SHadar Hen Zion 	struct mlx4_resource_tracker *tracker =
50671b9c6b06SHadar Hen Zion 		&priv->mfunc.master.res_tracker;
50681b9c6b06SHadar Hen Zion 	struct list_head *fs_rule_list =
50691b9c6b06SHadar Hen Zion 		&tracker->slave_list[slave].res_list[RES_FS_RULE];
50701b9c6b06SHadar Hen Zion 	struct res_fs_rule *fs_rule;
50711b9c6b06SHadar Hen Zion 	struct res_fs_rule *tmp;
50721b9c6b06SHadar Hen Zion 	int state;
50731b9c6b06SHadar Hen Zion 	u64 base;
50741b9c6b06SHadar Hen Zion 	int err;
50751b9c6b06SHadar Hen Zion 
50761b9c6b06SHadar Hen Zion 	err = move_all_busy(dev, slave, RES_FS_RULE);
50771b9c6b06SHadar Hen Zion 	if (err)
50781b9c6b06SHadar Hen Zion 		mlx4_warn(dev, "rem_slave_fs_rule: Could not move all mtts to busy for slave %d\n",
50791b9c6b06SHadar Hen Zion 			  slave);
50801b9c6b06SHadar Hen Zion 
50811b9c6b06SHadar Hen Zion 	spin_lock_irq(mlx4_tlock(dev));
50821b9c6b06SHadar Hen Zion 	list_for_each_entry_safe(fs_rule, tmp, fs_rule_list, com.list) {
50831b9c6b06SHadar Hen Zion 		spin_unlock_irq(mlx4_tlock(dev));
50841b9c6b06SHadar Hen Zion 		if (fs_rule->com.owner == slave) {
50851b9c6b06SHadar Hen Zion 			base = fs_rule->com.res_id;
50861b9c6b06SHadar Hen Zion 			state = fs_rule->com.from_state;
50871b9c6b06SHadar Hen Zion 			while (state != 0) {
50881b9c6b06SHadar Hen Zion 				switch (state) {
50891b9c6b06SHadar Hen Zion 				case RES_FS_RULE_ALLOCATED:
50901b9c6b06SHadar Hen Zion 					/* detach rule */
50911b9c6b06SHadar Hen Zion 					err = mlx4_cmd(dev, base, 0, 0,
50921b9c6b06SHadar Hen Zion 						       MLX4_QP_FLOW_STEERING_DETACH,
50931b9c6b06SHadar Hen Zion 						       MLX4_CMD_TIME_CLASS_A,
50941b9c6b06SHadar Hen Zion 						       MLX4_CMD_NATIVE);
50951b9c6b06SHadar Hen Zion 
50961b9c6b06SHadar Hen Zion 					spin_lock_irq(mlx4_tlock(dev));
50971b9c6b06SHadar Hen Zion 					rb_erase(&fs_rule->com.node,
50981b9c6b06SHadar Hen Zion 						 &tracker->res_tree[RES_FS_RULE]);
50991b9c6b06SHadar Hen Zion 					list_del(&fs_rule->com.list);
51001b9c6b06SHadar Hen Zion 					spin_unlock_irq(mlx4_tlock(dev));
5101461d5f1bSMoshe Shemesh 					kfree(fs_rule->mirr_mbox);
51021b9c6b06SHadar Hen Zion 					kfree(fs_rule);
51031b9c6b06SHadar Hen Zion 					state = 0;
51041b9c6b06SHadar Hen Zion 					break;
51051b9c6b06SHadar Hen Zion 
51061b9c6b06SHadar Hen Zion 				default:
51071b9c6b06SHadar Hen Zion 					state = 0;
51081b9c6b06SHadar Hen Zion 				}
51091b9c6b06SHadar Hen Zion 			}
51101b9c6b06SHadar Hen Zion 		}
51111b9c6b06SHadar Hen Zion 		spin_lock_irq(mlx4_tlock(dev));
51121b9c6b06SHadar Hen Zion 	}
51131b9c6b06SHadar Hen Zion 	spin_unlock_irq(mlx4_tlock(dev));
51141b9c6b06SHadar Hen Zion }
51151b9c6b06SHadar Hen Zion 
rem_slave_eqs(struct mlx4_dev * dev,int slave)5116c82e9aa0SEli Cohen static void rem_slave_eqs(struct mlx4_dev *dev, int slave)
5117c82e9aa0SEli Cohen {
5118c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
5119c82e9aa0SEli Cohen 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
5120c82e9aa0SEli Cohen 	struct list_head *eq_list =
5121c82e9aa0SEli Cohen 		&tracker->slave_list[slave].res_list[RES_EQ];
5122c82e9aa0SEli Cohen 	struct res_eq *eq;
5123c82e9aa0SEli Cohen 	struct res_eq *tmp;
5124c82e9aa0SEli Cohen 	int err;
5125c82e9aa0SEli Cohen 	int state;
5126c82e9aa0SEli Cohen 	int eqn;
5127c82e9aa0SEli Cohen 
5128c82e9aa0SEli Cohen 	err = move_all_busy(dev, slave, RES_EQ);
5129c82e9aa0SEli Cohen 	if (err)
51301a91de28SJoe Perches 		mlx4_warn(dev, "rem_slave_eqs: Could not move all eqs - too busy for slave %d\n",
51311a91de28SJoe Perches 			  slave);
5132c82e9aa0SEli Cohen 
5133c82e9aa0SEli Cohen 	spin_lock_irq(mlx4_tlock(dev));
5134c82e9aa0SEli Cohen 	list_for_each_entry_safe(eq, tmp, eq_list, com.list) {
5135c82e9aa0SEli Cohen 		spin_unlock_irq(mlx4_tlock(dev));
5136c82e9aa0SEli Cohen 		if (eq->com.owner == slave) {
5137c82e9aa0SEli Cohen 			eqn = eq->com.res_id;
5138c82e9aa0SEli Cohen 			state = eq->com.from_state;
5139c82e9aa0SEli Cohen 			while (state != 0) {
5140c82e9aa0SEli Cohen 				switch (state) {
5141c82e9aa0SEli Cohen 				case RES_EQ_RESERVED:
5142c82e9aa0SEli Cohen 					spin_lock_irq(mlx4_tlock(dev));
51434af1c048SHadar Hen Zion 					rb_erase(&eq->com.node,
51444af1c048SHadar Hen Zion 						 &tracker->res_tree[RES_EQ]);
5145c82e9aa0SEli Cohen 					list_del(&eq->com.list);
5146c82e9aa0SEli Cohen 					spin_unlock_irq(mlx4_tlock(dev));
5147c82e9aa0SEli Cohen 					kfree(eq);
5148c82e9aa0SEli Cohen 					state = 0;
5149c82e9aa0SEli Cohen 					break;
5150c82e9aa0SEli Cohen 
5151c82e9aa0SEli Cohen 				case RES_EQ_HW:
51522d3c7397SYishai Hadas 					err = mlx4_cmd(dev, slave, eqn & 0x3ff,
515330a5da5bSJack Morgenstein 						       1, MLX4_CMD_HW2SW_EQ,
5154c82e9aa0SEli Cohen 						       MLX4_CMD_TIME_CLASS_A,
5155c82e9aa0SEli Cohen 						       MLX4_CMD_NATIVE);
5156eb71d0d6SJack Morgenstein 					if (err)
51571a91de28SJoe Perches 						mlx4_dbg(dev, "rem_slave_eqs: failed to move slave %d eqs %d to SW ownership\n",
51582d3c7397SYishai Hadas 							 slave, eqn & 0x3ff);
5159c82e9aa0SEli Cohen 					atomic_dec(&eq->mtt->ref_count);
5160c82e9aa0SEli Cohen 					state = RES_EQ_RESERVED;
5161c82e9aa0SEli Cohen 					break;
5162c82e9aa0SEli Cohen 
5163c82e9aa0SEli Cohen 				default:
5164c82e9aa0SEli Cohen 					state = 0;
5165c82e9aa0SEli Cohen 				}
5166c82e9aa0SEli Cohen 			}
5167c82e9aa0SEli Cohen 		}
5168c82e9aa0SEli Cohen 		spin_lock_irq(mlx4_tlock(dev));
5169c82e9aa0SEli Cohen 	}
5170c82e9aa0SEli Cohen 	spin_unlock_irq(mlx4_tlock(dev));
5171c82e9aa0SEli Cohen }
5172c82e9aa0SEli Cohen 
rem_slave_counters(struct mlx4_dev * dev,int slave)5173ba062d52SJack Morgenstein static void rem_slave_counters(struct mlx4_dev *dev, int slave)
5174ba062d52SJack Morgenstein {
5175ba062d52SJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
5176ba062d52SJack Morgenstein 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
5177ba062d52SJack Morgenstein 	struct list_head *counter_list =
5178ba062d52SJack Morgenstein 		&tracker->slave_list[slave].res_list[RES_COUNTER];
5179ba062d52SJack Morgenstein 	struct res_counter *counter;
5180ba062d52SJack Morgenstein 	struct res_counter *tmp;
5181ba062d52SJack Morgenstein 	int err;
5182f5adbfeeSEran Ben Elisha 	int *counters_arr = NULL;
5183f5adbfeeSEran Ben Elisha 	int i, j;
5184ba062d52SJack Morgenstein 
5185ba062d52SJack Morgenstein 	err = move_all_busy(dev, slave, RES_COUNTER);
5186ba062d52SJack Morgenstein 	if (err)
51871a91de28SJoe Perches 		mlx4_warn(dev, "rem_slave_counters: Could not move all counters - too busy for slave %d\n",
51881a91de28SJoe Perches 			  slave);
5189ba062d52SJack Morgenstein 
5190f5adbfeeSEran Ben Elisha 	counters_arr = kmalloc_array(dev->caps.max_counters,
5191f5adbfeeSEran Ben Elisha 				     sizeof(*counters_arr), GFP_KERNEL);
5192f5adbfeeSEran Ben Elisha 	if (!counters_arr)
5193f5adbfeeSEran Ben Elisha 		return;
5194f5adbfeeSEran Ben Elisha 
5195f5adbfeeSEran Ben Elisha 	do {
5196f5adbfeeSEran Ben Elisha 		i = 0;
5197f5adbfeeSEran Ben Elisha 		j = 0;
5198ba062d52SJack Morgenstein 		spin_lock_irq(mlx4_tlock(dev));
5199ba062d52SJack Morgenstein 		list_for_each_entry_safe(counter, tmp, counter_list, com.list) {
5200ba062d52SJack Morgenstein 			if (counter->com.owner == slave) {
5201f5adbfeeSEran Ben Elisha 				counters_arr[i++] = counter->com.res_id;
52024af1c048SHadar Hen Zion 				rb_erase(&counter->com.node,
52034af1c048SHadar Hen Zion 					 &tracker->res_tree[RES_COUNTER]);
5204ba062d52SJack Morgenstein 				list_del(&counter->com.list);
5205ba062d52SJack Morgenstein 				kfree(counter);
5206ba062d52SJack Morgenstein 			}
5207ba062d52SJack Morgenstein 		}
5208ba062d52SJack Morgenstein 		spin_unlock_irq(mlx4_tlock(dev));
5209f5adbfeeSEran Ben Elisha 
5210f5adbfeeSEran Ben Elisha 		while (j < i) {
5211f5adbfeeSEran Ben Elisha 			__mlx4_counter_free(dev, counters_arr[j++]);
5212f5adbfeeSEran Ben Elisha 			mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
5213f5adbfeeSEran Ben Elisha 		}
5214f5adbfeeSEran Ben Elisha 	} while (i);
5215f5adbfeeSEran Ben Elisha 
5216f5adbfeeSEran Ben Elisha 	kfree(counters_arr);
5217ba062d52SJack Morgenstein }
5218ba062d52SJack Morgenstein 
rem_slave_xrcdns(struct mlx4_dev * dev,int slave)5219ba062d52SJack Morgenstein static void rem_slave_xrcdns(struct mlx4_dev *dev, int slave)
5220ba062d52SJack Morgenstein {
5221ba062d52SJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
5222ba062d52SJack Morgenstein 	struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
5223ba062d52SJack Morgenstein 	struct list_head *xrcdn_list =
5224ba062d52SJack Morgenstein 		&tracker->slave_list[slave].res_list[RES_XRCD];
5225ba062d52SJack Morgenstein 	struct res_xrcdn *xrcd;
5226ba062d52SJack Morgenstein 	struct res_xrcdn *tmp;
5227ba062d52SJack Morgenstein 	int err;
5228ba062d52SJack Morgenstein 	int xrcdn;
5229ba062d52SJack Morgenstein 
5230ba062d52SJack Morgenstein 	err = move_all_busy(dev, slave, RES_XRCD);
5231ba062d52SJack Morgenstein 	if (err)
52321a91de28SJoe Perches 		mlx4_warn(dev, "rem_slave_xrcdns: Could not move all xrcdns - too busy for slave %d\n",
52331a91de28SJoe Perches 			  slave);
5234ba062d52SJack Morgenstein 
5235ba062d52SJack Morgenstein 	spin_lock_irq(mlx4_tlock(dev));
5236ba062d52SJack Morgenstein 	list_for_each_entry_safe(xrcd, tmp, xrcdn_list, com.list) {
5237ba062d52SJack Morgenstein 		if (xrcd->com.owner == slave) {
5238ba062d52SJack Morgenstein 			xrcdn = xrcd->com.res_id;
52394af1c048SHadar Hen Zion 			rb_erase(&xrcd->com.node, &tracker->res_tree[RES_XRCD]);
5240ba062d52SJack Morgenstein 			list_del(&xrcd->com.list);
5241ba062d52SJack Morgenstein 			kfree(xrcd);
5242ba062d52SJack Morgenstein 			__mlx4_xrcd_free(dev, xrcdn);
5243ba062d52SJack Morgenstein 		}
5244ba062d52SJack Morgenstein 	}
5245ba062d52SJack Morgenstein 	spin_unlock_irq(mlx4_tlock(dev));
5246ba062d52SJack Morgenstein }
5247ba062d52SJack Morgenstein 
mlx4_delete_all_resources_for_slave(struct mlx4_dev * dev,int slave)5248c82e9aa0SEli Cohen void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave)
5249c82e9aa0SEli Cohen {
5250c82e9aa0SEli Cohen 	struct mlx4_priv *priv = mlx4_priv(dev);
5251111c6094SJack Morgenstein 	mlx4_reset_roce_gids(dev, slave);
5252c82e9aa0SEli Cohen 	mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
52534874080dSJack Morgenstein 	rem_slave_vlans(dev, slave);
5254c82e9aa0SEli Cohen 	rem_slave_macs(dev, slave);
525580cb0021SHadar Hen Zion 	rem_slave_fs_rule(dev, slave);
5256c82e9aa0SEli Cohen 	rem_slave_qps(dev, slave);
5257c82e9aa0SEli Cohen 	rem_slave_srqs(dev, slave);
5258c82e9aa0SEli Cohen 	rem_slave_cqs(dev, slave);
5259c82e9aa0SEli Cohen 	rem_slave_mrs(dev, slave);
5260c82e9aa0SEli Cohen 	rem_slave_eqs(dev, slave);
5261c82e9aa0SEli Cohen 	rem_slave_mtts(dev, slave);
5262ba062d52SJack Morgenstein 	rem_slave_counters(dev, slave);
5263ba062d52SJack Morgenstein 	rem_slave_xrcdns(dev, slave);
5264c82e9aa0SEli Cohen 	mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
5265c82e9aa0SEli Cohen }
5266b01978caSJack Morgenstein 
update_qos_vpp(struct mlx4_update_qp_context * ctx,struct mlx4_vf_immed_vlan_work * work)5267269f9883SIdo Shamay static void update_qos_vpp(struct mlx4_update_qp_context *ctx,
5268269f9883SIdo Shamay 			   struct mlx4_vf_immed_vlan_work *work)
5269269f9883SIdo Shamay {
5270269f9883SIdo Shamay 	ctx->qp_mask |= cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_QOS_VPP);
5271269f9883SIdo Shamay 	ctx->qp_context.qos_vport = work->qos_vport;
5272269f9883SIdo Shamay }
5273269f9883SIdo Shamay 
mlx4_vf_immed_vlan_work_handler(struct work_struct * _work)5274b01978caSJack Morgenstein void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work)
5275b01978caSJack Morgenstein {
5276b01978caSJack Morgenstein 	struct mlx4_vf_immed_vlan_work *work =
5277b01978caSJack Morgenstein 		container_of(_work, struct mlx4_vf_immed_vlan_work, work);
5278b01978caSJack Morgenstein 	struct mlx4_cmd_mailbox *mailbox;
5279b01978caSJack Morgenstein 	struct mlx4_update_qp_context *upd_context;
5280b01978caSJack Morgenstein 	struct mlx4_dev *dev = &work->priv->dev;
5281b01978caSJack Morgenstein 	struct mlx4_resource_tracker *tracker =
5282b01978caSJack Morgenstein 		&work->priv->mfunc.master.res_tracker;
5283b01978caSJack Morgenstein 	struct list_head *qp_list =
5284b01978caSJack Morgenstein 		&tracker->slave_list[work->slave].res_list[RES_QP];
5285b01978caSJack Morgenstein 	struct res_qp *qp;
5286b01978caSJack Morgenstein 	struct res_qp *tmp;
5287f0f829bfSRony Efraim 	u64 qp_path_mask_vlan_ctrl =
5288f0f829bfSRony Efraim 		       ((1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_UNTAGGED) |
5289b01978caSJack Morgenstein 		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_1P) |
5290b01978caSJack Morgenstein 		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_TAGGED) |
5291b01978caSJack Morgenstein 		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_UNTAGGED) |
5292b01978caSJack Morgenstein 		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_1P) |
5293f0f829bfSRony Efraim 		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_TAGGED));
5294f0f829bfSRony Efraim 
5295f0f829bfSRony Efraim 	u64 qp_path_mask = ((1ULL << MLX4_UPD_QP_PATH_MASK_VLAN_INDEX) |
5296f0f829bfSRony Efraim 		       (1ULL << MLX4_UPD_QP_PATH_MASK_FVL) |
5297f0f829bfSRony Efraim 		       (1ULL << MLX4_UPD_QP_PATH_MASK_CV) |
52987c3d21c8SMoshe Shemesh 		       (1ULL << MLX4_UPD_QP_PATH_MASK_SV) |
5299f0f829bfSRony Efraim 		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_HIDE_CQE_VLAN) |
5300f0f829bfSRony Efraim 		       (1ULL << MLX4_UPD_QP_PATH_MASK_FEUP) |
5301f0f829bfSRony Efraim 		       (1ULL << MLX4_UPD_QP_PATH_MASK_FVL_RX) |
5302b01978caSJack Morgenstein 		       (1ULL << MLX4_UPD_QP_PATH_MASK_SCHED_QUEUE));
5303b01978caSJack Morgenstein 
5304b01978caSJack Morgenstein 	int err;
5305b01978caSJack Morgenstein 	int port, errors = 0;
5306b01978caSJack Morgenstein 	u8 vlan_control;
5307b01978caSJack Morgenstein 
5308b01978caSJack Morgenstein 	if (mlx4_is_slave(dev)) {
5309b01978caSJack Morgenstein 		mlx4_warn(dev, "Trying to update-qp in slave %d\n",
5310b01978caSJack Morgenstein 			  work->slave);
5311b01978caSJack Morgenstein 		goto out;
5312b01978caSJack Morgenstein 	}
5313b01978caSJack Morgenstein 
5314b01978caSJack Morgenstein 	mailbox = mlx4_alloc_cmd_mailbox(dev);
5315b01978caSJack Morgenstein 	if (IS_ERR(mailbox))
5316b01978caSJack Morgenstein 		goto out;
53170a6eac24SRony Efraim 	if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE) /* block all */
53180a6eac24SRony Efraim 		vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
53190a6eac24SRony Efraim 			MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
53200a6eac24SRony Efraim 			MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED |
53210a6eac24SRony Efraim 			MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
53220a6eac24SRony Efraim 			MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED |
53230a6eac24SRony Efraim 			MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
53240a6eac24SRony Efraim 	else if (!work->vlan_id)
5325b01978caSJack Morgenstein 		vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
5326b01978caSJack Morgenstein 			MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
53277c3d21c8SMoshe Shemesh 	else if (work->vlan_proto == htons(ETH_P_8021AD))
53287c3d21c8SMoshe Shemesh 		vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
53297c3d21c8SMoshe Shemesh 			MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
53307c3d21c8SMoshe Shemesh 			MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
53317c3d21c8SMoshe Shemesh 			MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
53327c3d21c8SMoshe Shemesh 	else  /* vst 802.1Q */
5333b01978caSJack Morgenstein 		vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
5334b01978caSJack Morgenstein 			MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
5335b01978caSJack Morgenstein 			MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
5336b01978caSJack Morgenstein 
5337b01978caSJack Morgenstein 	upd_context = mailbox->buf;
5338311be98aSMatan Barak 	upd_context->qp_mask = cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_VSD);
5339b01978caSJack Morgenstein 
5340b01978caSJack Morgenstein 	spin_lock_irq(mlx4_tlock(dev));
5341b01978caSJack Morgenstein 	list_for_each_entry_safe(qp, tmp, qp_list, com.list) {
5342b01978caSJack Morgenstein 		spin_unlock_irq(mlx4_tlock(dev));
5343b01978caSJack Morgenstein 		if (qp->com.owner == work->slave) {
5344b01978caSJack Morgenstein 			if (qp->com.from_state != RES_QP_HW ||
5345b01978caSJack Morgenstein 			    !qp->sched_queue ||  /* no INIT2RTR trans yet */
5346b01978caSJack Morgenstein 			    mlx4_is_qp_reserved(dev, qp->local_qpn) ||
5347b01978caSJack Morgenstein 			    qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET)) {
5348b01978caSJack Morgenstein 				spin_lock_irq(mlx4_tlock(dev));
5349b01978caSJack Morgenstein 				continue;
5350b01978caSJack Morgenstein 			}
5351b01978caSJack Morgenstein 			port = (qp->sched_queue >> 6 & 1) + 1;
5352b01978caSJack Morgenstein 			if (port != work->port) {
5353b01978caSJack Morgenstein 				spin_lock_irq(mlx4_tlock(dev));
5354b01978caSJack Morgenstein 				continue;
5355b01978caSJack Morgenstein 			}
5356f0f829bfSRony Efraim 			if (MLX4_QP_ST_RC == ((qp->qpc_flags >> 16) & 0xff))
5357f0f829bfSRony Efraim 				upd_context->primary_addr_path_mask = cpu_to_be64(qp_path_mask);
5358f0f829bfSRony Efraim 			else
5359f0f829bfSRony Efraim 				upd_context->primary_addr_path_mask =
5360f0f829bfSRony Efraim 					cpu_to_be64(qp_path_mask | qp_path_mask_vlan_ctrl);
5361f0f829bfSRony Efraim 			if (work->vlan_id == MLX4_VGT) {
5362f0f829bfSRony Efraim 				upd_context->qp_context.param3 = qp->param3;
5363f0f829bfSRony Efraim 				upd_context->qp_context.pri_path.vlan_control = qp->vlan_control;
5364f0f829bfSRony Efraim 				upd_context->qp_context.pri_path.fvl_rx = qp->fvl_rx;
5365f0f829bfSRony Efraim 				upd_context->qp_context.pri_path.vlan_index = qp->vlan_index;
5366f0f829bfSRony Efraim 				upd_context->qp_context.pri_path.fl = qp->pri_path_fl;
5367f0f829bfSRony Efraim 				upd_context->qp_context.pri_path.feup = qp->feup;
5368f0f829bfSRony Efraim 				upd_context->qp_context.pri_path.sched_queue =
5369f0f829bfSRony Efraim 					qp->sched_queue;
5370f0f829bfSRony Efraim 			} else {
5371f0f829bfSRony Efraim 				upd_context->qp_context.param3 = qp->param3 & ~cpu_to_be32(MLX4_STRIP_VLAN);
5372f0f829bfSRony Efraim 				upd_context->qp_context.pri_path.vlan_control = vlan_control;
5373f0f829bfSRony Efraim 				upd_context->qp_context.pri_path.vlan_index = work->vlan_ix;
5374f0f829bfSRony Efraim 				upd_context->qp_context.pri_path.fvl_rx =
5375f0f829bfSRony Efraim 					qp->fvl_rx | MLX4_FVL_RX_FORCE_ETH_VLAN;
5376f0f829bfSRony Efraim 				upd_context->qp_context.pri_path.fl =
53777c3d21c8SMoshe Shemesh 					qp->pri_path_fl | MLX4_FL_ETH_HIDE_CQE_VLAN;
53787c3d21c8SMoshe Shemesh 				if (work->vlan_proto == htons(ETH_P_8021AD))
53797c3d21c8SMoshe Shemesh 					upd_context->qp_context.pri_path.fl |= MLX4_FL_SV;
53807c3d21c8SMoshe Shemesh 				else
53817c3d21c8SMoshe Shemesh 					upd_context->qp_context.pri_path.fl |= MLX4_FL_CV;
5382f0f829bfSRony Efraim 				upd_context->qp_context.pri_path.feup =
5383f0f829bfSRony Efraim 					qp->feup | MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN;
5384b01978caSJack Morgenstein 				upd_context->qp_context.pri_path.sched_queue =
5385b01978caSJack Morgenstein 					qp->sched_queue & 0xC7;
5386b01978caSJack Morgenstein 				upd_context->qp_context.pri_path.sched_queue |=
5387b01978caSJack Morgenstein 					((work->qos & 0x7) << 3);
5388269f9883SIdo Shamay 
5389269f9883SIdo Shamay 				if (dev->caps.flags2 &
5390269f9883SIdo Shamay 				    MLX4_DEV_CAP_FLAG2_QOS_VPP)
5391269f9883SIdo Shamay 					update_qos_vpp(upd_context, work);
5392f0f829bfSRony Efraim 			}
5393b01978caSJack Morgenstein 
5394b01978caSJack Morgenstein 			err = mlx4_cmd(dev, mailbox->dma,
5395b01978caSJack Morgenstein 				       qp->local_qpn & 0xffffff,
5396b01978caSJack Morgenstein 				       0, MLX4_CMD_UPDATE_QP,
5397b01978caSJack Morgenstein 				       MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
5398b01978caSJack Morgenstein 			if (err) {
53991a91de28SJoe Perches 				mlx4_info(dev, "UPDATE_QP failed for slave %d, port %d, qpn %d (%d)\n",
54001a91de28SJoe Perches 					  work->slave, port, qp->local_qpn, err);
5401b01978caSJack Morgenstein 				errors++;
5402b01978caSJack Morgenstein 			}
5403b01978caSJack Morgenstein 		}
5404b01978caSJack Morgenstein 		spin_lock_irq(mlx4_tlock(dev));
5405b01978caSJack Morgenstein 	}
5406b01978caSJack Morgenstein 	spin_unlock_irq(mlx4_tlock(dev));
5407b01978caSJack Morgenstein 	mlx4_free_cmd_mailbox(dev, mailbox);
5408b01978caSJack Morgenstein 
5409b01978caSJack Morgenstein 	if (errors)
5410b01978caSJack Morgenstein 		mlx4_err(dev, "%d UPDATE_QP failures for slave %d, port %d\n",
5411b01978caSJack Morgenstein 			 errors, work->slave, work->port);
5412b01978caSJack Morgenstein 
5413b01978caSJack Morgenstein 	/* unregister previous vlan_id if needed and we had no errors
5414b01978caSJack Morgenstein 	 * while updating the QPs
5415b01978caSJack Morgenstein 	 */
5416b01978caSJack Morgenstein 	if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN && !errors &&
5417b01978caSJack Morgenstein 	    NO_INDX != work->orig_vlan_ix)
5418b01978caSJack Morgenstein 		__mlx4_unregister_vlan(&work->priv->dev, work->port,
54192009d005SJack Morgenstein 				       work->orig_vlan_id);
5420b01978caSJack Morgenstein out:
5421b01978caSJack Morgenstein 	kfree(work);
5422b01978caSJack Morgenstein 	return;
5423b01978caSJack Morgenstein }
5424