ipoib_main.c (6054B)
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2/* 3 * Copyright(c) 2020 Intel Corporation. 4 * 5 */ 6 7/* 8 * This file contains HFI1 support for ipoib functionality 9 */ 10 11#include "ipoib.h" 12#include "hfi.h" 13 14static u32 qpn_from_mac(const u8 *mac_arr) 15{ 16 return (u32)mac_arr[1] << 16 | mac_arr[2] << 8 | mac_arr[3]; 17} 18 19static int hfi1_ipoib_dev_init(struct net_device *dev) 20{ 21 struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 22 int ret; 23 24 dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 25 if (!dev->tstats) 26 return -ENOMEM; 27 28 ret = priv->netdev_ops->ndo_init(dev); 29 if (ret) 30 goto out_ret; 31 32 ret = hfi1_netdev_add_data(priv->dd, 33 qpn_from_mac(priv->netdev->dev_addr), 34 dev); 35 if (ret < 0) { 36 priv->netdev_ops->ndo_uninit(dev); 37 goto out_ret; 38 } 39 40 return 0; 41out_ret: 42 free_percpu(dev->tstats); 43 dev->tstats = NULL; 44 return ret; 45} 46 47static void hfi1_ipoib_dev_uninit(struct net_device *dev) 48{ 49 struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 50 51 free_percpu(dev->tstats); 52 dev->tstats = NULL; 53 54 hfi1_netdev_remove_data(priv->dd, qpn_from_mac(priv->netdev->dev_addr)); 55 56 priv->netdev_ops->ndo_uninit(dev); 57} 58 59static int hfi1_ipoib_dev_open(struct net_device *dev) 60{ 61 struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 62 int ret; 63 64 ret = priv->netdev_ops->ndo_open(dev); 65 if (!ret) { 66 struct hfi1_ibport *ibp = to_iport(priv->device, 67 priv->port_num); 68 struct rvt_qp *qp; 69 u32 qpn = qpn_from_mac(priv->netdev->dev_addr); 70 71 rcu_read_lock(); 72 qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn); 73 if (!qp) { 74 rcu_read_unlock(); 75 priv->netdev_ops->ndo_stop(dev); 76 return -EINVAL; 77 } 78 rvt_get_qp(qp); 79 priv->qp = qp; 80 rcu_read_unlock(); 81 82 hfi1_netdev_enable_queues(priv->dd); 83 hfi1_ipoib_napi_tx_enable(dev); 84 } 85 86 return ret; 87} 88 89static int hfi1_ipoib_dev_stop(struct net_device *dev) 90{ 91 struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 92 93 if (!priv->qp) 94 return 0; 95 96 hfi1_ipoib_napi_tx_disable(dev); 97 hfi1_netdev_disable_queues(priv->dd); 98 99 rvt_put_qp(priv->qp); 100 priv->qp = NULL; 101 102 return priv->netdev_ops->ndo_stop(dev); 103} 104 105static const struct net_device_ops hfi1_ipoib_netdev_ops = { 106 .ndo_init = hfi1_ipoib_dev_init, 107 .ndo_uninit = hfi1_ipoib_dev_uninit, 108 .ndo_open = hfi1_ipoib_dev_open, 109 .ndo_stop = hfi1_ipoib_dev_stop, 110 .ndo_get_stats64 = dev_get_tstats64, 111}; 112 113static int hfi1_ipoib_mcast_attach(struct net_device *dev, 114 struct ib_device *device, 115 union ib_gid *mgid, 116 u16 mlid, 117 int set_qkey, 118 u32 qkey) 119{ 120 struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 121 u32 qpn = (u32)qpn_from_mac(priv->netdev->dev_addr); 122 struct hfi1_ibport *ibp = to_iport(priv->device, priv->port_num); 123 struct rvt_qp *qp; 124 int ret = -EINVAL; 125 126 rcu_read_lock(); 127 128 qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn); 129 if (qp) { 130 rvt_get_qp(qp); 131 rcu_read_unlock(); 132 if (set_qkey) 133 priv->qkey = qkey; 134 135 /* attach QP to multicast group */ 136 ret = ib_attach_mcast(&qp->ibqp, mgid, mlid); 137 rvt_put_qp(qp); 138 } else { 139 rcu_read_unlock(); 140 } 141 142 return ret; 143} 144 145static int hfi1_ipoib_mcast_detach(struct net_device *dev, 146 struct ib_device *device, 147 union ib_gid *mgid, 148 u16 mlid) 149{ 150 struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 151 u32 qpn = (u32)qpn_from_mac(priv->netdev->dev_addr); 152 struct hfi1_ibport *ibp = to_iport(priv->device, priv->port_num); 153 struct rvt_qp *qp; 154 int ret = -EINVAL; 155 156 rcu_read_lock(); 157 158 qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn); 159 if (qp) { 160 rvt_get_qp(qp); 161 rcu_read_unlock(); 162 ret = ib_detach_mcast(&qp->ibqp, mgid, mlid); 163 rvt_put_qp(qp); 164 } else { 165 rcu_read_unlock(); 166 } 167 return ret; 168} 169 170static void hfi1_ipoib_netdev_dtor(struct net_device *dev) 171{ 172 struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 173 174 hfi1_ipoib_txreq_deinit(priv); 175 hfi1_ipoib_rxq_deinit(priv->netdev); 176 177 free_percpu(dev->tstats); 178 dev->tstats = NULL; 179} 180 181static void hfi1_ipoib_set_id(struct net_device *dev, int id) 182{ 183 struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev); 184 185 priv->pkey_index = (u16)id; 186 ib_query_pkey(priv->device, 187 priv->port_num, 188 priv->pkey_index, 189 &priv->pkey); 190} 191 192static int hfi1_ipoib_setup_rn(struct ib_device *device, 193 u32 port_num, 194 struct net_device *netdev, 195 void *param) 196{ 197 struct hfi1_devdata *dd = dd_from_ibdev(device); 198 struct rdma_netdev *rn = netdev_priv(netdev); 199 struct hfi1_ipoib_dev_priv *priv; 200 int rc; 201 202 rn->send = hfi1_ipoib_send; 203 rn->tx_timeout = hfi1_ipoib_tx_timeout; 204 rn->attach_mcast = hfi1_ipoib_mcast_attach; 205 rn->detach_mcast = hfi1_ipoib_mcast_detach; 206 rn->set_id = hfi1_ipoib_set_id; 207 rn->hca = device; 208 rn->port_num = port_num; 209 rn->mtu = netdev->mtu; 210 211 priv = hfi1_ipoib_priv(netdev); 212 priv->dd = dd; 213 priv->netdev = netdev; 214 priv->device = device; 215 priv->port_num = port_num; 216 priv->netdev_ops = netdev->netdev_ops; 217 218 ib_query_pkey(device, port_num, priv->pkey_index, &priv->pkey); 219 220 rc = hfi1_ipoib_txreq_init(priv); 221 if (rc) { 222 dd_dev_err(dd, "IPoIB netdev TX init - failed(%d)\n", rc); 223 return rc; 224 } 225 226 rc = hfi1_ipoib_rxq_init(netdev); 227 if (rc) { 228 dd_dev_err(dd, "IPoIB netdev RX init - failed(%d)\n", rc); 229 hfi1_ipoib_txreq_deinit(priv); 230 return rc; 231 } 232 233 netdev->netdev_ops = &hfi1_ipoib_netdev_ops; 234 235 netdev->priv_destructor = hfi1_ipoib_netdev_dtor; 236 netdev->needs_free_netdev = true; 237 238 return 0; 239} 240 241int hfi1_ipoib_rn_get_params(struct ib_device *device, 242 u32 port_num, 243 enum rdma_netdev_t type, 244 struct rdma_netdev_alloc_params *params) 245{ 246 struct hfi1_devdata *dd = dd_from_ibdev(device); 247 248 if (type != RDMA_NETDEV_IPOIB) 249 return -EOPNOTSUPP; 250 251 if (!HFI1_CAP_IS_KSET(AIP) || !dd->num_netdev_contexts) 252 return -EOPNOTSUPP; 253 254 if (!port_num || port_num > dd->num_pports) 255 return -EINVAL; 256 257 params->sizeof_priv = sizeof(struct hfi1_ipoib_rdma_netdev); 258 params->txqs = dd->num_sdma; 259 params->rxqs = dd->num_netdev_contexts; 260 params->param = NULL; 261 params->initialize_rdma_netdev = hfi1_ipoib_setup_rn; 262 263 return 0; 264}