From 42ed15c43186e5bd63e04a9987944629062500d3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 19 Dec 2019 16:05:23 +0100 Subject: [PATCH] 4.19-stable patches added patches: xhci-fix-usb3-device-initiated-resume-race-with-roothub-autosuspend.patch --- queue-4.19/series | 1 + ...resume-race-with-roothub-autosuspend.patch | 101 ++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 queue-4.19/xhci-fix-usb3-device-initiated-resume-race-with-roothub-autosuspend.patch diff --git a/queue-4.19/series b/queue-4.19/series index 2eb2acfb86e..94657c5545e 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -44,3 +44,4 @@ dm-btree-increase-rebalance-threshold-in-__rebalance2.patch scsi-iscsi-fix-a-potential-deadlock-in-the-timeout-handler.patch scsi-qla2xxx-change-discovery-state-before-plogi.patch drm-radeon-fix-r1xx-r2xx-register-checker-for-pot-textures.patch +xhci-fix-usb3-device-initiated-resume-race-with-roothub-autosuspend.patch diff --git a/queue-4.19/xhci-fix-usb3-device-initiated-resume-race-with-roothub-autosuspend.patch b/queue-4.19/xhci-fix-usb3-device-initiated-resume-race-with-roothub-autosuspend.patch new file mode 100644 index 00000000000..7772db91f45 --- /dev/null +++ b/queue-4.19/xhci-fix-usb3-device-initiated-resume-race-with-roothub-autosuspend.patch @@ -0,0 +1,101 @@ +From 057d476fff778f1d3b9f861fdb5437ea1a3cfc99 Mon Sep 17 00:00:00 2001 +From: Mathias Nyman +Date: Wed, 11 Dec 2019 16:20:03 +0200 +Subject: xhci: fix USB3 device initiated resume race with roothub autosuspend + +From: Mathias Nyman + +commit 057d476fff778f1d3b9f861fdb5437ea1a3cfc99 upstream. + +A race in xhci USB3 remote wake handling may force device back to suspend +after it initiated resume siganaling, causing a missed resume event or warm +reset of device. + +When a USB3 link completes resume signaling and goes to enabled (UO) +state a interrupt is issued and the interrupt handler will clear the +bus_state->port_remote_wakeup resume flag, allowing bus suspend. + +If the USB3 roothub thread just finished reading port status before +the interrupt, finding ports still in suspended (U3) state, but hasn't +yet started suspending the hub, then the xhci interrupt handler will clear +the flag that prevented roothub suspend and allow bus to suspend, forcing +all port links back to suspended (U3) state. + +Example case: +usb_runtime_suspend() # because all ports still show suspended U3 + usb_suspend_both() + hub_suspend(); # successful as hub->wakeup_bits not set yet +==> INTERRUPT +xhci_irq() + handle_port_status() + clear bus_state->port_remote_wakeup + usb_wakeup_notification() + sets hub->wakeup_bits; + kick_hub_wq() +<== END INTERRUPT + hcd_bus_suspend() + xhci_bus_suspend() # success as port_remote_wakeup bits cleared + +Fix this by increasing roothub usage count during port resume to prevent +roothub autosuspend, and by making sure bus_state->port_remote_wakeup +flag is only cleared after resume completion is visible, i.e. +after xhci roothub returned U0 or other non-U3 link state link on a +get port status request. + +Issue rootcaused by Chiasheng Lee + +Cc: +Cc: Lee, Hou-hsun +Reported-by: Lee, Chiasheng +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20191211142007.8847-3-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci-hub.c | 8 ++++++++ + drivers/usb/host/xhci-ring.c | 3 +-- + 2 files changed, 9 insertions(+), 2 deletions(-) + +--- a/drivers/usb/host/xhci-hub.c ++++ b/drivers/usb/host/xhci-hub.c +@@ -868,6 +868,14 @@ static u32 xhci_get_port_status(struct u + status |= USB_PORT_STAT_C_BH_RESET << 16; + if ((raw_port_status & PORT_CEC)) + status |= USB_PORT_STAT_C_CONFIG_ERROR << 16; ++ ++ /* USB3 remote wake resume signaling completed */ ++ if (bus_state->port_remote_wakeup & (1 << wIndex) && ++ (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME && ++ (raw_port_status & PORT_PLS_MASK) != XDEV_RECOVERY) { ++ bus_state->port_remote_wakeup &= ~(1 << wIndex); ++ usb_hcd_end_port_resume(&hcd->self, wIndex); ++ } + } + + if (hcd->speed < HCD_USB3) { +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -1609,7 +1609,6 @@ static void handle_port_status(struct xh + slot_id = xhci_find_slot_id_by_port(hcd, xhci, hcd_portnum + 1); + if (slot_id && xhci->devs[slot_id]) + xhci->devs[slot_id]->flags |= VDEV_PORT_ERROR; +- bus_state->port_remote_wakeup &= ~(1 << hcd_portnum); + } + + if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) { +@@ -1630,6 +1629,7 @@ static void handle_port_status(struct xh + bus_state->port_remote_wakeup |= 1 << hcd_portnum; + xhci_test_and_clear_bit(xhci, port, PORT_PLC); + xhci_set_link_state(xhci, port, XDEV_U0); ++ usb_hcd_start_port_resume(&hcd->self, hcd_portnum); + /* Need to wait until the next link state change + * indicates the device is actually in U0. + */ +@@ -1669,7 +1669,6 @@ static void handle_port_status(struct xh + if (slot_id && xhci->devs[slot_id]) + xhci_ring_device(xhci, slot_id); + if (bus_state->port_remote_wakeup & (1 << hcd_portnum)) { +- bus_state->port_remote_wakeup &= ~(1 << hcd_portnum); + xhci_test_and_clear_bit(xhci, port, PORT_PLC); + usb_wakeup_notification(hcd->self.root_hub, + hcd_portnum + 1); -- 2.47.3