| From 904df64a5f4d5ebd670801d869ca0a6d6a6e8df6 Mon Sep 17 00:00:00 2001 |
| From: Kai-Heng Feng <kai.heng.feng@canonical.com> |
| Date: Fri, 21 Aug 2020 12:15:48 +0300 |
| Subject: xhci: Do warm-reset when both CAS and XDEV_RESUME are set |
| |
| From: Kai-Heng Feng <kai.heng.feng@canonical.com> |
| |
| commit 904df64a5f4d5ebd670801d869ca0a6d6a6e8df6 upstream. |
| |
| Sometimes re-plugging a USB device during system sleep renders the device |
| useless: |
| [ 173.418345] xhci_hcd 0000:00:14.0: Get port status 2-4 read: 0x14203e2, return 0x10262 |
| ... |
| [ 176.496485] usb 2-4: Waited 2000ms for CONNECT |
| [ 176.496781] usb usb2-port4: status 0000.0262 after resume, -19 |
| [ 176.497103] usb 2-4: can't resume, status -19 |
| [ 176.497438] usb usb2-port4: logical disconnect |
| |
| Because PLS equals to XDEV_RESUME, xHCI driver reports U3 to usbcore, |
| despite of CAS bit is flagged. |
| |
| So proritize CAS over XDEV_RESUME to let usbcore handle warm-reset for |
| the port. |
| |
| Cc: stable <stable@vger.kernel.org> |
| Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com> |
| Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> |
| Link: https://lore.kernel.org/r/20200821091549.20556-3-mathias.nyman@linux.intel.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/host/xhci-hub.c | 19 ++++++++++--------- |
| 1 file changed, 10 insertions(+), 9 deletions(-) |
| |
| --- a/drivers/usb/host/xhci-hub.c |
| +++ b/drivers/usb/host/xhci-hub.c |
| @@ -623,15 +623,6 @@ static void xhci_hub_report_usb3_link_st |
| { |
| u32 pls = status_reg & PORT_PLS_MASK; |
| |
| - /* resume state is a xHCI internal state. |
| - * Do not report it to usb core, instead, pretend to be U3, |
| - * thus usb core knows it's not ready for transfer |
| - */ |
| - if (pls == XDEV_RESUME) { |
| - *status |= USB_SS_PORT_LS_U3; |
| - return; |
| - } |
| - |
| /* When the CAS bit is set then warm reset |
| * should be performed on port |
| */ |
| @@ -654,6 +645,16 @@ static void xhci_hub_report_usb3_link_st |
| pls |= USB_PORT_STAT_CONNECTION; |
| } else { |
| /* |
| + * Resume state is an xHCI internal state. Do not report it to |
| + * usb core, instead, pretend to be U3, thus usb core knows |
| + * it's not ready for transfer. |
| + */ |
| + if (pls == XDEV_RESUME) { |
| + *status |= USB_SS_PORT_LS_U3; |
| + return; |
| + } |
| + |
| + /* |
| * If CAS bit isn't set but the Port is already at |
| * Compliance Mode, fake a connection so the USB core |
| * notices the Compliance state and resets the port. |