Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit de8ba41b authored by Liad Kaufman's avatar Liad Kaufman Committed by Luca Coelho
Browse files

iwlwifi: mvm: support init flow debugging



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: default avatarLiad Kaufman <liad.kaufman@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 1247070d
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -1639,6 +1639,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
	IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
	IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
	return 0;
	return 0;
 error:
 error:
	if (!iwlmvm_mod_params.init_dbg)
		iwl_mvm_stop_device(mvm);
		iwl_mvm_stop_device(mvm);
	return ret;
	return ret;
}
}
+4 −1
Original line number Original line Diff line number Diff line
@@ -123,14 +123,17 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm)
		return ret;
		return ret;
	}
	}


	mvm->init_status |= IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE;
	return 0;
	return 0;
}
}


void iwl_mvm_leds_exit(struct iwl_mvm *mvm)
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;
		return;


	led_classdev_unregister(&mvm->led);
	led_classdev_unregister(&mvm->led);
	kfree(mvm->led.name);
	kfree(mvm->led.name);
	mvm->init_status &= ~IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE;
}
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -735,6 +735,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
	ret = ieee80211_register_hw(mvm->hw);
	ret = ieee80211_register_hw(mvm->hw);
	if (ret)
	if (ret)
		iwl_mvm_leds_exit(mvm);
		iwl_mvm_leds_exit(mvm);
	mvm->init_status |= IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE;


	if (mvm->cfg->vht_mu_mimo_supported)
	if (mvm->cfg->vht_mu_mimo_supported)
		wiphy_ext_feature_set(hw->wiphy,
		wiphy_ext_feature_set(hw->wiphy,
+10 −0
Original line number Original line Diff line number Diff line
@@ -754,6 +754,8 @@ struct iwl_mvm {


	struct work_struct roc_done_wk;
	struct work_struct roc_done_wk;


	unsigned long init_status;

	unsigned long status;
	unsigned long status;


	u32 queue_sync_cookie;
	u32 queue_sync_cookie;
@@ -1088,6 +1090,14 @@ enum iwl_mvm_status {
	IWL_MVM_STATUS_DUMPING_FW_LOG,
	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)
static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm)
{
{
	return test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status) ||
	return test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status) ||
+15 −3
Original line number Original line Diff line number Diff line
@@ -7,6 +7,7 @@
 *
 *
 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
 * 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
 * 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
 * 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) 2012 - 2014 Intel Corporation. All rights reserved.
 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
 * Copyright(c) 2016 Intel Deutschland GmbH
 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
 * All rights reserved.
 * All rights reserved.
 *
 *
 * Redistribution and use in source and binary forms, with or without
 * 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->fw = fw;
	mvm->hw = hw;
	mvm->hw = hw;


	mvm->init_status = 0;

	if (iwl_mvm_has_new_rx_api(mvm)) {
	if (iwl_mvm_has_new_rx_api(mvm)) {
		op_mode->ops = &iwl_mvm_ops_mq;
		op_mode->ops = &iwl_mvm_ops_mq;
		trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_desc);
		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);
	iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE);
	mutex_unlock(&mvm->mutex);
	mutex_unlock(&mvm->mutex);
	/* returns 0 if successful, 1 if success but in rfkill */
	/* 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);
		IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
		goto out_free;
		goto out_free;
	}
	}
@@ -791,12 +794,18 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
	return op_mode;
	return op_mode;


 out_unregister:
 out_unregister:
	if (iwlmvm_mod_params.init_dbg)
		return op_mode;

	ieee80211_unregister_hw(mvm->hw);
	ieee80211_unregister_hw(mvm->hw);
	mvm->hw_registered = false;
	mvm->hw_registered = false;
	iwl_mvm_leds_exit(mvm);
	iwl_mvm_leds_exit(mvm);
	iwl_mvm_thermal_exit(mvm);
	iwl_mvm_thermal_exit(mvm);
 out_free:
 out_free:
	flush_delayed_work(&mvm->fw_dump_wk);
	flush_delayed_work(&mvm->fw_dump_wk);

	if (iwlmvm_mod_params.init_dbg)
		return op_mode;
	iwl_phy_db_free(mvm->phy_db);
	iwl_phy_db_free(mvm->phy_db);
	kfree(mvm->scan_cmd);
	kfree(mvm->scan_cmd);
	iwl_trans_op_mode_leave(trans);
	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);
	iwl_mvm_thermal_exit(mvm);


	if (mvm->init_status & IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE) {
		ieee80211_unregister_hw(mvm->hw);
		ieee80211_unregister_hw(mvm->hw);
		mvm->init_status &= ~IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE;
	}


	kfree(mvm->scan_cmd);
	kfree(mvm->scan_cmd);
	kfree(mvm->mcast_filter_cmd);
	kfree(mvm->mcast_filter_cmd);
Loading