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
101	netdev_stats_to_stats64(storage, &dev->stats);
102	dev_fetch_sw_netstats(storage, priv->netstats);
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  = hfi1_ipoib_dev_get_stats64,
111};
112
113static int hfi1_ipoib_send(struct net_device *dev,
114			   struct sk_buff *skb,
115			   struct ib_ah *address,
116			   u32 dqpn)
117{
118	return hfi1_ipoib_send_dma(dev, skb, address, dqpn);
119}
120
121static int hfi1_ipoib_mcast_attach(struct net_device *dev,
122				   struct ib_device *device,
123				   union ib_gid *mgid,
124				   u16 mlid,
125				   int set_qkey,
126				   u32 qkey)
127{
128	struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
129	u32 qpn = (u32)qpn_from_mac(priv->netdev->dev_addr);
130	struct hfi1_ibport *ibp = to_iport(priv->device, priv->port_num);
131	struct rvt_qp *qp;
132	int ret = -EINVAL;
133
134	rcu_read_lock();
135
136	qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn);
137	if (qp) {
138		rvt_get_qp(qp);
139		rcu_read_unlock();
140		if (set_qkey)
141			priv->qkey = qkey;
142
143		/* attach QP to multicast group */
144		ret = ib_attach_mcast(&qp->ibqp, mgid, mlid);
145		rvt_put_qp(qp);
146	} else {
147		rcu_read_unlock();
148	}
149
150	return ret;
151}
152
153static int hfi1_ipoib_mcast_detach(struct net_device *dev,
154				   struct ib_device *device,
155				   union ib_gid *mgid,
156				   u16 mlid)
157{
158	struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
159	u32 qpn = (u32)qpn_from_mac(priv->netdev->dev_addr);
160	struct hfi1_ibport *ibp = to_iport(priv->device, priv->port_num);
161	struct rvt_qp *qp;
162	int ret = -EINVAL;
163
164	rcu_read_lock();
165
166	qp = rvt_lookup_qpn(ib_to_rvt(priv->device), &ibp->rvp, qpn);
167	if (qp) {
168		rvt_get_qp(qp);
169		rcu_read_unlock();
170		ret = ib_detach_mcast(&qp->ibqp, mgid, mlid);
171		rvt_put_qp(qp);
172	} else {
173		rcu_read_unlock();
174	}
175	return ret;
176}
177
178static void hfi1_ipoib_netdev_dtor(struct net_device *dev)
179{
180	struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
181
182	hfi1_ipoib_txreq_deinit(priv);
183	hfi1_ipoib_rxq_deinit(priv->netdev);
184
185	free_percpu(priv->netstats);
186}
187
188static void hfi1_ipoib_set_id(struct net_device *dev, int id)
189{
190	struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
191
192	priv->pkey_index = (u16)id;
193	ib_query_pkey(priv->device,
194		      priv->port_num,
195		      priv->pkey_index,
196		      &priv->pkey);
197}
198
199static int hfi1_ipoib_setup_rn(struct ib_device *device,
200			       u8 port_num,
201			       struct net_device *netdev,
202			       void *param)
203{
204	struct hfi1_devdata *dd = dd_from_ibdev(device);
205	struct rdma_netdev *rn = netdev_priv(netdev);
206	struct hfi1_ipoib_dev_priv *priv;
207	int rc;
208
209	rn->send = hfi1_ipoib_send;
210	rn->attach_mcast = hfi1_ipoib_mcast_attach;
211	rn->detach_mcast = hfi1_ipoib_mcast_detach;
212	rn->set_id = hfi1_ipoib_set_id;
213	rn->hca = device;
214	rn->port_num = port_num;
215	rn->mtu = netdev->mtu;
216
217	priv = hfi1_ipoib_priv(netdev);
218	priv->dd = dd;
219	priv->netdev = netdev;
220	priv->device = device;
221	priv->port_num = port_num;
222	priv->netdev_ops = netdev->netdev_ops;
223
224	ib_query_pkey(device, port_num, priv->pkey_index, &priv->pkey);
225
226	rc = hfi1_ipoib_txreq_init(priv);
227	if (rc) {
228		dd_dev_err(dd, "IPoIB netdev TX init - failed(%d)\n", rc);
229		return rc;
230	}
231
232	rc = hfi1_ipoib_rxq_init(netdev);
233	if (rc) {
234		dd_dev_err(dd, "IPoIB netdev RX init - failed(%d)\n", rc);
235		hfi1_ipoib_txreq_deinit(priv);
236		return rc;
237	}
238
239	netdev->netdev_ops = &hfi1_ipoib_netdev_ops;
240
241	netdev->priv_destructor = hfi1_ipoib_netdev_dtor;
242	netdev->needs_free_netdev = true;
243
244	return 0;
245}
246
247int hfi1_ipoib_rn_get_params(struct ib_device *device,
248			     u8 port_num,
249			     enum rdma_netdev_t type,
250			     struct rdma_netdev_alloc_params *params)
251{
252	struct hfi1_devdata *dd = dd_from_ibdev(device);
253
254	if (type != RDMA_NETDEV_IPOIB)
255		return -EOPNOTSUPP;
256
257	if (!HFI1_CAP_IS_KSET(AIP) || !dd->num_netdev_contexts)
258		return -EOPNOTSUPP;
259
260	if (!port_num || port_num > dd->num_pports)
261		return -EINVAL;
262
263	params->sizeof_priv = sizeof(struct hfi1_ipoib_rdma_netdev);
264	params->txqs = dd->num_sdma;
265	params->rxqs = dd->num_netdev_contexts;
266	params->param = NULL;
267	params->initialize_rdma_netdev = hfi1_ipoib_setup_rn;
268
269	return 0;
270}
271