aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Mason <jon.mason@intel.com>2012-11-16 21:27:13 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-17 22:11:14 -0500
commit548c237c0a9972df5d1afaca38aa733ee577128d (patch)
tree4e528e54395066efeec4ddcfd83c308ef77af90f
parentfce8a7bb5b4bfb8a27324703fd5b002ee9247e90 (diff)
net: Add support for NTB virtual ethernet device
A virtual ethernet device that uses the NTB transport API to send/receive data. Signed-off-by: Jon Mason <jon.mason@intel.com> Reviewed-by: Nicholas Bellinger <nab@linux-iscsi.org> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/net/Kconfig4
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/ntb_netdev.c419
4 files changed, 425 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index c5d675a8c53d..01bee6aadb48 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5398,6 +5398,7 @@ NTB DRIVER
5398M: Jon Mason <jon.mason@intel.com> 5398M: Jon Mason <jon.mason@intel.com>
5399S: Supported 5399S: Supported
5400F: drivers/ntb/ 5400F: drivers/ntb/
5401F: drivers/net/ntb_netdev.c
5401F: include/linux/ntb.h 5402F: include/linux/ntb.h
5402 5403
5403NTFS FILESYSTEM 5404NTFS FILESYSTEM
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 6a70184c3f23..5db9acbc0cae 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -189,6 +189,10 @@ config NETPOLL_TRAP
189config NET_POLL_CONTROLLER 189config NET_POLL_CONTROLLER
190 def_bool NETPOLL 190 def_bool NETPOLL
191 191
192config NTB_NETDEV
193 tristate "Virtual Ethernet over NTB"
194 depends on NTB
195
192config RIONET 196config RIONET
193 tristate "RapidIO Ethernet over messaging driver support" 197 tristate "RapidIO Ethernet over messaging driver support"
194 depends on RAPIDIO 198 depends on RAPIDIO
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 335db78fd987..ef3d090efedf 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -71,3 +71,4 @@ obj-$(CONFIG_USB_IPHETH) += usb/
71obj-$(CONFIG_USB_CDC_PHONET) += usb/ 71obj-$(CONFIG_USB_CDC_PHONET) += usb/
72 72
73obj-$(CONFIG_HYPERV_NET) += hyperv/ 73obj-$(CONFIG_HYPERV_NET) += hyperv/
74obj-$(CONFIG_NTB_NETDEV) += ntb_netdev.o
diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c
new file mode 100644
index 000000000000..af48a69cab02
--- /dev/null
+++ b/drivers/net/ntb_netdev.c
@@ -0,0 +1,419 @@
1/*
2 * This file is provided under a dual BSD/GPLv2 license. When using or
3 * redistributing this file, you may do so under either license.
4 *
5 * GPL LICENSE SUMMARY
6 *
7 * Copyright(c) 2012 Intel Corporation. All rights reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of version 2 of the GNU General Public License as
11 * published by the Free Software Foundation.
12 *
13 * BSD LICENSE
14 *
15 * Copyright(c) 2012 Intel Corporation. All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 *
21 * * Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * * Redistributions in binary form must reproduce the above copy
24 * notice, this list of conditions and the following disclaimer in
25 * the documentation and/or other materials provided with the
26 * distribution.
27 * * Neither the name of Intel Corporation nor the names of its
28 * contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
37 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
38 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
39 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
41 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 *
43 * Intel PCIe NTB Network Linux driver
44 *
45 * Contact Information:
46 * Jon Mason <jon.mason@intel.com>
47 */
48#include <linux/etherdevice.h>
49#include <linux/ethtool.h>
50#include <linux/module.h>
51#include <linux/pci.h>
52#include <linux/ntb.h>
53
54#define NTB_NETDEV_VER "0.6"
55
56MODULE_DESCRIPTION(KBUILD_MODNAME);
57MODULE_VERSION(NTB_NETDEV_VER);
58MODULE_LICENSE("Dual BSD/GPL");
59MODULE_AUTHOR("Intel Corporation");
60
61struct ntb_netdev {
62 struct list_head list;
63 struct pci_dev *pdev;
64 struct net_device *ndev;
65 struct ntb_transport_qp *qp;
66};
67
68#define NTB_TX_TIMEOUT_MS 1000
69#define NTB_RXQ_SIZE 100
70
71static LIST_HEAD(dev_list);
72
73static void ntb_netdev_event_handler(void *data, int status)
74{
75 struct net_device *ndev = data;
76 struct ntb_netdev *dev = netdev_priv(ndev);
77
78 netdev_dbg(ndev, "Event %x, Link %x\n", status,
79 ntb_transport_link_query(dev->qp));
80
81 /* Currently, only link status event is supported */
82 if (status)
83 netif_carrier_on(ndev);
84 else
85 netif_carrier_off(ndev);
86}
87
88static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
89 void *data, int len)
90{
91 struct net_device *ndev = qp_data;
92 struct sk_buff *skb;
93 int rc;
94
95 skb = data;
96 if (!skb)
97 return;
98
99 netdev_dbg(ndev, "%s: %d byte payload received\n", __func__, len);
100
101 skb_put(skb, len);
102 skb->protocol = eth_type_trans(skb, ndev);
103 skb->ip_summed = CHECKSUM_NONE;
104
105 if (netif_rx(skb) == NET_RX_DROP) {
106 ndev->stats.rx_errors++;
107 ndev->stats.rx_dropped++;
108 } else {
109 ndev->stats.rx_packets++;
110 ndev->stats.rx_bytes += len;
111 }
112
113 skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
114 if (!skb) {
115 ndev->stats.rx_errors++;
116 ndev->stats.rx_frame_errors++;
117 return;
118 }
119
120 rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);
121 if (rc) {
122 ndev->stats.rx_errors++;
123 ndev->stats.rx_fifo_errors++;
124 }
125}
126
127static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
128 void *data, int len)
129{
130 struct net_device *ndev = qp_data;
131 struct sk_buff *skb;
132
133 skb = data;
134 if (!skb || !ndev)
135 return;
136
137 if (len > 0) {
138 ndev->stats.tx_packets++;
139 ndev->stats.tx_bytes += skb->len;
140 } else {
141 ndev->stats.tx_errors++;
142 ndev->stats.tx_aborted_errors++;
143 }
144
145 dev_kfree_skb(skb);
146
147 if (netif_queue_stopped(ndev))
148 netif_wake_queue(ndev);
149}
150
151static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,
152 struct net_device *ndev)
153{
154 struct ntb_netdev *dev = netdev_priv(ndev);
155 int rc;
156
157 netdev_dbg(ndev, "ntb_transport_tx_enqueue\n");
158
159 rc = ntb_transport_tx_enqueue(dev->qp, skb, skb->data, skb->len);
160 if (rc)
161 goto err;
162
163 return NETDEV_TX_OK;
164
165err:
166 ndev->stats.tx_dropped++;
167 ndev->stats.tx_errors++;
168 netif_stop_queue(ndev);
169 return NETDEV_TX_BUSY;
170}
171
172static int ntb_netdev_open(struct net_device *ndev)
173{
174 struct ntb_netdev *dev = netdev_priv(ndev);
175 struct sk_buff *skb;
176 int rc, i, len;
177
178 /* Add some empty rx bufs */
179 for (i = 0; i < NTB_RXQ_SIZE; i++) {
180 skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
181 if (!skb) {
182 rc = -ENOMEM;
183 goto err;
184 }
185
186 rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
187 ndev->mtu + ETH_HLEN);
188 if (rc == -EINVAL)
189 goto err;
190 }
191
192 netif_carrier_off(ndev);
193 ntb_transport_link_up(dev->qp);
194
195 return 0;
196
197err:
198 while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
199 dev_kfree_skb(skb);
200 return rc;
201}
202
203static int ntb_netdev_close(struct net_device *ndev)
204{
205 struct ntb_netdev *dev = netdev_priv(ndev);
206 struct sk_buff *skb;
207 int len;
208
209 ntb_transport_link_down(dev->qp);
210
211 while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
212 dev_kfree_skb(skb);
213
214 return 0;
215}
216
217static int ntb_netdev_change_mtu(struct net_device *ndev, int new_mtu)
218{
219 struct ntb_netdev *dev = netdev_priv(ndev);
220 struct sk_buff *skb;
221 int len, rc;
222
223 if (new_mtu > ntb_transport_max_size(dev->qp) - ETH_HLEN)
224 return -EINVAL;
225
226 if (!netif_running(ndev)) {
227 ndev->mtu = new_mtu;
228 return 0;
229 }
230
231 /* Bring down the link and dispose of posted rx entries */
232 ntb_transport_link_down(dev->qp);
233
234 if (ndev->mtu < new_mtu) {
235 int i;
236
237 for (i = 0; (skb = ntb_transport_rx_remove(dev->qp, &len)); i++)
238 dev_kfree_skb(skb);
239
240 for (; i; i--) {
241 skb = netdev_alloc_skb(ndev, new_mtu + ETH_HLEN);
242 if (!skb) {
243 rc = -ENOMEM;
244 goto err;
245 }
246
247 rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
248 new_mtu + ETH_HLEN);
249 if (rc) {
250 dev_kfree_skb(skb);
251 goto err;
252 }
253 }
254 }
255
256 ndev->mtu = new_mtu;
257
258 ntb_transport_link_up(dev->qp);
259
260 return 0;
261
262err:
263 ntb_transport_link_down(dev->qp);
264
265 while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
266 dev_kfree_skb(skb);
267
268 netdev_err(ndev, "Error changing MTU, device inoperable\n");
269 return rc;
270}
271
272static void ntb_netdev_tx_timeout(struct net_device *ndev)
273{
274 if (netif_running(ndev))
275 netif_wake_queue(ndev);
276}
277
278static const struct net_device_ops ntb_netdev_ops = {
279 .ndo_open = ntb_netdev_open,
280 .ndo_stop = ntb_netdev_close,
281 .ndo_start_xmit = ntb_netdev_start_xmit,
282 .ndo_change_mtu = ntb_netdev_change_mtu,
283 .ndo_tx_timeout = ntb_netdev_tx_timeout,
284 .ndo_set_mac_address = eth_mac_addr,
285};
286
287static void ntb_get_drvinfo(struct net_device *ndev,
288 struct ethtool_drvinfo *info)
289{
290 struct ntb_netdev *dev = netdev_priv(ndev);
291
292 strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
293 strlcpy(info->version, NTB_NETDEV_VER, sizeof(info->version));
294 strlcpy(info->bus_info, pci_name(dev->pdev), sizeof(info->bus_info));
295}
296
297static int ntb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
298{
299 cmd->supported = SUPPORTED_Backplane;
300 cmd->advertising = ADVERTISED_Backplane;
301 cmd->speed = SPEED_UNKNOWN;
302 ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
303 cmd->duplex = DUPLEX_FULL;
304 cmd->port = PORT_OTHER;
305 cmd->phy_address = 0;
306 cmd->transceiver = XCVR_DUMMY1;
307 cmd->autoneg = AUTONEG_ENABLE;
308 cmd->maxtxpkt = 0;
309 cmd->maxrxpkt = 0;
310
311 return 0;
312}
313
314static const struct ethtool_ops ntb_ethtool_ops = {
315 .get_drvinfo = ntb_get_drvinfo,
316 .get_link = ethtool_op_get_link,
317 .get_settings = ntb_get_settings,
318};
319
320static const struct ntb_queue_handlers ntb_netdev_handlers = {
321 .tx_handler = ntb_netdev_tx_handler,
322 .rx_handler = ntb_netdev_rx_handler,
323 .event_handler = ntb_netdev_event_handler,
324};
325
326static int __devinit ntb_netdev_probe(struct pci_dev *pdev)
327{
328 struct net_device *ndev;
329 struct ntb_netdev *dev;
330 int rc;
331
332 ndev = alloc_etherdev(sizeof(struct ntb_netdev));
333 if (!ndev)
334 return -ENOMEM;
335
336 dev = netdev_priv(ndev);
337 dev->ndev = ndev;
338 dev->pdev = pdev;
339 BUG_ON(!dev->pdev);
340 ndev->features = NETIF_F_HIGHDMA;
341
342 ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
343
344 ndev->hw_features = ndev->features;
345 ndev->watchdog_timeo = msecs_to_jiffies(NTB_TX_TIMEOUT_MS);
346
347 random_ether_addr(ndev->perm_addr);
348 memcpy(ndev->dev_addr, ndev->perm_addr, ndev->addr_len);
349
350 ndev->netdev_ops = &ntb_netdev_ops;
351 SET_ETHTOOL_OPS(ndev, &ntb_ethtool_ops);
352
353 dev->qp = ntb_transport_create_queue(ndev, pdev, &ntb_netdev_handlers);
354 if (!dev->qp) {
355 rc = -EIO;
356 goto err;
357 }
358
359 ndev->mtu = ntb_transport_max_size(dev->qp) - ETH_HLEN;
360
361 rc = register_netdev(ndev);
362 if (rc)
363 goto err1;
364
365 list_add(&dev->list, &dev_list);
366 pr_info("%s: %s created\n", KBUILD_MODNAME, ndev->name);
367 return 0;
368
369err1:
370 ntb_transport_free_queue(dev->qp);
371err:
372 free_netdev(ndev);
373 return rc;
374}
375
376static void __exit ntb_netdev_remove(struct pci_dev *pdev)
377{
378 struct net_device *ndev;
379 struct ntb_netdev *dev;
380
381 list_for_each_entry(dev, &dev_list, list) {
382 if (dev->pdev == pdev)
383 break;
384 }
385 if (dev == NULL)
386 return;
387
388 ndev = dev->ndev;
389
390 unregister_netdev(ndev);
391 ntb_transport_free_queue(dev->qp);
392 free_netdev(ndev);
393}
394
395static struct ntb_client ntb_netdev_client = {
396 .driver.name = KBUILD_MODNAME,
397 .driver.owner = THIS_MODULE,
398 .probe = ntb_netdev_probe,
399 .remove = ntb_netdev_remove,
400};
401
402static int __init ntb_netdev_init_module(void)
403{
404 int rc;
405
406 rc = ntb_register_client_dev(KBUILD_MODNAME);
407 if (rc)
408 return rc;
409 return ntb_register_client(&ntb_netdev_client);
410}
411module_init(ntb_netdev_init_module);
412
413static void __exit ntb_netdev_exit_module(void)
414{
415 ntb_unregister_client(&ntb_netdev_client);
416 ntb_unregister_client_dev(KBUILD_MODNAME);
417 pr_info("%s: Driver removed\n", KBUILD_MODNAME);
418}
419module_exit(ntb_netdev_exit_module);