• Andiry Xu's avatar
    USB: xHCI: prevent infinite loop when processing MSE event · c2d7b49f
    Andiry Xu authored
    When a xHC host is unable to handle isochronous transfer in the
    interval, it reports a Missed Service Error event and skips some tds.
    
    Currently xhci driver handles MSE event in the following ways:
    
    1. When encounter a MSE event, set ep->skip flag, update event ring
       dequeue pointer and return.
    
    2. When encounter the next event on this ep, the driver will run the
       do-while loop, fetch td from ep's td_list to find the td
       corresponding to this event.  All tds missed are marked as short
       transfer(-EXDEV).
    
    The do-while loop will end in two ways:
    
    1. If the td pointed by the event trb is found;
    
    2. If the ep ring's td_list is empty.
    
    However, if a buggy HW reports some unpredicted event (for example, an
    overrun event following a MSE event while the ep ring is actually not
    empty), the driver will never find the td, and it will loop until the
    td_list is empty.
    
    Unfortunately, the spinlock is dropped when give back a urb in the
    do-while loop.  During the spinlock released period, the class driver
    may still submit urbs and add tds to the td_list.  This may cause
    disaster, since the td_list will never be empty and the loop never ends,
    and the system hangs.
    
    To fix this, count the number of TDs on the ep ring before skipping TDs,
    and quit the loop when skipped that number of tds.  This guarantees the
    do-while loop will end after certain number of cycles, and driver will
    not be trapped in an infinite loop.
    Signed-off-by: default avatarAndiry Xu <andiry.xu@amd.com>
    Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    c2d7b49f
xhci-ring.c 111 KB