aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-ring.c
diff options
context:
space:
mode:
authorAlex He <alex.he@amd.com>2011-06-03 15:58:25 +0800
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2011-06-15 14:37:14 -0700
commite1cf486d881d853d710e2d86a7adfc5fd260990f (patch)
tree73d63dac735e213e1aee47f1ebbbbd02d62e086d /drivers/usb/host/xhci-ring.c
parentd23336329fa4c157ed6256d4279a73b87486a1b6 (diff)
downloadkernel_samsung_smdk4412-e1cf486d881d853d710e2d86a7adfc5fd260990f.zip
kernel_samsung_smdk4412-e1cf486d881d853d710e2d86a7adfc5fd260990f.tar.gz
kernel_samsung_smdk4412-e1cf486d881d853d710e2d86a7adfc5fd260990f.tar.bz2
xHCI 1.0: Force Stopped Event(FSE)
FSE shall occur on the TD natural boundary. The software ep_ring dequeue pointer exceed the hardware ep_ring dequeue pointer in these cases of Table-3. As a result, the event_trb(pointed by hardware dequeue pointer) of the FSE can't be found in the current TD(pointed by software dequeue pointer). What should we do is to figured out the FSE case and skip over it. Signed-off-by: Alex He <alex.he@amd.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb/host/xhci-ring.c')
-rw-r--r--drivers/usb/host/xhci-ring.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 800f417..0c00849 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2063,6 +2063,20 @@ static int handle_tx_event(struct xhci_hcd *xhci,
/* Is this a TRB in the currently executing TD? */
event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
td->last_trb, event_dma);
+
+ /*
+ * Skip the Force Stopped Event. The event_trb(event_dma) of FSE
+ * is not in the current TD pointed by ep_ring->dequeue because
+ * that the hardware dequeue pointer still at the previous TRB
+ * of the current TD. The previous TRB maybe a Link TD or the
+ * last TRB of the previous TD. The command completion handle
+ * will take care the rest.
+ */
+ if (!event_seg && trb_comp_code == COMP_STOP_INVAL) {
+ ret = 0;
+ goto cleanup;
+ }
+
if (!event_seg) {
if (!ep->skip ||
!usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {