18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 38c2ecf20Sopenharmony_ci * Copyright (c) 2005 Mellanox Technologies. All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 68c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 78c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 88c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 98c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 128c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 138c2ecf20Sopenharmony_ci * conditions are met: 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 168c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 178c2ecf20Sopenharmony_ci * disclaimer. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 208c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 218c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 228c2ecf20Sopenharmony_ci * provided with the distribution. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 258c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 268c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 278c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 288c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 298c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 308c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 318c2ecf20Sopenharmony_ci * SOFTWARE. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/slab.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include "ipoib.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ciint ipoib_mcast_attach(struct net_device *dev, struct ib_device *hca, 398c2ecf20Sopenharmony_ci union ib_gid *mgid, u16 mlid, int set_qkey, u32 qkey) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 428c2ecf20Sopenharmony_ci struct ib_qp_attr *qp_attr = NULL; 438c2ecf20Sopenharmony_ci int ret; 448c2ecf20Sopenharmony_ci u16 pkey_index; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &pkey_index)) { 478c2ecf20Sopenharmony_ci clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); 488c2ecf20Sopenharmony_ci ret = -ENXIO; 498c2ecf20Sopenharmony_ci goto out; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (set_qkey) { 548c2ecf20Sopenharmony_ci ret = -ENOMEM; 558c2ecf20Sopenharmony_ci qp_attr = kmalloc(sizeof(*qp_attr), GFP_KERNEL); 568c2ecf20Sopenharmony_ci if (!qp_attr) 578c2ecf20Sopenharmony_ci goto out; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* set correct QKey for QP */ 608c2ecf20Sopenharmony_ci qp_attr->qkey = qkey; 618c2ecf20Sopenharmony_ci ret = ib_modify_qp(priv->qp, qp_attr, IB_QP_QKEY); 628c2ecf20Sopenharmony_ci if (ret) { 638c2ecf20Sopenharmony_ci ipoib_warn(priv, "failed to modify QP, ret = %d\n", ret); 648c2ecf20Sopenharmony_ci goto out; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* attach QP to multicast group */ 698c2ecf20Sopenharmony_ci ret = ib_attach_mcast(priv->qp, mgid, mlid); 708c2ecf20Sopenharmony_ci if (ret) 718c2ecf20Sopenharmony_ci ipoib_warn(priv, "failed to attach to multicast group, ret = %d\n", ret); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciout: 748c2ecf20Sopenharmony_ci kfree(qp_attr); 758c2ecf20Sopenharmony_ci return ret; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ciint ipoib_mcast_detach(struct net_device *dev, struct ib_device *hca, 798c2ecf20Sopenharmony_ci union ib_gid *mgid, u16 mlid) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 828c2ecf20Sopenharmony_ci int ret; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci ret = ib_detach_mcast(priv->qp, mgid, mlid); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return ret; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ciint ipoib_init_qp(struct net_device *dev) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 928c2ecf20Sopenharmony_ci int ret; 938c2ecf20Sopenharmony_ci struct ib_qp_attr qp_attr; 948c2ecf20Sopenharmony_ci int attr_mask; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) 978c2ecf20Sopenharmony_ci return -1; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci qp_attr.qp_state = IB_QPS_INIT; 1008c2ecf20Sopenharmony_ci qp_attr.qkey = 0; 1018c2ecf20Sopenharmony_ci qp_attr.port_num = priv->port; 1028c2ecf20Sopenharmony_ci qp_attr.pkey_index = priv->pkey_index; 1038c2ecf20Sopenharmony_ci attr_mask = 1048c2ecf20Sopenharmony_ci IB_QP_QKEY | 1058c2ecf20Sopenharmony_ci IB_QP_PORT | 1068c2ecf20Sopenharmony_ci IB_QP_PKEY_INDEX | 1078c2ecf20Sopenharmony_ci IB_QP_STATE; 1088c2ecf20Sopenharmony_ci ret = ib_modify_qp(priv->qp, &qp_attr, attr_mask); 1098c2ecf20Sopenharmony_ci if (ret) { 1108c2ecf20Sopenharmony_ci ipoib_warn(priv, "failed to modify QP to init, ret = %d\n", ret); 1118c2ecf20Sopenharmony_ci goto out_fail; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci qp_attr.qp_state = IB_QPS_RTR; 1158c2ecf20Sopenharmony_ci /* Can't set this in a INIT->RTR transition */ 1168c2ecf20Sopenharmony_ci attr_mask &= ~IB_QP_PORT; 1178c2ecf20Sopenharmony_ci ret = ib_modify_qp(priv->qp, &qp_attr, attr_mask); 1188c2ecf20Sopenharmony_ci if (ret) { 1198c2ecf20Sopenharmony_ci ipoib_warn(priv, "failed to modify QP to RTR, ret = %d\n", ret); 1208c2ecf20Sopenharmony_ci goto out_fail; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci qp_attr.qp_state = IB_QPS_RTS; 1248c2ecf20Sopenharmony_ci qp_attr.sq_psn = 0; 1258c2ecf20Sopenharmony_ci attr_mask |= IB_QP_SQ_PSN; 1268c2ecf20Sopenharmony_ci attr_mask &= ~IB_QP_PKEY_INDEX; 1278c2ecf20Sopenharmony_ci ret = ib_modify_qp(priv->qp, &qp_attr, attr_mask); 1288c2ecf20Sopenharmony_ci if (ret) { 1298c2ecf20Sopenharmony_ci ipoib_warn(priv, "failed to modify QP to RTS, ret = %d\n", ret); 1308c2ecf20Sopenharmony_ci goto out_fail; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ciout_fail: 1368c2ecf20Sopenharmony_ci qp_attr.qp_state = IB_QPS_RESET; 1378c2ecf20Sopenharmony_ci if (ib_modify_qp(priv->qp, &qp_attr, IB_QP_STATE)) 1388c2ecf20Sopenharmony_ci ipoib_warn(priv, "Failed to modify QP to RESET state\n"); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return ret; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ciint ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 1468c2ecf20Sopenharmony_ci struct ib_qp_init_attr init_attr = { 1478c2ecf20Sopenharmony_ci .cap = { 1488c2ecf20Sopenharmony_ci .max_send_wr = ipoib_sendq_size, 1498c2ecf20Sopenharmony_ci .max_recv_wr = ipoib_recvq_size, 1508c2ecf20Sopenharmony_ci .max_send_sge = min_t(u32, priv->ca->attrs.max_send_sge, 1518c2ecf20Sopenharmony_ci MAX_SKB_FRAGS + 1), 1528c2ecf20Sopenharmony_ci .max_recv_sge = IPOIB_UD_RX_SG 1538c2ecf20Sopenharmony_ci }, 1548c2ecf20Sopenharmony_ci .sq_sig_type = IB_SIGNAL_ALL_WR, 1558c2ecf20Sopenharmony_ci .qp_type = IB_QPT_UD 1568c2ecf20Sopenharmony_ci }; 1578c2ecf20Sopenharmony_ci struct ib_cq_init_attr cq_attr = {}; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci int ret, size, req_vec; 1608c2ecf20Sopenharmony_ci int i; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci size = ipoib_recvq_size + 1; 1638c2ecf20Sopenharmony_ci ret = ipoib_cm_dev_init(dev); 1648c2ecf20Sopenharmony_ci if (!ret) { 1658c2ecf20Sopenharmony_ci size += ipoib_sendq_size; 1668c2ecf20Sopenharmony_ci if (ipoib_cm_has_srq(dev)) 1678c2ecf20Sopenharmony_ci size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */ 1688c2ecf20Sopenharmony_ci else 1698c2ecf20Sopenharmony_ci size += ipoib_recvq_size * ipoib_max_conn_qp; 1708c2ecf20Sopenharmony_ci } else 1718c2ecf20Sopenharmony_ci if (ret != -EOPNOTSUPP) 1728c2ecf20Sopenharmony_ci return ret; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci req_vec = (priv->port - 1) * 2; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci cq_attr.cqe = size; 1778c2ecf20Sopenharmony_ci cq_attr.comp_vector = req_vec % priv->ca->num_comp_vectors; 1788c2ecf20Sopenharmony_ci priv->recv_cq = ib_create_cq(priv->ca, ipoib_ib_rx_completion, NULL, 1798c2ecf20Sopenharmony_ci priv, &cq_attr); 1808c2ecf20Sopenharmony_ci if (IS_ERR(priv->recv_cq)) { 1818c2ecf20Sopenharmony_ci pr_warn("%s: failed to create receive CQ\n", ca->name); 1828c2ecf20Sopenharmony_ci goto out_cm_dev_cleanup; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci cq_attr.cqe = ipoib_sendq_size; 1868c2ecf20Sopenharmony_ci cq_attr.comp_vector = (req_vec + 1) % priv->ca->num_comp_vectors; 1878c2ecf20Sopenharmony_ci priv->send_cq = ib_create_cq(priv->ca, ipoib_ib_tx_completion, NULL, 1888c2ecf20Sopenharmony_ci priv, &cq_attr); 1898c2ecf20Sopenharmony_ci if (IS_ERR(priv->send_cq)) { 1908c2ecf20Sopenharmony_ci pr_warn("%s: failed to create send CQ\n", ca->name); 1918c2ecf20Sopenharmony_ci goto out_free_recv_cq; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP)) 1958c2ecf20Sopenharmony_ci goto out_free_send_cq; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci init_attr.send_cq = priv->send_cq; 1988c2ecf20Sopenharmony_ci init_attr.recv_cq = priv->recv_cq; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (priv->hca_caps & IB_DEVICE_UD_TSO) 2018c2ecf20Sopenharmony_ci init_attr.create_flags |= IB_QP_CREATE_IPOIB_UD_LSO; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (priv->hca_caps & IB_DEVICE_BLOCK_MULTICAST_LOOPBACK) 2048c2ecf20Sopenharmony_ci init_attr.create_flags |= IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (priv->hca_caps & IB_DEVICE_MANAGED_FLOW_STEERING) 2078c2ecf20Sopenharmony_ci init_attr.create_flags |= IB_QP_CREATE_NETIF_QP; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (priv->hca_caps & IB_DEVICE_RDMA_NETDEV_OPA) 2108c2ecf20Sopenharmony_ci init_attr.create_flags |= IB_QP_CREATE_NETDEV_USE; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci priv->qp = ib_create_qp(priv->pd, &init_attr); 2138c2ecf20Sopenharmony_ci if (IS_ERR(priv->qp)) { 2148c2ecf20Sopenharmony_ci pr_warn("%s: failed to create QP\n", ca->name); 2158c2ecf20Sopenharmony_ci goto out_free_send_cq; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (ib_req_notify_cq(priv->send_cq, IB_CQ_NEXT_COMP)) 2198c2ecf20Sopenharmony_ci goto out_free_send_cq; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci for (i = 0; i < MAX_SKB_FRAGS + 1; ++i) 2228c2ecf20Sopenharmony_ci priv->tx_sge[i].lkey = priv->pd->local_dma_lkey; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci priv->tx_wr.wr.opcode = IB_WR_SEND; 2258c2ecf20Sopenharmony_ci priv->tx_wr.wr.sg_list = priv->tx_sge; 2268c2ecf20Sopenharmony_ci priv->tx_wr.wr.send_flags = IB_SEND_SIGNALED; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci priv->rx_sge[0].lkey = priv->pd->local_dma_lkey; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci priv->rx_sge[0].length = IPOIB_UD_BUF_SIZE(priv->max_ib_mtu); 2318c2ecf20Sopenharmony_ci priv->rx_wr.num_sge = 1; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci priv->rx_wr.next = NULL; 2348c2ecf20Sopenharmony_ci priv->rx_wr.sg_list = priv->rx_sge; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (init_attr.cap.max_send_sge > 1) 2378c2ecf20Sopenharmony_ci dev->features |= NETIF_F_SG; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci priv->max_send_sge = init_attr.cap.max_send_sge; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return 0; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ciout_free_send_cq: 2448c2ecf20Sopenharmony_ci ib_destroy_cq(priv->send_cq); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciout_free_recv_cq: 2478c2ecf20Sopenharmony_ci ib_destroy_cq(priv->recv_cq); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ciout_cm_dev_cleanup: 2508c2ecf20Sopenharmony_ci ipoib_cm_dev_cleanup(dev); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return -ENODEV; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_civoid ipoib_transport_dev_cleanup(struct net_device *dev) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (priv->qp) { 2608c2ecf20Sopenharmony_ci if (ib_destroy_qp(priv->qp)) 2618c2ecf20Sopenharmony_ci ipoib_warn(priv, "ib_qp_destroy failed\n"); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci priv->qp = NULL; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci ib_destroy_cq(priv->send_cq); 2678c2ecf20Sopenharmony_ci ib_destroy_cq(priv->recv_cq); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_civoid ipoib_event(struct ib_event_handler *handler, 2718c2ecf20Sopenharmony_ci struct ib_event *record) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = 2748c2ecf20Sopenharmony_ci container_of(handler, struct ipoib_dev_priv, event_handler); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (record->element.port_num != priv->port) 2778c2ecf20Sopenharmony_ci return; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ipoib_dbg(priv, "Event %d on device %s port %d\n", record->event, 2808c2ecf20Sopenharmony_ci dev_name(&record->device->dev), record->element.port_num); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (record->event == IB_EVENT_CLIENT_REREGISTER) { 2838c2ecf20Sopenharmony_ci queue_work(ipoib_workqueue, &priv->flush_light); 2848c2ecf20Sopenharmony_ci } else if (record->event == IB_EVENT_PORT_ERR || 2858c2ecf20Sopenharmony_ci record->event == IB_EVENT_PORT_ACTIVE || 2868c2ecf20Sopenharmony_ci record->event == IB_EVENT_LID_CHANGE) { 2878c2ecf20Sopenharmony_ci queue_work(ipoib_workqueue, &priv->flush_normal); 2888c2ecf20Sopenharmony_ci } else if (record->event == IB_EVENT_PKEY_CHANGE) { 2898c2ecf20Sopenharmony_ci queue_work(ipoib_workqueue, &priv->flush_heavy); 2908c2ecf20Sopenharmony_ci } else if (record->event == IB_EVENT_GID_CHANGE && 2918c2ecf20Sopenharmony_ci !test_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags)) { 2928c2ecf20Sopenharmony_ci queue_work(ipoib_workqueue, &priv->flush_light); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci} 295