| From f69e3120df82391a0ee8118e0a156239a06b2afb Mon Sep 17 00:00:00 2001 |
| From: Alan Stern <stern@rowland.harvard.edu> |
| Date: Thu, 3 Nov 2011 11:37:10 -0400 |
| Subject: USB: XHCI: resume root hubs when the controller resumes |
| |
| From: Alan Stern <stern@rowland.harvard.edu> |
| |
| commit f69e3120df82391a0ee8118e0a156239a06b2afb upstream. |
| |
| This patch (as1494) fixes a problem in xhci-hcd's resume routine. |
| When the controller is runtime-resumed, this can only mean that one of |
| the two root hubs has made a wakeup request and therefore needs to be |
| resumed as well. Rather than try to determine which root hub requires |
| attention (which might be difficult in the case where a new |
| non-SuperSpeed device has been plugged in), the patch simply resumes |
| both root hubs. |
| |
| Without this change, there is a race: The controller might be put back |
| to sleep before it can activate its IRQ line, and the wakeup condition |
| might never get handled. |
| |
| The patch also simplifies the logic in xhci_resume a little, combining |
| some repeated flag settings into a single pair of statements. |
| |
| Signed-off-by: Alan Stern <stern@rowland.harvard.edu> |
| CC: Sarah Sharp <sarah.a.sharp@linux.intel.com> |
| Tested-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/usb/host/xhci.c | 29 ++++++++++++++--------------- |
| 1 file changed, 14 insertions(+), 15 deletions(-) |
| |
| --- a/drivers/usb/host/xhci.c |
| +++ b/drivers/usb/host/xhci.c |
| @@ -749,7 +749,7 @@ int xhci_resume(struct xhci_hcd *xhci, b |
| u32 command, temp = 0; |
| struct usb_hcd *hcd = xhci_to_hcd(xhci); |
| struct usb_hcd *secondary_hcd; |
| - int retval; |
| + int retval = 0; |
| |
| /* Wait a bit if either of the roothubs need to settle from the |
| * transition into bus suspend. |
| @@ -759,6 +759,9 @@ int xhci_resume(struct xhci_hcd *xhci, b |
| xhci->bus_state[1].next_statechange)) |
| msleep(100); |
| |
| + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
| + set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); |
| + |
| spin_lock_irq(&xhci->lock); |
| if (xhci->quirks & XHCI_RESET_ON_RESUME) |
| hibernated = true; |
| @@ -828,20 +831,13 @@ int xhci_resume(struct xhci_hcd *xhci, b |
| return retval; |
| xhci_dbg(xhci, "Start the primary HCD\n"); |
| retval = xhci_run(hcd->primary_hcd); |
| - if (retval) |
| - goto failed_restart; |
| - |
| - xhci_dbg(xhci, "Start the secondary HCD\n"); |
| - retval = xhci_run(secondary_hcd); |
| if (!retval) { |
| - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
| - set_bit(HCD_FLAG_HW_ACCESSIBLE, |
| - &xhci->shared_hcd->flags); |
| + xhci_dbg(xhci, "Start the secondary HCD\n"); |
| + retval = xhci_run(secondary_hcd); |
| } |
| -failed_restart: |
| hcd->state = HC_STATE_SUSPENDED; |
| xhci->shared_hcd->state = HC_STATE_SUSPENDED; |
| - return retval; |
| + goto done; |
| } |
| |
| /* step 4: set Run/Stop bit */ |
| @@ -860,11 +856,14 @@ failed_restart: |
| * Running endpoints by ringing their doorbells |
| */ |
| |
| - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
| - set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); |
| - |
| spin_unlock_irq(&xhci->lock); |
| - return 0; |
| + |
| + done: |
| + if (retval == 0) { |
| + usb_hcd_resume_root_hub(hcd); |
| + usb_hcd_resume_root_hub(xhci->shared_hcd); |
| + } |
| + return retval; |
| } |
| #endif /* CONFIG_PM */ |
| |