Skip to content

Commit 83810f8

Browse files
matnymangregkh
authored andcommitted
xhci: turn off port power in shutdown
If ports are not turned off in shutdown then runtime suspended self-powered USB devices may survive in U3 link state over S5. During subsequent boot, if firmware sends an IPC command to program the port in DISCONNECT state, it will time out, causing significant delay in the boot time. Turning off roothub port power is also recommended in xhci specification 4.19.4 "Port Power" in the additional note. Cc: [email protected] Signed-off-by: Mathias Nyman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent a808925 commit 83810f8

File tree

3 files changed

+16
-3
lines changed

3 files changed

+16
-3
lines changed

drivers/usb/host/xhci-hub.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd)
652652
* It will release and re-aquire the lock while calling ACPI
653653
* method.
654654
*/
655-
static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
655+
void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
656656
u16 index, bool on, unsigned long *flags)
657657
__must_hold(&xhci->lock)
658658
{

drivers/usb/host/xhci.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,8 @@ static void xhci_stop(struct usb_hcd *hcd)
791791
void xhci_shutdown(struct usb_hcd *hcd)
792792
{
793793
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
794+
unsigned long flags;
795+
int i;
794796

795797
if (xhci->quirks & XHCI_SPURIOUS_REBOOT)
796798
usb_disable_xhci_ports(to_pci_dev(hcd->self.sysdev));
@@ -806,12 +808,21 @@ void xhci_shutdown(struct usb_hcd *hcd)
806808
del_timer_sync(&xhci->shared_hcd->rh_timer);
807809
}
808810

809-
spin_lock_irq(&xhci->lock);
811+
spin_lock_irqsave(&xhci->lock, flags);
810812
xhci_halt(xhci);
813+
814+
/* Power off USB2 ports*/
815+
for (i = 0; i < xhci->usb2_rhub.num_ports; i++)
816+
xhci_set_port_power(xhci, xhci->main_hcd, i, false, &flags);
817+
818+
/* Power off USB3 ports*/
819+
for (i = 0; i < xhci->usb3_rhub.num_ports; i++)
820+
xhci_set_port_power(xhci, xhci->shared_hcd, i, false, &flags);
821+
811822
/* Workaround for spurious wakeups at shutdown with HSW */
812823
if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
813824
xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
814-
spin_unlock_irq(&xhci->lock);
825+
spin_unlock_irqrestore(&xhci->lock, flags);
815826

816827
xhci_cleanup_msix(xhci);
817828

drivers/usb/host/xhci.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2196,6 +2196,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
21962196
int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
21972197
int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
21982198
struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd);
2199+
void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, u16 index,
2200+
bool on, unsigned long *flags);
21992201

22002202
void xhci_hc_died(struct xhci_hcd *xhci);
22012203

0 commit comments

Comments
 (0)