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