diff options
Diffstat (limited to 'drivers/usb/host/xhci-hub.c')
-rw-r--r-- | drivers/usb/host/xhci-hub.c | 43 |
1 files changed, 20 insertions, 23 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 1ad6bc1951c7..6231ce6aa0c3 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -20,7 +20,8 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/gfp.h> + +#include <linux/slab.h> #include <asm/unaligned.h> #include "xhci.h" @@ -270,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; @@ -284,34 +284,31 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) spin_lock_irqsave(&xhci->lock, flags); for (i = LAST_EP_INDEX; i > 0; i--) { - if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) - xhci_queue_stop_endpoint(xhci, slot_id, i, suspend); + if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) { + struct xhci_command *command; + command = xhci_alloc_command(xhci, false, false, + GFP_NOIO); + if (!command) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_free_command(xhci, cmd); + return -ENOMEM; + + } + xhci_queue_stop_endpoint(xhci, command, slot_id, i, + suspend); + } } - cmd->command_trb = xhci_find_next_enqueue(xhci->cmd_ring); - list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list); - xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend); + xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend); xhci_ring_cmd_db(xhci); 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"); - spin_lock_irqsave(&xhci->lock, flags); - /* The timeout might have raced with the event ring handler, so - * only delete from the list if the item isn't poisoned. - */ - if (cmd->cmd_list.next != LIST_POISON1) - list_del(&cmd->cmd_list); - spin_unlock_irqrestore(&xhci->lock, flags); + 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; - goto command_cleanup; } - -command_cleanup: xhci_free_command(xhci, cmd); return ret; } |