linux/drivers/infiniband/hw/hfi1/ipoib_main.c
<<
>>
Prefs
   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(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        priv->netstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
  25
  26        ret = priv->netdev_ops->ndo_init(dev);
  27        if (ret)
  28                return ret;
  29
  30        ret = hfi1_netdev_add_data(priv->dd,
  31                                   qpn_from_mac(priv->netdev->dev_addr),
  32                                   dev);
  33        if (ret < 0) {
  34                priv->netdev_ops->ndo_uninit(dev);
  35                return ret;
  36        }
  37
  38        return 0;
  39}
  40
  41static void hfi1_ipoib_dev_uninit(struct net_device *dev)
  42{
  43        struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
  44
  45        hfi1_netdev_remove_data(priv->dd, qpn_from_mac(priv->netdev->dev_addr));
  46
  47        priv->netdev_ops->ndo_uninit(dev);
  48}
  49
  50static int hfi1_ipoib_dev_open(struct net_device *dev)
  51{
  52        struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
  53        int ret;
  54
  55        ret = priv->netdev_ops->ndo_open(dev);
  56        if (!ret) {
  57                struct hfi1_ibport *ibp = to_iport(priv->device,
  58                                                   priv->port_num);
  59                struct rvt_qp *qp;
  60                u32 qpn = qpn_from_mac(priv->netdev->dev_addr);
  61
  62                rcu_read_lock();
  63                qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn);
  64                if (!qp) {
  65                        rcu_read_unlock();
  66                        priv->netdev_ops->ndo_stop(dev);
  67                        return -EINVAL;
  68                }
  69                rvt_get_qp(qp);
  70                priv->qp = qp;
  71                rcu_read_unlock();
  72
  73                hfi1_netdev_enable_queues(priv->dd);
  74                hfi1_ipoib_napi_tx_enable(dev);
  75        }
  76
  77        return ret;
  78}
  79
  80static int hfi1_ipoib_dev_stop(struct net_device *dev)
  81{
  82        struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
  83
  84        if (!priv->qp)
  85                return 0;
  86
  87        hfi1_ipoib_napi_tx_disable(dev);
  88        hfi1_netdev_disable_queues(priv->dd);
  89
  90        rvt_put_qp(priv->qp);
  91        priv->qp = NULL;
  92
  93        return priv->netdev_ops->ndo_stop(dev);
  94}
  95
  96static void hfi1_ipoib_dev_get_stats64(struct net_device *dev,
  97                                       struct rtnl_link_stats64 *storage)
  98{
  99        struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
 100        u64 rx_packets = 0ull;
 101        u64 rx_bytes = 0ull;
 102        u64 tx_packets = 0ull;
 103        u64 tx_bytes = 0ull;
 104        int i;
 105
 106        netdev_stats_to_stats64(storage, &dev->stats);
 107
 108        for_each_possible_cpu(i) {
 109                const struct pcpu_sw_netstats *stats;
 110                unsigned int start;
 111                u64 trx_packets;
 112                u64 trx_bytes;
 113                u64 ttx_packets;
 114                u64 ttx_bytes;
 115
 116                stats = per_cpu_ptr(priv->netstats, i);
 117                do {
 118                        start = u64_stats_fetch_begin_irq(&stats->syncp);
 119                        trx_packets = stats->rx_packets;
 120                        trx_bytes = stats->rx_bytes;
 121                        ttx_packets = stats->tx_packets;
 122                        ttx_bytes = stats->tx_bytes;
 123                } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
 124
 125                rx_packets += trx_packets;
 126                rx_bytes += trx_bytes;
 127                tx_packets += ttx_packets;
 128                tx_bytes += ttx_bytes;
 129        }
 130
 131        storage->rx_packets += rx_packets;
 132        storage->rx_bytes += rx_bytes;
 133        storage->tx_packets += tx_packets;
 134        storage->tx_bytes += tx_bytes;
 135}
 136
 137static const struct net_device_ops hfi1_ipoib_netdev_ops = {
 138        .ndo_init         = hfi1_ipoib_dev_init,
 139        .ndo_uninit       = hfi1_ipoib_dev_uninit,
 140        .ndo_open         = hfi1_ipoib_dev_open,
 141        .ndo_stop         = hfi1_ipoib_dev_stop,
 142        .ndo_get_stats64  = hfi1_ipoib_dev_get_stats64,
 143};
 144
 145static int hfi1_ipoib_send(struct net_device *dev,
 146                           struct sk_buff *skb,
 147                           struct ib_ah *address,
 148                           u32 dqpn)
 149{
 150        return hfi1_ipoib_send_dma(dev, skb, address, dqpn);
 151}
 152
 153static int hfi1_ipoib_mcast_attach(struct net_device *dev,
 154                                   struct ib_device *device,
 155                                   union ib_gid *mgid,
 156                                   u16 mlid,
 157                                   int set_qkey,
 158                                   u32 qkey)
 159{
 160        struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
 161        u32 qpn = (u32)qpn_from_mac(priv->netdev->dev_addr);
 162        struct hfi1_ibport *ibp = to_iport(priv->device, priv->port_num);
 163        struct rvt_qp *qp;
 164        int ret = -EINVAL;
 165
 166        rcu_read_lock();
 167
 168        qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn);
 169        if (qp) {
 170                rvt_get_qp(qp);
 171                rcu_read_unlock();
 172                if (set_qkey)
 173                        priv->qkey = qkey;
 174
 175                /* attach QP to multicast group */
 176                ret = ib_attach_mcast(&qp->ibqp, mgid, mlid);
 177                rvt_put_qp(qp);
 178        } else {
 179                rcu_read_unlock();
 180        }
 181
 182        return ret;
 183}
 184
 185static int hfi1_ipoib_mcast_detach(struct net_device *dev,
 186                                   struct ib_device *device,
 187                                   union ib_gid *mgid,
 188                                   u16 mlid)
 189{
 190        struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
 191        u32 qpn = (u32)qpn_from_mac(priv->netdev->dev_addr);
 192        struct hfi1_ibport *ibp = to_iport(priv->device, priv->port_num);
 193        struct rvt_qp *qp;
 194        int ret = -EINVAL;
 195
 196        rcu_read_lock();
 197
 198        qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn);
 199        if (qp) {
 200                rvt_get_qp(qp);
 201                rcu_read_unlock();
 202                ret = ib_detach_mcast(&qp->ibqp, mgid, mlid);
 203                rvt_put_qp(qp);
 204        } else {
 205                rcu_read_unlock();
 206        }
 207        return ret;
 208}
 209
 210static void hfi1_ipoib_netdev_dtor(struct net_device *dev)
 211{
 212        struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
 213
 214        hfi1_ipoib_txreq_deinit(priv);
 215        hfi1_ipoib_rxq_deinit(priv->netdev);
 216
 217        free_percpu(priv->netstats);
 218}
 219
 220static void hfi1_ipoib_free_rdma_netdev(struct net_device *dev)
 221{
 222        hfi1_ipoib_netdev_dtor(dev);
 223        free_netdev(dev);
 224}
 225
 226static void hfi1_ipoib_set_id(struct net_device *dev, int id)
 227{
 228        struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
 229
 230        priv->pkey_index = (u16)id;
 231        ib_query_pkey(priv->device,
 232                      priv->port_num,
 233                      priv->pkey_index,
 234                      &priv->pkey);
 235}
 236
 237static int hfi1_ipoib_setup_rn(struct ib_device *device,
 238                               u8 port_num,
 239                               struct net_device *netdev,
 240                               void *param)
 241{
 242        struct hfi1_devdata *dd = dd_from_ibdev(device);
 243        struct rdma_netdev *rn = netdev_priv(netdev);
 244        struct hfi1_ipoib_dev_priv *priv;
 245        int rc;
 246
 247        rn->send = hfi1_ipoib_send;
 248        rn->attach_mcast = hfi1_ipoib_mcast_attach;
 249        rn->detach_mcast = hfi1_ipoib_mcast_detach;
 250        rn->set_id = hfi1_ipoib_set_id;
 251        rn->hca = device;
 252        rn->port_num = port_num;
 253        rn->mtu = netdev->mtu;
 254
 255        priv = hfi1_ipoib_priv(netdev);
 256        priv->dd = dd;
 257        priv->netdev = netdev;
 258        priv->device = device;
 259        priv->port_num = port_num;
 260        priv->netdev_ops = netdev->netdev_ops;
 261
 262        netdev->netdev_ops = &hfi1_ipoib_netdev_ops;
 263
 264        ib_query_pkey(device, port_num, priv->pkey_index, &priv->pkey);
 265
 266        rc = hfi1_ipoib_txreq_init(priv);
 267        if (rc) {
 268                dd_dev_err(dd, "IPoIB netdev TX init - failed(%d)\n", rc);
 269                hfi1_ipoib_free_rdma_netdev(netdev);
 270                return rc;
 271        }
 272
 273        rc = hfi1_ipoib_rxq_init(netdev);
 274        if (rc) {
 275                dd_dev_err(dd, "IPoIB netdev RX init - failed(%d)\n", rc);
 276                hfi1_ipoib_free_rdma_netdev(netdev);
 277                return rc;
 278        }
 279
 280        netdev->priv_destructor = hfi1_ipoib_netdev_dtor;
 281        netdev->needs_free_netdev = true;
 282
 283        return 0;
 284}
 285
 286int hfi1_ipoib_rn_get_params(struct ib_device *device,
 287                             u8 port_num,
 288                             enum rdma_netdev_t type,
 289                             struct rdma_netdev_alloc_params *params)
 290{
 291        struct hfi1_devdata *dd = dd_from_ibdev(device);
 292
 293        if (type != RDMA_NETDEV_IPOIB)
 294                return -EOPNOTSUPP;
 295
 296        if (!HFI1_CAP_IS_KSET(AIP) || !dd->num_netdev_contexts)
 297                return -EOPNOTSUPP;
 298
 299        if (!port_num || port_num > dd->num_pports)
 300                return -EINVAL;
 301
 302        params->sizeof_priv = sizeof(struct hfi1_ipoib_rdma_netdev);
 303        params->txqs = dd->num_sdma;
 304        params->rxqs = dd->num_netdev_contexts;
 305        params->param = NULL;
 306        params->initialize_rdma_netdev = hfi1_ipoib_setup_rn;
 307
 308        return 0;
 309}
 310