iwlwifi: mvm: support init flow debugging
authorLiad Kaufman <liad.kaufman@intel.com>
Thu, 16 Mar 2017 11:00:59 +0000 (13:00 +0200)
committerLuca Coelho <luciano.coelho@intel.com>
Mon, 5 Jun 2017 20:29:32 +0000 (23:29 +0300)
In case an assert happens on init flow, the current
driver powers down the NIC, except if iwlmvm modparam
init_dbg=1, and only on very specific flows.

Extend this capability to cover most failure cases
by keeping track of what init configurations have been
completed. This way, we can allow NOT powering down
the NIC, while making sure that when the driver is
removed we don't try to free resources that haven't
been allocated. (This can result in a kernel panic.)

Signed-off-by: Liad Kaufman <liad.kaufman@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/led.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/mvm/tof.c
drivers/net/wireless/intel/iwlwifi/mvm/tt.c

index 8bdeb7c891e94540e0cb12e6442aa36a0af5042c..16200960baf27f2329f829b519fff4f076b4f03a 100644 (file)
@@ -1639,7 +1639,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
        return 0;
  error:
-       iwl_mvm_stop_device(mvm);
+       if (!iwlmvm_mod_params.init_dbg)
+               iwl_mvm_stop_device(mvm);
        return ret;
 }
 
index 1e51fbe95f7c96c8cacd82d669a395f559de69bc..3cac4278a5fde9ecd36744c36a2489f3be74c237 100644 (file)
@@ -123,14 +123,17 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm)
                return ret;
        }
 
+       mvm->init_status |= IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE;
        return 0;
 }
 
 void iwl_mvm_leds_exit(struct iwl_mvm *mvm)
 {
-       if (iwlwifi_mod_params.led_mode == IWL_LED_DISABLE)
+       if (iwlwifi_mod_params.led_mode == IWL_LED_DISABLE ||
+           !(mvm->init_status & IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE))
                return;
 
        led_classdev_unregister(&mvm->led);
        kfree(mvm->led.name);
+       mvm->init_status &= ~IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE;
 }
index 50510e96a82d2ec31ce86de71c973aa0521396a9..f52c251cd891b50f2d16ad6ee4f583a8699b5c30 100644 (file)
@@ -735,6 +735,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        ret = ieee80211_register_hw(mvm->hw);
        if (ret)
                iwl_mvm_leds_exit(mvm);
+       mvm->init_status |= IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE;
 
        if (mvm->cfg->vht_mu_mimo_supported)
                wiphy_ext_feature_set(hw->wiphy,
index 7519fda01792157a89afea499219aca14eb274ae..05489694979e1509ddf223c1d6f0f0da8218e62d 100644 (file)
@@ -754,6 +754,8 @@ struct iwl_mvm {
 
        struct work_struct roc_done_wk;
 
+       unsigned long init_status;
+
        unsigned long status;
 
        u32 queue_sync_cookie;
@@ -1088,6 +1090,14 @@ enum iwl_mvm_status {
        IWL_MVM_STATUS_DUMPING_FW_LOG,
 };
 
+/* Keep track of completed init configuration */
+enum iwl_mvm_init_status {
+       IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE = BIT(0),
+       IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE = BIT(1),
+       IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE = BIT(2),
+       IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE = BIT(3),
+};
+
 static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm)
 {
        return test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status) ||
index 607cc83908b5815bb38fefdee4c8825f99232ed3..085dbe4d0fe9cfea616e890babe75db0670baf2c 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,7 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
- * Copyright(c) 2016 Intel Deutschland GmbH
+ * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -589,6 +590,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        mvm->fw = fw;
        mvm->hw = hw;
 
+       mvm->init_status = 0;
+
        if (iwl_mvm_has_new_rx_api(mvm)) {
                op_mode->ops = &iwl_mvm_ops_mq;
                trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_desc);
@@ -753,7 +756,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE);
        mutex_unlock(&mvm->mutex);
        /* returns 0 if successful, 1 if success but in rfkill */
-       if (err < 0 && !iwlmvm_mod_params.init_dbg) {
+       if (err < 0) {
                IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
                goto out_free;
        }
@@ -791,12 +794,18 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        return op_mode;
 
  out_unregister:
+       if (iwlmvm_mod_params.init_dbg)
+               return op_mode;
+
        ieee80211_unregister_hw(mvm->hw);
        mvm->hw_registered = false;
        iwl_mvm_leds_exit(mvm);
        iwl_mvm_thermal_exit(mvm);
  out_free:
        flush_delayed_work(&mvm->fw_dump_wk);
+
+       if (iwlmvm_mod_params.init_dbg)
+               return op_mode;
        iwl_phy_db_free(mvm->phy_db);
        kfree(mvm->scan_cmd);
        iwl_trans_op_mode_leave(trans);
@@ -821,7 +830,10 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
 
        iwl_mvm_thermal_exit(mvm);
 
-       ieee80211_unregister_hw(mvm->hw);
+       if (mvm->init_status & IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE) {
+               ieee80211_unregister_hw(mvm->hw);
+               mvm->init_status &= ~IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE;
+       }
 
        kfree(mvm->scan_cmd);
        kfree(mvm->mcast_filter_cmd);
index 16ce8a56b5b94d9b5356011a98e19888be8faef9..634175b2480ca4b80dbd540bf180cfc3117f733d 100644 (file)
@@ -93,17 +93,21 @@ void iwl_mvm_tof_init(struct iwl_mvm *mvm)
                cpu_to_le32(TOF_RANGE_REQ_EXT_CMD);
 
        mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID;
+       mvm->init_status |= IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE;
 }
 
 void iwl_mvm_tof_clean(struct iwl_mvm *mvm)
 {
        struct iwl_mvm_tof_data *tof_data = &mvm->tof_data;
 
-       if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT))
+       if (!fw_has_capa(&mvm->fw->ucode_capa,
+                        IWL_UCODE_TLV_CAPA_TOF_SUPPORT) ||
+           !(mvm->init_status & IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE))
                return;
 
        memset(tof_data, 0, sizeof(*tof_data));
        mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID;
+       mvm->init_status &= ~IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE;
 }
 
 static void iwl_tof_iterator(void *_data, u8 *mac,
index f9cbd197246f7ba6ba9e5e0af816cbec54eb9790..4e03ea911a1f8f03a3fe66952751abbe260e0d1b 100644 (file)
@@ -882,10 +882,14 @@ void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff)
        iwl_mvm_cooling_device_register(mvm);
        iwl_mvm_thermal_zone_register(mvm);
 #endif
+       mvm->init_status |= IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE;
 }
 
 void iwl_mvm_thermal_exit(struct iwl_mvm *mvm)
 {
+       if (!(mvm->init_status & IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE))
+               return;
+
        cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit);
        IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n");
 
@@ -893,4 +897,5 @@ void iwl_mvm_thermal_exit(struct iwl_mvm *mvm)
        iwl_mvm_cooling_device_unregister(mvm);
        iwl_mvm_thermal_zone_unregister(mvm);
 #endif
+       mvm->init_status &= ~IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE;
 }