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 <hirof...@mail.parknet.co.jp>
---

 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 <hirof...@mail.parknet.co.jp>
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to