Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 629e4427 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman
Browse files

EHCI: fix interrupt-driven remote wakeup



Now that port status change notifications are interrupt-driven,
ehci-hcd needs to tell usbcore when a remote-wakeup resume operation
is finished -- we can no longer rely on the core to poll and find
out.  This patch (as843) uses the root-hub status timer to force a
poll after the resume is complete.

The patch also changes the test for detecting when the TDRSMDN resume
period has expired.  It's necessary to use time_after_eq() instead of
time_after(), since the polling is triggered precisely by a timer.
The same change is made for TDRSTR reset expiration, for consistency.

Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 1d619f12
Loading
Loading
Loading
Loading
+32 −18
Original line number Diff line number Diff line
@@ -379,7 +379,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
			ehci->reset_done [i] = 0;
		if ((temp & mask) != 0
				|| ((temp & PORT_RESUME) != 0
					&& time_after (jiffies,
					&& time_after_eq(jiffies,
						ehci->reset_done[i]))) {
			if (i < 7)
			    buf [0] |= 1 << (i + 1);
@@ -554,8 +554,20 @@ static int ehci_hub_control (
			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;

		/* whoever resumes must GetPortStatus to complete it!! */
		if ((temp & PORT_RESUME)
				&& time_after (jiffies,
		if (temp & PORT_RESUME) {

			/* Remote Wakeup received? */
			if (!ehci->reset_done[wIndex]) {
				/* resume signaling for 20 msec */
				ehci->reset_done[wIndex] = jiffies
						+ msecs_to_jiffies(20);
				/* check the port again */
				mod_timer(&ehci_to_hcd(ehci)->rh_timer,
						ehci->reset_done[wIndex]);
			}

			/* resume completed? */
			else if (time_after_eq(jiffies,
					ehci->reset_done[wIndex])) {
				status |= 1 << USB_PORT_FEAT_C_SUSPEND;
				ehci->reset_done[wIndex] = 0;
@@ -568,16 +580,18 @@ static int ehci_hub_control (
				retval = handshake(ehci, status_reg,
					   PORT_RESUME, 0, 2000 /* 2msec */);
				if (retval != 0) {
				ehci_err (ehci, "port %d resume error %d\n",
					ehci_err(ehci,
						"port %d resume error %d\n",
						wIndex + 1, retval);
					goto error;
				}
				temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
			}
		}

		/* whoever resets must GetPortStatus to complete it!! */
		if ((temp & PORT_RESET)
				&& time_after (jiffies,
				&& time_after_eq(jiffies,
					ehci->reset_done[wIndex])) {
			status |= 1 << USB_PORT_FEAT_C_RESET;
			ehci->reset_done [wIndex] = 0;