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 <[email protected]>
---
 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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to