1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2012 Mellanox Technologies. All rights reserved.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * This software is available to you under a choice of one of two
5*4882a593Smuzhiyun * licenses. You may choose to be licensed under the terms of the GNU
6*4882a593Smuzhiyun * General Public License (GPL) Version 2, available from the file
7*4882a593Smuzhiyun * COPYING in the main directory of this source tree, or the
8*4882a593Smuzhiyun * OpenIB.org BSD license below:
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Redistribution and use in source and binary forms, with or
11*4882a593Smuzhiyun * without modification, are permitted provided that the following
12*4882a593Smuzhiyun * conditions are met:
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * - Redistributions of source code must retain the above
15*4882a593Smuzhiyun * copyright notice, this list of conditions and the following
16*4882a593Smuzhiyun * disclaimer.
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * - Redistributions in binary form must reproduce the above
19*4882a593Smuzhiyun * copyright notice, this list of conditions and the following
20*4882a593Smuzhiyun * disclaimer in the documentation and/or other materials
21*4882a593Smuzhiyun * provided with the distribution.
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24*4882a593Smuzhiyun * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25*4882a593Smuzhiyun * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26*4882a593Smuzhiyun * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27*4882a593Smuzhiyun * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28*4882a593Smuzhiyun * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29*4882a593Smuzhiyun * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30*4882a593Smuzhiyun * SOFTWARE.
31*4882a593Smuzhiyun */
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #include <rdma/ib_mad.h>
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #include <linux/mlx4/cmd.h>
36*4882a593Smuzhiyun #include <linux/rbtree.h>
37*4882a593Smuzhiyun #include <linux/idr.h>
38*4882a593Smuzhiyun #include <rdma/ib_cm.h>
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #include "mlx4_ib.h"
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #define CM_CLEANUP_CACHE_TIMEOUT (30 * HZ)
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun struct id_map_entry {
45*4882a593Smuzhiyun struct rb_node node;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun u32 sl_cm_id;
48*4882a593Smuzhiyun u32 pv_cm_id;
49*4882a593Smuzhiyun int slave_id;
50*4882a593Smuzhiyun int scheduled_delete;
51*4882a593Smuzhiyun struct mlx4_ib_dev *dev;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun struct list_head list;
54*4882a593Smuzhiyun struct delayed_work timeout;
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun struct rej_tmout_entry {
58*4882a593Smuzhiyun int slave;
59*4882a593Smuzhiyun u32 rem_pv_cm_id;
60*4882a593Smuzhiyun struct delayed_work timeout;
61*4882a593Smuzhiyun struct xarray *xa_rej_tmout;
62*4882a593Smuzhiyun };
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun struct cm_generic_msg {
65*4882a593Smuzhiyun struct ib_mad_hdr hdr;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun __be32 local_comm_id;
68*4882a593Smuzhiyun __be32 remote_comm_id;
69*4882a593Smuzhiyun unsigned char unused[2];
70*4882a593Smuzhiyun __be16 rej_reason;
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun struct cm_sidr_generic_msg {
74*4882a593Smuzhiyun struct ib_mad_hdr hdr;
75*4882a593Smuzhiyun __be32 request_id;
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun struct cm_req_msg {
79*4882a593Smuzhiyun unsigned char unused[0x60];
80*4882a593Smuzhiyun union ib_gid primary_path_sgid;
81*4882a593Smuzhiyun };
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun
set_local_comm_id(struct ib_mad * mad,u32 cm_id)84*4882a593Smuzhiyun static void set_local_comm_id(struct ib_mad *mad, u32 cm_id)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
87*4882a593Smuzhiyun struct cm_sidr_generic_msg *msg =
88*4882a593Smuzhiyun (struct cm_sidr_generic_msg *)mad;
89*4882a593Smuzhiyun msg->request_id = cpu_to_be32(cm_id);
90*4882a593Smuzhiyun } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
91*4882a593Smuzhiyun pr_err("trying to set local_comm_id in SIDR_REP\n");
92*4882a593Smuzhiyun return;
93*4882a593Smuzhiyun } else {
94*4882a593Smuzhiyun struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
95*4882a593Smuzhiyun msg->local_comm_id = cpu_to_be32(cm_id);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
get_local_comm_id(struct ib_mad * mad)99*4882a593Smuzhiyun static u32 get_local_comm_id(struct ib_mad *mad)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
102*4882a593Smuzhiyun struct cm_sidr_generic_msg *msg =
103*4882a593Smuzhiyun (struct cm_sidr_generic_msg *)mad;
104*4882a593Smuzhiyun return be32_to_cpu(msg->request_id);
105*4882a593Smuzhiyun } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
106*4882a593Smuzhiyun pr_err("trying to set local_comm_id in SIDR_REP\n");
107*4882a593Smuzhiyun return -1;
108*4882a593Smuzhiyun } else {
109*4882a593Smuzhiyun struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
110*4882a593Smuzhiyun return be32_to_cpu(msg->local_comm_id);
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
set_remote_comm_id(struct ib_mad * mad,u32 cm_id)114*4882a593Smuzhiyun static void set_remote_comm_id(struct ib_mad *mad, u32 cm_id)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
117*4882a593Smuzhiyun struct cm_sidr_generic_msg *msg =
118*4882a593Smuzhiyun (struct cm_sidr_generic_msg *)mad;
119*4882a593Smuzhiyun msg->request_id = cpu_to_be32(cm_id);
120*4882a593Smuzhiyun } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
121*4882a593Smuzhiyun pr_err("trying to set remote_comm_id in SIDR_REQ\n");
122*4882a593Smuzhiyun return;
123*4882a593Smuzhiyun } else {
124*4882a593Smuzhiyun struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
125*4882a593Smuzhiyun msg->remote_comm_id = cpu_to_be32(cm_id);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
get_remote_comm_id(struct ib_mad * mad)129*4882a593Smuzhiyun static u32 get_remote_comm_id(struct ib_mad *mad)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
132*4882a593Smuzhiyun struct cm_sidr_generic_msg *msg =
133*4882a593Smuzhiyun (struct cm_sidr_generic_msg *)mad;
134*4882a593Smuzhiyun return be32_to_cpu(msg->request_id);
135*4882a593Smuzhiyun } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
136*4882a593Smuzhiyun pr_err("trying to set remote_comm_id in SIDR_REQ\n");
137*4882a593Smuzhiyun return -1;
138*4882a593Smuzhiyun } else {
139*4882a593Smuzhiyun struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
140*4882a593Smuzhiyun return be32_to_cpu(msg->remote_comm_id);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
gid_from_req_msg(struct ib_device * ibdev,struct ib_mad * mad)144*4882a593Smuzhiyun static union ib_gid gid_from_req_msg(struct ib_device *ibdev, struct ib_mad *mad)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun struct cm_req_msg *msg = (struct cm_req_msg *)mad;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun return msg->primary_path_sgid;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun /* Lock should be taken before called */
152*4882a593Smuzhiyun static struct id_map_entry *
id_map_find_by_sl_id(struct ib_device * ibdev,u32 slave_id,u32 sl_cm_id)153*4882a593Smuzhiyun id_map_find_by_sl_id(struct ib_device *ibdev, u32 slave_id, u32 sl_cm_id)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun struct rb_root *sl_id_map = &to_mdev(ibdev)->sriov.sl_id_map;
156*4882a593Smuzhiyun struct rb_node *node = sl_id_map->rb_node;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun while (node) {
159*4882a593Smuzhiyun struct id_map_entry *id_map_entry =
160*4882a593Smuzhiyun rb_entry(node, struct id_map_entry, node);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun if (id_map_entry->sl_cm_id > sl_cm_id)
163*4882a593Smuzhiyun node = node->rb_left;
164*4882a593Smuzhiyun else if (id_map_entry->sl_cm_id < sl_cm_id)
165*4882a593Smuzhiyun node = node->rb_right;
166*4882a593Smuzhiyun else if (id_map_entry->slave_id > slave_id)
167*4882a593Smuzhiyun node = node->rb_left;
168*4882a593Smuzhiyun else if (id_map_entry->slave_id < slave_id)
169*4882a593Smuzhiyun node = node->rb_right;
170*4882a593Smuzhiyun else
171*4882a593Smuzhiyun return id_map_entry;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun return NULL;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
id_map_ent_timeout(struct work_struct * work)176*4882a593Smuzhiyun static void id_map_ent_timeout(struct work_struct *work)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun struct delayed_work *delay = to_delayed_work(work);
179*4882a593Smuzhiyun struct id_map_entry *ent = container_of(delay, struct id_map_entry, timeout);
180*4882a593Smuzhiyun struct id_map_entry *found_ent;
181*4882a593Smuzhiyun struct mlx4_ib_dev *dev = ent->dev;
182*4882a593Smuzhiyun struct mlx4_ib_sriov *sriov = &dev->sriov;
183*4882a593Smuzhiyun struct rb_root *sl_id_map = &sriov->sl_id_map;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun spin_lock(&sriov->id_map_lock);
186*4882a593Smuzhiyun if (!xa_erase(&sriov->pv_id_table, ent->pv_cm_id))
187*4882a593Smuzhiyun goto out;
188*4882a593Smuzhiyun found_ent = id_map_find_by_sl_id(&dev->ib_dev, ent->slave_id, ent->sl_cm_id);
189*4882a593Smuzhiyun if (found_ent && found_ent == ent)
190*4882a593Smuzhiyun rb_erase(&found_ent->node, sl_id_map);
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun out:
193*4882a593Smuzhiyun list_del(&ent->list);
194*4882a593Smuzhiyun spin_unlock(&sriov->id_map_lock);
195*4882a593Smuzhiyun kfree(ent);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
sl_id_map_add(struct ib_device * ibdev,struct id_map_entry * new)198*4882a593Smuzhiyun static void sl_id_map_add(struct ib_device *ibdev, struct id_map_entry *new)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun struct rb_root *sl_id_map = &to_mdev(ibdev)->sriov.sl_id_map;
201*4882a593Smuzhiyun struct rb_node **link = &sl_id_map->rb_node, *parent = NULL;
202*4882a593Smuzhiyun struct id_map_entry *ent;
203*4882a593Smuzhiyun int slave_id = new->slave_id;
204*4882a593Smuzhiyun int sl_cm_id = new->sl_cm_id;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun ent = id_map_find_by_sl_id(ibdev, slave_id, sl_cm_id);
207*4882a593Smuzhiyun if (ent) {
208*4882a593Smuzhiyun pr_debug("overriding existing sl_id_map entry (cm_id = %x)\n",
209*4882a593Smuzhiyun sl_cm_id);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun rb_replace_node(&ent->node, &new->node, sl_id_map);
212*4882a593Smuzhiyun return;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /* Go to the bottom of the tree */
216*4882a593Smuzhiyun while (*link) {
217*4882a593Smuzhiyun parent = *link;
218*4882a593Smuzhiyun ent = rb_entry(parent, struct id_map_entry, node);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun if (ent->sl_cm_id > sl_cm_id || (ent->sl_cm_id == sl_cm_id && ent->slave_id > slave_id))
221*4882a593Smuzhiyun link = &(*link)->rb_left;
222*4882a593Smuzhiyun else
223*4882a593Smuzhiyun link = &(*link)->rb_right;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun rb_link_node(&new->node, parent, link);
227*4882a593Smuzhiyun rb_insert_color(&new->node, sl_id_map);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun static struct id_map_entry *
id_map_alloc(struct ib_device * ibdev,int slave_id,u32 sl_cm_id)231*4882a593Smuzhiyun id_map_alloc(struct ib_device *ibdev, int slave_id, u32 sl_cm_id)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun int ret;
234*4882a593Smuzhiyun struct id_map_entry *ent;
235*4882a593Smuzhiyun struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun ent = kmalloc(sizeof (struct id_map_entry), GFP_KERNEL);
238*4882a593Smuzhiyun if (!ent)
239*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun ent->sl_cm_id = sl_cm_id;
242*4882a593Smuzhiyun ent->slave_id = slave_id;
243*4882a593Smuzhiyun ent->scheduled_delete = 0;
244*4882a593Smuzhiyun ent->dev = to_mdev(ibdev);
245*4882a593Smuzhiyun INIT_DELAYED_WORK(&ent->timeout, id_map_ent_timeout);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun ret = xa_alloc_cyclic(&sriov->pv_id_table, &ent->pv_cm_id, ent,
248*4882a593Smuzhiyun xa_limit_32b, &sriov->pv_id_next, GFP_KERNEL);
249*4882a593Smuzhiyun if (ret >= 0) {
250*4882a593Smuzhiyun spin_lock(&sriov->id_map_lock);
251*4882a593Smuzhiyun sl_id_map_add(ibdev, ent);
252*4882a593Smuzhiyun list_add_tail(&ent->list, &sriov->cm_list);
253*4882a593Smuzhiyun spin_unlock(&sriov->id_map_lock);
254*4882a593Smuzhiyun return ent;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /*error flow*/
258*4882a593Smuzhiyun kfree(ent);
259*4882a593Smuzhiyun mlx4_ib_warn(ibdev, "Allocation failed (err:0x%x)\n", ret);
260*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun static struct id_map_entry *
id_map_get(struct ib_device * ibdev,int * pv_cm_id,int slave_id,int sl_cm_id)264*4882a593Smuzhiyun id_map_get(struct ib_device *ibdev, int *pv_cm_id, int slave_id, int sl_cm_id)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun struct id_map_entry *ent;
267*4882a593Smuzhiyun struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun spin_lock(&sriov->id_map_lock);
270*4882a593Smuzhiyun if (*pv_cm_id == -1) {
271*4882a593Smuzhiyun ent = id_map_find_by_sl_id(ibdev, slave_id, sl_cm_id);
272*4882a593Smuzhiyun if (ent)
273*4882a593Smuzhiyun *pv_cm_id = (int) ent->pv_cm_id;
274*4882a593Smuzhiyun } else
275*4882a593Smuzhiyun ent = xa_load(&sriov->pv_id_table, *pv_cm_id);
276*4882a593Smuzhiyun spin_unlock(&sriov->id_map_lock);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun return ent;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
schedule_delayed(struct ib_device * ibdev,struct id_map_entry * id)281*4882a593Smuzhiyun static void schedule_delayed(struct ib_device *ibdev, struct id_map_entry *id)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov;
284*4882a593Smuzhiyun unsigned long flags;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun spin_lock(&sriov->id_map_lock);
287*4882a593Smuzhiyun spin_lock_irqsave(&sriov->going_down_lock, flags);
288*4882a593Smuzhiyun /*make sure that there is no schedule inside the scheduled work.*/
289*4882a593Smuzhiyun if (!sriov->is_going_down && !id->scheduled_delete) {
290*4882a593Smuzhiyun id->scheduled_delete = 1;
291*4882a593Smuzhiyun schedule_delayed_work(&id->timeout, CM_CLEANUP_CACHE_TIMEOUT);
292*4882a593Smuzhiyun } else if (id->scheduled_delete) {
293*4882a593Smuzhiyun /* Adjust timeout if already scheduled */
294*4882a593Smuzhiyun mod_delayed_work(system_wq, &id->timeout, CM_CLEANUP_CACHE_TIMEOUT);
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun spin_unlock_irqrestore(&sriov->going_down_lock, flags);
297*4882a593Smuzhiyun spin_unlock(&sriov->id_map_lock);
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun #define REJ_REASON(m) be16_to_cpu(((struct cm_generic_msg *)(m))->rej_reason)
mlx4_ib_multiplex_cm_handler(struct ib_device * ibdev,int port,int slave_id,struct ib_mad * mad)301*4882a593Smuzhiyun int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id,
302*4882a593Smuzhiyun struct ib_mad *mad)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun struct id_map_entry *id;
305*4882a593Smuzhiyun u32 sl_cm_id;
306*4882a593Smuzhiyun int pv_cm_id = -1;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID ||
309*4882a593Smuzhiyun mad->mad_hdr.attr_id == CM_REP_ATTR_ID ||
310*4882a593Smuzhiyun mad->mad_hdr.attr_id == CM_MRA_ATTR_ID ||
311*4882a593Smuzhiyun mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID ||
312*4882a593Smuzhiyun (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID && REJ_REASON(mad) == IB_CM_REJ_TIMEOUT)) {
313*4882a593Smuzhiyun sl_cm_id = get_local_comm_id(mad);
314*4882a593Smuzhiyun id = id_map_get(ibdev, &pv_cm_id, slave_id, sl_cm_id);
315*4882a593Smuzhiyun if (id)
316*4882a593Smuzhiyun goto cont;
317*4882a593Smuzhiyun id = id_map_alloc(ibdev, slave_id, sl_cm_id);
318*4882a593Smuzhiyun if (IS_ERR(id)) {
319*4882a593Smuzhiyun mlx4_ib_warn(ibdev, "%s: id{slave: %d, sl_cm_id: 0x%x} Failed to id_map_alloc\n",
320*4882a593Smuzhiyun __func__, slave_id, sl_cm_id);
321*4882a593Smuzhiyun return PTR_ERR(id);
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID ||
324*4882a593Smuzhiyun mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
325*4882a593Smuzhiyun return 0;
326*4882a593Smuzhiyun } else {
327*4882a593Smuzhiyun sl_cm_id = get_local_comm_id(mad);
328*4882a593Smuzhiyun id = id_map_get(ibdev, &pv_cm_id, slave_id, sl_cm_id);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun if (!id) {
332*4882a593Smuzhiyun pr_debug("id{slave: %d, sl_cm_id: 0x%x} is NULL! attr_id: 0x%x\n",
333*4882a593Smuzhiyun slave_id, sl_cm_id, be16_to_cpu(mad->mad_hdr.attr_id));
334*4882a593Smuzhiyun return -EINVAL;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun cont:
338*4882a593Smuzhiyun set_local_comm_id(mad, id->pv_cm_id);
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID)
341*4882a593Smuzhiyun schedule_delayed(ibdev, id);
342*4882a593Smuzhiyun return 0;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
rej_tmout_timeout(struct work_struct * work)345*4882a593Smuzhiyun static void rej_tmout_timeout(struct work_struct *work)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun struct delayed_work *delay = to_delayed_work(work);
348*4882a593Smuzhiyun struct rej_tmout_entry *item = container_of(delay, struct rej_tmout_entry, timeout);
349*4882a593Smuzhiyun struct rej_tmout_entry *deleted;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun deleted = xa_cmpxchg(item->xa_rej_tmout, item->rem_pv_cm_id, item, NULL, 0);
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun if (deleted != item)
354*4882a593Smuzhiyun pr_debug("deleted(%p) != item(%p)\n", deleted, item);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun kfree(item);
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
alloc_rej_tmout(struct mlx4_ib_sriov * sriov,u32 rem_pv_cm_id,int slave)359*4882a593Smuzhiyun static int alloc_rej_tmout(struct mlx4_ib_sriov *sriov, u32 rem_pv_cm_id, int slave)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun struct rej_tmout_entry *item;
362*4882a593Smuzhiyun struct rej_tmout_entry *old;
363*4882a593Smuzhiyun int ret = 0;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun xa_lock(&sriov->xa_rej_tmout);
366*4882a593Smuzhiyun item = xa_load(&sriov->xa_rej_tmout, (unsigned long)rem_pv_cm_id);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun if (item) {
369*4882a593Smuzhiyun if (xa_err(item))
370*4882a593Smuzhiyun ret = xa_err(item);
371*4882a593Smuzhiyun else
372*4882a593Smuzhiyun /* If a retry, adjust delayed work */
373*4882a593Smuzhiyun mod_delayed_work(system_wq, &item->timeout, CM_CLEANUP_CACHE_TIMEOUT);
374*4882a593Smuzhiyun goto err_or_exists;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun xa_unlock(&sriov->xa_rej_tmout);
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun item = kmalloc(sizeof(*item), GFP_KERNEL);
379*4882a593Smuzhiyun if (!item)
380*4882a593Smuzhiyun return -ENOMEM;
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun INIT_DELAYED_WORK(&item->timeout, rej_tmout_timeout);
383*4882a593Smuzhiyun item->slave = slave;
384*4882a593Smuzhiyun item->rem_pv_cm_id = rem_pv_cm_id;
385*4882a593Smuzhiyun item->xa_rej_tmout = &sriov->xa_rej_tmout;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun old = xa_cmpxchg(&sriov->xa_rej_tmout, (unsigned long)rem_pv_cm_id, NULL, item, GFP_KERNEL);
388*4882a593Smuzhiyun if (old) {
389*4882a593Smuzhiyun pr_debug(
390*4882a593Smuzhiyun "Non-null old entry (%p) or error (%d) when inserting\n",
391*4882a593Smuzhiyun old, xa_err(old));
392*4882a593Smuzhiyun kfree(item);
393*4882a593Smuzhiyun return xa_err(old);
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun schedule_delayed_work(&item->timeout, CM_CLEANUP_CACHE_TIMEOUT);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun return 0;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun err_or_exists:
401*4882a593Smuzhiyun xa_unlock(&sriov->xa_rej_tmout);
402*4882a593Smuzhiyun return ret;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
lookup_rej_tmout_slave(struct mlx4_ib_sriov * sriov,u32 rem_pv_cm_id)405*4882a593Smuzhiyun static int lookup_rej_tmout_slave(struct mlx4_ib_sriov *sriov, u32 rem_pv_cm_id)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun struct rej_tmout_entry *item;
408*4882a593Smuzhiyun int slave;
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun xa_lock(&sriov->xa_rej_tmout);
411*4882a593Smuzhiyun item = xa_load(&sriov->xa_rej_tmout, (unsigned long)rem_pv_cm_id);
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun if (!item || xa_err(item)) {
414*4882a593Smuzhiyun pr_debug("Could not find slave. rem_pv_cm_id 0x%x error: %d\n",
415*4882a593Smuzhiyun rem_pv_cm_id, xa_err(item));
416*4882a593Smuzhiyun slave = !item ? -ENOENT : xa_err(item);
417*4882a593Smuzhiyun } else {
418*4882a593Smuzhiyun slave = item->slave;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun xa_unlock(&sriov->xa_rej_tmout);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun return slave;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
mlx4_ib_demux_cm_handler(struct ib_device * ibdev,int port,int * slave,struct ib_mad * mad)425*4882a593Smuzhiyun int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
426*4882a593Smuzhiyun struct ib_mad *mad)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov;
429*4882a593Smuzhiyun u32 rem_pv_cm_id = get_local_comm_id(mad);
430*4882a593Smuzhiyun u32 pv_cm_id;
431*4882a593Smuzhiyun struct id_map_entry *id;
432*4882a593Smuzhiyun int sts;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID ||
435*4882a593Smuzhiyun mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
436*4882a593Smuzhiyun union ib_gid gid;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun if (!slave)
439*4882a593Smuzhiyun return 0;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun gid = gid_from_req_msg(ibdev, mad);
442*4882a593Smuzhiyun *slave = mlx4_ib_find_real_gid(ibdev, port, gid.global.interface_id);
443*4882a593Smuzhiyun if (*slave < 0) {
444*4882a593Smuzhiyun mlx4_ib_warn(ibdev, "failed matching slave_id by gid (0x%llx)\n",
445*4882a593Smuzhiyun be64_to_cpu(gid.global.interface_id));
446*4882a593Smuzhiyun return -ENOENT;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun sts = alloc_rej_tmout(sriov, rem_pv_cm_id, *slave);
450*4882a593Smuzhiyun if (sts)
451*4882a593Smuzhiyun /* Even if this fails, we pass on the REQ to the slave */
452*4882a593Smuzhiyun pr_debug("Could not allocate rej_tmout entry. rem_pv_cm_id 0x%x slave %d status %d\n",
453*4882a593Smuzhiyun rem_pv_cm_id, *slave, sts);
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun return 0;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun pv_cm_id = get_remote_comm_id(mad);
459*4882a593Smuzhiyun id = id_map_get(ibdev, (int *)&pv_cm_id, -1, -1);
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun if (!id) {
462*4882a593Smuzhiyun if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID &&
463*4882a593Smuzhiyun REJ_REASON(mad) == IB_CM_REJ_TIMEOUT && slave) {
464*4882a593Smuzhiyun *slave = lookup_rej_tmout_slave(sriov, rem_pv_cm_id);
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun return (*slave < 0) ? *slave : 0;
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun pr_debug("Couldn't find an entry for pv_cm_id 0x%x, attr_id 0x%x\n",
469*4882a593Smuzhiyun pv_cm_id, be16_to_cpu(mad->mad_hdr.attr_id));
470*4882a593Smuzhiyun return -ENOENT;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun if (slave)
474*4882a593Smuzhiyun *slave = id->slave_id;
475*4882a593Smuzhiyun set_remote_comm_id(mad, id->sl_cm_id);
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID ||
478*4882a593Smuzhiyun mad->mad_hdr.attr_id == CM_REJ_ATTR_ID)
479*4882a593Smuzhiyun schedule_delayed(ibdev, id);
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun return 0;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun
mlx4_ib_cm_paravirt_init(struct mlx4_ib_dev * dev)484*4882a593Smuzhiyun void mlx4_ib_cm_paravirt_init(struct mlx4_ib_dev *dev)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun spin_lock_init(&dev->sriov.id_map_lock);
487*4882a593Smuzhiyun INIT_LIST_HEAD(&dev->sriov.cm_list);
488*4882a593Smuzhiyun dev->sriov.sl_id_map = RB_ROOT;
489*4882a593Smuzhiyun xa_init_flags(&dev->sriov.pv_id_table, XA_FLAGS_ALLOC);
490*4882a593Smuzhiyun xa_init(&dev->sriov.xa_rej_tmout);
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun
rej_tmout_xa_cleanup(struct mlx4_ib_sriov * sriov,int slave)493*4882a593Smuzhiyun static void rej_tmout_xa_cleanup(struct mlx4_ib_sriov *sriov, int slave)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun struct rej_tmout_entry *item;
496*4882a593Smuzhiyun bool flush_needed = false;
497*4882a593Smuzhiyun unsigned long id;
498*4882a593Smuzhiyun int cnt = 0;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun xa_lock(&sriov->xa_rej_tmout);
501*4882a593Smuzhiyun xa_for_each(&sriov->xa_rej_tmout, id, item) {
502*4882a593Smuzhiyun if (slave < 0 || slave == item->slave) {
503*4882a593Smuzhiyun mod_delayed_work(system_wq, &item->timeout, 0);
504*4882a593Smuzhiyun flush_needed = true;
505*4882a593Smuzhiyun ++cnt;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun xa_unlock(&sriov->xa_rej_tmout);
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun if (flush_needed) {
511*4882a593Smuzhiyun flush_scheduled_work();
512*4882a593Smuzhiyun pr_debug("Deleted %d entries in xarray for slave %d during cleanup\n",
513*4882a593Smuzhiyun cnt, slave);
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun if (slave < 0)
517*4882a593Smuzhiyun WARN_ON(!xa_empty(&sriov->xa_rej_tmout));
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun /* slave = -1 ==> all slaves */
521*4882a593Smuzhiyun /* TBD -- call paravirt clean for single slave. Need for slave RESET event */
mlx4_ib_cm_paravirt_clean(struct mlx4_ib_dev * dev,int slave)522*4882a593Smuzhiyun void mlx4_ib_cm_paravirt_clean(struct mlx4_ib_dev *dev, int slave)
523*4882a593Smuzhiyun {
524*4882a593Smuzhiyun struct mlx4_ib_sriov *sriov = &dev->sriov;
525*4882a593Smuzhiyun struct rb_root *sl_id_map = &sriov->sl_id_map;
526*4882a593Smuzhiyun struct list_head lh;
527*4882a593Smuzhiyun struct rb_node *nd;
528*4882a593Smuzhiyun int need_flush = 0;
529*4882a593Smuzhiyun struct id_map_entry *map, *tmp_map;
530*4882a593Smuzhiyun /* cancel all delayed work queue entries */
531*4882a593Smuzhiyun INIT_LIST_HEAD(&lh);
532*4882a593Smuzhiyun spin_lock(&sriov->id_map_lock);
533*4882a593Smuzhiyun list_for_each_entry_safe(map, tmp_map, &dev->sriov.cm_list, list) {
534*4882a593Smuzhiyun if (slave < 0 || slave == map->slave_id) {
535*4882a593Smuzhiyun if (map->scheduled_delete)
536*4882a593Smuzhiyun need_flush |= !cancel_delayed_work(&map->timeout);
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun spin_unlock(&sriov->id_map_lock);
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun if (need_flush)
543*4882a593Smuzhiyun flush_scheduled_work(); /* make sure all timers were flushed */
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun /* now, remove all leftover entries from databases*/
546*4882a593Smuzhiyun spin_lock(&sriov->id_map_lock);
547*4882a593Smuzhiyun if (slave < 0) {
548*4882a593Smuzhiyun while (rb_first(sl_id_map)) {
549*4882a593Smuzhiyun struct id_map_entry *ent =
550*4882a593Smuzhiyun rb_entry(rb_first(sl_id_map),
551*4882a593Smuzhiyun struct id_map_entry, node);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun rb_erase(&ent->node, sl_id_map);
554*4882a593Smuzhiyun xa_erase(&sriov->pv_id_table, ent->pv_cm_id);
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun list_splice_init(&dev->sriov.cm_list, &lh);
557*4882a593Smuzhiyun } else {
558*4882a593Smuzhiyun /* first, move nodes belonging to slave to db remove list */
559*4882a593Smuzhiyun nd = rb_first(sl_id_map);
560*4882a593Smuzhiyun while (nd) {
561*4882a593Smuzhiyun struct id_map_entry *ent =
562*4882a593Smuzhiyun rb_entry(nd, struct id_map_entry, node);
563*4882a593Smuzhiyun nd = rb_next(nd);
564*4882a593Smuzhiyun if (ent->slave_id == slave)
565*4882a593Smuzhiyun list_move_tail(&ent->list, &lh);
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun /* remove those nodes from databases */
568*4882a593Smuzhiyun list_for_each_entry_safe(map, tmp_map, &lh, list) {
569*4882a593Smuzhiyun rb_erase(&map->node, sl_id_map);
570*4882a593Smuzhiyun xa_erase(&sriov->pv_id_table, map->pv_cm_id);
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun /* add remaining nodes from cm_list */
574*4882a593Smuzhiyun list_for_each_entry_safe(map, tmp_map, &dev->sriov.cm_list, list) {
575*4882a593Smuzhiyun if (slave == map->slave_id)
576*4882a593Smuzhiyun list_move_tail(&map->list, &lh);
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun spin_unlock(&sriov->id_map_lock);
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun /* free any map entries left behind due to cancel_delayed_work above */
583*4882a593Smuzhiyun list_for_each_entry_safe(map, tmp_map, &lh, list) {
584*4882a593Smuzhiyun list_del(&map->list);
585*4882a593Smuzhiyun kfree(map);
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun rej_tmout_xa_cleanup(sriov, slave);
589*4882a593Smuzhiyun }
590