Now, xhci_abort_cmd_ring() is sleepable. So no reason to use busy loop anymore. - Convert udelay(1000) => msleep(1). - Add xhci_handshake_sleep(), and use it. As related change, current xhci_handshake() is strange behavior, E.g. xhci_handshake(ptr, mask, done, 1) does result = readl(ptr); /* check result */ udelay(1); <= meaningless delay return -ETIMEDOUT; Instead of above, this changes to do result = readl(ptr); /* check result */ udelay(1); result = readl(ptr); /* check result */ return -ETIMEDOUT; Signed-off-by: OGAWA Hirofumi <hirofumi@xxxxxxxxxxxxxxxxxx> --- drivers/usb/host/xhci-ring.c | 10 ++++---- drivers/usb/host/xhci.c | 52 +++++++++++++++++++++++++++++++++--------- drivers/usb/host/xhci.h | 1 3 files changed, 48 insertions(+), 15 deletions(-) diff -puN drivers/usb/host/xhci-ring.c~xhci-fix-abort-race3 drivers/usb/host/xhci-ring.c --- xhci/drivers/usb/host/xhci-ring.c~xhci-fix-abort-race3 2016-11-16 13:36:08.787328641 +0900 +++ xhci-hirofumi/drivers/usb/host/xhci-ring.c 2016-11-16 13:36:08.789328640 +0900 @@ -359,15 +359,15 @@ static int xhci_abort_cmd_ring(struct xh * seconds), then it should assume that the there are * larger problems with the xHC and assert HCRST. */ - ret = xhci_handshake(&xhci->op_regs->cmd_ring, - CMD_RING_RUNNING, 0, 5 * 1000 * 1000); + ret = xhci_handshake_sleep(&xhci->op_regs->cmd_ring, + CMD_RING_RUNNING, 0, 5 * 1000 * 1000); if (ret < 0) { /* we are about to kill xhci, give it one more chance */ xhci_write_64(xhci, temp_64 | CMD_RING_ABORT, &xhci->op_regs->cmd_ring); - udelay(1000); - ret = xhci_handshake(&xhci->op_regs->cmd_ring, - CMD_RING_RUNNING, 0, 3 * 1000 * 1000); + msleep(1); + ret = xhci_handshake_sleep(&xhci->op_regs->cmd_ring, + CMD_RING_RUNNING, 0, 3 * 1000 * 1000); if (ret < 0) { xhci_err(xhci, "Stopped the command ring failed, " "maybe the host is dead\n"); diff -puN drivers/usb/host/xhci.c~xhci-fix-abort-race3 drivers/usb/host/xhci.c --- xhci/drivers/usb/host/xhci.c~xhci-fix-abort-race3 2016-11-16 13:36:08.787328641 +0900 +++ xhci-hirofumi/drivers/usb/host/xhci.c 2016-11-16 13:36:08.790328639 +0900 @@ -61,21 +61,53 @@ MODULE_PARM_DESC(quirks, "Bit flags for * handshake done). There are two failure modes: "usec" have passed (major * hardware flakeout), or the register reads as all-ones (hardware removed). */ +static int __xhci_handshake(void __iomem *ptr, u32 mask, u32 done) +{ + u32 result; + + result = readl(ptr); + if (result == ~(u32)0) /* card removed */ + return -ENODEV; + result &= mask; + if (result == done) + return 0; + return 1; +} + int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec) { - u32 result; + int ret; - do { - result = readl(ptr); - if (result == ~(u32)0) /* card removed */ - return -ENODEV; - result &= mask; - if (result == done) - return 0; + while (1) { + ret = __xhci_handshake(ptr, mask, done); + if (ret <= 0) + goto out; + if (usec <= 0) + break; udelay(1); usec--; - } while (usec > 0); - return -ETIMEDOUT; + } + ret = -ETIMEDOUT; +out: + return ret; +} + +int xhci_handshake_sleep(void __iomem *ptr, u32 mask, u32 done, int usec) +{ + unsigned long timeout = jiffies + usecs_to_jiffies(usec); + int ret; + + while (1) { + ret = __xhci_handshake(ptr, mask, done); + if (ret <= 0) + goto out; + if (time_after(jiffies, timeout)) + break; + usleep_range(1, 10); + } + ret = -ETIMEDOUT; +out: + return ret; } /* diff -puN drivers/usb/host/xhci.h~xhci-fix-abort-race3 drivers/usb/host/xhci.h --- xhci/drivers/usb/host/xhci.h~xhci-fix-abort-race3 2016-11-16 13:36:08.788328640 +0900 +++ xhci-hirofumi/drivers/usb/host/xhci.h 2016-11-16 13:36:08.790328639 +0900 @@ -1844,6 +1844,7 @@ void xhci_free_command(struct xhci_hcd * /* 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_sleep(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_reset(struct xhci_hcd *xhci); _ -- OGAWA Hirofumi <hirofumi@xxxxxxxxxxxxxxxxxx> -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html