aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-mem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/xhci-mem.c')
-rw-r--r--drivers/usb/host/xhci-mem.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 6e5b6057de79..40ac016a7e94 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -738,6 +738,14 @@ void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
ep_ctx->ep_info &= cpu_to_le32(~EP_MAXPSTREAMS_MASK);
ep_ctx->ep_info |= cpu_to_le32(EP_MAXPSTREAMS(max_primary_streams)
| EP_HAS_LSA);
+
+ /*
+ * Set Host Initiated Data Move Disable to always defer stream
+ * selection to the device. xHC implementations may treat this
+ * field as "don't care, forced to 1" anyway - xHCI 1.2 s4.12.1.
+ */
+ ep_ctx->ep_info2 |= EP_HID;
+
ep_ctx->deq = cpu_to_le64(stream_info->ctx_array_dma);
}
@@ -1413,6 +1421,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
unsigned int ep_index;
struct xhci_ep_ctx *ep_ctx;
struct xhci_ring *ep_ring;
+ struct usb_interface_cache *intfc;
unsigned int max_packet;
enum xhci_ring_type ring_type;
u32 max_esit_payload;
@@ -1422,6 +1431,8 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
unsigned int mult;
unsigned int avg_trb_len;
unsigned int err_count = 0;
+ unsigned int is_ums_dev = 0;
+ unsigned int i;
ep_index = xhci_get_endpoint_index(&ep->desc);
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
@@ -1467,6 +1478,33 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
max_burst = xhci_get_endpoint_max_burst(udev, ep);
avg_trb_len = max_esit_payload;
+ /*
+ * VL805 errata - Bulk OUT bursts to superspeed mass-storage
+ * devices behind hub ports can cause data corruption with
+ * non-wMaxPacket-multiple transfers.
+ */
+ for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
+ intfc = udev->config->intf_cache[i];
+ /*
+ * Slight hack - look at interface altsetting 0, which
+ * should be the UMS bulk-only interface. If the class
+ * matches, then we disable out bursts for all OUT
+ * endpoints because endpoint assignments may change
+ * between alternate settings.
+ */
+ if (intfc->altsetting[0].desc.bInterfaceClass ==
+ USB_CLASS_MASS_STORAGE) {
+ is_ums_dev = 1;
+ break;
+ }
+ }
+ if (xhci->quirks & XHCI_VLI_SS_BULK_OUT_BUG &&
+ usb_endpoint_is_bulk_out(&ep->desc) && is_ums_dev &&
+ udev->route)
+ max_burst = 0;
+ else
+ max_burst = xhci_get_endpoint_max_burst(udev, ep);
+
/* FIXME dig Mult and streams info out of ep companion desc */
/* Allow 3 retries for everything but isoc, set CErr = 3 */