[PATCH 3/3] xhci: Remove busy loop from xhci_abort_cmd_ring()

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

 



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



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

  Powered by Linux