Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+19 -4
+19 -4
drivers/usb/host/xhci.c
··· 730 730 { 731 731 u32 command, temp = 0; 732 732 struct usb_hcd *hcd = xhci_to_hcd(xhci); 733 + struct usb_hcd *secondary_hcd; 733 734 int retval; 734 735 735 736 /* Wait a bit if either of the roothubs need to settle from the ··· 791 790 xhci_dbg(xhci, "xhci_stop completed - status = %x\n", 792 791 xhci_readl(xhci, &xhci->op_regs->status)); 793 792 794 - xhci_dbg(xhci, "Initialize the HCD\n"); 795 - retval = xhci_init(hcd); 793 + /* USB core calls the PCI reinit and start functions twice: 794 + * first with the primary HCD, and then with the secondary HCD. 795 + * If we don't do the same, the host will never be started. 796 + */ 797 + if (!usb_hcd_is_primary_hcd(hcd)) 798 + secondary_hcd = hcd; 799 + else 800 + secondary_hcd = xhci->shared_hcd; 801 + 802 + xhci_dbg(xhci, "Initialize the xhci_hcd\n"); 803 + retval = xhci_init(hcd->primary_hcd); 796 804 if (retval) 797 805 return retval; 806 + xhci_dbg(xhci, "Start the primary HCD\n"); 807 + retval = xhci_run(hcd->primary_hcd); 808 + if (retval) 809 + goto failed_restart; 798 810 799 - xhci_dbg(xhci, "Start the HCD\n"); 800 - retval = xhci_run(hcd); 811 + xhci_dbg(xhci, "Start the secondary HCD\n"); 812 + retval = xhci_run(secondary_hcd); 801 813 if (!retval) 802 814 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 815 + failed_restart: 803 816 hcd->state = HC_STATE_SUSPENDED; 804 817 return retval; 805 818 }