Recent reworks left this loop ending with: if (ep->skip) ep->skip = false; while (ep->skip); which obviously cannot ever repeat. Repetition is only possible by a 'continue' statement earlier in the loop body. Move the "tail" which only executes once out of the loop body. Bring the cases of "Found TD" and "skip isoc td" closely together to consolidate the skipping logic in one place and improve clarity. Now this code properly controls the loop condition. Signed-off-by: Michal Pecio <michal.pecio@xxxxxxxxx> --- drivers/usb/host/xhci-ring.c | 102 ++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 401c34ff2260..e65cc80cb285 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2829,63 +2829,65 @@ static int handle_tx_event(struct xhci_hcd *xhci, } } } - if (!ep_seg) { - - if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) { - skip_isoc_td(xhci, td, ep, status); - continue; - } - - /* - * 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. Ignore it. - * FIXME xHCI 4.10.1.1: this should be freed now, not mid-TD - */ - if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) && - ep_ring->last_td_was_short) { - ep_ring->last_td_was_short = false; - return 0; - } - - /* HC is busted, give up! */ - xhci_err(xhci, - "ERROR Transfer event TRB DMA ptr not " - "part of current TD ep_index %d " - "comp_code %u\n", ep_index, - trb_comp_code); - trb_in_td(xhci, td, ep_trb_dma, true); - return -ESHUTDOWN; - } - + /* + * If ep->skip is set, it means there are missed tds on the + * endpoint ring need to take care of. + * Process them as short transfer until reach the td pointed by + * the event. + */ if (ep->skip) { - xhci_dbg(xhci, - "Found td. Clear skip flag for slot %u ep %u.\n", - slot_id, ep_index); - ep->skip = false; + if (ep_seg) { + xhci_dbg(xhci, + "Found td. Clear skip flag for slot %u ep %u.\n", + slot_id, ep_index); + ep->skip = false; + } else { + if (usb_endpoint_xfer_isoc(&td->urb->ep->desc)) + skip_isoc_td(xhci, td, ep, status); + else + break; + } } - /* - * If ep->skip is set, it means there are missed tds on the - * endpoint ring need to take care of. - * Process them as short transfer until reach the td pointed by - * the event. - */ } while (ep->skip); + if (!ep_seg) { + + /* + * 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. Ignore it. + * FIXME xHCI 4.10.1.1: this should be freed now, not mid-TD + */ + if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) && + ep_ring->last_td_was_short) { + ep_ring->last_td_was_short = false; + return 0; + } + + /* HC is busted, give up! */ + xhci_err(xhci, + "ERROR Transfer event TRB DMA ptr not " + "part of current TD ep_index %d " + "comp_code %u\n", ep_index, + trb_comp_code); + trb_in_td(xhci, td, ep_trb_dma, true); + return -ESHUTDOWN; + } + if (trb_comp_code == COMP_SHORT_PACKET) ep_ring->last_td_was_short = true; else ep_ring->last_td_was_short = false; -- 2.43.0