This is a note to let you know that I've just added the patch titled iwlwifi: fix RFkill while calibrating to the 3.17-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: iwlwifi-fix-rfkill-while-calibrating.patch and it can be found in the queue-3.17 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From 31b8b343e019e0a0c57ca9c13520a87f9cab884b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach <emmanuel.grumbach@xxxxxxxxx> Date: Sun, 2 Nov 2014 15:48:09 +0200 Subject: iwlwifi: fix RFkill while calibrating From: Emmanuel Grumbach <emmanuel.grumbach@xxxxxxxxx> commit 31b8b343e019e0a0c57ca9c13520a87f9cab884b upstream. If the RFkill interrupt fires while we calibrate, it would make the firmware fail and the driver wasn't able to recover. Change the flow so that the driver will kill the firmware in that case. Since we have now two flows that are calling trans_stop_device (the RFkill interrupt and the op_mode_mvm_start function) - we need to better sync this. Use the STATUS_DEVICE_ENABLED in the pcie transport in an atomic way to achieve this. This fixes: https://bugzilla.kernel.org/show_bug.cgi?id=86231 Reviewed-by: Johannes Berg <johannes.berg@xxxxxxxxx> Reviewed-by: Luciano Coelho <luciano.coelho@xxxxxxxxx> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@xxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/net/wireless/iwlwifi/mvm/fw.c | 10 +++++++++- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 1 + drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/ops.c | 11 ++++++++++- drivers/net/wireless/iwlwifi/pcie/trans.c | 4 ++-- 5 files changed, 23 insertions(+), 4 deletions(-) --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -282,7 +282,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mv lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(mvm->init_ucode_complete)) + if (WARN_ON_ONCE(mvm->init_ucode_complete || mvm->calibrating)) return 0; iwl_init_notification_wait(&mvm->notif_wait, @@ -332,6 +332,8 @@ int iwl_run_init_mvm_ucode(struct iwl_mv goto out; } + mvm->calibrating = true; + /* Send TX valid antennas before triggering calibrations */ ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); if (ret) @@ -356,11 +358,17 @@ int iwl_run_init_mvm_ucode(struct iwl_mv MVM_UCODE_CALIB_TIMEOUT); if (!ret) mvm->init_ucode_complete = true; + + if (ret && iwl_mvm_is_radio_killed(mvm)) { + IWL_DEBUG_RF_KILL(mvm, "RFKILL while calibrating.\n"); + ret = 1; + } goto out; error: iwl_remove_notification(&mvm->notif_wait, &calib_wait); out: + mvm->calibrating = false; if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) { /* we want to debug INIT and we have no NVM - fake */ mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -778,6 +778,7 @@ static void iwl_mvm_restart_cleanup(stru iwl_trans_stop_device(mvm->trans); mvm->scan_status = IWL_MVM_SCAN_NONE; + mvm->calibrating = false; /* just in case one was running */ ieee80211_remain_on_channel_expired(mvm->hw); --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -541,6 +541,7 @@ struct iwl_mvm { enum iwl_ucode_type cur_ucode; bool ucode_loaded; bool init_ucode_complete; + bool calibrating; u32 error_event_table; u32 log_event_table; u32 umac_error_event_table; --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -745,6 +745,7 @@ void iwl_mvm_set_hw_ctkill_state(struct static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + bool calibrating = ACCESS_ONCE(mvm->calibrating); if (state) set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); @@ -753,7 +754,15 @@ static bool iwl_mvm_set_hw_rfkill_state( wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); - return state && mvm->cur_ucode != IWL_UCODE_INIT; + /* iwl_run_init_mvm_ucode is waiting for results, abort it */ + if (calibrating) + iwl_abort_notification_waits(&mvm->notif_wait); + + /* + * Stop the device if we run OPERATIONAL firmware or if we are in the + * middle of the calibrations. + */ + return state && (mvm->cur_ucode != IWL_UCODE_INIT || calibrating); } static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -913,7 +913,8 @@ static void iwl_trans_pcie_stop_device(s * restart. So don't process again if the device is * already dead. */ - if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) { + if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) { + IWL_DEBUG_INFO(trans, "DEVICE_ENABLED bit was set and is now cleared\n"); iwl_pcie_tx_stop(trans); iwl_pcie_rx_stop(trans); @@ -943,7 +944,6 @@ static void iwl_trans_pcie_stop_device(s /* clear all status bits */ clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); clear_bit(STATUS_INT_ENABLED, &trans->status); - clear_bit(STATUS_DEVICE_ENABLED, &trans->status); clear_bit(STATUS_TPOWER_PMI, &trans->status); clear_bit(STATUS_RFKILL, &trans->status); Patches currently in stable-queue which might be from emmanuel.grumbach@xxxxxxxxx are queue-3.17/iwlwifi-fix-rfkill-while-calibrating.patch -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html