diff mbox

[J/Unstable/OEM-5.15/OEM-5.17,1/1] UBUNTU: SAUCE: xhci: turn off port power in shutdown

Message ID 20220601130223.68409-3-kai.heng.feng@canonical.com
State New
Headers show

Commit Message

Kai-Heng Feng June 1, 2022, 1:02 p.m. UTC
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>
---
 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(-)

Comments

Andrea Righi June 23, 2022, 1:07 p.m. UTC | #1
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
Stefan Bader Aug. 2, 2022, 8:37 a.m. UTC | #2
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 mbox

Patch

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);