aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2013-04-11 00:40:40 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-11 15:57:32 -0400
commit4b49f58fff00e6e9b24eaa31d4c6324393d76b0a (patch)
tree769d35914f31c2e0107935f0fa25562728011567
parent0162c55463057196346e7b53f83b5b53a47a32cc (diff)
usbnet: handle link change
The link change is detected via the interrupt pipe, and bulk pipes are responsible for transfering packets, so it is reasonable to stop bulk transfer after link is reported as off. Two adavantages may be obtained with stopping bulk transfer after link becomes off: - USB bus bandwidth is saved(USB bus is shared bus except for USB3.0), for example, lots of 'IN' token packets and 'NYET' handshake packets is transfered on 2.0 bus. - probabaly power might be saved for usb host controller since cancelling bulk transfer may disable the asynchronous schedule of host controller. With this patch, when link becomes off, about ~10% performance boost can be found on bulk transfer of anther usb device which is attached to same bus with the usbnet device, see below test on next-20130410: - read from usb mass storage(Sandisk Extreme USB 3.0) on pandaboard with below command after unplugging ethernet cable: dd if=/dev/sda iflag=direct of=/dev/null bs=1M count=800 - without the patch 1, 838860800 bytes (839 MB) copied, 36.2216 s, 23.2 MB/s 2, 838860800 bytes (839 MB) copied, 35.8368 s, 23.4 MB/s 3, 838860800 bytes (839 MB) copied, 35.823 s, 23.4 MB/s 4, 838860800 bytes (839 MB) copied, 35.937 s, 23.3 MB/s 5, 838860800 bytes (839 MB) copied, 35.7365 s, 23.5 MB/s average: 23.6MB/s - with the patch 1, 838860800 bytes (839 MB) copied, 32.3817 s, 25.9 MB/s 2, 838860800 bytes (839 MB) copied, 31.7389 s, 26.4 MB/s 3, 838860800 bytes (839 MB) copied, 32.438 s, 25.9 MB/s 4, 838860800 bytes (839 MB) copied, 32.5492 s, 25.8 MB/s 5, 838860800 bytes (839 MB) copied, 31.6178 s, 26.5 MB/s average: 26.1MB/s Signed-off-by: Ming Lei <ming.lei@canonical.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/usb/usbnet.c30
-rw-r--r--include/linux/usb/usbnet.h1
2 files changed, 31 insertions, 0 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 34e425264a7a..1e5a9b72650e 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -938,6 +938,27 @@ static const struct ethtool_ops usbnet_ethtool_ops = {
938 938
939/*-------------------------------------------------------------------------*/ 939/*-------------------------------------------------------------------------*/
940 940
941static void __handle_link_change(struct usbnet *dev)
942{
943 if (!test_bit(EVENT_DEV_OPEN, &dev->flags))
944 return;
945
946 if (!netif_carrier_ok(dev->net)) {
947 /* kill URBs for reading packets to save bus bandwidth */
948 unlink_urbs(dev, &dev->rxq);
949
950 /*
951 * tx_timeout will unlink URBs for sending packets and
952 * tx queue is stopped by netcore after link becomes off
953 */
954 } else {
955 /* submitting URBs for reading packets */
956 tasklet_schedule(&dev->bh);
957 }
958
959 clear_bit(EVENT_LINK_CHANGE, &dev->flags);
960}
961
941/* work that cannot be done in interrupt context uses keventd. 962/* work that cannot be done in interrupt context uses keventd.
942 * 963 *
943 * NOTE: with 2.5 we could do more of this using completion callbacks, 964 * NOTE: with 2.5 we could do more of this using completion callbacks,
@@ -1035,8 +1056,14 @@ skip_reset:
1035 } else { 1056 } else {
1036 usb_autopm_put_interface(dev->intf); 1057 usb_autopm_put_interface(dev->intf);
1037 } 1058 }
1059
1060 /* handle link change from link resetting */
1061 __handle_link_change(dev);
1038 } 1062 }
1039 1063
1064 if (test_bit (EVENT_LINK_CHANGE, &dev->flags))
1065 __handle_link_change(dev);
1066
1040 if (dev->flags) 1067 if (dev->flags)
1041 netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags); 1068 netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags);
1042} 1069}
@@ -1286,6 +1313,7 @@ static void usbnet_bh (unsigned long param)
1286 // or are we maybe short a few urbs? 1313 // or are we maybe short a few urbs?
1287 } else if (netif_running (dev->net) && 1314 } else if (netif_running (dev->net) &&
1288 netif_device_present (dev->net) && 1315 netif_device_present (dev->net) &&
1316 netif_carrier_ok(dev->net) &&
1289 !timer_pending (&dev->delay) && 1317 !timer_pending (&dev->delay) &&
1290 !test_bit (EVENT_RX_HALT, &dev->flags)) { 1318 !test_bit (EVENT_RX_HALT, &dev->flags)) {
1291 int temp = dev->rxq.qlen; 1319 int temp = dev->rxq.qlen;
@@ -1663,6 +1691,8 @@ void usbnet_link_change(struct usbnet *dev, bool link, bool need_reset)
1663 1691
1664 if (need_reset && link) 1692 if (need_reset && link)
1665 usbnet_defer_kevent(dev, EVENT_LINK_RESET); 1693 usbnet_defer_kevent(dev, EVENT_LINK_RESET);
1694 else
1695 usbnet_defer_kevent(dev, EVENT_LINK_CHANGE);
1666} 1696}
1667EXPORT_SYMBOL(usbnet_link_change); 1697EXPORT_SYMBOL(usbnet_link_change);
1668 1698
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index eb021b8f53bd..da46327fca17 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -72,6 +72,7 @@ struct usbnet {
72# define EVENT_DEVICE_REPORT_IDLE 8 72# define EVENT_DEVICE_REPORT_IDLE 8
73# define EVENT_NO_RUNTIME_PM 9 73# define EVENT_NO_RUNTIME_PM 9
74# define EVENT_RX_KILL 10 74# define EVENT_RX_KILL 10
75# define EVENT_LINK_CHANGE 11
75}; 76};
76 77
77static inline struct usb_driver *driver_of(struct usb_interface *intf) 78static inline struct usb_driver *driver_of(struct usb_interface *intf)