This patch (as1649) adds a mechanism for host controller drivers to
inform usbcore when they have begun or ended resume signalling on a
particular root-hub port.  The core will then make sure that the root
hub does not get runtime-suspended while the port resume is going on.

Since commit 596d789a211d134dc5f94d1e5957248c204ef850 (USB: set hub's
default autosuspend delay as 0), the system tries to suspend hubs
whenever they aren't in use.  While a root-hub port is being resumed,
the root hub does not appear to be in use.  Attempted runtime suspends
fail because of the ongoing port resume, but the PM core just keeps on
trying over and over again.  We want to prevent this wasteful effort.

Signed-off-by: Alan Stern <[email protected]>
Tested-by: Ming Lei <[email protected]>

---

 drivers/usb/core/hcd.c  |   44 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb.h     |    2 ++
 include/linux/usb/hcd.h |    3 +++
 3 files changed, 49 insertions(+)

Index: usb-3.8/include/linux/usb.h
===================================================================
--- usb-3.8.orig/include/linux/usb.h
+++ usb-3.8/include/linux/usb.h
@@ -357,6 +357,8 @@ struct usb_bus {
        int bandwidth_int_reqs;         /* number of Interrupt requests */
        int bandwidth_isoc_reqs;        /* number of Isoc. requests */
 
+       unsigned resuming_ports;        /* bit array: resuming root-hub ports */
+
 #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
        struct mon_bus *mon_bus;        /* non-null when associated */
        int monitored;                  /* non-zero when monitored */
Index: usb-3.8/include/linux/usb/hcd.h
===================================================================
--- usb-3.8.orig/include/linux/usb/hcd.h
+++ usb-3.8/include/linux/usb/hcd.h
@@ -430,6 +430,9 @@ extern void usb_hcd_poll_rh_status(struc
 extern void usb_wakeup_notification(struct usb_device *hdev,
                unsigned int portnum);
 
+extern void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum);
+extern void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum);
+
 /* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
 #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
 #define        usb_dotoggle(dev, ep, out)  ((dev)->toggle[out] ^= (1 << (ep)))
Index: usb-3.8/drivers/usb/core/hcd.c
===================================================================
--- usb-3.8.orig/drivers/usb/core/hcd.c
+++ usb-3.8/drivers/usb/core/hcd.c
@@ -39,6 +39,7 @@
 #include <asm/unaligned.h>
 #include <linux/platform_device.h>
 #include <linux/workqueue.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
@@ -1029,6 +1030,49 @@ static int register_root_hub(struct usb_
        return retval;
 }
 
+/*
+ * usb_hcd_start_port_resume - a root-hub port is sending a resume signal
+ * @bus: the bus which the root hub belongs to
+ * @portnum: the port which is being resumed
+ *
+ * HCDs should call this function when they know that a resume signal is
+ * being sent to a root-hub port.  The root hub will be prevented from
+ * going into autosuspend until usb_hcd_end_port_resume() is called.
+ *
+ * The bus's private lock must be held by the caller.
+ */
+void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum)
+{
+       unsigned bit = 1 << portnum;
+
+       if (!(bus->resuming_ports & bit)) {
+               bus->resuming_ports |= bit;
+               pm_runtime_get_noresume(&bus->root_hub->dev);
+       }
+}
+EXPORT_SYMBOL_GPL(usb_hcd_start_port_resume);
+
+/*
+ * usb_hcd_end_port_resume - a root-hub port has stopped sending a resume 
signal
+ * @bus: the bus which the root hub belongs to
+ * @portnum: the port which is being resumed
+ *
+ * HCDs should call this function when they know that a resume signal has
+ * stopped being sent to a root-hub port.  The root hub will be allowed to
+ * autosuspend again.
+ *
+ * The bus's private lock must be held by the caller.
+ */
+void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum)
+{
+       unsigned bit = 1 << portnum;
+
+       if (bus->resuming_ports & bit) {
+               bus->resuming_ports &= ~bit;
+               pm_runtime_put_noidle(&bus->root_hub->dev);
+       }
+}
+EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume);
 
 /*-------------------------------------------------------------------------*/
 

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

Reply via email to