On Wed, Nov 19, 2014 at 06:23:09PM +0200, Emmanuel Grumbach wrote: > From: Emmanuel Grumbach <emmanuel.grumbach@xxxxxxxxx> > > commit 31b8b343e019e0a0c57ca9c13520a87f9cab884b upstream. > Thank you, I'll use this for the 3.16 kernel as well. Cheers, -- Luís > 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 > > CC: <stable@xxxxxxxxxxxxxxx> [3.10+] > Reviewed-by: Johannes Berg <johannes.berg@xxxxxxxxx> > Reviewed-by: Luciano Coelho <luciano.coelho@xxxxxxxxx> > Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@xxxxxxxxx> > --- > 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(-) > > diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c > index bf720a8..c77e6bc 100644 > --- 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_mvm *mvm, bool read_nvm) > > 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_mvm *mvm, bool read_nvm) > 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_mvm *mvm, bool read_nvm) > 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) + > diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c > index cdc272d..26de13b 100644 > --- 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(struct iwl_mvm *mvm) > 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); > diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h > index 2e73d3b..c35f555 100644 > --- 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; > diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c > index d31a117..f9471ee 100644 > --- 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 iwl_mvm *mvm, bool state) > 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(struct iwl_op_mode *op_mode, bool 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) > diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c > index d7231a8..6c02467 100644 > --- 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(struct iwl_trans *trans) > * 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(struct iwl_trans *trans) > /* 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); > > -- > 1.9.1 > > -- > 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 -- 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