diff options
author | Oliver Neukum <oliver@neukum.org> | 2009-12-03 18:31:18 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-12-03 18:31:18 -0500 |
commit | 69ee472f2706371ca639de49b06df91615c07d8d (patch) | |
tree | 3f6de524e96679a2e54b55bb0ba9d1fd71c8222c /drivers/net/usb/usbnet.c | |
parent | 7f515790274d26d710303b7a1f23571ca93a6288 (diff) |
usbnet & cdc-ether: Autosuspend for online devices
Using remote wakeup and delayed transmission to allow
online device to go into usb autosuspend.
Minimal alternate support for devices that don't support
remote wakeup.
Signed-off-by: Oliver Neukum <oliver@neukum.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb/usbnet.c')
-rw-r--r-- | drivers/net/usb/usbnet.c | 157 |
1 files changed, 128 insertions, 29 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 511e7bdc4573..035fab04c0a0 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c | |||
@@ -353,7 +353,8 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) | |||
353 | 353 | ||
354 | if (netif_running (dev->net) && | 354 | if (netif_running (dev->net) && |
355 | netif_device_present (dev->net) && | 355 | netif_device_present (dev->net) && |
356 | !test_bit (EVENT_RX_HALT, &dev->flags)) { | 356 | !test_bit (EVENT_RX_HALT, &dev->flags) && |
357 | !test_bit (EVENT_DEV_ASLEEP, &dev->flags)) { | ||
357 | switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) { | 358 | switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) { |
358 | case -EPIPE: | 359 | case -EPIPE: |
359 | usbnet_defer_kevent (dev, EVENT_RX_HALT); | 360 | usbnet_defer_kevent (dev, EVENT_RX_HALT); |
@@ -611,15 +612,39 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs); | |||
611 | /*-------------------------------------------------------------------------*/ | 612 | /*-------------------------------------------------------------------------*/ |
612 | 613 | ||
613 | // precondition: never called in_interrupt | 614 | // precondition: never called in_interrupt |
615 | static void usbnet_terminate_urbs(struct usbnet *dev) | ||
616 | { | ||
617 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup); | ||
618 | DECLARE_WAITQUEUE(wait, current); | ||
619 | int temp; | ||
620 | |||
621 | /* ensure there are no more active urbs */ | ||
622 | add_wait_queue(&unlink_wakeup, &wait); | ||
623 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
624 | dev->wait = &unlink_wakeup; | ||
625 | temp = unlink_urbs(dev, &dev->txq) + | ||
626 | unlink_urbs(dev, &dev->rxq); | ||
627 | |||
628 | /* maybe wait for deletions to finish. */ | ||
629 | while (!skb_queue_empty(&dev->rxq) | ||
630 | && !skb_queue_empty(&dev->txq) | ||
631 | && !skb_queue_empty(&dev->done)) { | ||
632 | schedule_timeout(UNLINK_TIMEOUT_MS); | ||
633 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
634 | if (netif_msg_ifdown(dev)) | ||
635 | devdbg(dev, "waited for %d urb completions", | ||
636 | temp); | ||
637 | } | ||
638 | set_current_state(TASK_RUNNING); | ||
639 | dev->wait = NULL; | ||
640 | remove_wait_queue(&unlink_wakeup, &wait); | ||
641 | } | ||
614 | 642 | ||
615 | int usbnet_stop (struct net_device *net) | 643 | int usbnet_stop (struct net_device *net) |
616 | { | 644 | { |
617 | struct usbnet *dev = netdev_priv(net); | 645 | struct usbnet *dev = netdev_priv(net); |
618 | struct driver_info *info = dev->driver_info; | 646 | struct driver_info *info = dev->driver_info; |
619 | int temp; | ||
620 | int retval; | 647 | int retval; |
621 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); | ||
622 | DECLARE_WAITQUEUE (wait, current); | ||
623 | 648 | ||
624 | netif_stop_queue (net); | 649 | netif_stop_queue (net); |
625 | 650 | ||
@@ -641,25 +666,8 @@ int usbnet_stop (struct net_device *net) | |||
641 | info->description); | 666 | info->description); |
642 | } | 667 | } |
643 | 668 | ||
644 | if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) { | 669 | if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) |
645 | /* ensure there are no more active urbs */ | 670 | usbnet_terminate_urbs(dev); |
646 | add_wait_queue(&unlink_wakeup, &wait); | ||
647 | dev->wait = &unlink_wakeup; | ||
648 | temp = unlink_urbs(dev, &dev->txq) + | ||
649 | unlink_urbs(dev, &dev->rxq); | ||
650 | |||
651 | /* maybe wait for deletions to finish. */ | ||
652 | while (!skb_queue_empty(&dev->rxq) && | ||
653 | !skb_queue_empty(&dev->txq) && | ||
654 | !skb_queue_empty(&dev->done)) { | ||
655 | msleep(UNLINK_TIMEOUT_MS); | ||
656 | if (netif_msg_ifdown(dev)) | ||
657 | devdbg(dev, "waited for %d urb completions", | ||
658 | temp); | ||
659 | } | ||
660 | dev->wait = NULL; | ||
661 | remove_wait_queue(&unlink_wakeup, &wait); | ||
662 | } | ||
663 | 671 | ||
664 | usb_kill_urb(dev->interrupt); | 672 | usb_kill_urb(dev->interrupt); |
665 | 673 | ||
@@ -672,7 +680,10 @@ int usbnet_stop (struct net_device *net) | |||
672 | dev->flags = 0; | 680 | dev->flags = 0; |
673 | del_timer_sync (&dev->delay); | 681 | del_timer_sync (&dev->delay); |
674 | tasklet_kill (&dev->bh); | 682 | tasklet_kill (&dev->bh); |
675 | usb_autopm_put_interface(dev->intf); | 683 | if (info->manage_power) |
684 | info->manage_power(dev, 0); | ||
685 | else | ||
686 | usb_autopm_put_interface(dev->intf); | ||
676 | 687 | ||
677 | return 0; | 688 | return 0; |
678 | } | 689 | } |
@@ -753,6 +764,12 @@ int usbnet_open (struct net_device *net) | |||
753 | 764 | ||
754 | // delay posting reads until we're fully open | 765 | // delay posting reads until we're fully open |
755 | tasklet_schedule (&dev->bh); | 766 | tasklet_schedule (&dev->bh); |
767 | if (info->manage_power) { | ||
768 | retval = info->manage_power(dev, 1); | ||
769 | if (retval < 0) | ||
770 | goto done; | ||
771 | usb_autopm_put_interface(dev->intf); | ||
772 | } | ||
756 | return retval; | 773 | return retval; |
757 | done: | 774 | done: |
758 | usb_autopm_put_interface(dev->intf); | 775 | usb_autopm_put_interface(dev->intf); |
@@ -881,11 +898,16 @@ kevent (struct work_struct *work) | |||
881 | /* usb_clear_halt() needs a thread context */ | 898 | /* usb_clear_halt() needs a thread context */ |
882 | if (test_bit (EVENT_TX_HALT, &dev->flags)) { | 899 | if (test_bit (EVENT_TX_HALT, &dev->flags)) { |
883 | unlink_urbs (dev, &dev->txq); | 900 | unlink_urbs (dev, &dev->txq); |
901 | status = usb_autopm_get_interface(dev->intf); | ||
902 | if (status < 0) | ||
903 | goto fail_pipe; | ||
884 | status = usb_clear_halt (dev->udev, dev->out); | 904 | status = usb_clear_halt (dev->udev, dev->out); |
905 | usb_autopm_put_interface(dev->intf); | ||
885 | if (status < 0 && | 906 | if (status < 0 && |
886 | status != -EPIPE && | 907 | status != -EPIPE && |
887 | status != -ESHUTDOWN) { | 908 | status != -ESHUTDOWN) { |
888 | if (netif_msg_tx_err (dev)) | 909 | if (netif_msg_tx_err (dev)) |
910 | fail_pipe: | ||
889 | deverr (dev, "can't clear tx halt, status %d", | 911 | deverr (dev, "can't clear tx halt, status %d", |
890 | status); | 912 | status); |
891 | } else { | 913 | } else { |
@@ -896,11 +918,16 @@ kevent (struct work_struct *work) | |||
896 | } | 918 | } |
897 | if (test_bit (EVENT_RX_HALT, &dev->flags)) { | 919 | if (test_bit (EVENT_RX_HALT, &dev->flags)) { |
898 | unlink_urbs (dev, &dev->rxq); | 920 | unlink_urbs (dev, &dev->rxq); |
921 | status = usb_autopm_get_interface(dev->intf); | ||
922 | if (status < 0) | ||
923 | goto fail_halt; | ||
899 | status = usb_clear_halt (dev->udev, dev->in); | 924 | status = usb_clear_halt (dev->udev, dev->in); |
925 | usb_autopm_put_interface(dev->intf); | ||
900 | if (status < 0 && | 926 | if (status < 0 && |
901 | status != -EPIPE && | 927 | status != -EPIPE && |
902 | status != -ESHUTDOWN) { | 928 | status != -ESHUTDOWN) { |
903 | if (netif_msg_rx_err (dev)) | 929 | if (netif_msg_rx_err (dev)) |
930 | fail_halt: | ||
904 | deverr (dev, "can't clear rx halt, status %d", | 931 | deverr (dev, "can't clear rx halt, status %d", |
905 | status); | 932 | status); |
906 | } else { | 933 | } else { |
@@ -919,7 +946,12 @@ kevent (struct work_struct *work) | |||
919 | clear_bit (EVENT_RX_MEMORY, &dev->flags); | 946 | clear_bit (EVENT_RX_MEMORY, &dev->flags); |
920 | if (urb != NULL) { | 947 | if (urb != NULL) { |
921 | clear_bit (EVENT_RX_MEMORY, &dev->flags); | 948 | clear_bit (EVENT_RX_MEMORY, &dev->flags); |
949 | status = usb_autopm_get_interface(dev->intf); | ||
950 | if (status < 0) | ||
951 | goto fail_lowmem; | ||
922 | rx_submit (dev, urb, GFP_KERNEL); | 952 | rx_submit (dev, urb, GFP_KERNEL); |
953 | usb_autopm_put_interface(dev->intf); | ||
954 | fail_lowmem: | ||
923 | tasklet_schedule (&dev->bh); | 955 | tasklet_schedule (&dev->bh); |
924 | } | 956 | } |
925 | } | 957 | } |
@@ -929,11 +961,18 @@ kevent (struct work_struct *work) | |||
929 | int retval = 0; | 961 | int retval = 0; |
930 | 962 | ||
931 | clear_bit (EVENT_LINK_RESET, &dev->flags); | 963 | clear_bit (EVENT_LINK_RESET, &dev->flags); |
964 | status = usb_autopm_get_interface(dev->intf); | ||
965 | if (status < 0) | ||
966 | goto skip_reset; | ||
932 | if(info->link_reset && (retval = info->link_reset(dev)) < 0) { | 967 | if(info->link_reset && (retval = info->link_reset(dev)) < 0) { |
968 | usb_autopm_put_interface(dev->intf); | ||
969 | skip_reset: | ||
933 | devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s", | 970 | devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s", |
934 | retval, | 971 | retval, |
935 | dev->udev->bus->bus_name, dev->udev->devpath, | 972 | dev->udev->bus->bus_name, dev->udev->devpath, |
936 | info->description); | 973 | info->description); |
974 | } else { | ||
975 | usb_autopm_put_interface(dev->intf); | ||
937 | } | 976 | } |
938 | } | 977 | } |
939 | 978 | ||
@@ -971,6 +1010,7 @@ static void tx_complete (struct urb *urb) | |||
971 | case -EPROTO: | 1010 | case -EPROTO: |
972 | case -ETIME: | 1011 | case -ETIME: |
973 | case -EILSEQ: | 1012 | case -EILSEQ: |
1013 | usb_mark_last_busy(dev->udev); | ||
974 | if (!timer_pending (&dev->delay)) { | 1014 | if (!timer_pending (&dev->delay)) { |
975 | mod_timer (&dev->delay, | 1015 | mod_timer (&dev->delay, |
976 | jiffies + THROTTLE_JIFFIES); | 1016 | jiffies + THROTTLE_JIFFIES); |
@@ -987,6 +1027,7 @@ static void tx_complete (struct urb *urb) | |||
987 | } | 1027 | } |
988 | } | 1028 | } |
989 | 1029 | ||
1030 | usb_autopm_put_interface_async(dev->intf); | ||
990 | urb->dev = NULL; | 1031 | urb->dev = NULL; |
991 | entry->state = tx_done; | 1032 | entry->state = tx_done; |
992 | defer_bh(dev, skb, &dev->txq); | 1033 | defer_bh(dev, skb, &dev->txq); |
@@ -1057,14 +1098,34 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, | |||
1057 | } | 1098 | } |
1058 | } | 1099 | } |
1059 | 1100 | ||
1060 | spin_lock_irqsave (&dev->txq.lock, flags); | 1101 | spin_lock_irqsave(&dev->txq.lock, flags); |
1102 | retval = usb_autopm_get_interface_async(dev->intf); | ||
1103 | if (retval < 0) { | ||
1104 | spin_unlock_irqrestore(&dev->txq.lock, flags); | ||
1105 | goto drop; | ||
1106 | } | ||
1107 | |||
1108 | #ifdef CONFIG_PM | ||
1109 | /* if this triggers the device is still a sleep */ | ||
1110 | if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) { | ||
1111 | /* transmission will be done in resume */ | ||
1112 | usb_anchor_urb(urb, &dev->deferred); | ||
1113 | /* no use to process more packets */ | ||
1114 | netif_stop_queue(net); | ||
1115 | spin_unlock_irqrestore(&dev->txq.lock, flags); | ||
1116 | devdbg(dev, "Delaying transmission for resumption"); | ||
1117 | goto deferred; | ||
1118 | } | ||
1119 | #endif | ||
1061 | 1120 | ||
1062 | switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { | 1121 | switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { |
1063 | case -EPIPE: | 1122 | case -EPIPE: |
1064 | netif_stop_queue (net); | 1123 | netif_stop_queue (net); |
1065 | usbnet_defer_kevent (dev, EVENT_TX_HALT); | 1124 | usbnet_defer_kevent (dev, EVENT_TX_HALT); |
1125 | usb_autopm_put_interface_async(dev->intf); | ||
1066 | break; | 1126 | break; |
1067 | default: | 1127 | default: |
1128 | usb_autopm_put_interface_async(dev->intf); | ||
1068 | if (netif_msg_tx_err (dev)) | 1129 | if (netif_msg_tx_err (dev)) |
1069 | devdbg (dev, "tx: submit urb err %d", retval); | 1130 | devdbg (dev, "tx: submit urb err %d", retval); |
1070 | break; | 1131 | break; |
@@ -1088,6 +1149,9 @@ drop: | |||
1088 | devdbg (dev, "> tx, len %d, type 0x%x", | 1149 | devdbg (dev, "> tx, len %d, type 0x%x", |
1089 | length, skb->protocol); | 1150 | length, skb->protocol); |
1090 | } | 1151 | } |
1152 | #ifdef CONFIG_PM | ||
1153 | deferred: | ||
1154 | #endif | ||
1091 | return NETDEV_TX_OK; | 1155 | return NETDEV_TX_OK; |
1092 | } | 1156 | } |
1093 | EXPORT_SYMBOL_GPL(usbnet_start_xmit); | 1157 | EXPORT_SYMBOL_GPL(usbnet_start_xmit); |
@@ -1263,6 +1327,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) | |||
1263 | dev->bh.func = usbnet_bh; | 1327 | dev->bh.func = usbnet_bh; |
1264 | dev->bh.data = (unsigned long) dev; | 1328 | dev->bh.data = (unsigned long) dev; |
1265 | INIT_WORK (&dev->kevent, kevent); | 1329 | INIT_WORK (&dev->kevent, kevent); |
1330 | init_usb_anchor(&dev->deferred); | ||
1266 | dev->delay.function = usbnet_bh; | 1331 | dev->delay.function = usbnet_bh; |
1267 | dev->delay.data = (unsigned long) dev; | 1332 | dev->delay.data = (unsigned long) dev; |
1268 | init_timer (&dev->delay); | 1333 | init_timer (&dev->delay); |
@@ -1382,13 +1447,23 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message) | |||
1382 | struct usbnet *dev = usb_get_intfdata(intf); | 1447 | struct usbnet *dev = usb_get_intfdata(intf); |
1383 | 1448 | ||
1384 | if (!dev->suspend_count++) { | 1449 | if (!dev->suspend_count++) { |
1450 | spin_lock_irq(&dev->txq.lock); | ||
1451 | /* don't autosuspend while transmitting */ | ||
1452 | if (dev->txq.qlen && (message.event & PM_EVENT_AUTO)) { | ||
1453 | spin_unlock_irq(&dev->txq.lock); | ||
1454 | return -EBUSY; | ||
1455 | } else { | ||
1456 | set_bit(EVENT_DEV_ASLEEP, &dev->flags); | ||
1457 | spin_unlock_irq(&dev->txq.lock); | ||
1458 | } | ||
1385 | /* | 1459 | /* |
1386 | * accelerate emptying of the rx and queues, to avoid | 1460 | * accelerate emptying of the rx and queues, to avoid |
1387 | * having everything error out. | 1461 | * having everything error out. |
1388 | */ | 1462 | */ |
1389 | netif_device_detach (dev->net); | 1463 | netif_device_detach (dev->net); |
1390 | (void) unlink_urbs (dev, &dev->rxq); | 1464 | usbnet_terminate_urbs(dev); |
1391 | (void) unlink_urbs (dev, &dev->txq); | 1465 | usb_kill_urb(dev->interrupt); |
1466 | |||
1392 | /* | 1467 | /* |
1393 | * reattach so runtime management can use and | 1468 | * reattach so runtime management can use and |
1394 | * wake the device | 1469 | * wake the device |
@@ -1402,10 +1477,34 @@ EXPORT_SYMBOL_GPL(usbnet_suspend); | |||
1402 | int usbnet_resume (struct usb_interface *intf) | 1477 | int usbnet_resume (struct usb_interface *intf) |
1403 | { | 1478 | { |
1404 | struct usbnet *dev = usb_get_intfdata(intf); | 1479 | struct usbnet *dev = usb_get_intfdata(intf); |
1480 | struct sk_buff *skb; | ||
1481 | struct urb *res; | ||
1482 | int retval; | ||
1483 | |||
1484 | if (!--dev->suspend_count) { | ||
1485 | spin_lock_irq(&dev->txq.lock); | ||
1486 | while ((res = usb_get_from_anchor(&dev->deferred))) { | ||
1487 | |||
1488 | printk(KERN_INFO"%s has delayed data\n", __func__); | ||
1489 | skb = (struct sk_buff *)res->context; | ||
1490 | retval = usb_submit_urb(res, GFP_ATOMIC); | ||
1491 | if (retval < 0) { | ||
1492 | dev_kfree_skb_any(skb); | ||
1493 | usb_free_urb(res); | ||
1494 | usb_autopm_put_interface_async(dev->intf); | ||
1495 | } else { | ||
1496 | dev->net->trans_start = jiffies; | ||
1497 | __skb_queue_tail(&dev->txq, skb); | ||
1498 | } | ||
1499 | } | ||
1405 | 1500 | ||
1406 | if (!--dev->suspend_count) | 1501 | smp_mb(); |
1502 | clear_bit(EVENT_DEV_ASLEEP, &dev->flags); | ||
1503 | spin_unlock_irq(&dev->txq.lock); | ||
1504 | if (!(dev->txq.qlen >= TX_QLEN(dev))) | ||
1505 | netif_start_queue(dev->net); | ||
1407 | tasklet_schedule (&dev->bh); | 1506 | tasklet_schedule (&dev->bh); |
1408 | 1507 | } | |
1409 | return 0; | 1508 | return 0; |
1410 | } | 1509 | } |
1411 | EXPORT_SYMBOL_GPL(usbnet_resume); | 1510 | EXPORT_SYMBOL_GPL(usbnet_resume); |