diff options
author | Kalle Valo <kvalo@codeaurora.org> | 2015-11-17 13:57:38 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-11-18 07:28:30 -0500 |
commit | e705c12146aa9c69ca498d4ebb83ba7138f9b41f (patch) | |
tree | b55d4eb7a83c2ec117f460684eb71c89eee6a709 /drivers/net/wireless/intel/iwlwifi/mvm/tt.c | |
parent | 7ac9a364c1721a863ecc6cc9aba66e10114908db (diff) |
iwlwifi: move under intel vendor directory
Part of reorganising wireless drivers directory and Kconfig.
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/tt.c')
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c new file mode 100644 index 000000000000..cadfc0460597 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c | |||
@@ -0,0 +1,460 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. | ||
9 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of version 2 of the GNU General Public License as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
23 | * USA | ||
24 | * | ||
25 | * The full GNU General Public License is included in this distribution | ||
26 | * in the file called COPYING. | ||
27 | * | ||
28 | * Contact Information: | ||
29 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
30 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
31 | * | ||
32 | * BSD LICENSE | ||
33 | * | ||
34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | ||
35 | * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH | ||
36 | * Copyright(c) 2015 Intel Deutschland GmbH | ||
37 | * All rights reserved. | ||
38 | * | ||
39 | * Redistribution and use in source and binary forms, with or without | ||
40 | * modification, are permitted provided that the following conditions | ||
41 | * are met: | ||
42 | * | ||
43 | * * Redistributions of source code must retain the above copyright | ||
44 | * notice, this list of conditions and the following disclaimer. | ||
45 | * * Redistributions in binary form must reproduce the above copyright | ||
46 | * notice, this list of conditions and the following disclaimer in | ||
47 | * the documentation and/or other materials provided with the | ||
48 | * distribution. | ||
49 | * * Neither the name Intel Corporation nor the names of its | ||
50 | * contributors may be used to endorse or promote products derived | ||
51 | * from this software without specific prior written permission. | ||
52 | * | ||
53 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
54 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
55 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
56 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
57 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
58 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
59 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
60 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
61 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
62 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
63 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
64 | * | ||
65 | *****************************************************************************/ | ||
66 | |||
67 | #include "mvm.h" | ||
68 | |||
69 | #define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ | ||
70 | |||
71 | static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) | ||
72 | { | ||
73 | struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; | ||
74 | u32 duration = tt->params.ct_kill_duration; | ||
75 | |||
76 | if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) | ||
77 | return; | ||
78 | |||
79 | IWL_ERR(mvm, "Enter CT Kill\n"); | ||
80 | iwl_mvm_set_hw_ctkill_state(mvm, true); | ||
81 | |||
82 | tt->throttle = false; | ||
83 | tt->dynamic_smps = false; | ||
84 | |||
85 | /* Don't schedule an exit work if we're in test mode, since | ||
86 | * the temperature will not change unless we manually set it | ||
87 | * again (or disable testing). | ||
88 | */ | ||
89 | if (!mvm->temperature_test) | ||
90 | schedule_delayed_work(&tt->ct_kill_exit, | ||
91 | round_jiffies_relative(duration * HZ)); | ||
92 | } | ||
93 | |||
94 | static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) | ||
95 | { | ||
96 | if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) | ||
97 | return; | ||
98 | |||
99 | IWL_ERR(mvm, "Exit CT Kill\n"); | ||
100 | iwl_mvm_set_hw_ctkill_state(mvm, false); | ||
101 | } | ||
102 | |||
103 | void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp) | ||
104 | { | ||
105 | /* ignore the notification if we are in test mode */ | ||
106 | if (mvm->temperature_test) | ||
107 | return; | ||
108 | |||
109 | if (mvm->temperature == temp) | ||
110 | return; | ||
111 | |||
112 | mvm->temperature = temp; | ||
113 | iwl_mvm_tt_handler(mvm); | ||
114 | } | ||
115 | |||
116 | static int iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm, | ||
117 | struct iwl_rx_packet *pkt) | ||
118 | { | ||
119 | struct iwl_dts_measurement_notif *notif; | ||
120 | int len = iwl_rx_packet_payload_len(pkt); | ||
121 | int temp; | ||
122 | |||
123 | if (WARN_ON_ONCE(len != sizeof(*notif))) { | ||
124 | IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); | ||
125 | return -EINVAL; | ||
126 | } | ||
127 | |||
128 | notif = (void *)pkt->data; | ||
129 | |||
130 | temp = le32_to_cpu(notif->temp); | ||
131 | |||
132 | /* shouldn't be negative, but since it's s32, make sure it isn't */ | ||
133 | if (WARN_ON_ONCE(temp < 0)) | ||
134 | temp = 0; | ||
135 | |||
136 | IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", temp); | ||
137 | |||
138 | return temp; | ||
139 | } | ||
140 | |||
141 | static bool iwl_mvm_temp_notif_wait(struct iwl_notif_wait_data *notif_wait, | ||
142 | struct iwl_rx_packet *pkt, void *data) | ||
143 | { | ||
144 | struct iwl_mvm *mvm = | ||
145 | container_of(notif_wait, struct iwl_mvm, notif_wait); | ||
146 | int *temp = data; | ||
147 | int ret; | ||
148 | |||
149 | ret = iwl_mvm_temp_notif_parse(mvm, pkt); | ||
150 | if (ret < 0) | ||
151 | return true; | ||
152 | |||
153 | *temp = ret; | ||
154 | |||
155 | return true; | ||
156 | } | ||
157 | |||
158 | void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) | ||
159 | { | ||
160 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
161 | int temp; | ||
162 | |||
163 | /* the notification is handled synchronously in ctkill, so skip here */ | ||
164 | if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) | ||
165 | return; | ||
166 | |||
167 | temp = iwl_mvm_temp_notif_parse(mvm, pkt); | ||
168 | if (temp < 0) | ||
169 | return; | ||
170 | |||
171 | iwl_mvm_tt_temp_changed(mvm, temp); | ||
172 | } | ||
173 | |||
174 | static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) | ||
175 | { | ||
176 | struct iwl_dts_measurement_cmd cmd = { | ||
177 | .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP), | ||
178 | }; | ||
179 | struct iwl_ext_dts_measurement_cmd extcmd = { | ||
180 | .control_mode = cpu_to_le32(DTS_AUTOMATIC), | ||
181 | }; | ||
182 | u32 cmdid; | ||
183 | |||
184 | if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WIDE_CMD_HDR)) | ||
185 | cmdid = iwl_cmd_id(CMD_DTS_MEASUREMENT_TRIGGER_WIDE, | ||
186 | PHY_OPS_GROUP, 0); | ||
187 | else | ||
188 | cmdid = CMD_DTS_MEASUREMENT_TRIGGER; | ||
189 | |||
190 | if (!fw_has_capa(&mvm->fw->ucode_capa, | ||
191 | IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE)) | ||
192 | return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(cmd), &cmd); | ||
193 | |||
194 | return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(extcmd), &extcmd); | ||
195 | } | ||
196 | |||
197 | int iwl_mvm_get_temp(struct iwl_mvm *mvm) | ||
198 | { | ||
199 | struct iwl_notification_wait wait_temp_notif; | ||
200 | static u16 temp_notif[] = { WIDE_ID(PHY_OPS_GROUP, | ||
201 | DTS_MEASUREMENT_NOTIF_WIDE) }; | ||
202 | int ret, temp; | ||
203 | |||
204 | if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WIDE_CMD_HDR)) | ||
205 | temp_notif[0] = DTS_MEASUREMENT_NOTIFICATION; | ||
206 | |||
207 | lockdep_assert_held(&mvm->mutex); | ||
208 | |||
209 | iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif, | ||
210 | temp_notif, ARRAY_SIZE(temp_notif), | ||
211 | iwl_mvm_temp_notif_wait, &temp); | ||
212 | |||
213 | ret = iwl_mvm_get_temp_cmd(mvm); | ||
214 | if (ret) { | ||
215 | IWL_ERR(mvm, "Failed to get the temperature (err=%d)\n", ret); | ||
216 | iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif); | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif, | ||
221 | IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT); | ||
222 | if (ret) { | ||
223 | IWL_ERR(mvm, "Getting the temperature timed out\n"); | ||
224 | return ret; | ||
225 | } | ||
226 | |||
227 | return temp; | ||
228 | } | ||
229 | |||
230 | static void check_exit_ctkill(struct work_struct *work) | ||
231 | { | ||
232 | struct iwl_mvm_tt_mgmt *tt; | ||
233 | struct iwl_mvm *mvm; | ||
234 | u32 duration; | ||
235 | s32 temp; | ||
236 | |||
237 | tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work); | ||
238 | mvm = container_of(tt, struct iwl_mvm, thermal_throttle); | ||
239 | |||
240 | duration = tt->params.ct_kill_duration; | ||
241 | |||
242 | mutex_lock(&mvm->mutex); | ||
243 | |||
244 | if (__iwl_mvm_mac_start(mvm)) | ||
245 | goto reschedule; | ||
246 | |||
247 | /* make sure the device is available for direct read/writes */ | ||
248 | if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) { | ||
249 | __iwl_mvm_mac_stop(mvm); | ||
250 | goto reschedule; | ||
251 | } | ||
252 | |||
253 | temp = iwl_mvm_get_temp(mvm); | ||
254 | |||
255 | iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL); | ||
256 | |||
257 | __iwl_mvm_mac_stop(mvm); | ||
258 | |||
259 | if (temp < 0) | ||
260 | goto reschedule; | ||
261 | |||
262 | IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp); | ||
263 | |||
264 | if (temp <= tt->params.ct_kill_exit) { | ||
265 | mutex_unlock(&mvm->mutex); | ||
266 | iwl_mvm_exit_ctkill(mvm); | ||
267 | return; | ||
268 | } | ||
269 | |||
270 | reschedule: | ||
271 | mutex_unlock(&mvm->mutex); | ||
272 | schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, | ||
273 | round_jiffies(duration * HZ)); | ||
274 | } | ||
275 | |||
276 | static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac, | ||
277 | struct ieee80211_vif *vif) | ||
278 | { | ||
279 | struct iwl_mvm *mvm = _data; | ||
280 | enum ieee80211_smps_mode smps_mode; | ||
281 | |||
282 | lockdep_assert_held(&mvm->mutex); | ||
283 | |||
284 | if (mvm->thermal_throttle.dynamic_smps) | ||
285 | smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
286 | else | ||
287 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | ||
288 | |||
289 | if (vif->type != NL80211_IFTYPE_STATION) | ||
290 | return; | ||
291 | |||
292 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode); | ||
293 | } | ||
294 | |||
295 | static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable) | ||
296 | { | ||
297 | struct ieee80211_sta *sta; | ||
298 | struct iwl_mvm_sta *mvmsta; | ||
299 | int i, err; | ||
300 | |||
301 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | ||
302 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | ||
303 | lockdep_is_held(&mvm->mutex)); | ||
304 | if (IS_ERR_OR_NULL(sta)) | ||
305 | continue; | ||
306 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
307 | if (enable == mvmsta->tt_tx_protection) | ||
308 | continue; | ||
309 | err = iwl_mvm_tx_protection(mvm, mvmsta, enable); | ||
310 | if (err) { | ||
311 | IWL_ERR(mvm, "Failed to %s Tx protection\n", | ||
312 | enable ? "enable" : "disable"); | ||
313 | } else { | ||
314 | IWL_DEBUG_TEMP(mvm, "%s Tx protection\n", | ||
315 | enable ? "Enable" : "Disable"); | ||
316 | mvmsta->tt_tx_protection = enable; | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | |||
321 | void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff) | ||
322 | { | ||
323 | struct iwl_host_cmd cmd = { | ||
324 | .id = REPLY_THERMAL_MNG_BACKOFF, | ||
325 | .len = { sizeof(u32), }, | ||
326 | .data = { &backoff, }, | ||
327 | }; | ||
328 | |||
329 | backoff = max(backoff, mvm->thermal_throttle.min_backoff); | ||
330 | |||
331 | if (iwl_mvm_send_cmd(mvm, &cmd) == 0) { | ||
332 | IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n", | ||
333 | backoff); | ||
334 | mvm->thermal_throttle.tx_backoff = backoff; | ||
335 | } else { | ||
336 | IWL_ERR(mvm, "Failed to change Thermal Tx backoff\n"); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | void iwl_mvm_tt_handler(struct iwl_mvm *mvm) | ||
341 | { | ||
342 | struct iwl_tt_params *params = &mvm->thermal_throttle.params; | ||
343 | struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; | ||
344 | s32 temperature = mvm->temperature; | ||
345 | bool throttle_enable = false; | ||
346 | int i; | ||
347 | u32 tx_backoff; | ||
348 | |||
349 | IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", mvm->temperature); | ||
350 | |||
351 | if (params->support_ct_kill && temperature >= params->ct_kill_entry) { | ||
352 | iwl_mvm_enter_ctkill(mvm); | ||
353 | return; | ||
354 | } | ||
355 | |||
356 | if (params->support_ct_kill && | ||
357 | temperature <= params->ct_kill_exit) { | ||
358 | iwl_mvm_exit_ctkill(mvm); | ||
359 | return; | ||
360 | } | ||
361 | |||
362 | if (params->support_dynamic_smps) { | ||
363 | if (!tt->dynamic_smps && | ||
364 | temperature >= params->dynamic_smps_entry) { | ||
365 | IWL_DEBUG_TEMP(mvm, "Enable dynamic SMPS\n"); | ||
366 | tt->dynamic_smps = true; | ||
367 | ieee80211_iterate_active_interfaces_atomic( | ||
368 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
369 | iwl_mvm_tt_smps_iterator, mvm); | ||
370 | throttle_enable = true; | ||
371 | } else if (tt->dynamic_smps && | ||
372 | temperature <= params->dynamic_smps_exit) { | ||
373 | IWL_DEBUG_TEMP(mvm, "Disable dynamic SMPS\n"); | ||
374 | tt->dynamic_smps = false; | ||
375 | ieee80211_iterate_active_interfaces_atomic( | ||
376 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
377 | iwl_mvm_tt_smps_iterator, mvm); | ||
378 | } | ||
379 | } | ||
380 | |||
381 | if (params->support_tx_protection) { | ||
382 | if (temperature >= params->tx_protection_entry) { | ||
383 | iwl_mvm_tt_tx_protection(mvm, true); | ||
384 | throttle_enable = true; | ||
385 | } else if (temperature <= params->tx_protection_exit) { | ||
386 | iwl_mvm_tt_tx_protection(mvm, false); | ||
387 | } | ||
388 | } | ||
389 | |||
390 | if (params->support_tx_backoff) { | ||
391 | tx_backoff = tt->min_backoff; | ||
392 | for (i = 0; i < TT_TX_BACKOFF_SIZE; i++) { | ||
393 | if (temperature < params->tx_backoff[i].temperature) | ||
394 | break; | ||
395 | tx_backoff = max(tt->min_backoff, | ||
396 | params->tx_backoff[i].backoff); | ||
397 | } | ||
398 | if (tx_backoff != tt->min_backoff) | ||
399 | throttle_enable = true; | ||
400 | if (tt->tx_backoff != tx_backoff) | ||
401 | iwl_mvm_tt_tx_backoff(mvm, tx_backoff); | ||
402 | } | ||
403 | |||
404 | if (!tt->throttle && throttle_enable) { | ||
405 | IWL_WARN(mvm, | ||
406 | "Due to high temperature thermal throttling initiated\n"); | ||
407 | tt->throttle = true; | ||
408 | } else if (tt->throttle && !tt->dynamic_smps && | ||
409 | tt->tx_backoff == tt->min_backoff && | ||
410 | temperature <= params->tx_protection_exit) { | ||
411 | IWL_WARN(mvm, | ||
412 | "Temperature is back to normal thermal throttling stopped\n"); | ||
413 | tt->throttle = false; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | static const struct iwl_tt_params iwl_mvm_default_tt_params = { | ||
418 | .ct_kill_entry = 118, | ||
419 | .ct_kill_exit = 96, | ||
420 | .ct_kill_duration = 5, | ||
421 | .dynamic_smps_entry = 114, | ||
422 | .dynamic_smps_exit = 110, | ||
423 | .tx_protection_entry = 114, | ||
424 | .tx_protection_exit = 108, | ||
425 | .tx_backoff = { | ||
426 | {.temperature = 112, .backoff = 200}, | ||
427 | {.temperature = 113, .backoff = 600}, | ||
428 | {.temperature = 114, .backoff = 1200}, | ||
429 | {.temperature = 115, .backoff = 2000}, | ||
430 | {.temperature = 116, .backoff = 4000}, | ||
431 | {.temperature = 117, .backoff = 10000}, | ||
432 | }, | ||
433 | .support_ct_kill = true, | ||
434 | .support_dynamic_smps = true, | ||
435 | .support_tx_protection = true, | ||
436 | .support_tx_backoff = true, | ||
437 | }; | ||
438 | |||
439 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff) | ||
440 | { | ||
441 | struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; | ||
442 | |||
443 | IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n"); | ||
444 | |||
445 | if (mvm->cfg->thermal_params) | ||
446 | tt->params = *mvm->cfg->thermal_params; | ||
447 | else | ||
448 | tt->params = iwl_mvm_default_tt_params; | ||
449 | |||
450 | tt->throttle = false; | ||
451 | tt->dynamic_smps = false; | ||
452 | tt->min_backoff = min_backoff; | ||
453 | INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); | ||
454 | } | ||
455 | |||
456 | void iwl_mvm_tt_exit(struct iwl_mvm *mvm) | ||
457 | { | ||
458 | cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit); | ||
459 | IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n"); | ||
460 | } | ||