diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2013-03-27 16:14:19 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-03-28 14:06:27 -0400 |
commit | 0aa2832dd0d9d8609fd8f15139bc7572541a1215 (patch) | |
tree | 9537cc80217eca1614ca988a87b34170b8dbcc8f | |
parent | e9e88fb7bca9f527ccdf4166a240a9023ba6ee73 (diff) |
USB: use "global suspend" for system sleep on USB-2 buses
This patch (as1674) speeds up system sleep transitions by not
suspending each individual device on a USB-1.1 or USB-2 bus. The
devices will automatically go into suspend when their root hubs are
suspended (i.e., stop sending out Start-Of-Frame packets) -- this is
what the USB spec calls "global suspend".
Since this is what we do already when CONFIG_USB_SUSPEND isn't
enabled, it shouldn't cause any problems.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: Peter Chen <peter.chen@freescale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/core/hub.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 669da9ef714d..443d5cc9330b 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -2886,9 +2886,11 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev) | |||
2886 | * Linux (2.6) currently has NO mechanisms to initiate that: no khubd | 2886 | * Linux (2.6) currently has NO mechanisms to initiate that: no khubd |
2887 | * timer, no SRP, no requests through sysfs. | 2887 | * timer, no SRP, no requests through sysfs. |
2888 | * | 2888 | * |
2889 | * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when | 2889 | * If CONFIG_USB_SUSPEND isn't enabled, non-SuperSpeed devices really get |
2890 | * the root hub for their bus goes into global suspend ... so we don't | 2890 | * suspended only when their bus goes into global suspend (i.e., the root |
2891 | * (falsely) update the device power state to say it suspended. | 2891 | * hub is suspended). Nevertheless, we change @udev->state to |
2892 | * USB_STATE_SUSPENDED as this is the device's "logical" state. The actual | ||
2893 | * upstream port setting is stored in @udev->port_is_suspended. | ||
2892 | * | 2894 | * |
2893 | * Returns 0 on success, else negative errno. | 2895 | * Returns 0 on success, else negative errno. |
2894 | */ | 2896 | */ |
@@ -2899,6 +2901,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) | |||
2899 | enum pm_qos_flags_status pm_qos_stat; | 2901 | enum pm_qos_flags_status pm_qos_stat; |
2900 | int port1 = udev->portnum; | 2902 | int port1 = udev->portnum; |
2901 | int status; | 2903 | int status; |
2904 | bool really_suspend = true; | ||
2902 | 2905 | ||
2903 | /* enable remote wakeup when appropriate; this lets the device | 2906 | /* enable remote wakeup when appropriate; this lets the device |
2904 | * wake up the upstream hub (including maybe the root hub). | 2907 | * wake up the upstream hub (including maybe the root hub). |
@@ -2955,9 +2958,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) | |||
2955 | /* see 7.1.7.6 */ | 2958 | /* see 7.1.7.6 */ |
2956 | if (hub_is_superspeed(hub->hdev)) | 2959 | if (hub_is_superspeed(hub->hdev)) |
2957 | status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3); | 2960 | status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3); |
2958 | else | 2961 | else if (PMSG_IS_AUTO(msg)) |
2959 | status = set_port_feature(hub->hdev, port1, | 2962 | status = set_port_feature(hub->hdev, port1, |
2960 | USB_PORT_FEAT_SUSPEND); | 2963 | USB_PORT_FEAT_SUSPEND); |
2964 | /* | ||
2965 | * For system suspend, we do not need to enable the suspend feature | ||
2966 | * on individual USB-2 ports. The devices will automatically go | ||
2967 | * into suspend a few ms after the root hub stops sending packets. | ||
2968 | * The USB 2.0 spec calls this "global suspend". | ||
2969 | */ | ||
2970 | else { | ||
2971 | really_suspend = false; | ||
2972 | status = 0; | ||
2973 | } | ||
2961 | if (status) { | 2974 | if (status) { |
2962 | dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n", | 2975 | dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n", |
2963 | port1, status); | 2976 | port1, status); |
@@ -2993,8 +3006,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) | |||
2993 | (PMSG_IS_AUTO(msg) ? "auto-" : ""), | 3006 | (PMSG_IS_AUTO(msg) ? "auto-" : ""), |
2994 | udev->do_remote_wakeup); | 3007 | udev->do_remote_wakeup); |
2995 | usb_set_device_state(udev, USB_STATE_SUSPENDED); | 3008 | usb_set_device_state(udev, USB_STATE_SUSPENDED); |
2996 | udev->port_is_suspended = 1; | 3009 | if (really_suspend) { |
2997 | msleep(10); | 3010 | udev->port_is_suspended = 1; |
3011 | msleep(10); | ||
3012 | } | ||
2998 | } | 3013 | } |
2999 | 3014 | ||
3000 | /* | 3015 | /* |