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