iwlwifi: fix initialisation while RF-kill is asserted
authorEran Harary <eran.harary@intel.com>
Mon, 13 May 2013 04:53:26 +0000 (07:53 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 16 May 2013 21:17:29 +0000 (23:17 +0200)
If RF-kill is asserted while a device is initialized, the
firmware INIT image can now be run to retrieve the NVM
data and register to mac80211 properly. Previously, the
initialisation would fail in this scenario and the driver
wouldn't register with mac80211 at all, making the device
unusable.

Signed-off-by: Eran Harary <eran.harary@intel.com>
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/nvm.c
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/pcie/tx.c

index 0470334..84f1c8d 100644 (file)
@@ -189,7 +189,8 @@ enum CMD_MODE {
        CMD_SYNC                = 0,
        CMD_ASYNC               = BIT(0),
        CMD_WANT_SKB            = BIT(1),
-       CMD_ON_DEMAND           = BIT(2),
+       CMD_SEND_IN_RFKILL      = BIT(2),
+       CMD_ON_DEMAND           = BIT(3),
 };
 
 #define DEF_CMD_PAYLOAD_SIZE 320
index a4071cf..20ee281 100644 (file)
@@ -326,6 +326,17 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
        ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans);
        WARN_ON(ret);
 
+       /*
+        * abort after reading the nvm in case RF Kill is on, we will complete
+        * the init seq later when RF kill will switch to off
+        */
+       if (test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status)) {
+               IWL_DEBUG_RF_KILL(mvm,
+                                 "jump over all phy activities due to RF kill\n");
+               iwl_remove_notification(&mvm->notif_wait, &calib_wait);
+               return 1;
+       }
+
        /* Send TX valid antennas before triggering calibrations */
        ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
        if (ret)
@@ -402,8 +413,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
                ret = iwl_run_init_mvm_ucode(mvm, false);
                if (ret && !iwlmvm_mod_params.init_dbg) {
                        IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret);
+                       /* this can't happen */
+                       if (WARN_ON(ret > 0))
+                               ret = -ERFKILL;
                        goto error;
                }
+               /* should stop & start HW since that INIT image just loaded */
+               iwl_trans_stop_hw(mvm->trans, false);
+               ret = iwl_trans_start_hw(mvm->trans);
+               if (ret)
+                       return ret;
        }
 
        if (iwlmvm_mod_params.init_dbg)
index 3f05c6b..2cd669c 100644 (file)
@@ -98,7 +98,7 @@ static int iwl_nvm_write_chunk(struct iwl_mvm *mvm, u16 section,
        struct iwl_host_cmd cmd = {
                .id = NVM_ACCESS_CMD,
                .len = { sizeof(struct iwl_nvm_access_cmd), length },
-               .flags = CMD_SYNC,
+               .flags = CMD_SYNC | CMD_SEND_IN_RFKILL,
                .data = { &nvm_access_cmd, data },
                /* data may come from vmalloc, so use _DUP */
                .dataflags = { 0, IWL_HCMD_DFL_DUP },
@@ -120,7 +120,7 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
        struct iwl_rx_packet *pkt;
        struct iwl_host_cmd cmd = {
                .id = NVM_ACCESS_CMD,
-               .flags = CMD_SYNC | CMD_WANT_SKB,
+               .flags = CMD_SYNC | CMD_WANT_SKB | CMD_SEND_IN_RFKILL,
                .data = { &nvm_access_cmd, },
        };
        int ret, bytes_read, offset_read;
index bb79a8d..e3f69a0 100644 (file)
@@ -396,7 +396,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        mutex_lock(&mvm->mutex);
        err = iwl_run_init_mvm_ucode(mvm, true);
        mutex_unlock(&mvm->mutex);
-       if (err && !iwlmvm_mod_params.init_dbg) {
+       /* returns 0 if successful, 1 if success but in rfkill */
+       if (err < 0 && !iwlmvm_mod_params.init_dbg) {
                IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
                goto out_free;
        }
index 595df17..bf5f824 100644 (file)
@@ -1569,7 +1569,8 @@ int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        if (test_bit(STATUS_FW_ERROR, &trans_pcie->status))
                return -EIO;
 
-       if (test_bit(STATUS_RFKILL, &trans_pcie->status)) {
+       if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
+           test_bit(STATUS_RFKILL, &trans_pcie->status)) {
                IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n",
                                  cmd->id);
                return -ERFKILL;