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, ¶ms);
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, ®_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, ®_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, ®_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