Message ID | 20220601130223.68409-3-kai.heng.feng@canonical.com |
---|---|
State | New |
Headers | show |
On Wed, Jun 01, 2022 at 09:02:23PM +0800, Kai-Heng Feng wrote: > From: Mathias Nyman <mathias.nyman@linux.intel.com> > > BugLink: https://bugs.launchpad.net/bugs/1976503 > > 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. > > Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> > (cherry picked from commit 1f6e23bcb9b2a2981d1124e4adb1f463cbc769ba git://git.kernel.org/pub/scm/linux/kernel/git/mnyman/xhci.git for-usb-linus) > Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com> Applied to linux-unstable. Thanks! -Andrea
On 01.06.22 15:02, Kai-Heng Feng wrote: > From: Mathias Nyman <mathias.nyman@linux.intel.com> > > BugLink: https://bugs.launchpad.net/bugs/1976503 > > 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. > > Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> > (cherry picked from commit 1f6e23bcb9b2a2981d1124e4adb1f463cbc769ba git://git.kernel.org/pub/scm/linux/kernel/git/mnyman/xhci.git for-usb-linus) > Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com> > --- The first patch arrived via stable v5.15.38 since submission. The second patch went upstream and was cherry picked from b4cf2ad7b9d7 instead. Note that the upstream patch powers off USB2 ports first and then USB3 ports while the SAUCE patch did this in the opposite order. Applied to jammy:linux/master-next. Thanks. -Stefan > drivers/usb/host/xhci-hub.c | 2 +- > drivers/usb/host/xhci.c | 14 ++++++++++++-- > drivers/usb/host/xhci.h | 2 ++ > 3 files changed, 15 insertions(+), 3 deletions(-) > > diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c > index 426120e8329b4..dd6fec90de309 100644 > --- a/drivers/usb/host/xhci-hub.c > +++ b/drivers/usb/host/xhci-hub.c > @@ -652,7 +652,7 @@ struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd) > * It will release and re-aquire the lock while calling ACPI > * method. > */ > -static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, > +void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, > u16 index, bool on, unsigned long *flags) > __must_hold(&xhci->lock) > { > diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c > index 0c07c7c4a84b9..25ef61298fe18 100644 > --- a/drivers/usb/host/xhci.c > +++ b/drivers/usb/host/xhci.c > @@ -774,6 +774,8 @@ static void xhci_stop(struct usb_hcd *hcd) > void xhci_shutdown(struct usb_hcd *hcd) > { > struct xhci_hcd *xhci = hcd_to_xhci(hcd); > + unsigned long flags; > + int i; > > if (xhci->quirks & XHCI_SPURIOUS_REBOOT) > usb_disable_xhci_ports(to_pci_dev(hcd->self.sysdev)); > @@ -789,12 +791,20 @@ void xhci_shutdown(struct usb_hcd *hcd) > del_timer_sync(&xhci->shared_hcd->rh_timer); > } > > - spin_lock_irq(&xhci->lock); > + spin_lock_irqsave(&xhci->lock, flags); > xhci_halt(xhci); > + > + /* Power off USB3 ports*/ > + for (i = 0; i < xhci->usb3_rhub.num_ports; i++) > + xhci_set_port_power(xhci, xhci->shared_hcd, i, false, &flags); > + /* Power off USB2 ports*/ > + for (i = 0; i < xhci->usb2_rhub.num_ports; i++) > + xhci_set_port_power(xhci, xhci->main_hcd, i, false, &flags); > + > /* Workaround for spurious wakeups at shutdown with HSW */ > if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) > xhci_reset(xhci, XHCI_RESET_SHORT_USEC); > - spin_unlock_irq(&xhci->lock); > + spin_unlock_irqrestore(&xhci->lock, flags); > > xhci_cleanup_msix(xhci); > > diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h > index bc0789229527f..79fa34f1e31c4 100644 > --- a/drivers/usb/host/xhci.h > +++ b/drivers/usb/host/xhci.h > @@ -2174,6 +2174,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, > int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); > int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1); > struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd); > +void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, u16 index, > + bool on, unsigned long *flags); > > void xhci_hc_died(struct xhci_hcd *xhci); >
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 426120e8329b4..dd6fec90de309 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -652,7 +652,7 @@ struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd) * It will release and re-aquire the lock while calling ACPI * method. */ -static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, +void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, u16 index, bool on, unsigned long *flags) __must_hold(&xhci->lock) { diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 0c07c7c4a84b9..25ef61298fe18 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -774,6 +774,8 @@ static void xhci_stop(struct usb_hcd *hcd) void xhci_shutdown(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); + unsigned long flags; + int i; if (xhci->quirks & XHCI_SPURIOUS_REBOOT) usb_disable_xhci_ports(to_pci_dev(hcd->self.sysdev)); @@ -789,12 +791,20 @@ void xhci_shutdown(struct usb_hcd *hcd) del_timer_sync(&xhci->shared_hcd->rh_timer); } - spin_lock_irq(&xhci->lock); + spin_lock_irqsave(&xhci->lock, flags); xhci_halt(xhci); + + /* Power off USB3 ports*/ + for (i = 0; i < xhci->usb3_rhub.num_ports; i++) + xhci_set_port_power(xhci, xhci->shared_hcd, i, false, &flags); + /* Power off USB2 ports*/ + for (i = 0; i < xhci->usb2_rhub.num_ports; i++) + xhci_set_port_power(xhci, xhci->main_hcd, i, false, &flags); + /* Workaround for spurious wakeups at shutdown with HSW */ if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) xhci_reset(xhci, XHCI_RESET_SHORT_USEC); - spin_unlock_irq(&xhci->lock); + spin_unlock_irqrestore(&xhci->lock, flags); xhci_cleanup_msix(xhci); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index bc0789229527f..79fa34f1e31c4 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2174,6 +2174,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1); struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd); +void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, u16 index, + bool on, unsigned long *flags); void xhci_hc_died(struct xhci_hcd *xhci);