xhci 1.0: Set transfer burst count field.
authorSarah Sharp <sarah.a.sharp@linux.intel.com>
Fri, 8 Apr 2011 16:37:29 +0000 (09:37 -0700)
committerSarah Sharp <sarah.a.sharp@linux.intel.com>
Mon, 2 May 2011 23:42:56 +0000 (16:42 -0700)
The xHCI 1.0 specification adds a new field to the fourth dword in an
isochronous TRB: the transfer burst count (TBC).  This field is only
non-zero for SuperSpeed devices.  Each SS endpoint sets the bMaxBurst
field in the SuperSpeed endpoint companion descriptor, which indicates how
many max-packet-sized "bursts" it can handle in one service interval.  The
device driver may choose to burst less max packet sized chunks each
service interval (which is defined by one TD).  The xHCI driver indicates
to the host controller how many bursts it needs to schedule through the
transfer burst count field.

This patch will only effect xHCI hosts that advertise 1.0 support (0x100)
in the HCI version field of their capabilities register.

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

index 27d690d889af8833c9cd68719c41542f9a075930..cc5963263a65878548ad341a5552c3e955becf6a 100644 (file)
@@ -3123,6 +3123,27 @@ static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
        return num_trbs;
 }
 
+/*
+ * The transfer burst count field of the isochronous TRB defines the number of
+ * bursts that are required to move all packets in this TD.  Only SuperSpeed
+ * devices can burst up to bMaxBurst number of packets per service interval.
+ * This field is zero based, meaning a value of zero in the field means one
+ * burst.  Basically, for everything but SuperSpeed devices, this field will be
+ * zero.  Only xHCI 1.0 host controllers support this field.
+ */
+static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci,
+               struct usb_device *udev,
+               struct urb *urb, unsigned int total_packet_count)
+{
+       unsigned int max_burst;
+
+       if (xhci->hci_version < 0x100 || udev->speed != USB_SPEED_SUPER)
+               return 0;
+
+       max_burst = urb->ep->ss_ep_comp.bMaxBurst;
+       return roundup(total_packet_count, max_burst + 1) - 1;
+}
+
 /* This is for isoc transfer */
 static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                struct urb *urb, int slot_id, unsigned int ep_index)
@@ -3164,14 +3185,18 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        /* Queue the first TRB, even if it's zero-length */
        for (i = 0; i < num_tds; i++) {
                unsigned int total_packet_count;
+               unsigned int burst_count;
 
                first_trb = true;
                running_total = 0;
                addr = start_addr + urb->iso_frame_desc[i].offset;
                td_len = urb->iso_frame_desc[i].length;
                td_remain_len = td_len;
+               /* FIXME: Ignoring zero-length packets, can those happen? */
                total_packet_count = roundup(td_len,
                                le16_to_cpu(urb->ep->desc.wMaxPacketSize));
+               burst_count = xhci_get_burst_count(xhci, urb->dev, urb,
+                               total_packet_count);
 
                trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
 
@@ -3185,7 +3210,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 
                for (j = 0; j < trbs_per_td; j++) {
                        u32 remainder = 0;
-                       field = 0;
+                       field = TRB_TBC(burst_count);
 
                        if (first_trb) {
                                /* Queue the isoc TRB */
index 85e779808189946b6b706ae18f11ba16035d8774..87ec3b07972857a58e85e15f8a426f14a0f7fd28 100644 (file)
@@ -943,6 +943,7 @@ struct xhci_event_cmd {
 /* Interrupter Target - which MSI-X vector to target the completion event at */
 #define TRB_INTR_TARGET(p)     (((p) & 0x3ff) << 22)
 #define GET_INTR_TARGET(p)     (((p) >> 22) & 0x3ff)
+#define TRB_TBC(p)             (((p) & 0x3) << 7)
 
 /* Cycle bit - indicates TRB ownership by HC or HCD */
 #define TRB_CYCLE              (1<<0)