18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright(c) 2020 Intel Corporation. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci/* 88c2ecf20Sopenharmony_ci * This file contains HFI1 support for ipoib functionality 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "ipoib.h" 128c2ecf20Sopenharmony_ci#include "hfi.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic u32 qpn_from_mac(u8 *mac_arr) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci return (u32)mac_arr[1] << 16 | mac_arr[2] << 8 | mac_arr[3]; 178c2ecf20Sopenharmony_ci} 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int hfi1_ipoib_dev_init(struct net_device *dev) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 228c2ecf20Sopenharmony_ci int ret; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci priv->netstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci ret = priv->netdev_ops->ndo_init(dev); 278c2ecf20Sopenharmony_ci if (ret) 288c2ecf20Sopenharmony_ci return ret; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci ret = hfi1_netdev_add_data(priv->dd, 318c2ecf20Sopenharmony_ci qpn_from_mac(priv->netdev->dev_addr), 328c2ecf20Sopenharmony_ci dev); 338c2ecf20Sopenharmony_ci if (ret < 0) { 348c2ecf20Sopenharmony_ci priv->netdev_ops->ndo_uninit(dev); 358c2ecf20Sopenharmony_ci return ret; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci return 0; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void hfi1_ipoib_dev_uninit(struct net_device *dev) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci hfi1_netdev_remove_data(priv->dd, qpn_from_mac(priv->netdev->dev_addr)); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci priv->netdev_ops->ndo_uninit(dev); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int hfi1_ipoib_dev_open(struct net_device *dev) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 538c2ecf20Sopenharmony_ci int ret; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci ret = priv->netdev_ops->ndo_open(dev); 568c2ecf20Sopenharmony_ci if (!ret) { 578c2ecf20Sopenharmony_ci struct hfi1_ibport *ibp = to_iport(priv->device, 588c2ecf20Sopenharmony_ci priv->port_num); 598c2ecf20Sopenharmony_ci struct rvt_qp *qp; 608c2ecf20Sopenharmony_ci u32 qpn = qpn_from_mac(priv->netdev->dev_addr); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci rcu_read_lock(); 638c2ecf20Sopenharmony_ci qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn); 648c2ecf20Sopenharmony_ci if (!qp) { 658c2ecf20Sopenharmony_ci rcu_read_unlock(); 668c2ecf20Sopenharmony_ci priv->netdev_ops->ndo_stop(dev); 678c2ecf20Sopenharmony_ci return -EINVAL; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci rvt_get_qp(qp); 708c2ecf20Sopenharmony_ci priv->qp = qp; 718c2ecf20Sopenharmony_ci rcu_read_unlock(); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci hfi1_netdev_enable_queues(priv->dd); 748c2ecf20Sopenharmony_ci hfi1_ipoib_napi_tx_enable(dev); 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return ret; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int hfi1_ipoib_dev_stop(struct net_device *dev) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (!priv->qp) 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci hfi1_ipoib_napi_tx_disable(dev); 888c2ecf20Sopenharmony_ci hfi1_netdev_disable_queues(priv->dd); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci rvt_put_qp(priv->qp); 918c2ecf20Sopenharmony_ci priv->qp = NULL; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return priv->netdev_ops->ndo_stop(dev); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void hfi1_ipoib_dev_get_stats64(struct net_device *dev, 978c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *storage) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci netdev_stats_to_stats64(storage, &dev->stats); 1028c2ecf20Sopenharmony_ci dev_fetch_sw_netstats(storage, priv->netstats); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic const struct net_device_ops hfi1_ipoib_netdev_ops = { 1068c2ecf20Sopenharmony_ci .ndo_init = hfi1_ipoib_dev_init, 1078c2ecf20Sopenharmony_ci .ndo_uninit = hfi1_ipoib_dev_uninit, 1088c2ecf20Sopenharmony_ci .ndo_open = hfi1_ipoib_dev_open, 1098c2ecf20Sopenharmony_ci .ndo_stop = hfi1_ipoib_dev_stop, 1108c2ecf20Sopenharmony_ci .ndo_get_stats64 = hfi1_ipoib_dev_get_stats64, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic int hfi1_ipoib_send(struct net_device *dev, 1148c2ecf20Sopenharmony_ci struct sk_buff *skb, 1158c2ecf20Sopenharmony_ci struct ib_ah *address, 1168c2ecf20Sopenharmony_ci u32 dqpn) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci return hfi1_ipoib_send_dma(dev, skb, address, dqpn); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int hfi1_ipoib_mcast_attach(struct net_device *dev, 1228c2ecf20Sopenharmony_ci struct ib_device *device, 1238c2ecf20Sopenharmony_ci union ib_gid *mgid, 1248c2ecf20Sopenharmony_ci u16 mlid, 1258c2ecf20Sopenharmony_ci int set_qkey, 1268c2ecf20Sopenharmony_ci u32 qkey) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 1298c2ecf20Sopenharmony_ci u32 qpn = (u32)qpn_from_mac(priv->netdev->dev_addr); 1308c2ecf20Sopenharmony_ci struct hfi1_ibport *ibp = to_iport(priv->device, priv->port_num); 1318c2ecf20Sopenharmony_ci struct rvt_qp *qp; 1328c2ecf20Sopenharmony_ci int ret = -EINVAL; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci rcu_read_lock(); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn); 1378c2ecf20Sopenharmony_ci if (qp) { 1388c2ecf20Sopenharmony_ci rvt_get_qp(qp); 1398c2ecf20Sopenharmony_ci rcu_read_unlock(); 1408c2ecf20Sopenharmony_ci if (set_qkey) 1418c2ecf20Sopenharmony_ci priv->qkey = qkey; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* attach QP to multicast group */ 1448c2ecf20Sopenharmony_ci ret = ib_attach_mcast(&qp->ibqp, mgid, mlid); 1458c2ecf20Sopenharmony_ci rvt_put_qp(qp); 1468c2ecf20Sopenharmony_ci } else { 1478c2ecf20Sopenharmony_ci rcu_read_unlock(); 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return ret; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic int hfi1_ipoib_mcast_detach(struct net_device *dev, 1548c2ecf20Sopenharmony_ci struct ib_device *device, 1558c2ecf20Sopenharmony_ci union ib_gid *mgid, 1568c2ecf20Sopenharmony_ci u16 mlid) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 1598c2ecf20Sopenharmony_ci u32 qpn = (u32)qpn_from_mac(priv->netdev->dev_addr); 1608c2ecf20Sopenharmony_ci struct hfi1_ibport *ibp = to_iport(priv->device, priv->port_num); 1618c2ecf20Sopenharmony_ci struct rvt_qp *qp; 1628c2ecf20Sopenharmony_ci int ret = -EINVAL; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci rcu_read_lock(); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn); 1678c2ecf20Sopenharmony_ci if (qp) { 1688c2ecf20Sopenharmony_ci rvt_get_qp(qp); 1698c2ecf20Sopenharmony_ci rcu_read_unlock(); 1708c2ecf20Sopenharmony_ci ret = ib_detach_mcast(&qp->ibqp, mgid, mlid); 1718c2ecf20Sopenharmony_ci rvt_put_qp(qp); 1728c2ecf20Sopenharmony_ci } else { 1738c2ecf20Sopenharmony_ci rcu_read_unlock(); 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci return ret; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic void hfi1_ipoib_netdev_dtor(struct net_device *dev) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci hfi1_ipoib_txreq_deinit(priv); 1838c2ecf20Sopenharmony_ci hfi1_ipoib_rxq_deinit(priv->netdev); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci free_percpu(priv->netstats); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic void hfi1_ipoib_set_id(struct net_device *dev, int id) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci priv->pkey_index = (u16)id; 1938c2ecf20Sopenharmony_ci ib_query_pkey(priv->device, 1948c2ecf20Sopenharmony_ci priv->port_num, 1958c2ecf20Sopenharmony_ci priv->pkey_index, 1968c2ecf20Sopenharmony_ci &priv->pkey); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int hfi1_ipoib_setup_rn(struct ib_device *device, 2008c2ecf20Sopenharmony_ci u8 port_num, 2018c2ecf20Sopenharmony_ci struct net_device *netdev, 2028c2ecf20Sopenharmony_ci void *param) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = dd_from_ibdev(device); 2058c2ecf20Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(netdev); 2068c2ecf20Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv; 2078c2ecf20Sopenharmony_ci int rc; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci rn->send = hfi1_ipoib_send; 2108c2ecf20Sopenharmony_ci rn->attach_mcast = hfi1_ipoib_mcast_attach; 2118c2ecf20Sopenharmony_ci rn->detach_mcast = hfi1_ipoib_mcast_detach; 2128c2ecf20Sopenharmony_ci rn->set_id = hfi1_ipoib_set_id; 2138c2ecf20Sopenharmony_ci rn->hca = device; 2148c2ecf20Sopenharmony_ci rn->port_num = port_num; 2158c2ecf20Sopenharmony_ci rn->mtu = netdev->mtu; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci priv = hfi1_ipoib_priv(netdev); 2188c2ecf20Sopenharmony_ci priv->dd = dd; 2198c2ecf20Sopenharmony_ci priv->netdev = netdev; 2208c2ecf20Sopenharmony_ci priv->device = device; 2218c2ecf20Sopenharmony_ci priv->port_num = port_num; 2228c2ecf20Sopenharmony_ci priv->netdev_ops = netdev->netdev_ops; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci ib_query_pkey(device, port_num, priv->pkey_index, &priv->pkey); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci rc = hfi1_ipoib_txreq_init(priv); 2278c2ecf20Sopenharmony_ci if (rc) { 2288c2ecf20Sopenharmony_ci dd_dev_err(dd, "IPoIB netdev TX init - failed(%d)\n", rc); 2298c2ecf20Sopenharmony_ci return rc; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci rc = hfi1_ipoib_rxq_init(netdev); 2338c2ecf20Sopenharmony_ci if (rc) { 2348c2ecf20Sopenharmony_ci dd_dev_err(dd, "IPoIB netdev RX init - failed(%d)\n", rc); 2358c2ecf20Sopenharmony_ci hfi1_ipoib_txreq_deinit(priv); 2368c2ecf20Sopenharmony_ci return rc; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci netdev->netdev_ops = &hfi1_ipoib_netdev_ops; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci netdev->priv_destructor = hfi1_ipoib_netdev_dtor; 2428c2ecf20Sopenharmony_ci netdev->needs_free_netdev = true; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ciint hfi1_ipoib_rn_get_params(struct ib_device *device, 2488c2ecf20Sopenharmony_ci u8 port_num, 2498c2ecf20Sopenharmony_ci enum rdma_netdev_t type, 2508c2ecf20Sopenharmony_ci struct rdma_netdev_alloc_params *params) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = dd_from_ibdev(device); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (type != RDMA_NETDEV_IPOIB) 2558c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (!HFI1_CAP_IS_KSET(AIP) || !dd->num_netdev_contexts) 2588c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (!port_num || port_num > dd->num_pports) 2618c2ecf20Sopenharmony_ci return -EINVAL; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci params->sizeof_priv = sizeof(struct hfi1_ipoib_rdma_netdev); 2648c2ecf20Sopenharmony_ci params->txqs = dd->num_sdma; 2658c2ecf20Sopenharmony_ci params->rxqs = dd->num_netdev_contexts; 2668c2ecf20Sopenharmony_ci params->param = NULL; 2678c2ecf20Sopenharmony_ci params->initialize_rdma_netdev = hfi1_ipoib_setup_rn; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 271