ipoib_verbs.c revision 273246
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	ret = ib_modify_qp(priv->qp, &qp_attr, attr_mask);
93	if (ret) {
94		ipoib_warn(priv, "failed to modify QP to init, ret = %d\n", ret);
95		goto out_fail;
96	}
97
98	qp_attr.qp_state = IB_QPS_RTR;
99	/* Can't set this in a INIT->RTR transition */
100	attr_mask &= ~IB_QP_PORT;
101	ret = ib_modify_qp(priv->qp, &qp_attr, attr_mask);
102	if (ret) {
103		ipoib_warn(priv, "failed to modify QP to RTR, ret = %d\n", ret);
104		goto out_fail;
105	}
106
107	qp_attr.qp_state = IB_QPS_RTS;
108	qp_attr.sq_psn = 0;
109	attr_mask |= IB_QP_SQ_PSN;
110	attr_mask &= ~IB_QP_PKEY_INDEX;
111	ret = ib_modify_qp(priv->qp, &qp_attr, attr_mask);
112	if (ret) {
113		ipoib_warn(priv, "failed to modify QP to RTS, ret = %d\n", ret);
114		goto out_fail;
115	}
116
117	return 0;
118
119out_fail:
120	qp_attr.qp_state = IB_QPS_RESET;
121	if (ib_modify_qp(priv->qp, &qp_attr, IB_QP_STATE))
122		ipoib_warn(priv, "Failed to modify QP to RESET state\n");
123
124	return ret;
125}
126
127int ipoib_transport_dev_init(struct ipoib_dev_priv *priv, struct ib_device *ca)
128{
129	struct ib_qp_init_attr init_attr = {
130		.cap = {
131			.max_send_wr  = ipoib_sendq_size,
132			.max_recv_wr  = ipoib_recvq_size,
133			.max_send_sge = 1,
134			.max_recv_sge = IPOIB_UD_RX_SG
135		},
136		.sq_sig_type = IB_SIGNAL_ALL_WR,
137		.qp_type     = IB_QPT_UD
138	};
139
140	int ret, size;
141	int i;
142	/* XXX struct ethtool_coalesce *coal; */
143
144	priv->pd = ib_alloc_pd(priv->ca);
145	if (IS_ERR(priv->pd)) {
146		printk(KERN_WARNING "%s: failed to allocate PD\n", ca->name);
147		return -ENODEV;
148	}
149
150	priv->mr = ib_get_dma_mr(priv->pd, IB_ACCESS_LOCAL_WRITE);
151	if (IS_ERR(priv->mr)) {
152		printk(KERN_WARNING "%s: ib_get_dma_mr failed\n", ca->name);
153		goto out_free_pd;
154	}
155
156	size = ipoib_recvq_size + 1;
157	ret = ipoib_cm_dev_init(priv);
158	if (!ret) {
159		size += ipoib_sendq_size;
160		if (ipoib_cm_has_srq(priv))
161			size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */
162		else
163			size += ipoib_recvq_size * ipoib_max_conn_qp;
164	}
165
166	priv->recv_cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, priv, size, 0);
167	if (IS_ERR(priv->recv_cq)) {
168		printk(KERN_WARNING "%s: failed to create receive CQ\n", ca->name);
169		goto out_free_mr;
170	}
171
172	priv->send_cq = ib_create_cq(priv->ca, ipoib_send_comp_handler, NULL,
173				     priv, ipoib_sendq_size, 0);
174	if (IS_ERR(priv->send_cq)) {
175		printk(KERN_WARNING "%s: failed to create send CQ\n", ca->name);
176		goto out_free_recv_cq;
177	}
178
179	if (ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP))
180		goto out_free_send_cq;
181
182#if 0
183	/* XXX */
184	coal = kzalloc(sizeof *coal, GFP_KERNEL);
185	if (coal) {
186		coal->rx_coalesce_usecs = 10;
187		coal->tx_coalesce_usecs = 10;
188		coal->rx_max_coalesced_frames = 16;
189		coal->tx_max_coalesced_frames = 16;
190		dev->ethtool_ops->set_coalesce(dev, coal);
191		kfree(coal);
192	}
193#endif
194
195	init_attr.send_cq = priv->send_cq;
196	init_attr.recv_cq = priv->recv_cq;
197
198	if (priv->hca_caps & IB_DEVICE_UD_TSO)
199		init_attr.create_flags |= IB_QP_CREATE_IPOIB_UD_LSO;
200
201	if (priv->hca_caps & IB_DEVICE_BLOCK_MULTICAST_LOOPBACK)
202		init_attr.create_flags |= IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK;
203
204	init_attr.cap.max_send_sge = IPOIB_UD_TX_SG;
205
206	priv->qp = ib_create_qp(priv->pd, &init_attr);
207	if (IS_ERR(priv->qp)) {
208		printk(KERN_WARNING "%s: failed to create QP\n", ca->name);
209		goto out_free_send_cq;
210	}
211
212	IF_LLADDR(priv->dev)[1] = (priv->qp->qp_num >> 16) & 0xff;
213	IF_LLADDR(priv->dev)[2] = (priv->qp->qp_num >>  8) & 0xff;
214	IF_LLADDR(priv->dev)[3] = (priv->qp->qp_num      ) & 0xff;
215
216	for (i = 0; i < IPOIB_MAX_TX_SG; ++i)
217		priv->tx_sge[i].lkey = priv->mr->lkey;
218
219	priv->tx_wr.opcode	= IB_WR_SEND;
220	priv->tx_wr.sg_list	= priv->tx_sge;
221	priv->tx_wr.send_flags	= IB_SEND_SIGNALED;
222
223	for (i = 0; i < IPOIB_UD_RX_SG; ++i)
224		priv->rx_sge[i].lkey = priv->mr->lkey;
225	priv->rx_wr.next = NULL;
226	priv->rx_wr.sg_list = priv->rx_sge;
227
228	return 0;
229
230out_free_send_cq:
231	ib_destroy_cq(priv->send_cq);
232
233out_free_recv_cq:
234	ib_destroy_cq(priv->recv_cq);
235
236out_free_mr:
237	ib_dereg_mr(priv->mr);
238	ipoib_cm_dev_cleanup(priv);
239
240out_free_pd:
241	ib_dealloc_pd(priv->pd);
242	return -ENODEV;
243}
244
245void ipoib_transport_dev_cleanup(struct ipoib_dev_priv *priv)
246{
247
248	if (priv->qp) {
249		if (ib_destroy_qp(priv->qp))
250			ipoib_warn(priv, "ib_qp_destroy failed\n");
251
252		priv->qp = NULL;
253		clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
254	}
255
256	if (ib_destroy_cq(priv->send_cq))
257		ipoib_warn(priv, "ib_cq_destroy (send) failed\n");
258
259	if (ib_destroy_cq(priv->recv_cq))
260		ipoib_warn(priv, "ib_cq_destroy (recv) failed\n");
261
262	ipoib_cm_dev_cleanup(priv);
263
264	if (ib_dereg_mr(priv->mr))
265		ipoib_warn(priv, "ib_dereg_mr failed\n");
266
267	if (ib_dealloc_pd(priv->pd))
268		ipoib_warn(priv, "ib_dealloc_pd failed\n");
269}
270
271void ipoib_event(struct ib_event_handler *handler,
272		 struct ib_event *record)
273{
274	struct ipoib_dev_priv *priv =
275		container_of(handler, struct ipoib_dev_priv, event_handler);
276
277	if (record->element.port_num != priv->port)
278		return;
279
280	ipoib_dbg(priv, "Event %d on device %s port %d\n", record->event,
281		  record->device->name, record->element.port_num);
282
283	if (record->event == IB_EVENT_SM_CHANGE ||
284	    record->event == IB_EVENT_CLIENT_REREGISTER) {
285		queue_work(ipoib_workqueue, &priv->flush_light);
286	} else if (record->event == IB_EVENT_PORT_ERR ||
287		   record->event == IB_EVENT_PORT_ACTIVE ||
288		   record->event == IB_EVENT_LID_CHANGE) {
289		queue_work(ipoib_workqueue, &priv->flush_normal);
290	} else if (record->event == IB_EVENT_PKEY_CHANGE) {
291		queue_work(ipoib_workqueue, &priv->flush_heavy);
292	}
293}
294