summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-ring.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/xhci-ring.c')
-rw-r--r--drivers/usb/host/xhci-ring.c118
1 files changed, 57 insertions, 61 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index d45f533772ee..c8910fd9b34c 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -359,21 +359,19 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags)
xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
&xhci->op_regs->cmd_ring);
- /* Section 4.6.1.2 of xHCI 1.0 spec says software should
- * time the completion od all xHCI commands, including
- * the Command Abort operation. If software doesn't see
- * CRR negated in a timely manner (e.g. longer than 5
- * seconds), then it should assume that the there are
- * larger problems with the xHC and assert HCRST.
+ /* Section 4.6.1.2 of xHCI 1.0 spec says software should also time the
+ * completion of the Command Abort operation. If CRR is not negated in 5
+ * seconds then driver handles it as if host died (-ENODEV).
+ * In the future we should distinguish between -ENODEV and -ETIMEDOUT
+ * and try to recover a -ETIMEDOUT with a host controller reset.
*/
ret = xhci_handshake(&xhci->op_regs->cmd_ring,
CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
if (ret < 0) {
- xhci_err(xhci,
- "Stop command ring failed, maybe the host is dead\n");
- xhci->xhc_state |= XHCI_STATE_DYING;
+ xhci_err(xhci, "Abort failed to stop command ring: %d\n", ret);
xhci_halt(xhci);
- return -ESHUTDOWN;
+ xhci_hc_died(xhci);
+ return ret;
}
/*
* Writing the CMD_RING_ABORT bit should cause a cmd completion event,
@@ -873,6 +871,40 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci,
}
}
+/*
+ * host controller died, register read returns 0xffffffff
+ * Complete pending commands, mark them ABORTED.
+ * URBs need to be given back as usb core might be waiting with device locks
+ * held for the URBs to finish during device disconnect, blocking host remove.
+ *
+ * Call with xhci->lock held.
+ * lock is relased and re-acquired while giving back urb.
+ */
+void xhci_hc_died(struct xhci_hcd *xhci)
+{
+ int i, j;
+
+ if (xhci->xhc_state & XHCI_STATE_DYING)
+ return;
+
+ xhci_err(xhci, "xHCI host controller not responding, assume dead\n");
+ xhci->xhc_state |= XHCI_STATE_DYING;
+
+ xhci_cleanup_command_queue(xhci);
+
+ /* return any pending urbs, remove may be waiting for them */
+ for (i = 0; i <= HCS_MAX_SLOTS(xhci->hcs_params1); i++) {
+ if (!xhci->devs[i])
+ continue;
+ for (j = 0; j < 31; j++)
+ xhci_kill_endpoint_urbs(xhci, i, j);
+ }
+
+ /* inform usb core hc died if PCI remove isn't already handling it */
+ if (!(xhci->xhc_state & XHCI_STATE_REMOVING))
+ usb_hc_died(xhci_to_hcd(xhci));
+}
+
/* Watchdog timer function for when a stop endpoint command fails to complete.
* In this case, we assume the host controller is broken or dying or dead. The
* host may still be completing some other events, so we have to be careful to
@@ -894,7 +926,6 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
{
struct xhci_hcd *xhci;
struct xhci_virt_ep *ep;
- int ret, i, j;
unsigned long flags;
ep = (struct xhci_virt_ep *) arg;
@@ -911,52 +942,22 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
}
xhci_warn(xhci, "xHCI host not responding to stop endpoint command.\n");
- xhci_warn(xhci, "Assuming host is dying, halting host.\n");
- /* 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);
+ xhci_halt(xhci);
- ret = xhci_halt(xhci);
+ /*
+ * handle a stop endpoint cmd timeout as if host died (-ENODEV).
+ * In the future we could distinguish between -ENODEV and -ETIMEDOUT
+ * and try to recover a -ETIMEDOUT with a host controller reset
+ */
+ xhci_hc_died(xhci);
- spin_lock_irqsave(&xhci->lock, flags);
- if (ret < 0) {
- /* This is bad; the host is not responding to commands and it's
- * not allowing itself to be halted. At least interrupts are
- * disabled. If we call usb_hc_died(), it will attempt to
- * disconnect all device drivers under this host. Those
- * disconnect() methods will wait for all URBs to be unlinked,
- * so we must complete them.
- */
- xhci_warn(xhci, "Non-responsive xHCI host is not halting.\n");
- xhci_warn(xhci, "Completing active URBs anyway.\n");
- /* We could turn all TDs on the rings to no-ops. This won't
- * help if the host has cached part of the ring, and is slow if
- * we want to preserve the cycle bit. Skip it and hope the host
- * doesn't touch the memory.
- */
- }
- for (i = 0; i < MAX_HC_SLOTS; i++) {
- if (!xhci->devs[i])
- continue;
- for (j = 0; j < 31; j++)
- xhci_kill_endpoint_urbs(xhci, i, j);
- }
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
- "Calling usb_hc_died()");
- usb_hc_died(xhci_to_hcd(xhci));
- xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
"xHCI host controller is dead.");
}
-
static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
struct xhci_virt_device *dev,
struct xhci_ring *ep_ring,
@@ -1291,7 +1292,6 @@ void xhci_cleanup_command_queue(struct xhci_hcd *xhci)
void xhci_handle_command_timeout(struct work_struct *work)
{
struct xhci_hcd *xhci;
- int ret;
unsigned long flags;
u64 hw_ring_state;
@@ -1312,22 +1312,17 @@ void xhci_handle_command_timeout(struct work_struct *work)
/* Make sure command ring is running before aborting it */
hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+ if (hw_ring_state == ~(u64)0) {
+ xhci_hc_died(xhci);
+ goto time_out_completed;
+ }
+
if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) &&
(hw_ring_state & CMD_RING_RUNNING)) {
/* Prevent new doorbell, and start command abort */
xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
xhci_dbg(xhci, "Command timeout\n");
- ret = xhci_abort_cmd_ring(xhci, flags);
- if (unlikely(ret == -ESHUTDOWN)) {
- xhci_err(xhci, "Abort command ring failed\n");
- xhci_cleanup_command_queue(xhci);
- spin_unlock_irqrestore(&xhci->lock, flags);
- usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
- xhci_dbg(xhci, "xHCI host controller is dead.\n");
-
- return;
- }
-
+ xhci_abort_cmd_ring(xhci, flags);
goto time_out_completed;
}
@@ -2695,7 +2690,8 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
spin_lock(&xhci->lock);
/* Check if the xHC generated the interrupt, or the irq is shared */
status = readl(&xhci->op_regs->status);
- if (status == 0xffffffff) {
+ if (status == ~(u32)0) {
+ xhci_hc_died(xhci);
ret = IRQ_HANDLED;
goto out;
}