Skip to contentSkip to conversation

patch "xhci: prevent bus_suspend if SS port resuming in phase 1" added to usb-linus

PATCH [email protected] 1 participant 1 message Jul 22, 2015

Subsystems (3)
lore
Share & tools
lore

[email protected]

author maintainer Applied
#0 lore raw

This is a note to let you know that I've just added the patch titled

xhci: prevent bus_suspend if SS port resuming in phase 1

to my usb git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
in the usb-linus branch.

The patch will show up in the next release of the linux-next tree (usually sometime within the next 24 hours during the week.)

The patch will hopefully also be merged in Linus's tree for the next -rc kernel release.

If you have any questions about this process, please let me know.

Quoted 1 line

From fac4271d1126c45ceaceb7f4a336317b771eb121 Mon Sep 17 00:00:00 2001

From: Zhuang Jin Can <[email protected]>
Date: Tue, 21 Jul 2015 17:20:30 +0300
Subject: xhci: prevent bus_suspend if SS port resuming in phase 1

When the link is just waken, it's in Resume state, and driver sets PLS to U0. This refers to Phase 1. Phase 2 refers to when the link has completed the transition from Resume state to U0.

With the fix of xhci: report U3 when link is in resume state, it also exposes an issue that usb3 roothub and controller can suspend right after phase 1, and this causes a hard hang in controller.

To fix the issue, we need to prevent usb3 bus suspend if any port is resuming in phase 1.

[merge separate USB2 and USB3 port resume checking to one -Mathias]
---
 drivers/usb/host/xhci-hub.c  | 6 +++---
 drivers/usb/host/xhci-ring.c | 3 +++
 drivers/usb/host/xhci.h      | 1 +
 3 files changed, 7 insertions(+), 3 deletions(-)
drivers/usb/host/xhci-hub.c +3 -3
index 7df8878cc37b..fdca8edc5836 100644
@@ -1123,10 +1123,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
 	spin_lock_irqsave(&xhci->lock, flags);
 
 	if (hcd->self.root_hub->do_remote_wakeup) {
-		if (bus_state->resuming_ports) {
+		if (bus_state->resuming_ports ||	/* USB2 */
+		    bus_state->port_remote_wakeup) {	/* USB3 */
 			spin_unlock_irqrestore(&xhci->lock, flags);
-			xhci_dbg(xhci, "suspend failed because "
-						"a port is resuming\n");
+			xhci_dbg(xhci, "suspend failed because a port is resuming\n");
 			return -EBUSY;
 		}
 	}
drivers/usb/host/xhci-ring.c +3 -0
index 94416ff70810..6a8fc52aed58 100644
@@ -1546,6 +1546,9 @@ static void handle_port_status(struct xhci_hcd *xhci,
 		usb_hcd_resume_root_hub(hcd);
 	}
 
+	if (hcd->speed == HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE)
+		bus_state->port_remote_wakeup &= ~(1 << faked_port_index);
+
 	if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) {
 		xhci_dbg(xhci, "port resume event for port %d\n", port_id);
 
drivers/usb/host/xhci.h +1 -0
index 31e46cc55807..ed2ebf647c38 100644
@@ -285,6 +285,7 @@ struct xhci_op_regs {
 #define XDEV_U0		(0x0 << 5)
 #define XDEV_U2		(0x2 << 5)
 #define XDEV_U3		(0x3 << 5)
+#define XDEV_INACTIVE	(0x6 << 5)
 #define XDEV_RESUME	(0xf << 5)
 /* true: port has power (see HCC_PPC) */
 #define PORT_POWER	(1 << 9)
Signature · 1 line
2.4.6