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