]> git.baikalelectronics.ru Git - kernel.git/commit
iwlwifi: pcie: fix a race in firmware loading flow
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Mon, 13 Jun 2016 05:28:26 +0000 (08:28 +0300)
committerLuca Coelho <luciano.coelho@intel.com>
Wed, 6 Jul 2016 07:16:12 +0000 (10:16 +0300)
commitaa530a7c07c131416faba7cc6f10c9f8464475df
tree567536a45f9a61b173ed1cfb08cd14a37d6bc413
parentabfc320d276ab5cc99cec175731ad59aad9ab4d0
iwlwifi: pcie: fix a race in firmware loading flow

Upon firmware load interrupt (FH_TX), the ISR re-enables the
firmware load interrupt only to avoid races with other
flows as described in the commit below. When the firmware
is completely loaded, the thread that is loading the
firmware will enable all the interrupts to make sure that
the driver gets the ALIVE interrupt.
The problem with that is that the thread that is loading
the firmware is actually racing against the ISR and we can
get to the following situation:

CPU0 CPU1
iwl_pcie_load_given_ucode
...
iwl_pcie_load_firmware_chunk
wait_for_interrupt
<interrupt>
ISR handles CSR_INT_BIT_FH_TX
ISR wakes up the thread on CPU0
/* enable all the interrupts
 * to get the ALIVE interrupt
 */
iwl_enable_interrupts
ISR re-enables CSR_INT_BIT_FH_TX only
/* start the firmware */
iwl_write32(trans, CSR_RESET, 0);

BUG! ALIVE interrupt will never arrive since it has been
masked by CPU1.

In order to fix that, change the ISR to first check if
STATUS_INT_ENABLED is set. If so, re-enable all the
interrupts. If STATUS_INT_ENABLED is clear, then we can
check what specific interrupt happened and re-enable only
that specific interrupt (RFKILL or FH_TX).

All the credit for the analysis goes to Kirtika who did the
actual debugging work.

Cc: <stable@vger.kernel.org> [4.5+]
Fixes: e0841c24e37 ("iwlwifi: pcie: fix RF-Kill vs. firmware load race")
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/pcie/internal.h
drivers/net/wireless/intel/iwlwifi/pcie/rx.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c