diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/host/xhci-hub.c | 11 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 14 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 378 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 78 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 8 |
5 files changed, 169 insertions, 320 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 12871b5d4a2e..6231ce6aa0c3 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -271,7 +271,6 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) struct xhci_virt_device *virt_dev; struct xhci_command *cmd; unsigned long flags; - int timeleft; int ret; int i; @@ -304,12 +303,10 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) spin_unlock_irqrestore(&xhci->lock, flags); /* Wait for last stop endpoint command to finish */ - timeleft = wait_for_completion_interruptible_timeout( - cmd->completion, - XHCI_CMD_DEFAULT_TIMEOUT); - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for stop endpoint command\n", - timeleft == 0 ? "Timeout" : "Signal"); + wait_for_completion(cmd->completion); + + if (cmd->status == COMP_CMD_ABORT || cmd->status == COMP_CMD_STOP) { + xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n"); ret = -ETIME; } xhci_free_command(xhci, cmd); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 38dc721bc8bb..6a57e81c2a76 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1793,10 +1793,11 @@ void xhci_free_command(struct xhci_hcd *xhci, void xhci_mem_cleanup(struct xhci_hcd *xhci) { struct device *dev = xhci_to_hcd(xhci)->self.controller; - struct xhci_cd *cur_cd, *next_cd; int size; int i, j, num_ports; + del_timer_sync(&xhci->cmd_timer); + /* Free the Event Ring Segment Table and the actual Event Ring */ size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); if (xhci->erst.entries) @@ -1815,11 +1816,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci_ring_free(xhci, xhci->cmd_ring); xhci->cmd_ring = NULL; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed command ring"); - list_for_each_entry_safe(cur_cd, next_cd, - &xhci->cancel_cmd_list, cancel_cmd_list) { - list_del(&cur_cd->cancel_cmd_list); - kfree(cur_cd); - } xhci_cleanup_command_queue(xhci); for (i = 1; i < MAX_HC_SLOTS; ++i) @@ -2323,7 +2319,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) u32 page_size, temp; int i; - INIT_LIST_HEAD(&xhci->cancel_cmd_list); INIT_LIST_HEAD(&xhci->cmd_list); page_size = readl(&xhci->op_regs->page_size); @@ -2510,6 +2505,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) "Wrote ERST address to ir_set 0."); xhci_print_ir_set(xhci, 0); + /* init command timeout timer */ + init_timer(&xhci->cmd_timer); + xhci->cmd_timer.data = (unsigned long) xhci; + xhci->cmd_timer.function = xhci_handle_command_timeout; + /* * XXX: Might need to set the Interrupter Moderation Register to * something other than the default (~1ms minimum between interrupts). diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 3d60865a3d8f..d67ff71209f5 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -287,17 +287,7 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) 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); @@ -323,71 +313,6 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) 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, @@ -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, 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); } +/* + * 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, 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"); return; } + + del_timer(&xhci->cmd_timer); + trace_xhci_cmd_completion(cmd_trb, (struct xhci_generic_trb *) event); 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])); @@ -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); break; 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; case TRB_RESET_EP: WARN_ON(slot_id != TRB_TO_SLOT_ID( @@ -1583,6 +1446,14 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, 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); 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; 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, field4 | xhci->cmd_ring->cycle_state); return 0; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 64c1ba353856..2b8d9a24af09 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1820,6 +1820,11 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, int ret; switch (*cmd_status) { + case COMP_CMD_ABORT: + case COMP_CMD_STOP: + xhci_warn(xhci, "Timeout while waiting for configure endpoint command\n"); + ret = -ETIME; + break; case COMP_ENOMEM: dev_warn(&udev->dev, "Not enough host controller resources " "for new device state.\n"); @@ -1866,6 +1871,11 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id]; switch (*cmd_status) { + case COMP_CMD_ABORT: + case COMP_CMD_STOP: + xhci_warn(xhci, "Timeout while waiting for evaluate context command\n"); + ret = -ETIME; + break; case COMP_EINVAL: dev_warn(&udev->dev, "WARN: xHCI driver setup invalid evaluate " "context command.\n"); @@ -2590,7 +2600,6 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, bool ctx_change, bool must_succeed) { int ret; - int timeleft; unsigned long flags; struct xhci_input_control_ctx *ctrl_ctx; struct xhci_virt_device *virt_dev; @@ -2646,21 +2655,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, spin_unlock_irqrestore(&xhci->lock, flags); /* Wait for the configure endpoint command to complete */ - timeleft = wait_for_completion_interruptible_timeout( - command->completion, - XHCI_CMD_DEFAULT_TIMEOUT); - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for %s command\n", - timeleft == 0 ? "Timeout" : "Signal", - ctx_change == 0 ? - "configure endpoint" : - "evaluate context"); - /* cancel the configure endpoint command */ - ret = xhci_cancel_cmd(xhci, command, command->command_trb); - if (ret < 0) - return ret; - return -ETIME; - } + wait_for_completion(command->completion); if (!ctx_change) ret = xhci_configure_endpoint_result(xhci, udev, @@ -3438,7 +3433,6 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) unsigned int slot_id; struct xhci_virt_device *virt_dev; struct xhci_command *reset_device_cmd; - int timeleft; int last_freed_endpoint; struct xhci_slot_ctx *slot_ctx; int old_active_eps = 0; @@ -3506,15 +3500,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) spin_unlock_irqrestore(&xhci->lock, flags); /* Wait for the Reset Device command to finish */ - timeleft = wait_for_completion_interruptible_timeout( - reset_device_cmd->completion, - XHCI_CMD_DEFAULT_TIMEOUT); - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for reset device command\n", - timeleft == 0 ? "Timeout" : "Signal"); - ret = -ETIME; - goto command_cleanup; - } + wait_for_completion(reset_device_cmd->completion); /* The Reset Device command can't fail, according to the 0.95/0.96 spec, * unless we tried to reset a slot ID that wasn't enabled, @@ -3522,6 +3508,11 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) */ ret = reset_device_cmd->status; switch (ret) { + case COMP_CMD_ABORT: + case COMP_CMD_STOP: + xhci_warn(xhci, "Timeout waiting for reset device command\n"); + ret = -ETIME; + goto command_cleanup; case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */ case COMP_CTX_STATE: /* 0.96 completion code for same thing */ xhci_dbg(xhci, "Can't reset device (slot ID %u) in %s state\n", @@ -3691,7 +3682,6 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); unsigned long flags; - int timeleft; int ret; struct xhci_command *command; @@ -3711,19 +3701,9 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) xhci_ring_cmd_db(xhci); spin_unlock_irqrestore(&xhci->lock, flags); - /* XXX: how much time for xHC slot assignment? */ - timeleft = wait_for_completion_interruptible_timeout( - command->completion, - XHCI_CMD_DEFAULT_TIMEOUT); - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for a slot\n", - timeleft == 0 ? "Timeout" : "Signal"); - /* cancel the enable slot request */ - ret = xhci_cancel_cmd(xhci, NULL, command->command_trb); - return ret; - } + wait_for_completion(command->completion); - if (!xhci->slot_id) { + if (!xhci->slot_id || command->status != COMP_SUCCESS) { xhci_err(xhci, "Error while assigning device slot ID\n"); xhci_err(xhci, "Max number of devices this xHCI host supports is %u.\n", HCS_MAX_SLOTS( @@ -3792,7 +3772,6 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, { const char *act = setup == SETUP_CONTEXT_ONLY ? "context" : "address"; unsigned long flags; - int timeleft; struct xhci_virt_device *virt_dev; int ret = 0; struct xhci_hcd *xhci = hcd_to_xhci(hcd); @@ -3867,23 +3846,18 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, spin_unlock_irqrestore(&xhci->lock, flags); /* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */ - timeleft = wait_for_completion_interruptible_timeout( - command->completion, XHCI_CMD_DEFAULT_TIMEOUT); + wait_for_completion(command->completion); + /* FIXME: From section 4.3.4: "Software shall be responsible for timing * the SetAddress() "recovery interval" required by USB and aborting the * command on a timeout. */ - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for setup %s command\n", - timeleft == 0 ? "Timeout" : "Signal", act); - /* cancel the address device command */ - ret = xhci_cancel_cmd(xhci, NULL, command->command_trb); - if (ret < 0) - return ret; - return -ETIME; - } - switch (command->status) { + case COMP_CMD_ABORT: + case COMP_CMD_STOP: + xhci_warn(xhci, "Timeout while waiting for setup device command\n"); + ret = -ETIME; + break; case COMP_CTX_STATE: case COMP_EBADSLT: xhci_err(xhci, "Setup ERROR: setup %s command for slot %d.\n", diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index fde57b09a9bd..2774526449a6 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1295,7 +1295,6 @@ struct xhci_td { /* command descriptor */ struct xhci_cd { - struct list_head cancel_cmd_list; struct xhci_command *command; union xhci_trb *cmd_trb; }; @@ -1480,9 +1479,10 @@ struct xhci_hcd { #define CMD_RING_STATE_RUNNING (1 << 0) #define CMD_RING_STATE_ABORTED (1 << 1) #define CMD_RING_STATE_STOPPED (1 << 2) - struct list_head cancel_cmd_list; struct list_head cmd_list; unsigned int cmd_ring_reserved_trbs; + struct timer_list cmd_timer; + struct xhci_command *current_cmd; struct xhci_ring *event_ring; struct xhci_erst erst; /* Scratchpad */ @@ -1845,8 +1845,8 @@ void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, struct xhci_dequeue_state *deq_state); void xhci_stop_endpoint_command_watchdog(unsigned long arg); -int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command, - union xhci_trb *cmd_trb); +void xhci_handle_command_timeout(unsigned long data); + void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, unsigned int stream_id); void xhci_cleanup_command_queue(struct xhci_hcd *xhci); |