[PATCH v3 4/9] xhci: Simplify setting of TRB type and flags in queue_bulk_sg_tx()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux