diff options
author | Jeremy Cline <jcline@redhat.com> | 2018-07-13 10:27:41 -0400 |
---|---|---|
committer | Jeremy Cline <jcline@redhat.com> | 2018-07-13 10:28:51 -0400 |
commit | ce14d7838dafab3bfeca407ffa13c6bf43156311 (patch) | |
tree | 1feca35c3482b935516b06ab92759689a8d85b54 | |
parent | a883cbc71e4ac768361d0c07af8e70691c10e32b (diff) | |
download | kernel-ce14d7838dafab3bfeca407ffa13c6bf43156311.tar.gz kernel-ce14d7838dafab3bfeca407ffa13c6bf43156311.tar.xz kernel-ce14d7838dafab3bfeca407ffa13c6bf43156311.zip |
Fix perceived dead xhci host (rhbz 1597333)
-rw-r--r-- | kernel.spec | 6 | ||||
-rw-r--r-- | xhci-Fix-perceived-dead-host-due-to-runtime-suspend-.patch | 126 |
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 + |