Re: [RFC] usb: XHCI: Implement xhci_handshake_check_state() API

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 15.9.2023 12.17, Udipto Goswami wrote:
In some situations where xhci removal happens parallel to
xhci_handshake, we enoughter a scenario where the
xhci_handshake will fails because the status does not change
the entire duration of polling. This causes the xhci_handshake
to timeout resulting in long wait which might lead to watchdog
timeout.

The API  handles command timeout which may happen upon XHCI
stack removal. Check for xhci state and exit the handshake if
xhci is removed.

Signed-off-by: Udipto Goswami <quic_ugoswami@xxxxxxxxxxx>
---
  drivers/usb/host/xhci-ring.c |  2 +-
  drivers/usb/host/xhci.c      | 27 ++++++++++++++++++++++++++-
  drivers/usb/host/xhci.h      |  2 ++
  3 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 1dde53f6eb31..af9e27d3d303 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -450,7 +450,7 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags)
  	 * In the future we should distinguish between -ENODEV and -ETIMEDOUT
  	 * and try to recover a -ETIMEDOUT with a host controller reset.
  	 */
-	ret = xhci_handshake(&xhci->op_regs->cmd_ring,
+	ret = xhci_handshake_check_state(xhci, &xhci->op_regs->cmd_ring,
  			CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
  	if (ret < 0) {
  		xhci_err(xhci, "Abort failed to stop command ring: %d\n", ret);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index e1b1b64a0723..7bfcb09bcad0 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -84,6 +84,30 @@ int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us)
  /*
   * Disable interrupts and begin the xHCI halting process.
   */
+int xhci_handshake_check_state(struct xhci_hcd *xhci,
+	void __iomem *ptr, u32 mask, u32 done, int usec)
+{
+	u32	result;
+
+	do {
+		result = readl_relaxed(ptr);
+		if (result == ~(u32)0)
+			return -ENODEV;
+
+		if (xhci->xhc_state & XHCI_STATE_REMOVING)
+			return -ENODEV;
+
+		result &= mask;
+		if (result == done)
+			return 0;
+
+		udelay(1);
+		usec--;
+	} while (usec > 0);
+
+	return -ETIMEDOUT;
+}
+

Could we use the same readl_poll_timeout_atomic() macro that xhci_handshake() does?

Something like:

int xhci_handshake_check_state(struct xhci_hcd *xhci, void __iomem *ptr,
				u32 mask, u32 done, int usec, unsigned int exit_state)
{
	...

	ret = readl_poll_timeout_atomic(ptr, result,
                                        (result & mask) == done ||
                                        result == U32_MAX ||
					xhci->xhc_state & exit_state,
                                        1, timeout_us);

        if (result == U32_MAX || xhci->xch_state & exit_state)
                return -ENODEV;
	
	return ret;
}

-Mathias





[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux