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