]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
xhci: workaround CSS timeout on AMD SNPS 3.0 xHC
authorSandeep Singh <sandeep.singh@amd.com>
Wed, 5 Dec 2018 08:32:00 +0000 (09:32 +0100)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Thu, 6 Dec 2018 13:47:52 +0000 (14:47 +0100)
BugLink: https://bugs.launchpad.net/bugs/1806838
Occasionally AMD SNPS 3.0 xHC does not respond to
CSS when set, also it does not flag anything on SRE and HCE
to point the internal xHC errors on USBSTS register. This stalls
the entire system wide suspend and there is no point in stalling
just because of xHC CSS is not responding.

To work around this problem, if the xHC does not flag
anything on SRE and HCE, we can skip the CSS
timeout and allow the system to continue the suspend. Once the
system resume happens we can internally reset the controller
using XHCI_RESET_ON_RESUME quirk

Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
Signed-off-by: Sandeep Singh <Sandeep.Singh@amd.com>
cc: Nehal Shah <Nehal-bakulchandra.Shah@amd.com>
Cc: <stable@vger.kernel.org>
Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
(backported from commit b5282b66f0dfe6e76644c5195ec6aa3de15fefa3 git://git.kernel.org/pub/scm/linux/kernel/git/mnyman/xhci.git for-usb-linus)
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Acked-by: Seth Forshee <seth.forshee@canonical.com>
Acked-by: Khalid Elmously <khalid.elmously@canonical.com>
Acked-by: Andy Whitcroft <andy.whitcroft@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h

index c3ae5784649ac9fb7941be5c8b982329eab979e5..c62fa1424601582846b73dca583f9895a8f485de 100644 (file)
@@ -132,6 +132,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                 pdev->device == 0x43bb))
                xhci->quirks |= XHCI_SUSPEND_DELAY;
 
+       if (pdev->vendor == PCI_VENDOR_ID_AMD &&
+           (pdev->device == 0x15e0 || pdev->device == 0x15e1))
+               xhci->quirks |= XHCI_SNPS_BROKEN_SUSPEND;
+
        if (pdev->vendor == PCI_VENDOR_ID_AMD)
                xhci->quirks |= XHCI_TRUST_TX_LENGTH;
 
index 2ad8d16811f50da72379366befd34d5a776b5f24..c700bfb809df903b38685ba04c62d0b4561c1a2c 100644 (file)
@@ -866,6 +866,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
        unsigned int            delay = XHCI_MAX_HALT_USEC;
        struct usb_hcd          *hcd = xhci_to_hcd(xhci);
        u32                     command;
+       u32                     res;
 
        if (!hcd->state)
                return 0;
@@ -919,11 +920,28 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
        command = readl(&xhci->op_regs->command);
        command |= CMD_CSS;
        writel(command, &xhci->op_regs->command);
+       xhci->broken_suspend = 0;
        if (xhci_handshake(&xhci->op_regs->status,
                                STS_SAVE, 0, 10 * 1000)) {
-               xhci_warn(xhci, "WARN: xHC save state timeout\n");
-               spin_unlock_irq(&xhci->lock);
-               return -ETIMEDOUT;
+       /*
+        * AMD SNPS xHC 3.0 occasionally does not clear the
+        * SSS bit of USBSTS and when driver tries to poll
+        * to see if the xHC clears BIT(8) which never happens
+        * and driver assumes that controller is not responding
+        * and times out. To workaround this, its good to check
+        * if SRE and HCE bits are not set (as per xhci
+        * Section 5.4.2) and bypass the timeout.
+        */
+               res = readl(&xhci->op_regs->status);
+               if ((xhci->quirks & XHCI_SNPS_BROKEN_SUSPEND) &&
+                   (((res & STS_SRE) == 0) &&
+                               ((res & STS_HCE) == 0))) {
+                       xhci->broken_suspend = 1;
+               } else {
+                       xhci_warn(xhci, "WARN: xHC save state timeout\n");
+                       spin_unlock_irq(&xhci->lock);
+                       return -ETIMEDOUT;
+               }
        }
        spin_unlock_irq(&xhci->lock);
 
@@ -976,7 +994,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
 
        spin_lock_irq(&xhci->lock);
-       if (xhci->quirks & XHCI_RESET_ON_RESUME)
+       if ((xhci->quirks & XHCI_RESET_ON_RESUME) || xhci->broken_suspend)
                hibernated = true;
 
        if (!hibernated) {
index b80767aeedeb1a78814c0862e6121bcce64169ed..269b2f4a90392bf57e3e89cda1ec971092441466 100644 (file)
@@ -1825,6 +1825,7 @@ struct xhci_hcd {
 #define XHCI_ASMEDIA_MODIFY_FLOWCONTROL        BIT_ULL(28)
 #define XHCI_HW_LPM_DISABLE    BIT_ULL(29)
 #define XHCI_SUSPEND_DELAY     BIT_ULL(30)
+#define XHCI_SNPS_BROKEN_SUSPEND    BIT_ULL(35)
 
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
@@ -1861,6 +1862,8 @@ struct xhci_hcd {
        void                    *dbc;
        /* platform-specific data -- must come last */
        unsigned long           priv[0] __aligned(sizeof(s64));
+       /* Broken Suspend flag for SNPS Suspend resume issue */
+       u8                      broken_suspend;
 };
 
 /* Platform specific overrides to generic XHCI hc_driver ops */