aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2011-05-24 11:53:29 -0700
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2011-05-25 15:23:35 -0700
commit0714a57c6865f31ed3366e5abdfae7da580d41d2 (patch)
treee4a486c30e1030bd480916bd7b386e23b56d2621 /drivers
parentd762f4383100c2a87b1a3f2d678cd3b5425655b4 (diff)
downloadkernel_samsung_smdk4412-0714a57c6865f31ed3366e5abdfae7da580d41d2.zip
kernel_samsung_smdk4412-0714a57c6865f31ed3366e5abdfae7da580d41d2.tar.gz
kernel_samsung_smdk4412-0714a57c6865f31ed3366e5abdfae7da580d41d2.tar.bz2
xhci: Clear stopped_td when Stop Endpoint command completes.
When an URB is cancelled, the xHCI driver issues a Stop Endpoint command so that it can manipulate the ring and remove the transfer. The xHC hardware then places a transfer event with the completion code "Stopped" or "Stopped Invalid" to let the driver know what TD it was in the middle of processing. This TD and TRB is stored in ep->stopped_td and ep->stopped_trb. These pointers are also used in handling stalled endpoints. By design, the Stop Endpoint command can race with URB completion. By the time the Stop Endpoint command is handled, the URBs to be cancelled may have been given back to the driver. Unfortunately, the stopped_td and stopped_trb pointers were not getting cleared in this case. The USB core unconditionally tries to reset the toggle bits on any endpoints when a new alternate interface setting is installed. When the xHCI driver saw that ep->stopped_td was still set from the Stop Endpoint command, xhci_reset_endpoint assumed the endpoint was actually stalled, and attempted to clean up the endpoint rings. This would manifest itself in a failed Reset Endpoint command and failed Set TR dequeue Pointer command after a successful Configure Endpoint command. It may have also been causing driver oops when the stopped_td was accessed. This patch should be backported to stable kernels since 2.6.31. Before 2.6.33, stopped_td was found in the xhci_endpoint_ring, not the xhci_virt_ep. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/xhci-ring.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 237a765..ba55123 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -692,6 +692,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
if (list_empty(&ep->cancelled_td_list)) {
xhci_stop_watchdog_timer_in_irq(xhci, ep);
+ ep->stopped_td = NULL;
+ ep->stopped_trb = NULL;
ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
return;
}