xhci: handle no ping response error properly

If a host fails to wake up a isochronous SuperSpeed device from U1/U2
in time for a isoch transfer it will generate a "No ping response error"
Host will then move to the next transfer descriptor.

Handle this case in the same way as missed service errors, tag the
current TD as skipped and handle it on the next transfer event.

Cc: stable <stable@vger.kernel.org>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by Mathias Nyman and committed by Greg Kroah-Hartman 3b4739b8 e210c422

Changed files
+15 -5
drivers
usb
+15 -5
drivers/usb/host/xhci-ring.c
··· 2284 2284 u32 trb_comp_code; 2285 2285 int ret = 0; 2286 2286 int td_num = 0; 2287 + bool handling_skipped_tds = false; 2287 2288 2288 2289 slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); 2289 2290 xdev = xhci->devs[slot_id]; ··· 2420 2419 */ 2421 2420 ep->skip = true; 2422 2421 xhci_dbg(xhci, "Miss service interval error, set skip flag\n"); 2422 + goto cleanup; 2423 + case COMP_PING_ERR: 2424 + ep->skip = true; 2425 + xhci_dbg(xhci, "No Ping response error, Skip one Isoc TD\n"); 2423 2426 goto cleanup; 2424 2427 default: 2425 2428 if (xhci_is_vendor_info_code(xhci, trb_comp_code)) { ··· 2561 2556 ep, &status); 2562 2557 2563 2558 cleanup: 2559 + 2560 + 2561 + handling_skipped_tds = ep->skip && 2562 + trb_comp_code != COMP_MISSED_INT && 2563 + trb_comp_code != COMP_PING_ERR; 2564 + 2564 2565 /* 2565 - * Do not update event ring dequeue pointer if ep->skip is set. 2566 - * Will roll back to continue process missed tds. 2566 + * Do not update event ring dequeue pointer if we're in a loop 2567 + * processing missed tds. 2567 2568 */ 2568 - if (trb_comp_code == COMP_MISSED_INT || !ep->skip) { 2569 + if (!handling_skipped_tds) 2569 2570 inc_deq(xhci, xhci->event_ring); 2570 - } 2571 2571 2572 2572 if (ret) { 2573 2573 urb = td->urb; ··· 2607 2597 * Process them as short transfer until reach the td pointed by 2608 2598 * the event. 2609 2599 */ 2610 - } while (ep->skip && trb_comp_code != COMP_MISSED_INT); 2600 + } while (handling_skipped_tds); 2611 2601 2612 2602 return 0; 2613 2603 }