Linux Audio

Check our new training course

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