• Luis R. Rodriguez's avatar
    firmware: fix batched requests - send wake up on failure on direct lookups · 90d41e74
    Luis R. Rodriguez authored
    Fix batched requests from waiting forever on failure.
    
    The firmware API batched requests feature has been broken since the API call
    request_firmware_direct() was introduced on commit bba3a87e ("firmware:
    Introduce request_firmware_direct()"), added on v3.14 *iff* the firmware
    being requested was not present in *certain kernel builds* [0].
    
    When no firmware is found the worker which goes on to finish never informs
    waiters queued up of this, so any batched request will stall in what seems
    to be forever (MAX_SCHEDULE_TIMEOUT). Sadly, a reboot will also stall, as
    the reboot notifier was only designed to kill custom fallback workers. The
    issue seems to the user as a type of soft lockup, what *actually* happens
    underneath the hood is a wait call which never completes as we failed to
    issue a completion on error.
    
    For device drivers with optional firmware schemes (ie, Intel iwlwifi, or
    Netronome -- even though it uses request_firmware() and not
    request_firmware_direct()), this could mean that when you boot a system with
    multiple cards the firmware will seem to never load on the system, or that
    the card is just not responsive even the driver initialization. Due to
    differences in scheduling possible this should not always trigger --
    one would need to to ensure that multiple requests are in place at the
    right time for this to work, also release_firmware() must not be called
    prior to any other incoming request. The complexity may not be worth
    supporting batched requests in the future given the wait mechanism is
    only used also for the fallback mechanism. We'll keep it for now and
    just fix it.
    
    Its reported that at least with the Intel WiFi cards on one system this
    issue was creeping up 50% of the boots [0].
    
    Before this commit batched requests testing revealed:
    ============================================================================
    CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n
    CONFIG_FW_LOADER_USER_HELPER=y
    
    Most common Linux distribution setup.
    
    API-type                               no-firmware-found   firmware-found
    ----------------------------------------------------------------------
    request_firmware()                     FAIL                OK
    request_firmware_direct()              FAIL                OK
    request_firmware_nowait(uevent=true)   FAIL                OK
    request_firmware_nowait(uevent=false)  FAIL                OK
    ============================================================================
    CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n
    CONFIG_FW_LOADER_USER_HELPER=n
    
    Only possible if CONFIG_DELL_RBU=n and CONFIG_LEDS_LP55XX_COMMON=n, rare.
    
    API-type                               no-firmware-found   firmware-found
    ----------------------------------------------------------------------
    request_firmware()                     FAIL                OK
    request_firmware_direct()              FAIL                OK
    request_firmware_nowait(uevent=true)   FAIL                OK
    request_firmware_nowait(uevent=false)  FAIL                OK
    ============================================================================
    CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
    CONFIG_FW_LOADER_USER_HELPER=y
    
    Google Android setup.
    
    API-type                               no-firmware-found   firmware-found
    ----------------------------------------------------------------------
    request_firmware()                     OK                  OK
    request_firmware_direct()              FAIL                OK
    request_firmware_nowait(uevent=true)   OK                  OK
    request_firmware_nowait(uevent=false)  OK                  OK
    ============================================================================
    
    Ater this commit batched testing results:
    ============================================================================
    CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n
    CONFIG_FW_LOADER_USER_HELPER=y
    
    Most common Linux distribution setup.
    
    API-type                               no-firmware-found   firmware-found
    ----------------------------------------------------------------------
    request_firmware()                     OK                  OK
    request_firmware_direct()              OK                  OK
    request_firmware_nowait(uevent=true)   OK                  OK
    request_firmware_nowait(uevent=false)  OK                  OK
    ============================================================================
    CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n
    CONFIG_FW_LOADER_USER_HELPER=n
    
    Only possible if CONFIG_DELL_RBU=n and CONFIG_LEDS_LP55XX_COMMON=n, rare.
    
    API-type                               no-firmware-found   firmware-found
    ----------------------------------------------------------------------
    request_firmware()                     OK                  OK
    request_firmware_direct()              OK                  OK
    request_firmware_nowait(uevent=true)   OK                  OK
    request_firmware_nowait(uevent=false)  OK                  OK
    ============================================================================
    CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
    CONFIG_FW_LOADER_USER_HELPER=y
    
    Google Android setup.
    
    API-type                               no-firmware-found   firmware-found
    ----------------------------------------------------------------------
    request_firmware()                     OK                  OK
    request_firmware_direct()              OK                  OK
    request_firmware_nowait(uevent=true)   OK                  OK
    request_firmware_nowait(uevent=false)  OK                  OK
    ============================================================================
    
    [0] https://bugzilla.kernel.org/show_bug.cgi?id=195477
    
    Cc: stable <stable@vger.kernel.org> # v3.14
    Fixes: bba3a87e ("firmware: Introduce request_firmware_direct()"
    Reported-by: default avatarNicolas <nbroeking@me.com>
    Reported-by: default avatarJohn Ewalt  <jewalt@lgsinnovations.com>
    Reported-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
    Signed-off-by: default avatarLuis R. Rodriguez <mcgrof@kernel.org>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    90d41e74
firmware_class.c 45.8 KB