> 
> 
> The patch below does not apply to the 3.10-stable tree.
> If someone wants it applied there, or to any other stable or longterm tree,
> then please email the backport, including the original git commit id to
> <stable@vger.kernel.org>.

I'll drop this one for 3.10.
Conflicts are too big for my poorly sleep fueled brain right now.
I did port it for later kernel.

> 
> thanks,
> 
> greg k-h
> 
> ------------------ original commit in Linus's tree ------------------
> 
> From 31b8b343e019e0a0c57ca9c13520a87f9cab884b Mon Sep 17 00:00:00
> 2001
> From: Emmanuel Grumbach <emmanuel.grumb...@intel.com>
> Date: Sun, 2 Nov 2014 15:48:09 +0200
> Subject: [PATCH] iwlwifi: fix RFkill while calibrating
> 
> 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@vger.kernel.org> [3.10+]
> Reviewed-by: Johannes Berg <johannes.b...@intel.com>
> Reviewed-by: Luciano Coelho <luciano.coe...@intel.com>
> Signed-off-by: Emmanuel Grumbach <emmanuel.grumb...@intel.com>
> 
> diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c
> b/drivers/net/wireless/iwlwifi/mvm/fw.c
> index e0d9f19650b0..eb03943f8463 100644
> --- a/drivers/net/wireless/iwlwifi/mvm/fw.c
> +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
> @@ -284,7 +284,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,
> @@ -334,6 +334,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)
> @@ -358,11 +360,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 585fe5b7100f..b62405865b25 100644
> --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
> +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
> @@ -788,6 +788,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm
> *mvm)
> 
>       mvm->scan_status = IWL_MVM_SCAN_NONE;
>       mvm->ps_disabled = false;
> +     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 b153ced7015b..845429c88cf4 100644
> --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
> +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
> @@ -548,6 +548,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 27fb0a1ef274..5b719ee8e789 100644
> --- a/drivers/net/wireless/iwlwifi/mvm/ops.c
> +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
> @@ -753,6 +753,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);
> @@ -761,7 +762,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 3781b029e54a..160c3ebc48d0 100644
> --- a/drivers/net/wireless/iwlwifi/pcie/trans.c
> +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
> @@ -915,7 +915,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);
> 
> @@ -945,7 +946,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);
> 

--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to