ipoib_verbs.c revision 331769
1/*
2 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
3 * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses.  You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
10 *
11 *     Redistribution and use in source and binary forms, with or
12 *     without modification, are permitted provided that the following
13 *     conditions are met:
14 *
15 *      - Redistributions of source code must retain the above
16 *        copyright notice, this list of conditions and the following
17 *        disclaimer.
18 *
19 *      - Redistributions in binary form must reproduce the above
20 *        copyright notice, this list of conditions and the following
21 *        disclaimer in the documentation and/or other materials
22 *        provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 */
33
34#include "ipoib.h"
35
36int ipoib_mcast_attach(struct ipoib_dev_priv *priv, u16 mlid, union ib_gid *mgid, int set_qkey)
37{
38	struct ib_qp_attr *qp_attr = NULL;
39	int ret;
40	u16 pkey_index;
41
42	if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &pkey_index)) {
43		clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
44		ret = -ENXIO;
45		goto out;
46	}
47	set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
48
49	if (set_qkey) {
50		ret = -ENOMEM;
51		qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL);
52		if (!qp_attr)
53			goto out;
54
55		/* set correct QKey for QP */
56		qp_attr->qkey = priv->qkey;
57		ret = ib_modify_qp(priv->qp, qp_attr, IB_QP_QKEY);
58		if (ret) {
59			ipoib_warn(priv, "failed to modify QP, ret = %d\n", ret);
60			goto out;
61		}
62	}
63
64	/* attach QP to multicast group */
65	ret = ib_attach_mcast(priv->qp, mgid, mlid);
66	if (ret)
67		ipoib_warn(priv, "failed to attach to multicast group, ret = %d\n", ret);
68
69out:
70	kfree(qp_attr);
71	return ret;
72}
73
74int ipoib_init_qp(struct ipoib_dev_priv *priv)
75{
76	int ret;
77	struct ib_qp_attr qp_attr;
78	int attr_mask;
79
80	if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags))
81		return -1;
82
83	qp_attr.qp_state = IB_QPS_INIT;
84	qp_attr.qkey = 0;
85	qp_attr.port_num = priv->port;
86	qp_attr.pkey_index = priv->pkey_index;
87	attr_mask =
88	    IB_QP_QKEY |
89	    IB_QP_PORT |
90	    IB_QP_PKEY_INDEX |
91	    IB_QP_STATE;
92
93	ret = ib_modify_qp(priv->qp, &qp_attr, attr_mask);
94	if (ret) {
95		ipoib_warn(priv, "failed to modify QP to init, ret = %d\n", ret);
96		goto out_fail;
97	}
98
99	qp_attr.qp_state = IB_QPS_RTR;
100	/* Can't set this in a INIT->RTR transition */
101	attr_mask &= ~IB_QP_PORT;
102	ret = ib_modify_qp(priv->qp, &qp_attr, attr_mask);
103	if (ret) {
104		ipoib_warn(priv, "failed to modify QP to RTR, ret = %d\n", ret);
105		goto out_fail;
106	}
107
108	qp_attr.qp_state = IB_QPS_RTS;
109	qp_attr.sq_psn = 0;
110	attr_mask |= IB_QP_SQ_PSN;
111	attr_mask &= ~IB_QP_PKEY_INDEX;
112	ret = ib_modify_qp(priv->qp, &qp_attr, attr_mask);
113	if (ret) {
114		ipoib_warn(priv, "failed to modify QP to RTS, ret = %d\n", ret);
115		goto out_fail;
116	}
117
118	return 0;
119
120out_fail:
121	qp_attr.qp_state = IB_QPS_RESET;
122	if (ib_modify_qp(priv->qp, &qp_attr, IB_QP_STATE))
123		ipoib_warn(priv, "Failed to modify QP to RESET state\n");
124
125	return ret;
126}
127
128int ipoib_transport_dev_init(struct ipoib_dev_priv *priv, struct ib_device *ca)
129{
130	struct ib_qp_init_attr init_attr = {
131		.cap = {
132			.max_send_wr  = ipoib_sendq_size,
133			.max_recv_wr  = ipoib_recvq_size,
134			.max_send_sge = 1,
135			.max_recv_sge = IPOIB_UD_RX_SG
136		},
137		.sq_sig_type = IB_SIGNAL_ALL_WR,
138		.qp_type     = IB_QPT_UD
139	};
140	struct ib_cq_init_attr cq_attr = {};
141
142	int ret, size;
143	int i;
144	/* XXX struct ethtool_coalesce *coal; */
145
146	priv->pd = ib_alloc_pd(priv->ca, 0);
147	if (IS_ERR(priv->pd)) {
148		printk(KERN_WARNING "%s: failed to allocate PD\n", ca->name);
149		return -ENODEV;
150	}
151
152	size = ipoib_recvq_size + 1;
153	ret = ipoib_cm_dev_init(priv);
154	if (!ret) {
155		size += ipoib_sendq_size;
156		if (ipoib_cm_has_srq(priv))
157			size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */
158		else
159			size += ipoib_recvq_size * ipoib_max_conn_qp;
160	}
161
162	cq_attr.cqe = size;
163	priv->recv_cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, priv, &cq_attr);
164	if (IS_ERR(priv->recv_cq)) {
165		printk(KERN_WARNING "%s: failed to create receive CQ\n", ca->name);
166		goto out_free_mr;
167	}
168
169	cq_attr.cqe = ipoib_sendq_size;
170	priv->send_cq = ib_create_cq(priv->ca, ipoib_send_comp_handler, NULL,
171				     priv, &cq_attr);
172	if (IS_ERR(priv->send_cq)) {
173		printk(KERN_WARNING "%s: failed to create send CQ\n", ca->name);
174		goto out_free_recv_cq;
175	}
176
177	if (ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP))
178		goto out_free_send_cq;
179
180#if 0
181	/* XXX */
182	coal = kzalloc(sizeof *coal, GFP_KERNEL);
183	if (coal) {
184		coal->rx_coalesce_usecs = 10;
185		coal->tx_coalesce_usecs = 10;
186		coal->rx_max_coalesced_frames = 16;
187		coal->tx_max_coalesced_frames = 16;
188		dev->ethtool_ops->set_coalesce(dev, coal);
189		kfree(coal);
190	}
191#endif
192
193	init_attr.send_cq = priv->send_cq;
194	init_attr.recv_cq = priv->recv_cq;
195
196	if (priv->hca_caps & IB_DEVICE_UD_TSO)
197		init_attr.create_flags |= IB_QP_CREATE_IPOIB_UD_LSO;
198
199	if (priv->hca_caps & IB_DEVICE_BLOCK_MULTICAST_LOOPBACK)
200		init_attr.create_flags |= IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK;
201
202	init_attr.cap.max_send_sge = IPOIB_UD_TX_SG;
203
204	priv->qp = ib_create_qp(priv->pd, &init_attr);
205	if (IS_ERR(priv->qp)) {
206		printk(KERN_WARNING "%s: failed to create QP\n", ca->name);
207		goto out_free_send_cq;
208	}
209
210	IF_LLADDR(priv->dev)[1] = (priv->qp->qp_num >> 16) & 0xff;
211	IF_LLADDR(priv->dev)[2] = (priv->qp->qp_num >>  8) & 0xff;
212	IF_LLADDR(priv->dev)[3] = (priv->qp->qp_num      ) & 0xff;
213
214	for (i = 0; i < IPOIB_MAX_TX_SG; ++i)
215		priv->tx_sge[i].lkey = priv->pd->local_dma_lkey;
216
217	priv->tx_wr.wr.opcode		= IB_WR_SEND;
218	priv->tx_wr.wr.sg_list		= priv->tx_sge;
219	priv->tx_wr.wr.send_flags	= IB_SEND_SIGNALED;
220
221	for (i = 0; i < IPOIB_UD_RX_SG; ++i)
222		priv->rx_sge[i].lkey = priv->pd->local_dma_lkey;
223	priv->rx_wr.next = NULL;
224	priv->rx_wr.sg_list = priv->rx_sge;
225
226	return 0;
227
228out_free_send_cq:
229	ib_destroy_cq(priv->send_cq);
230
231out_free_recv_cq:
232	ib_destroy_cq(priv->recv_cq);
233
234out_free_mr:
235	ipoib_cm_dev_cleanup(priv);
236
237	ib_dealloc_pd(priv->pd);
238	return -ENODEV;
239}
240
241void ipoib_transport_dev_cleanup(struct ipoib_dev_priv *priv)
242{
243
244	if (priv->qp) {
245		if (ib_destroy_qp(priv->qp))
246			ipoib_warn(priv, "ib_qp_destroy failed\n");
247
248		priv->qp = NULL;
249		clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
250	}
251
252	if (ib_destroy_cq(priv->send_cq))
253		ipoib_warn(priv, "ib_cq_destroy (send) failed\n");
254
255	if (ib_destroy_cq(priv->recv_cq))
256		ipoib_warn(priv, "ib_cq_destroy (recv) failed\n");
257
258	ipoib_cm_dev_cleanup(priv);
259
260	ib_dealloc_pd(priv->pd);
261}
262
263void ipoib_event(struct ib_event_handler *handler,
264		 struct ib_event *record)
265{
266	struct ipoib_dev_priv *priv =
267		container_of(handler, struct ipoib_dev_priv, event_handler);
268
269	if (record->element.port_num != priv->port)
270		return;
271
272	ipoib_dbg(priv, "Event %d on device %s port %d\n", record->event,
273		  record->device->name, record->element.port_num);
274
275	if (record->event == IB_EVENT_SM_CHANGE ||
276	    record->event == IB_EVENT_CLIENT_REREGISTER) {
277		queue_work(ipoib_workqueue, &priv->flush_light);
278	} else if (record->event == IB_EVENT_PORT_ERR ||
279		   record->event == IB_EVENT_PORT_ACTIVE ||
280		   record->event == IB_EVENT_LID_CHANGE) {
281		queue_work(ipoib_workqueue, &priv->flush_normal);
282	} else if (record->event == IB_EVENT_PKEY_CHANGE) {
283		queue_work(ipoib_workqueue, &priv->flush_heavy);
284	}
285}
286