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 0470334d6a81cf6960efd0219b7553aa8c8702b5..84f1c8dc97413fa3fe5c2cb48f33bfcc9c031505 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 a4071cf09a249a42a7472a4dacfa6039c1a5b70c..20ee2812cc9b535b11d12c9bdcfca4fd4c8903ef 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 3f05c6b23874d56bdf70ca8f1cbf0ea1b3592957..2cd669c3c47aacdc1a14b4a434637a164e9c91bf 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 bb79a8dcf6bbd081690a15c90d499d86ed028ae3..e3f69a08251d7f5101cac0642b4a40e7a594a3c6 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 595df1756b84d67f825c3696f66be6d770e5b8c0..bf5f8246385eec1ef6cc4401600292d3bcb0bd9a 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;