diff options
author | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2011-03-11 13:20:58 -0500 |
---|---|---|
committer | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2011-03-13 21:23:48 -0400 |
commit | c6cc27c782e3a64cced0fcf1d6f492c8d8881c76 (patch) | |
tree | b671f8101eb7513343f8bb02a7e00712798aa0ed /drivers/usb/host/xhci.c | |
parent | b320937972d456db2a46fdcbc6bebc4dcdc9daa4 (diff) |
xhci: Return canceled URBs immediately when host is halted.
When the xHCI host controller is halted, it won't respond to commands
placed on the command ring. So if an URB is cancelled after the first
roothub is deallocated, it will try to place a stop endpoint command on
the command ring, which will fail. The command watchdog timer will fire
after five seconds, and the host controller will be marked as dying, and
all URBs will be completed.
Add a flag to the xHCI's internal state variable for when the host
controller is halted. Immediately return the canceled URB if the host
controller is halted.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r-- | drivers/usb/host/xhci.c | 10 |
1 files changed, 8 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) | |||
98 | */ | 98 | */ |
99 | int xhci_halt(struct xhci_hcd *xhci) | 99 | int xhci_halt(struct xhci_hcd *xhci) |
100 | { | 100 | { |
101 | int ret; | ||
101 | xhci_dbg(xhci, "// Halt the HC\n"); | 102 | xhci_dbg(xhci, "// Halt the HC\n"); |
102 | xhci_quiesce(xhci); | 103 | xhci_quiesce(xhci); |
103 | 104 | ||
104 | return handshake(xhci, &xhci->op_regs->status, | 105 | ret = handshake(xhci, &xhci->op_regs->status, |
105 | STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); | 106 | STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); |
107 | if (!ret) | ||
108 | xhci->xhc_state |= XHCI_STATE_HALTED; | ||
109 | return ret; | ||
106 | } | 110 | } |
107 | 111 | ||
108 | /* | 112 | /* |
@@ -129,6 +133,8 @@ int xhci_start(struct xhci_hcd *xhci) | |||
129 | xhci_err(xhci, "Host took too long to start, " | 133 | xhci_err(xhci, "Host took too long to start, " |
130 | "waited %u microseconds.\n", | 134 | "waited %u microseconds.\n", |
131 | XHCI_MAX_HALT_USEC); | 135 | XHCI_MAX_HALT_USEC); |
136 | if (!ret) | ||
137 | xhci->xhc_state &= ~XHCI_STATE_HALTED; | ||
132 | return ret; | 138 | return ret; |
133 | } | 139 | } |
134 | 140 | ||
@@ -1212,7 +1218,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) | |||
1212 | if (ret || !urb->hcpriv) | 1218 | if (ret || !urb->hcpriv) |
1213 | goto done; | 1219 | goto done; |
1214 | temp = xhci_readl(xhci, &xhci->op_regs->status); | 1220 | temp = xhci_readl(xhci, &xhci->op_regs->status); |
1215 | if (temp == 0xffffffff) { | 1221 | if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) { |
1216 | xhci_dbg(xhci, "HW died, freeing TD.\n"); | 1222 | xhci_dbg(xhci, "HW died, freeing TD.\n"); |
1217 | urb_priv = urb->hcpriv; | 1223 | urb_priv = urb->hcpriv; |
1218 | 1224 | ||