diff mbox

[1/3] USB: Report wakeup events on root-hub ports

Message ID Pine.LNX.4.44L0.1806081654110.1285-100000@iolanthe.rowland.org (mailing list archive)
State New, archived
Headers show

Commit Message

Alan Stern June 8, 2018, 8:59 p.m. UTC
When a USB device attached to a root-hub port sends a wakeup request
to a sleeping system, we do not report the wakeup event to the PM
core.  This is because a system resume involves waking up all
suspended USB ports as quickly as possible; without the normal
USB_RESUME_TIMEOUT delay, the host controller driver doesn't set the
USB_PORT_STAT_C_SUSPEND flag and so usb_port_resume() doesn't realize
that a wakeup request was received.

However, some environments (such as Chrome OS) want to have all wakeup
events reported so they can be ascribed to the appropriate device.  To
accommodate these environments, this patch adds a new routine to the
hub driver and a corresponding new HCD method to be used when a root
hub resumes.  The HCD method returns a bitmap of ports that have
initiated a wakeup signal but not yet completed resuming.  The hub
driver can then report to the PM core that the child devices attached
to these ports initiated a wakeup event.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Suggested-by: Anshuman Gupta <anshuman.gupta@intel.com>

---


[as1867]


 drivers/usb/core/hub.c  |   42 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/hcd.h |    1 +
 2 files changed, 43 insertions(+)



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

Patch

Index: usb-4.x/drivers/usb/core/hub.c
===================================================================
--- usb-4.x.orig/drivers/usb/core/hub.c
+++ usb-4.x/drivers/usb/core/hub.c
@@ -3636,12 +3636,54 @@  static int hub_suspend(struct usb_interf
 	return 0;
 }
 
+/* Report wakeup requests from the ports of a resuming root hub */
+static void report_wakeup_requests(struct usb_hub *hub)
+{
+	struct usb_device	*hdev = hub->hdev;
+	struct usb_device	*udev;
+	struct usb_hcd		*hcd;
+	unsigned long		resuming_ports;
+	int			i;
+
+	if (hdev->parent)
+		return;		/* Not a root hub */
+
+	hcd = bus_to_hcd(hdev->bus);
+	if (hcd->driver->get_resuming_ports) {
+
+		/*
+		 * The get_resuming_ports() method returns a bitmap (origin 0)
+		 * of ports which have started wakeup signaling but have not
+		 * yet finished resuming.  During system resume we will
+		 * resume all the enabled ports, regardless of any wakeup
+		 * signals, which means the wakeup requests would be lost.
+		 * To prevent this, report them to the PM core here.
+		 */
+		resuming_ports = hcd->driver->get_resuming_ports(hcd);
+		for (i = 0; i < hdev->maxchild; ++i) {
+			if (test_bit(i, &resuming_ports)) {
+				udev = hub->ports[i]->child;
+				if (udev)
+					pm_wakeup_event(&udev->dev, 0);
+			}
+		}
+	}
+}
+
 static int hub_resume(struct usb_interface *intf)
 {
 	struct usb_hub *hub = usb_get_intfdata(intf);
 
 	dev_dbg(&intf->dev, "%s\n", __func__);
 	hub_activate(hub, HUB_RESUME);
+
+	/*
+	 * This should be called only for system resume, not runtime resume.
+	 * We can't tell the difference here, so some wakeup requests will be
+	 * reported at the wrong time or more than once.  This shouldn't
+	 * matter much, so long as they do get reported.
+	 */
+	report_wakeup_requests(hub);
 	return 0;
 }
 
Index: usb-4.x/include/linux/usb/hcd.h
===================================================================
--- usb-4.x.orig/include/linux/usb/hcd.h
+++ usb-4.x/include/linux/usb/hcd.h
@@ -322,6 +322,7 @@  struct hc_driver {
 	int	(*bus_suspend)(struct usb_hcd *);
 	int	(*bus_resume)(struct usb_hcd *);
 	int	(*start_port_reset)(struct usb_hcd *, unsigned port_num);
+	unsigned long	(*get_resuming_ports)(struct usb_hcd *);
 
 		/* force handover of high-speed port to full-speed companion */
 	void	(*relinquish_port)(struct usb_hcd *, int);