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