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 11:06:27 -0700 |
commit | 0aa2832dd0d9d8609fd8f15139bc7572541a1215 (patch) | |
tree | 9537cc80217eca1614ca988a87b34170b8dbcc8f /drivers/usb | |
parent | e9e88fb7bca9f527ccdf4166a240a9023ba6ee73 (diff) | |
download | op-kernel-dev-0aa2832dd0d9d8609fd8f15139bc7572541a1215.zip op-kernel-dev-0aa2832dd0d9d8609fd8f15139bc7572541a1215.tar.gz |
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>
Diffstat (limited to 'drivers/usb')
-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 669da9e..443d5cc 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) * Linux (2.6) currently has NO mechanisms to initiate that: no khubd * timer, no SRP, no requests through sysfs. * - * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when - * the root hub for their bus goes into global suspend ... so we don't - * (falsely) update the device power state to say it suspended. + * If CONFIG_USB_SUSPEND isn't enabled, non-SuperSpeed devices really get + * suspended only when their bus goes into global suspend (i.e., the root + * hub is suspended). Nevertheless, we change @udev->state to + * USB_STATE_SUSPENDED as this is the device's "logical" state. The actual + * upstream port setting is stored in @udev->port_is_suspended. * * Returns 0 on success, else negative errno. */ @@ -2899,6 +2901,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) enum pm_qos_flags_status pm_qos_stat; int port1 = udev->portnum; int status; + bool really_suspend = true; /* enable remote wakeup when appropriate; this lets the device * 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) /* see 7.1.7.6 */ if (hub_is_superspeed(hub->hdev)) status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3); - else + else if (PMSG_IS_AUTO(msg)) status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND); + /* + * For system suspend, we do not need to enable the suspend feature + * on individual USB-2 ports. The devices will automatically go + * into suspend a few ms after the root hub stops sending packets. + * The USB 2.0 spec calls this "global suspend". + */ + else { + really_suspend = false; + status = 0; + } if (status) { dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n", port1, status); @@ -2993,8 +3006,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) (PMSG_IS_AUTO(msg) ? "auto-" : ""), udev->do_remote_wakeup); usb_set_device_state(udev, USB_STATE_SUSPENDED); - udev->port_is_suspended = 1; - msleep(10); + if (really_suspend) { + udev->port_is_suspended = 1; + msleep(10); + } } /* |