Skip to content

Commit

Permalink
xhci: don't finish a TD if we get a short transfer event mid TD
Browse files Browse the repository at this point in the history
If the difference is big enough between the bytes asked and received
in a bulk transfer we can get a short transfer event pointing to a TRB in
the middle of the TD. We don't want to handle the TD yet as we will anyway
receive a new event for the last TRB in the TD.

Hold off from finishing the TD and removing it from the list until we
receive an event for the last TRB in the TD

Cc: stable <stable@vger.kernel.org>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Mathias Nyman authored and Greg Kroah-Hartman committed Oct 17, 2015
1 parent 25cb62b commit e210c42
Showing 1 changed file with 10 additions and 0 deletions.
10 changes: 10 additions & 0 deletions drivers/usb/host/xhci-ring.c
Original file line number Diff line number Diff line change
Expand Up @@ -2191,6 +2191,10 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
}
/* Fast path - was this the last TRB in the TD for this URB? */
} else if (event_trb == td->last_trb) {
if (td->urb_length_set && trb_comp_code == COMP_SHORT_TX)
return finish_td(xhci, td, event_trb, event, ep,
status, false);

if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
td->urb->actual_length =
td->urb->transfer_buffer_length -
Expand Down Expand Up @@ -2242,6 +2246,12 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
td->urb->actual_length +=
TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));

if (trb_comp_code == COMP_SHORT_TX) {
xhci_dbg(xhci, "mid bulk/intr SP, wait for last TRB event\n");
td->urb_length_set = true;
return 0;
}
}

return finish_td(xhci, td, event_trb, event, ep, status, false);
Expand Down

0 comments on commit e210c42

Please sign in to comment.