diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 68 |
1 files changed, 33 insertions, 35 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 2dd11732bb87..7597ef8105c6 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2862,10 +2862,9 @@ static int handle_tx_event(struct xhci_hcd *xhci, td = list_first_entry(&ep_ring->td_list, struct xhci_td, td_list); - /* Is this TRB not part of the currently executing TD? */ - if (!trb_in_td(td, ep_trb_dma)) { + if (ep->skip) { - if (ep->skip) { + if (!trb_in_td(td, ep_trb_dma)) { /* this event is unlikely to match any TD, don't skip them all */ if (trb_comp_code == COMP_STOPPED_LENGTH_INVALID) return 0; @@ -2903,38 +2902,6 @@ static int handle_tx_event(struct xhci_hcd *xhci, goto check_endpoint_halted; } - /* TD was queued after xrun, maybe xrun was on a link, don't panic yet */ - if (ring_xrun_event) - return 0; - - /* - * Skip the Force Stopped Event. The 'ep_trb' 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 (trb_comp_code == COMP_STOPPED || - trb_comp_code == COMP_STOPPED_LENGTH_INVALID) { - return 0; - } - - /* - * Some hosts give a spurious success event after a short - * transfer or error on last TRB. Ignore it. - */ - if (xhci_spurious_success_tx_event(xhci, ep_ring)) { - xhci_dbg(xhci, "Spurious event dma %pad, comp_code %u after %u\n", - &ep_trb_dma, trb_comp_code, ep_ring->old_trb_comp_code); - ep_ring->old_trb_comp_code = 0; - return 0; - } - - /* HC is busted, give up! */ - goto debug_finding_td; - } - - if (ep->skip) { xhci_dbg(xhci, "Found td. Clear skip flag for slot %u ep %u.\n", slot_id, ep_index); @@ -2949,6 +2916,37 @@ static int handle_tx_event(struct xhci_hcd *xhci, */ } while (ep->skip); + /* Handle events not referencing the current TD */ + if (!trb_in_td(td, ep_trb_dma)) { + /* TD was queued after xrun, maybe xrun was on a link, don't panic yet */ + if (ring_xrun_event) + return 0; + + /* + * Skip the Force Stopped Event. The 'ep_trb' 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 (trb_comp_code == COMP_STOPPED || trb_comp_code == COMP_STOPPED_LENGTH_INVALID) + return 0; + + /* + * Some hosts give a spurious success event after a short + * transfer or error on last TRB. Ignore it. + */ + if (xhci_spurious_success_tx_event(xhci, ep_ring)) { + xhci_dbg(xhci, "Spurious event dma %pad, comp_code %u after %u\n", + &ep_trb_dma, trb_comp_code, ep_ring->old_trb_comp_code); + ep_ring->old_trb_comp_code = 0; + return 0; + } + + /* HC is busted, give up! */ + goto debug_finding_td; + } + ep_ring->old_trb_comp_code = trb_comp_code; /* Get out if a TD was queued at enqueue after the xrun occurred */ |
