1 /******************************************************************************
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.
8 * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
24 * The full GNU General Public License is included in this distribution
25 * in the file called COPYING.
27 * Contact Information:
28 * Intel Linux Wireless <ilw@linux.intel.com>
29 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
33 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
40 * * Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * * Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in
44 * the documentation and/or other materials provided with the
46 * * Neither the name Intel Corporation nor the names of its
47 * contributors may be used to endorse or promote products derived
48 * from this software without specific prior written permission.
50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
54 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
56 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
57 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
58 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
60 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62 *****************************************************************************/
65 #include "iwl-config.h"
70 #define OTP_DTS_DIODE_DEVIATION 96 /*in words*/
71 /* VBG - Voltage Band Gap error data (temperature offset) */
72 #define OTP_WP_DTS_VBG (OTP_DTS_DIODE_DEVIATION + 2)
73 #define MEAS_VBG_MIN_VAL 2300
74 #define MEAS_VBG_MAX_VAL 3000
75 #define MEAS_VBG_DEFAULT_VAL 2700
76 #define DTS_DIODE_VALID(flags) (flags & DTS_DIODE_REG_FLAGS_PASS_ONCE)
77 #define MIN_TEMPERATURE 0
78 #define MAX_TEMPERATURE 125
79 #define TEMPERATURE_ERROR (MAX_TEMPERATURE + 1)
80 #define PTAT_DIGITAL_VALUE_MIN_VALUE 0
81 #define PTAT_DIGITAL_VALUE_MAX_VALUE 0xFF
82 #define DTS_VREFS_NUM 5
83 static inline u32
DTS_DIODE_GET_VREFS_ID(u32 flags
)
85 return (flags
& DTS_DIODE_REG_FLAGS_VREFS_ID
) >>
86 DTS_DIODE_REG_FLAGS_VREFS_ID_POS
;
89 #define CALC_VREFS_MIN_DIFF 43
90 #define CALC_VREFS_MAX_DIFF 51
91 #define CALC_LUT_SIZE (1 + CALC_VREFS_MAX_DIFF - CALC_VREFS_MIN_DIFF)
92 #define CALC_LUT_INDEX_OFFSET CALC_VREFS_MIN_DIFF
93 #define CALC_TEMPERATURE_RESULT_SHIFT_OFFSET 23
96 * @digital_value: The diode's digital-value sampled (temperature/voltage)
97 * @vref_low: The lower voltage-reference (the vref just below the diode's
98 * sampled digital-value)
99 * @vref_high: The higher voltage-reference (the vref just above the diode's
100 * sampled digital-value)
101 * @flags: bits[1:0]: The ID of the Vrefs pair (lowVref,highVref)
102 * bits[6:2]: Reserved.
103 * bits[7:7]: Indicates completion of at least 1 successful sample
104 * since last DTS reset.
106 struct iwl_mvm_dts_diode_bits
{
113 union dts_diode_results
{
115 struct iwl_mvm_dts_diode_bits bits
;
118 static s16
iwl_mvm_dts_get_volt_band_gap(struct iwl_mvm
*mvm
)
120 struct iwl_nvm_section calib_sec
;
124 /* TODO: move parsing to NVM code */
125 calib_sec
= mvm
->nvm_sections
[NVM_SECTION_TYPE_CALIBRATION
];
126 calib
= (__le16
*)calib_sec
.data
;
128 vbg
= le16_to_cpu(calib
[OTP_WP_DTS_VBG
]);
130 if (vbg
< MEAS_VBG_MIN_VAL
|| vbg
> MEAS_VBG_MAX_VAL
)
131 vbg
= MEAS_VBG_DEFAULT_VAL
;
136 static u16
iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm
*mvm
)
139 u8 ptat
, pa1
, pa2
, median
;
141 /* TODO: move parsing to NVM code */
142 calib
= mvm
->nvm_sections
[NVM_SECTION_TYPE_CALIBRATION
].data
;
143 ptat
= calib
[OTP_DTS_DIODE_DEVIATION
];
144 pa1
= calib
[OTP_DTS_DIODE_DEVIATION
+ 1];
145 pa2
= calib
[OTP_DTS_DIODE_DEVIATION
+ 2];
147 /* get the median: */
150 median
= (pa1
> pa2
) ? pa1
: pa2
;
155 median
= (ptat
> pa2
) ? ptat
: pa2
;
160 return ptat
- median
;
163 static u8
iwl_mvm_dts_calibrate_ptat_deviation(struct iwl_mvm
*mvm
, u8 value
)
165 /* Calibrate the PTAT digital value, based on PTAT deviation data: */
166 s16 new_val
= value
- iwl_mvm_dts_get_ptat_deviation_offset(mvm
);
168 if (new_val
> PTAT_DIGITAL_VALUE_MAX_VALUE
)
169 new_val
= PTAT_DIGITAL_VALUE_MAX_VALUE
;
170 else if (new_val
< PTAT_DIGITAL_VALUE_MIN_VALUE
)
171 new_val
= PTAT_DIGITAL_VALUE_MIN_VALUE
;
176 static bool dts_get_adjacent_vrefs(struct iwl_mvm
*mvm
,
177 union dts_diode_results
*avg_ptat
)
179 u8 vrefs_results
[DTS_VREFS_NUM
];
180 u8 low_vref_index
= 0, flags
;
183 reg
= iwl_read_prph(mvm
->trans
, DTSC_VREF_AVG
);
184 memcpy(vrefs_results
, ®
, sizeof(reg
));
185 reg
= iwl_read_prph(mvm
->trans
, DTSC_VREF5_AVG
);
186 vrefs_results
[4] = reg
& 0xff;
188 if (avg_ptat
->bits
.digital_value
< vrefs_results
[0] ||
189 avg_ptat
->bits
.digital_value
> vrefs_results
[4])
192 if (avg_ptat
->bits
.digital_value
> vrefs_results
[3])
194 else if (avg_ptat
->bits
.digital_value
> vrefs_results
[2])
196 else if (avg_ptat
->bits
.digital_value
> vrefs_results
[1])
199 avg_ptat
->bits
.vref_low
= vrefs_results
[low_vref_index
];
200 avg_ptat
->bits
.vref_high
= vrefs_results
[low_vref_index
+ 1];
201 flags
= avg_ptat
->bits
.flags
;
202 avg_ptat
->bits
.flags
=
203 (flags
& ~DTS_DIODE_REG_FLAGS_VREFS_ID
) |
204 (low_vref_index
& DTS_DIODE_REG_FLAGS_VREFS_ID
);
209 * return true it the results are valid, and false otherwise.
211 static bool dts_read_ptat_avg_results(struct iwl_mvm
*mvm
,
212 union dts_diode_results
*avg_ptat
)
217 /* fill the diode value and pass_once with avg-reg results */
218 reg
= iwl_read_prph(mvm
->trans
, DTSC_PTAT_AVG
);
219 reg
&= DTS_DIODE_REG_DIG_VAL
| DTS_DIODE_REG_PASS_ONCE
;
220 avg_ptat
->reg_value
= reg
;
222 /* calibrate the PTAT digital value */
223 tmp
= avg_ptat
->bits
.digital_value
;
224 tmp
= iwl_mvm_dts_calibrate_ptat_deviation(mvm
, tmp
);
225 avg_ptat
->bits
.digital_value
= tmp
;
228 * fill vrefs fields, based on the avgVrefs results
229 * and the diode value
231 return dts_get_adjacent_vrefs(mvm
, avg_ptat
) &&
232 DTS_DIODE_VALID(avg_ptat
->bits
.flags
);
235 static s32
calculate_nic_temperature(union dts_diode_results avg_ptat
,
241 * For temperature calculation (at the end, shift right by 23)
242 * LUT[(D2-D1)] = ROUND{ 2^23 / ((D2-D1)*9*10) }
243 * (D2-D1) == 43 44 45 46 47 48 49 50 51
245 static const u16 calc_lut
[CALC_LUT_SIZE
] = {
246 2168, 2118, 2071, 2026, 1983, 1942, 1902, 1864, 1828,
250 * The diff between the high and low voltage-references is assumed
251 * to be strictly be in range of [60,68]
253 vrefs_diff
= avg_ptat
.bits
.vref_high
- avg_ptat
.bits
.vref_low
;
255 if (vrefs_diff
< CALC_VREFS_MIN_DIFF
||
256 vrefs_diff
> CALC_VREFS_MAX_DIFF
)
257 return TEMPERATURE_ERROR
;
259 /* calculate the result: */
261 vrefs_diff
* (DTS_DIODE_GET_VREFS_ID(avg_ptat
.bits
.flags
) + 9);
262 tmp_result
+= avg_ptat
.bits
.digital_value
;
263 tmp_result
-= avg_ptat
.bits
.vref_high
;
265 /* multiply by the LUT value (based on the diff) */
266 tmp_result
*= calc_lut
[vrefs_diff
- CALC_LUT_INDEX_OFFSET
];
269 * Get the BandGap (the voltage refereces source) error data
270 * (temperature offset)
272 tmp_result
*= volt_band_gap
;
275 * here, tmp_result value can be up to 32-bits. We want to right-shift
276 * it *without* sign-extend.
278 tmp_result
= tmp_result
>> CALC_TEMPERATURE_RESULT_SHIFT_OFFSET
;
281 * at this point, tmp_result should be in the range:
282 * 200 <= tmp_result <= 365
284 return (s16
)tmp_result
- 240;
287 static s32
check_nic_temperature(struct iwl_mvm
*mvm
)
290 union dts_diode_results avg_ptat
;
292 volt_band_gap
= iwl_mvm_dts_get_volt_band_gap(mvm
);
295 iwl_write_prph(mvm
->trans
, SHR_MISC_WFM_DTS_EN
, 0);
297 /* SV initialization */
298 iwl_write_prph(mvm
->trans
, SHR_MISC_WFM_DTS_EN
, 1);
299 iwl_write_prph(mvm
->trans
, DTSC_CFG_MODE
,
300 DTSC_CFG_MODE_PERIODIC
);
302 /* wait for results */
304 if (!dts_read_ptat_avg_results(mvm
, &avg_ptat
))
305 return TEMPERATURE_ERROR
;
308 iwl_write_prph(mvm
->trans
, SHR_MISC_WFM_DTS_EN
, 0);
310 return calculate_nic_temperature(avg_ptat
, volt_band_gap
);
313 static void iwl_mvm_enter_ctkill(struct iwl_mvm
*mvm
)
315 u32 duration
= mvm
->thermal_throttle
.params
->ct_kill_duration
;
317 IWL_ERR(mvm
, "Enter CT Kill\n");
318 iwl_mvm_set_hw_ctkill_state(mvm
, true);
319 schedule_delayed_work(&mvm
->thermal_throttle
.ct_kill_exit
,
320 round_jiffies_relative(duration
* HZ
));
323 static void iwl_mvm_exit_ctkill(struct iwl_mvm
*mvm
)
325 IWL_ERR(mvm
, "Exit CT Kill\n");
326 iwl_mvm_set_hw_ctkill_state(mvm
, false);
329 static void check_exit_ctkill(struct work_struct
*work
)
331 struct iwl_mvm_tt_mgmt
*tt
;
336 tt
= container_of(work
, struct iwl_mvm_tt_mgmt
, ct_kill_exit
.work
);
337 mvm
= container_of(tt
, struct iwl_mvm
, thermal_throttle
);
339 duration
= tt
->params
->ct_kill_duration
;
341 iwl_trans_start_hw(mvm
->trans
);
342 temp
= check_nic_temperature(mvm
);
343 iwl_trans_stop_device(mvm
->trans
);
345 if (temp
< MIN_TEMPERATURE
|| temp
> MAX_TEMPERATURE
) {
346 IWL_DEBUG_TEMP(mvm
, "Failed to measure NIC temperature\n");
349 IWL_DEBUG_TEMP(mvm
, "NIC temperature: %d\n", temp
);
351 if (temp
<= tt
->params
->ct_kill_exit
) {
352 iwl_mvm_exit_ctkill(mvm
);
357 schedule_delayed_work(&mvm
->thermal_throttle
.ct_kill_exit
,
358 round_jiffies(duration
* HZ
));
361 static void iwl_mvm_tt_smps_iterator(void *_data
, u8
*mac
,
362 struct ieee80211_vif
*vif
)
364 struct iwl_mvm
*mvm
= _data
;
365 enum ieee80211_smps_mode smps_mode
;
367 lockdep_assert_held(&mvm
->mutex
);
369 if (mvm
->thermal_throttle
.dynamic_smps
)
370 smps_mode
= IEEE80211_SMPS_DYNAMIC
;
372 smps_mode
= IEEE80211_SMPS_AUTOMATIC
;
374 if (vif
->type
!= NL80211_IFTYPE_STATION
)
377 iwl_mvm_update_smps(mvm
, vif
, IWL_MVM_SMPS_REQ_TT
, smps_mode
);
380 static void iwl_mvm_tt_tx_protection(struct iwl_mvm
*mvm
, bool enable
)
382 struct ieee80211_sta
*sta
;
383 struct iwl_mvm_sta
*mvmsta
;
386 for (i
= 0; i
< IWL_MVM_STATION_COUNT
; i
++) {
387 sta
= rcu_dereference_protected(mvm
->fw_id_to_mac_id
[i
],
388 lockdep_is_held(&mvm
->mutex
));
389 if (IS_ERR_OR_NULL(sta
))
391 mvmsta
= iwl_mvm_sta_from_mac80211(sta
);
392 if (enable
== mvmsta
->tt_tx_protection
)
394 err
= iwl_mvm_tx_protection(mvm
, mvmsta
, enable
);
396 IWL_ERR(mvm
, "Failed to %s Tx protection\n",
397 enable
? "enable" : "disable");
399 IWL_DEBUG_TEMP(mvm
, "%s Tx protection\n",
400 enable
? "Enable" : "Disable");
401 mvmsta
->tt_tx_protection
= enable
;
406 static void iwl_mvm_tt_tx_backoff(struct iwl_mvm
*mvm
, u32 backoff
)
408 struct iwl_host_cmd cmd
= {
409 .id
= REPLY_THERMAL_MNG_BACKOFF
,
410 .len
= { sizeof(u32
), },
411 .data
= { &backoff
, },
415 if (iwl_mvm_send_cmd(mvm
, &cmd
) == 0) {
416 IWL_DEBUG_TEMP(mvm
, "Set Thermal Tx backoff to: %u\n",
418 mvm
->thermal_throttle
.tx_backoff
= backoff
;
420 IWL_ERR(mvm
, "Failed to change Thermal Tx backoff\n");
424 void iwl_mvm_tt_handler(struct iwl_mvm
*mvm
)
426 const struct iwl_tt_params
*params
= mvm
->thermal_throttle
.params
;
427 struct iwl_mvm_tt_mgmt
*tt
= &mvm
->thermal_throttle
;
428 s32 temperature
= mvm
->temperature
;
429 bool throttle_enable
= false;
433 IWL_DEBUG_TEMP(mvm
, "NIC temperature: %d\n", mvm
->temperature
);
435 if (params
->support_ct_kill
&& temperature
>= params
->ct_kill_entry
) {
436 iwl_mvm_enter_ctkill(mvm
);
440 if (params
->support_dynamic_smps
) {
441 if (!tt
->dynamic_smps
&&
442 temperature
>= params
->dynamic_smps_entry
) {
443 IWL_DEBUG_TEMP(mvm
, "Enable dynamic SMPS\n");
444 tt
->dynamic_smps
= true;
445 ieee80211_iterate_active_interfaces_atomic(
446 mvm
->hw
, IEEE80211_IFACE_ITER_NORMAL
,
447 iwl_mvm_tt_smps_iterator
, mvm
);
448 throttle_enable
= true;
449 } else if (tt
->dynamic_smps
&&
450 temperature
<= params
->dynamic_smps_exit
) {
451 IWL_DEBUG_TEMP(mvm
, "Disable dynamic SMPS\n");
452 tt
->dynamic_smps
= false;
453 ieee80211_iterate_active_interfaces_atomic(
454 mvm
->hw
, IEEE80211_IFACE_ITER_NORMAL
,
455 iwl_mvm_tt_smps_iterator
, mvm
);
459 if (params
->support_tx_protection
) {
460 if (temperature
>= params
->tx_protection_entry
) {
461 iwl_mvm_tt_tx_protection(mvm
, true);
462 throttle_enable
= true;
463 } else if (temperature
<= params
->tx_protection_exit
) {
464 iwl_mvm_tt_tx_protection(mvm
, false);
468 if (params
->support_tx_backoff
) {
470 for (i
= 0; i
< TT_TX_BACKOFF_SIZE
; i
++) {
471 if (temperature
< params
->tx_backoff
[i
].temperature
)
473 tx_backoff
= params
->tx_backoff
[i
].backoff
;
476 throttle_enable
= true;
477 if (tt
->tx_backoff
!= tx_backoff
)
478 iwl_mvm_tt_tx_backoff(mvm
, tx_backoff
);
481 if (!tt
->throttle
&& throttle_enable
) {
483 "Due to high temperature thermal throttling initiated\n");
485 } else if (tt
->throttle
&& !tt
->dynamic_smps
&& tt
->tx_backoff
== 0 &&
486 temperature
<= params
->tx_protection_exit
) {
488 "Temperature is back to normal thermal throttling stopped\n");
489 tt
->throttle
= false;
493 static const struct iwl_tt_params iwl7000_tt_params
= {
494 .ct_kill_entry
= 118,
496 .ct_kill_duration
= 5,
497 .dynamic_smps_entry
= 114,
498 .dynamic_smps_exit
= 110,
499 .tx_protection_entry
= 114,
500 .tx_protection_exit
= 108,
502 {.temperature
= 112, .backoff
= 200},
503 {.temperature
= 113, .backoff
= 600},
504 {.temperature
= 114, .backoff
= 1200},
505 {.temperature
= 115, .backoff
= 2000},
506 {.temperature
= 116, .backoff
= 4000},
507 {.temperature
= 117, .backoff
= 10000},
509 .support_ct_kill
= true,
510 .support_dynamic_smps
= true,
511 .support_tx_protection
= true,
512 .support_tx_backoff
= true,
515 static const struct iwl_tt_params iwl7000_high_temp_tt_params
= {
516 .ct_kill_entry
= 118,
518 .ct_kill_duration
= 5,
519 .dynamic_smps_entry
= 114,
520 .dynamic_smps_exit
= 110,
521 .tx_protection_entry
= 114,
522 .tx_protection_exit
= 108,
524 {.temperature
= 112, .backoff
= 300},
525 {.temperature
= 113, .backoff
= 800},
526 {.temperature
= 114, .backoff
= 1500},
527 {.temperature
= 115, .backoff
= 3000},
528 {.temperature
= 116, .backoff
= 5000},
529 {.temperature
= 117, .backoff
= 10000},
531 .support_ct_kill
= true,
532 .support_dynamic_smps
= true,
533 .support_tx_protection
= true,
534 .support_tx_backoff
= true,
537 void iwl_mvm_tt_initialize(struct iwl_mvm
*mvm
)
539 struct iwl_mvm_tt_mgmt
*tt
= &mvm
->thermal_throttle
;
541 IWL_DEBUG_TEMP(mvm
, "Initialize Thermal Throttling\n");
543 if (mvm
->cfg
->high_temp
)
544 tt
->params
= &iwl7000_high_temp_tt_params
;
546 tt
->params
= &iwl7000_tt_params
;
548 tt
->throttle
= false;
549 INIT_DELAYED_WORK(&tt
->ct_kill_exit
, check_exit_ctkill
);
552 void iwl_mvm_tt_exit(struct iwl_mvm
*mvm
)
554 cancel_delayed_work_sync(&mvm
->thermal_throttle
.ct_kill_exit
);
555 IWL_DEBUG_TEMP(mvm
, "Exit Thermal Throttling\n");