summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/xhci.c10
-rw-r--r--drivers/usb/host/xhci.h1
2 files changed, 9 insertions, 2 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 238ebe158b83..2c11411ca5f5 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -98,11 +98,15 @@ void xhci_quiesce(struct xhci_hcd *xhci)
*/
int xhci_halt(struct xhci_hcd *xhci)
{
+ int ret;
xhci_dbg(xhci, "// Halt the HC\n");
xhci_quiesce(xhci);
- return handshake(xhci, &xhci->op_regs->status,
+ ret = handshake(xhci, &xhci->op_regs->status,
STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
+ if (!ret)
+ xhci->xhc_state |= XHCI_STATE_HALTED;
+ return ret;
}
/*
@@ -129,6 +133,8 @@ int xhci_start(struct xhci_hcd *xhci)
xhci_err(xhci, "Host took too long to start, "
"waited %u microseconds.\n",
XHCI_MAX_HALT_USEC);
+ if (!ret)
+ xhci->xhc_state &= ~XHCI_STATE_HALTED;
return ret;
}
@@ -1212,7 +1218,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
if (ret || !urb->hcpriv)
goto done;
temp = xhci_readl(xhci, &xhci->op_regs->status);
- if (temp == 0xffffffff) {
+ if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {
xhci_dbg(xhci, "HW died, freeing TD.\n");
urb_priv = urb->hcpriv;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index e9217bb288ad..e69f1cdf4b5b 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1260,6 +1260,7 @@ struct xhci_hcd {
* There are no reports of xHCI host controllers that display this issue.
*/
#define XHCI_STATE_DYING (1 << 0)
+#define XHCI_STATE_HALTED (1 << 1)
/* Statistics */
int error_bitmask;
unsigned int quirks;