• Sarah Sharp's avatar
    USB: xhci: Add watchdog timer for URB cancellation. · 6f5165cf
    Sarah Sharp authored
    In order to giveback a canceled URB, we must ensure that the xHCI
    hardware will not access the buffer in an URB.  We can't modify the
    buffer pointers on endpoint rings without issuing and waiting for a stop
    endpoint command.  Since URBs can be canceled in interrupt context, we
    can't wait on that command.  The old code trusted that the host
    controller would respond to the command, and would giveback the URBs in
    the event handler.  If the hardware never responds to the stop endpoint
    command, the URBs will never be completed, and we might hang the USB
    subsystem.
    
    Implement a watchdog timer that is spawned whenever a stop endpoint
    command is queued.  If a stop endpoint command event is found on the
    event ring during an interrupt, we need to stop the watchdog timer with
    del_timer().  Since del_timer() can fail if the timer is running and
    waiting on the xHCI lock, we need a way to signal to the timer that
    everything is fine and it should exit.  If we simply clear
    EP_HALT_PENDING, a new stop endpoint command could sneak in and set it
    before the watchdog timer can grab the lock.
    
    Instead we use a combination of the EP_HALT_PENDING flag and a counter
    for the number of pending stop endpoint commands
    (xhci_virt_ep->stop_cmds_pending).  If we need to cancel the watchdog
    timer and del_timer() succeeds, we decrement the number of pending stop
    endpoint commands.  If del_timer() fails, we leave the number of pending
    stop endpoint commands alone.  In either case, we clear the
    EP_HALT_PENDING flag.
    
    The timer will decrement the number of pending stop endpoint commands
    once it obtains the lock.  If the timer is the tail end of the last stop
    endpoint command (xhci_virt_ep->stop_cmds_pending == 0), and the
    endpoint's command is still pending (EP_HALT_PENDING is set), we assume
    the host is dying.  The watchdog timer will set XHCI_STATE_DYING, try to
    halt the xHCI host, and give back all pending URBs.
    
    Various other places in the driver need to check whether the xHCI host
    is dying.  If the interrupt handler ever notices, it should immediately
    stop processing events.  The URB enqueue function should also return
    -ESHUTDOWN.  The URB dequeue function should simply return the value
    of usb_hcd_check_unlink_urb() and the watchdog timer will take care of
    giving the URB back.  When a device is disconnected, the xHCI hardware
    structures should be freed without issuing a disable slot command (since
    the hardware probably won't respond to it anyway).  The debugging
    polling loop should stop polling if the host is dying.
    
    When a device is disconnected, any pending watchdog timers are killed
    with del_timer_sync().  It must be synchronous so that the watchdog
    timer doesn't attempt to access the freed endpoint structures.
    Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
    6f5165cf
xhci-mem.c 29.4 KB