Commit | Line | Data |
---|---|---|
9ee718aa EL |
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 Intel Corporation. All rights reserved. | |
9 | * | |
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. | |
13 | * | |
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. | |
18 | * | |
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, | |
22 | * USA | |
23 | * | |
24 | * The full GNU General Public License is included in this distribution | |
25 | * in the file called COPYING. | |
26 | * | |
27 | * Contact Information: | |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | |
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | |
30 | * | |
31 | * BSD LICENSE | |
32 | * | |
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | |
34 | * All rights reserved. | |
35 | * | |
36 | * Redistribution and use in source and binary forms, with or without | |
37 | * modification, are permitted provided that the following conditions | |
38 | * are met: | |
39 | * | |
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 | |
45 | * distribution. | |
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. | |
49 | * | |
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. | |
61 | * | |
62 | *****************************************************************************/ | |
63 | ||
64 | #include "mvm.h" | |
65 | #include "iwl-config.h" | |
66 | #include "iwl-io.h" | |
67 | #include "iwl-csr.h" | |
68 | #include "iwl-prph.h" | |
69 | ||
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) | |
84 | { | |
85 | return (flags & DTS_DIODE_REG_FLAGS_VREFS_ID) >> | |
86 | DTS_DIODE_REG_FLAGS_VREFS_ID_POS; | |
87 | } | |
88 | ||
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 | |
94 | ||
95 | /* | |
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. | |
105 | */ | |
106 | struct iwl_mvm_dts_diode_bits { | |
107 | u8 digital_value; | |
108 | u8 vref_low; | |
109 | u8 vref_high; | |
110 | u8 flags; | |
111 | } __packed; | |
112 | ||
113 | union dts_diode_results { | |
114 | u32 reg_value; | |
115 | struct iwl_mvm_dts_diode_bits bits; | |
116 | } __packed; | |
117 | ||
118 | static s16 iwl_mvm_dts_get_volt_band_gap(struct iwl_mvm *mvm) | |
119 | { | |
120 | struct iwl_nvm_section calib_sec; | |
121 | const __le16 *calib; | |
122 | u16 vbg; | |
123 | ||
124 | /* TODO: move parsing to NVM code */ | |
125 | calib_sec = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION]; | |
126 | calib = (__le16 *)calib_sec.data; | |
127 | ||
128 | vbg = le16_to_cpu(calib[OTP_WP_DTS_VBG]); | |
129 | ||
130 | if (vbg < MEAS_VBG_MIN_VAL || vbg > MEAS_VBG_MAX_VAL) | |
131 | vbg = MEAS_VBG_DEFAULT_VAL; | |
132 | ||
133 | return vbg; | |
134 | } | |
135 | ||
136 | static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm) | |
137 | { | |
138 | const u8 *calib; | |
139 | u8 ptat, pa1, pa2, median; | |
140 | ||
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]; | |
146 | ||
147 | /* get the median: */ | |
148 | if (ptat > pa1) { | |
149 | if (ptat > pa2) | |
150 | median = (pa1 > pa2) ? pa1 : pa2; | |
151 | else | |
152 | median = ptat; | |
153 | } else { | |
154 | if (pa1 > pa2) | |
155 | median = (ptat > pa2) ? ptat : pa2; | |
156 | else | |
157 | median = pa1; | |
158 | } | |
159 | ||
160 | return ptat - median; | |
161 | } | |
162 | ||
163 | static u8 iwl_mvm_dts_calibrate_ptat_deviation(struct iwl_mvm *mvm, u8 value) | |
164 | { | |
165 | /* Calibrate the PTAT digital value, based on PTAT deviation data: */ | |
166 | s16 new_val = value - iwl_mvm_dts_get_ptat_deviation_offset(mvm); | |
167 | ||
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; | |
172 | ||
173 | return new_val; | |
174 | } | |
175 | ||
176 | static bool dts_get_adjacent_vrefs(struct iwl_mvm *mvm, | |
177 | union dts_diode_results *avg_ptat) | |
178 | { | |
179 | u8 vrefs_results[DTS_VREFS_NUM]; | |
180 | u8 low_vref_index = 0, flags; | |
181 | u32 reg; | |
182 | ||
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; | |
187 | ||
188 | if (avg_ptat->bits.digital_value < vrefs_results[0] || | |
189 | avg_ptat->bits.digital_value > vrefs_results[4]) | |
190 | return false; | |
191 | ||
192 | if (avg_ptat->bits.digital_value > vrefs_results[3]) | |
193 | low_vref_index = 3; | |
194 | else if (avg_ptat->bits.digital_value > vrefs_results[2]) | |
195 | low_vref_index = 2; | |
196 | else if (avg_ptat->bits.digital_value > vrefs_results[1]) | |
197 | low_vref_index = 1; | |
198 | ||
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); | |
205 | return true; | |
206 | } | |
207 | ||
208 | /* | |
209 | * return true it the results are valid, and false otherwise. | |
210 | */ | |
211 | static bool dts_read_ptat_avg_results(struct iwl_mvm *mvm, | |
212 | union dts_diode_results *avg_ptat) | |
213 | { | |
214 | u32 reg; | |
215 | u8 tmp; | |
216 | ||
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; | |
221 | ||
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; | |
226 | ||
227 | /* | |
228 | * fill vrefs fields, based on the avgVrefs results | |
229 | * and the diode value | |
230 | */ | |
231 | return dts_get_adjacent_vrefs(mvm, avg_ptat) && | |
232 | DTS_DIODE_VALID(avg_ptat->bits.flags); | |
233 | } | |
234 | ||
235 | static s32 calculate_nic_temperature(union dts_diode_results avg_ptat, | |
236 | u16 volt_band_gap) | |
237 | { | |
238 | u32 tmp_result; | |
239 | u8 vrefs_diff; | |
240 | /* | |
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 | |
244 | */ | |
245 | static const u16 calc_lut[CALC_LUT_SIZE] = { | |
246 | 2168, 2118, 2071, 2026, 1983, 1942, 1902, 1864, 1828, | |
247 | }; | |
248 | ||
249 | /* | |
250 | * The diff between the high and low voltage-references is assumed | |
251 | * to be strictly be in range of [60,68] | |
252 | */ | |
253 | vrefs_diff = avg_ptat.bits.vref_high - avg_ptat.bits.vref_low; | |
254 | ||
255 | if (vrefs_diff < CALC_VREFS_MIN_DIFF || | |
256 | vrefs_diff > CALC_VREFS_MAX_DIFF) | |
257 | return TEMPERATURE_ERROR; | |
258 | ||
259 | /* calculate the result: */ | |
260 | tmp_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; | |
264 | ||
265 | /* multiply by the LUT value (based on the diff) */ | |
266 | tmp_result *= calc_lut[vrefs_diff - CALC_LUT_INDEX_OFFSET]; | |
267 | ||
268 | /* | |
269 | * Get the BandGap (the voltage refereces source) error data | |
270 | * (temperature offset) | |
271 | */ | |
272 | tmp_result *= volt_band_gap; | |
273 | ||
274 | /* | |
275 | * here, tmp_result value can be up to 32-bits. We want to right-shift | |
276 | * it *without* sign-extend. | |
277 | */ | |
278 | tmp_result = tmp_result >> CALC_TEMPERATURE_RESULT_SHIFT_OFFSET; | |
279 | ||
280 | /* | |
281 | * at this point, tmp_result should be in the range: | |
282 | * 200 <= tmp_result <= 365 | |
283 | */ | |
284 | return (s16)tmp_result - 240; | |
285 | } | |
286 | ||
287 | static s32 check_nic_temperature(struct iwl_mvm *mvm) | |
288 | { | |
289 | u16 volt_band_gap; | |
290 | union dts_diode_results avg_ptat; | |
291 | ||
292 | volt_band_gap = iwl_mvm_dts_get_volt_band_gap(mvm); | |
293 | ||
294 | /* disable DTS */ | |
295 | iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0); | |
296 | ||
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); | |
301 | ||
302 | /* wait for results */ | |
303 | msleep(100); | |
304 | if (!dts_read_ptat_avg_results(mvm, &avg_ptat)) | |
305 | return TEMPERATURE_ERROR; | |
306 | ||
307 | /* disable DTS */ | |
308 | iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0); | |
309 | ||
310 | return calculate_nic_temperature(avg_ptat, volt_band_gap); | |
311 | } | |
312 | ||
313 | static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) | |
314 | { | |
315 | u32 duration = mvm->thermal_throttle.params->ct_kill_duration; | |
316 | ||
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)); | |
321 | } | |
322 | ||
323 | static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) | |
324 | { | |
325 | IWL_ERR(mvm, "Exit CT Kill\n"); | |
326 | iwl_mvm_set_hw_ctkill_state(mvm, false); | |
327 | } | |
328 | ||
329 | static void check_exit_ctkill(struct work_struct *work) | |
330 | { | |
331 | struct iwl_mvm_tt_mgmt *tt; | |
332 | struct iwl_mvm *mvm; | |
333 | u32 duration; | |
334 | s32 temp; | |
335 | ||
336 | tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work); | |
337 | mvm = container_of(tt, struct iwl_mvm, thermal_throttle); | |
338 | ||
339 | duration = tt->params->ct_kill_duration; | |
340 | ||
341 | iwl_trans_start_hw(mvm->trans); | |
342 | temp = check_nic_temperature(mvm); | |
343 | iwl_trans_stop_hw(mvm->trans, false); | |
344 | ||
345 | if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { | |
346 | IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n"); | |
347 | goto reschedule; | |
348 | } | |
349 | IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp); | |
350 | ||
351 | if (temp <= tt->params->ct_kill_exit) { | |
352 | iwl_mvm_exit_ctkill(mvm); | |
353 | return; | |
354 | } | |
355 | ||
356 | reschedule: | |
357 | schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, | |
358 | round_jiffies(duration * HZ)); | |
359 | } | |
360 | ||
361 | static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac, | |
362 | struct ieee80211_vif *vif) | |
363 | { | |
364 | struct iwl_mvm *mvm = _data; | |
365 | enum ieee80211_smps_mode smps_mode; | |
366 | ||
367 | lockdep_assert_held(&mvm->mutex); | |
368 | ||
369 | if (mvm->thermal_throttle.dynamic_smps) | |
370 | smps_mode = IEEE80211_SMPS_DYNAMIC; | |
371 | else | |
372 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | |
373 | ||
374 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode); | |
375 | } | |
376 | ||
377 | static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable) | |
378 | { | |
379 | struct ieee80211_sta *sta; | |
380 | struct iwl_mvm_sta *mvmsta; | |
381 | int i, err; | |
382 | ||
383 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | |
384 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | |
385 | lockdep_is_held(&mvm->mutex)); | |
386 | if (IS_ERR_OR_NULL(sta)) | |
387 | continue; | |
388 | mvmsta = (void *)sta->drv_priv; | |
389 | if (enable == mvmsta->tt_tx_protection) | |
390 | continue; | |
391 | err = iwl_mvm_tx_protection(mvm, &mvmsta->lq_sta.lq, | |
392 | mvmsta, enable); | |
393 | if (err) { | |
394 | IWL_ERR(mvm, "Failed to %s Tx protection\n", | |
395 | enable ? "enable" : "disable"); | |
396 | } else { | |
397 | IWL_DEBUG_TEMP(mvm, "%s Tx protection\n", | |
398 | enable ? "Enable" : "Disable"); | |
399 | mvmsta->tt_tx_protection = enable; | |
400 | } | |
401 | } | |
402 | } | |
403 | ||
404 | static void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff) | |
405 | { | |
406 | struct iwl_host_cmd cmd = { | |
407 | .id = REPLY_THERMAL_MNG_BACKOFF, | |
408 | .len = { sizeof(u32), }, | |
409 | .data = { &backoff, }, | |
410 | .flags = CMD_SYNC, | |
411 | }; | |
412 | ||
413 | if (iwl_mvm_send_cmd(mvm, &cmd) == 0) { | |
414 | IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n", | |
415 | backoff); | |
416 | mvm->thermal_throttle.tx_backoff = backoff; | |
417 | } else { | |
418 | IWL_ERR(mvm, "Failed to change Thermal Tx backoff\n"); | |
419 | } | |
420 | } | |
421 | ||
422 | void iwl_mvm_tt_handler(struct iwl_mvm *mvm) | |
423 | { | |
424 | const struct iwl_tt_params *params = mvm->thermal_throttle.params; | |
425 | struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; | |
426 | s32 temperature = mvm->temperature; | |
427 | int i; | |
428 | u32 tx_backoff; | |
429 | ||
430 | IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", mvm->temperature); | |
431 | ||
432 | if (params->support_ct_kill && temperature >= params->ct_kill_entry) { | |
433 | iwl_mvm_enter_ctkill(mvm); | |
434 | return; | |
435 | } | |
436 | ||
437 | if (params->support_dynamic_smps) { | |
438 | if (!tt->dynamic_smps && | |
439 | temperature >= params->dynamic_smps_entry) { | |
440 | IWL_DEBUG_TEMP(mvm, "Enable dynamic SMPS\n"); | |
441 | tt->dynamic_smps = true; | |
442 | ieee80211_iterate_active_interfaces_atomic( | |
443 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | |
444 | iwl_mvm_tt_smps_iterator, mvm); | |
445 | } else if (tt->dynamic_smps && | |
446 | temperature <= params->dynamic_smps_exit) { | |
447 | IWL_DEBUG_TEMP(mvm, "Disable dynamic SMPS\n"); | |
448 | tt->dynamic_smps = false; | |
449 | ieee80211_iterate_active_interfaces_atomic( | |
450 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | |
451 | iwl_mvm_tt_smps_iterator, mvm); | |
452 | } | |
453 | } | |
454 | ||
455 | if (params->support_tx_protection) { | |
456 | if (temperature >= params->tx_protection_entry) | |
457 | iwl_mvm_tt_tx_protection(mvm, true); | |
458 | else if (temperature <= params->tx_protection_exit) | |
459 | iwl_mvm_tt_tx_protection(mvm, false); | |
460 | } | |
461 | ||
462 | if (params->support_tx_backoff) { | |
463 | tx_backoff = 0; | |
464 | for (i = 0; i < TT_TX_BACKOFF_SIZE; i++) { | |
465 | if (temperature < params->tx_backoff[i].temperature) | |
466 | break; | |
467 | tx_backoff = params->tx_backoff[i].backoff; | |
468 | } | |
469 | if (tt->tx_backoff != tx_backoff) | |
470 | iwl_mvm_tt_tx_backoff(mvm, tx_backoff); | |
471 | } | |
472 | } | |
473 | ||
474 | static const struct iwl_tt_params iwl7000_tt_params = { | |
475 | .ct_kill_entry = 118, | |
476 | .ct_kill_exit = 96, | |
477 | .ct_kill_duration = 5, | |
478 | .dynamic_smps_entry = 114, | |
479 | .dynamic_smps_exit = 110, | |
480 | .tx_protection_entry = 114, | |
481 | .tx_protection_exit = 108, | |
482 | .tx_backoff = { | |
483 | {.temperature = 112, .backoff = 200}, | |
484 | {.temperature = 113, .backoff = 600}, | |
485 | {.temperature = 114, .backoff = 1200}, | |
486 | {.temperature = 115, .backoff = 2000}, | |
487 | {.temperature = 116, .backoff = 4000}, | |
488 | {.temperature = 117, .backoff = 10000}, | |
489 | }, | |
490 | .support_ct_kill = true, | |
491 | .support_dynamic_smps = true, | |
492 | .support_tx_protection = true, | |
493 | .support_tx_backoff = true, | |
494 | }; | |
495 | ||
496 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm) | |
497 | { | |
498 | struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; | |
499 | ||
500 | IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n"); | |
501 | tt->params = &iwl7000_tt_params; | |
502 | INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); | |
503 | } | |
504 | ||
505 | void iwl_mvm_tt_exit(struct iwl_mvm *mvm) | |
506 | { | |
507 | cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit); | |
508 | IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n"); | |
509 | } |