|
@@ -287,17 +287,7 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
|
|
|
|
|
|
xhci_dbg(xhci, "Abort command ring\n");
|
|
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);
|
|
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->cmd_ring_state = CMD_RING_STATE_ABORTED;
|
|
xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
|
|
xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
|
|
&xhci->op_regs->cmd_ring);
|
|
&xhci->op_regs->cmd_ring);
|
|
@@ -323,71 +313,6 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
|
|
return 0;
|
|
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,
|
|
void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
|
|
unsigned int slot_id,
|
|
unsigned int slot_id,
|
|
unsigned int ep_index,
|
|
unsigned int ep_index,
|
|
@@ -1206,164 +1131,6 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-/* Complete the command and detele it from the devcie's command queue.
|
|
|
|
- */
|
|
|
|
-static void xhci_complete_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
|
|
|
|
- struct xhci_command *command, u32 status)
|
|
|
|
-{
|
|
|
|
- command->status = status;
|
|
|
|
- list_del(&command->cmd_list);
|
|
|
|
- if (command->completion)
|
|
|
|
- complete(command->completion);
|
|
|
|
- else
|
|
|
|
- xhci_free_command(xhci, command);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * Finding the command trb need to be cancelled and modifying it to
|
|
|
|
- * NO OP command. And if the command is in device's command wait
|
|
|
|
- * list, finishing and freeing it.
|
|
|
|
- *
|
|
|
|
- * If we can't find the command trb, we think it had already been
|
|
|
|
- * executed.
|
|
|
|
- */
|
|
|
|
-static void xhci_cmd_to_noop(struct xhci_hcd *xhci, struct xhci_cd *cur_cd)
|
|
|
|
-{
|
|
|
|
- struct xhci_segment *cur_seg;
|
|
|
|
- union xhci_trb *cmd_trb;
|
|
|
|
- u32 cycle_state;
|
|
|
|
-
|
|
|
|
- if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- /* find the current segment of command ring */
|
|
|
|
- cur_seg = find_trb_seg(xhci->cmd_ring->first_seg,
|
|
|
|
- xhci->cmd_ring->dequeue, &cycle_state);
|
|
|
|
-
|
|
|
|
- if (!cur_seg) {
|
|
|
|
- xhci_warn(xhci, "Command ring mismatch, dequeue = %p %llx (dma)\n",
|
|
|
|
- xhci->cmd_ring->dequeue,
|
|
|
|
- (unsigned long long)
|
|
|
|
- xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
|
|
|
|
- xhci->cmd_ring->dequeue));
|
|
|
|
- xhci_debug_ring(xhci, xhci->cmd_ring);
|
|
|
|
- xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* find the command trb matched by cd from command ring */
|
|
|
|
- for (cmd_trb = xhci->cmd_ring->dequeue;
|
|
|
|
- cmd_trb != xhci->cmd_ring->enqueue;
|
|
|
|
- next_trb(xhci, xhci->cmd_ring, &cur_seg, &cmd_trb)) {
|
|
|
|
- /* If the trb is link trb, continue */
|
|
|
|
- if (TRB_TYPE_LINK_LE32(cmd_trb->generic.field[3]))
|
|
|
|
- continue;
|
|
|
|
-
|
|
|
|
- if (cur_cd->cmd_trb == cmd_trb) {
|
|
|
|
-
|
|
|
|
- /* If the command in device's command list, we should
|
|
|
|
- * finish it and free the command structure.
|
|
|
|
- */
|
|
|
|
- if (cur_cd->command)
|
|
|
|
- xhci_complete_cmd_in_cmd_wait_list(xhci,
|
|
|
|
- cur_cd->command, COMP_CMD_STOP);
|
|
|
|
-
|
|
|
|
- /* get cycle state from the origin command trb */
|
|
|
|
- cycle_state = le32_to_cpu(cmd_trb->generic.field[3])
|
|
|
|
- & TRB_CYCLE;
|
|
|
|
-
|
|
|
|
- /* modify the command trb to NO OP command */
|
|
|
|
- cmd_trb->generic.field[0] = 0;
|
|
|
|
- cmd_trb->generic.field[1] = 0;
|
|
|
|
- cmd_trb->generic.field[2] = 0;
|
|
|
|
- cmd_trb->generic.field[3] = cpu_to_le32(
|
|
|
|
- TRB_TYPE(TRB_CMD_NOOP) | cycle_state);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void xhci_cancel_cmd_in_cd_list(struct xhci_hcd *xhci)
|
|
|
|
-{
|
|
|
|
- struct xhci_cd *cur_cd, *next_cd;
|
|
|
|
-
|
|
|
|
- if (list_empty(&xhci->cancel_cmd_list))
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- list_for_each_entry_safe(cur_cd, next_cd,
|
|
|
|
- &xhci->cancel_cmd_list, cancel_cmd_list) {
|
|
|
|
- xhci_cmd_to_noop(xhci, cur_cd);
|
|
|
|
- list_del(&cur_cd->cancel_cmd_list);
|
|
|
|
- kfree(cur_cd);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * traversing the cancel_cmd_list. If the command descriptor according
|
|
|
|
- * to cmd_trb is found, the function free it and return 1, otherwise
|
|
|
|
- * return 0.
|
|
|
|
- */
|
|
|
|
-static int xhci_search_cmd_trb_in_cd_list(struct xhci_hcd *xhci,
|
|
|
|
- union xhci_trb *cmd_trb)
|
|
|
|
-{
|
|
|
|
- struct xhci_cd *cur_cd, *next_cd;
|
|
|
|
-
|
|
|
|
- if (list_empty(&xhci->cancel_cmd_list))
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- list_for_each_entry_safe(cur_cd, next_cd,
|
|
|
|
- &xhci->cancel_cmd_list, cancel_cmd_list) {
|
|
|
|
- if (cur_cd->cmd_trb == cmd_trb) {
|
|
|
|
- if (cur_cd->command)
|
|
|
|
- xhci_complete_cmd_in_cmd_wait_list(xhci,
|
|
|
|
- cur_cd->command, COMP_CMD_STOP);
|
|
|
|
- list_del(&cur_cd->cancel_cmd_list);
|
|
|
|
- kfree(cur_cd);
|
|
|
|
- return 1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * If the cmd_trb_comp_code is COMP_CMD_ABORT, we just check whether the
|
|
|
|
- * trb pointed by the command ring dequeue pointer is the trb we want to
|
|
|
|
- * cancel or not. And if the cmd_trb_comp_code is COMP_CMD_STOP, we will
|
|
|
|
- * traverse the cancel_cmd_list to trun the all of the commands according
|
|
|
|
- * to command descriptor to NO-OP trb.
|
|
|
|
- */
|
|
|
|
-static int handle_stopped_cmd_ring(struct xhci_hcd *xhci,
|
|
|
|
- int cmd_trb_comp_code)
|
|
|
|
-{
|
|
|
|
- int cur_trb_is_good = 0;
|
|
|
|
-
|
|
|
|
- /* Searching the cmd trb pointed by the command ring dequeue
|
|
|
|
- * pointer in command descriptor list. If it is found, free it.
|
|
|
|
- */
|
|
|
|
- cur_trb_is_good = xhci_search_cmd_trb_in_cd_list(xhci,
|
|
|
|
- xhci->cmd_ring->dequeue);
|
|
|
|
-
|
|
|
|
- if (cmd_trb_comp_code == COMP_CMD_ABORT)
|
|
|
|
- xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
|
|
|
|
- else if (cmd_trb_comp_code == COMP_CMD_STOP) {
|
|
|
|
- /* traversing the cancel_cmd_list and canceling
|
|
|
|
- * the command according to command descriptor
|
|
|
|
- */
|
|
|
|
- xhci_cancel_cmd_in_cd_list(xhci);
|
|
|
|
-
|
|
|
|
- xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
|
|
|
|
- /*
|
|
|
|
- * ring command ring doorbell again to restart the
|
|
|
|
- * command ring
|
|
|
|
- */
|
|
|
|
- if (xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue)
|
|
|
|
- xhci_ring_cmd_db(xhci);
|
|
|
|
- }
|
|
|
|
- return cur_trb_is_good;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id,
|
|
static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id,
|
|
u32 cmd_comp_code)
|
|
u32 cmd_comp_code)
|
|
{
|
|
{
|
|
@@ -1480,6 +1247,97 @@ void xhci_cleanup_command_queue(struct xhci_hcd *xhci)
|
|
xhci_complete_del_and_free_cmd(cur_cmd, COMP_CMD_ABORT);
|
|
xhci_complete_del_and_free_cmd(cur_cmd, COMP_CMD_ABORT);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Turn all commands on command ring with status set to "aborted" to no-op trbs.
|
|
|
|
+ * If there are other commands waiting then restart the ring and kick the timer.
|
|
|
|
+ * This must be called with command ring stopped and xhci->lock held.
|
|
|
|
+ */
|
|
|
|
+static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
|
|
|
|
+ struct xhci_command *cur_cmd)
|
|
|
|
+{
|
|
|
|
+ struct xhci_command *i_cmd, *tmp_cmd;
|
|
|
|
+ u32 cycle_state;
|
|
|
|
+
|
|
|
|
+ /* Turn all aborted commands in list to no-ops, then restart */
|
|
|
|
+ list_for_each_entry_safe(i_cmd, tmp_cmd, &xhci->cmd_list,
|
|
|
|
+ cmd_list) {
|
|
|
|
+
|
|
|
|
+ if (i_cmd->status != COMP_CMD_ABORT)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ i_cmd->status = COMP_CMD_STOP;
|
|
|
|
+
|
|
|
|
+ xhci_dbg(xhci, "Turn aborted command %p to no-op\n",
|
|
|
|
+ i_cmd->command_trb);
|
|
|
|
+ /* get cycle state from the original cmd trb */
|
|
|
|
+ cycle_state = le32_to_cpu(
|
|
|
|
+ i_cmd->command_trb->generic.field[3]) & TRB_CYCLE;
|
|
|
|
+ /* modify the command trb to no-op command */
|
|
|
|
+ i_cmd->command_trb->generic.field[0] = 0;
|
|
|
|
+ i_cmd->command_trb->generic.field[1] = 0;
|
|
|
|
+ i_cmd->command_trb->generic.field[2] = 0;
|
|
|
|
+ i_cmd->command_trb->generic.field[3] = cpu_to_le32(
|
|
|
|
+ TRB_TYPE(TRB_CMD_NOOP) | cycle_state);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * caller waiting for completion is called when command
|
|
|
|
+ * completion event is received for these no-op commands
|
|
|
|
+ */
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
|
|
|
|
+
|
|
|
|
+ /* ring command ring doorbell to restart the command ring */
|
|
|
|
+ if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) &&
|
|
|
|
+ !(xhci->xhc_state & XHCI_STATE_DYING)) {
|
|
|
|
+ xhci->current_cmd = cur_cmd;
|
|
|
|
+ mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT);
|
|
|
|
+ xhci_ring_cmd_db(xhci);
|
|
|
|
+ }
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void xhci_handle_command_timeout(unsigned long data)
|
|
|
|
+{
|
|
|
|
+ struct xhci_hcd *xhci;
|
|
|
|
+ int ret;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ u64 hw_ring_state;
|
|
|
|
+ struct xhci_command *cur_cmd = NULL;
|
|
|
|
+ xhci = (struct xhci_hcd *) data;
|
|
|
|
+
|
|
|
|
+ /* mark this command to be cancelled */
|
|
|
|
+ spin_lock_irqsave(&xhci->lock, flags);
|
|
|
|
+ if (xhci->current_cmd) {
|
|
|
|
+ cur_cmd = xhci->current_cmd;
|
|
|
|
+ cur_cmd->status = COMP_CMD_ABORT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /* Make sure command ring is running before aborting it */
|
|
|
|
+ hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
|
|
|
|
+ if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) &&
|
|
|
|
+ (hw_ring_state & CMD_RING_RUNNING)) {
|
|
|
|
+
|
|
|
|
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
|
|
|
+ xhci_dbg(xhci, "Command timeout\n");
|
|
|
|
+ ret = xhci_abort_cmd_ring(xhci);
|
|
|
|
+ if (unlikely(ret == -ESHUTDOWN)) {
|
|
|
|
+ xhci_err(xhci, "Abort command ring failed\n");
|
|
|
|
+ xhci_cleanup_command_queue(xhci);
|
|
|
|
+ usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
|
|
|
|
+ xhci_dbg(xhci, "xHCI host controller is dead.\n");
|
|
|
|
+ }
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ /* command timeout on stopped ring, ring can't be aborted */
|
|
|
|
+ xhci_dbg(xhci, "Command timeout on stopped ring\n");
|
|
|
|
+ xhci_handle_stopped_cmd_ring(xhci, xhci->current_cmd);
|
|
|
|
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|
static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|
struct xhci_event_cmd *event)
|
|
struct xhci_event_cmd *event)
|
|
{
|
|
{
|
|
@@ -1513,26 +1371,28 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|
"Command completion event does not match command\n");
|
|
"Command completion event does not match command\n");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ del_timer(&xhci->cmd_timer);
|
|
|
|
+
|
|
trace_xhci_cmd_completion(cmd_trb, (struct xhci_generic_trb *) event);
|
|
trace_xhci_cmd_completion(cmd_trb, (struct xhci_generic_trb *) event);
|
|
|
|
|
|
cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status));
|
|
cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status));
|
|
- if (cmd_comp_code == COMP_CMD_ABORT || cmd_comp_code == COMP_CMD_STOP) {
|
|
|
|
- /* If the return value is 0, we think the trb pointed by
|
|
|
|
- * command ring dequeue pointer is a good trb. The good
|
|
|
|
- * trb means we don't want to cancel the trb, but it have
|
|
|
|
- * been stopped by host. So we should handle it normally.
|
|
|
|
- * Otherwise, driver should invoke inc_deq() and return.
|
|
|
|
- */
|
|
|
|
- if (handle_stopped_cmd_ring(xhci, cmd_comp_code)) {
|
|
|
|
- inc_deq(xhci, xhci->cmd_ring);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- /* There is no command to handle if we get a stop event when the
|
|
|
|
- * command ring is empty, event->cmd_trb points to the next
|
|
|
|
- * unset command
|
|
|
|
- */
|
|
|
|
- if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue)
|
|
|
|
- return;
|
|
|
|
|
|
+
|
|
|
|
+ /* If CMD ring stopped we own the trbs between enqueue and dequeue */
|
|
|
|
+ if (cmd_comp_code == COMP_CMD_STOP) {
|
|
|
|
+ xhci_handle_stopped_cmd_ring(xhci, cmd);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ /*
|
|
|
|
+ * Host aborted the command ring, check if the current command was
|
|
|
|
+ * supposed to be aborted, otherwise continue normally.
|
|
|
|
+ * The command ring is stopped now, but the xHC will issue a Command
|
|
|
|
+ * Ring Stopped event which will cause us to restart it.
|
|
|
|
+ */
|
|
|
|
+ if (cmd_comp_code == COMP_CMD_ABORT) {
|
|
|
|
+ xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
|
|
|
|
+ if (cmd->status == COMP_CMD_ABORT)
|
|
|
|
+ goto event_handled;
|
|
}
|
|
}
|
|
|
|
|
|
cmd_type = TRB_FIELD_TO_TYPE(le32_to_cpu(cmd_trb->generic.field[3]));
|
|
cmd_type = TRB_FIELD_TO_TYPE(le32_to_cpu(cmd_trb->generic.field[3]));
|
|
@@ -1563,6 +1423,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|
xhci_handle_cmd_set_deq(xhci, slot_id, cmd_trb, cmd_comp_code);
|
|
xhci_handle_cmd_set_deq(xhci, slot_id, cmd_trb, cmd_comp_code);
|
|
break;
|
|
break;
|
|
case TRB_CMD_NOOP:
|
|
case TRB_CMD_NOOP:
|
|
|
|
+ /* Is this an aborted command turned to NO-OP? */
|
|
|
|
+ if (cmd->status == COMP_CMD_STOP)
|
|
|
|
+ cmd_comp_code = COMP_CMD_STOP;
|
|
break;
|
|
break;
|
|
case TRB_RESET_EP:
|
|
case TRB_RESET_EP:
|
|
WARN_ON(slot_id != TRB_TO_SLOT_ID(
|
|
WARN_ON(slot_id != TRB_TO_SLOT_ID(
|
|
@@ -1583,6 +1446,14 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* restart timer if this wasn't the last command */
|
|
|
|
+ if (cmd->cmd_list.next != &xhci->cmd_list) {
|
|
|
|
+ xhci->current_cmd = list_entry(cmd->cmd_list.next,
|
|
|
|
+ struct xhci_command, cmd_list);
|
|
|
|
+ mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+event_handled:
|
|
xhci_complete_del_and_free_cmd(cmd, cmd_comp_code);
|
|
xhci_complete_del_and_free_cmd(cmd, cmd_comp_code);
|
|
|
|
|
|
inc_deq(xhci, xhci->cmd_ring);
|
|
inc_deq(xhci, xhci->cmd_ring);
|
|
@@ -3988,6 +3859,13 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd,
|
|
cmd->command_trb = xhci->cmd_ring->enqueue;
|
|
cmd->command_trb = xhci->cmd_ring->enqueue;
|
|
list_add_tail(&cmd->cmd_list, &xhci->cmd_list);
|
|
list_add_tail(&cmd->cmd_list, &xhci->cmd_list);
|
|
|
|
|
|
|
|
+ /* if there are no other commands queued we start the timeout timer */
|
|
|
|
+ if (xhci->cmd_list.next == &cmd->cmd_list &&
|
|
|
|
+ !timer_pending(&xhci->cmd_timer)) {
|
|
|
|
+ xhci->current_cmd = cmd;
|
|
|
|
+ mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT);
|
|
|
|
+ }
|
|
|
|
+
|
|
queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3,
|
|
queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3,
|
|
field4 | xhci->cmd_ring->cycle_state);
|
|
field4 | xhci->cmd_ring->cycle_state);
|
|
return 0;
|
|
return 0;
|