123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
- /*
- * Copyright(c) 2020 Intel Corporation.
- *
- */
- /*
- * This file contains HFI1 support for ipoib functionality
- */
- #include "ipoib.h"
- #include "hfi.h"
- static u32 qpn_from_mac(const u8 *mac_arr)
- {
- return (u32)mac_arr[1] << 16 | mac_arr[2] << 8 | mac_arr[3];
- }
- static int hfi1_ipoib_dev_init(struct net_device *dev)
- {
- struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
- int ret;
- dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
- if (!dev->tstats)
- return -ENOMEM;
- ret = priv->netdev_ops->ndo_init(dev);
- if (ret)
- goto out_ret;
- ret = hfi1_netdev_add_data(priv->dd,
- qpn_from_mac(priv->netdev->dev_addr),
- dev);
- if (ret < 0) {
- priv->netdev_ops->ndo_uninit(dev);
- goto out_ret;
- }
- return 0;
- out_ret:
- free_percpu(dev->tstats);
- dev->tstats = NULL;
- return ret;
- }
- static void hfi1_ipoib_dev_uninit(struct net_device *dev)
- {
- struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
- free_percpu(dev->tstats);
- dev->tstats = NULL;
- hfi1_netdev_remove_data(priv->dd, qpn_from_mac(priv->netdev->dev_addr));
- priv->netdev_ops->ndo_uninit(dev);
- }
- static int hfi1_ipoib_dev_open(struct net_device *dev)
- {
- struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
- int ret;
- ret = priv->netdev_ops->ndo_open(dev);
- if (!ret) {
- struct hfi1_ibport *ibp = to_iport(priv->device,
- priv->port_num);
- struct rvt_qp *qp;
- u32 qpn = qpn_from_mac(priv->netdev->dev_addr);
- rcu_read_lock();
- qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn);
- if (!qp) {
- rcu_read_unlock();
- priv->netdev_ops->ndo_stop(dev);
- return -EINVAL;
- }
- rvt_get_qp(qp);
- priv->qp = qp;
- rcu_read_unlock();
- hfi1_netdev_enable_queues(priv->dd);
- hfi1_ipoib_napi_tx_enable(dev);
- }
- return ret;
- }
- static int hfi1_ipoib_dev_stop(struct net_device *dev)
- {
- struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
- if (!priv->qp)
- return 0;
- hfi1_ipoib_napi_tx_disable(dev);
- hfi1_netdev_disable_queues(priv->dd);
- rvt_put_qp(priv->qp);
- priv->qp = NULL;
- return priv->netdev_ops->ndo_stop(dev);
- }
- static const struct net_device_ops hfi1_ipoib_netdev_ops = {
- .ndo_init = hfi1_ipoib_dev_init,
- .ndo_uninit = hfi1_ipoib_dev_uninit,
- .ndo_open = hfi1_ipoib_dev_open,
- .ndo_stop = hfi1_ipoib_dev_stop,
- .ndo_get_stats64 = dev_get_tstats64,
- };
- static int hfi1_ipoib_mcast_attach(struct net_device *dev,
- struct ib_device *device,
- union ib_gid *mgid,
- u16 mlid,
- int set_qkey,
- u32 qkey)
- {
- struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
- u32 qpn = (u32)qpn_from_mac(priv->netdev->dev_addr);
- struct hfi1_ibport *ibp = to_iport(priv->device, priv->port_num);
- struct rvt_qp *qp;
- int ret = -EINVAL;
- rcu_read_lock();
- qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn);
- if (qp) {
- rvt_get_qp(qp);
- rcu_read_unlock();
- if (set_qkey)
- priv->qkey = qkey;
- /* attach QP to multicast group */
- ret = ib_attach_mcast(&qp->ibqp, mgid, mlid);
- rvt_put_qp(qp);
- } else {
- rcu_read_unlock();
- }
- return ret;
- }
- static int hfi1_ipoib_mcast_detach(struct net_device *dev,
- struct ib_device *device,
- union ib_gid *mgid,
- u16 mlid)
- {
- struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
- u32 qpn = (u32)qpn_from_mac(priv->netdev->dev_addr);
- struct hfi1_ibport *ibp = to_iport(priv->device, priv->port_num);
- struct rvt_qp *qp;
- int ret = -EINVAL;
- rcu_read_lock();
- qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn);
- if (qp) {
- rvt_get_qp(qp);
- rcu_read_unlock();
- ret = ib_detach_mcast(&qp->ibqp, mgid, mlid);
- rvt_put_qp(qp);
- } else {
- rcu_read_unlock();
- }
- return ret;
- }
- static void hfi1_ipoib_netdev_dtor(struct net_device *dev)
- {
- struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
- hfi1_ipoib_txreq_deinit(priv);
- hfi1_ipoib_rxq_deinit(priv->netdev);
- free_percpu(dev->tstats);
- dev->tstats = NULL;
- }
- static void hfi1_ipoib_set_id(struct net_device *dev, int id)
- {
- struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
- priv->pkey_index = (u16)id;
- ib_query_pkey(priv->device,
- priv->port_num,
- priv->pkey_index,
- &priv->pkey);
- }
- static int hfi1_ipoib_setup_rn(struct ib_device *device,
- u32 port_num,
- struct net_device *netdev,
- void *param)
- {
- struct hfi1_devdata *dd = dd_from_ibdev(device);
- struct rdma_netdev *rn = netdev_priv(netdev);
- struct hfi1_ipoib_dev_priv *priv;
- int rc;
- rn->send = hfi1_ipoib_send;
- rn->tx_timeout = hfi1_ipoib_tx_timeout;
- rn->attach_mcast = hfi1_ipoib_mcast_attach;
- rn->detach_mcast = hfi1_ipoib_mcast_detach;
- rn->set_id = hfi1_ipoib_set_id;
- rn->hca = device;
- rn->port_num = port_num;
- rn->mtu = netdev->mtu;
- priv = hfi1_ipoib_priv(netdev);
- priv->dd = dd;
- priv->netdev = netdev;
- priv->device = device;
- priv->port_num = port_num;
- priv->netdev_ops = netdev->netdev_ops;
- ib_query_pkey(device, port_num, priv->pkey_index, &priv->pkey);
- rc = hfi1_ipoib_txreq_init(priv);
- if (rc) {
- dd_dev_err(dd, "IPoIB netdev TX init - failed(%d)\n", rc);
- return rc;
- }
- rc = hfi1_ipoib_rxq_init(netdev);
- if (rc) {
- dd_dev_err(dd, "IPoIB netdev RX init - failed(%d)\n", rc);
- hfi1_ipoib_txreq_deinit(priv);
- return rc;
- }
- netdev->netdev_ops = &hfi1_ipoib_netdev_ops;
- netdev->priv_destructor = hfi1_ipoib_netdev_dtor;
- netdev->needs_free_netdev = true;
- return 0;
- }
- int hfi1_ipoib_rn_get_params(struct ib_device *device,
- u32 port_num,
- enum rdma_netdev_t type,
- struct rdma_netdev_alloc_params *params)
- {
- struct hfi1_devdata *dd = dd_from_ibdev(device);
- if (type != RDMA_NETDEV_IPOIB)
- return -EOPNOTSUPP;
- if (!HFI1_CAP_IS_KSET(AIP) || !dd->num_netdev_contexts)
- return -EOPNOTSUPP;
- if (!port_num || port_num > dd->num_pports)
- return -EINVAL;
- params->sizeof_priv = sizeof(struct hfi1_ipoib_rdma_netdev);
- params->txqs = dd->num_sdma;
- params->rxqs = dd->num_netdev_contexts;
- params->param = NULL;
- params->initialize_rdma_netdev = hfi1_ipoib_setup_rn;
- return 0;
- }
|