Thread (7 messages) 7 messages, 2 authors, 2020-05-07

Re: [PATCH v2] xhci: Set port link to RxDetect if port is not enabled after resume

From: Kai-Heng Feng <hidden>
Date: 2020-05-07 04:52:37
Also in: lkml
Subsystem: the rest, usb subsystem, usb xhci driver · Maintainers: Linus Torvalds, Greg Kroah-Hartman, Mathias Nyman

On Apr 28, 2020, at 00:49, Mathias Nyman [off-list ref] wrote:

On 27.4.2020 12.05, Kai-Heng Feng wrote:
quoted
quoted
On Apr 23, 2020, at 19:25, Mathias Nyman [off-list ref] wrote:

Was this roothub port forcefully suspended xhci_bus_suspend()?
i.e. was a bit set in bus_state->bus_suspended for this port?
No, it's a USB3 device so it was set to U3 via USB_PORT_FEAT_LINK_STATE.
Logs show port was first forced by xhci_bus_suspend() to U3  ("port 0 not
suspended" message)
and only later set to U3 by USB_PORT_FEAT_LINK_STATE.
Seems line wrong order or race.
The "port 0 not suspended" is actually for 3-1, if we print bus num and port + 1:
[  213.732977] xhci_hcd 0000:3f:00.0: port 3-1 not suspended

For port 4-1 it's always suspended before suspend the bus.
I'll send a patch to adjust the debug message for better clarity.
while suspended we get a port event about a connect status change,
showing port link state is in disabled.
Cherry picked messages:

[ 1330.021450] xhci_hcd 0000:3f:00.0: port 0 not suspended
[ 1330.036822] xhci_hcd 0000:3f:00.0: Set port 4-1 link state, portsc: 0x1203, write 0x11261
[ 1331.020736] xhci_hcd 0000:3f:00.0: Port change event, 4-1, id 1, portsc: 0x20280
[ 1331.020738] xhci_hcd 0000:3f:00.0: resume root hub
[ 1331.020741] xhci_hcd 0000:3f:00.0: handle_port_status: starting port polling.

If we force the port link state to U3 in xhci_bus_suspend() maybe it would make
sense to try and recover it in xhci_bus_resume(). But only for that forced
port.

None of the previous suspend/resume cycles in the logs went smooth either.
Each time device 4-1 was forced to U3 bus xhci_bus_suspend(), and at resume the
link was stuck in polling until timeout, after which it went to compliance mode,
and had to be warm reset to recover.
If my observation above is true, port 4-1 is indeed suspended by usb_port_suspend() rather than xhci_bus_suspend().
We could add the code to recover USB3 ports from disabled state in case we
forced them to U3, but the rootcause of theus suspend/resume issues should
be found as well
Seems like the issue doesn't happen if the host system use S2Idle instead of S3.
However, I can't see any difference in xHCI driver with different suspend methods.
Maybe the root cause is that, ASMedia controller and SMSC hub are just quirky?
quoted hunk ↗ jump to hunk
Limiting your code to USB3 devices that xhi_bus_suspend forced to U3 would look
something like this:
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 9eca1fe81061..0f16dd936ab8 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1789,6 +1789,15 @@ int xhci_bus_resume(struct usb_hcd *hcd)
			case XDEV_RESUME:
				/* resume already initiated */
				break;
+			case XDEV_DISABLED:
+				if (hcd->speed >= HCD_USB3) {
+					portsc = xhci_port_state_to_neutral(
+						portsc);
+					portsc &= ~PORT_PLS_MASK;
+					portsc |= PORT_LINK_STROBE |
+						XDEV_RXDETECT;
+				}
+				/* fall through for both USB3 abd USB2 */
			default:
				/* not in a resumeable state, ignore it */
				clear_bit(port_index,
This doesn't work because port 4-1 isn't suspended by xhci_bus_suspend().

Maybe we can restrict the case to ports that are suspended by USB_PORT_FEAT_LINK_STATE.
Is the following patch looks good to you?
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index f37316d2c8fa..dc2e14ea308d 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1787,6 +1787,16 @@ int xhci_bus_resume(struct usb_hcd *hcd)
                        clear_bit(port_index, &bus_state->bus_suspended);
                        continue;
                }
+
+               if (bus_state->suspended_ports & (1 << port_index)) {
+                       if ((portsc & PORT_PLS_MASK) == XDEV_DISABLED &&
+                           hcd->speed >= HCD_USB3) {
+                               portsc = xhci_port_state_to_neutral(portsc);
+                               portsc &= ~PORT_PLS_MASK;
+                               portsc |= PORT_LINK_STROBE | XDEV_RXDETECT;
+                       }
+               }
+
                /* resume if we suspended the link, and it is still suspended */
                if (test_bit(port_index, &bus_state->bus_suspended))
                        switch (portsc & PORT_PLS_MASK) {

Kai-Heng
-Mathias
  
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help