From a50c8aa953c65fd690eca03a2618ac445a3da05d Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 4 Sep 2009 10:53:15 -0700 Subject: USB: xhci: Fix command wait list handling. In the xHCI driver, configure endpoint commands that are submitted to the hardware may involve one of two data structures. If the configure endpoint command is setting up a new configuration or modifying max packet sizes, the data structures and completions are statically allocated in the xhci_virt_device structure. If the command is being used to set up streams or add hub information, then the data structures are dynamically allocated, and placed on a device command waiting list. Break out the code to check whether a completed command is in the device command waiting list. Fix a subtle bug in the old code: continue processing the command if the command isn't in the wait list. In the old code, if there was a command in the wait list, but it didn't match the completed command, the completed command event would be dropped. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 46 ++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index a9379b3beba..2274604e863 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -685,6 +685,34 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci, } } +/* Check to see if a command in the device's command queue matches this one. + * Signal the completion or free the command, and return 1. Return 0 if the + * completed command isn't at the head of the command list. + */ +static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, + struct xhci_event_cmd *event) +{ + struct xhci_command *command; + + if (list_empty(&virt_dev->cmd_list)) + return 0; + + command = list_entry(virt_dev->cmd_list.next, + struct xhci_command, cmd_list); + if (xhci->cmd_ring->dequeue != command->command_trb) + return 0; + + command->status = + GET_COMP_CODE(event->status); + list_del(&command->cmd_list); + if (command->completion) + complete(command->completion); + else + xhci_free_command(xhci, command); + return 1; +} + static void handle_cmd_completion(struct xhci_hcd *xhci, struct xhci_event_cmd *event) { @@ -724,24 +752,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, break; case TRB_TYPE(TRB_CONFIG_EP): virt_dev = xhci->devs[slot_id]; - /* Check to see if a command in the device's command queue - * matches this one. Signal the completion or free the command. - */ - if (!list_empty(&virt_dev->cmd_list)) { - struct xhci_command *command; - command = list_entry(virt_dev->cmd_list.next, - struct xhci_command, cmd_list); - if (xhci->cmd_ring->dequeue == command->command_trb) { - command->status = - GET_COMP_CODE(event->status); - list_del(&command->cmd_list); - if (command->completion) - complete(command->completion); - else - xhci_free_command(xhci, command); - } + if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event)) break; - } /* * Configure endpoint commands can come from the USB core * configuration or alt setting changes, or because the HW -- cgit v1.2.3