xref: /openbmc/linux/drivers/infiniband/hw/mlx4/mad.c (revision fc06573dfaf8a33bc0533bb70c49de13fa5232a4)
1225c7b1fSRoland Dreier /*
2225c7b1fSRoland Dreier  * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
3225c7b1fSRoland Dreier  *
4225c7b1fSRoland Dreier  * This software is available to you under a choice of one of two
5225c7b1fSRoland Dreier  * licenses.  You may choose to be licensed under the terms of the GNU
6225c7b1fSRoland Dreier  * General Public License (GPL) Version 2, available from the file
7225c7b1fSRoland Dreier  * COPYING in the main directory of this source tree, or the
8225c7b1fSRoland Dreier  * OpenIB.org BSD license below:
9225c7b1fSRoland Dreier  *
10225c7b1fSRoland Dreier  *     Redistribution and use in source and binary forms, with or
11225c7b1fSRoland Dreier  *     without modification, are permitted provided that the following
12225c7b1fSRoland Dreier  *     conditions are met:
13225c7b1fSRoland Dreier  *
14225c7b1fSRoland Dreier  *      - Redistributions of source code must retain the above
15225c7b1fSRoland Dreier  *        copyright notice, this list of conditions and the following
16225c7b1fSRoland Dreier  *        disclaimer.
17225c7b1fSRoland Dreier  *
18225c7b1fSRoland Dreier  *      - Redistributions in binary form must reproduce the above
19225c7b1fSRoland Dreier  *        copyright notice, this list of conditions and the following
20225c7b1fSRoland Dreier  *        disclaimer in the documentation and/or other materials
21225c7b1fSRoland Dreier  *        provided with the distribution.
22225c7b1fSRoland Dreier  *
23225c7b1fSRoland Dreier  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24225c7b1fSRoland Dreier  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25225c7b1fSRoland Dreier  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26225c7b1fSRoland Dreier  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27225c7b1fSRoland Dreier  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28225c7b1fSRoland Dreier  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29225c7b1fSRoland Dreier  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30225c7b1fSRoland Dreier  * SOFTWARE.
31225c7b1fSRoland Dreier  */
32225c7b1fSRoland Dreier 
33225c7b1fSRoland Dreier #include <rdma/ib_mad.h>
34225c7b1fSRoland Dreier #include <rdma/ib_smi.h>
35225c7b1fSRoland Dreier 
36225c7b1fSRoland Dreier #include <linux/mlx4/cmd.h>
375a0e3ad6STejun Heo #include <linux/gfp.h>
38c3779134SOr Gerlitz #include <rdma/ib_pma.h>
39225c7b1fSRoland Dreier 
40225c7b1fSRoland Dreier #include "mlx4_ib.h"
41225c7b1fSRoland Dreier 
42225c7b1fSRoland Dreier enum {
43225c7b1fSRoland Dreier 	MLX4_IB_VENDOR_CLASS1 = 0x9,
44225c7b1fSRoland Dreier 	MLX4_IB_VENDOR_CLASS2 = 0xa
45225c7b1fSRoland Dreier };
46225c7b1fSRoland Dreier 
47*fc06573dSJack Morgenstein #define MLX4_TUN_SEND_WRID_SHIFT 34
48*fc06573dSJack Morgenstein #define MLX4_TUN_QPN_SHIFT 32
49*fc06573dSJack Morgenstein #define MLX4_TUN_WRID_RECV (((u64) 1) << MLX4_TUN_SEND_WRID_SHIFT)
50*fc06573dSJack Morgenstein #define MLX4_TUN_SET_WRID_QPN(a) (((u64) ((a) & 0x3)) << MLX4_TUN_QPN_SHIFT)
51*fc06573dSJack Morgenstein 
52*fc06573dSJack Morgenstein #define MLX4_TUN_IS_RECV(a)  (((a) >>  MLX4_TUN_SEND_WRID_SHIFT) & 0x1)
53*fc06573dSJack Morgenstein #define MLX4_TUN_WRID_QPN(a) (((a) >> MLX4_TUN_QPN_SHIFT) & 0x3)
54*fc06573dSJack Morgenstein 
55*fc06573dSJack Morgenstein struct mlx4_mad_rcv_buf {
56*fc06573dSJack Morgenstein 	struct ib_grh grh;
57*fc06573dSJack Morgenstein 	u8 payload[256];
58*fc06573dSJack Morgenstein } __packed;
59*fc06573dSJack Morgenstein 
60*fc06573dSJack Morgenstein struct mlx4_mad_snd_buf {
61*fc06573dSJack Morgenstein 	u8 payload[256];
62*fc06573dSJack Morgenstein } __packed;
63*fc06573dSJack Morgenstein 
64*fc06573dSJack Morgenstein struct mlx4_tunnel_mad {
65*fc06573dSJack Morgenstein 	struct ib_grh grh;
66*fc06573dSJack Morgenstein 	struct mlx4_ib_tunnel_header hdr;
67*fc06573dSJack Morgenstein 	struct ib_mad mad;
68*fc06573dSJack Morgenstein } __packed;
69*fc06573dSJack Morgenstein 
70*fc06573dSJack Morgenstein struct mlx4_rcv_tunnel_mad {
71*fc06573dSJack Morgenstein 	struct mlx4_rcv_tunnel_hdr hdr;
72*fc06573dSJack Morgenstein 	struct ib_grh grh;
73*fc06573dSJack Morgenstein 	struct ib_mad mad;
74*fc06573dSJack Morgenstein } __packed;
75*fc06573dSJack Morgenstein 
76225c7b1fSRoland Dreier int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int ignore_mkey, int ignore_bkey,
77225c7b1fSRoland Dreier 		 int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
78225c7b1fSRoland Dreier 		 void *in_mad, void *response_mad)
79225c7b1fSRoland Dreier {
80225c7b1fSRoland Dreier 	struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
81225c7b1fSRoland Dreier 	void *inbox;
82225c7b1fSRoland Dreier 	int err;
83225c7b1fSRoland Dreier 	u32 in_modifier = port;
84225c7b1fSRoland Dreier 	u8 op_modifier = 0;
85225c7b1fSRoland Dreier 
86225c7b1fSRoland Dreier 	inmailbox = mlx4_alloc_cmd_mailbox(dev->dev);
87225c7b1fSRoland Dreier 	if (IS_ERR(inmailbox))
88225c7b1fSRoland Dreier 		return PTR_ERR(inmailbox);
89225c7b1fSRoland Dreier 	inbox = inmailbox->buf;
90225c7b1fSRoland Dreier 
91225c7b1fSRoland Dreier 	outmailbox = mlx4_alloc_cmd_mailbox(dev->dev);
92225c7b1fSRoland Dreier 	if (IS_ERR(outmailbox)) {
93225c7b1fSRoland Dreier 		mlx4_free_cmd_mailbox(dev->dev, inmailbox);
94225c7b1fSRoland Dreier 		return PTR_ERR(outmailbox);
95225c7b1fSRoland Dreier 	}
96225c7b1fSRoland Dreier 
97225c7b1fSRoland Dreier 	memcpy(inbox, in_mad, 256);
98225c7b1fSRoland Dreier 
99225c7b1fSRoland Dreier 	/*
100225c7b1fSRoland Dreier 	 * Key check traps can't be generated unless we have in_wc to
101225c7b1fSRoland Dreier 	 * tell us where to send the trap.
102225c7b1fSRoland Dreier 	 */
103225c7b1fSRoland Dreier 	if (ignore_mkey || !in_wc)
104225c7b1fSRoland Dreier 		op_modifier |= 0x1;
105225c7b1fSRoland Dreier 	if (ignore_bkey || !in_wc)
106225c7b1fSRoland Dreier 		op_modifier |= 0x2;
107225c7b1fSRoland Dreier 
108225c7b1fSRoland Dreier 	if (in_wc) {
109225c7b1fSRoland Dreier 		struct {
110225c7b1fSRoland Dreier 			__be32		my_qpn;
111225c7b1fSRoland Dreier 			u32		reserved1;
112225c7b1fSRoland Dreier 			__be32		rqpn;
113225c7b1fSRoland Dreier 			u8		sl;
114225c7b1fSRoland Dreier 			u8		g_path;
115225c7b1fSRoland Dreier 			u16		reserved2[2];
116225c7b1fSRoland Dreier 			__be16		pkey;
117225c7b1fSRoland Dreier 			u32		reserved3[11];
118225c7b1fSRoland Dreier 			u8		grh[40];
119225c7b1fSRoland Dreier 		} *ext_info;
120225c7b1fSRoland Dreier 
121225c7b1fSRoland Dreier 		memset(inbox + 256, 0, 256);
122225c7b1fSRoland Dreier 		ext_info = inbox + 256;
123225c7b1fSRoland Dreier 
124225c7b1fSRoland Dreier 		ext_info->my_qpn = cpu_to_be32(in_wc->qp->qp_num);
125225c7b1fSRoland Dreier 		ext_info->rqpn   = cpu_to_be32(in_wc->src_qp);
126225c7b1fSRoland Dreier 		ext_info->sl     = in_wc->sl << 4;
127225c7b1fSRoland Dreier 		ext_info->g_path = in_wc->dlid_path_bits |
128225c7b1fSRoland Dreier 			(in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0);
129225c7b1fSRoland Dreier 		ext_info->pkey   = cpu_to_be16(in_wc->pkey_index);
130225c7b1fSRoland Dreier 
131225c7b1fSRoland Dreier 		if (in_grh)
132225c7b1fSRoland Dreier 			memcpy(ext_info->grh, in_grh, 40);
133225c7b1fSRoland Dreier 
134225c7b1fSRoland Dreier 		op_modifier |= 0x4;
135225c7b1fSRoland Dreier 
136225c7b1fSRoland Dreier 		in_modifier |= in_wc->slid << 16;
137225c7b1fSRoland Dreier 	}
138225c7b1fSRoland Dreier 
139225c7b1fSRoland Dreier 	err = mlx4_cmd_box(dev->dev, inmailbox->dma, outmailbox->dma,
140225c7b1fSRoland Dreier 			   in_modifier, op_modifier,
141f9baff50SJack Morgenstein 			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
142f9baff50SJack Morgenstein 			   MLX4_CMD_NATIVE);
143225c7b1fSRoland Dreier 
144fe11cb6bSIlpo Järvinen 	if (!err)
145225c7b1fSRoland Dreier 		memcpy(response_mad, outmailbox->buf, 256);
146225c7b1fSRoland Dreier 
147225c7b1fSRoland Dreier 	mlx4_free_cmd_mailbox(dev->dev, inmailbox);
148225c7b1fSRoland Dreier 	mlx4_free_cmd_mailbox(dev->dev, outmailbox);
149225c7b1fSRoland Dreier 
150225c7b1fSRoland Dreier 	return err;
151225c7b1fSRoland Dreier }
152225c7b1fSRoland Dreier 
153225c7b1fSRoland Dreier static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl)
154225c7b1fSRoland Dreier {
155225c7b1fSRoland Dreier 	struct ib_ah *new_ah;
156225c7b1fSRoland Dreier 	struct ib_ah_attr ah_attr;
157df7fba66SJack Morgenstein 	unsigned long flags;
158225c7b1fSRoland Dreier 
159225c7b1fSRoland Dreier 	if (!dev->send_agent[port_num - 1][0])
160225c7b1fSRoland Dreier 		return;
161225c7b1fSRoland Dreier 
162225c7b1fSRoland Dreier 	memset(&ah_attr, 0, sizeof ah_attr);
163225c7b1fSRoland Dreier 	ah_attr.dlid     = lid;
164225c7b1fSRoland Dreier 	ah_attr.sl       = sl;
165225c7b1fSRoland Dreier 	ah_attr.port_num = port_num;
166225c7b1fSRoland Dreier 
167225c7b1fSRoland Dreier 	new_ah = ib_create_ah(dev->send_agent[port_num - 1][0]->qp->pd,
168225c7b1fSRoland Dreier 			      &ah_attr);
169225c7b1fSRoland Dreier 	if (IS_ERR(new_ah))
170225c7b1fSRoland Dreier 		return;
171225c7b1fSRoland Dreier 
172df7fba66SJack Morgenstein 	spin_lock_irqsave(&dev->sm_lock, flags);
173225c7b1fSRoland Dreier 	if (dev->sm_ah[port_num - 1])
174225c7b1fSRoland Dreier 		ib_destroy_ah(dev->sm_ah[port_num - 1]);
175225c7b1fSRoland Dreier 	dev->sm_ah[port_num - 1] = new_ah;
176df7fba66SJack Morgenstein 	spin_unlock_irqrestore(&dev->sm_lock, flags);
177225c7b1fSRoland Dreier }
178225c7b1fSRoland Dreier 
179225c7b1fSRoland Dreier /*
18000f5ce99SJack Morgenstein  * Snoop SM MADs for port info, GUID info, and  P_Key table sets, so we can
18100f5ce99SJack Morgenstein  * synthesize LID change, Client-Rereg, GID change, and P_Key change events.
182225c7b1fSRoland Dreier  */
183f0f6f346SMoni Shoua static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad,
184f0f6f346SMoni Shoua 		      u16 prev_lid)
185225c7b1fSRoland Dreier {
18600f5ce99SJack Morgenstein 	struct ib_port_info *pinfo;
18700f5ce99SJack Morgenstein 	u16 lid;
188225c7b1fSRoland Dreier 
18900f5ce99SJack Morgenstein 	struct mlx4_ib_dev *dev = to_mdev(ibdev);
190225c7b1fSRoland Dreier 	if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
191225c7b1fSRoland Dreier 	     mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
19200f5ce99SJack Morgenstein 	    mad->mad_hdr.method == IB_MGMT_METHOD_SET)
19300f5ce99SJack Morgenstein 		switch (mad->mad_hdr.attr_id) {
19400f5ce99SJack Morgenstein 		case IB_SMP_ATTR_PORT_INFO:
19500f5ce99SJack Morgenstein 			pinfo = (struct ib_port_info *) ((struct ib_smp *) mad)->data;
19600f5ce99SJack Morgenstein 			lid = be16_to_cpu(pinfo->lid);
197225c7b1fSRoland Dreier 
19800f5ce99SJack Morgenstein 			update_sm_ah(dev, port_num,
199225c7b1fSRoland Dreier 				     be16_to_cpu(pinfo->sm_lid),
200225c7b1fSRoland Dreier 				     pinfo->neighbormtu_mastersmsl & 0xf);
201225c7b1fSRoland Dreier 
20200f5ce99SJack Morgenstein 			if (pinfo->clientrereg_resv_subnetto & 0x80)
20300f5ce99SJack Morgenstein 				mlx4_ib_dispatch_event(dev, port_num,
20400f5ce99SJack Morgenstein 						       IB_EVENT_CLIENT_REREGISTER);
205225c7b1fSRoland Dreier 
20600f5ce99SJack Morgenstein 			if (prev_lid != lid)
20700f5ce99SJack Morgenstein 				mlx4_ib_dispatch_event(dev, port_num,
20800f5ce99SJack Morgenstein 						       IB_EVENT_LID_CHANGE);
20900f5ce99SJack Morgenstein 			break;
210225c7b1fSRoland Dreier 
21100f5ce99SJack Morgenstein 		case IB_SMP_ATTR_PKEY_TABLE:
21200f5ce99SJack Morgenstein 			mlx4_ib_dispatch_event(dev, port_num,
21300f5ce99SJack Morgenstein 					       IB_EVENT_PKEY_CHANGE);
21400f5ce99SJack Morgenstein 			break;
215f0f6f346SMoni Shoua 
21600f5ce99SJack Morgenstein 		case IB_SMP_ATTR_GUID_INFO:
2176634961cSJack Morgenstein 			/* paravirtualized master's guid is guid 0 -- does not change */
2186634961cSJack Morgenstein 			if (!mlx4_is_master(dev->dev))
21900f5ce99SJack Morgenstein 				mlx4_ib_dispatch_event(dev, port_num,
22000f5ce99SJack Morgenstein 						       IB_EVENT_GID_CHANGE);
22100f5ce99SJack Morgenstein 			break;
22200f5ce99SJack Morgenstein 		default:
22300f5ce99SJack Morgenstein 			break;
224225c7b1fSRoland Dreier 		}
225225c7b1fSRoland Dreier }
226225c7b1fSRoland Dreier 
227225c7b1fSRoland Dreier static void node_desc_override(struct ib_device *dev,
228225c7b1fSRoland Dreier 			       struct ib_mad *mad)
229225c7b1fSRoland Dreier {
230df7fba66SJack Morgenstein 	unsigned long flags;
231df7fba66SJack Morgenstein 
232225c7b1fSRoland Dreier 	if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
233225c7b1fSRoland Dreier 	     mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
234225c7b1fSRoland Dreier 	    mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
235225c7b1fSRoland Dreier 	    mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
236df7fba66SJack Morgenstein 		spin_lock_irqsave(&to_mdev(dev)->sm_lock, flags);
237225c7b1fSRoland Dreier 		memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
238df7fba66SJack Morgenstein 		spin_unlock_irqrestore(&to_mdev(dev)->sm_lock, flags);
239225c7b1fSRoland Dreier 	}
240225c7b1fSRoland Dreier }
241225c7b1fSRoland Dreier 
242225c7b1fSRoland Dreier static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *mad)
243225c7b1fSRoland Dreier {
244225c7b1fSRoland Dreier 	int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED;
245225c7b1fSRoland Dreier 	struct ib_mad_send_buf *send_buf;
246225c7b1fSRoland Dreier 	struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn];
247225c7b1fSRoland Dreier 	int ret;
248df7fba66SJack Morgenstein 	unsigned long flags;
249225c7b1fSRoland Dreier 
250225c7b1fSRoland Dreier 	if (agent) {
251225c7b1fSRoland Dreier 		send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR,
252225c7b1fSRoland Dreier 					      IB_MGMT_MAD_DATA, GFP_ATOMIC);
25313974909SDan Carpenter 		if (IS_ERR(send_buf))
25413974909SDan Carpenter 			return;
255225c7b1fSRoland Dreier 		/*
256225c7b1fSRoland Dreier 		 * We rely here on the fact that MLX QPs don't use the
257225c7b1fSRoland Dreier 		 * address handle after the send is posted (this is
258225c7b1fSRoland Dreier 		 * wrong following the IB spec strictly, but we know
259225c7b1fSRoland Dreier 		 * it's OK for our devices).
260225c7b1fSRoland Dreier 		 */
261df7fba66SJack Morgenstein 		spin_lock_irqsave(&dev->sm_lock, flags);
262225c7b1fSRoland Dreier 		memcpy(send_buf->mad, mad, sizeof *mad);
263225c7b1fSRoland Dreier 		if ((send_buf->ah = dev->sm_ah[port_num - 1]))
264225c7b1fSRoland Dreier 			ret = ib_post_send_mad(send_buf, NULL);
265225c7b1fSRoland Dreier 		else
266225c7b1fSRoland Dreier 			ret = -EINVAL;
267df7fba66SJack Morgenstein 		spin_unlock_irqrestore(&dev->sm_lock, flags);
268225c7b1fSRoland Dreier 
269225c7b1fSRoland Dreier 		if (ret)
270225c7b1fSRoland Dreier 			ib_free_send_mad(send_buf);
271225c7b1fSRoland Dreier 	}
272225c7b1fSRoland Dreier }
273225c7b1fSRoland Dreier 
274c3779134SOr Gerlitz static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
275225c7b1fSRoland Dreier 			struct ib_wc *in_wc, struct ib_grh *in_grh,
276225c7b1fSRoland Dreier 			struct ib_mad *in_mad, struct ib_mad *out_mad)
277225c7b1fSRoland Dreier {
278f0f6f346SMoni Shoua 	u16 slid, prev_lid = 0;
279225c7b1fSRoland Dreier 	int err;
280f0f6f346SMoni Shoua 	struct ib_port_attr pattr;
281225c7b1fSRoland Dreier 
282b1d8eb5aSJack Morgenstein 	if (in_wc && in_wc->qp->qp_num) {
283b1d8eb5aSJack Morgenstein 		pr_debug("received MAD: slid:%d sqpn:%d "
284b1d8eb5aSJack Morgenstein 			"dlid_bits:%d dqpn:%d wc_flags:0x%x, cls %x, mtd %x, atr %x\n",
285b1d8eb5aSJack Morgenstein 			in_wc->slid, in_wc->src_qp,
286b1d8eb5aSJack Morgenstein 			in_wc->dlid_path_bits,
287b1d8eb5aSJack Morgenstein 			in_wc->qp->qp_num,
288b1d8eb5aSJack Morgenstein 			in_wc->wc_flags,
289b1d8eb5aSJack Morgenstein 			in_mad->mad_hdr.mgmt_class, in_mad->mad_hdr.method,
290b1d8eb5aSJack Morgenstein 			be16_to_cpu(in_mad->mad_hdr.attr_id));
291b1d8eb5aSJack Morgenstein 		if (in_wc->wc_flags & IB_WC_GRH) {
292b1d8eb5aSJack Morgenstein 			pr_debug("sgid_hi:0x%016llx sgid_lo:0x%016llx\n",
293b1d8eb5aSJack Morgenstein 				 be64_to_cpu(in_grh->sgid.global.subnet_prefix),
294b1d8eb5aSJack Morgenstein 				 be64_to_cpu(in_grh->sgid.global.interface_id));
295b1d8eb5aSJack Morgenstein 			pr_debug("dgid_hi:0x%016llx dgid_lo:0x%016llx\n",
296b1d8eb5aSJack Morgenstein 				 be64_to_cpu(in_grh->dgid.global.subnet_prefix),
297b1d8eb5aSJack Morgenstein 				 be64_to_cpu(in_grh->dgid.global.interface_id));
298b1d8eb5aSJack Morgenstein 		}
299b1d8eb5aSJack Morgenstein 	}
300b1d8eb5aSJack Morgenstein 
301225c7b1fSRoland Dreier 	slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE);
302225c7b1fSRoland Dreier 
303225c7b1fSRoland Dreier 	if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0) {
304225c7b1fSRoland Dreier 		forward_trap(to_mdev(ibdev), port_num, in_mad);
305225c7b1fSRoland Dreier 		return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
306225c7b1fSRoland Dreier 	}
307225c7b1fSRoland Dreier 
308225c7b1fSRoland Dreier 	if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
309225c7b1fSRoland Dreier 	    in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
310225c7b1fSRoland Dreier 		if (in_mad->mad_hdr.method   != IB_MGMT_METHOD_GET &&
311225c7b1fSRoland Dreier 		    in_mad->mad_hdr.method   != IB_MGMT_METHOD_SET &&
312225c7b1fSRoland Dreier 		    in_mad->mad_hdr.method   != IB_MGMT_METHOD_TRAP_REPRESS)
313225c7b1fSRoland Dreier 			return IB_MAD_RESULT_SUCCESS;
314225c7b1fSRoland Dreier 
315225c7b1fSRoland Dreier 		/*
316a6f7feaeSJack Morgenstein 		 * Don't process SMInfo queries -- the SMA can't handle them.
317225c7b1fSRoland Dreier 		 */
318a6f7feaeSJack Morgenstein 		if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO)
319225c7b1fSRoland Dreier 			return IB_MAD_RESULT_SUCCESS;
320225c7b1fSRoland Dreier 	} else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT ||
321225c7b1fSRoland Dreier 		   in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS1   ||
3226578cf33SEli Cohen 		   in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS2   ||
3236578cf33SEli Cohen 		   in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CONG_MGMT) {
324225c7b1fSRoland Dreier 		if (in_mad->mad_hdr.method  != IB_MGMT_METHOD_GET &&
325225c7b1fSRoland Dreier 		    in_mad->mad_hdr.method  != IB_MGMT_METHOD_SET)
326225c7b1fSRoland Dreier 			return IB_MAD_RESULT_SUCCESS;
327225c7b1fSRoland Dreier 	} else
328225c7b1fSRoland Dreier 		return IB_MAD_RESULT_SUCCESS;
329225c7b1fSRoland Dreier 
330f0f6f346SMoni Shoua 	if ((in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
331f0f6f346SMoni Shoua 	     in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
332f0f6f346SMoni Shoua 	    in_mad->mad_hdr.method == IB_MGMT_METHOD_SET &&
333f0f6f346SMoni Shoua 	    in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO &&
334f0f6f346SMoni Shoua 	    !ib_query_port(ibdev, port_num, &pattr))
335f0f6f346SMoni Shoua 		prev_lid = pattr.lid;
336f0f6f346SMoni Shoua 
337225c7b1fSRoland Dreier 	err = mlx4_MAD_IFC(to_mdev(ibdev),
338225c7b1fSRoland Dreier 			   mad_flags & IB_MAD_IGNORE_MKEY,
339225c7b1fSRoland Dreier 			   mad_flags & IB_MAD_IGNORE_BKEY,
340225c7b1fSRoland Dreier 			   port_num, in_wc, in_grh, in_mad, out_mad);
341225c7b1fSRoland Dreier 	if (err)
342225c7b1fSRoland Dreier 		return IB_MAD_RESULT_FAILURE;
343225c7b1fSRoland Dreier 
344225c7b1fSRoland Dreier 	if (!out_mad->mad_hdr.status) {
34500f5ce99SJack Morgenstein 		if (!(to_mdev(ibdev)->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV))
346f0f6f346SMoni Shoua 			smp_snoop(ibdev, port_num, in_mad, prev_lid);
347225c7b1fSRoland Dreier 		node_desc_override(ibdev, out_mad);
348225c7b1fSRoland Dreier 	}
349225c7b1fSRoland Dreier 
350225c7b1fSRoland Dreier 	/* set return bit in status of directed route responses */
351225c7b1fSRoland Dreier 	if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
352225c7b1fSRoland Dreier 		out_mad->mad_hdr.status |= cpu_to_be16(1 << 15);
353225c7b1fSRoland Dreier 
354225c7b1fSRoland Dreier 	if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS)
355225c7b1fSRoland Dreier 		/* no response for trap repress */
356225c7b1fSRoland Dreier 		return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
357225c7b1fSRoland Dreier 
358225c7b1fSRoland Dreier 	return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
359225c7b1fSRoland Dreier }
360225c7b1fSRoland Dreier 
361c3779134SOr Gerlitz static void edit_counter(struct mlx4_counter *cnt,
362c3779134SOr Gerlitz 					struct ib_pma_portcounters *pma_cnt)
363c3779134SOr Gerlitz {
364c3779134SOr Gerlitz 	pma_cnt->port_xmit_data = cpu_to_be32((be64_to_cpu(cnt->tx_bytes)>>2));
365c3779134SOr Gerlitz 	pma_cnt->port_rcv_data  = cpu_to_be32((be64_to_cpu(cnt->rx_bytes)>>2));
366c3779134SOr Gerlitz 	pma_cnt->port_xmit_packets = cpu_to_be32(be64_to_cpu(cnt->tx_frames));
367c3779134SOr Gerlitz 	pma_cnt->port_rcv_packets  = cpu_to_be32(be64_to_cpu(cnt->rx_frames));
368c3779134SOr Gerlitz }
369c3779134SOr Gerlitz 
370c3779134SOr Gerlitz static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
371c3779134SOr Gerlitz 			struct ib_wc *in_wc, struct ib_grh *in_grh,
372c3779134SOr Gerlitz 			struct ib_mad *in_mad, struct ib_mad *out_mad)
373c3779134SOr Gerlitz {
374c3779134SOr Gerlitz 	struct mlx4_cmd_mailbox *mailbox;
375c3779134SOr Gerlitz 	struct mlx4_ib_dev *dev = to_mdev(ibdev);
376c3779134SOr Gerlitz 	int err;
377c3779134SOr Gerlitz 	u32 inmod = dev->counters[port_num - 1] & 0xffff;
378c3779134SOr Gerlitz 	u8 mode;
379c3779134SOr Gerlitz 
380c3779134SOr Gerlitz 	if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT)
381c3779134SOr Gerlitz 		return -EINVAL;
382c3779134SOr Gerlitz 
383c3779134SOr Gerlitz 	mailbox = mlx4_alloc_cmd_mailbox(dev->dev);
384c3779134SOr Gerlitz 	if (IS_ERR(mailbox))
385c3779134SOr Gerlitz 		return IB_MAD_RESULT_FAILURE;
386c3779134SOr Gerlitz 
387c3779134SOr Gerlitz 	err = mlx4_cmd_box(dev->dev, 0, mailbox->dma, inmod, 0,
388f9baff50SJack Morgenstein 			   MLX4_CMD_QUERY_IF_STAT, MLX4_CMD_TIME_CLASS_C,
389f9baff50SJack Morgenstein 			   MLX4_CMD_WRAPPED);
390c3779134SOr Gerlitz 	if (err)
391c3779134SOr Gerlitz 		err = IB_MAD_RESULT_FAILURE;
392c3779134SOr Gerlitz 	else {
393c3779134SOr Gerlitz 		memset(out_mad->data, 0, sizeof out_mad->data);
394c3779134SOr Gerlitz 		mode = ((struct mlx4_counter *)mailbox->buf)->counter_mode;
395c3779134SOr Gerlitz 		switch (mode & 0xf) {
396c3779134SOr Gerlitz 		case 0:
397c3779134SOr Gerlitz 			edit_counter(mailbox->buf,
398c3779134SOr Gerlitz 						(void *)(out_mad->data + 40));
399c3779134SOr Gerlitz 			err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
400c3779134SOr Gerlitz 			break;
401c3779134SOr Gerlitz 		default:
402c3779134SOr Gerlitz 			err = IB_MAD_RESULT_FAILURE;
403c3779134SOr Gerlitz 		}
404c3779134SOr Gerlitz 	}
405c3779134SOr Gerlitz 
406c3779134SOr Gerlitz 	mlx4_free_cmd_mailbox(dev->dev, mailbox);
407c3779134SOr Gerlitz 
408c3779134SOr Gerlitz 	return err;
409c3779134SOr Gerlitz }
410c3779134SOr Gerlitz 
411c3779134SOr Gerlitz int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
412c3779134SOr Gerlitz 			struct ib_wc *in_wc, struct ib_grh *in_grh,
413c3779134SOr Gerlitz 			struct ib_mad *in_mad, struct ib_mad *out_mad)
414c3779134SOr Gerlitz {
415c3779134SOr Gerlitz 	switch (rdma_port_get_link_layer(ibdev, port_num)) {
416c3779134SOr Gerlitz 	case IB_LINK_LAYER_INFINIBAND:
417c3779134SOr Gerlitz 		return ib_process_mad(ibdev, mad_flags, port_num, in_wc,
418c3779134SOr Gerlitz 				      in_grh, in_mad, out_mad);
419c3779134SOr Gerlitz 	case IB_LINK_LAYER_ETHERNET:
420c3779134SOr Gerlitz 		return iboe_process_mad(ibdev, mad_flags, port_num, in_wc,
421c3779134SOr Gerlitz 					  in_grh, in_mad, out_mad);
422c3779134SOr Gerlitz 	default:
423c3779134SOr Gerlitz 		return -EINVAL;
424c3779134SOr Gerlitz 	}
425c3779134SOr Gerlitz }
426c3779134SOr Gerlitz 
427225c7b1fSRoland Dreier static void send_handler(struct ib_mad_agent *agent,
428225c7b1fSRoland Dreier 			 struct ib_mad_send_wc *mad_send_wc)
429225c7b1fSRoland Dreier {
430225c7b1fSRoland Dreier 	ib_free_send_mad(mad_send_wc->send_buf);
431225c7b1fSRoland Dreier }
432225c7b1fSRoland Dreier 
433225c7b1fSRoland Dreier int mlx4_ib_mad_init(struct mlx4_ib_dev *dev)
434225c7b1fSRoland Dreier {
435225c7b1fSRoland Dreier 	struct ib_mad_agent *agent;
436225c7b1fSRoland Dreier 	int p, q;
437225c7b1fSRoland Dreier 	int ret;
438fa417f7bSEli Cohen 	enum rdma_link_layer ll;
439225c7b1fSRoland Dreier 
440fa417f7bSEli Cohen 	for (p = 0; p < dev->num_ports; ++p) {
441fa417f7bSEli Cohen 		ll = rdma_port_get_link_layer(&dev->ib_dev, p + 1);
442225c7b1fSRoland Dreier 		for (q = 0; q <= 1; ++q) {
443fa417f7bSEli Cohen 			if (ll == IB_LINK_LAYER_INFINIBAND) {
444225c7b1fSRoland Dreier 				agent = ib_register_mad_agent(&dev->ib_dev, p + 1,
445225c7b1fSRoland Dreier 							      q ? IB_QPT_GSI : IB_QPT_SMI,
446225c7b1fSRoland Dreier 							      NULL, 0, send_handler,
447225c7b1fSRoland Dreier 							      NULL, NULL);
448225c7b1fSRoland Dreier 				if (IS_ERR(agent)) {
449225c7b1fSRoland Dreier 					ret = PTR_ERR(agent);
450225c7b1fSRoland Dreier 					goto err;
451225c7b1fSRoland Dreier 				}
452225c7b1fSRoland Dreier 				dev->send_agent[p][q] = agent;
453fa417f7bSEli Cohen 			} else
454fa417f7bSEli Cohen 				dev->send_agent[p][q] = NULL;
455fa417f7bSEli Cohen 		}
456225c7b1fSRoland Dreier 	}
457225c7b1fSRoland Dreier 
458225c7b1fSRoland Dreier 	return 0;
459225c7b1fSRoland Dreier 
460225c7b1fSRoland Dreier err:
4617ff93f8bSYevgeny Petrilin 	for (p = 0; p < dev->num_ports; ++p)
462225c7b1fSRoland Dreier 		for (q = 0; q <= 1; ++q)
463225c7b1fSRoland Dreier 			if (dev->send_agent[p][q])
464225c7b1fSRoland Dreier 				ib_unregister_mad_agent(dev->send_agent[p][q]);
465225c7b1fSRoland Dreier 
466225c7b1fSRoland Dreier 	return ret;
467225c7b1fSRoland Dreier }
468225c7b1fSRoland Dreier 
469225c7b1fSRoland Dreier void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev)
470225c7b1fSRoland Dreier {
471225c7b1fSRoland Dreier 	struct ib_mad_agent *agent;
472225c7b1fSRoland Dreier 	int p, q;
473225c7b1fSRoland Dreier 
4747ff93f8bSYevgeny Petrilin 	for (p = 0; p < dev->num_ports; ++p) {
475225c7b1fSRoland Dreier 		for (q = 0; q <= 1; ++q) {
476225c7b1fSRoland Dreier 			agent = dev->send_agent[p][q];
477fa417f7bSEli Cohen 			if (agent) {
478225c7b1fSRoland Dreier 				dev->send_agent[p][q] = NULL;
479225c7b1fSRoland Dreier 				ib_unregister_mad_agent(agent);
480225c7b1fSRoland Dreier 			}
481fa417f7bSEli Cohen 		}
482225c7b1fSRoland Dreier 
483225c7b1fSRoland Dreier 		if (dev->sm_ah[p])
484225c7b1fSRoland Dreier 			ib_destroy_ah(dev->sm_ah[p]);
485225c7b1fSRoland Dreier 	}
486225c7b1fSRoland Dreier }
48700f5ce99SJack Morgenstein 
48800f5ce99SJack Morgenstein void handle_port_mgmt_change_event(struct work_struct *work)
48900f5ce99SJack Morgenstein {
49000f5ce99SJack Morgenstein 	struct ib_event_work *ew = container_of(work, struct ib_event_work, work);
49100f5ce99SJack Morgenstein 	struct mlx4_ib_dev *dev = ew->ib_dev;
49200f5ce99SJack Morgenstein 	struct mlx4_eqe *eqe = &(ew->ib_eqe);
49300f5ce99SJack Morgenstein 	u8 port = eqe->event.port_mgmt_change.port;
49400f5ce99SJack Morgenstein 	u32 changed_attr;
49500f5ce99SJack Morgenstein 
49600f5ce99SJack Morgenstein 	switch (eqe->subtype) {
49700f5ce99SJack Morgenstein 	case MLX4_DEV_PMC_SUBTYPE_PORT_INFO:
49800f5ce99SJack Morgenstein 		changed_attr = be32_to_cpu(eqe->event.port_mgmt_change.params.port_info.changed_attr);
49900f5ce99SJack Morgenstein 
50000f5ce99SJack Morgenstein 		/* Update the SM ah - This should be done before handling
50100f5ce99SJack Morgenstein 		   the other changed attributes so that MADs can be sent to the SM */
50200f5ce99SJack Morgenstein 		if (changed_attr & MSTR_SM_CHANGE_MASK) {
50300f5ce99SJack Morgenstein 			u16 lid = be16_to_cpu(eqe->event.port_mgmt_change.params.port_info.mstr_sm_lid);
50400f5ce99SJack Morgenstein 			u8 sl = eqe->event.port_mgmt_change.params.port_info.mstr_sm_sl & 0xf;
50500f5ce99SJack Morgenstein 			update_sm_ah(dev, port, lid, sl);
50600f5ce99SJack Morgenstein 		}
50700f5ce99SJack Morgenstein 
50800f5ce99SJack Morgenstein 		/* Check if it is a lid change event */
50900f5ce99SJack Morgenstein 		if (changed_attr & MLX4_EQ_PORT_INFO_LID_CHANGE_MASK)
51000f5ce99SJack Morgenstein 			mlx4_ib_dispatch_event(dev, port, IB_EVENT_LID_CHANGE);
51100f5ce99SJack Morgenstein 
51200f5ce99SJack Morgenstein 		/* Generate GUID changed event */
51300f5ce99SJack Morgenstein 		if (changed_attr & MLX4_EQ_PORT_INFO_GID_PFX_CHANGE_MASK)
51400f5ce99SJack Morgenstein 			mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE);
51500f5ce99SJack Morgenstein 
51600f5ce99SJack Morgenstein 		if (changed_attr & MLX4_EQ_PORT_INFO_CLIENT_REREG_MASK)
51700f5ce99SJack Morgenstein 			mlx4_ib_dispatch_event(dev, port,
51800f5ce99SJack Morgenstein 					       IB_EVENT_CLIENT_REREGISTER);
51900f5ce99SJack Morgenstein 		break;
52000f5ce99SJack Morgenstein 
52100f5ce99SJack Morgenstein 	case MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE:
52200f5ce99SJack Morgenstein 		mlx4_ib_dispatch_event(dev, port, IB_EVENT_PKEY_CHANGE);
52300f5ce99SJack Morgenstein 		break;
52400f5ce99SJack Morgenstein 	case MLX4_DEV_PMC_SUBTYPE_GUID_INFO:
5256634961cSJack Morgenstein 		/* paravirtualized master's guid is guid 0 -- does not change */
5266634961cSJack Morgenstein 		if (!mlx4_is_master(dev->dev))
52700f5ce99SJack Morgenstein 			mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE);
52800f5ce99SJack Morgenstein 		break;
52900f5ce99SJack Morgenstein 	default:
53000f5ce99SJack Morgenstein 		pr_warn("Unsupported subtype 0x%x for "
53100f5ce99SJack Morgenstein 			"Port Management Change event\n", eqe->subtype);
53200f5ce99SJack Morgenstein 	}
53300f5ce99SJack Morgenstein 
53400f5ce99SJack Morgenstein 	kfree(ew);
53500f5ce99SJack Morgenstein }
53600f5ce99SJack Morgenstein 
53700f5ce99SJack Morgenstein void mlx4_ib_dispatch_event(struct mlx4_ib_dev *dev, u8 port_num,
53800f5ce99SJack Morgenstein 			    enum ib_event_type type)
53900f5ce99SJack Morgenstein {
54000f5ce99SJack Morgenstein 	struct ib_event event;
54100f5ce99SJack Morgenstein 
54200f5ce99SJack Morgenstein 	event.device		= &dev->ib_dev;
54300f5ce99SJack Morgenstein 	event.element.port_num	= port_num;
54400f5ce99SJack Morgenstein 	event.event		= type;
54500f5ce99SJack Morgenstein 
54600f5ce99SJack Morgenstein 	ib_dispatch_event(&event);
54700f5ce99SJack Morgenstein }
548*fc06573dSJack Morgenstein 
549*fc06573dSJack Morgenstein static void mlx4_ib_tunnel_comp_handler(struct ib_cq *cq, void *arg)
550*fc06573dSJack Morgenstein {
551*fc06573dSJack Morgenstein 	unsigned long flags;
552*fc06573dSJack Morgenstein 	struct mlx4_ib_demux_pv_ctx *ctx = cq->cq_context;
553*fc06573dSJack Morgenstein 	struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev);
554*fc06573dSJack Morgenstein 	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
555*fc06573dSJack Morgenstein 	if (!dev->sriov.is_going_down && ctx->state == DEMUX_PV_STATE_ACTIVE)
556*fc06573dSJack Morgenstein 		queue_work(ctx->wq, &ctx->work);
557*fc06573dSJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
558*fc06573dSJack Morgenstein }
559*fc06573dSJack Morgenstein 
560*fc06573dSJack Morgenstein static int mlx4_ib_post_pv_qp_buf(struct mlx4_ib_demux_pv_ctx *ctx,
561*fc06573dSJack Morgenstein 				  struct mlx4_ib_demux_pv_qp *tun_qp,
562*fc06573dSJack Morgenstein 				  int index)
563*fc06573dSJack Morgenstein {
564*fc06573dSJack Morgenstein 	struct ib_sge sg_list;
565*fc06573dSJack Morgenstein 	struct ib_recv_wr recv_wr, *bad_recv_wr;
566*fc06573dSJack Morgenstein 	int size;
567*fc06573dSJack Morgenstein 
568*fc06573dSJack Morgenstein 	size = (tun_qp->qp->qp_type == IB_QPT_UD) ?
569*fc06573dSJack Morgenstein 		sizeof (struct mlx4_tunnel_mad) : sizeof (struct mlx4_mad_rcv_buf);
570*fc06573dSJack Morgenstein 
571*fc06573dSJack Morgenstein 	sg_list.addr = tun_qp->ring[index].map;
572*fc06573dSJack Morgenstein 	sg_list.length = size;
573*fc06573dSJack Morgenstein 	sg_list.lkey = ctx->mr->lkey;
574*fc06573dSJack Morgenstein 
575*fc06573dSJack Morgenstein 	recv_wr.next = NULL;
576*fc06573dSJack Morgenstein 	recv_wr.sg_list = &sg_list;
577*fc06573dSJack Morgenstein 	recv_wr.num_sge = 1;
578*fc06573dSJack Morgenstein 	recv_wr.wr_id = (u64) index | MLX4_TUN_WRID_RECV |
579*fc06573dSJack Morgenstein 		MLX4_TUN_SET_WRID_QPN(tun_qp->proxy_qpt);
580*fc06573dSJack Morgenstein 	ib_dma_sync_single_for_device(ctx->ib_dev, tun_qp->ring[index].map,
581*fc06573dSJack Morgenstein 				      size, DMA_FROM_DEVICE);
582*fc06573dSJack Morgenstein 	return ib_post_recv(tun_qp->qp, &recv_wr, &bad_recv_wr);
583*fc06573dSJack Morgenstein }
584*fc06573dSJack Morgenstein 
585*fc06573dSJack Morgenstein static int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx,
586*fc06573dSJack Morgenstein 				 enum ib_qp_type qp_type, int is_tun)
587*fc06573dSJack Morgenstein {
588*fc06573dSJack Morgenstein 	int i;
589*fc06573dSJack Morgenstein 	struct mlx4_ib_demux_pv_qp *tun_qp;
590*fc06573dSJack Morgenstein 	int rx_buf_size, tx_buf_size;
591*fc06573dSJack Morgenstein 
592*fc06573dSJack Morgenstein 	if (qp_type > IB_QPT_GSI)
593*fc06573dSJack Morgenstein 		return -EINVAL;
594*fc06573dSJack Morgenstein 
595*fc06573dSJack Morgenstein 	tun_qp = &ctx->qp[qp_type];
596*fc06573dSJack Morgenstein 
597*fc06573dSJack Morgenstein 	tun_qp->ring = kzalloc(sizeof (struct mlx4_ib_buf) * MLX4_NUM_TUNNEL_BUFS,
598*fc06573dSJack Morgenstein 			       GFP_KERNEL);
599*fc06573dSJack Morgenstein 	if (!tun_qp->ring)
600*fc06573dSJack Morgenstein 		return -ENOMEM;
601*fc06573dSJack Morgenstein 
602*fc06573dSJack Morgenstein 	tun_qp->tx_ring = kcalloc(MLX4_NUM_TUNNEL_BUFS,
603*fc06573dSJack Morgenstein 				  sizeof (struct mlx4_ib_tun_tx_buf),
604*fc06573dSJack Morgenstein 				  GFP_KERNEL);
605*fc06573dSJack Morgenstein 	if (!tun_qp->tx_ring) {
606*fc06573dSJack Morgenstein 		kfree(tun_qp->ring);
607*fc06573dSJack Morgenstein 		tun_qp->ring = NULL;
608*fc06573dSJack Morgenstein 		return -ENOMEM;
609*fc06573dSJack Morgenstein 	}
610*fc06573dSJack Morgenstein 
611*fc06573dSJack Morgenstein 	if (is_tun) {
612*fc06573dSJack Morgenstein 		rx_buf_size = sizeof (struct mlx4_tunnel_mad);
613*fc06573dSJack Morgenstein 		tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad);
614*fc06573dSJack Morgenstein 	} else {
615*fc06573dSJack Morgenstein 		rx_buf_size = sizeof (struct mlx4_mad_rcv_buf);
616*fc06573dSJack Morgenstein 		tx_buf_size = sizeof (struct mlx4_mad_snd_buf);
617*fc06573dSJack Morgenstein 	}
618*fc06573dSJack Morgenstein 
619*fc06573dSJack Morgenstein 	for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) {
620*fc06573dSJack Morgenstein 		tun_qp->ring[i].addr = kmalloc(rx_buf_size, GFP_KERNEL);
621*fc06573dSJack Morgenstein 		if (!tun_qp->ring[i].addr)
622*fc06573dSJack Morgenstein 			goto err;
623*fc06573dSJack Morgenstein 		tun_qp->ring[i].map = ib_dma_map_single(ctx->ib_dev,
624*fc06573dSJack Morgenstein 							tun_qp->ring[i].addr,
625*fc06573dSJack Morgenstein 							rx_buf_size,
626*fc06573dSJack Morgenstein 							DMA_FROM_DEVICE);
627*fc06573dSJack Morgenstein 	}
628*fc06573dSJack Morgenstein 
629*fc06573dSJack Morgenstein 	for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) {
630*fc06573dSJack Morgenstein 		tun_qp->tx_ring[i].buf.addr =
631*fc06573dSJack Morgenstein 			kmalloc(tx_buf_size, GFP_KERNEL);
632*fc06573dSJack Morgenstein 		if (!tun_qp->tx_ring[i].buf.addr)
633*fc06573dSJack Morgenstein 			goto tx_err;
634*fc06573dSJack Morgenstein 		tun_qp->tx_ring[i].buf.map =
635*fc06573dSJack Morgenstein 			ib_dma_map_single(ctx->ib_dev,
636*fc06573dSJack Morgenstein 					  tun_qp->tx_ring[i].buf.addr,
637*fc06573dSJack Morgenstein 					  tx_buf_size,
638*fc06573dSJack Morgenstein 					  DMA_TO_DEVICE);
639*fc06573dSJack Morgenstein 		tun_qp->tx_ring[i].ah = NULL;
640*fc06573dSJack Morgenstein 	}
641*fc06573dSJack Morgenstein 	spin_lock_init(&tun_qp->tx_lock);
642*fc06573dSJack Morgenstein 	tun_qp->tx_ix_head = 0;
643*fc06573dSJack Morgenstein 	tun_qp->tx_ix_tail = 0;
644*fc06573dSJack Morgenstein 	tun_qp->proxy_qpt = qp_type;
645*fc06573dSJack Morgenstein 
646*fc06573dSJack Morgenstein 	return 0;
647*fc06573dSJack Morgenstein 
648*fc06573dSJack Morgenstein tx_err:
649*fc06573dSJack Morgenstein 	while (i > 0) {
650*fc06573dSJack Morgenstein 		--i;
651*fc06573dSJack Morgenstein 		ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map,
652*fc06573dSJack Morgenstein 				    tx_buf_size, DMA_TO_DEVICE);
653*fc06573dSJack Morgenstein 		kfree(tun_qp->tx_ring[i].buf.addr);
654*fc06573dSJack Morgenstein 	}
655*fc06573dSJack Morgenstein 	kfree(tun_qp->tx_ring);
656*fc06573dSJack Morgenstein 	tun_qp->tx_ring = NULL;
657*fc06573dSJack Morgenstein 	i = MLX4_NUM_TUNNEL_BUFS;
658*fc06573dSJack Morgenstein err:
659*fc06573dSJack Morgenstein 	while (i > 0) {
660*fc06573dSJack Morgenstein 		--i;
661*fc06573dSJack Morgenstein 		ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map,
662*fc06573dSJack Morgenstein 				    rx_buf_size, DMA_FROM_DEVICE);
663*fc06573dSJack Morgenstein 		kfree(tun_qp->ring[i].addr);
664*fc06573dSJack Morgenstein 	}
665*fc06573dSJack Morgenstein 	kfree(tun_qp->ring);
666*fc06573dSJack Morgenstein 	tun_qp->ring = NULL;
667*fc06573dSJack Morgenstein 	return -ENOMEM;
668*fc06573dSJack Morgenstein }
669*fc06573dSJack Morgenstein 
670*fc06573dSJack Morgenstein static void mlx4_ib_free_pv_qp_bufs(struct mlx4_ib_demux_pv_ctx *ctx,
671*fc06573dSJack Morgenstein 				     enum ib_qp_type qp_type, int is_tun)
672*fc06573dSJack Morgenstein {
673*fc06573dSJack Morgenstein 	int i;
674*fc06573dSJack Morgenstein 	struct mlx4_ib_demux_pv_qp *tun_qp;
675*fc06573dSJack Morgenstein 	int rx_buf_size, tx_buf_size;
676*fc06573dSJack Morgenstein 
677*fc06573dSJack Morgenstein 	if (qp_type > IB_QPT_GSI)
678*fc06573dSJack Morgenstein 		return;
679*fc06573dSJack Morgenstein 
680*fc06573dSJack Morgenstein 	tun_qp = &ctx->qp[qp_type];
681*fc06573dSJack Morgenstein 	if (is_tun) {
682*fc06573dSJack Morgenstein 		rx_buf_size = sizeof (struct mlx4_tunnel_mad);
683*fc06573dSJack Morgenstein 		tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad);
684*fc06573dSJack Morgenstein 	} else {
685*fc06573dSJack Morgenstein 		rx_buf_size = sizeof (struct mlx4_mad_rcv_buf);
686*fc06573dSJack Morgenstein 		tx_buf_size = sizeof (struct mlx4_mad_snd_buf);
687*fc06573dSJack Morgenstein 	}
688*fc06573dSJack Morgenstein 
689*fc06573dSJack Morgenstein 
690*fc06573dSJack Morgenstein 	for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) {
691*fc06573dSJack Morgenstein 		ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map,
692*fc06573dSJack Morgenstein 				    rx_buf_size, DMA_FROM_DEVICE);
693*fc06573dSJack Morgenstein 		kfree(tun_qp->ring[i].addr);
694*fc06573dSJack Morgenstein 	}
695*fc06573dSJack Morgenstein 
696*fc06573dSJack Morgenstein 	for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) {
697*fc06573dSJack Morgenstein 		ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map,
698*fc06573dSJack Morgenstein 				    tx_buf_size, DMA_TO_DEVICE);
699*fc06573dSJack Morgenstein 		kfree(tun_qp->tx_ring[i].buf.addr);
700*fc06573dSJack Morgenstein 		if (tun_qp->tx_ring[i].ah)
701*fc06573dSJack Morgenstein 			ib_destroy_ah(tun_qp->tx_ring[i].ah);
702*fc06573dSJack Morgenstein 	}
703*fc06573dSJack Morgenstein 	kfree(tun_qp->tx_ring);
704*fc06573dSJack Morgenstein 	kfree(tun_qp->ring);
705*fc06573dSJack Morgenstein }
706*fc06573dSJack Morgenstein 
707*fc06573dSJack Morgenstein static void mlx4_ib_tunnel_comp_worker(struct work_struct *work)
708*fc06573dSJack Morgenstein {
709*fc06573dSJack Morgenstein 	/* dummy until next patch in series */
710*fc06573dSJack Morgenstein }
711*fc06573dSJack Morgenstein 
712*fc06573dSJack Morgenstein static void pv_qp_event_handler(struct ib_event *event, void *qp_context)
713*fc06573dSJack Morgenstein {
714*fc06573dSJack Morgenstein 	struct mlx4_ib_demux_pv_ctx *sqp = qp_context;
715*fc06573dSJack Morgenstein 
716*fc06573dSJack Morgenstein 	/* It's worse than that! He's dead, Jim! */
717*fc06573dSJack Morgenstein 	pr_err("Fatal error (%d) on a MAD QP on port %d\n",
718*fc06573dSJack Morgenstein 	       event->event, sqp->port);
719*fc06573dSJack Morgenstein }
720*fc06573dSJack Morgenstein 
721*fc06573dSJack Morgenstein static int create_pv_sqp(struct mlx4_ib_demux_pv_ctx *ctx,
722*fc06573dSJack Morgenstein 			    enum ib_qp_type qp_type, int create_tun)
723*fc06573dSJack Morgenstein {
724*fc06573dSJack Morgenstein 	int i, ret;
725*fc06573dSJack Morgenstein 	struct mlx4_ib_demux_pv_qp *tun_qp;
726*fc06573dSJack Morgenstein 	struct mlx4_ib_qp_tunnel_init_attr qp_init_attr;
727*fc06573dSJack Morgenstein 	struct ib_qp_attr attr;
728*fc06573dSJack Morgenstein 	int qp_attr_mask_INIT;
729*fc06573dSJack Morgenstein 
730*fc06573dSJack Morgenstein 	if (qp_type > IB_QPT_GSI)
731*fc06573dSJack Morgenstein 		return -EINVAL;
732*fc06573dSJack Morgenstein 
733*fc06573dSJack Morgenstein 	tun_qp = &ctx->qp[qp_type];
734*fc06573dSJack Morgenstein 
735*fc06573dSJack Morgenstein 	memset(&qp_init_attr, 0, sizeof qp_init_attr);
736*fc06573dSJack Morgenstein 	qp_init_attr.init_attr.send_cq = ctx->cq;
737*fc06573dSJack Morgenstein 	qp_init_attr.init_attr.recv_cq = ctx->cq;
738*fc06573dSJack Morgenstein 	qp_init_attr.init_attr.sq_sig_type = IB_SIGNAL_ALL_WR;
739*fc06573dSJack Morgenstein 	qp_init_attr.init_attr.cap.max_send_wr = MLX4_NUM_TUNNEL_BUFS;
740*fc06573dSJack Morgenstein 	qp_init_attr.init_attr.cap.max_recv_wr = MLX4_NUM_TUNNEL_BUFS;
741*fc06573dSJack Morgenstein 	qp_init_attr.init_attr.cap.max_send_sge = 1;
742*fc06573dSJack Morgenstein 	qp_init_attr.init_attr.cap.max_recv_sge = 1;
743*fc06573dSJack Morgenstein 	if (create_tun) {
744*fc06573dSJack Morgenstein 		qp_init_attr.init_attr.qp_type = IB_QPT_UD;
745*fc06573dSJack Morgenstein 		qp_init_attr.init_attr.create_flags = MLX4_IB_SRIOV_TUNNEL_QP;
746*fc06573dSJack Morgenstein 		qp_init_attr.port = ctx->port;
747*fc06573dSJack Morgenstein 		qp_init_attr.slave = ctx->slave;
748*fc06573dSJack Morgenstein 		qp_init_attr.proxy_qp_type = qp_type;
749*fc06573dSJack Morgenstein 		qp_attr_mask_INIT = IB_QP_STATE | IB_QP_PKEY_INDEX |
750*fc06573dSJack Morgenstein 			   IB_QP_QKEY | IB_QP_PORT;
751*fc06573dSJack Morgenstein 	} else {
752*fc06573dSJack Morgenstein 		qp_init_attr.init_attr.qp_type = qp_type;
753*fc06573dSJack Morgenstein 		qp_init_attr.init_attr.create_flags = MLX4_IB_SRIOV_SQP;
754*fc06573dSJack Morgenstein 		qp_attr_mask_INIT = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_QKEY;
755*fc06573dSJack Morgenstein 	}
756*fc06573dSJack Morgenstein 	qp_init_attr.init_attr.port_num = ctx->port;
757*fc06573dSJack Morgenstein 	qp_init_attr.init_attr.qp_context = ctx;
758*fc06573dSJack Morgenstein 	qp_init_attr.init_attr.event_handler = pv_qp_event_handler;
759*fc06573dSJack Morgenstein 	tun_qp->qp = ib_create_qp(ctx->pd, &qp_init_attr.init_attr);
760*fc06573dSJack Morgenstein 	if (IS_ERR(tun_qp->qp)) {
761*fc06573dSJack Morgenstein 		ret = PTR_ERR(tun_qp->qp);
762*fc06573dSJack Morgenstein 		tun_qp->qp = NULL;
763*fc06573dSJack Morgenstein 		pr_err("Couldn't create %s QP (%d)\n",
764*fc06573dSJack Morgenstein 		       create_tun ? "tunnel" : "special", ret);
765*fc06573dSJack Morgenstein 		return ret;
766*fc06573dSJack Morgenstein 	}
767*fc06573dSJack Morgenstein 
768*fc06573dSJack Morgenstein 	memset(&attr, 0, sizeof attr);
769*fc06573dSJack Morgenstein 	attr.qp_state = IB_QPS_INIT;
770*fc06573dSJack Morgenstein 	attr.pkey_index =
771*fc06573dSJack Morgenstein 		to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0];
772*fc06573dSJack Morgenstein 	attr.qkey = IB_QP1_QKEY;
773*fc06573dSJack Morgenstein 	attr.port_num = ctx->port;
774*fc06573dSJack Morgenstein 	ret = ib_modify_qp(tun_qp->qp, &attr, qp_attr_mask_INIT);
775*fc06573dSJack Morgenstein 	if (ret) {
776*fc06573dSJack Morgenstein 		pr_err("Couldn't change %s qp state to INIT (%d)\n",
777*fc06573dSJack Morgenstein 		       create_tun ? "tunnel" : "special", ret);
778*fc06573dSJack Morgenstein 		goto err_qp;
779*fc06573dSJack Morgenstein 	}
780*fc06573dSJack Morgenstein 	attr.qp_state = IB_QPS_RTR;
781*fc06573dSJack Morgenstein 	ret = ib_modify_qp(tun_qp->qp, &attr, IB_QP_STATE);
782*fc06573dSJack Morgenstein 	if (ret) {
783*fc06573dSJack Morgenstein 		pr_err("Couldn't change %s qp state to RTR (%d)\n",
784*fc06573dSJack Morgenstein 		       create_tun ? "tunnel" : "special", ret);
785*fc06573dSJack Morgenstein 		goto err_qp;
786*fc06573dSJack Morgenstein 	}
787*fc06573dSJack Morgenstein 	attr.qp_state = IB_QPS_RTS;
788*fc06573dSJack Morgenstein 	attr.sq_psn = 0;
789*fc06573dSJack Morgenstein 	ret = ib_modify_qp(tun_qp->qp, &attr, IB_QP_STATE | IB_QP_SQ_PSN);
790*fc06573dSJack Morgenstein 	if (ret) {
791*fc06573dSJack Morgenstein 		pr_err("Couldn't change %s qp state to RTS (%d)\n",
792*fc06573dSJack Morgenstein 		       create_tun ? "tunnel" : "special", ret);
793*fc06573dSJack Morgenstein 		goto err_qp;
794*fc06573dSJack Morgenstein 	}
795*fc06573dSJack Morgenstein 
796*fc06573dSJack Morgenstein 	for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) {
797*fc06573dSJack Morgenstein 		ret = mlx4_ib_post_pv_qp_buf(ctx, tun_qp, i);
798*fc06573dSJack Morgenstein 		if (ret) {
799*fc06573dSJack Morgenstein 			pr_err(" mlx4_ib_post_pv_buf error"
800*fc06573dSJack Morgenstein 			       " (err = %d, i = %d)\n", ret, i);
801*fc06573dSJack Morgenstein 			goto err_qp;
802*fc06573dSJack Morgenstein 		}
803*fc06573dSJack Morgenstein 	}
804*fc06573dSJack Morgenstein 	return 0;
805*fc06573dSJack Morgenstein 
806*fc06573dSJack Morgenstein err_qp:
807*fc06573dSJack Morgenstein 	ib_destroy_qp(tun_qp->qp);
808*fc06573dSJack Morgenstein 	tun_qp->qp = NULL;
809*fc06573dSJack Morgenstein 	return ret;
810*fc06573dSJack Morgenstein }
811*fc06573dSJack Morgenstein 
812*fc06573dSJack Morgenstein /*
813*fc06573dSJack Morgenstein  * IB MAD completion callback for real SQPs
814*fc06573dSJack Morgenstein  */
815*fc06573dSJack Morgenstein static void mlx4_ib_sqp_comp_worker(struct work_struct *work)
816*fc06573dSJack Morgenstein {
817*fc06573dSJack Morgenstein 	/* dummy until next patch in series */
818*fc06573dSJack Morgenstein }
819*fc06573dSJack Morgenstein 
820*fc06573dSJack Morgenstein static int alloc_pv_object(struct mlx4_ib_dev *dev, int slave, int port,
821*fc06573dSJack Morgenstein 			       struct mlx4_ib_demux_pv_ctx **ret_ctx)
822*fc06573dSJack Morgenstein {
823*fc06573dSJack Morgenstein 	struct mlx4_ib_demux_pv_ctx *ctx;
824*fc06573dSJack Morgenstein 
825*fc06573dSJack Morgenstein 	*ret_ctx = NULL;
826*fc06573dSJack Morgenstein 	ctx = kzalloc(sizeof (struct mlx4_ib_demux_pv_ctx), GFP_KERNEL);
827*fc06573dSJack Morgenstein 	if (!ctx) {
828*fc06573dSJack Morgenstein 		pr_err("failed allocating pv resource context "
829*fc06573dSJack Morgenstein 		       "for port %d, slave %d\n", port, slave);
830*fc06573dSJack Morgenstein 		return -ENOMEM;
831*fc06573dSJack Morgenstein 	}
832*fc06573dSJack Morgenstein 
833*fc06573dSJack Morgenstein 	ctx->ib_dev = &dev->ib_dev;
834*fc06573dSJack Morgenstein 	ctx->port = port;
835*fc06573dSJack Morgenstein 	ctx->slave = slave;
836*fc06573dSJack Morgenstein 	*ret_ctx = ctx;
837*fc06573dSJack Morgenstein 	return 0;
838*fc06573dSJack Morgenstein }
839*fc06573dSJack Morgenstein 
840*fc06573dSJack Morgenstein static void free_pv_object(struct mlx4_ib_dev *dev, int slave, int port)
841*fc06573dSJack Morgenstein {
842*fc06573dSJack Morgenstein 	if (dev->sriov.demux[port - 1].tun[slave]) {
843*fc06573dSJack Morgenstein 		kfree(dev->sriov.demux[port - 1].tun[slave]);
844*fc06573dSJack Morgenstein 		dev->sriov.demux[port - 1].tun[slave] = NULL;
845*fc06573dSJack Morgenstein 	}
846*fc06573dSJack Morgenstein }
847*fc06573dSJack Morgenstein 
848*fc06573dSJack Morgenstein static int create_pv_resources(struct ib_device *ibdev, int slave, int port,
849*fc06573dSJack Morgenstein 			       int create_tun, struct mlx4_ib_demux_pv_ctx *ctx)
850*fc06573dSJack Morgenstein {
851*fc06573dSJack Morgenstein 	int ret, cq_size;
852*fc06573dSJack Morgenstein 
853*fc06573dSJack Morgenstein 	ctx->state = DEMUX_PV_STATE_STARTING;
854*fc06573dSJack Morgenstein 	/* have QP0 only on port owner, and only if link layer is IB */
855*fc06573dSJack Morgenstein 	if (ctx->slave == mlx4_master_func_num(to_mdev(ctx->ib_dev)->dev) &&
856*fc06573dSJack Morgenstein 	    rdma_port_get_link_layer(ibdev, ctx->port) == IB_LINK_LAYER_INFINIBAND)
857*fc06573dSJack Morgenstein 		ctx->has_smi = 1;
858*fc06573dSJack Morgenstein 
859*fc06573dSJack Morgenstein 	if (ctx->has_smi) {
860*fc06573dSJack Morgenstein 		ret = mlx4_ib_alloc_pv_bufs(ctx, IB_QPT_SMI, create_tun);
861*fc06573dSJack Morgenstein 		if (ret) {
862*fc06573dSJack Morgenstein 			pr_err("Failed allocating qp0 tunnel bufs (%d)\n", ret);
863*fc06573dSJack Morgenstein 			goto err_out;
864*fc06573dSJack Morgenstein 		}
865*fc06573dSJack Morgenstein 	}
866*fc06573dSJack Morgenstein 
867*fc06573dSJack Morgenstein 	ret = mlx4_ib_alloc_pv_bufs(ctx, IB_QPT_GSI, create_tun);
868*fc06573dSJack Morgenstein 	if (ret) {
869*fc06573dSJack Morgenstein 		pr_err("Failed allocating qp1 tunnel bufs (%d)\n", ret);
870*fc06573dSJack Morgenstein 		goto err_out_qp0;
871*fc06573dSJack Morgenstein 	}
872*fc06573dSJack Morgenstein 
873*fc06573dSJack Morgenstein 	cq_size = 2 * MLX4_NUM_TUNNEL_BUFS;
874*fc06573dSJack Morgenstein 	if (ctx->has_smi)
875*fc06573dSJack Morgenstein 		cq_size *= 2;
876*fc06573dSJack Morgenstein 
877*fc06573dSJack Morgenstein 	ctx->cq = ib_create_cq(ctx->ib_dev, mlx4_ib_tunnel_comp_handler,
878*fc06573dSJack Morgenstein 			       NULL, ctx, cq_size, 0);
879*fc06573dSJack Morgenstein 	if (IS_ERR(ctx->cq)) {
880*fc06573dSJack Morgenstein 		ret = PTR_ERR(ctx->cq);
881*fc06573dSJack Morgenstein 		pr_err("Couldn't create tunnel CQ (%d)\n", ret);
882*fc06573dSJack Morgenstein 		goto err_buf;
883*fc06573dSJack Morgenstein 	}
884*fc06573dSJack Morgenstein 
885*fc06573dSJack Morgenstein 	ctx->pd = ib_alloc_pd(ctx->ib_dev);
886*fc06573dSJack Morgenstein 	if (IS_ERR(ctx->pd)) {
887*fc06573dSJack Morgenstein 		ret = PTR_ERR(ctx->pd);
888*fc06573dSJack Morgenstein 		pr_err("Couldn't create tunnel PD (%d)\n", ret);
889*fc06573dSJack Morgenstein 		goto err_cq;
890*fc06573dSJack Morgenstein 	}
891*fc06573dSJack Morgenstein 
892*fc06573dSJack Morgenstein 	ctx->mr = ib_get_dma_mr(ctx->pd, IB_ACCESS_LOCAL_WRITE);
893*fc06573dSJack Morgenstein 	if (IS_ERR(ctx->mr)) {
894*fc06573dSJack Morgenstein 		ret = PTR_ERR(ctx->mr);
895*fc06573dSJack Morgenstein 		pr_err("Couldn't get tunnel DMA MR (%d)\n", ret);
896*fc06573dSJack Morgenstein 		goto err_pd;
897*fc06573dSJack Morgenstein 	}
898*fc06573dSJack Morgenstein 
899*fc06573dSJack Morgenstein 	if (ctx->has_smi) {
900*fc06573dSJack Morgenstein 		ret = create_pv_sqp(ctx, IB_QPT_SMI, create_tun);
901*fc06573dSJack Morgenstein 		if (ret) {
902*fc06573dSJack Morgenstein 			pr_err("Couldn't create %s QP0 (%d)\n",
903*fc06573dSJack Morgenstein 			       create_tun ? "tunnel for" : "",  ret);
904*fc06573dSJack Morgenstein 			goto err_mr;
905*fc06573dSJack Morgenstein 		}
906*fc06573dSJack Morgenstein 	}
907*fc06573dSJack Morgenstein 
908*fc06573dSJack Morgenstein 	ret = create_pv_sqp(ctx, IB_QPT_GSI, create_tun);
909*fc06573dSJack Morgenstein 	if (ret) {
910*fc06573dSJack Morgenstein 		pr_err("Couldn't create %s QP1 (%d)\n",
911*fc06573dSJack Morgenstein 		       create_tun ? "tunnel for" : "",  ret);
912*fc06573dSJack Morgenstein 		goto err_qp0;
913*fc06573dSJack Morgenstein 	}
914*fc06573dSJack Morgenstein 
915*fc06573dSJack Morgenstein 	if (create_tun)
916*fc06573dSJack Morgenstein 		INIT_WORK(&ctx->work, mlx4_ib_tunnel_comp_worker);
917*fc06573dSJack Morgenstein 	else
918*fc06573dSJack Morgenstein 		INIT_WORK(&ctx->work, mlx4_ib_sqp_comp_worker);
919*fc06573dSJack Morgenstein 
920*fc06573dSJack Morgenstein 	ctx->wq = to_mdev(ibdev)->sriov.demux[port - 1].wq;
921*fc06573dSJack Morgenstein 
922*fc06573dSJack Morgenstein 	ret = ib_req_notify_cq(ctx->cq, IB_CQ_NEXT_COMP);
923*fc06573dSJack Morgenstein 	if (ret) {
924*fc06573dSJack Morgenstein 		pr_err("Couldn't arm tunnel cq (%d)\n", ret);
925*fc06573dSJack Morgenstein 		goto err_wq;
926*fc06573dSJack Morgenstein 	}
927*fc06573dSJack Morgenstein 	ctx->state = DEMUX_PV_STATE_ACTIVE;
928*fc06573dSJack Morgenstein 	return 0;
929*fc06573dSJack Morgenstein 
930*fc06573dSJack Morgenstein err_wq:
931*fc06573dSJack Morgenstein 	ctx->wq = NULL;
932*fc06573dSJack Morgenstein 	ib_destroy_qp(ctx->qp[1].qp);
933*fc06573dSJack Morgenstein 	ctx->qp[1].qp = NULL;
934*fc06573dSJack Morgenstein 
935*fc06573dSJack Morgenstein 
936*fc06573dSJack Morgenstein err_qp0:
937*fc06573dSJack Morgenstein 	if (ctx->has_smi)
938*fc06573dSJack Morgenstein 		ib_destroy_qp(ctx->qp[0].qp);
939*fc06573dSJack Morgenstein 	ctx->qp[0].qp = NULL;
940*fc06573dSJack Morgenstein 
941*fc06573dSJack Morgenstein err_mr:
942*fc06573dSJack Morgenstein 	ib_dereg_mr(ctx->mr);
943*fc06573dSJack Morgenstein 	ctx->mr = NULL;
944*fc06573dSJack Morgenstein 
945*fc06573dSJack Morgenstein err_pd:
946*fc06573dSJack Morgenstein 	ib_dealloc_pd(ctx->pd);
947*fc06573dSJack Morgenstein 	ctx->pd = NULL;
948*fc06573dSJack Morgenstein 
949*fc06573dSJack Morgenstein err_cq:
950*fc06573dSJack Morgenstein 	ib_destroy_cq(ctx->cq);
951*fc06573dSJack Morgenstein 	ctx->cq = NULL;
952*fc06573dSJack Morgenstein 
953*fc06573dSJack Morgenstein err_buf:
954*fc06573dSJack Morgenstein 	mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_GSI, create_tun);
955*fc06573dSJack Morgenstein 
956*fc06573dSJack Morgenstein err_out_qp0:
957*fc06573dSJack Morgenstein 	if (ctx->has_smi)
958*fc06573dSJack Morgenstein 		mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_SMI, create_tun);
959*fc06573dSJack Morgenstein err_out:
960*fc06573dSJack Morgenstein 	ctx->state = DEMUX_PV_STATE_DOWN;
961*fc06573dSJack Morgenstein 	return ret;
962*fc06573dSJack Morgenstein }
963*fc06573dSJack Morgenstein 
964*fc06573dSJack Morgenstein static void destroy_pv_resources(struct mlx4_ib_dev *dev, int slave, int port,
965*fc06573dSJack Morgenstein 				 struct mlx4_ib_demux_pv_ctx *ctx, int flush)
966*fc06573dSJack Morgenstein {
967*fc06573dSJack Morgenstein 	if (!ctx)
968*fc06573dSJack Morgenstein 		return;
969*fc06573dSJack Morgenstein 	if (ctx->state > DEMUX_PV_STATE_DOWN) {
970*fc06573dSJack Morgenstein 		ctx->state = DEMUX_PV_STATE_DOWNING;
971*fc06573dSJack Morgenstein 		if (flush)
972*fc06573dSJack Morgenstein 			flush_workqueue(ctx->wq);
973*fc06573dSJack Morgenstein 		if (ctx->has_smi) {
974*fc06573dSJack Morgenstein 			ib_destroy_qp(ctx->qp[0].qp);
975*fc06573dSJack Morgenstein 			ctx->qp[0].qp = NULL;
976*fc06573dSJack Morgenstein 			mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_SMI, 1);
977*fc06573dSJack Morgenstein 		}
978*fc06573dSJack Morgenstein 		ib_destroy_qp(ctx->qp[1].qp);
979*fc06573dSJack Morgenstein 		ctx->qp[1].qp = NULL;
980*fc06573dSJack Morgenstein 		mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_GSI, 1);
981*fc06573dSJack Morgenstein 		ib_dereg_mr(ctx->mr);
982*fc06573dSJack Morgenstein 		ctx->mr = NULL;
983*fc06573dSJack Morgenstein 		ib_dealloc_pd(ctx->pd);
984*fc06573dSJack Morgenstein 		ctx->pd = NULL;
985*fc06573dSJack Morgenstein 		ib_destroy_cq(ctx->cq);
986*fc06573dSJack Morgenstein 		ctx->cq = NULL;
987*fc06573dSJack Morgenstein 		ctx->state = DEMUX_PV_STATE_DOWN;
988*fc06573dSJack Morgenstein 	}
989*fc06573dSJack Morgenstein }
990*fc06573dSJack Morgenstein 
991*fc06573dSJack Morgenstein static int mlx4_ib_tunnels_update(struct mlx4_ib_dev *dev, int slave,
992*fc06573dSJack Morgenstein 				  int port, int do_init)
993*fc06573dSJack Morgenstein {
994*fc06573dSJack Morgenstein 	int ret = 0;
995*fc06573dSJack Morgenstein 
996*fc06573dSJack Morgenstein 	if (!do_init) {
997*fc06573dSJack Morgenstein 		/* for master, destroy real sqp resources */
998*fc06573dSJack Morgenstein 		if (slave == mlx4_master_func_num(dev->dev))
999*fc06573dSJack Morgenstein 			destroy_pv_resources(dev, slave, port,
1000*fc06573dSJack Morgenstein 					     dev->sriov.sqps[port - 1], 1);
1001*fc06573dSJack Morgenstein 		/* destroy the tunnel qp resources */
1002*fc06573dSJack Morgenstein 		destroy_pv_resources(dev, slave, port,
1003*fc06573dSJack Morgenstein 				     dev->sriov.demux[port - 1].tun[slave], 1);
1004*fc06573dSJack Morgenstein 		return 0;
1005*fc06573dSJack Morgenstein 	}
1006*fc06573dSJack Morgenstein 
1007*fc06573dSJack Morgenstein 	/* create the tunnel qp resources */
1008*fc06573dSJack Morgenstein 	ret = create_pv_resources(&dev->ib_dev, slave, port, 1,
1009*fc06573dSJack Morgenstein 				  dev->sriov.demux[port - 1].tun[slave]);
1010*fc06573dSJack Morgenstein 
1011*fc06573dSJack Morgenstein 	/* for master, create the real sqp resources */
1012*fc06573dSJack Morgenstein 	if (!ret && slave == mlx4_master_func_num(dev->dev))
1013*fc06573dSJack Morgenstein 		ret = create_pv_resources(&dev->ib_dev, slave, port, 0,
1014*fc06573dSJack Morgenstein 					  dev->sriov.sqps[port - 1]);
1015*fc06573dSJack Morgenstein 	return ret;
1016*fc06573dSJack Morgenstein }
1017*fc06573dSJack Morgenstein 
1018*fc06573dSJack Morgenstein void mlx4_ib_tunnels_update_work(struct work_struct *work)
1019*fc06573dSJack Morgenstein {
1020*fc06573dSJack Morgenstein 	struct mlx4_ib_demux_work *dmxw;
1021*fc06573dSJack Morgenstein 
1022*fc06573dSJack Morgenstein 	dmxw = container_of(work, struct mlx4_ib_demux_work, work);
1023*fc06573dSJack Morgenstein 	mlx4_ib_tunnels_update(dmxw->dev, dmxw->slave, (int) dmxw->port,
1024*fc06573dSJack Morgenstein 			       dmxw->do_init);
1025*fc06573dSJack Morgenstein 	kfree(dmxw);
1026*fc06573dSJack Morgenstein 	return;
1027*fc06573dSJack Morgenstein }
1028*fc06573dSJack Morgenstein 
1029*fc06573dSJack Morgenstein static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev,
1030*fc06573dSJack Morgenstein 				       struct mlx4_ib_demux_ctx *ctx,
1031*fc06573dSJack Morgenstein 				       int port)
1032*fc06573dSJack Morgenstein {
1033*fc06573dSJack Morgenstein 	char name[12];
1034*fc06573dSJack Morgenstein 	int ret = 0;
1035*fc06573dSJack Morgenstein 	int i;
1036*fc06573dSJack Morgenstein 
1037*fc06573dSJack Morgenstein 	ctx->tun = kcalloc(dev->dev->caps.sqp_demux,
1038*fc06573dSJack Morgenstein 			   sizeof (struct mlx4_ib_demux_pv_ctx *), GFP_KERNEL);
1039*fc06573dSJack Morgenstein 	if (!ctx->tun)
1040*fc06573dSJack Morgenstein 		return -ENOMEM;
1041*fc06573dSJack Morgenstein 
1042*fc06573dSJack Morgenstein 	ctx->dev = dev;
1043*fc06573dSJack Morgenstein 	ctx->port = port;
1044*fc06573dSJack Morgenstein 	ctx->ib_dev = &dev->ib_dev;
1045*fc06573dSJack Morgenstein 
1046*fc06573dSJack Morgenstein 	for (i = 0; i < dev->dev->caps.sqp_demux; i++) {
1047*fc06573dSJack Morgenstein 		ret = alloc_pv_object(dev, i, port, &ctx->tun[i]);
1048*fc06573dSJack Morgenstein 		if (ret) {
1049*fc06573dSJack Morgenstein 			ret = -ENOMEM;
1050*fc06573dSJack Morgenstein 			goto err_wq;
1051*fc06573dSJack Morgenstein 		}
1052*fc06573dSJack Morgenstein 	}
1053*fc06573dSJack Morgenstein 
1054*fc06573dSJack Morgenstein 	snprintf(name, sizeof name, "mlx4_ibt%d", port);
1055*fc06573dSJack Morgenstein 	ctx->wq = create_singlethread_workqueue(name);
1056*fc06573dSJack Morgenstein 	if (!ctx->wq) {
1057*fc06573dSJack Morgenstein 		pr_err("Failed to create tunnelling WQ for port %d\n", port);
1058*fc06573dSJack Morgenstein 		ret = -ENOMEM;
1059*fc06573dSJack Morgenstein 		goto err_wq;
1060*fc06573dSJack Morgenstein 	}
1061*fc06573dSJack Morgenstein 
1062*fc06573dSJack Morgenstein 	snprintf(name, sizeof name, "mlx4_ibud%d", port);
1063*fc06573dSJack Morgenstein 	ctx->ud_wq = create_singlethread_workqueue(name);
1064*fc06573dSJack Morgenstein 	if (!ctx->ud_wq) {
1065*fc06573dSJack Morgenstein 		pr_err("Failed to create up/down WQ for port %d\n", port);
1066*fc06573dSJack Morgenstein 		ret = -ENOMEM;
1067*fc06573dSJack Morgenstein 		goto err_udwq;
1068*fc06573dSJack Morgenstein 	}
1069*fc06573dSJack Morgenstein 
1070*fc06573dSJack Morgenstein 	return 0;
1071*fc06573dSJack Morgenstein 
1072*fc06573dSJack Morgenstein err_udwq:
1073*fc06573dSJack Morgenstein 	destroy_workqueue(ctx->wq);
1074*fc06573dSJack Morgenstein 	ctx->wq = NULL;
1075*fc06573dSJack Morgenstein 
1076*fc06573dSJack Morgenstein err_wq:
1077*fc06573dSJack Morgenstein 	for (i = 0; i < dev->dev->caps.sqp_demux; i++)
1078*fc06573dSJack Morgenstein 		free_pv_object(dev, i, port);
1079*fc06573dSJack Morgenstein 	kfree(ctx->tun);
1080*fc06573dSJack Morgenstein 	ctx->tun = NULL;
1081*fc06573dSJack Morgenstein 	return ret;
1082*fc06573dSJack Morgenstein }
1083*fc06573dSJack Morgenstein 
1084*fc06573dSJack Morgenstein static void mlx4_ib_free_sqp_ctx(struct mlx4_ib_demux_pv_ctx *sqp_ctx)
1085*fc06573dSJack Morgenstein {
1086*fc06573dSJack Morgenstein 	if (sqp_ctx->state > DEMUX_PV_STATE_DOWN) {
1087*fc06573dSJack Morgenstein 		sqp_ctx->state = DEMUX_PV_STATE_DOWNING;
1088*fc06573dSJack Morgenstein 		flush_workqueue(sqp_ctx->wq);
1089*fc06573dSJack Morgenstein 		if (sqp_ctx->has_smi) {
1090*fc06573dSJack Morgenstein 			ib_destroy_qp(sqp_ctx->qp[0].qp);
1091*fc06573dSJack Morgenstein 			sqp_ctx->qp[0].qp = NULL;
1092*fc06573dSJack Morgenstein 			mlx4_ib_free_pv_qp_bufs(sqp_ctx, IB_QPT_SMI, 0);
1093*fc06573dSJack Morgenstein 		}
1094*fc06573dSJack Morgenstein 		ib_destroy_qp(sqp_ctx->qp[1].qp);
1095*fc06573dSJack Morgenstein 		sqp_ctx->qp[1].qp = NULL;
1096*fc06573dSJack Morgenstein 		mlx4_ib_free_pv_qp_bufs(sqp_ctx, IB_QPT_GSI, 0);
1097*fc06573dSJack Morgenstein 		ib_dereg_mr(sqp_ctx->mr);
1098*fc06573dSJack Morgenstein 		sqp_ctx->mr = NULL;
1099*fc06573dSJack Morgenstein 		ib_dealloc_pd(sqp_ctx->pd);
1100*fc06573dSJack Morgenstein 		sqp_ctx->pd = NULL;
1101*fc06573dSJack Morgenstein 		ib_destroy_cq(sqp_ctx->cq);
1102*fc06573dSJack Morgenstein 		sqp_ctx->cq = NULL;
1103*fc06573dSJack Morgenstein 		sqp_ctx->state = DEMUX_PV_STATE_DOWN;
1104*fc06573dSJack Morgenstein 	}
1105*fc06573dSJack Morgenstein }
1106*fc06573dSJack Morgenstein 
1107*fc06573dSJack Morgenstein static void mlx4_ib_free_demux_ctx(struct mlx4_ib_demux_ctx *ctx)
1108*fc06573dSJack Morgenstein {
1109*fc06573dSJack Morgenstein 	int i;
1110*fc06573dSJack Morgenstein 	if (ctx) {
1111*fc06573dSJack Morgenstein 		struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev);
1112*fc06573dSJack Morgenstein 		for (i = 0; i < dev->dev->caps.sqp_demux; i++) {
1113*fc06573dSJack Morgenstein 			if (!ctx->tun[i])
1114*fc06573dSJack Morgenstein 				continue;
1115*fc06573dSJack Morgenstein 			if (ctx->tun[i]->state > DEMUX_PV_STATE_DOWN)
1116*fc06573dSJack Morgenstein 				ctx->tun[i]->state = DEMUX_PV_STATE_DOWNING;
1117*fc06573dSJack Morgenstein 		}
1118*fc06573dSJack Morgenstein 		flush_workqueue(ctx->wq);
1119*fc06573dSJack Morgenstein 		for (i = 0; i < dev->dev->caps.sqp_demux; i++) {
1120*fc06573dSJack Morgenstein 			destroy_pv_resources(dev, i, ctx->port, ctx->tun[i], 0);
1121*fc06573dSJack Morgenstein 			free_pv_object(dev, i, ctx->port);
1122*fc06573dSJack Morgenstein 		}
1123*fc06573dSJack Morgenstein 		kfree(ctx->tun);
1124*fc06573dSJack Morgenstein 		destroy_workqueue(ctx->ud_wq);
1125*fc06573dSJack Morgenstein 		destroy_workqueue(ctx->wq);
1126*fc06573dSJack Morgenstein 	}
1127*fc06573dSJack Morgenstein }
1128*fc06573dSJack Morgenstein 
1129*fc06573dSJack Morgenstein static void mlx4_ib_master_tunnels(struct mlx4_ib_dev *dev, int do_init)
1130*fc06573dSJack Morgenstein {
1131*fc06573dSJack Morgenstein 	int i;
1132*fc06573dSJack Morgenstein 
1133*fc06573dSJack Morgenstein 	if (!mlx4_is_master(dev->dev))
1134*fc06573dSJack Morgenstein 		return;
1135*fc06573dSJack Morgenstein 	/* initialize or tear down tunnel QPs for the master */
1136*fc06573dSJack Morgenstein 	for (i = 0; i < dev->dev->caps.num_ports; i++)
1137*fc06573dSJack Morgenstein 		mlx4_ib_tunnels_update(dev, mlx4_master_func_num(dev->dev), i + 1, do_init);
1138*fc06573dSJack Morgenstein 	return;
1139*fc06573dSJack Morgenstein }
1140*fc06573dSJack Morgenstein 
1141*fc06573dSJack Morgenstein int mlx4_ib_init_sriov(struct mlx4_ib_dev *dev)
1142*fc06573dSJack Morgenstein {
1143*fc06573dSJack Morgenstein 	int i = 0;
1144*fc06573dSJack Morgenstein 	int err;
1145*fc06573dSJack Morgenstein 
1146*fc06573dSJack Morgenstein 	if (!mlx4_is_mfunc(dev->dev))
1147*fc06573dSJack Morgenstein 		return 0;
1148*fc06573dSJack Morgenstein 
1149*fc06573dSJack Morgenstein 	dev->sriov.is_going_down = 0;
1150*fc06573dSJack Morgenstein 	spin_lock_init(&dev->sriov.going_down_lock);
1151*fc06573dSJack Morgenstein 
1152*fc06573dSJack Morgenstein 	mlx4_ib_warn(&dev->ib_dev, "multi-function enabled\n");
1153*fc06573dSJack Morgenstein 
1154*fc06573dSJack Morgenstein 	if (mlx4_is_slave(dev->dev)) {
1155*fc06573dSJack Morgenstein 		mlx4_ib_warn(&dev->ib_dev, "operating in qp1 tunnel mode\n");
1156*fc06573dSJack Morgenstein 		return 0;
1157*fc06573dSJack Morgenstein 	}
1158*fc06573dSJack Morgenstein 
1159*fc06573dSJack Morgenstein 	mlx4_ib_warn(&dev->ib_dev, "initializing demux service for %d qp1 clients\n",
1160*fc06573dSJack Morgenstein 		     dev->dev->caps.sqp_demux);
1161*fc06573dSJack Morgenstein 	for (i = 0; i < dev->num_ports; i++) {
1162*fc06573dSJack Morgenstein 		err = alloc_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1,
1163*fc06573dSJack Morgenstein 				      &dev->sriov.sqps[i]);
1164*fc06573dSJack Morgenstein 		if (err)
1165*fc06573dSJack Morgenstein 			goto demux_err;
1166*fc06573dSJack Morgenstein 		err = mlx4_ib_alloc_demux_ctx(dev, &dev->sriov.demux[i], i + 1);
1167*fc06573dSJack Morgenstein 		if (err)
1168*fc06573dSJack Morgenstein 			goto demux_err;
1169*fc06573dSJack Morgenstein 	}
1170*fc06573dSJack Morgenstein 	mlx4_ib_master_tunnels(dev, 1);
1171*fc06573dSJack Morgenstein 	return 0;
1172*fc06573dSJack Morgenstein 
1173*fc06573dSJack Morgenstein demux_err:
1174*fc06573dSJack Morgenstein 	while (i > 0) {
1175*fc06573dSJack Morgenstein 		free_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1);
1176*fc06573dSJack Morgenstein 		mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]);
1177*fc06573dSJack Morgenstein 		--i;
1178*fc06573dSJack Morgenstein 	}
1179*fc06573dSJack Morgenstein 
1180*fc06573dSJack Morgenstein 	return err;
1181*fc06573dSJack Morgenstein }
1182*fc06573dSJack Morgenstein 
1183*fc06573dSJack Morgenstein void mlx4_ib_close_sriov(struct mlx4_ib_dev *dev)
1184*fc06573dSJack Morgenstein {
1185*fc06573dSJack Morgenstein 	int i;
1186*fc06573dSJack Morgenstein 	unsigned long flags;
1187*fc06573dSJack Morgenstein 
1188*fc06573dSJack Morgenstein 	if (!mlx4_is_mfunc(dev->dev))
1189*fc06573dSJack Morgenstein 		return;
1190*fc06573dSJack Morgenstein 
1191*fc06573dSJack Morgenstein 	spin_lock_irqsave(&dev->sriov.going_down_lock, flags);
1192*fc06573dSJack Morgenstein 	dev->sriov.is_going_down = 1;
1193*fc06573dSJack Morgenstein 	spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags);
1194*fc06573dSJack Morgenstein 	if (mlx4_is_master(dev->dev))
1195*fc06573dSJack Morgenstein 		for (i = 0; i < dev->num_ports; i++) {
1196*fc06573dSJack Morgenstein 			flush_workqueue(dev->sriov.demux[i].ud_wq);
1197*fc06573dSJack Morgenstein 			mlx4_ib_free_sqp_ctx(dev->sriov.sqps[i]);
1198*fc06573dSJack Morgenstein 			kfree(dev->sriov.sqps[i]);
1199*fc06573dSJack Morgenstein 			dev->sriov.sqps[i] = NULL;
1200*fc06573dSJack Morgenstein 			mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]);
1201*fc06573dSJack Morgenstein 		}
1202*fc06573dSJack Morgenstein }
1203