xhci: Fix re-init on power loss after resume.
authorSarah Sharp <sarah.a.sharp@linux.intel.com>
Fri, 17 Dec 2010 20:35:05 +0000 (12:35 -0800)
committerSarah Sharp <sarah.a.sharp@linux.intel.com>
Mon, 14 Mar 2011 01:23:45 +0000 (18:23 -0700)
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>
drivers/usb/host/xhci.c

index 4549068..ce024dc 100644 (file)
@@ -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;
        }