|
@@ -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);
|