diff options
author | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2010-12-17 12:35:05 -0800 |
---|---|---|
committer | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2011-03-13 18:23:45 -0700 |
commit | 65b22f93fde320b34d43e4a3978e1b52b1bcc279 (patch) | |
tree | 087312018a0076866f28e056f1481db76cfe2b78 /drivers/usb | |
parent | f9de8151877b4f01cc8e124b0e213a6c6c78d970 (diff) |
xhci: Fix re-init on power loss after resume.
When a host controller has lost power during a suspend, we must
reinitialize it. Now that the xHCI host has two roothubs, xhci_run() and
xhci_stop() expect to be called with both usb_hcd structures. Be sure
that the re-initialization code in xhci_resume() mirrors the process the
USB PCI probe function uses.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/xhci.c | 23 |
1 files changed, 19 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 4549068758f..ce024dc7116 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -730,6 +730,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) { u32 command, temp = 0; struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct usb_hcd *secondary_hcd; int retval; /* Wait a bit if either of the roothubs need to settle from the @@ -790,15 +791,29 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) xhci_dbg(xhci, "xhci_stop completed - status = %x\n", xhci_readl(xhci, &xhci->op_regs->status)); - xhci_dbg(xhci, "Initialize the HCD\n"); - retval = xhci_init(hcd); + /* USB core calls the PCI reinit and start functions twice: + * first with the primary HCD, and then with the secondary HCD. + * If we don't do the same, the host will never be started. + */ + if (!usb_hcd_is_primary_hcd(hcd)) + secondary_hcd = hcd; + else + secondary_hcd = xhci->shared_hcd; + + xhci_dbg(xhci, "Initialize the xhci_hcd\n"); + retval = xhci_init(hcd->primary_hcd); if (retval) 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 HCD\n"); - retval = xhci_run(hcd); + xhci_dbg(xhci, "Start the secondary HCD\n"); + retval = xhci_run(secondary_hcd); if (!retval) set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); +failed_restart: hcd->state = HC_STATE_SUSPENDED; return retval; } |