Commit | Line | Data |
---|---|---|
5da4b55f MA |
1 | /****************************************************************************** |
2 | * | |
01f8162a | 3 | * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. |
5da4b55f MA |
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: | |
759ef89f | 25 | * Intel Linux Wireless <ilw@linux.intel.com> |
5da4b55f MA |
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> | |
5da4b55f MA |
32 | #include <linux/init.h> |
33 | ||
34 | #include <net/mac80211.h> | |
35 | ||
36 | #include "iwl-eeprom.h" | |
3e0d4cb1 | 37 | #include "iwl-dev.h" |
5da4b55f | 38 | #include "iwl-core.h" |
39b73fb1 | 39 | #include "iwl-io.h" |
5a36ba0e | 40 | #include "iwl-commands.h" |
5da4b55f MA |
41 | #include "iwl-debug.h" |
42 | #include "iwl-power.h" | |
5da4b55f MA |
43 | |
44 | /* | |
7af2c460 | 45 | * Setting power level allow the card to go to sleep when not busy. |
5da4b55f | 46 | * |
7af2c460 JB |
47 | * The power level is set to INDEX_1 (the least deep state) by |
48 | * default, and will, in the future, be the deepest state unless | |
49 | * otherwise required by pm_qos network latency requirements. | |
5da4b55f | 50 | * |
7af2c460 JB |
51 | * Using INDEX_1 without pm_qos is ok because mac80211 will disable |
52 | * PS when even checking every beacon for the TIM bit would exceed | |
53 | * the required latency. | |
5da4b55f MA |
54 | */ |
55 | ||
5da4b55f MA |
56 | #define IWL_POWER_RANGE_0_MAX (2) |
57 | #define IWL_POWER_RANGE_1_MAX (10) | |
58 | ||
59 | ||
7af2c460 JB |
60 | #define NOSLP cpu_to_le16(0), 0, 0 |
61 | #define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 | |
62 | #define TU_TO_USEC 1024 | |
63 | #define SLP_TOUT(T) cpu_to_le32((T) * TU_TO_USEC) | |
64 | #define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \ | |
65 | cpu_to_le32(X1), \ | |
66 | cpu_to_le32(X2), \ | |
67 | cpu_to_le32(X3), \ | |
68 | cpu_to_le32(X4)} | |
5da4b55f | 69 | /* default power management (not Tx power) table values */ |
7af2c460 JB |
70 | /* for DTIM period 0 through IWL_POWER_RANGE_0_MAX */ |
71 | static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { | |
5da4b55f MA |
72 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, |
73 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, | |
74 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, | |
75 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, | |
76 | {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1}, | |
77 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 2, 4, 6, 0xFF)}, 2} | |
78 | }; | |
79 | ||
80 | ||
7af2c460 JB |
81 | /* for DTIM period IWL_POWER_RANGE_0_MAX + 1 through IWL_POWER_RANGE_1_MAX */ |
82 | static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { | |
5da4b55f MA |
83 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, |
84 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, | |
85 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, | |
86 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, | |
87 | {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1}, | |
88 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} | |
89 | }; | |
90 | ||
7af2c460 JB |
91 | /* for DTIM period > IWL_POWER_RANGE_1_MAX */ |
92 | static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { | |
5da4b55f MA |
93 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, |
94 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, | |
95 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, | |
96 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, | |
97 | {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, | |
98 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} | |
99 | }; | |
100 | ||
46f9381a WYG |
101 | /* default Thermal Throttling transaction table |
102 | * Current state | Throttling Down | Throttling Up | |
103 | *============================================================================= | |
104 | * Condition Nxt State Condition Nxt State Condition Nxt State | |
105 | *----------------------------------------------------------------------------- | |
106 | * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A | |
107 | * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 | |
108 | * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 | |
109 | * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 | |
110 | *============================================================================= | |
111 | */ | |
112 | static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = { | |
113 | {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104}, | |
114 | {IWL_TI_1, 105, CT_KILL_THRESHOLD}, | |
115 | {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} | |
116 | }; | |
117 | static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = { | |
118 | {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95}, | |
119 | {IWL_TI_2, 110, CT_KILL_THRESHOLD}, | |
120 | {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} | |
121 | }; | |
122 | static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = { | |
123 | {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100}, | |
124 | {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}, | |
125 | {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} | |
126 | }; | |
127 | static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = { | |
128 | {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD}, | |
129 | {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}, | |
130 | {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX} | |
131 | }; | |
132 | ||
133 | /* Advance Thermal Throttling default restriction table */ | |
134 | static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = { | |
3ad3b92a JB |
135 | {IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true }, |
136 | {IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true }, | |
137 | {IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false }, | |
138 | {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false } | |
46f9381a | 139 | }; |
d25aabb0 | 140 | |
ca579617 MA |
141 | /* set card power command */ |
142 | static int iwl_set_power(struct iwl_priv *priv, void *cmd) | |
143 | { | |
f0f74a0e JB |
144 | return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, |
145 | sizeof(struct iwl_powertable_cmd), cmd); | |
ca579617 | 146 | } |
5da4b55f MA |
147 | |
148 | /* initialize to default */ | |
5cd19c5f | 149 | static void iwl_power_init_handle(struct iwl_priv *priv) |
5da4b55f | 150 | { |
5da4b55f | 151 | struct iwl_power_mgr *pow_data; |
7af2c460 | 152 | int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_NUM; |
e7b63581 TW |
153 | struct iwl_powertable_cmd *cmd; |
154 | int i; | |
3fdb68de | 155 | u16 lctl; |
5da4b55f | 156 | |
e1623446 | 157 | IWL_DEBUG_POWER(priv, "Initialize power \n"); |
5da4b55f | 158 | |
5cd19c5f | 159 | pow_data = &priv->power_data; |
5da4b55f MA |
160 | |
161 | memset(pow_data, 0, sizeof(*pow_data)); | |
162 | ||
163 | memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); | |
164 | memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); | |
165 | memcpy(&pow_data->pwr_range_2[0], &range_2[0], size); | |
166 | ||
3fdb68de | 167 | lctl = iwl_pcie_link_ctl(priv); |
5da4b55f | 168 | |
e1623446 | 169 | IWL_DEBUG_POWER(priv, "adjust power command flags\n"); |
5da4b55f | 170 | |
7af2c460 | 171 | for (i = 0; i < IWL_POWER_NUM; i++) { |
e7b63581 | 172 | cmd = &pow_data->pwr_range_0[i].cmd; |
5da4b55f | 173 | |
3fdb68de | 174 | if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN) |
e7b63581 TW |
175 | cmd->flags &= ~IWL_POWER_PCI_PM_MSK; |
176 | else | |
177 | cmd->flags |= IWL_POWER_PCI_PM_MSK; | |
5da4b55f | 178 | } |
5da4b55f MA |
179 | } |
180 | ||
a96a27f9 | 181 | /* adjust power command according to DTIM period and power level*/ |
5cd19c5f WT |
182 | static int iwl_update_power_cmd(struct iwl_priv *priv, |
183 | struct iwl_powertable_cmd *cmd, u16 mode) | |
5da4b55f | 184 | { |
5da4b55f | 185 | struct iwl_power_vec_entry *range; |
5da4b55f | 186 | struct iwl_power_mgr *pow_data; |
5cd19c5f WT |
187 | int i; |
188 | u32 max_sleep = 0; | |
189 | u8 period; | |
190 | bool skip; | |
5da4b55f MA |
191 | |
192 | if (mode > IWL_POWER_INDEX_5) { | |
e1623446 | 193 | IWL_DEBUG_POWER(priv, "Error invalid power mode \n"); |
5cd19c5f | 194 | return -EINVAL; |
5da4b55f | 195 | } |
5cd19c5f WT |
196 | |
197 | pow_data = &priv->power_data; | |
5da4b55f MA |
198 | |
199 | if (pow_data->dtim_period <= IWL_POWER_RANGE_0_MAX) | |
200 | range = &pow_data->pwr_range_0[0]; | |
201 | else if (pow_data->dtim_period <= IWL_POWER_RANGE_1_MAX) | |
202 | range = &pow_data->pwr_range_1[0]; | |
203 | else | |
204 | range = &pow_data->pwr_range_2[0]; | |
205 | ||
206 | period = pow_data->dtim_period; | |
ca579617 | 207 | memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); |
5da4b55f MA |
208 | |
209 | if (period == 0) { | |
210 | period = 1; | |
5cd19c5f | 211 | skip = false; |
5da4b55f | 212 | } else { |
5cd19c5f WT |
213 | skip = !!range[mode].no_dtim; |
214 | } | |
215 | ||
216 | if (skip) { | |
5da4b55f MA |
217 | __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; |
218 | max_sleep = le32_to_cpu(slp_itrvl); | |
219 | if (max_sleep == 0xFF) | |
220 | max_sleep = period * (skip + 1); | |
221 | else if (max_sleep > period) | |
222 | max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; | |
223 | cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; | |
5cd19c5f WT |
224 | } else { |
225 | max_sleep = period; | |
226 | cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; | |
5da4b55f MA |
227 | } |
228 | ||
5cd19c5f | 229 | for (i = 0; i < IWL_POWER_VEC_SIZE; i++) |
5da4b55f MA |
230 | if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) |
231 | cmd->sleep_interval[i] = cpu_to_le32(max_sleep); | |
5da4b55f | 232 | |
e1623446 TW |
233 | IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags); |
234 | IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); | |
235 | IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); | |
236 | IWL_DEBUG_POWER(priv, "Sleep interval vector = { %d , %d , %d , %d , %d }\n", | |
5da4b55f MA |
237 | le32_to_cpu(cmd->sleep_interval[0]), |
238 | le32_to_cpu(cmd->sleep_interval[1]), | |
239 | le32_to_cpu(cmd->sleep_interval[2]), | |
240 | le32_to_cpu(cmd->sleep_interval[3]), | |
241 | le32_to_cpu(cmd->sleep_interval[4])); | |
242 | ||
5cd19c5f | 243 | return 0; |
5da4b55f MA |
244 | } |
245 | ||
246 | ||
247 | /* | |
a33c2f47 | 248 | * compute the final power mode index |
5da4b55f | 249 | */ |
04816448 | 250 | int iwl_power_update_mode(struct iwl_priv *priv, bool force) |
5da4b55f MA |
251 | { |
252 | struct iwl_power_mgr *setting = &(priv->power_data); | |
253 | int ret = 0; | |
3ad3b92a | 254 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
5da4b55f | 255 | u16 uninitialized_var(final_mode); |
a71c8f62 | 256 | bool update_chains; |
5da4b55f | 257 | |
04816448 | 258 | /* Don't update the RX chain when chain noise calibration is running */ |
a71c8f62 WT |
259 | update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || |
260 | priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; | |
04816448 | 261 | |
7af2c460 | 262 | final_mode = priv->power_data.user_power_setting; |
5da4b55f | 263 | |
7af2c460 | 264 | if (setting->power_disabled) |
5da4b55f MA |
265 | final_mode = IWL_POWER_MODE_CAM; |
266 | ||
39b73fb1 WYG |
267 | if (tt->state >= IWL_TI_1) { |
268 | /* TT power setting overwrite user & system power setting */ | |
269 | final_mode = tt->tt_power_mode; | |
270 | } | |
7af2c460 | 271 | if (iwl_is_ready_rf(priv) && |
04816448 | 272 | ((setting->power_mode != final_mode) || force)) { |
ca579617 | 273 | struct iwl_powertable_cmd cmd; |
5da4b55f MA |
274 | |
275 | if (final_mode != IWL_POWER_MODE_CAM) | |
276 | set_bit(STATUS_POWER_PMI, &priv->status); | |
277 | ||
5cd19c5f | 278 | iwl_update_power_cmd(priv, &cmd, final_mode); |
5da4b55f MA |
279 | cmd.keep_alive_beacons = 0; |
280 | ||
281 | if (final_mode == IWL_POWER_INDEX_5) | |
282 | cmd.flags |= IWL_POWER_FAST_PD; | |
283 | ||
ca579617 | 284 | ret = iwl_set_power(priv, &cmd); |
3a780d25 WYG |
285 | if (!ret) { |
286 | if (final_mode == IWL_POWER_MODE_CAM) | |
287 | clear_bit(STATUS_POWER_PMI, &priv->status); | |
288 | ||
289 | if (priv->cfg->ops->lib->update_chain_flags && | |
290 | update_chains) | |
291 | priv->cfg->ops->lib->update_chain_flags(priv); | |
292 | else | |
293 | IWL_DEBUG_POWER(priv, | |
294 | "Cannot update the power, chain noise " | |
a71c8f62 WT |
295 | "calibration running: %d\n", |
296 | priv->chain_noise_data.state); | |
5da4b55f | 297 | setting->power_mode = final_mode; |
3a780d25 WYG |
298 | } else |
299 | IWL_ERR(priv, "set power fail, ret = %d", ret); | |
5da4b55f MA |
300 | } |
301 | ||
302 | return ret; | |
303 | } | |
304 | EXPORT_SYMBOL(iwl_power_update_mode); | |
305 | ||
5da4b55f MA |
306 | /* set user_power_setting */ |
307 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) | |
308 | { | |
7af2c460 | 309 | if (mode >= IWL_POWER_NUM) |
5da4b55f MA |
310 | return -EINVAL; |
311 | ||
312 | priv->power_data.user_power_setting = mode; | |
313 | ||
04816448 | 314 | return iwl_power_update_mode(priv, 0); |
5da4b55f MA |
315 | } |
316 | EXPORT_SYMBOL(iwl_power_set_user_mode); | |
317 | ||
46f9381a WYG |
318 | bool iwl_ht_enabled(struct iwl_priv *priv) |
319 | { | |
3ad3b92a | 320 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
46f9381a WYG |
321 | struct iwl_tt_restriction *restriction; |
322 | ||
3ad3b92a | 323 | if (!priv->thermal_throttle.advanced_tt) |
46f9381a WYG |
324 | return true; |
325 | restriction = tt->restriction + tt->state; | |
326 | return restriction->is_ht; | |
327 | } | |
328 | EXPORT_SYMBOL(iwl_ht_enabled); | |
329 | ||
3ad3b92a | 330 | enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv) |
46f9381a | 331 | { |
3ad3b92a | 332 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
46f9381a WYG |
333 | struct iwl_tt_restriction *restriction; |
334 | ||
3ad3b92a JB |
335 | if (!priv->thermal_throttle.advanced_tt) |
336 | return IWL_ANT_OK_MULTI; | |
46f9381a WYG |
337 | restriction = tt->restriction + tt->state; |
338 | return restriction->tx_stream; | |
339 | } | |
340 | EXPORT_SYMBOL(iwl_tx_ant_restriction); | |
341 | ||
3ad3b92a | 342 | enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv) |
46f9381a | 343 | { |
3ad3b92a | 344 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
46f9381a WYG |
345 | struct iwl_tt_restriction *restriction; |
346 | ||
3ad3b92a JB |
347 | if (!priv->thermal_throttle.advanced_tt) |
348 | return IWL_ANT_OK_MULTI; | |
46f9381a WYG |
349 | restriction = tt->restriction + tt->state; |
350 | return restriction->rx_stream; | |
351 | } | |
352 | EXPORT_SYMBOL(iwl_rx_ant_restriction); | |
353 | ||
39b73fb1 WYG |
354 | #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ |
355 | ||
356 | /* | |
357 | * toggle the bit to wake up uCode and check the temperature | |
358 | * if the temperature is below CT, uCode will stay awake and send card | |
359 | * state notification with CT_KILL bit clear to inform Thermal Throttling | |
360 | * Management to change state. Otherwise, uCode will go back to sleep | |
361 | * without doing anything, driver should continue the 5 seconds timer | |
362 | * to wake up uCode for temperature check until temperature drop below CT | |
363 | */ | |
364 | static void iwl_tt_check_exit_ct_kill(unsigned long data) | |
365 | { | |
366 | struct iwl_priv *priv = (struct iwl_priv *)data; | |
3ad3b92a | 367 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
39b73fb1 WYG |
368 | unsigned long flags; |
369 | ||
370 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | |
371 | return; | |
372 | ||
373 | if (tt->state == IWL_TI_CT_KILL) { | |
3ad3b92a | 374 | if (priv->thermal_throttle.ct_kill_toggle) { |
39b73fb1 WYG |
375 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, |
376 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); | |
3ad3b92a | 377 | priv->thermal_throttle.ct_kill_toggle = false; |
39b73fb1 WYG |
378 | } else { |
379 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, | |
380 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); | |
3ad3b92a | 381 | priv->thermal_throttle.ct_kill_toggle = true; |
39b73fb1 WYG |
382 | } |
383 | iwl_read32(priv, CSR_UCODE_DRV_GP1); | |
384 | spin_lock_irqsave(&priv->reg_lock, flags); | |
385 | if (!iwl_grab_nic_access(priv)) | |
386 | iwl_release_nic_access(priv); | |
387 | spin_unlock_irqrestore(&priv->reg_lock, flags); | |
388 | ||
389 | /* Reschedule the ct_kill timer to occur in | |
390 | * CT_KILL_EXIT_DURATION seconds to ensure we get a | |
391 | * thermal update */ | |
3ad3b92a | 392 | mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies + |
39b73fb1 WYG |
393 | CT_KILL_EXIT_DURATION * HZ); |
394 | } | |
395 | } | |
396 | ||
397 | static void iwl_perform_ct_kill_task(struct iwl_priv *priv, | |
398 | bool stop) | |
399 | { | |
400 | if (stop) { | |
401 | IWL_DEBUG_POWER(priv, "Stop all queues\n"); | |
402 | if (priv->mac80211_registered) | |
403 | ieee80211_stop_queues(priv->hw); | |
404 | IWL_DEBUG_POWER(priv, | |
405 | "Schedule 5 seconds CT_KILL Timer\n"); | |
3ad3b92a | 406 | mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies + |
39b73fb1 WYG |
407 | CT_KILL_EXIT_DURATION * HZ); |
408 | } else { | |
409 | IWL_DEBUG_POWER(priv, "Wake all queues\n"); | |
410 | if (priv->mac80211_registered) | |
411 | ieee80211_wake_queues(priv->hw); | |
412 | } | |
413 | } | |
414 | ||
415 | #define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY) | |
416 | #define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100) | |
417 | #define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90) | |
418 | ||
419 | /* | |
420 | * Legacy thermal throttling | |
421 | * 1) Avoid NIC destruction due to high temperatures | |
422 | * Chip will identify dangerously high temperatures that can | |
423 | * harm the device and will power down | |
424 | * 2) Avoid the NIC power down due to high temperature | |
425 | * Throttle early enough to lower the power consumption before | |
426 | * drastic steps are needed | |
427 | */ | |
428 | static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) | |
429 | { | |
3ad3b92a | 430 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
ee9f2989 | 431 | enum iwl_tt_state old_state; |
39b73fb1 WYG |
432 | struct iwl_power_mgr *setting = &priv->power_data; |
433 | ||
434 | #ifdef CONFIG_IWLWIFI_DEBUG | |
435 | if ((tt->tt_previous_temp) && | |
436 | (temp > tt->tt_previous_temp) && | |
437 | ((temp - tt->tt_previous_temp) > | |
438 | IWL_TT_INCREASE_MARGIN)) { | |
439 | IWL_DEBUG_POWER(priv, | |
440 | "Temperature increase %d degree Celsius\n", | |
441 | (temp - tt->tt_previous_temp)); | |
442 | } | |
443 | #endif | |
ee9f2989 | 444 | old_state = tt->state; |
39b73fb1 WYG |
445 | /* in Celsius */ |
446 | if (temp >= IWL_MINIMAL_POWER_THRESHOLD) | |
ee9f2989 | 447 | tt->state = IWL_TI_CT_KILL; |
39b73fb1 | 448 | else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2) |
ee9f2989 | 449 | tt->state = IWL_TI_2; |
39b73fb1 | 450 | else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1) |
ee9f2989 | 451 | tt->state = IWL_TI_1; |
39b73fb1 | 452 | else |
ee9f2989 | 453 | tt->state = IWL_TI_0; |
39b73fb1 WYG |
454 | |
455 | #ifdef CONFIG_IWLWIFI_DEBUG | |
456 | tt->tt_previous_temp = temp; | |
457 | #endif | |
ee9f2989 WYG |
458 | if (tt->state != old_state) { |
459 | if (old_state == IWL_TI_0) { | |
39b73fb1 WYG |
460 | tt->sys_power_mode = setting->power_mode; |
461 | IWL_DEBUG_POWER(priv, "current power mode: %u\n", | |
462 | setting->power_mode); | |
463 | } | |
ee9f2989 | 464 | switch (tt->state) { |
39b73fb1 WYG |
465 | case IWL_TI_0: |
466 | /* when system ready to go back to IWL_TI_0 state | |
467 | * using system power mode instead of TT power mode | |
468 | * revert back to the orginal power mode which was saved | |
469 | * before enter Thermal Throttling state | |
470 | * update priv->power_data.user_power_setting to the | |
471 | * required power mode to make sure | |
472 | * iwl_power_update_mode() will update power correctly. | |
473 | */ | |
474 | priv->power_data.user_power_setting = | |
475 | tt->sys_power_mode; | |
476 | tt->tt_power_mode = tt->sys_power_mode; | |
477 | break; | |
478 | case IWL_TI_1: | |
479 | tt->tt_power_mode = IWL_POWER_INDEX_3; | |
480 | break; | |
481 | case IWL_TI_2: | |
482 | tt->tt_power_mode = IWL_POWER_INDEX_4; | |
483 | break; | |
484 | default: | |
485 | tt->tt_power_mode = IWL_POWER_INDEX_5; | |
486 | break; | |
487 | } | |
a28027cd | 488 | mutex_lock(&priv->mutex); |
39b73fb1 WYG |
489 | if (iwl_power_update_mode(priv, true)) { |
490 | /* TT state not updated | |
491 | * try again during next temperature read | |
492 | */ | |
ee9f2989 | 493 | tt->state = old_state; |
39b73fb1 WYG |
494 | IWL_ERR(priv, "Cannot update power mode, " |
495 | "TT state not updated\n"); | |
496 | } else { | |
ee9f2989 | 497 | if (tt->state == IWL_TI_CT_KILL) |
39b73fb1 | 498 | iwl_perform_ct_kill_task(priv, true); |
ee9f2989 WYG |
499 | else if (old_state == IWL_TI_CT_KILL && |
500 | tt->state != IWL_TI_CT_KILL) | |
39b73fb1 | 501 | iwl_perform_ct_kill_task(priv, false); |
39b73fb1 WYG |
502 | IWL_DEBUG_POWER(priv, "Temperature state changed %u\n", |
503 | tt->state); | |
504 | IWL_DEBUG_POWER(priv, "Power Index change to %u\n", | |
505 | tt->tt_power_mode); | |
506 | } | |
a28027cd | 507 | mutex_unlock(&priv->mutex); |
39b73fb1 WYG |
508 | } |
509 | } | |
510 | ||
46f9381a WYG |
511 | /* |
512 | * Advance thermal throttling | |
513 | * 1) Avoid NIC destruction due to high temperatures | |
514 | * Chip will identify dangerously high temperatures that can | |
515 | * harm the device and will power down | |
516 | * 2) Avoid the NIC power down due to high temperature | |
517 | * Throttle early enough to lower the power consumption before | |
518 | * drastic steps are needed | |
519 | * Actions include relaxing the power down sleep thresholds and | |
520 | * decreasing the number of TX streams | |
521 | * 3) Avoid throughput performance impact as much as possible | |
522 | * | |
523 | *============================================================================= | |
524 | * Condition Nxt State Condition Nxt State Condition Nxt State | |
525 | *----------------------------------------------------------------------------- | |
526 | * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A | |
527 | * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 | |
528 | * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 | |
529 | * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 | |
530 | *============================================================================= | |
531 | */ | |
532 | static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) | |
533 | { | |
3ad3b92a | 534 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
46f9381a WYG |
535 | int i; |
536 | bool changed = false; | |
537 | enum iwl_tt_state old_state; | |
538 | struct iwl_tt_trans *transaction; | |
539 | ||
540 | old_state = tt->state; | |
541 | for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) { | |
542 | /* based on the current TT state, | |
543 | * find the curresponding transaction table | |
544 | * each table has (IWL_TI_STATE_MAX - 1) entries | |
545 | * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1)) | |
546 | * will advance to the correct table. | |
547 | * then based on the current temperature | |
548 | * find the next state need to transaction to | |
549 | * go through all the possible (IWL_TI_STATE_MAX - 1) entries | |
550 | * in the current table to see if transaction is needed | |
551 | */ | |
552 | transaction = tt->transaction + | |
553 | ((old_state * (IWL_TI_STATE_MAX - 1)) + i); | |
554 | if (temp >= transaction->tt_low && | |
555 | temp <= transaction->tt_high) { | |
556 | #ifdef CONFIG_IWLWIFI_DEBUG | |
557 | if ((tt->tt_previous_temp) && | |
558 | (temp > tt->tt_previous_temp) && | |
559 | ((temp - tt->tt_previous_temp) > | |
560 | IWL_TT_INCREASE_MARGIN)) { | |
561 | IWL_DEBUG_POWER(priv, | |
562 | "Temperature increase %d " | |
563 | "degree Celsius\n", | |
564 | (temp - tt->tt_previous_temp)); | |
565 | } | |
566 | tt->tt_previous_temp = temp; | |
567 | #endif | |
568 | if (old_state != | |
569 | transaction->next_state) { | |
570 | changed = true; | |
571 | tt->state = | |
572 | transaction->next_state; | |
573 | } | |
574 | break; | |
575 | } | |
576 | } | |
577 | if (changed) { | |
578 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; | |
579 | struct iwl_power_mgr *setting = &priv->power_data; | |
580 | ||
581 | if (tt->state >= IWL_TI_1) { | |
582 | /* if switching from IWL_TI_0 to other TT state | |
583 | * save previous power setting in tt->sys_power_mode */ | |
584 | if (old_state == IWL_TI_0) | |
585 | tt->sys_power_mode = setting->power_mode; | |
586 | /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */ | |
587 | tt->tt_power_mode = IWL_POWER_INDEX_5; | |
588 | if (!iwl_ht_enabled(priv)) | |
589 | /* disable HT */ | |
590 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | | |
591 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | | |
7aafef1c | 592 | RXON_FLG_HT40_PROT_MSK | |
46f9381a WYG |
593 | RXON_FLG_HT_PROT_MSK); |
594 | else { | |
595 | /* check HT capability and set | |
596 | * according to the system HT capability | |
597 | * in case get disabled before */ | |
598 | iwl_set_rxon_ht(priv, &priv->current_ht_config); | |
599 | } | |
600 | ||
601 | } else { | |
602 | /* restore system power setting */ | |
603 | /* the previous power mode was saved in | |
604 | * tt->sys_power_mode when system move into | |
605 | * Thermal Throttling state | |
606 | * set power_data.user_power_setting to the previous | |
607 | * system power mode to make sure power will get | |
608 | * updated correctly | |
609 | */ | |
610 | priv->power_data.user_power_setting = | |
611 | tt->sys_power_mode; | |
612 | tt->tt_power_mode = tt->sys_power_mode; | |
613 | /* check HT capability and set | |
614 | * according to the system HT capability | |
615 | * in case get disabled before */ | |
616 | iwl_set_rxon_ht(priv, &priv->current_ht_config); | |
617 | } | |
a28027cd | 618 | mutex_lock(&priv->mutex); |
46f9381a WYG |
619 | if (iwl_power_update_mode(priv, true)) { |
620 | /* TT state not updated | |
621 | * try again during next temperature read | |
622 | */ | |
623 | IWL_ERR(priv, "Cannot update power mode, " | |
624 | "TT state not updated\n"); | |
625 | tt->state = old_state; | |
626 | } else { | |
627 | IWL_DEBUG_POWER(priv, | |
628 | "Thermal Throttling to new state: %u\n", | |
629 | tt->state); | |
630 | if (old_state != IWL_TI_CT_KILL && | |
631 | tt->state == IWL_TI_CT_KILL) { | |
632 | IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n"); | |
633 | iwl_perform_ct_kill_task(priv, true); | |
634 | ||
635 | } else if (old_state == IWL_TI_CT_KILL && | |
636 | tt->state != IWL_TI_CT_KILL) { | |
637 | IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n"); | |
638 | iwl_perform_ct_kill_task(priv, false); | |
639 | } | |
640 | } | |
a28027cd | 641 | mutex_unlock(&priv->mutex); |
46f9381a WYG |
642 | } |
643 | } | |
644 | ||
39b73fb1 WYG |
645 | /* Card State Notification indicated reach critical temperature |
646 | * if PSP not enable, no Thermal Throttling function will be performed | |
647 | * just set the GP1 bit to acknowledge the event | |
648 | * otherwise, go into IWL_TI_CT_KILL state | |
649 | * since Card State Notification will not provide any temperature reading | |
46f9381a | 650 | * for Legacy mode |
39b73fb1 | 651 | * so just pass the CT_KILL temperature to iwl_legacy_tt_handler() |
46f9381a WYG |
652 | * for advance mode |
653 | * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state | |
39b73fb1 | 654 | */ |
a28027cd | 655 | static void iwl_bg_ct_enter(struct work_struct *work) |
39b73fb1 | 656 | { |
a28027cd | 657 | struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter); |
3ad3b92a | 658 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
39b73fb1 WYG |
659 | |
660 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | |
661 | return; | |
662 | ||
a28027cd WYG |
663 | if (!iwl_is_ready(priv)) |
664 | return; | |
665 | ||
39b73fb1 WYG |
666 | if (tt->state != IWL_TI_CT_KILL) { |
667 | IWL_ERR(priv, "Device reached critical temperature " | |
668 | "- ucode going to sleep!\n"); | |
3ad3b92a | 669 | if (!priv->thermal_throttle.advanced_tt) |
46f9381a WYG |
670 | iwl_legacy_tt_handler(priv, |
671 | IWL_MINIMAL_POWER_THRESHOLD); | |
672 | else | |
673 | iwl_advance_tt_handler(priv, | |
674 | CT_KILL_THRESHOLD + 1); | |
39b73fb1 WYG |
675 | } |
676 | } | |
39b73fb1 WYG |
677 | |
678 | /* Card State Notification indicated out of critical temperature | |
679 | * since Card State Notification will not provide any temperature reading | |
680 | * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature | |
681 | * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state | |
682 | */ | |
a28027cd | 683 | static void iwl_bg_ct_exit(struct work_struct *work) |
39b73fb1 | 684 | { |
a28027cd | 685 | struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit); |
3ad3b92a | 686 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
39b73fb1 WYG |
687 | |
688 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | |
689 | return; | |
690 | ||
a28027cd WYG |
691 | if (!iwl_is_ready(priv)) |
692 | return; | |
693 | ||
39b73fb1 | 694 | /* stop ct_kill_exit_tm timer */ |
3ad3b92a | 695 | del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm); |
39b73fb1 WYG |
696 | |
697 | if (tt->state == IWL_TI_CT_KILL) { | |
698 | IWL_ERR(priv, | |
699 | "Device temperature below critical" | |
700 | "- ucode awake!\n"); | |
3ad3b92a | 701 | if (!priv->thermal_throttle.advanced_tt) |
46f9381a WYG |
702 | iwl_legacy_tt_handler(priv, |
703 | IWL_REDUCED_PERFORMANCE_THRESHOLD_2); | |
704 | else | |
705 | iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD); | |
39b73fb1 WYG |
706 | } |
707 | } | |
a28027cd WYG |
708 | |
709 | void iwl_tt_enter_ct_kill(struct iwl_priv *priv) | |
710 | { | |
711 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | |
712 | return; | |
713 | ||
714 | IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n"); | |
715 | queue_work(priv->workqueue, &priv->ct_enter); | |
716 | } | |
717 | EXPORT_SYMBOL(iwl_tt_enter_ct_kill); | |
718 | ||
719 | void iwl_tt_exit_ct_kill(struct iwl_priv *priv) | |
720 | { | |
721 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | |
722 | return; | |
723 | ||
724 | IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n"); | |
725 | queue_work(priv->workqueue, &priv->ct_exit); | |
726 | } | |
39b73fb1 WYG |
727 | EXPORT_SYMBOL(iwl_tt_exit_ct_kill); |
728 | ||
a28027cd | 729 | static void iwl_bg_tt_work(struct work_struct *work) |
39b73fb1 | 730 | { |
a28027cd | 731 | struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work); |
39b73fb1 WYG |
732 | s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */ |
733 | ||
734 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | |
735 | return; | |
736 | ||
737 | if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) | |
738 | temp = KELVIN_TO_CELSIUS(priv->temperature); | |
739 | ||
3ad3b92a | 740 | if (!priv->thermal_throttle.advanced_tt) |
46f9381a WYG |
741 | iwl_legacy_tt_handler(priv, temp); |
742 | else | |
743 | iwl_advance_tt_handler(priv, temp); | |
39b73fb1 | 744 | } |
a28027cd WYG |
745 | |
746 | void iwl_tt_handler(struct iwl_priv *priv) | |
747 | { | |
748 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | |
749 | return; | |
750 | ||
751 | IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n"); | |
752 | queue_work(priv->workqueue, &priv->tt_work); | |
753 | } | |
39b73fb1 WYG |
754 | EXPORT_SYMBOL(iwl_tt_handler); |
755 | ||
756 | /* Thermal throttling initialization | |
46f9381a WYG |
757 | * For advance thermal throttling: |
758 | * Initialize Thermal Index and temperature threshold table | |
759 | * Initialize thermal throttling restriction table | |
39b73fb1 WYG |
760 | */ |
761 | void iwl_tt_initialize(struct iwl_priv *priv) | |
762 | { | |
3ad3b92a | 763 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
39b73fb1 | 764 | struct iwl_power_mgr *setting = &priv->power_data; |
46f9381a WYG |
765 | int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1); |
766 | struct iwl_tt_trans *transaction; | |
39b73fb1 WYG |
767 | |
768 | IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n"); | |
769 | ||
770 | memset(tt, 0, sizeof(struct iwl_tt_mgmt)); | |
771 | ||
772 | tt->state = IWL_TI_0; | |
773 | tt->sys_power_mode = setting->power_mode; | |
774 | tt->tt_power_mode = tt->sys_power_mode; | |
3ad3b92a JB |
775 | init_timer(&priv->thermal_throttle.ct_kill_exit_tm); |
776 | priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv; | |
777 | priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; | |
a28027cd WYG |
778 | |
779 | /* setup deferred ct kill work */ | |
780 | INIT_WORK(&priv->tt_work, iwl_bg_tt_work); | |
781 | INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); | |
782 | INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit); | |
783 | ||
46f9381a WYG |
784 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { |
785 | case CSR_HW_REV_TYPE_6x00: | |
786 | case CSR_HW_REV_TYPE_6x50: | |
787 | IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n"); | |
788 | tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) * | |
789 | IWL_TI_STATE_MAX, GFP_KERNEL); | |
790 | tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) * | |
791 | IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1), | |
792 | GFP_KERNEL); | |
793 | if (!tt->restriction || !tt->transaction) { | |
794 | IWL_ERR(priv, "Fallback to Legacy Throttling\n"); | |
3ad3b92a | 795 | priv->thermal_throttle.advanced_tt = false; |
46f9381a WYG |
796 | kfree(tt->restriction); |
797 | tt->restriction = NULL; | |
798 | kfree(tt->transaction); | |
799 | tt->transaction = NULL; | |
800 | } else { | |
801 | transaction = tt->transaction + | |
802 | (IWL_TI_0 * (IWL_TI_STATE_MAX - 1)); | |
803 | memcpy(transaction, &tt_range_0[0], size); | |
804 | transaction = tt->transaction + | |
805 | (IWL_TI_1 * (IWL_TI_STATE_MAX - 1)); | |
806 | memcpy(transaction, &tt_range_1[0], size); | |
807 | transaction = tt->transaction + | |
808 | (IWL_TI_2 * (IWL_TI_STATE_MAX - 1)); | |
809 | memcpy(transaction, &tt_range_2[0], size); | |
810 | transaction = tt->transaction + | |
811 | (IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1)); | |
812 | memcpy(transaction, &tt_range_3[0], size); | |
813 | size = sizeof(struct iwl_tt_restriction) * | |
814 | IWL_TI_STATE_MAX; | |
815 | memcpy(tt->restriction, | |
816 | &restriction_range[0], size); | |
3ad3b92a | 817 | priv->thermal_throttle.advanced_tt = true; |
46f9381a WYG |
818 | } |
819 | break; | |
820 | default: | |
821 | IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n"); | |
3ad3b92a | 822 | priv->thermal_throttle.advanced_tt = false; |
46f9381a WYG |
823 | break; |
824 | } | |
39b73fb1 WYG |
825 | } |
826 | EXPORT_SYMBOL(iwl_tt_initialize); | |
827 | ||
828 | /* cleanup thermal throttling management related memory and timer */ | |
829 | void iwl_tt_exit(struct iwl_priv *priv) | |
830 | { | |
3ad3b92a | 831 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
46f9381a | 832 | |
39b73fb1 | 833 | /* stop ct_kill_exit_tm timer if activated */ |
3ad3b92a | 834 | del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm); |
a28027cd WYG |
835 | cancel_work_sync(&priv->tt_work); |
836 | cancel_work_sync(&priv->ct_enter); | |
837 | cancel_work_sync(&priv->ct_exit); | |
46f9381a | 838 | |
3ad3b92a | 839 | if (priv->thermal_throttle.advanced_tt) { |
46f9381a WYG |
840 | /* free advance thermal throttling memory */ |
841 | kfree(tt->restriction); | |
842 | tt->restriction = NULL; | |
843 | kfree(tt->transaction); | |
844 | tt->transaction = NULL; | |
845 | } | |
39b73fb1 WYG |
846 | } |
847 | EXPORT_SYMBOL(iwl_tt_exit); | |
848 | ||
a96a27f9 | 849 | /* initialize to default */ |
5da4b55f MA |
850 | void iwl_power_initialize(struct iwl_priv *priv) |
851 | { | |
5da4b55f | 852 | iwl_power_init_handle(priv); |
7af2c460 JB |
853 | priv->power_data.user_power_setting = IWL_POWER_INDEX_1; |
854 | /* default to disabled until mac80211 says otherwise */ | |
855 | priv->power_data.power_disabled = 1; | |
5da4b55f MA |
856 | } |
857 | EXPORT_SYMBOL(iwl_power_initialize); |