]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
iwlwifi: fix load in rfkill flow for unified firmware
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Wed, 29 May 2019 13:39:50 +0000 (16:39 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Sat, 1 Jun 2019 05:04:46 +0000 (08:04 +0300)
When we have a single image (same firmware image for INIT and
OPERATIONAL), we couldn't load the driver and register to the
stack if we had hardware RF-Kill asserted.

Fix this. This required a few changes:

1) Run the firmware as part of the INIT phase even if its
   ucode_type is not IWL_UCODE_INIT.
2) Send the commands that are sent to the unified image in
   INIT flow even in RF-Kill.
3) Don't ask the transport to stop the hardware upon RF-Kill
   interrupt if the RF-Kill is asserted.
4) Allow the RF-Kill interrupt to take us out of L1A so that
   the RF-Kill interrupt will be received by the host (to
   enable the radio).

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/pcie/internal.h

index ab68b5d53ec957d02156f3989c336d6b448a70be..153717587aebd31e89b69b4bf2853f8ac485910e 100644 (file)
@@ -311,6 +311,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
        int ret;
        enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img;
        static const u16 alive_cmd[] = { MVM_ALIVE };
+       bool run_in_rfkill =
+               ucode_type == IWL_UCODE_INIT || iwl_mvm_has_unified_ucode(mvm);
 
        if (ucode_type == IWL_UCODE_REGULAR &&
            iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) &&
@@ -328,7 +330,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
                                   alive_cmd, ARRAY_SIZE(alive_cmd),
                                   iwl_alive_fn, &alive_data);
 
-       ret = iwl_trans_start_fw(mvm->trans, fw, ucode_type == IWL_UCODE_INIT);
+       /*
+        * We want to load the INIT firmware even in RFKILL
+        * For the unified firmware case, the ucode_type is not
+        * INIT, but we still need to run it.
+        */
+       ret = iwl_trans_start_fw(mvm->trans, fw, run_in_rfkill);
        if (ret) {
                iwl_fw_set_current_image(&mvm->fwrt, old_type);
                iwl_remove_notification(&mvm->notif_wait, &alive_wait);
@@ -433,7 +440,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
         * commands
         */
        ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(SYSTEM_GROUP,
-                                               INIT_EXTENDED_CFG_CMD), 0,
+                                               INIT_EXTENDED_CFG_CMD),
+                                  CMD_SEND_IN_RFKILL,
                                   sizeof(init_cfg), &init_cfg);
        if (ret) {
                IWL_ERR(mvm, "Failed to run init config command: %d\n",
@@ -457,7 +465,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
        }
 
        ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP,
-                                               NVM_ACCESS_COMPLETE), 0,
+                                               NVM_ACCESS_COMPLETE),
+                                  CMD_SEND_IN_RFKILL,
                                   sizeof(nvm_complete), &nvm_complete);
        if (ret) {
                IWL_ERR(mvm, "Failed to run complete NVM access: %d\n",
@@ -482,6 +491,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
                }
        }
 
+       mvm->rfkill_safe_init_done = true;
+
        return 0;
 
 error:
@@ -526,7 +537,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
 
        lockdep_assert_held(&mvm->mutex);
 
-       if (WARN_ON_ONCE(mvm->calibrating))
+       if (WARN_ON_ONCE(mvm->rfkill_safe_init_done))
                return 0;
 
        iwl_init_notification_wait(&mvm->notif_wait,
@@ -576,7 +587,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
                goto remove_notif;
        }
 
-       mvm->calibrating = true;
+       mvm->rfkill_safe_init_done = true;
 
        /* Send TX valid antennas before triggering calibrations */
        ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
@@ -612,7 +623,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
 remove_notif:
        iwl_remove_notification(&mvm->notif_wait, &calib_wait);
 out:
-       mvm->calibrating = false;
+       mvm->rfkill_safe_init_done = 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) +
index 5c52469288beb55ed5cd21f97a6c184b38c0c136..fdbabca0280e164e24e436fee97292976b7d1d20 100644 (file)
@@ -1209,7 +1209,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
 
        mvm->scan_status = 0;
        mvm->ps_disabled = false;
-       mvm->calibrating = false;
+       mvm->rfkill_safe_init_done = false;
 
        /* just in case one was running */
        iwl_mvm_cleanup_roc_te(mvm);
index 7b829a5be77364eb9a853fad34e35c5059295712..02efcf2189c489ad92a0ff1acaf8de436d3cc758 100644 (file)
@@ -880,7 +880,7 @@ struct iwl_mvm {
        struct iwl_mvm_vif *bf_allowed_vif;
 
        bool hw_registered;
-       bool calibrating;
+       bool rfkill_safe_init_done;
        bool support_umac_log;
 
        u32 ampdu_ref;
index 004de67f91576536f1d09c970d1d171bba874d72..fad3bf563712e02c9ff0bbe426b3ca58ac46aab4 100644 (file)
@@ -1209,7 +1209,8 @@ 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 = READ_ONCE(mvm->calibrating);
+       bool rfkill_safe_init_done = READ_ONCE(mvm->rfkill_safe_init_done);
+       bool unified = iwl_mvm_has_unified_ucode(mvm);
 
        if (state)
                set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
@@ -1218,15 +1219,23 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
 
        iwl_mvm_set_rfkill_state(mvm);
 
-       /* iwl_run_init_mvm_ucode is waiting for results, abort it */
-       if (calibrating)
+        /* iwl_run_init_mvm_ucode is waiting for results, abort it. */
+       if (rfkill_safe_init_done)
                iwl_abort_notification_waits(&mvm->notif_wait);
 
+       /*
+        * Don't ask the transport to stop the firmware. We'll do it
+        * after cfg80211 takes us down.
+        */
+       if (unified)
+               return false;
+
        /*
         * Stop the device if we run OPERATIONAL firmware or if we are in the
         * middle of the calibrations.
         */
-       return state && (mvm->fwrt.cur_fw_img != IWL_UCODE_INIT || calibrating);
+       return state && (mvm->fwrt.cur_fw_img != IWL_UCODE_INIT ||
+                        rfkill_safe_init_done);
 }
 
 static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
index b513037dc0661e9eaae98f162841fbbe2e86e779..85973dd572341be089e66effcd6821be93ddacd8 100644 (file)
@@ -928,7 +928,7 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
                                           MSIX_HW_INT_CAUSES_REG_RF_KILL);
        }
 
-       if (trans->cfg->device_family == IWL_DEVICE_FAMILY_9000) {
+       if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_9000) {
                /*
                 * On 9000-series devices this bit isn't enabled by default, so
                 * when we power down the device we need set the bit to allow it