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

USB: XHCI: resume root hubs when the controller resumes

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: default avatarAlan Stern <stern@rowland.harvard.edu>
CC: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: stable <stable@vger.kernel.org>
Tested-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 97ff22ee
...@@ -799,7 +799,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) ...@@ -799,7 +799,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
u32 command, temp = 0; u32 command, temp = 0;
struct usb_hcd *hcd = xhci_to_hcd(xhci); struct usb_hcd *hcd = xhci_to_hcd(xhci);
struct usb_hcd *secondary_hcd; struct usb_hcd *secondary_hcd;
int retval; int retval = 0;
/* Wait a bit if either of the roothubs need to settle from the /* Wait a bit if either of the roothubs need to settle from the
* transition into bus suspend. * transition into bus suspend.
...@@ -809,6 +809,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) ...@@ -809,6 +809,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
xhci->bus_state[1].next_statechange)) xhci->bus_state[1].next_statechange))
msleep(100); 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); spin_lock_irq(&xhci->lock);
if (xhci->quirks & XHCI_RESET_ON_RESUME) if (xhci->quirks & XHCI_RESET_ON_RESUME)
hibernated = true; hibernated = true;
...@@ -878,20 +881,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) ...@@ -878,20 +881,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
return retval; return retval;
xhci_dbg(xhci, "Start the primary HCD\n"); xhci_dbg(xhci, "Start the primary HCD\n");
retval = xhci_run(hcd->primary_hcd); 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) { if (!retval) {
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); xhci_dbg(xhci, "Start the secondary HCD\n");
set_bit(HCD_FLAG_HW_ACCESSIBLE, retval = xhci_run(secondary_hcd);
&xhci->shared_hcd->flags);
} }
failed_restart:
hcd->state = HC_STATE_SUSPENDED; hcd->state = HC_STATE_SUSPENDED;
xhci->shared_hcd->state = HC_STATE_SUSPENDED; xhci->shared_hcd->state = HC_STATE_SUSPENDED;
return retval; goto done;
} }
/* step 4: set Run/Stop bit */ /* step 4: set Run/Stop bit */
...@@ -910,11 +906,14 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) ...@@ -910,11 +906,14 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
* Running endpoints by ringing their doorbells * 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); 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 */ #endif /* CONFIG_PM */
......
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