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 <st...@rowland.harvard.edu>
CC: Peter Chen <peter.c...@freescale.com>

---

 drivers/usb/core/hub.c |   30 +++++++++++++++++++++++-------
 1 file changed, 23 insertions(+), 7 deletions(-)

Index: usb-3.9/drivers/usb/core/hub.c
===================================================================
--- usb-3.9.orig/drivers/usb/core/hub.c
+++ usb-3.9/drivers/usb/core/hub.c
@@ -2882,9 +2882,11 @@ static int usb_disable_function_remotewa
  * 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.
  */
@@ -2895,6 +2897,7 @@ int usb_port_suspend(struct usb_device *
        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).
@@ -2951,9 +2954,19 @@ int usb_port_suspend(struct usb_device *
        /* 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);
@@ -2989,8 +3002,10 @@ int usb_port_suspend(struct usb_device *
                                (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);
+               }
        }
 
        /*

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to