]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
xhci: make xhci_handshake timeout for xhci_reset() adjustable
authorMathias Nyman <mathias.nyman@linux.intel.com>
Thu, 3 Mar 2022 11:08:55 +0000 (13:08 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 8 Apr 2022 12:39:49 +0000 (14:39 +0200)
commit 14073ce951b5919da450022c050772902f24f054 upstream.

xhci_reset() timeout was increased from 250ms to 10 seconds in order to
give Renesas 720201 xHC enough time to get ready in probe.

xhci_reset() is called with interrupts disabled in other places, and
waiting for 10 seconds there is not acceptable.

Add a timeout parameter to xhci_reset(), and adjust it back to 250ms
when called from xhci_stop() or xhci_shutdown() where interrupts are
disabled, and successful reset isn't that critical.
This solves issues when deactivating host mode on platforms like SM8450.

For now don't change the timeout if xHC is reset in xhci_resume().
No issues are reported for it, and we need the reset to succeed.
Locking around that reset needs to be revisited later.

Additionally change the signed integer timeout parameter in
xhci_handshake() to a u64 to match the timeout value we pass to
readl_poll_timeout_atomic()

Fixes: 22ceac191211 ("xhci: Increase reset timeout for Renesas 720201 host.")
Cc: stable@vger.kernel.org
Reported-by: Sergey Shtylyov <s.shtylyov@omp.ru>
Reported-by: Pavan Kondeti <quic_pkondeti@quicinc.com>
Tested-by: Pavan Kondeti <quic_pkondeti@quicinc.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20220303110903.1662404-2-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h

index 3f410bc040e26cf021ca2ef24bed40248950bc79..460a8a86e3111ffe2d6d5e621c58e80d47759c9f 100644 (file)
@@ -676,7 +676,7 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
        }
        pm_runtime_allow(xhci_to_hcd(xhci)->self.controller);
        xhci->test_mode = 0;
-       return xhci_reset(xhci);
+       return xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
 }
 
 void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
index ed380ee58ab5d7c0a125a03b9d391ec181d46d20..024e8911df344174a8290abe2f8b3dd09b1f180f 100644 (file)
@@ -2595,7 +2595,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
 
 fail:
        xhci_halt(xhci);
-       xhci_reset(xhci);
+       xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
        xhci_mem_cleanup(xhci);
        return -ENOMEM;
 }
index 49f74299d3f572691beb99d4d42693a6fbc3b29e..95effd28179b4d003c6c2480cd50bd8a0c7bb718 100644 (file)
@@ -66,7 +66,7 @@ static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring)
  * handshake done).  There are two failure modes:  "usec" have passed (major
  * hardware flakeout), or the register reads as all-ones (hardware removed).
  */
-int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec)
+int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us)
 {
        u32     result;
        int     ret;
@@ -74,7 +74,7 @@ int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec)
        ret = readl_poll_timeout_atomic(ptr, result,
                                        (result & mask) == done ||
                                        result == U32_MAX,
-                                       1, usec);
+                                       1, timeout_us);
        if (result == U32_MAX)          /* card removed */
                return -ENODEV;
 
@@ -163,7 +163,7 @@ int xhci_start(struct xhci_hcd *xhci)
  * Transactions will be terminated immediately, and operational registers
  * will be set to their defaults.
  */
-int xhci_reset(struct xhci_hcd *xhci)
+int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us)
 {
        u32 command;
        u32 state;
@@ -196,8 +196,7 @@ int xhci_reset(struct xhci_hcd *xhci)
        if (xhci->quirks & XHCI_INTEL_HOST)
                udelay(1000);
 
-       ret = xhci_handshake(&xhci->op_regs->command,
-                       CMD_RESET, 0, 10 * 1000 * 1000);
+       ret = xhci_handshake(&xhci->op_regs->command, CMD_RESET, 0, timeout_us);
        if (ret)
                return ret;
 
@@ -210,8 +209,7 @@ int xhci_reset(struct xhci_hcd *xhci)
         * xHCI cannot write to any doorbells or operational registers other
         * than status until the "Controller Not Ready" flag is cleared.
         */
-       ret = xhci_handshake(&xhci->op_regs->status,
-                       STS_CNR, 0, 10 * 1000 * 1000);
+       ret = xhci_handshake(&xhci->op_regs->status, STS_CNR, 0, timeout_us);
 
        xhci->usb2_rhub.bus_state.port_c_suspend = 0;
        xhci->usb2_rhub.bus_state.suspended_ports = 0;
@@ -732,7 +730,7 @@ static void xhci_stop(struct usb_hcd *hcd)
        xhci->xhc_state |= XHCI_STATE_HALTED;
        xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
        xhci_halt(xhci);
-       xhci_reset(xhci);
+       xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
        spin_unlock_irq(&xhci->lock);
 
        xhci_cleanup_msix(xhci);
@@ -785,7 +783,7 @@ void xhci_shutdown(struct usb_hcd *hcd)
        xhci_halt(xhci);
        /* Workaround for spurious wakeups at shutdown with HSW */
        if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
-               xhci_reset(xhci);
+               xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
        spin_unlock_irq(&xhci->lock);
 
        xhci_cleanup_msix(xhci);
@@ -1170,7 +1168,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                xhci_dbg(xhci, "Stop HCD\n");
                xhci_halt(xhci);
                xhci_zero_64b_regs(xhci);
-               retval = xhci_reset(xhci);
+               retval = xhci_reset(xhci, XHCI_RESET_LONG_USEC);
                spin_unlock_irq(&xhci->lock);
                if (retval)
                        return retval;
@@ -5276,7 +5274,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 
        xhci_dbg(xhci, "Resetting HCD\n");
        /* Reset the internal HC memory state and registers. */
-       retval = xhci_reset(xhci);
+       retval = xhci_reset(xhci, XHCI_RESET_LONG_USEC);
        if (retval)
                return retval;
        xhci_dbg(xhci, "Reset complete\n");
index 39370395a34f9be68a7bd8fd1c3f7950753ed492..8fd838f9d56a10847f71c62c2683cc62b6b6be04 100644 (file)
@@ -229,6 +229,9 @@ struct xhci_op_regs {
 #define CMD_ETE                (1 << 14)
 /* bits 15:31 are reserved (and should be preserved on writes). */
 
+#define XHCI_RESET_LONG_USEC           (10 * 1000 * 1000)
+#define XHCI_RESET_SHORT_USEC          (250 * 1000)
+
 /* IMAN - Interrupt Management Register */
 #define IMAN_IE                (1 << 1)
 #define IMAN_IP                (1 << 0)
@@ -2068,11 +2071,11 @@ void xhci_free_container_ctx(struct xhci_hcd *xhci,
 
 /* xHCI host controller glue */
 typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
-int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec);
+int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us);
 void xhci_quiesce(struct xhci_hcd *xhci);
 int xhci_halt(struct xhci_hcd *xhci);
 int xhci_start(struct xhci_hcd *xhci);
-int xhci_reset(struct xhci_hcd *xhci);
+int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us);
 int xhci_run(struct usb_hcd *hcd);
 int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
 void xhci_shutdown(struct usb_hcd *hcd);