aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/xhci-pci.c1
-rw-r--r--drivers/usb/host/xhci-ring.c20
-rw-r--r--drivers/usb/host/xhci.h1
3 files changed, 19 insertions, 3 deletions
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 4509f69..39e230f 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -123,6 +123,7 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u "
"has broken MSI implementation\n",
pdev->revision);
+ xhci->quirks |= XHCI_TRUST_TX_LENGTH;
}
if (pdev->vendor == PCI_VENDOR_ID_NEC)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 7eab409..de3c151 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1739,8 +1739,12 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
/* handle completion code */
switch (trb_comp_code) {
case COMP_SUCCESS:
- frame->status = 0;
- break;
+ if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {
+ frame->status = 0;
+ break;
+ }
+ if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
+ trb_comp_code = COMP_SHORT_TX;
case COMP_SHORT_TX:
frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
-EREMOTEIO : 0;
@@ -1839,13 +1843,16 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
switch (trb_comp_code) {
case COMP_SUCCESS:
/* Double check that the HW transferred everything. */
- if (event_trb != td->last_trb) {
+ if (event_trb != td->last_trb ||
+ TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
xhci_warn(xhci, "WARN Successful completion "
"on short TX\n");
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
*status = -EREMOTEIO;
else
*status = 0;
+ if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
+ trb_comp_code = COMP_SHORT_TX;
} else {
*status = 0;
}
@@ -1986,6 +1993,13 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* transfer type
*/
case COMP_SUCCESS:
+ if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
+ break;
+ if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
+ trb_comp_code = COMP_SHORT_TX;
+ else
+ xhci_warn(xhci, "WARN Successful completion on short TX: "
+ "needs XHCI_TRUST_TX_LENGTH quirk?\n");
case COMP_SHORT_TX:
break;
case COMP_STOP:
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index dfd260a..25c3e26 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1315,6 +1315,7 @@ struct xhci_hcd {
#define XHCI_BROKEN_MSI (1 << 6)
#define XHCI_RESET_ON_RESUME (1 << 7)
#define XHCI_AMD_0x96_HOST (1 << 9)
+#define XHCI_TRUST_TX_LENGTH (1 << 10)
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */