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

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
...@@ -379,8 +379,8 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -379,8 +379,8 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
ehci->reset_done [i] = 0; ehci->reset_done [i] = 0;
if ((temp & mask) != 0 if ((temp & mask) != 0
|| ((temp & PORT_RESUME) != 0 || ((temp & PORT_RESUME) != 0
&& time_after (jiffies, && time_after_eq(jiffies,
ehci->reset_done [i]))) { ehci->reset_done[i]))) {
if (i < 7) if (i < 7)
buf [0] |= 1 << (i + 1); buf [0] |= 1 << (i + 1);
else else
...@@ -554,11 +554,23 @@ static int ehci_hub_control ( ...@@ -554,11 +554,23 @@ static int ehci_hub_control (
status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT; status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
/* whoever resumes must GetPortStatus to complete it!! */ /* whoever resumes must GetPortStatus to complete it!! */
if ((temp & PORT_RESUME) if (temp & PORT_RESUME) {
&& time_after (jiffies,
ehci->reset_done [wIndex])) { /* 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; status |= 1 << USB_PORT_FEAT_C_SUSPEND;
ehci->reset_done [wIndex] = 0; ehci->reset_done[wIndex] = 0;
/* stop resume signaling */ /* stop resume signaling */
temp = ehci_readl(ehci, status_reg); temp = ehci_readl(ehci, status_reg);
...@@ -568,17 +580,19 @@ static int ehci_hub_control ( ...@@ -568,17 +580,19 @@ static int ehci_hub_control (
retval = handshake(ehci, status_reg, retval = handshake(ehci, status_reg,
PORT_RESUME, 0, 2000 /* 2msec */); PORT_RESUME, 0, 2000 /* 2msec */);
if (retval != 0) { if (retval != 0) {
ehci_err (ehci, "port %d resume error %d\n", ehci_err(ehci,
"port %d resume error %d\n",
wIndex + 1, retval); wIndex + 1, retval);
goto error; goto error;
} }
temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
} }
}
/* whoever resets must GetPortStatus to complete it!! */ /* whoever resets must GetPortStatus to complete it!! */
if ((temp & PORT_RESET) if ((temp & PORT_RESET)
&& time_after (jiffies, && time_after_eq(jiffies,
ehci->reset_done [wIndex])) { ehci->reset_done[wIndex])) {
status |= 1 << USB_PORT_FEAT_C_RESET; status |= 1 << USB_PORT_FEAT_C_RESET;
ehci->reset_done [wIndex] = 0; ehci->reset_done [wIndex] = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment