The TRB type and flags are the same for all the TRB expect the first (which needs the opposite value of TRB_CYCLE) and the last (which needs TRB_CHAIN clear and TRB_IOC set). So move the code that sets it up outside the loop. Signed-off-by: David Laight <david.laight@xxxxxxxxxx> --- drivers/usb/host/xhci-ring.c | 48 +++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index a9cf058..51cc8a6 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3276,7 +3276,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, int trb_buff_len, this_sg_len, running_total; int len_left; unsigned int total_packet_count; - bool first_trb; + u32 trb_type_flags; u64 addr; int ret; @@ -3307,6 +3307,14 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, start_trb = &ep_ring->enqueue->generic; start_cycle = ep_ring->cycle_state; + trb_type_flags = TRB_CHAIN | TRB_TYPE(TRB_NORMAL); + /* To avoid changing TRB_CYCLE on the first TRB we set it here */ + trb_type_flags |= TRB_CYCLE; + + /* Set interrupt on short packet for IN endpoints */ + if (usb_urb_dir_in(urb)) + trb_type_flags |= TRB_ISP; + running_total = 0; len_left = urb->transfer_buffer_length; /* @@ -3326,39 +3334,26 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (trb_buff_len > urb->transfer_buffer_length) trb_buff_len = urb->transfer_buffer_length; - first_trb = true; /* Queue the first TRB, even if it's zero-length */ for (;;) { - u32 field = 0; u32 length_field = 0; u32 remainder = 0; - /* Don't change the cycle bit of the first TRB until later */ - if (first_trb) { - first_trb = false; - if (start_cycle == 0) - field |= 0x1; - } else - field |= ep_ring->cycle_state; + /* Set the correct cycle bit (inverted for first TRB). */ + trb_type_flags ^= ep_ring->cycle_state; - /* Chain all the TRBs together; clear the chain bit in the last - * TRB to indicate it's the last TRB in the chain. - */ - if (trb_buff_len != len_left) { - if (trb_buff_len == 0) - goto next_frag; - field |= TRB_CHAIN; - } else { + /* Check for last fragment... */ + if (trb_buff_len == len_left) { /* FIXME - add check for ZERO_PACKET flag before this */ urb_priv = urb->hcpriv; urb_priv->td[0]->last_trb = ep_ring->enqueue; - field |= TRB_IOC; + /* Request interrupt and clear chain */ + trb_type_flags ^= TRB_IOC | TRB_CHAIN; + } else { + if (trb_buff_len == 0) + goto next_frag; } - /* Only set interrupt on short packet for IN endpoints */ - if (usb_urb_dir_in(urb)) - field |= TRB_ISP; - /* Set the TRB length, TD size, and interrupter fields. */ if (xhci->hci_version < 0x100) { remainder = xhci_td_remainder(len_left); @@ -3375,12 +3370,15 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, lower_32_bits(addr), upper_32_bits(addr), length_field, - field | TRB_TYPE(TRB_NORMAL)); + trb_type_flags); /* If we didn't set the chain bit, we must have finished */ - if (!(field & TRB_CHAIN)) + if (!(trb_type_flags & TRB_CHAIN)) break; + /* We want the current cycle in subsequent TRB */ + trb_type_flags &= ~TRB_CYCLE; + running_total += trb_buff_len; len_left -= trb_buff_len; -- 1.8.1.2 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html