Commit ad808333 authored by Sarah Sharp's avatar Sarah Sharp

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: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
parent 69e848c2
...@@ -118,6 +118,10 @@ static int xhci_pci_setup(struct usb_hcd *hcd) ...@@ -118,6 +118,10 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
/* AMD PLL quirk */ /* AMD PLL quirk */
if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
xhci->quirks |= XHCI_AMD_PLL_FIX; 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. */ /* Make sure the HC is halted. */
retval = xhci_halt(xhci); retval = xhci_halt(xhci);
......
...@@ -2061,6 +2061,16 @@ static int handle_tx_event(struct xhci_hcd *xhci, ...@@ -2061,6 +2061,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (!event_seg) { if (!event_seg) {
if (!ep->skip || if (!ep->skip ||
!usb_endpoint_xfer_isoc(&td->urb->ep->desc)) { !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! */ /* HC is busted, give up! */
xhci_err(xhci, xhci_err(xhci,
"ERROR Transfer event TRB DMA ptr not " "ERROR Transfer event TRB DMA ptr not "
...@@ -2071,6 +2081,10 @@ static int handle_tx_event(struct xhci_hcd *xhci, ...@@ -2071,6 +2081,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
ret = skip_isoc_td(xhci, td, event, ep, &status); ret = skip_isoc_td(xhci, td, event, ep, &status);
goto cleanup; 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) { if (ep->skip) {
xhci_dbg(xhci, "Found td. Clear skip flag.\n"); xhci_dbg(xhci, "Found td. Clear skip flag.\n");
......
...@@ -1123,6 +1123,7 @@ struct xhci_ring { ...@@ -1123,6 +1123,7 @@ struct xhci_ring {
*/ */
u32 cycle_state; u32 cycle_state;
unsigned int stream_id; unsigned int stream_id;
bool last_td_was_short;
}; };
struct xhci_erst_entry { struct xhci_erst_entry {
...@@ -1290,6 +1291,7 @@ struct xhci_hcd { ...@@ -1290,6 +1291,7 @@ struct xhci_hcd {
#define XHCI_RESET_EP_QUIRK (1 << 1) #define XHCI_RESET_EP_QUIRK (1 << 1)
#define XHCI_NEC_HOST (1 << 2) #define XHCI_NEC_HOST (1 << 2)
#define XHCI_AMD_PLL_FIX (1 << 3) #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 */ /* There are two roothubs to keep track of bus suspend info for */
struct xhci_bus_state bus_state[2]; struct xhci_bus_state bus_state[2];
/* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */ /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment