diff options
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 22 |
1 files changed, 12 insertions, 10 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index ec278a9f9540..82dd93c2afdd 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -494,7 +494,7 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags) struct xhci_segment *new_seg = xhci->cmd_ring->deq_seg; union xhci_trb *new_deq = xhci->cmd_ring->dequeue; u64 crcr; - int ret; + int ret, completed; xhci_dbg(xhci, "Abort command ring\n"); @@ -521,25 +521,27 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags) * In the future we should distinguish between -ENODEV and -ETIMEDOUT * and try to recover a -ETIMEDOUT with a host controller reset. */ + spin_unlock_irqrestore(&xhci->lock, flags); ret = xhci_handshake(&xhci->op_regs->cmd_ring, CMD_RING_RUNNING, 0, 5 * 1000 * 1000); - if (ret < 0) { - xhci_err(xhci, "Abort failed to stop command ring: %d\n", ret); - xhci_halt(xhci); - xhci_hc_died(xhci); - return ret; - } /* * Writing the CMD_RING_ABORT bit should cause a cmd completion event, * however on some host hw the CMD_RING_RUNNING bit is correctly cleared * but the completion event in never sent. Wait 2 secs (arbitrary * number) to handle those cases after negation of CMD_RING_RUNNING. */ - spin_unlock_irqrestore(&xhci->lock, flags); - ret = wait_for_completion_timeout(&xhci->cmd_ring_stop_completion, + if (ret >= 0) + completed = wait_for_completion_timeout(&xhci->cmd_ring_stop_completion, msecs_to_jiffies(2000)); spin_lock_irqsave(&xhci->lock, flags); - if (!ret) { + + if (ret < 0) { + xhci_err(xhci, "Abort failed to stop command ring: %d\n", ret); + xhci_halt(xhci); + xhci_hc_died(xhci); + return ret; + } + if (!completed) { xhci_dbg(xhci, "No stop event for abort, ring start fail?\n"); xhci_cleanup_command_queue(xhci); } else { |
