Skip to content
  • Sarah Sharp's avatar
    USB: Disable USB 3.0 LPM in critical sections. · 8306095f
    Sarah Sharp authored
    
    
    There are several places where the USB core needs to disable USB 3.0
    Link PM:
     - usb_bind_interface
     - usb_unbind_interface
     - usb_driver_claim_interface
     - usb_port_suspend/usb_port_resume
     - usb_reset_and_verify_device
     - usb_set_interface
     - usb_reset_configuration
     - usb_set_configuration
    
    Use the new LPM disable/enable functions to temporarily disable LPM
    around these critical sections.
    
    We need to protect the critical section around binding and unbinding USB
    interface drivers.  USB drivers may want to disable hub-initiated USB
    3.0 LPM, which will change the value of the U1/U2 timeouts that the xHCI
    driver will install.  We need to disable LPM completely until the driver
    is bound to the interface, and the driver has a chance to enable
    whatever alternate interface setting it needs in its probe routine.
    Then re-enable USB3 LPM, and recalculate the U1/U2 timeout values.
    
    We also need to disable LPM in usb_driver_claim_interface,
    because drivers like usbfs can bind to an interface through that
    function.  Note, there is no way currently for userspace drivers to
    disable hub-initiated USB 3.0 LPM.  Revisit this later.
    
    When a driver is unbound, the U1/U2 timeouts may change because we are
    unbinding the last driver that needed hub-initiated USB 3.0 LPM to be
    disabled.
    
    USB LPM must be disabled when a USB device is going to be suspended.
    The USB 3.0 spec does not define a state transition from U1 or U2 into
    U3, so we need to bring the device into U0 by disabling LPM before we
    can place it into U3.  Therefore, call usb_unlocked_disable_lpm() in
    usb_port_suspend(), and call usb_unlocked_enable_lpm() in
    usb_port_resume().  If the port suspend fails, make sure to re-enable
    LPM by calling usb_unlocked_enable_lpm(), since usb_port_resume() will
    not be called on a failed port suspend.
    
    USB 3.0 devices lose their USB 3.0 LPM settings (including whether USB
    device-initiated LPM is enabled) across device suspend.  Therefore,
    disable LPM before the device will be reset in
    usb_reset_and_verify_device(), and re-enable LPM after the reset is
    complete and the configuration/alt settings are re-installed.
    
    The calculated U1/U2 timeout values are heavily dependent on what USB
    device endpoints are currently enabled.  When any of the enabled
    endpoints on the device might change, due to a new configuration, or new
    alternate interface setting, we need to first disable USB 3.0 LPM, add
    or delete endpoints from the xHCI schedule, install the new interfaces
    and alt settings, and then re-enable LPM.  Do this in usb_set_interface,
    usb_reset_configuration, and usb_set_configuration.
    
    Basically, there is a call to disable and then enable LPM in all
    functions that lock the bandwidth_mutex.  One exception is
    usb_disable_device, because the device is disconnecting or otherwise
    going away, and we should not care about whether USB 3.0 LPM is enabled.
    
    Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
    8306095f