xref: /openbmc/linux/drivers/net/ntb_netdev.c (revision ee1cd5048959de496cd005c50b137212a5b62062)
1548c237cSJon Mason /*
2548c237cSJon Mason  * This file is provided under a dual BSD/GPLv2 license.  When using or
3548c237cSJon Mason  *   redistributing this file, you may do so under either license.
4548c237cSJon Mason  *
5548c237cSJon Mason  *   GPL LICENSE SUMMARY
6548c237cSJon Mason  *
7548c237cSJon Mason  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
8e26a5843SAllen Hubbe  *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
9548c237cSJon Mason  *
10548c237cSJon Mason  *   This program is free software; you can redistribute it and/or modify
11548c237cSJon Mason  *   it under the terms of version 2 of the GNU General Public License as
12548c237cSJon Mason  *   published by the Free Software Foundation.
13548c237cSJon Mason  *
14548c237cSJon Mason  *   BSD LICENSE
15548c237cSJon Mason  *
16548c237cSJon Mason  *   Copyright(c) 2012 Intel Corporation. All rights reserved.
17e26a5843SAllen Hubbe  *   Copyright (C) 2015 EMC Corporation. All Rights Reserved.
18548c237cSJon Mason  *
19548c237cSJon Mason  *   Redistribution and use in source and binary forms, with or without
20548c237cSJon Mason  *   modification, are permitted provided that the following conditions
21548c237cSJon Mason  *   are met:
22548c237cSJon Mason  *
23548c237cSJon Mason  *     * Redistributions of source code must retain the above copyright
24548c237cSJon Mason  *       notice, this list of conditions and the following disclaimer.
25548c237cSJon Mason  *     * Redistributions in binary form must reproduce the above copy
26548c237cSJon Mason  *       notice, this list of conditions and the following disclaimer in
27548c237cSJon Mason  *       the documentation and/or other materials provided with the
28548c237cSJon Mason  *       distribution.
29548c237cSJon Mason  *     * Neither the name of Intel Corporation nor the names of its
30548c237cSJon Mason  *       contributors may be used to endorse or promote products derived
31548c237cSJon Mason  *       from this software without specific prior written permission.
32548c237cSJon Mason  *
33548c237cSJon Mason  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
34548c237cSJon Mason  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
35548c237cSJon Mason  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
36548c237cSJon Mason  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
37548c237cSJon Mason  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38548c237cSJon Mason  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39548c237cSJon Mason  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
40548c237cSJon Mason  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
41548c237cSJon Mason  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42548c237cSJon Mason  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
43548c237cSJon Mason  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44548c237cSJon Mason  *
45e26a5843SAllen Hubbe  * PCIe NTB Network Linux driver
46548c237cSJon Mason  *
47548c237cSJon Mason  * Contact Information:
48548c237cSJon Mason  * Jon Mason <jon.mason@intel.com>
49548c237cSJon Mason  */
50548c237cSJon Mason #include <linux/etherdevice.h>
51548c237cSJon Mason #include <linux/ethtool.h>
52548c237cSJon Mason #include <linux/module.h>
53548c237cSJon Mason #include <linux/pci.h>
54e26a5843SAllen Hubbe #include <linux/ntb.h>
55ec110bc7SAllen Hubbe #include <linux/ntb_transport.h>
56548c237cSJon Mason 
5724208bbeSJon Mason #define NTB_NETDEV_VER	"0.7"
58548c237cSJon Mason 
59548c237cSJon Mason MODULE_DESCRIPTION(KBUILD_MODNAME);
60548c237cSJon Mason MODULE_VERSION(NTB_NETDEV_VER);
61548c237cSJon Mason MODULE_LICENSE("Dual BSD/GPL");
62548c237cSJon Mason MODULE_AUTHOR("Intel Corporation");
63548c237cSJon Mason 
64e74bfeedSDave Jiang /* Time in usecs for tx resource reaper */
65e74bfeedSDave Jiang static unsigned int tx_time = 1;
66e74bfeedSDave Jiang 
67e74bfeedSDave Jiang /* Number of descriptors to free before resuming tx */
68e74bfeedSDave Jiang static unsigned int tx_start = 10;
69e74bfeedSDave Jiang 
70e74bfeedSDave Jiang /* Number of descriptors still available before stop upper layer tx */
71e74bfeedSDave Jiang static unsigned int tx_stop = 5;
72e74bfeedSDave Jiang 
73548c237cSJon Mason struct ntb_netdev {
74548c237cSJon Mason 	struct pci_dev *pdev;
75548c237cSJon Mason 	struct net_device *ndev;
76548c237cSJon Mason 	struct ntb_transport_qp *qp;
77e74bfeedSDave Jiang 	struct timer_list tx_timer;
78548c237cSJon Mason };
79548c237cSJon Mason 
80548c237cSJon Mason #define	NTB_TX_TIMEOUT_MS	1000
81548c237cSJon Mason #define	NTB_RXQ_SIZE		100
82548c237cSJon Mason 
ntb_netdev_event_handler(void * data,int link_is_up)83e26a5843SAllen Hubbe static void ntb_netdev_event_handler(void *data, int link_is_up)
84548c237cSJon Mason {
85548c237cSJon Mason 	struct net_device *ndev = data;
86548c237cSJon Mason 	struct ntb_netdev *dev = netdev_priv(ndev);
87548c237cSJon Mason 
88e26a5843SAllen Hubbe 	netdev_dbg(ndev, "Event %x, Link %x\n", link_is_up,
89548c237cSJon Mason 		   ntb_transport_link_query(dev->qp));
90548c237cSJon Mason 
91e26a5843SAllen Hubbe 	if (link_is_up) {
92e26a5843SAllen Hubbe 		if (ntb_transport_link_query(dev->qp))
93403c63cbSJon Mason 			netif_carrier_on(ndev);
94e26a5843SAllen Hubbe 	} else {
95e26a5843SAllen Hubbe 		netif_carrier_off(ndev);
96403c63cbSJon Mason 	}
97548c237cSJon Mason }
98548c237cSJon Mason 
ntb_netdev_rx_handler(struct ntb_transport_qp * qp,void * qp_data,void * data,int len)99548c237cSJon Mason static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
100548c237cSJon Mason 				  void *data, int len)
101548c237cSJon Mason {
102548c237cSJon Mason 	struct net_device *ndev = qp_data;
103548c237cSJon Mason 	struct sk_buff *skb;
104548c237cSJon Mason 	int rc;
105548c237cSJon Mason 
106548c237cSJon Mason 	skb = data;
107548c237cSJon Mason 	if (!skb)
108548c237cSJon Mason 		return;
109548c237cSJon Mason 
110548c237cSJon Mason 	netdev_dbg(ndev, "%s: %d byte payload received\n", __func__, len);
111548c237cSJon Mason 
112da2e5ae5SAllen Hubbe 	if (len < 0) {
113da2e5ae5SAllen Hubbe 		ndev->stats.rx_errors++;
114da2e5ae5SAllen Hubbe 		ndev->stats.rx_length_errors++;
115da2e5ae5SAllen Hubbe 		goto enqueue_again;
116da2e5ae5SAllen Hubbe 	}
117da2e5ae5SAllen Hubbe 
118548c237cSJon Mason 	skb_put(skb, len);
119548c237cSJon Mason 	skb->protocol = eth_type_trans(skb, ndev);
120548c237cSJon Mason 	skb->ip_summed = CHECKSUM_NONE;
121548c237cSJon Mason 
122*e3af5b14SDave Jiang 	if (netif_rx(skb) == NET_RX_DROP) {
123548c237cSJon Mason 		ndev->stats.rx_errors++;
124548c237cSJon Mason 		ndev->stats.rx_dropped++;
125548c237cSJon Mason 	} else {
126548c237cSJon Mason 		ndev->stats.rx_packets++;
127548c237cSJon Mason 		ndev->stats.rx_bytes += len;
128548c237cSJon Mason 	}
129548c237cSJon Mason 
130548c237cSJon Mason 	skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
131548c237cSJon Mason 	if (!skb) {
132548c237cSJon Mason 		ndev->stats.rx_errors++;
133548c237cSJon Mason 		ndev->stats.rx_frame_errors++;
134548c237cSJon Mason 		return;
135548c237cSJon Mason 	}
136548c237cSJon Mason 
137da2e5ae5SAllen Hubbe enqueue_again:
138548c237cSJon Mason 	rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);
139548c237cSJon Mason 	if (rc) {
1405f7d78b2SEric Pilmore 		dev_kfree_skb_any(skb);
141548c237cSJon Mason 		ndev->stats.rx_errors++;
142548c237cSJon Mason 		ndev->stats.rx_fifo_errors++;
143548c237cSJon Mason 	}
144548c237cSJon Mason }
145548c237cSJon Mason 
__ntb_netdev_maybe_stop_tx(struct net_device * netdev,struct ntb_transport_qp * qp,int size)146e74bfeedSDave Jiang static int __ntb_netdev_maybe_stop_tx(struct net_device *netdev,
147e74bfeedSDave Jiang 				      struct ntb_transport_qp *qp, int size)
148e74bfeedSDave Jiang {
149e74bfeedSDave Jiang 	struct ntb_netdev *dev = netdev_priv(netdev);
150e74bfeedSDave Jiang 
151e74bfeedSDave Jiang 	netif_stop_queue(netdev);
152e74bfeedSDave Jiang 	/* Make sure to see the latest value of ntb_transport_tx_free_entry()
153e74bfeedSDave Jiang 	 * since the queue was last started.
154e74bfeedSDave Jiang 	 */
155e74bfeedSDave Jiang 	smp_mb();
156e74bfeedSDave Jiang 
157e74bfeedSDave Jiang 	if (likely(ntb_transport_tx_free_entry(qp) < size)) {
158e74bfeedSDave Jiang 		mod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time));
159e74bfeedSDave Jiang 		return -EBUSY;
160e74bfeedSDave Jiang 	}
161e74bfeedSDave Jiang 
162e74bfeedSDave Jiang 	netif_start_queue(netdev);
163e74bfeedSDave Jiang 	return 0;
164e74bfeedSDave Jiang }
165e74bfeedSDave Jiang 
ntb_netdev_maybe_stop_tx(struct net_device * ndev,struct ntb_transport_qp * qp,int size)166e74bfeedSDave Jiang static int ntb_netdev_maybe_stop_tx(struct net_device *ndev,
167e74bfeedSDave Jiang 				    struct ntb_transport_qp *qp, int size)
168e74bfeedSDave Jiang {
169e74bfeedSDave Jiang 	if (netif_queue_stopped(ndev) ||
170e74bfeedSDave Jiang 	    (ntb_transport_tx_free_entry(qp) >= size))
171e74bfeedSDave Jiang 		return 0;
172e74bfeedSDave Jiang 
173e74bfeedSDave Jiang 	return __ntb_netdev_maybe_stop_tx(ndev, qp, size);
174e74bfeedSDave Jiang }
175e74bfeedSDave Jiang 
ntb_netdev_tx_handler(struct ntb_transport_qp * qp,void * qp_data,void * data,int len)176548c237cSJon Mason static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
177548c237cSJon Mason 				  void *data, int len)
178548c237cSJon Mason {
179548c237cSJon Mason 	struct net_device *ndev = qp_data;
180548c237cSJon Mason 	struct sk_buff *skb;
181e74bfeedSDave Jiang 	struct ntb_netdev *dev = netdev_priv(ndev);
182548c237cSJon Mason 
183548c237cSJon Mason 	skb = data;
184548c237cSJon Mason 	if (!skb || !ndev)
185548c237cSJon Mason 		return;
186548c237cSJon Mason 
187548c237cSJon Mason 	if (len > 0) {
188548c237cSJon Mason 		ndev->stats.tx_packets++;
189548c237cSJon Mason 		ndev->stats.tx_bytes += skb->len;
190548c237cSJon Mason 	} else {
191548c237cSJon Mason 		ndev->stats.tx_errors++;
192548c237cSJon Mason 		ndev->stats.tx_aborted_errors++;
193548c237cSJon Mason 	}
194548c237cSJon Mason 
1955f7d78b2SEric Pilmore 	dev_kfree_skb_any(skb);
196e74bfeedSDave Jiang 
197e74bfeedSDave Jiang 	if (ntb_transport_tx_free_entry(dev->qp) >= tx_start) {
198e74bfeedSDave Jiang 		/* Make sure anybody stopping the queue after this sees the new
199e74bfeedSDave Jiang 		 * value of ntb_transport_tx_free_entry()
200e74bfeedSDave Jiang 		 */
201e74bfeedSDave Jiang 		smp_mb();
202e74bfeedSDave Jiang 		if (netif_queue_stopped(ndev))
203e74bfeedSDave Jiang 			netif_wake_queue(ndev);
204e74bfeedSDave Jiang 	}
205548c237cSJon Mason }
206548c237cSJon Mason 
ntb_netdev_start_xmit(struct sk_buff * skb,struct net_device * ndev)207548c237cSJon Mason static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,
208548c237cSJon Mason 					 struct net_device *ndev)
209548c237cSJon Mason {
210548c237cSJon Mason 	struct ntb_netdev *dev = netdev_priv(ndev);
211548c237cSJon Mason 	int rc;
212548c237cSJon Mason 
213e74bfeedSDave Jiang 	ntb_netdev_maybe_stop_tx(ndev, dev->qp, tx_stop);
214e74bfeedSDave Jiang 
215548c237cSJon Mason 	rc = ntb_transport_tx_enqueue(dev->qp, skb, skb->data, skb->len);
216548c237cSJon Mason 	if (rc)
217548c237cSJon Mason 		goto err;
218548c237cSJon Mason 
219e74bfeedSDave Jiang 	/* check for next submit */
220e74bfeedSDave Jiang 	ntb_netdev_maybe_stop_tx(ndev, dev->qp, tx_stop);
221e74bfeedSDave Jiang 
222548c237cSJon Mason 	return NETDEV_TX_OK;
223548c237cSJon Mason 
224548c237cSJon Mason err:
225548c237cSJon Mason 	ndev->stats.tx_dropped++;
226548c237cSJon Mason 	ndev->stats.tx_errors++;
227548c237cSJon Mason 	return NETDEV_TX_BUSY;
228548c237cSJon Mason }
229548c237cSJon Mason 
ntb_netdev_tx_timer(struct timer_list * t)2302fd2f61eSKees Cook static void ntb_netdev_tx_timer(struct timer_list *t)
231e74bfeedSDave Jiang {
2322fd2f61eSKees Cook 	struct ntb_netdev *dev = from_timer(dev, t, tx_timer);
2332fd2f61eSKees Cook 	struct net_device *ndev = dev->ndev;
234e74bfeedSDave Jiang 
235e74bfeedSDave Jiang 	if (ntb_transport_tx_free_entry(dev->qp) < tx_stop) {
236a861594bSJon Mason 		mod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time));
237e74bfeedSDave Jiang 	} else {
238e74bfeedSDave Jiang 		/* Make sure anybody stopping the queue after this sees the new
239e74bfeedSDave Jiang 		 * value of ntb_transport_tx_free_entry()
240e74bfeedSDave Jiang 		 */
241e74bfeedSDave Jiang 		smp_mb();
242e74bfeedSDave Jiang 		if (netif_queue_stopped(ndev))
243e74bfeedSDave Jiang 			netif_wake_queue(ndev);
244e74bfeedSDave Jiang 	}
245e74bfeedSDave Jiang }
246e74bfeedSDave Jiang 
ntb_netdev_open(struct net_device * ndev)247548c237cSJon Mason static int ntb_netdev_open(struct net_device *ndev)
248548c237cSJon Mason {
249548c237cSJon Mason 	struct ntb_netdev *dev = netdev_priv(ndev);
250548c237cSJon Mason 	struct sk_buff *skb;
251548c237cSJon Mason 	int rc, i, len;
252548c237cSJon Mason 
253548c237cSJon Mason 	/* Add some empty rx bufs */
254548c237cSJon Mason 	for (i = 0; i < NTB_RXQ_SIZE; i++) {
255548c237cSJon Mason 		skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
256548c237cSJon Mason 		if (!skb) {
257548c237cSJon Mason 			rc = -ENOMEM;
258548c237cSJon Mason 			goto err;
259548c237cSJon Mason 		}
260548c237cSJon Mason 
261548c237cSJon Mason 		rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
262548c237cSJon Mason 					      ndev->mtu + ETH_HLEN);
263da4eb27aSDave Jiang 		if (rc) {
264e8bc2ebdSJon Mason 			dev_kfree_skb(skb);
265548c237cSJon Mason 			goto err;
266548c237cSJon Mason 		}
267e8bc2ebdSJon Mason 	}
268548c237cSJon Mason 
2692fd2f61eSKees Cook 	timer_setup(&dev->tx_timer, ntb_netdev_tx_timer, 0);
270e74bfeedSDave Jiang 
271548c237cSJon Mason 	netif_carrier_off(ndev);
272548c237cSJon Mason 	ntb_transport_link_up(dev->qp);
273e74bfeedSDave Jiang 	netif_start_queue(ndev);
274548c237cSJon Mason 
275548c237cSJon Mason 	return 0;
276548c237cSJon Mason 
277548c237cSJon Mason err:
278548c237cSJon Mason 	while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
279548c237cSJon Mason 		dev_kfree_skb(skb);
280548c237cSJon Mason 	return rc;
281548c237cSJon Mason }
282548c237cSJon Mason 
ntb_netdev_close(struct net_device * ndev)283548c237cSJon Mason static int ntb_netdev_close(struct net_device *ndev)
284548c237cSJon Mason {
285548c237cSJon Mason 	struct ntb_netdev *dev = netdev_priv(ndev);
286548c237cSJon Mason 	struct sk_buff *skb;
287548c237cSJon Mason 	int len;
288548c237cSJon Mason 
289548c237cSJon Mason 	ntb_transport_link_down(dev->qp);
290548c237cSJon Mason 
291548c237cSJon Mason 	while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
292548c237cSJon Mason 		dev_kfree_skb(skb);
293548c237cSJon Mason 
294e74bfeedSDave Jiang 	del_timer_sync(&dev->tx_timer);
295e74bfeedSDave Jiang 
296548c237cSJon Mason 	return 0;
297548c237cSJon Mason }
298548c237cSJon Mason 
ntb_netdev_change_mtu(struct net_device * ndev,int new_mtu)299548c237cSJon Mason static int ntb_netdev_change_mtu(struct net_device *ndev, int new_mtu)
300548c237cSJon Mason {
301548c237cSJon Mason 	struct ntb_netdev *dev = netdev_priv(ndev);
302548c237cSJon Mason 	struct sk_buff *skb;
303548c237cSJon Mason 	int len, rc;
304548c237cSJon Mason 
305548c237cSJon Mason 	if (new_mtu > ntb_transport_max_size(dev->qp) - ETH_HLEN)
306548c237cSJon Mason 		return -EINVAL;
307548c237cSJon Mason 
308548c237cSJon Mason 	if (!netif_running(ndev)) {
309548c237cSJon Mason 		ndev->mtu = new_mtu;
310548c237cSJon Mason 		return 0;
311548c237cSJon Mason 	}
312548c237cSJon Mason 
313548c237cSJon Mason 	/* Bring down the link and dispose of posted rx entries */
314548c237cSJon Mason 	ntb_transport_link_down(dev->qp);
315548c237cSJon Mason 
316548c237cSJon Mason 	if (ndev->mtu < new_mtu) {
317548c237cSJon Mason 		int i;
318548c237cSJon Mason 
319548c237cSJon Mason 		for (i = 0; (skb = ntb_transport_rx_remove(dev->qp, &len)); i++)
320548c237cSJon Mason 			dev_kfree_skb(skb);
321548c237cSJon Mason 
322548c237cSJon Mason 		for (; i; i--) {
323548c237cSJon Mason 			skb = netdev_alloc_skb(ndev, new_mtu + ETH_HLEN);
324548c237cSJon Mason 			if (!skb) {
325548c237cSJon Mason 				rc = -ENOMEM;
326548c237cSJon Mason 				goto err;
327548c237cSJon Mason 			}
328548c237cSJon Mason 
329548c237cSJon Mason 			rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
330548c237cSJon Mason 						      new_mtu + ETH_HLEN);
331548c237cSJon Mason 			if (rc) {
332548c237cSJon Mason 				dev_kfree_skb(skb);
333548c237cSJon Mason 				goto err;
334548c237cSJon Mason 			}
335548c237cSJon Mason 		}
336548c237cSJon Mason 	}
337548c237cSJon Mason 
338548c237cSJon Mason 	ndev->mtu = new_mtu;
339548c237cSJon Mason 
340548c237cSJon Mason 	ntb_transport_link_up(dev->qp);
341548c237cSJon Mason 
342548c237cSJon Mason 	return 0;
343548c237cSJon Mason 
344548c237cSJon Mason err:
345548c237cSJon Mason 	ntb_transport_link_down(dev->qp);
346548c237cSJon Mason 
347548c237cSJon Mason 	while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
348548c237cSJon Mason 		dev_kfree_skb(skb);
349548c237cSJon Mason 
350548c237cSJon Mason 	netdev_err(ndev, "Error changing MTU, device inoperable\n");
351548c237cSJon Mason 	return rc;
352548c237cSJon Mason }
353548c237cSJon Mason 
354548c237cSJon Mason static const struct net_device_ops ntb_netdev_ops = {
355548c237cSJon Mason 	.ndo_open = ntb_netdev_open,
356548c237cSJon Mason 	.ndo_stop = ntb_netdev_close,
357548c237cSJon Mason 	.ndo_start_xmit = ntb_netdev_start_xmit,
358548c237cSJon Mason 	.ndo_change_mtu = ntb_netdev_change_mtu,
359548c237cSJon Mason 	.ndo_set_mac_address = eth_mac_addr,
360548c237cSJon Mason };
361548c237cSJon Mason 
ntb_get_drvinfo(struct net_device * ndev,struct ethtool_drvinfo * info)362548c237cSJon Mason static void ntb_get_drvinfo(struct net_device *ndev,
363548c237cSJon Mason 			    struct ethtool_drvinfo *info)
364548c237cSJon Mason {
365548c237cSJon Mason 	struct ntb_netdev *dev = netdev_priv(ndev);
366548c237cSJon Mason 
367fb3ceec1SWolfram Sang 	strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
368fb3ceec1SWolfram Sang 	strscpy(info->version, NTB_NETDEV_VER, sizeof(info->version));
369fb3ceec1SWolfram Sang 	strscpy(info->bus_info, pci_name(dev->pdev), sizeof(info->bus_info));
370548c237cSJon Mason }
371548c237cSJon Mason 
ntb_get_link_ksettings(struct net_device * dev,struct ethtool_link_ksettings * cmd)372a062d19eSPhilippe Reynes static int ntb_get_link_ksettings(struct net_device *dev,
373a062d19eSPhilippe Reynes 				  struct ethtool_link_ksettings *cmd)
374548c237cSJon Mason {
375a062d19eSPhilippe Reynes 	ethtool_link_ksettings_zero_link_mode(cmd, supported);
376a062d19eSPhilippe Reynes 	ethtool_link_ksettings_add_link_mode(cmd, supported, Backplane);
377a062d19eSPhilippe Reynes 	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
378a062d19eSPhilippe Reynes 	ethtool_link_ksettings_add_link_mode(cmd, advertising, Backplane);
379a062d19eSPhilippe Reynes 
380a062d19eSPhilippe Reynes 	cmd->base.speed = SPEED_UNKNOWN;
381a062d19eSPhilippe Reynes 	cmd->base.duplex = DUPLEX_FULL;
382a062d19eSPhilippe Reynes 	cmd->base.port = PORT_OTHER;
383a062d19eSPhilippe Reynes 	cmd->base.phy_address = 0;
384a062d19eSPhilippe Reynes 	cmd->base.autoneg = AUTONEG_ENABLE;
385548c237cSJon Mason 
386548c237cSJon Mason 	return 0;
387548c237cSJon Mason }
388548c237cSJon Mason 
389548c237cSJon Mason static const struct ethtool_ops ntb_ethtool_ops = {
390548c237cSJon Mason 	.get_drvinfo = ntb_get_drvinfo,
391548c237cSJon Mason 	.get_link = ethtool_op_get_link,
392a062d19eSPhilippe Reynes 	.get_link_ksettings = ntb_get_link_ksettings,
393548c237cSJon Mason };
394548c237cSJon Mason 
395548c237cSJon Mason static const struct ntb_queue_handlers ntb_netdev_handlers = {
396548c237cSJon Mason 	.tx_handler = ntb_netdev_tx_handler,
397548c237cSJon Mason 	.rx_handler = ntb_netdev_rx_handler,
398548c237cSJon Mason 	.event_handler = ntb_netdev_event_handler,
399548c237cSJon Mason };
400548c237cSJon Mason 
ntb_netdev_probe(struct device * client_dev)401e26a5843SAllen Hubbe static int ntb_netdev_probe(struct device *client_dev)
402548c237cSJon Mason {
403e26a5843SAllen Hubbe 	struct ntb_dev *ntb;
404548c237cSJon Mason 	struct net_device *ndev;
405e26a5843SAllen Hubbe 	struct pci_dev *pdev;
406548c237cSJon Mason 	struct ntb_netdev *dev;
407548c237cSJon Mason 	int rc;
408548c237cSJon Mason 
409e26a5843SAllen Hubbe 	ntb = dev_ntb(client_dev->parent);
410e26a5843SAllen Hubbe 	pdev = ntb->pdev;
411e26a5843SAllen Hubbe 	if (!pdev)
412e26a5843SAllen Hubbe 		return -ENODEV;
413e26a5843SAllen Hubbe 
414e26a5843SAllen Hubbe 	ndev = alloc_etherdev(sizeof(*dev));
415548c237cSJon Mason 	if (!ndev)
416548c237cSJon Mason 		return -ENOMEM;
417548c237cSJon Mason 
418854b1dd9SLogan Gunthorpe 	SET_NETDEV_DEV(ndev, client_dev);
419854b1dd9SLogan Gunthorpe 
420548c237cSJon Mason 	dev = netdev_priv(ndev);
421548c237cSJon Mason 	dev->ndev = ndev;
422548c237cSJon Mason 	dev->pdev = pdev;
423548c237cSJon Mason 	ndev->features = NETIF_F_HIGHDMA;
424548c237cSJon Mason 
425548c237cSJon Mason 	ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
426548c237cSJon Mason 
427548c237cSJon Mason 	ndev->hw_features = ndev->features;
428548c237cSJon Mason 	ndev->watchdog_timeo = msecs_to_jiffies(NTB_TX_TIMEOUT_MS);
429548c237cSJon Mason 
4306c1f0a1fSJoe Perches 	eth_random_addr(ndev->perm_addr);
431ea52a0b5SJakub Kicinski 	dev_addr_set(ndev, ndev->perm_addr);
432548c237cSJon Mason 
433548c237cSJon Mason 	ndev->netdev_ops = &ntb_netdev_ops;
4347ad24ea4SWilfried Klaebe 	ndev->ethtool_ops = &ntb_ethtool_ops;
435548c237cSJon Mason 
43691572088SJarod Wilson 	ndev->min_mtu = 0;
43791572088SJarod Wilson 	ndev->max_mtu = ETH_MAX_MTU;
43891572088SJarod Wilson 
439e26a5843SAllen Hubbe 	dev->qp = ntb_transport_create_queue(ndev, client_dev,
440e26a5843SAllen Hubbe 					     &ntb_netdev_handlers);
441548c237cSJon Mason 	if (!dev->qp) {
442548c237cSJon Mason 		rc = -EIO;
443548c237cSJon Mason 		goto err;
444548c237cSJon Mason 	}
445548c237cSJon Mason 
446548c237cSJon Mason 	ndev->mtu = ntb_transport_max_size(dev->qp) - ETH_HLEN;
447548c237cSJon Mason 
448548c237cSJon Mason 	rc = register_netdev(ndev);
449548c237cSJon Mason 	if (rc)
450548c237cSJon Mason 		goto err1;
451548c237cSJon Mason 
452906e86b2SAaron Sierra 	dev_set_drvdata(client_dev, ndev);
4537bcd2b11SJon Mason 	dev_info(&pdev->dev, "%s created\n", ndev->name);
454548c237cSJon Mason 	return 0;
455548c237cSJon Mason 
456548c237cSJon Mason err1:
457548c237cSJon Mason 	ntb_transport_free_queue(dev->qp);
458548c237cSJon Mason err:
459548c237cSJon Mason 	free_netdev(ndev);
460548c237cSJon Mason 	return rc;
461548c237cSJon Mason }
462548c237cSJon Mason 
ntb_netdev_remove(struct device * client_dev)463e26a5843SAllen Hubbe static void ntb_netdev_remove(struct device *client_dev)
464548c237cSJon Mason {
465906e86b2SAaron Sierra 	struct net_device *ndev = dev_get_drvdata(client_dev);
466906e86b2SAaron Sierra 	struct ntb_netdev *dev = netdev_priv(ndev);
467548c237cSJon Mason 
468548c237cSJon Mason 	unregister_netdev(ndev);
469548c237cSJon Mason 	ntb_transport_free_queue(dev->qp);
470548c237cSJon Mason 	free_netdev(ndev);
471548c237cSJon Mason }
472548c237cSJon Mason 
473e26a5843SAllen Hubbe static struct ntb_transport_client ntb_netdev_client = {
474548c237cSJon Mason 	.driver.name = KBUILD_MODNAME,
475548c237cSJon Mason 	.driver.owner = THIS_MODULE,
476548c237cSJon Mason 	.probe = ntb_netdev_probe,
477548c237cSJon Mason 	.remove = ntb_netdev_remove,
478548c237cSJon Mason };
479548c237cSJon Mason 
ntb_netdev_init_module(void)480548c237cSJon Mason static int __init ntb_netdev_init_module(void)
481548c237cSJon Mason {
482548c237cSJon Mason 	int rc;
483548c237cSJon Mason 
484e26a5843SAllen Hubbe 	rc = ntb_transport_register_client_dev(KBUILD_MODNAME);
485548c237cSJon Mason 	if (rc)
486548c237cSJon Mason 		return rc;
487b8f79dccSYuan Can 
488b8f79dccSYuan Can 	rc = ntb_transport_register_client(&ntb_netdev_client);
489b8f79dccSYuan Can 	if (rc) {
490b8f79dccSYuan Can 		ntb_transport_unregister_client_dev(KBUILD_MODNAME);
491b8f79dccSYuan Can 		return rc;
492b8f79dccSYuan Can 	}
493b8f79dccSYuan Can 
494b8f79dccSYuan Can 	return 0;
495548c237cSJon Mason }
496ce946519SGeoff Levand late_initcall(ntb_netdev_init_module);
497548c237cSJon Mason 
ntb_netdev_exit_module(void)498548c237cSJon Mason static void __exit ntb_netdev_exit_module(void)
499548c237cSJon Mason {
500ec110bc7SAllen Hubbe 	ntb_transport_unregister_client(&ntb_netdev_client);
501e26a5843SAllen Hubbe 	ntb_transport_unregister_client_dev(KBUILD_MODNAME);
502548c237cSJon Mason }
503548c237cSJon Mason module_exit(ntb_netdev_exit_module);
504