aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2012-05-08 12:22:49 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-01 03:12:59 -0400
commitd818cf47642e6379d61d9304fed3ca7c9d6786a8 (patch)
tree6b6e83de6ec265b0f92a1edd1ed2d1823502bc95 /drivers/usb
parentc97ecdcfde93b2b05a0e5f3b5eaaf38e750337ae (diff)
xhci: Add new short TX quirk for Fresco Logic host.
commit 1530bbc6272d9da1e39ef8e06190d42c13a02733 upstream. Sergio reported that when he recorded audio from a USB headset mic plugged into the USB 3.0 port on his ASUS N53SV-DH72, the audio sounded "robotic". When plugged into the USB 2.0 port under EHCI on the same laptop, the audio sounded fine. The device is: Bus 002 Device 004: ID 046d:0a0c Logitech, Inc. Clear Chat Comfort USB Headset The problem was tracked down to the Fresco Logic xHCI host controller not correctly reporting short transfers on isochronous IN endpoints. The driver would submit a 96 byte transfer, the device would only send 88 or 90 bytes, and the xHCI host would report the transfer had a "successful" completion code, with an untransferred buffer length of 8 or 6 bytes. The successful completion code and non-zero untransferred length is a contradiction. The xHCI host is supposed to only mark a transfer as successful if all the bytes are transferred. Otherwise, the transfer should be marked with a short packet completion code. Without the EHCI bus trace, we wouldn't know whether the xHCI driver should trust the completion code or the untransferred length. With it, we know to trust the untransferred length. Add a new xHCI quirk for the Fresco Logic host controller. If a transfer is reported as successful, but the untransferred length is non-zero, print a warning. For the Fresco Logic host, change the completion code to COMP_SHORT_TX and process the transfer like a short transfer. This should be backported to stable kernels that contain the commit f5182b4155b9d686c5540a6822486400e34ddd98 "xhci: Disable MSI for some Fresco Logic hosts." That commit was marked for stable kernels as old as 2.6.36. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Reported-by: Sergio Correia <lists@uece.net> Tested-by: Sergio Correia <lists@uece.net> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-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 4509f69d670..39e230f2dd1 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)
123 xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u " 123 xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u "
124 "has broken MSI implementation\n", 124 "has broken MSI implementation\n",
125 pdev->revision); 125 pdev->revision);
126 xhci->quirks |= XHCI_TRUST_TX_LENGTH;
126 } 127 }
127 128
128 if (pdev->vendor == PCI_VENDOR_ID_NEC) 129 if (pdev->vendor == PCI_VENDOR_ID_NEC)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 7eab409e062..de3c1513fdb 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,
1739 /* handle completion code */ 1739 /* handle completion code */
1740 switch (trb_comp_code) { 1740 switch (trb_comp_code) {
1741 case COMP_SUCCESS: 1741 case COMP_SUCCESS:
1742 frame->status = 0; 1742 if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {
1743 break; 1743 frame->status = 0;
1744 break;
1745 }
1746 if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
1747 trb_comp_code = COMP_SHORT_TX;
1744 case COMP_SHORT_TX: 1748 case COMP_SHORT_TX:
1745 frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ? 1749 frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
1746 -EREMOTEIO : 0; 1750 -EREMOTEIO : 0;
@@ -1839,13 +1843,16 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
1839 switch (trb_comp_code) { 1843 switch (trb_comp_code) {
1840 case COMP_SUCCESS: 1844 case COMP_SUCCESS:
1841 /* Double check that the HW transferred everything. */ 1845 /* Double check that the HW transferred everything. */
1842 if (event_trb != td->last_trb) { 1846 if (event_trb != td->last_trb ||
1847 TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
1843 xhci_warn(xhci, "WARN Successful completion " 1848 xhci_warn(xhci, "WARN Successful completion "
1844 "on short TX\n"); 1849 "on short TX\n");
1845 if (td->urb->transfer_flags & URB_SHORT_NOT_OK) 1850 if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
1846 *status = -EREMOTEIO; 1851 *status = -EREMOTEIO;
1847 else 1852 else
1848 *status = 0; 1853 *status = 0;
1854 if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
1855 trb_comp_code = COMP_SHORT_TX;
1849 } else { 1856 } else {
1850 *status = 0; 1857 *status = 0;
1851 } 1858 }
@@ -1986,6 +1993,13 @@ static int handle_tx_event(struct xhci_hcd *xhci,
1986 * transfer type 1993 * transfer type
1987 */ 1994 */
1988 case COMP_SUCCESS: 1995 case COMP_SUCCESS:
1996 if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
1997 break;
1998 if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
1999 trb_comp_code = COMP_SHORT_TX;
2000 else
2001 xhci_warn(xhci, "WARN Successful completion on short TX: "
2002 "needs XHCI_TRUST_TX_LENGTH quirk?\n");
1989 case COMP_SHORT_TX: 2003 case COMP_SHORT_TX:
1990 break; 2004 break;
1991 case COMP_STOP: 2005 case COMP_STOP:
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index dfd260ab403..25c3e26b999 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1315,6 +1315,7 @@ struct xhci_hcd {
1315#define XHCI_BROKEN_MSI (1 << 6) 1315#define XHCI_BROKEN_MSI (1 << 6)
1316#define XHCI_RESET_ON_RESUME (1 << 7) 1316#define XHCI_RESET_ON_RESUME (1 << 7)
1317#define XHCI_AMD_0x96_HOST (1 << 9) 1317#define XHCI_AMD_0x96_HOST (1 << 9)
1318#define XHCI_TRUST_TX_LENGTH (1 << 10)
1318 unsigned int num_active_eps; 1319 unsigned int num_active_eps;
1319 unsigned int limit_active_eps; 1320 unsigned int limit_active_eps;
1320 /* There are two roothubs to keep track of bus suspend info for */ 1321 /* There are two roothubs to keep track of bus suspend info for */