|
@@ -289,6 +289,114 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
|
|
|
xhci_readl(xhci, &xhci->dba->doorbell[0]);
|
|
|
}
|
|
|
|
|
|
+static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
|
|
|
+{
|
|
|
+ u64 temp_64;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ xhci_dbg(xhci, "Abort command ring\n");
|
|
|
+
|
|
|
+ if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING)) {
|
|
|
+ xhci_dbg(xhci, "The command ring isn't running, "
|
|
|
+ "Have the command ring been stopped?\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
|
|
|
+ if (!(temp_64 & CMD_RING_RUNNING)) {
|
|
|
+ xhci_dbg(xhci, "Command ring had been stopped\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
|
|
|
+ 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.
|
|
|
+ */
|
|
|
+ ret = handshake(xhci, &xhci->op_regs->cmd_ring,
|
|
|
+ CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
|
|
|
+ if (ret < 0) {
|
|
|
+ xhci_err(xhci, "Stopped the command ring failed, "
|
|
|
+ "maybe the host is dead\n");
|
|
|
+ xhci->xhc_state |= XHCI_STATE_DYING;
|
|
|
+ xhci_quiesce(xhci);
|
|
|
+ xhci_halt(xhci);
|
|
|
+ return -ESHUTDOWN;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int xhci_queue_cd(struct xhci_hcd *xhci,
|
|
|
+ struct xhci_command *command,
|
|
|
+ union xhci_trb *cmd_trb)
|
|
|
+{
|
|
|
+ struct xhci_cd *cd;
|
|
|
+ cd = kzalloc(sizeof(struct xhci_cd), GFP_ATOMIC);
|
|
|
+ if (!cd)
|
|
|
+ return -ENOMEM;
|
|
|
+ INIT_LIST_HEAD(&cd->cancel_cmd_list);
|
|
|
+
|
|
|
+ cd->command = command;
|
|
|
+ cd->cmd_trb = cmd_trb;
|
|
|
+ list_add_tail(&cd->cancel_cmd_list, &xhci->cancel_cmd_list);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Cancel the command which has issue.
|
|
|
+ *
|
|
|
+ * Some commands may hang due to waiting for acknowledgement from
|
|
|
+ * usb device. It is outside of the xHC's ability to control and
|
|
|
+ * will cause the command ring is blocked. When it occurs software
|
|
|
+ * should intervene to recover the command ring.
|
|
|
+ * See Section 4.6.1.1 and 4.6.1.2
|
|
|
+ */
|
|
|
+int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command,
|
|
|
+ union xhci_trb *cmd_trb)
|
|
|
+{
|
|
|
+ int retval = 0;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&xhci->lock, flags);
|
|
|
+
|
|
|
+ if (xhci->xhc_state & XHCI_STATE_DYING) {
|
|
|
+ xhci_warn(xhci, "Abort the command ring,"
|
|
|
+ " but the xHCI is dead.\n");
|
|
|
+ retval = -ESHUTDOWN;
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* queue the cmd desriptor to cancel_cmd_list */
|
|
|
+ retval = xhci_queue_cd(xhci, command, cmd_trb);
|
|
|
+ if (retval) {
|
|
|
+ xhci_warn(xhci, "Queuing command descriptor failed.\n");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* abort command ring */
|
|
|
+ retval = xhci_abort_cmd_ring(xhci);
|
|
|
+ if (retval) {
|
|
|
+ xhci_err(xhci, "Abort command ring failed\n");
|
|
|
+ if (unlikely(retval == -ESHUTDOWN)) {
|
|
|
+ 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 retval;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+fail:
|
|
|
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
|
|
+ return retval;
|
|
|
+}
|
|
|
+
|
|
|
void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
|
|
|
unsigned int slot_id,
|
|
|
unsigned int ep_index,
|