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 <[email protected]>
---
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 <[email protected]>
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html