summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Cline <jcline@redhat.com>2018-07-13 10:27:41 -0400
committerJeremy Cline <jcline@redhat.com>2018-07-13 10:28:51 -0400
commitce14d7838dafab3bfeca407ffa13c6bf43156311 (patch)
tree1feca35c3482b935516b06ab92759689a8d85b54
parenta883cbc71e4ac768361d0c07af8e70691c10e32b (diff)
downloadkernel-ce14d7838dafab3bfeca407ffa13c6bf43156311.tar.gz
kernel-ce14d7838dafab3bfeca407ffa13c6bf43156311.tar.xz
kernel-ce14d7838dafab3bfeca407ffa13c6bf43156311.zip
Fix perceived dead xhci host (rhbz 1597333)
-rw-r--r--kernel.spec6
-rw-r--r--xhci-Fix-perceived-dead-host-due-to-runtime-suspend-.patch126
2 files changed, 131 insertions, 1 deletions
diff --git a/kernel.spec b/kernel.spec
index 615584af2..39b98ba13 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -672,7 +672,10 @@ Patch523: 0001-xfs-More-robust-inode-extent-count-validation.patch
Patch524: CVE-2018-13405.patch
# rhbz 1592976
-Patch 525: xen-remove-global-bit-from-__default_kernel_pte_mask.patch
+Patch525: xen-remove-global-bit-from-__default_kernel_pte_mask.patch
+
+# rhbz 1597333
+Patch526: xhci-Fix-perceived-dead-host-due-to-runtime-suspend-.patch
# END OF PATCH DEFINITIONS
@@ -1925,6 +1928,7 @@ fi
%changelog
* Thu Jul 12 2018 Jeremy Cline <jeremy@jcline.org>
- Avoid an early WARN_ON in Xen (rhbz 1592976)
+- Fix perceived dead xhci host (rhbz 1597333)
* Thu Jul 12 2018 Dan Horák <dan@danny.cz>
- Enable HDA sound drivers on PPC
diff --git a/xhci-Fix-perceived-dead-host-due-to-runtime-suspend-.patch b/xhci-Fix-perceived-dead-host-due-to-runtime-suspend-.patch
new file mode 100644
index 000000000..b52d783ae
--- /dev/null
+++ b/xhci-Fix-perceived-dead-host-due-to-runtime-suspend-.patch
@@ -0,0 +1,126 @@
+From 229bc19fd7aca4f37964af06e3583c1c8f36b5d6 Mon Sep 17 00:00:00 2001
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+Date: Thu, 21 Jun 2018 16:19:41 +0300
+Subject: [PATCH] xhci: Fix perceived dead host due to runtime suspend race
+ with event handler
+
+Don't rely on event interrupt (EINT) bit alone to detect pending port
+change in resume. If no change event is detected the host may be suspended
+again, oterwise roothubs are resumed.
+
+There is a lag in xHC setting EINT. If we don't notice the pending change
+in resume, and the controller is runtime suspeded again, it causes the
+event handler to assume host is dead as it will fail to read xHC registers
+once PCI puts the controller to D3 state.
+
+[ 268.520969] xhci_hcd: xhci_resume: starting port polling.
+[ 268.520985] xhci_hcd: xhci_hub_status_data: stopping port polling.
+[ 268.521030] xhci_hcd: xhci_suspend: stopping port polling.
+[ 268.521040] xhci_hcd: // Setting command ring address to 0x349bd001
+[ 268.521139] xhci_hcd: Port Status Change Event for port 3
+[ 268.521149] xhci_hcd: resume root hub
+[ 268.521163] xhci_hcd: port resume event for port 3
+[ 268.521168] xhci_hcd: xHC is not running.
+[ 268.521174] xhci_hcd: handle_port_status: starting port polling.
+[ 268.596322] xhci_hcd: xhci_hc_died: xHCI host controller not responding, assume dead
+
+The EINT lag is described in a additional note in xhci specs 4.19.2:
+
+"Due to internal xHC scheduling and system delays, there will be a lag
+between a change bit being set and the Port Status Change Event that it
+generated being written to the Event Ring. If SW reads the PORTSC and
+sees a change bit set, there is no guarantee that the corresponding Port
+Status Change Event has already been written into the Event Ring."
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Jeremy Cline <jcline@redhat.com>
+---
+ drivers/usb/host/xhci.c | 40 +++++++++++++++++++++++++++++++++++++---
+ drivers/usb/host/xhci.h | 4 ++++
+ 2 files changed, 41 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
+index 8c8da2d657fa..f11ec61bcc7d 100644
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -908,6 +908,41 @@ static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci)
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ }
+
++static bool xhci_pending_portevent(struct xhci_hcd *xhci)
++{
++ struct xhci_port **ports;
++ int port_index;
++ u32 status;
++ u32 portsc;
++
++ status = readl(&xhci->op_regs->status);
++ if (status & STS_EINT)
++ return true;
++ /*
++ * Checking STS_EINT is not enough as there is a lag between a change
++ * bit being set and the Port Status Change Event that it generated
++ * being written to the Event Ring. See note in xhci 1.1 section 4.19.2.
++ */
++
++ port_index = xhci->usb2_rhub.num_ports;
++ ports = xhci->usb2_rhub.ports;
++ while (port_index--) {
++ portsc = readl(ports[port_index]->addr);
++ if (portsc & PORT_CHANGE_MASK ||
++ (portsc & PORT_PLS_MASK) == XDEV_RESUME)
++ return true;
++ }
++ port_index = xhci->usb3_rhub.num_ports;
++ ports = xhci->usb3_rhub.ports;
++ while (port_index--) {
++ portsc = readl(ports[port_index]->addr);
++ if (portsc & PORT_CHANGE_MASK ||
++ (portsc & PORT_PLS_MASK) == XDEV_RESUME)
++ return true;
++ }
++ return false;
++}
++
+ /*
+ * Stop HC (not bus-specific)
+ *
+@@ -1009,7 +1044,7 @@ EXPORT_SYMBOL_GPL(xhci_suspend);
+ */
+ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
+ {
+- u32 command, temp = 0, status;
++ u32 command, temp = 0;
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+ struct usb_hcd *secondary_hcd;
+ int retval = 0;
+@@ -1134,8 +1169,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
+ done:
+ if (retval == 0) {
+ /* Resume root hubs only when have pending events. */
+- status = readl(&xhci->op_regs->status);
+- if (status & STS_EINT) {
++ if (xhci_pending_portevent(xhci)) {
+ usb_hcd_resume_root_hub(xhci->shared_hcd);
+ usb_hcd_resume_root_hub(hcd);
+ }
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 939e2f86b595..841e89ffe2e9 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -382,6 +382,10 @@ struct xhci_op_regs {
+ #define PORT_PLC (1 << 22)
+ /* port configure error change - port failed to configure its link partner */
+ #define PORT_CEC (1 << 23)
++#define PORT_CHANGE_MASK (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
++ PORT_RC | PORT_PLC | PORT_CEC)
++
++
+ /* Cold Attach Status - xHC can set this bit to report device attached during
+ * Sx state. Warm port reset should be perfomed to clear this bit and move port
+ * to connected state.
+--
+2.17.1
+