diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-01-22 16:08:53 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-07 18:44:39 -0500 |
commit | 629e4427aa817d5c9f11885420abf54b8f5967dc (patch) | |
tree | 33c5a88751c5934df34252998a562fa757451b14 /drivers/usb/host/ehci-hub.c | |
parent | 1d619f128ba911cd3e6d6ad3475f146eb92f5c27 (diff) |
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: Alan Stern <stern@rowland.harvard.edu>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 50 |
1 files changed, 32 insertions, 18 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 3cfba69e0767..0d83c6df1a3b 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -379,8 +379,8 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
379 | ehci->reset_done [i] = 0; | 379 | ehci->reset_done [i] = 0; |
380 | if ((temp & mask) != 0 | 380 | if ((temp & mask) != 0 |
381 | || ((temp & PORT_RESUME) != 0 | 381 | || ((temp & PORT_RESUME) != 0 |
382 | && time_after (jiffies, | 382 | && time_after_eq(jiffies, |
383 | ehci->reset_done [i]))) { | 383 | ehci->reset_done[i]))) { |
384 | if (i < 7) | 384 | if (i < 7) |
385 | buf [0] |= 1 << (i + 1); | 385 | buf [0] |= 1 << (i + 1); |
386 | else | 386 | else |
@@ -554,31 +554,45 @@ static int ehci_hub_control ( | |||
554 | status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT; | 554 | status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT; |
555 | 555 | ||
556 | /* whoever resumes must GetPortStatus to complete it!! */ | 556 | /* whoever resumes must GetPortStatus to complete it!! */ |
557 | if ((temp & PORT_RESUME) | 557 | if (temp & PORT_RESUME) { |
558 | && time_after (jiffies, | ||
559 | ehci->reset_done [wIndex])) { | ||
560 | status |= 1 << USB_PORT_FEAT_C_SUSPEND; | ||
561 | ehci->reset_done [wIndex] = 0; | ||
562 | 558 | ||
563 | /* stop resume signaling */ | 559 | /* Remote Wakeup received? */ |
564 | temp = ehci_readl(ehci, status_reg); | 560 | if (!ehci->reset_done[wIndex]) { |
565 | ehci_writel(ehci, | 561 | /* resume signaling for 20 msec */ |
562 | ehci->reset_done[wIndex] = jiffies | ||
563 | + msecs_to_jiffies(20); | ||
564 | /* check the port again */ | ||
565 | mod_timer(&ehci_to_hcd(ehci)->rh_timer, | ||
566 | ehci->reset_done[wIndex]); | ||
567 | } | ||
568 | |||
569 | /* resume completed? */ | ||
570 | else if (time_after_eq(jiffies, | ||
571 | ehci->reset_done[wIndex])) { | ||
572 | status |= 1 << USB_PORT_FEAT_C_SUSPEND; | ||
573 | ehci->reset_done[wIndex] = 0; | ||
574 | |||
575 | /* stop resume signaling */ | ||
576 | temp = ehci_readl(ehci, status_reg); | ||
577 | ehci_writel(ehci, | ||
566 | temp & ~(PORT_RWC_BITS | PORT_RESUME), | 578 | temp & ~(PORT_RWC_BITS | PORT_RESUME), |
567 | status_reg); | 579 | status_reg); |
568 | retval = handshake(ehci, status_reg, | 580 | retval = handshake(ehci, status_reg, |
569 | PORT_RESUME, 0, 2000 /* 2msec */); | 581 | PORT_RESUME, 0, 2000 /* 2msec */); |
570 | if (retval != 0) { | 582 | if (retval != 0) { |
571 | ehci_err (ehci, "port %d resume error %d\n", | 583 | ehci_err(ehci, |
572 | wIndex + 1, retval); | 584 | "port %d resume error %d\n", |
573 | goto error; | 585 | wIndex + 1, retval); |
586 | goto error; | ||
587 | } | ||
588 | temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); | ||
574 | } | 589 | } |
575 | temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); | ||
576 | } | 590 | } |
577 | 591 | ||
578 | /* whoever resets must GetPortStatus to complete it!! */ | 592 | /* whoever resets must GetPortStatus to complete it!! */ |
579 | if ((temp & PORT_RESET) | 593 | if ((temp & PORT_RESET) |
580 | && time_after (jiffies, | 594 | && time_after_eq(jiffies, |
581 | ehci->reset_done [wIndex])) { | 595 | ehci->reset_done[wIndex])) { |
582 | status |= 1 << USB_PORT_FEAT_C_RESET; | 596 | status |= 1 << USB_PORT_FEAT_C_RESET; |
583 | ehci->reset_done [wIndex] = 0; | 597 | ehci->reset_done [wIndex] = 0; |
584 | 598 | ||