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