summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/xhci-ring.c27
-rw-r--r--drivers/usb/host/xhci.c1
-rw-r--r--drivers/usb/host/xhci.h1
3 files changed, 11 insertions, 18 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 213cb02cbfdb..2ce132b44525 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -627,12 +627,8 @@ static void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci,
struct xhci_virt_ep *ep)
{
ep->ep_state &= ~EP_STOP_CMD_PENDING;
- /* Can't del_timer_sync in interrupt, so we attempt to cancel. If the
- * timer is running on another CPU, we don't decrement stop_cmds_pending
- * (since we didn't successfully stop the watchdog timer).
- */
- if (del_timer(&ep->stop_cmd_timer))
- ep->stop_cmds_pending--;
+ /* Can't del_timer_sync in interrupt */
+ del_timer(&ep->stop_cmd_timer);
}
/*
@@ -895,10 +891,8 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci,
* simple flag to say whether there is a pending stop endpoint command for a
* particular endpoint.
*
- * Instead we use a combination of that flag and a counter for the number of
- * pending stop endpoint commands. If the timer is the tail end of the last
- * stop endpoint command, and the endpoint's command is still pending, we assume
- * the host is dying.
+ * Instead we use a combination of that flag and checking if a new timer is
+ * pending.
*/
void xhci_stop_endpoint_command_watchdog(unsigned long arg)
{
@@ -912,13 +906,11 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
spin_lock_irqsave(&xhci->lock, flags);
- ep->stop_cmds_pending--;
-
- if (ep->stop_cmds_pending || !(ep->ep_state & EP_STOP_CMD_PENDING)) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
- "Stop EP timer ran, but no command pending, "
- "exiting.");
+ /* bail out if cmd completed but raced with stop ep watchdog timer.*/
+ if (!(ep->ep_state & EP_STOP_CMD_PENDING) ||
+ timer_pending(&ep->stop_cmd_timer)) {
spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_dbg(xhci, "Stop EP timer raced with cmd completion, exit");
return;
}
@@ -927,7 +919,10 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
/* Oops, HC is dead or dying or at least not responding to the stop
* endpoint command.
*/
+
xhci->xhc_state |= XHCI_STATE_DYING;
+ ep->ep_state &= ~EP_STOP_CMD_PENDING;
+
/* Disable interrupts from the host controller and start halting it */
xhci_quiesce(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index fcb3fa4a6f79..fb7a6dc00226 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1570,7 +1570,6 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
goto done;
}
ep->ep_state |= EP_STOP_CMD_PENDING;
- ep->stop_cmds_pending++;
ep->stop_cmd_timer.expires = jiffies +
XHCI_STOP_EP_CMD_TIMEOUT * HZ;
add_timer(&ep->stop_cmd_timer);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 198f40388344..cdf8c037d481 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -924,7 +924,6 @@ struct xhci_virt_ep {
unsigned int stopped_stream;
/* Watchdog timer for stop endpoint command to cancel URBs */
struct timer_list stop_cmd_timer;
- int stop_cmds_pending;
struct xhci_hcd *xhci;
/* Dequeue pointer and dequeue segment for a submitted Set TR Dequeue
* command. We'll need to update the ring's dequeue segment and dequeue