cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tt.c (21278B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/******************************************************************************
      3 *
      4 * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
      5 * Copyright (C) 2018, 2020 Intel Corporation
      6 *
      7 * Portions of this file are derived from the ipw3945 project, as well
      8 * as portions of the ieee80211 subsystem header files.
      9 *****************************************************************************/
     10
     11
     12#include <linux/kernel.h>
     13#include <linux/module.h>
     14#include <linux/slab.h>
     15#include <net/mac80211.h>
     16#include "iwl-io.h"
     17#include "iwl-modparams.h"
     18#include "iwl-debug.h"
     19#include "agn.h"
     20#include "dev.h"
     21#include "commands.h"
     22#include "tt.h"
     23
     24/* default Thermal Throttling transaction table
     25 * Current state   |         Throttling Down               |  Throttling Up
     26 *=============================================================================
     27 *                 Condition Nxt State  Condition Nxt State Condition Nxt State
     28 *-----------------------------------------------------------------------------
     29 *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
     30 *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
     31 *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
     32 *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
     33 *=============================================================================
     34 */
     35static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
     36	{IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
     37	{IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
     38	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
     39};
     40static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
     41	{IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
     42	{IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
     43	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
     44};
     45static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
     46	{IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
     47	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
     48	{IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
     49};
     50static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
     51	{IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
     52	{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
     53	{IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
     54};
     55
     56/* Advance Thermal Throttling default restriction table */
     57static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
     58	{IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
     59	{IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
     60	{IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
     61	{IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
     62};
     63
     64bool iwl_tt_is_low_power_state(struct iwl_priv *priv)
     65{
     66	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
     67
     68	if (tt->state >= IWL_TI_1)
     69		return true;
     70	return false;
     71}
     72
     73u8 iwl_tt_current_power_mode(struct iwl_priv *priv)
     74{
     75	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
     76
     77	return tt->tt_power_mode;
     78}
     79
     80bool iwl_ht_enabled(struct iwl_priv *priv)
     81{
     82	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
     83	struct iwl_tt_restriction *restriction;
     84
     85	if (!priv->thermal_throttle.advanced_tt)
     86		return true;
     87	restriction = tt->restriction + tt->state;
     88	return restriction->is_ht;
     89}
     90
     91static bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
     92{
     93	s32 temp = priv->temperature; /* degrees CELSIUS except specified */
     94	bool within_margin = false;
     95
     96	if (!priv->thermal_throttle.advanced_tt)
     97		within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
     98				CT_KILL_THRESHOLD_LEGACY) ? true : false;
     99	else
    100		within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
    101				CT_KILL_THRESHOLD) ? true : false;
    102	return within_margin;
    103}
    104
    105bool iwl_check_for_ct_kill(struct iwl_priv *priv)
    106{
    107	bool is_ct_kill = false;
    108
    109	if (iwl_within_ct_kill_margin(priv)) {
    110		iwl_tt_enter_ct_kill(priv);
    111		is_ct_kill = true;
    112	}
    113	return is_ct_kill;
    114}
    115
    116enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
    117{
    118	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
    119	struct iwl_tt_restriction *restriction;
    120
    121	if (!priv->thermal_throttle.advanced_tt)
    122		return IWL_ANT_OK_MULTI;
    123	restriction = tt->restriction + tt->state;
    124	return restriction->tx_stream;
    125}
    126
    127enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
    128{
    129	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
    130	struct iwl_tt_restriction *restriction;
    131
    132	if (!priv->thermal_throttle.advanced_tt)
    133		return IWL_ANT_OK_MULTI;
    134	restriction = tt->restriction + tt->state;
    135	return restriction->rx_stream;
    136}
    137
    138#define CT_KILL_EXIT_DURATION (5)	/* 5 seconds duration */
    139#define CT_KILL_WAITING_DURATION (300)	/* 300ms duration */
    140
    141/*
    142 * toggle the bit to wake up uCode and check the temperature
    143 * if the temperature is below CT, uCode will stay awake and send card
    144 * state notification with CT_KILL bit clear to inform Thermal Throttling
    145 * Management to change state. Otherwise, uCode will go back to sleep
    146 * without doing anything, driver should continue the 5 seconds timer
    147 * to wake up uCode for temperature check until temperature drop below CT
    148 */
    149static void iwl_tt_check_exit_ct_kill(struct timer_list *t)
    150{
    151	struct iwl_priv *priv = from_timer(priv, t,
    152					   thermal_throttle.ct_kill_exit_tm);
    153	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
    154
    155	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
    156		return;
    157
    158	if (tt->state == IWL_TI_CT_KILL) {
    159		if (priv->thermal_throttle.ct_kill_toggle) {
    160			iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
    161				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
    162			priv->thermal_throttle.ct_kill_toggle = false;
    163		} else {
    164			iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
    165				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
    166			priv->thermal_throttle.ct_kill_toggle = true;
    167		}
    168		iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
    169		if (iwl_trans_grab_nic_access(priv->trans))
    170			iwl_trans_release_nic_access(priv->trans);
    171
    172		/* Reschedule the ct_kill timer to occur in
    173		 * CT_KILL_EXIT_DURATION seconds to ensure we get a
    174		 * thermal update */
    175		IWL_DEBUG_TEMP(priv, "schedule ct_kill exit timer\n");
    176		mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
    177			  jiffies + CT_KILL_EXIT_DURATION * HZ);
    178	}
    179}
    180
    181static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
    182			   bool stop)
    183{
    184	if (stop) {
    185		IWL_DEBUG_TEMP(priv, "Stop all queues\n");
    186		if (priv->mac80211_registered)
    187			ieee80211_stop_queues(priv->hw);
    188		IWL_DEBUG_TEMP(priv,
    189				"Schedule 5 seconds CT_KILL Timer\n");
    190		mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
    191			  jiffies + CT_KILL_EXIT_DURATION * HZ);
    192	} else {
    193		IWL_DEBUG_TEMP(priv, "Wake all queues\n");
    194		if (priv->mac80211_registered)
    195			ieee80211_wake_queues(priv->hw);
    196	}
    197}
    198
    199static void iwl_tt_ready_for_ct_kill(struct timer_list *t)
    200{
    201	struct iwl_priv *priv = from_timer(priv, t,
    202					   thermal_throttle.ct_kill_waiting_tm);
    203	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
    204
    205	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
    206		return;
    207
    208	/* temperature timer expired, ready to go into CT_KILL state */
    209	if (tt->state != IWL_TI_CT_KILL) {
    210		IWL_DEBUG_TEMP(priv, "entering CT_KILL state when "
    211				"temperature timer expired\n");
    212		tt->state = IWL_TI_CT_KILL;
    213		set_bit(STATUS_CT_KILL, &priv->status);
    214		iwl_perform_ct_kill_task(priv, true);
    215	}
    216}
    217
    218static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
    219{
    220	IWL_DEBUG_TEMP(priv, "Prepare to enter IWL_TI_CT_KILL\n");
    221	/* make request to retrieve statistics information */
    222	iwl_send_statistics_request(priv, 0, false);
    223	/* Reschedule the ct_kill wait timer */
    224	mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
    225		 jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
    226}
    227
    228#define IWL_MINIMAL_POWER_THRESHOLD		(CT_KILL_THRESHOLD_LEGACY)
    229#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2	(100)
    230#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1	(90)
    231
    232/*
    233 * Legacy thermal throttling
    234 * 1) Avoid NIC destruction due to high temperatures
    235 *	Chip will identify dangerously high temperatures that can
    236 *	harm the device and will power down
    237 * 2) Avoid the NIC power down due to high temperature
    238 *	Throttle early enough to lower the power consumption before
    239 *	drastic steps are needed
    240 */
    241static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
    242{
    243	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
    244	enum iwl_tt_state old_state;
    245
    246#ifdef CONFIG_IWLWIFI_DEBUG
    247	if ((tt->tt_previous_temp) &&
    248	    (temp > tt->tt_previous_temp) &&
    249	    ((temp - tt->tt_previous_temp) >
    250	    IWL_TT_INCREASE_MARGIN)) {
    251		IWL_DEBUG_TEMP(priv,
    252			"Temperature increase %d degree Celsius\n",
    253			(temp - tt->tt_previous_temp));
    254	}
    255#endif
    256	old_state = tt->state;
    257	/* in Celsius */
    258	if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
    259		tt->state = IWL_TI_CT_KILL;
    260	else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
    261		tt->state = IWL_TI_2;
    262	else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
    263		tt->state = IWL_TI_1;
    264	else
    265		tt->state = IWL_TI_0;
    266
    267#ifdef CONFIG_IWLWIFI_DEBUG
    268	tt->tt_previous_temp = temp;
    269#endif
    270	/* stop ct_kill_waiting_tm timer */
    271	del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
    272	if (tt->state != old_state) {
    273		switch (tt->state) {
    274		case IWL_TI_0:
    275			/*
    276			 * When the system is ready to go back to IWL_TI_0
    277			 * we only have to call iwl_power_update_mode() to
    278			 * do so.
    279			 */
    280			break;
    281		case IWL_TI_1:
    282			tt->tt_power_mode = IWL_POWER_INDEX_3;
    283			break;
    284		case IWL_TI_2:
    285			tt->tt_power_mode = IWL_POWER_INDEX_4;
    286			break;
    287		default:
    288			tt->tt_power_mode = IWL_POWER_INDEX_5;
    289			break;
    290		}
    291		mutex_lock(&priv->mutex);
    292		if (old_state == IWL_TI_CT_KILL)
    293			clear_bit(STATUS_CT_KILL, &priv->status);
    294		if (tt->state != IWL_TI_CT_KILL &&
    295		    iwl_power_update_mode(priv, true)) {
    296			/* TT state not updated
    297			 * try again during next temperature read
    298			 */
    299			if (old_state == IWL_TI_CT_KILL)
    300				set_bit(STATUS_CT_KILL, &priv->status);
    301			tt->state = old_state;
    302			IWL_ERR(priv, "Cannot update power mode, "
    303					"TT state not updated\n");
    304		} else {
    305			if (tt->state == IWL_TI_CT_KILL) {
    306				if (force) {
    307					set_bit(STATUS_CT_KILL, &priv->status);
    308					iwl_perform_ct_kill_task(priv, true);
    309				} else {
    310					iwl_prepare_ct_kill_task(priv);
    311					tt->state = old_state;
    312				}
    313			} else if (old_state == IWL_TI_CT_KILL) {
    314				iwl_perform_ct_kill_task(priv, false);
    315			}
    316			IWL_DEBUG_TEMP(priv, "Temperature state changed %u\n",
    317					tt->state);
    318			IWL_DEBUG_TEMP(priv, "Power Index change to %u\n",
    319					tt->tt_power_mode);
    320		}
    321		mutex_unlock(&priv->mutex);
    322	}
    323}
    324
    325/*
    326 * Advance thermal throttling
    327 * 1) Avoid NIC destruction due to high temperatures
    328 *	Chip will identify dangerously high temperatures that can
    329 *	harm the device and will power down
    330 * 2) Avoid the NIC power down due to high temperature
    331 *	Throttle early enough to lower the power consumption before
    332 *	drastic steps are needed
    333 *	Actions include relaxing the power down sleep thresholds and
    334 *	decreasing the number of TX streams
    335 * 3) Avoid throughput performance impact as much as possible
    336 *
    337 *=============================================================================
    338 *                 Condition Nxt State  Condition Nxt State Condition Nxt State
    339 *-----------------------------------------------------------------------------
    340 *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
    341 *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
    342 *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
    343 *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
    344 *=============================================================================
    345 */
    346static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
    347{
    348	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
    349	int i;
    350	bool changed = false;
    351	enum iwl_tt_state old_state;
    352	struct iwl_tt_trans *transaction;
    353
    354	old_state = tt->state;
    355	for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
    356		/* based on the current TT state,
    357		 * find the curresponding transaction table
    358		 * each table has (IWL_TI_STATE_MAX - 1) entries
    359		 * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
    360		 * will advance to the correct table.
    361		 * then based on the current temperature
    362		 * find the next state need to transaction to
    363		 * go through all the possible (IWL_TI_STATE_MAX - 1) entries
    364		 * in the current table to see if transaction is needed
    365		 */
    366		transaction = tt->transaction +
    367			((old_state * (IWL_TI_STATE_MAX - 1)) + i);
    368		if (temp >= transaction->tt_low &&
    369		    temp <= transaction->tt_high) {
    370#ifdef CONFIG_IWLWIFI_DEBUG
    371			if ((tt->tt_previous_temp) &&
    372			    (temp > tt->tt_previous_temp) &&
    373			    ((temp - tt->tt_previous_temp) >
    374			    IWL_TT_INCREASE_MARGIN)) {
    375				IWL_DEBUG_TEMP(priv,
    376					"Temperature increase %d "
    377					"degree Celsius\n",
    378					(temp - tt->tt_previous_temp));
    379			}
    380			tt->tt_previous_temp = temp;
    381#endif
    382			if (old_state !=
    383			    transaction->next_state) {
    384				changed = true;
    385				tt->state =
    386					transaction->next_state;
    387			}
    388			break;
    389		}
    390	}
    391	/* stop ct_kill_waiting_tm timer */
    392	del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
    393	if (changed) {
    394		if (tt->state >= IWL_TI_1) {
    395			/* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
    396			tt->tt_power_mode = IWL_POWER_INDEX_5;
    397
    398			if (!iwl_ht_enabled(priv)) {
    399				struct iwl_rxon_context *ctx;
    400
    401				for_each_context(priv, ctx) {
    402					struct iwl_rxon_cmd *rxon;
    403
    404					rxon = &ctx->staging;
    405
    406					/* disable HT */
    407					rxon->flags &= ~(
    408						RXON_FLG_CHANNEL_MODE_MSK |
    409						RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
    410						RXON_FLG_HT40_PROT_MSK |
    411						RXON_FLG_HT_PROT_MSK);
    412				}
    413			} else {
    414				/* check HT capability and set
    415				 * according to the system HT capability
    416				 * in case get disabled before */
    417				iwl_set_rxon_ht(priv, &priv->current_ht_config);
    418			}
    419
    420		} else {
    421			/*
    422			 * restore system power setting -- it will be
    423			 * recalculated automatically.
    424			 */
    425
    426			/* check HT capability and set
    427			 * according to the system HT capability
    428			 * in case get disabled before */
    429			iwl_set_rxon_ht(priv, &priv->current_ht_config);
    430		}
    431		mutex_lock(&priv->mutex);
    432		if (old_state == IWL_TI_CT_KILL)
    433			clear_bit(STATUS_CT_KILL, &priv->status);
    434		if (tt->state != IWL_TI_CT_KILL &&
    435		    iwl_power_update_mode(priv, true)) {
    436			/* TT state not updated
    437			 * try again during next temperature read
    438			 */
    439			IWL_ERR(priv, "Cannot update power mode, "
    440					"TT state not updated\n");
    441			if (old_state == IWL_TI_CT_KILL)
    442				set_bit(STATUS_CT_KILL, &priv->status);
    443			tt->state = old_state;
    444		} else {
    445			IWL_DEBUG_TEMP(priv,
    446					"Thermal Throttling to new state: %u\n",
    447					tt->state);
    448			if (old_state != IWL_TI_CT_KILL &&
    449			    tt->state == IWL_TI_CT_KILL) {
    450				if (force) {
    451					IWL_DEBUG_TEMP(priv,
    452						"Enter IWL_TI_CT_KILL\n");
    453					set_bit(STATUS_CT_KILL, &priv->status);
    454					iwl_perform_ct_kill_task(priv, true);
    455				} else {
    456					tt->state = old_state;
    457					iwl_prepare_ct_kill_task(priv);
    458				}
    459			} else if (old_state == IWL_TI_CT_KILL &&
    460				  tt->state != IWL_TI_CT_KILL) {
    461				IWL_DEBUG_TEMP(priv, "Exit IWL_TI_CT_KILL\n");
    462				iwl_perform_ct_kill_task(priv, false);
    463			}
    464		}
    465		mutex_unlock(&priv->mutex);
    466	}
    467}
    468
    469/* Card State Notification indicated reach critical temperature
    470 * if PSP not enable, no Thermal Throttling function will be performed
    471 * just set the GP1 bit to acknowledge the event
    472 * otherwise, go into IWL_TI_CT_KILL state
    473 * since Card State Notification will not provide any temperature reading
    474 * for Legacy mode
    475 * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
    476 * for advance mode
    477 * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
    478 */
    479static void iwl_bg_ct_enter(struct work_struct *work)
    480{
    481	struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
    482	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
    483
    484	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
    485		return;
    486
    487	if (!iwl_is_ready(priv))
    488		return;
    489
    490	if (tt->state != IWL_TI_CT_KILL) {
    491		IWL_ERR(priv, "Device reached critical temperature "
    492			      "- ucode going to sleep!\n");
    493		if (!priv->thermal_throttle.advanced_tt)
    494			iwl_legacy_tt_handler(priv,
    495					      IWL_MINIMAL_POWER_THRESHOLD,
    496					      true);
    497		else
    498			iwl_advance_tt_handler(priv,
    499					       CT_KILL_THRESHOLD + 1, true);
    500	}
    501}
    502
    503/* Card State Notification indicated out of critical temperature
    504 * since Card State Notification will not provide any temperature reading
    505 * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
    506 * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
    507 */
    508static void iwl_bg_ct_exit(struct work_struct *work)
    509{
    510	struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
    511	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
    512
    513	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
    514		return;
    515
    516	if (!iwl_is_ready(priv))
    517		return;
    518
    519	/* stop ct_kill_exit_tm timer */
    520	del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
    521
    522	if (tt->state == IWL_TI_CT_KILL) {
    523		IWL_ERR(priv,
    524			"Device temperature below critical"
    525			"- ucode awake!\n");
    526		/*
    527		 * exit from CT_KILL state
    528		 * reset the current temperature reading
    529		 */
    530		priv->temperature = 0;
    531		if (!priv->thermal_throttle.advanced_tt)
    532			iwl_legacy_tt_handler(priv,
    533				      IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
    534				      true);
    535		else
    536			iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
    537					       true);
    538	}
    539}
    540
    541void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
    542{
    543	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
    544		return;
    545
    546	IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n");
    547	queue_work(priv->workqueue, &priv->ct_enter);
    548}
    549
    550void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
    551{
    552	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
    553		return;
    554
    555	IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n");
    556	queue_work(priv->workqueue, &priv->ct_exit);
    557}
    558
    559static void iwl_bg_tt_work(struct work_struct *work)
    560{
    561	struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
    562	s32 temp = priv->temperature; /* degrees CELSIUS except specified */
    563
    564	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
    565		return;
    566
    567	if (!priv->thermal_throttle.advanced_tt)
    568		iwl_legacy_tt_handler(priv, temp, false);
    569	else
    570		iwl_advance_tt_handler(priv, temp, false);
    571}
    572
    573void iwl_tt_handler(struct iwl_priv *priv)
    574{
    575	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
    576		return;
    577
    578	IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n");
    579	queue_work(priv->workqueue, &priv->tt_work);
    580}
    581
    582/* Thermal throttling initialization
    583 * For advance thermal throttling:
    584 *     Initialize Thermal Index and temperature threshold table
    585 *     Initialize thermal throttling restriction table
    586 */
    587void iwl_tt_initialize(struct iwl_priv *priv)
    588{
    589	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
    590	int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
    591	struct iwl_tt_trans *transaction;
    592
    593	IWL_DEBUG_TEMP(priv, "Initialize Thermal Throttling\n");
    594
    595	memset(tt, 0, sizeof(struct iwl_tt_mgmt));
    596
    597	tt->state = IWL_TI_0;
    598	timer_setup(&priv->thermal_throttle.ct_kill_exit_tm,
    599		    iwl_tt_check_exit_ct_kill, 0);
    600	timer_setup(&priv->thermal_throttle.ct_kill_waiting_tm,
    601		    iwl_tt_ready_for_ct_kill, 0);
    602	/* setup deferred ct kill work */
    603	INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
    604	INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
    605	INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
    606
    607	if (priv->lib->adv_thermal_throttle) {
    608		IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n");
    609		tt->restriction = kcalloc(IWL_TI_STATE_MAX,
    610					  sizeof(struct iwl_tt_restriction),
    611					  GFP_KERNEL);
    612		tt->transaction = kcalloc(IWL_TI_STATE_MAX *
    613					  (IWL_TI_STATE_MAX - 1),
    614					  sizeof(struct iwl_tt_trans),
    615					  GFP_KERNEL);
    616		if (!tt->restriction || !tt->transaction) {
    617			IWL_ERR(priv, "Fallback to Legacy Throttling\n");
    618			priv->thermal_throttle.advanced_tt = false;
    619			kfree(tt->restriction);
    620			tt->restriction = NULL;
    621			kfree(tt->transaction);
    622			tt->transaction = NULL;
    623		} else {
    624			transaction = tt->transaction +
    625				(IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
    626			memcpy(transaction, &tt_range_0[0], size);
    627			transaction = tt->transaction +
    628				(IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
    629			memcpy(transaction, &tt_range_1[0], size);
    630			transaction = tt->transaction +
    631				(IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
    632			memcpy(transaction, &tt_range_2[0], size);
    633			transaction = tt->transaction +
    634				(IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
    635			memcpy(transaction, &tt_range_3[0], size);
    636			size = sizeof(struct iwl_tt_restriction) *
    637				IWL_TI_STATE_MAX;
    638			memcpy(tt->restriction,
    639				&restriction_range[0], size);
    640			priv->thermal_throttle.advanced_tt = true;
    641		}
    642	} else {
    643		IWL_DEBUG_TEMP(priv, "Legacy Thermal Throttling\n");
    644		priv->thermal_throttle.advanced_tt = false;
    645	}
    646}
    647
    648/* cleanup thermal throttling management related memory and timer */
    649void iwl_tt_exit(struct iwl_priv *priv)
    650{
    651	struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
    652
    653	/* stop ct_kill_exit_tm timer if activated */
    654	del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
    655	/* stop ct_kill_waiting_tm timer if activated */
    656	del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
    657	cancel_work_sync(&priv->tt_work);
    658	cancel_work_sync(&priv->ct_enter);
    659	cancel_work_sync(&priv->ct_exit);
    660
    661	if (priv->thermal_throttle.advanced_tt) {
    662		/* free advance thermal throttling memory */
    663		kfree(tt->restriction);
    664		tt->restriction = NULL;
    665		kfree(tt->transaction);
    666		tt->transaction = NULL;
    667	}
    668}