iwlwifi: mvm: avoid use-after-free on iwl_mvm_d0i3_enable_tx()
[cascardo/linux.git] / drivers / net / wireless / iwlwifi / mvm / ops.c
index fe40922..2ea0123 100644 (file)
@@ -82,7 +82,6 @@
 #include "rs.h"
 #include "fw-api-scan.h"
 #include "time-event.h"
-#include "iwl-fw-error-dump.h"
 
 #define DRV_DESCRIPTION        "The new Intel(R) wireless AGN driver for Linux"
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -234,6 +233,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
                   iwl_mvm_rx_ant_coupling_notif, true),
 
        RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),
+       RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, true),
 
        RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false),
 
@@ -358,6 +358,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
        CMD(TDLS_CHANNEL_SWITCH_CMD),
        CMD(TDLS_CHANNEL_SWITCH_NOTIFICATION),
        CMD(TDLS_CONFIG_CMD),
+       CMD(MCC_UPDATE_CMD),
 };
 #undef CMD
 
@@ -487,8 +488,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 
        /* Set a short watchdog for the command queue */
        trans_cfg.cmd_q_wdg_timeout =
-               iwlmvm_mod_params.tfd_q_hang_detect ? IWL_DEF_WD_TIMEOUT :
-                                                     IWL_WATCHDOG_DISABLED;
+               iwl_mvm_get_wd_timeout(mvm, NULL, false, true);
 
        snprintf(mvm->hw->wiphy->fw_version,
                 sizeof(mvm->hw->wiphy->fw_version),
@@ -523,12 +523,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        /* set the nvm_file_name according to priority */
        if (iwlwifi_mod_params.nvm_file) {
                mvm->nvm_file_name = iwlwifi_mod_params.nvm_file;
-       } else {
-               if ((trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) &&
-                   (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP))
-                       mvm->nvm_file_name = mvm->cfg->default_nvm_file_8000A;
+       } else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
+               if (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_B_STEP)
+                       mvm->nvm_file_name = mvm->cfg->default_nvm_file_B_step;
                else
-                       mvm->nvm_file_name = mvm->cfg->default_nvm_file;
+                       mvm->nvm_file_name = mvm->cfg->default_nvm_file_C_step;
        }
 
        if (WARN(cfg->no_power_up_nic_in_init && !mvm->nvm_file_name,
@@ -690,7 +689,6 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm,
 {
        struct iwl_fw_dbg_trigger_tlv *trig;
        struct iwl_fw_dbg_trigger_cmd *cmds_trig;
-       char buf[32];
        int i;
 
        if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_FW_NOTIF))
@@ -710,9 +708,9 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm,
                if (cmds_trig->cmds[i].cmd_id != pkt->hdr.cmd)
                        continue;
 
-               memset(buf, 0, sizeof(buf));
-               snprintf(buf, sizeof(buf), "CMD 0x%02x received", pkt->hdr.cmd);
-               iwl_mvm_fw_dbg_collect_trig(mvm, trig, buf, sizeof(buf));
+               iwl_mvm_fw_dbg_collect_trig(mvm, trig,
+                                           "CMD 0x%02x received",
+                                           pkt->hdr.cmd);
                break;
        }
 }
@@ -867,12 +865,22 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work)
                return;
 
        mutex_lock(&mvm->mutex);
+
+       /* stop recording */
+       if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+               iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
+       } else {
+               iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0);
+               /* wait before we collect the data till the DBGC stop */
+               udelay(100);
+       }
+
        iwl_mvm_fw_error_dump(mvm);
 
        /* start recording again if the firmware is not crashed */
        WARN_ON_ONCE((!test_bit(STATUS_FW_ERROR, &mvm->trans->status)) &&
-                     mvm->fw->dbg_dest_tlv &&
-                     iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf));
+                    mvm->fw->dbg_dest_tlv &&
+                    iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf));
 
        mutex_unlock(&mvm->mutex);
 
@@ -893,18 +901,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
         * the next start() call from mac80211. If restart isn't called
         * (no fw restart) scan status will stay busy.
         */
-       switch (mvm->scan_status) {
-       case IWL_MVM_SCAN_NONE:
-               break;
-       case IWL_MVM_SCAN_OS:
-               ieee80211_scan_completed(mvm->hw, true);
-               break;
-       case IWL_MVM_SCAN_SCHED:
-               /* Sched scan will be restarted by mac80211 in restart_hw. */
-               if (!mvm->restart_fw)
-                       ieee80211_sched_scan_stopped(mvm->hw);
-               break;
-       }
+       iwl_mvm_report_scan_aborted(mvm);
 
        /*
         * If we're restarting already, don't cycle restarts.
@@ -1174,7 +1171,7 @@ static void iwl_mvm_d0i3_disconnect_iter(void *data, u8 *mac,
 
        if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc &&
            mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id)
-               ieee80211_connection_loss(vif);
+               iwl_mvm_connection_loss(mvm, vif, "D0i3");
 }
 
 void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq)
@@ -1266,10 +1263,16 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
                ieee80211_iterate_active_interfaces(
                        mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
                        iwl_mvm_d0i3_disconnect_iter, mvm);
-
-       iwl_free_resp(&get_status_cmd);
 out:
        iwl_mvm_d0i3_enable_tx(mvm, qos_seq);
+
+       /* qos_seq might point inside resp_pkt, so free it only now */
+       if (get_status_cmd.resp_pkt)
+               iwl_free_resp(&get_status_cmd);
+
+       /* the FW might have updated the regdomain */
+       iwl_mvm_update_changed_regdom(mvm);
+
        iwl_mvm_unref(mvm, IWL_MVM_REF_EXIT_WORK);
        mutex_unlock(&mvm->mutex);
 }