[PATCH 1/2] usb: xhci: switch to running avg trb length

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

 



It's unlikely that we will ever know the avg so
instead of assuming it'll be something really large,
we will calculate the avg as we go as mentioned in
XHCI specification section 4.14.1.1.

Signed-off-by: Felipe Balbi <felipe.balbi@xxxxxxxxxxxxxxx>
---
 drivers/usb/host/xhci-mem.c  | 34 ++++++++++++++++++++++++----------
 drivers/usb/host/xhci-ring.c | 20 ++++++++++++++++++++
 drivers/usb/host/xhci.h      |  3 ++-
 3 files changed, 46 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index bad0d1f9a41d..0f2ca6e85bc0 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1451,18 +1451,34 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
 	virt_dev->eps[ep_index].skip = false;
 	ep_ring = virt_dev->eps[ep_index].new_ring;
 
-	/*
-	 * Get values to fill the endpoint context, mostly from ep descriptor.
-	 * The average TRB buffer lengt for bulk endpoints is unclear as we
-	 * have no clue on scatter gather list entry size. For Isoc and Int,
-	 * set it to max available. See xHCI 1.1 spec 4.14.1.1 for details.
-	 */
+	/* Get values to fill the endpoint context, mostly from ep descriptor. */
 	max_esit_payload = xhci_get_max_esit_payload(udev, ep);
 	interval = xhci_get_endpoint_interval(udev, ep);
 	mult = xhci_get_endpoint_mult(udev, ep);
 	max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
 	max_burst = xhci_get_endpoint_max_burst(udev, ep);
-	avg_trb_len = max_esit_payload;
+
+	/*
+	 * We are using a running avg for our endpoint's avg_trb_len. The reason
+	 * is that we have no clue about average transfer sizes for any
+	 * endpoints because the HCD does not know which USB Class is running on
+	 * the other end.
+	 *
+	 * See xHCI 1.1 spec 4.14.1.1 for details about initial avg_trb_len
+	 * setting.
+	 */
+	switch (usb_endpoint_type(&ep->desc)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		avg_trb_len = 8;
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		avg_trb_len = 1024;
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+	case USB_ENDPOINT_XFER_BULK:
+		avg_trb_len = 3072;
+		break;
+	}
 
 	/* FIXME dig Mult and streams info out of ep companion desc */
 
@@ -1472,9 +1488,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
 	/* Some devices get this wrong */
 	if (usb_endpoint_xfer_bulk(&ep->desc) && udev->speed == USB_SPEED_HIGH)
 		max_packet = 512;
-	/* xHCI 1.0 and 1.1 indicates that ctrl ep avg TRB Length should be 8 */
-	if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version >= 0x100)
-		avg_trb_len = 8;
+
 	/* xhci 1.1 with LEC support doesn't use mult field, use RsvdZ */
 	if ((xhci->hci_version > 0x100) && HCC2_LEC(xhci->hcc_params2))
 		mult = 0;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 99b4ff42f7a0..6c41dbbf9f2f 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2901,6 +2901,8 @@ static int prepare_transfer(struct xhci_hcd *xhci,
 	struct xhci_td	*td;
 	struct xhci_ring *ep_ring;
 	struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
+	unsigned int avg_trb_len;
+	unsigned int tx_info;
 
 	ep_ring = xhci_stream_id_to_ring(xdev, ep_index, stream_id);
 	if (!ep_ring) {
@@ -2909,6 +2911,24 @@ static int prepare_transfer(struct xhci_hcd *xhci,
 		return -EINVAL;
 	}
 
+	/*
+	 * Here we update avg_trb_len so that, over time, we get a better
+	 * representation of what the actual average length for this endpoint's
+	 * TRBs are going to be.
+	 */
+	if (urb->transfer_buffer_length > 0) {
+		tx_info = le32_to_cpu(ep_ctx->tx_info);
+
+		avg_trb_len = EP_AVG_TRB_LENGTH(tx_info);
+		avg_trb_len += urb->transfer_buffer_length;
+		avg_trb_len /= 2;
+
+		tx_info &= ~EP_AVG_TRB_LENGTH_MASK;
+		tx_info |= EP_AVG_TRB_LENGTH(avg_trb_len);
+
+		ep_ctx->tx_info = cpu_to_le32(tx_info);
+	}
+
 	ret = prepare_ring(xhci, ep_ring,
 			   le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
 			   num_trbs, mem_flags);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 6c629c97f8ad..9f1e9be0afcc 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -751,7 +751,8 @@ struct xhci_ep_ctx {
 #define GET_MAX_PACKET(p)	((p) & 0x7ff)
 
 /* tx_info bitmasks */
-#define EP_AVG_TRB_LENGTH(p)		((p) & 0xffff)
+#define EP_AVG_TRB_LENGTH_MASK		0xffff
+#define EP_AVG_TRB_LENGTH(p)		((p) & EP_AVG_TRB_LENGTH_MASK)
 #define EP_MAX_ESIT_PAYLOAD_LO(p)	(((p) & 0xffff) << 16)
 #define EP_MAX_ESIT_PAYLOAD_HI(p)	((((p) >> 16) & 0xff) << 24)
 #define CTX_TO_MAX_ESIT_PAYLOAD(p)	(((p) >> 16) & 0xffff)
-- 
2.8.1

--
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