xhci 1.0: Only interrupt on short packet for IN EPs.
authorSarah Sharp <sarah.a.sharp@linux.intel.com>
Wed, 23 Mar 2011 23:26:26 +0000 (16:26 -0700)
committerSarah Sharp <sarah.a.sharp@linux.intel.com>
Mon, 2 May 2011 23:42:55 +0000 (16:42 -0700)
It doesn't make sense to set the interrupt on short packet (TRB_ISP) flag
for TRBs queued to endpoints that only receive packets from the host
controller (i.e. OUT endpoints).  Packets can only be short when they are
sent from a USB device.  Plus, the xHCI 1.0 specification forbids setting
the flag for anything but IN endpoints.

While we're at it, remove some of my snide remarks about the inefficiency
of event data TRBs.

Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
drivers/usb/host/xhci-ring.c

index 73f8db0ecc4b6709cbac670c64218bc576668a2a..766f6a615b2a4d0470a73f26abbcf84b007ddf11 100644 (file)
@@ -2741,6 +2741,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                        td->last_trb = ep_ring->enqueue;
                        field |= TRB_IOC;
                }
+
+               /* Only set interrupt on short packet for IN endpoints */
+               if (usb_urb_dir_in(urb))
+                       field |= TRB_ISP;
+
                xhci_dbg(xhci, " sg entry: dma = %#x, len = %#x (%d), "
                                "64KB boundary at %#x, end dma = %#x\n",
                                (unsigned int) addr, trb_buff_len, trb_buff_len,
@@ -2766,12 +2771,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                                lower_32_bits(addr),
                                upper_32_bits(addr),
                                length_field,
-                               /* We always want to know if the TRB was short,
-                                * or we won't get an event when it completes.
-                                * (Unless we use event data TRBs, which are a
-                                * waste of space and HC resources.)
-                                */
-                               field | TRB_ISP | TRB_TYPE(TRB_NORMAL));
+                               field | TRB_TYPE(TRB_NORMAL));
                --num_trbs;
                running_total += trb_buff_len;
 
@@ -2905,6 +2905,11 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                        td->last_trb = ep_ring->enqueue;
                        field |= TRB_IOC;
                }
+
+               /* Only set interrupt on short packet for IN endpoints */
+               if (usb_urb_dir_in(urb))
+                       field |= TRB_ISP;
+
                remainder = xhci_td_remainder(urb->transfer_buffer_length -
                                running_total);
                length_field = TRB_LEN(trb_buff_len) |
@@ -2918,12 +2923,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                                lower_32_bits(addr),
                                upper_32_bits(addr),
                                length_field,
-                               /* We always want to know if the TRB was short,
-                                * or we won't get an event when it completes.
-                                * (Unless we use event data TRBs, which are a
-                                * waste of space and HC resources.)
-                                */
-                               field | TRB_ISP | TRB_TYPE(TRB_NORMAL));
+                               field | TRB_TYPE(TRB_NORMAL));
                --num_trbs;
                running_total += trb_buff_len;
 
@@ -3009,7 +3009,12 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                  field);
 
        /* If there's data, queue data TRBs */
-       field = 0;
+       /* Only set interrupt on short packet for IN endpoints */
+       if (usb_urb_dir_in(urb))
+               field = TRB_ISP | TRB_TYPE(TRB_DATA);
+       else
+               field = TRB_TYPE(TRB_DATA);
+
        length_field = TRB_LEN(urb->transfer_buffer_length) |
                xhci_td_remainder(urb->transfer_buffer_length) |
                TRB_INTR_TARGET(0);
@@ -3020,8 +3025,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                                lower_32_bits(urb->transfer_dma),
                                upper_32_bits(urb->transfer_dma),
                                length_field,
-                               /* Event on short tx */
-                               field | TRB_ISP | TRB_TYPE(TRB_DATA) | ep_ring->cycle_state);
+                               field | ep_ring->cycle_state);
        }
 
        /* Save the DMA address of the last TRB in the TD */
@@ -3145,6 +3149,10 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                                field |= ep_ring->cycle_state;
                        }
 
+                       /* Only set interrupt on short packet for IN EPs */
+                       if (usb_urb_dir_in(urb))
+                               field |= TRB_ISP;
+
                        /* Chain all the TRBs together; clear the chain bit in
                         * the last TRB to indicate it's the last TRB in the
                         * chain.
@@ -3172,12 +3180,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                                lower_32_bits(addr),
                                upper_32_bits(addr),
                                length_field,
-                               /* We always want to know if the TRB was short,
-                                * or we won't get an event when it completes.
-                                * (Unless we use event data TRBs, which are a
-                                * waste of space and HC resources.)
-                                */
-                               field | TRB_ISP);
+                               field);
                        running_total += trb_buff_len;
 
                        addr += trb_buff_len;