Skip to content

Commit

Permalink
USB: xhci: Fix command wait list handling.
Browse files Browse the repository at this point in the history
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 <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Sarah Sharp authored and Greg Kroah-Hartman committed Sep 23, 2009
1 parent 913a8a3 commit a50c8aa
Showing 1 changed file with 29 additions and 17 deletions.
46 changes: 29 additions & 17 deletions drivers/usb/host/xhci-ring.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit a50c8aa

Please sign in to comment.