162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
562306a36Sopenharmony_ci * Copyright (C) 2018, 2020 Intel Corporation
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Portions of this file are derived from the ipw3945 project, as well
862306a36Sopenharmony_ci * as portions of the ieee80211 subsystem header files.
962306a36Sopenharmony_ci *****************************************************************************/
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <net/mac80211.h>
1662306a36Sopenharmony_ci#include "iwl-io.h"
1762306a36Sopenharmony_ci#include "iwl-modparams.h"
1862306a36Sopenharmony_ci#include "iwl-debug.h"
1962306a36Sopenharmony_ci#include "agn.h"
2062306a36Sopenharmony_ci#include "dev.h"
2162306a36Sopenharmony_ci#include "commands.h"
2262306a36Sopenharmony_ci#include "tt.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* default Thermal Throttling transaction table
2562306a36Sopenharmony_ci * Current state   |         Throttling Down               |  Throttling Up
2662306a36Sopenharmony_ci *=============================================================================
2762306a36Sopenharmony_ci *                 Condition Nxt State  Condition Nxt State Condition Nxt State
2862306a36Sopenharmony_ci *-----------------------------------------------------------------------------
2962306a36Sopenharmony_ci *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
3062306a36Sopenharmony_ci *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
3162306a36Sopenharmony_ci *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
3262306a36Sopenharmony_ci *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
3362306a36Sopenharmony_ci *=============================================================================
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_cistatic const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
3662306a36Sopenharmony_ci	{IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
3762306a36Sopenharmony_ci	{IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
3862306a36Sopenharmony_ci	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_cistatic const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
4162306a36Sopenharmony_ci	{IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
4262306a36Sopenharmony_ci	{IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
4362306a36Sopenharmony_ci	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_cistatic const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
4662306a36Sopenharmony_ci	{IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
4762306a36Sopenharmony_ci	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
4862306a36Sopenharmony_ci	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_cistatic const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
5162306a36Sopenharmony_ci	{IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
5262306a36Sopenharmony_ci	{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
5362306a36Sopenharmony_ci	{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/* Advance Thermal Throttling default restriction table */
5762306a36Sopenharmony_cistatic const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
5862306a36Sopenharmony_ci	{IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
5962306a36Sopenharmony_ci	{IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
6062306a36Sopenharmony_ci	{IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
6162306a36Sopenharmony_ci	{IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cibool iwl_tt_is_low_power_state(struct iwl_priv *priv)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	if (tt->state >= IWL_TI_1)
6962306a36Sopenharmony_ci		return true;
7062306a36Sopenharmony_ci	return false;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciu8 iwl_tt_current_power_mode(struct iwl_priv *priv)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return tt->tt_power_mode;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cibool iwl_ht_enabled(struct iwl_priv *priv)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
8362306a36Sopenharmony_ci	struct iwl_tt_restriction *restriction;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (!priv->thermal_throttle.advanced_tt)
8662306a36Sopenharmony_ci		return true;
8762306a36Sopenharmony_ci	restriction = tt->restriction + tt->state;
8862306a36Sopenharmony_ci	return restriction->is_ht;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	s32 temp = priv->temperature; /* degrees CELSIUS except specified */
9462306a36Sopenharmony_ci	bool within_margin = false;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	if (!priv->thermal_throttle.advanced_tt)
9762306a36Sopenharmony_ci		within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
9862306a36Sopenharmony_ci				CT_KILL_THRESHOLD_LEGACY) ? true : false;
9962306a36Sopenharmony_ci	else
10062306a36Sopenharmony_ci		within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
10162306a36Sopenharmony_ci				CT_KILL_THRESHOLD) ? true : false;
10262306a36Sopenharmony_ci	return within_margin;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cibool iwl_check_for_ct_kill(struct iwl_priv *priv)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	bool is_ct_kill = false;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (iwl_within_ct_kill_margin(priv)) {
11062306a36Sopenharmony_ci		iwl_tt_enter_ct_kill(priv);
11162306a36Sopenharmony_ci		is_ct_kill = true;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci	return is_ct_kill;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cienum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
11962306a36Sopenharmony_ci	struct iwl_tt_restriction *restriction;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (!priv->thermal_throttle.advanced_tt)
12262306a36Sopenharmony_ci		return IWL_ANT_OK_MULTI;
12362306a36Sopenharmony_ci	restriction = tt->restriction + tt->state;
12462306a36Sopenharmony_ci	return restriction->tx_stream;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cienum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
13062306a36Sopenharmony_ci	struct iwl_tt_restriction *restriction;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	if (!priv->thermal_throttle.advanced_tt)
13362306a36Sopenharmony_ci		return IWL_ANT_OK_MULTI;
13462306a36Sopenharmony_ci	restriction = tt->restriction + tt->state;
13562306a36Sopenharmony_ci	return restriction->rx_stream;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci#define CT_KILL_EXIT_DURATION (5)	/* 5 seconds duration */
13962306a36Sopenharmony_ci#define CT_KILL_WAITING_DURATION (300)	/* 300ms duration */
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/*
14262306a36Sopenharmony_ci * toggle the bit to wake up uCode and check the temperature
14362306a36Sopenharmony_ci * if the temperature is below CT, uCode will stay awake and send card
14462306a36Sopenharmony_ci * state notification with CT_KILL bit clear to inform Thermal Throttling
14562306a36Sopenharmony_ci * Management to change state. Otherwise, uCode will go back to sleep
14662306a36Sopenharmony_ci * without doing anything, driver should continue the 5 seconds timer
14762306a36Sopenharmony_ci * to wake up uCode for temperature check until temperature drop below CT
14862306a36Sopenharmony_ci */
14962306a36Sopenharmony_cistatic void iwl_tt_check_exit_ct_kill(struct timer_list *t)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct iwl_priv *priv = from_timer(priv, t,
15262306a36Sopenharmony_ci					   thermal_throttle.ct_kill_exit_tm);
15362306a36Sopenharmony_ci	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
15662306a36Sopenharmony_ci		return;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (tt->state == IWL_TI_CT_KILL) {
15962306a36Sopenharmony_ci		if (priv->thermal_throttle.ct_kill_toggle) {
16062306a36Sopenharmony_ci			iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
16162306a36Sopenharmony_ci				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
16262306a36Sopenharmony_ci			priv->thermal_throttle.ct_kill_toggle = false;
16362306a36Sopenharmony_ci		} else {
16462306a36Sopenharmony_ci			iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
16562306a36Sopenharmony_ci				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
16662306a36Sopenharmony_ci			priv->thermal_throttle.ct_kill_toggle = true;
16762306a36Sopenharmony_ci		}
16862306a36Sopenharmony_ci		iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
16962306a36Sopenharmony_ci		if (iwl_trans_grab_nic_access(priv->trans))
17062306a36Sopenharmony_ci			iwl_trans_release_nic_access(priv->trans);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci		/* Reschedule the ct_kill timer to occur in
17362306a36Sopenharmony_ci		 * CT_KILL_EXIT_DURATION seconds to ensure we get a
17462306a36Sopenharmony_ci		 * thermal update */
17562306a36Sopenharmony_ci		IWL_DEBUG_TEMP(priv, "schedule ct_kill exit timer\n");
17662306a36Sopenharmony_ci		mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
17762306a36Sopenharmony_ci			  jiffies + CT_KILL_EXIT_DURATION * HZ);
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic void iwl_perform_ct_kill_task(struct iwl_priv *priv,
18262306a36Sopenharmony_ci			   bool stop)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	if (stop) {
18562306a36Sopenharmony_ci		IWL_DEBUG_TEMP(priv, "Stop all queues\n");
18662306a36Sopenharmony_ci		if (priv->mac80211_registered)
18762306a36Sopenharmony_ci			ieee80211_stop_queues(priv->hw);
18862306a36Sopenharmony_ci		IWL_DEBUG_TEMP(priv,
18962306a36Sopenharmony_ci				"Schedule 5 seconds CT_KILL Timer\n");
19062306a36Sopenharmony_ci		mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
19162306a36Sopenharmony_ci			  jiffies + CT_KILL_EXIT_DURATION * HZ);
19262306a36Sopenharmony_ci	} else {
19362306a36Sopenharmony_ci		IWL_DEBUG_TEMP(priv, "Wake all queues\n");
19462306a36Sopenharmony_ci		if (priv->mac80211_registered)
19562306a36Sopenharmony_ci			ieee80211_wake_queues(priv->hw);
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic void iwl_tt_ready_for_ct_kill(struct timer_list *t)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct iwl_priv *priv = from_timer(priv, t,
20262306a36Sopenharmony_ci					   thermal_throttle.ct_kill_waiting_tm);
20362306a36Sopenharmony_ci	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
20662306a36Sopenharmony_ci		return;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* temperature timer expired, ready to go into CT_KILL state */
20962306a36Sopenharmony_ci	if (tt->state != IWL_TI_CT_KILL) {
21062306a36Sopenharmony_ci		IWL_DEBUG_TEMP(priv, "entering CT_KILL state when "
21162306a36Sopenharmony_ci				"temperature timer expired\n");
21262306a36Sopenharmony_ci		tt->state = IWL_TI_CT_KILL;
21362306a36Sopenharmony_ci		set_bit(STATUS_CT_KILL, &priv->status);
21462306a36Sopenharmony_ci		iwl_perform_ct_kill_task(priv, true);
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	IWL_DEBUG_TEMP(priv, "Prepare to enter IWL_TI_CT_KILL\n");
22162306a36Sopenharmony_ci	/* make request to retrieve statistics information */
22262306a36Sopenharmony_ci	iwl_send_statistics_request(priv, 0, false);
22362306a36Sopenharmony_ci	/* Reschedule the ct_kill wait timer */
22462306a36Sopenharmony_ci	mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
22562306a36Sopenharmony_ci		 jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci#define IWL_MINIMAL_POWER_THRESHOLD		(CT_KILL_THRESHOLD_LEGACY)
22962306a36Sopenharmony_ci#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2	(100)
23062306a36Sopenharmony_ci#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1	(90)
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci/*
23362306a36Sopenharmony_ci * Legacy thermal throttling
23462306a36Sopenharmony_ci * 1) Avoid NIC destruction due to high temperatures
23562306a36Sopenharmony_ci *	Chip will identify dangerously high temperatures that can
23662306a36Sopenharmony_ci *	harm the device and will power down
23762306a36Sopenharmony_ci * 2) Avoid the NIC power down due to high temperature
23862306a36Sopenharmony_ci *	Throttle early enough to lower the power consumption before
23962306a36Sopenharmony_ci *	drastic steps are needed
24062306a36Sopenharmony_ci */
24162306a36Sopenharmony_cistatic void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
24462306a36Sopenharmony_ci	enum iwl_tt_state old_state;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUG
24762306a36Sopenharmony_ci	if ((tt->tt_previous_temp) &&
24862306a36Sopenharmony_ci	    (temp > tt->tt_previous_temp) &&
24962306a36Sopenharmony_ci	    ((temp - tt->tt_previous_temp) >
25062306a36Sopenharmony_ci	    IWL_TT_INCREASE_MARGIN)) {
25162306a36Sopenharmony_ci		IWL_DEBUG_TEMP(priv,
25262306a36Sopenharmony_ci			"Temperature increase %d degree Celsius\n",
25362306a36Sopenharmony_ci			(temp - tt->tt_previous_temp));
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci#endif
25662306a36Sopenharmony_ci	old_state = tt->state;
25762306a36Sopenharmony_ci	/* in Celsius */
25862306a36Sopenharmony_ci	if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
25962306a36Sopenharmony_ci		tt->state = IWL_TI_CT_KILL;
26062306a36Sopenharmony_ci	else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
26162306a36Sopenharmony_ci		tt->state = IWL_TI_2;
26262306a36Sopenharmony_ci	else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
26362306a36Sopenharmony_ci		tt->state = IWL_TI_1;
26462306a36Sopenharmony_ci	else
26562306a36Sopenharmony_ci		tt->state = IWL_TI_0;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUG
26862306a36Sopenharmony_ci	tt->tt_previous_temp = temp;
26962306a36Sopenharmony_ci#endif
27062306a36Sopenharmony_ci	/* stop ct_kill_waiting_tm timer */
27162306a36Sopenharmony_ci	del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
27262306a36Sopenharmony_ci	if (tt->state != old_state) {
27362306a36Sopenharmony_ci		switch (tt->state) {
27462306a36Sopenharmony_ci		case IWL_TI_0:
27562306a36Sopenharmony_ci			/*
27662306a36Sopenharmony_ci			 * When the system is ready to go back to IWL_TI_0
27762306a36Sopenharmony_ci			 * we only have to call iwl_power_update_mode() to
27862306a36Sopenharmony_ci			 * do so.
27962306a36Sopenharmony_ci			 */
28062306a36Sopenharmony_ci			break;
28162306a36Sopenharmony_ci		case IWL_TI_1:
28262306a36Sopenharmony_ci			tt->tt_power_mode = IWL_POWER_INDEX_3;
28362306a36Sopenharmony_ci			break;
28462306a36Sopenharmony_ci		case IWL_TI_2:
28562306a36Sopenharmony_ci			tt->tt_power_mode = IWL_POWER_INDEX_4;
28662306a36Sopenharmony_ci			break;
28762306a36Sopenharmony_ci		default:
28862306a36Sopenharmony_ci			tt->tt_power_mode = IWL_POWER_INDEX_5;
28962306a36Sopenharmony_ci			break;
29062306a36Sopenharmony_ci		}
29162306a36Sopenharmony_ci		mutex_lock(&priv->mutex);
29262306a36Sopenharmony_ci		if (old_state == IWL_TI_CT_KILL)
29362306a36Sopenharmony_ci			clear_bit(STATUS_CT_KILL, &priv->status);
29462306a36Sopenharmony_ci		if (tt->state != IWL_TI_CT_KILL &&
29562306a36Sopenharmony_ci		    iwl_power_update_mode(priv, true)) {
29662306a36Sopenharmony_ci			/* TT state not updated
29762306a36Sopenharmony_ci			 * try again during next temperature read
29862306a36Sopenharmony_ci			 */
29962306a36Sopenharmony_ci			if (old_state == IWL_TI_CT_KILL)
30062306a36Sopenharmony_ci				set_bit(STATUS_CT_KILL, &priv->status);
30162306a36Sopenharmony_ci			tt->state = old_state;
30262306a36Sopenharmony_ci			IWL_ERR(priv, "Cannot update power mode, "
30362306a36Sopenharmony_ci					"TT state not updated\n");
30462306a36Sopenharmony_ci		} else {
30562306a36Sopenharmony_ci			if (tt->state == IWL_TI_CT_KILL) {
30662306a36Sopenharmony_ci				if (force) {
30762306a36Sopenharmony_ci					set_bit(STATUS_CT_KILL, &priv->status);
30862306a36Sopenharmony_ci					iwl_perform_ct_kill_task(priv, true);
30962306a36Sopenharmony_ci				} else {
31062306a36Sopenharmony_ci					iwl_prepare_ct_kill_task(priv);
31162306a36Sopenharmony_ci					tt->state = old_state;
31262306a36Sopenharmony_ci				}
31362306a36Sopenharmony_ci			} else if (old_state == IWL_TI_CT_KILL) {
31462306a36Sopenharmony_ci				iwl_perform_ct_kill_task(priv, false);
31562306a36Sopenharmony_ci			}
31662306a36Sopenharmony_ci			IWL_DEBUG_TEMP(priv, "Temperature state changed %u\n",
31762306a36Sopenharmony_ci					tt->state);
31862306a36Sopenharmony_ci			IWL_DEBUG_TEMP(priv, "Power Index change to %u\n",
31962306a36Sopenharmony_ci					tt->tt_power_mode);
32062306a36Sopenharmony_ci		}
32162306a36Sopenharmony_ci		mutex_unlock(&priv->mutex);
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci/*
32662306a36Sopenharmony_ci * Advance thermal throttling
32762306a36Sopenharmony_ci * 1) Avoid NIC destruction due to high temperatures
32862306a36Sopenharmony_ci *	Chip will identify dangerously high temperatures that can
32962306a36Sopenharmony_ci *	harm the device and will power down
33062306a36Sopenharmony_ci * 2) Avoid the NIC power down due to high temperature
33162306a36Sopenharmony_ci *	Throttle early enough to lower the power consumption before
33262306a36Sopenharmony_ci *	drastic steps are needed
33362306a36Sopenharmony_ci *	Actions include relaxing the power down sleep thresholds and
33462306a36Sopenharmony_ci *	decreasing the number of TX streams
33562306a36Sopenharmony_ci * 3) Avoid throughput performance impact as much as possible
33662306a36Sopenharmony_ci *
33762306a36Sopenharmony_ci *=============================================================================
33862306a36Sopenharmony_ci *                 Condition Nxt State  Condition Nxt State Condition Nxt State
33962306a36Sopenharmony_ci *-----------------------------------------------------------------------------
34062306a36Sopenharmony_ci *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
34162306a36Sopenharmony_ci *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
34262306a36Sopenharmony_ci *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
34362306a36Sopenharmony_ci *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
34462306a36Sopenharmony_ci *=============================================================================
34562306a36Sopenharmony_ci */
34662306a36Sopenharmony_cistatic void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
34962306a36Sopenharmony_ci	int i;
35062306a36Sopenharmony_ci	bool changed = false;
35162306a36Sopenharmony_ci	enum iwl_tt_state old_state;
35262306a36Sopenharmony_ci	struct iwl_tt_trans *transaction;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	old_state = tt->state;
35562306a36Sopenharmony_ci	for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
35662306a36Sopenharmony_ci		/* based on the current TT state,
35762306a36Sopenharmony_ci		 * find the curresponding transaction table
35862306a36Sopenharmony_ci		 * each table has (IWL_TI_STATE_MAX - 1) entries
35962306a36Sopenharmony_ci		 * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
36062306a36Sopenharmony_ci		 * will advance to the correct table.
36162306a36Sopenharmony_ci		 * then based on the current temperature
36262306a36Sopenharmony_ci		 * find the next state need to transaction to
36362306a36Sopenharmony_ci		 * go through all the possible (IWL_TI_STATE_MAX - 1) entries
36462306a36Sopenharmony_ci		 * in the current table to see if transaction is needed
36562306a36Sopenharmony_ci		 */
36662306a36Sopenharmony_ci		transaction = tt->transaction +
36762306a36Sopenharmony_ci			((old_state * (IWL_TI_STATE_MAX - 1)) + i);
36862306a36Sopenharmony_ci		if (temp >= transaction->tt_low &&
36962306a36Sopenharmony_ci		    temp <= transaction->tt_high) {
37062306a36Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUG
37162306a36Sopenharmony_ci			if ((tt->tt_previous_temp) &&
37262306a36Sopenharmony_ci			    (temp > tt->tt_previous_temp) &&
37362306a36Sopenharmony_ci			    ((temp - tt->tt_previous_temp) >
37462306a36Sopenharmony_ci			    IWL_TT_INCREASE_MARGIN)) {
37562306a36Sopenharmony_ci				IWL_DEBUG_TEMP(priv,
37662306a36Sopenharmony_ci					"Temperature increase %d "
37762306a36Sopenharmony_ci					"degree Celsius\n",
37862306a36Sopenharmony_ci					(temp - tt->tt_previous_temp));
37962306a36Sopenharmony_ci			}
38062306a36Sopenharmony_ci			tt->tt_previous_temp = temp;
38162306a36Sopenharmony_ci#endif
38262306a36Sopenharmony_ci			if (old_state !=
38362306a36Sopenharmony_ci			    transaction->next_state) {
38462306a36Sopenharmony_ci				changed = true;
38562306a36Sopenharmony_ci				tt->state =
38662306a36Sopenharmony_ci					transaction->next_state;
38762306a36Sopenharmony_ci			}
38862306a36Sopenharmony_ci			break;
38962306a36Sopenharmony_ci		}
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci	/* stop ct_kill_waiting_tm timer */
39262306a36Sopenharmony_ci	del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
39362306a36Sopenharmony_ci	if (changed) {
39462306a36Sopenharmony_ci		if (tt->state >= IWL_TI_1) {
39562306a36Sopenharmony_ci			/* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
39662306a36Sopenharmony_ci			tt->tt_power_mode = IWL_POWER_INDEX_5;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci			if (!iwl_ht_enabled(priv)) {
39962306a36Sopenharmony_ci				struct iwl_rxon_context *ctx;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci				for_each_context(priv, ctx) {
40262306a36Sopenharmony_ci					struct iwl_rxon_cmd *rxon;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci					rxon = &ctx->staging;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci					/* disable HT */
40762306a36Sopenharmony_ci					rxon->flags &= ~(
40862306a36Sopenharmony_ci						RXON_FLG_CHANNEL_MODE_MSK |
40962306a36Sopenharmony_ci						RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
41062306a36Sopenharmony_ci						RXON_FLG_HT40_PROT_MSK |
41162306a36Sopenharmony_ci						RXON_FLG_HT_PROT_MSK);
41262306a36Sopenharmony_ci				}
41362306a36Sopenharmony_ci			} else {
41462306a36Sopenharmony_ci				/* check HT capability and set
41562306a36Sopenharmony_ci				 * according to the system HT capability
41662306a36Sopenharmony_ci				 * in case get disabled before */
41762306a36Sopenharmony_ci				iwl_set_rxon_ht(priv, &priv->current_ht_config);
41862306a36Sopenharmony_ci			}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci		} else {
42162306a36Sopenharmony_ci			/*
42262306a36Sopenharmony_ci			 * restore system power setting -- it will be
42362306a36Sopenharmony_ci			 * recalculated automatically.
42462306a36Sopenharmony_ci			 */
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci			/* check HT capability and set
42762306a36Sopenharmony_ci			 * according to the system HT capability
42862306a36Sopenharmony_ci			 * in case get disabled before */
42962306a36Sopenharmony_ci			iwl_set_rxon_ht(priv, &priv->current_ht_config);
43062306a36Sopenharmony_ci		}
43162306a36Sopenharmony_ci		mutex_lock(&priv->mutex);
43262306a36Sopenharmony_ci		if (old_state == IWL_TI_CT_KILL)
43362306a36Sopenharmony_ci			clear_bit(STATUS_CT_KILL, &priv->status);
43462306a36Sopenharmony_ci		if (tt->state != IWL_TI_CT_KILL &&
43562306a36Sopenharmony_ci		    iwl_power_update_mode(priv, true)) {
43662306a36Sopenharmony_ci			/* TT state not updated
43762306a36Sopenharmony_ci			 * try again during next temperature read
43862306a36Sopenharmony_ci			 */
43962306a36Sopenharmony_ci			IWL_ERR(priv, "Cannot update power mode, "
44062306a36Sopenharmony_ci					"TT state not updated\n");
44162306a36Sopenharmony_ci			if (old_state == IWL_TI_CT_KILL)
44262306a36Sopenharmony_ci				set_bit(STATUS_CT_KILL, &priv->status);
44362306a36Sopenharmony_ci			tt->state = old_state;
44462306a36Sopenharmony_ci		} else {
44562306a36Sopenharmony_ci			IWL_DEBUG_TEMP(priv,
44662306a36Sopenharmony_ci					"Thermal Throttling to new state: %u\n",
44762306a36Sopenharmony_ci					tt->state);
44862306a36Sopenharmony_ci			if (old_state != IWL_TI_CT_KILL &&
44962306a36Sopenharmony_ci			    tt->state == IWL_TI_CT_KILL) {
45062306a36Sopenharmony_ci				if (force) {
45162306a36Sopenharmony_ci					IWL_DEBUG_TEMP(priv,
45262306a36Sopenharmony_ci						"Enter IWL_TI_CT_KILL\n");
45362306a36Sopenharmony_ci					set_bit(STATUS_CT_KILL, &priv->status);
45462306a36Sopenharmony_ci					iwl_perform_ct_kill_task(priv, true);
45562306a36Sopenharmony_ci				} else {
45662306a36Sopenharmony_ci					tt->state = old_state;
45762306a36Sopenharmony_ci					iwl_prepare_ct_kill_task(priv);
45862306a36Sopenharmony_ci				}
45962306a36Sopenharmony_ci			} else if (old_state == IWL_TI_CT_KILL &&
46062306a36Sopenharmony_ci				  tt->state != IWL_TI_CT_KILL) {
46162306a36Sopenharmony_ci				IWL_DEBUG_TEMP(priv, "Exit IWL_TI_CT_KILL\n");
46262306a36Sopenharmony_ci				iwl_perform_ct_kill_task(priv, false);
46362306a36Sopenharmony_ci			}
46462306a36Sopenharmony_ci		}
46562306a36Sopenharmony_ci		mutex_unlock(&priv->mutex);
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci/* Card State Notification indicated reach critical temperature
47062306a36Sopenharmony_ci * if PSP not enable, no Thermal Throttling function will be performed
47162306a36Sopenharmony_ci * just set the GP1 bit to acknowledge the event
47262306a36Sopenharmony_ci * otherwise, go into IWL_TI_CT_KILL state
47362306a36Sopenharmony_ci * since Card State Notification will not provide any temperature reading
47462306a36Sopenharmony_ci * for Legacy mode
47562306a36Sopenharmony_ci * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
47662306a36Sopenharmony_ci * for advance mode
47762306a36Sopenharmony_ci * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
47862306a36Sopenharmony_ci */
47962306a36Sopenharmony_cistatic void iwl_bg_ct_enter(struct work_struct *work)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
48262306a36Sopenharmony_ci	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
48562306a36Sopenharmony_ci		return;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (!iwl_is_ready(priv))
48862306a36Sopenharmony_ci		return;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (tt->state != IWL_TI_CT_KILL) {
49162306a36Sopenharmony_ci		IWL_ERR(priv, "Device reached critical temperature "
49262306a36Sopenharmony_ci			      "- ucode going to sleep!\n");
49362306a36Sopenharmony_ci		if (!priv->thermal_throttle.advanced_tt)
49462306a36Sopenharmony_ci			iwl_legacy_tt_handler(priv,
49562306a36Sopenharmony_ci					      IWL_MINIMAL_POWER_THRESHOLD,
49662306a36Sopenharmony_ci					      true);
49762306a36Sopenharmony_ci		else
49862306a36Sopenharmony_ci			iwl_advance_tt_handler(priv,
49962306a36Sopenharmony_ci					       CT_KILL_THRESHOLD + 1, true);
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci/* Card State Notification indicated out of critical temperature
50462306a36Sopenharmony_ci * since Card State Notification will not provide any temperature reading
50562306a36Sopenharmony_ci * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
50662306a36Sopenharmony_ci * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
50762306a36Sopenharmony_ci */
50862306a36Sopenharmony_cistatic void iwl_bg_ct_exit(struct work_struct *work)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
51162306a36Sopenharmony_ci	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
51462306a36Sopenharmony_ci		return;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	if (!iwl_is_ready(priv))
51762306a36Sopenharmony_ci		return;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	/* stop ct_kill_exit_tm timer */
52062306a36Sopenharmony_ci	del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	if (tt->state == IWL_TI_CT_KILL) {
52362306a36Sopenharmony_ci		IWL_ERR(priv,
52462306a36Sopenharmony_ci			"Device temperature below critical"
52562306a36Sopenharmony_ci			"- ucode awake!\n");
52662306a36Sopenharmony_ci		/*
52762306a36Sopenharmony_ci		 * exit from CT_KILL state
52862306a36Sopenharmony_ci		 * reset the current temperature reading
52962306a36Sopenharmony_ci		 */
53062306a36Sopenharmony_ci		priv->temperature = 0;
53162306a36Sopenharmony_ci		if (!priv->thermal_throttle.advanced_tt)
53262306a36Sopenharmony_ci			iwl_legacy_tt_handler(priv,
53362306a36Sopenharmony_ci				      IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
53462306a36Sopenharmony_ci				      true);
53562306a36Sopenharmony_ci		else
53662306a36Sopenharmony_ci			iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
53762306a36Sopenharmony_ci					       true);
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_civoid iwl_tt_enter_ct_kill(struct iwl_priv *priv)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
54462306a36Sopenharmony_ci		return;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n");
54762306a36Sopenharmony_ci	queue_work(priv->workqueue, &priv->ct_enter);
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_civoid iwl_tt_exit_ct_kill(struct iwl_priv *priv)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
55362306a36Sopenharmony_ci		return;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n");
55662306a36Sopenharmony_ci	queue_work(priv->workqueue, &priv->ct_exit);
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic void iwl_bg_tt_work(struct work_struct *work)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
56262306a36Sopenharmony_ci	s32 temp = priv->temperature; /* degrees CELSIUS except specified */
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
56562306a36Sopenharmony_ci		return;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (!priv->thermal_throttle.advanced_tt)
56862306a36Sopenharmony_ci		iwl_legacy_tt_handler(priv, temp, false);
56962306a36Sopenharmony_ci	else
57062306a36Sopenharmony_ci		iwl_advance_tt_handler(priv, temp, false);
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_civoid iwl_tt_handler(struct iwl_priv *priv)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
57662306a36Sopenharmony_ci		return;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n");
57962306a36Sopenharmony_ci	queue_work(priv->workqueue, &priv->tt_work);
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci/* Thermal throttling initialization
58362306a36Sopenharmony_ci * For advance thermal throttling:
58462306a36Sopenharmony_ci *     Initialize Thermal Index and temperature threshold table
58562306a36Sopenharmony_ci *     Initialize thermal throttling restriction table
58662306a36Sopenharmony_ci */
58762306a36Sopenharmony_civoid iwl_tt_initialize(struct iwl_priv *priv)
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
59062306a36Sopenharmony_ci	int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
59162306a36Sopenharmony_ci	struct iwl_tt_trans *transaction;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	IWL_DEBUG_TEMP(priv, "Initialize Thermal Throttling\n");
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	memset(tt, 0, sizeof(struct iwl_tt_mgmt));
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	tt->state = IWL_TI_0;
59862306a36Sopenharmony_ci	timer_setup(&priv->thermal_throttle.ct_kill_exit_tm,
59962306a36Sopenharmony_ci		    iwl_tt_check_exit_ct_kill, 0);
60062306a36Sopenharmony_ci	timer_setup(&priv->thermal_throttle.ct_kill_waiting_tm,
60162306a36Sopenharmony_ci		    iwl_tt_ready_for_ct_kill, 0);
60262306a36Sopenharmony_ci	/* setup deferred ct kill work */
60362306a36Sopenharmony_ci	INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
60462306a36Sopenharmony_ci	INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
60562306a36Sopenharmony_ci	INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	if (priv->lib->adv_thermal_throttle) {
60862306a36Sopenharmony_ci		IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n");
60962306a36Sopenharmony_ci		tt->restriction = kcalloc(IWL_TI_STATE_MAX,
61062306a36Sopenharmony_ci					  sizeof(struct iwl_tt_restriction),
61162306a36Sopenharmony_ci					  GFP_KERNEL);
61262306a36Sopenharmony_ci		tt->transaction = kcalloc(IWL_TI_STATE_MAX *
61362306a36Sopenharmony_ci					  (IWL_TI_STATE_MAX - 1),
61462306a36Sopenharmony_ci					  sizeof(struct iwl_tt_trans),
61562306a36Sopenharmony_ci					  GFP_KERNEL);
61662306a36Sopenharmony_ci		if (!tt->restriction || !tt->transaction) {
61762306a36Sopenharmony_ci			IWL_ERR(priv, "Fallback to Legacy Throttling\n");
61862306a36Sopenharmony_ci			priv->thermal_throttle.advanced_tt = false;
61962306a36Sopenharmony_ci			kfree(tt->restriction);
62062306a36Sopenharmony_ci			tt->restriction = NULL;
62162306a36Sopenharmony_ci			kfree(tt->transaction);
62262306a36Sopenharmony_ci			tt->transaction = NULL;
62362306a36Sopenharmony_ci		} else {
62462306a36Sopenharmony_ci			transaction = tt->transaction +
62562306a36Sopenharmony_ci				(IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
62662306a36Sopenharmony_ci			memcpy(transaction, &tt_range_0[0], size);
62762306a36Sopenharmony_ci			transaction = tt->transaction +
62862306a36Sopenharmony_ci				(IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
62962306a36Sopenharmony_ci			memcpy(transaction, &tt_range_1[0], size);
63062306a36Sopenharmony_ci			transaction = tt->transaction +
63162306a36Sopenharmony_ci				(IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
63262306a36Sopenharmony_ci			memcpy(transaction, &tt_range_2[0], size);
63362306a36Sopenharmony_ci			transaction = tt->transaction +
63462306a36Sopenharmony_ci				(IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
63562306a36Sopenharmony_ci			memcpy(transaction, &tt_range_3[0], size);
63662306a36Sopenharmony_ci			size = sizeof(struct iwl_tt_restriction) *
63762306a36Sopenharmony_ci				IWL_TI_STATE_MAX;
63862306a36Sopenharmony_ci			memcpy(tt->restriction,
63962306a36Sopenharmony_ci				&restriction_range[0], size);
64062306a36Sopenharmony_ci			priv->thermal_throttle.advanced_tt = true;
64162306a36Sopenharmony_ci		}
64262306a36Sopenharmony_ci	} else {
64362306a36Sopenharmony_ci		IWL_DEBUG_TEMP(priv, "Legacy Thermal Throttling\n");
64462306a36Sopenharmony_ci		priv->thermal_throttle.advanced_tt = false;
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci/* cleanup thermal throttling management related memory and timer */
64962306a36Sopenharmony_civoid iwl_tt_exit(struct iwl_priv *priv)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/* stop ct_kill_exit_tm timer if activated */
65462306a36Sopenharmony_ci	del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
65562306a36Sopenharmony_ci	/* stop ct_kill_waiting_tm timer if activated */
65662306a36Sopenharmony_ci	del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
65762306a36Sopenharmony_ci	cancel_work_sync(&priv->tt_work);
65862306a36Sopenharmony_ci	cancel_work_sync(&priv->ct_enter);
65962306a36Sopenharmony_ci	cancel_work_sync(&priv->ct_exit);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	if (priv->thermal_throttle.advanced_tt) {
66262306a36Sopenharmony_ci		/* free advance thermal throttling memory */
66362306a36Sopenharmony_ci		kfree(tt->restriction);
66462306a36Sopenharmony_ci		tt->restriction = NULL;
66562306a36Sopenharmony_ci		kfree(tt->transaction);
66662306a36Sopenharmony_ci		tt->transaction = NULL;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci}
669