diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 142c1eca172c..e10c964b93e4 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -356,7 +356,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, 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 462b2a5f4720..ab3be847f759 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -81,6 +81,27 @@ int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec) return ret; } +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) /* card removed */ + return -ENODEV; + /* host removed. Bail out */ + if (xhci->xhc_state & XHCI_STATE_REMOVING) + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay(1); + usec--; + } while (usec > 0); + return -ETIMEDOUT; +} + /* * Disable interrupts and begin the xHCI halting process. */ @@ -204,7 +225,7 @@ int xhci_reset(struct xhci_hcd *xhci) if (xhci->quirks & XHCI_INTEL_HOST) udelay(1000); - ret = xhci_handshake(&xhci->op_regs->command, + ret = xhci_handshake_check_state(xhci, &xhci->op_regs->command, CMD_RESET, 0, 10 * 1000 * 1000); if (ret) return ret; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 78f7f2ad8262..e482532970a3 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2061,6 +2061,8 @@ 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_check_state(struct xhci_hcd *xhci, + void __iomem *ptr, u32 mask, u32 done, int usec); void xhci_quiesce(struct xhci_hcd *xhci); int xhci_halt(struct xhci_hcd *xhci); int xhci_start(struct xhci_hcd *xhci);