aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2011-05-25 10:43:56 -0700
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2011-05-27 12:08:13 -0700
commitad808333d8201d53075a11bc8dd83b81f3d68f0b (patch)
tree40f3a11f028175f61cce14088a0f93ebd68c4b60
parent69e848c2090aebba5698a1620604c7dccb448684 (diff)
downloadkernel_samsung_smdk4412-ad808333d8201d53075a11bc8dd83b81f3d68f0b.zip
kernel_samsung_smdk4412-ad808333d8201d53075a11bc8dd83b81f3d68f0b.tar.gz
kernel_samsung_smdk4412-ad808333d8201d53075a11bc8dd83b81f3d68f0b.tar.bz2
Intel xhci: Ignore spurious successful event.
The xHCI host controller in the Panther Point chipset sometimes produces spurious events on the event ring. If it receives a short packet, it first puts a Transfer Event with a short transfer completion code on the event ring. Then it puts a Transfer Event with a successful completion code on the ring for the same TD. The xHCI driver correctly processes the short transfer completion code, gives the URB back to the driver, and then prints a warning in dmesg about the spurious event. These warning messages really fill up dmesg when an HD webcam is plugged into xHCI. This spurious successful event behavior isn't technically disallowed by the xHCI specification, so make the xHCI driver just ignore the spurious completion event. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
-rw-r--r--drivers/usb/host/xhci-pci.c4
-rw-r--r--drivers/usb/host/xhci-ring.c14
-rw-r--r--drivers/usb/host/xhci.h2
3 files changed, 20 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index faf039a..eafd17f 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -118,6 +118,10 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
/* AMD PLL quirk */
if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
xhci->quirks |= XHCI_AMD_PLL_FIX;
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+ pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
+ xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
+ }
/* Make sure the HC is halted. */
retval = xhci_halt(xhci);
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index d1498c0..56f6c58 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2061,6 +2061,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (!event_seg) {
if (!ep->skip ||
!usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
+ /* Some host controllers give a spurious
+ * successful event after a short transfer.
+ * Ignore it.
+ */
+ if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) &&
+ ep_ring->last_td_was_short) {
+ ep_ring->last_td_was_short = false;
+ ret = 0;
+ goto cleanup;
+ }
/* HC is busted, give up! */
xhci_err(xhci,
"ERROR Transfer event TRB DMA ptr not "
@@ -2071,6 +2081,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
ret = skip_isoc_td(xhci, td, event, ep, &status);
goto cleanup;
}
+ if (trb_comp_code == COMP_SHORT_TX)
+ ep_ring->last_td_was_short = true;
+ else
+ ep_ring->last_td_was_short = false;
if (ep->skip) {
xhci_dbg(xhci, "Found td. Clear skip flag.\n");
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 0772a8c..5cfeb86 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1123,6 +1123,7 @@ struct xhci_ring {
*/
u32 cycle_state;
unsigned int stream_id;
+ bool last_td_was_short;
};
struct xhci_erst_entry {
@@ -1290,6 +1291,7 @@ struct xhci_hcd {
#define XHCI_RESET_EP_QUIRK (1 << 1)
#define XHCI_NEC_HOST (1 << 2)
#define XHCI_AMD_PLL_FIX (1 << 3)
+#define XHCI_SPURIOUS_SUCCESS (1 << 4)
/* There are two roothubs to keep track of bus suspend info for */
struct xhci_bus_state bus_state[2];
/* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */