diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-05-08 16:44:38 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-05-11 15:23:59 -0400 |
commit | 7af2c460789a78d9c0d4dc7776fcb87acdc71052 (patch) | |
tree | c2551f5272a8274eaeca9d432435a03d8b19429f /drivers/net/wireless/iwlwifi/iwl-power.c | |
parent | f0f74a0e65a69d4cc579e60f76a30b38ad7dbe06 (diff) |
iwlwifi: clean up PS code
This removes all the dead code that tries to adjust the power
saving level based on the system AC state (inacceptable policy
in the kernel) or based on overtemp conditions (unused).
Also, pass _all_ policy wrt. enabling PS to mac80211, since
we do not use the power_disabled internally I now use that to
mirror the mac80211 CONF_PS setting. When mac80211 turns off
CONF_PS we follow suit. This means that the user power level
(which can currently only be set from sysfs) is not touched
for mac80211 powersave changes.
This means no "association status" checks are necessary since
mac80211 will not allow power save to be enabled when not
associated.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Mohamed Abbas <mohamed.abbas@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-power.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.c | 228 |
1 files changed, 31 insertions, 197 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index c913069a2496..f2ea3f05f6e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c | |||
@@ -41,38 +41,33 @@ | |||
41 | #include "iwl-power.h" | 41 | #include "iwl-power.h" |
42 | 42 | ||
43 | /* | 43 | /* |
44 | * Setting power level allow the card to go to sleep when not busy | 44 | * Setting power level allow the card to go to sleep when not busy. |
45 | * there are three factor that decide the power level to go to, they | ||
46 | * are list here with its priority | ||
47 | * 1- critical_power_setting this will be set according to card temperature. | ||
48 | * 2- system_power_setting this will be set by system PM manager. | ||
49 | * 3- user_power_setting this will be set by user either by writing to sys or | ||
50 | * mac80211 | ||
51 | * | 45 | * |
52 | * if system_power_setting and user_power_setting is set to auto | 46 | * The power level is set to INDEX_1 (the least deep state) by |
53 | * the power level will be decided according to association status and battery | 47 | * default, and will, in the future, be the deepest state unless |
54 | * status. | 48 | * otherwise required by pm_qos network latency requirements. |
55 | * | 49 | * |
50 | * Using INDEX_1 without pm_qos is ok because mac80211 will disable | ||
51 | * PS when even checking every beacon for the TIM bit would exceed | ||
52 | * the required latency. | ||
56 | */ | 53 | */ |
57 | 54 | ||
58 | #define MSEC_TO_USEC 1024 | ||
59 | #define IWL_POWER_RANGE_0_MAX (2) | 55 | #define IWL_POWER_RANGE_0_MAX (2) |
60 | #define IWL_POWER_RANGE_1_MAX (10) | 56 | #define IWL_POWER_RANGE_1_MAX (10) |
61 | 57 | ||
62 | 58 | ||
63 | 59 | #define NOSLP cpu_to_le16(0), 0, 0 | |
64 | #define IWL_POWER_ON_BATTERY IWL_POWER_INDEX_5 | 60 | #define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 |
65 | #define IWL_POWER_ON_AC_DISASSOC IWL_POWER_MODE_CAM | 61 | #define TU_TO_USEC 1024 |
66 | #define IWL_POWER_ON_AC_ASSOC IWL_POWER_MODE_CAM | 62 | #define SLP_TOUT(T) cpu_to_le32((T) * TU_TO_USEC) |
67 | 63 | #define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \ | |
68 | 64 | cpu_to_le32(X1), \ | |
69 | #define IWL_CT_KILL_TEMPERATURE 110 | 65 | cpu_to_le32(X2), \ |
70 | #define IWL_MIN_POWER_TEMPERATURE 100 | 66 | cpu_to_le32(X3), \ |
71 | #define IWL_REDUCED_POWER_TEMPERATURE 95 | 67 | cpu_to_le32(X4)} |
72 | |||
73 | /* default power management (not Tx power) table values */ | 68 | /* default power management (not Tx power) table values */ |
74 | /* for TIM 0-10 */ | 69 | /* for DTIM period 0 through IWL_POWER_RANGE_0_MAX */ |
75 | static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { | 70 | static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { |
76 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, | 71 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, |
77 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, | 72 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, |
78 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, | 73 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, |
@@ -82,8 +77,8 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { | |||
82 | }; | 77 | }; |
83 | 78 | ||
84 | 79 | ||
85 | /* for TIM = 3-10 */ | 80 | /* for DTIM period IWL_POWER_RANGE_0_MAX + 1 through IWL_POWER_RANGE_1_MAX */ |
86 | static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { | 81 | static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { |
87 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, | 82 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, |
88 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, | 83 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, |
89 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, | 84 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, |
@@ -92,8 +87,8 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { | |||
92 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} | 87 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} |
93 | }; | 88 | }; |
94 | 89 | ||
95 | /* for TIM > 11 */ | 90 | /* for DTIM period > IWL_POWER_RANGE_1_MAX */ |
96 | static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = { | 91 | static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { |
97 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, | 92 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, |
98 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, | 93 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, |
99 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, | 94 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, |
@@ -109,35 +104,12 @@ static int iwl_set_power(struct iwl_priv *priv, void *cmd) | |||
109 | return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, | 104 | return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, |
110 | sizeof(struct iwl_powertable_cmd), cmd); | 105 | sizeof(struct iwl_powertable_cmd), cmd); |
111 | } | 106 | } |
112 | /* decide the right power level according to association status | ||
113 | * and battery status | ||
114 | */ | ||
115 | static u16 iwl_get_auto_power_mode(struct iwl_priv *priv) | ||
116 | { | ||
117 | u16 mode; | ||
118 | |||
119 | switch (priv->power_data.user_power_setting) { | ||
120 | case IWL_POWER_AUTO: | ||
121 | /* if running on battery */ | ||
122 | if (priv->power_data.is_battery_active) | ||
123 | mode = IWL_POWER_ON_BATTERY; | ||
124 | else if (iwl_is_associated(priv)) | ||
125 | mode = IWL_POWER_ON_AC_ASSOC; | ||
126 | else | ||
127 | mode = IWL_POWER_ON_AC_DISASSOC; | ||
128 | break; | ||
129 | default: | ||
130 | mode = priv->power_data.user_power_setting; | ||
131 | break; | ||
132 | } | ||
133 | return mode; | ||
134 | } | ||
135 | 107 | ||
136 | /* initialize to default */ | 108 | /* initialize to default */ |
137 | static void iwl_power_init_handle(struct iwl_priv *priv) | 109 | static void iwl_power_init_handle(struct iwl_priv *priv) |
138 | { | 110 | { |
139 | struct iwl_power_mgr *pow_data; | 111 | struct iwl_power_mgr *pow_data; |
140 | int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX; | 112 | int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_NUM; |
141 | struct iwl_powertable_cmd *cmd; | 113 | struct iwl_powertable_cmd *cmd; |
142 | int i; | 114 | int i; |
143 | u16 lctl; | 115 | u16 lctl; |
@@ -156,7 +128,7 @@ static void iwl_power_init_handle(struct iwl_priv *priv) | |||
156 | 128 | ||
157 | IWL_DEBUG_POWER(priv, "adjust power command flags\n"); | 129 | IWL_DEBUG_POWER(priv, "adjust power command flags\n"); |
158 | 130 | ||
159 | for (i = 0; i < IWL_POWER_MAX; i++) { | 131 | for (i = 0; i < IWL_POWER_NUM; i++) { |
160 | cmd = &pow_data->pwr_range_0[i].cmd; | 132 | cmd = &pow_data->pwr_range_0[i].cmd; |
161 | 133 | ||
162 | if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN) | 134 | if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN) |
@@ -246,33 +218,12 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) | |||
246 | update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || | 218 | update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || |
247 | priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; | 219 | priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; |
248 | 220 | ||
249 | /* If on battery, set to 3, | 221 | final_mode = priv->power_data.user_power_setting; |
250 | * if plugged into AC power, set to CAM ("continuously aware mode"), | ||
251 | * else user level */ | ||
252 | |||
253 | switch (setting->system_power_setting) { | ||
254 | case IWL_POWER_SYS_AUTO: | ||
255 | final_mode = iwl_get_auto_power_mode(priv); | ||
256 | break; | ||
257 | case IWL_POWER_SYS_BATTERY: | ||
258 | final_mode = IWL_POWER_INDEX_3; | ||
259 | break; | ||
260 | case IWL_POWER_SYS_AC: | ||
261 | final_mode = IWL_POWER_MODE_CAM; | ||
262 | break; | ||
263 | default: | ||
264 | final_mode = IWL_POWER_INDEX_3; | ||
265 | WARN_ON(1); | ||
266 | } | ||
267 | |||
268 | if (setting->critical_power_setting > final_mode) | ||
269 | final_mode = setting->critical_power_setting; | ||
270 | 222 | ||
271 | /* driver only support CAM for non STA network */ | 223 | if (setting->power_disabled) |
272 | if (priv->iw_mode != NL80211_IFTYPE_STATION) | ||
273 | final_mode = IWL_POWER_MODE_CAM; | 224 | final_mode = IWL_POWER_MODE_CAM; |
274 | 225 | ||
275 | if (iwl_is_ready_rf(priv) && !setting->power_disabled && | 226 | if (iwl_is_ready_rf(priv) && |
276 | ((setting->power_mode != final_mode) || force)) { | 227 | ((setting->power_mode != final_mode) || force)) { |
277 | struct iwl_powertable_cmd cmd; | 228 | struct iwl_powertable_cmd cmd; |
278 | 229 | ||
@@ -289,8 +240,6 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) | |||
289 | 240 | ||
290 | if (final_mode == IWL_POWER_MODE_CAM) | 241 | if (final_mode == IWL_POWER_MODE_CAM) |
291 | clear_bit(STATUS_POWER_PMI, &priv->status); | 242 | clear_bit(STATUS_POWER_PMI, &priv->status); |
292 | else | ||
293 | set_bit(STATUS_POWER_PMI, &priv->status); | ||
294 | 243 | ||
295 | if (priv->cfg->ops->lib->update_chain_flags && update_chains) | 244 | if (priv->cfg->ops->lib->update_chain_flags && update_chains) |
296 | priv->cfg->ops->lib->update_chain_flags(priv); | 245 | priv->cfg->ops->lib->update_chain_flags(priv); |
@@ -306,51 +255,10 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) | |||
306 | } | 255 | } |
307 | EXPORT_SYMBOL(iwl_power_update_mode); | 256 | EXPORT_SYMBOL(iwl_power_update_mode); |
308 | 257 | ||
309 | /* Allow other iwl code to disable/enable power management active | ||
310 | * this will be useful for rate scale to disable PM during heavy | ||
311 | * Tx/Rx activities | ||
312 | */ | ||
313 | int iwl_power_disable_management(struct iwl_priv *priv, u32 ms) | ||
314 | { | ||
315 | u16 prev_mode; | ||
316 | int ret = 0; | ||
317 | |||
318 | if (priv->power_data.power_disabled) | ||
319 | return -EBUSY; | ||
320 | |||
321 | prev_mode = priv->power_data.user_power_setting; | ||
322 | priv->power_data.user_power_setting = IWL_POWER_MODE_CAM; | ||
323 | ret = iwl_power_update_mode(priv, 0); | ||
324 | priv->power_data.power_disabled = 1; | ||
325 | priv->power_data.user_power_setting = prev_mode; | ||
326 | cancel_delayed_work(&priv->set_power_save); | ||
327 | if (ms) | ||
328 | queue_delayed_work(priv->workqueue, &priv->set_power_save, | ||
329 | msecs_to_jiffies(ms)); | ||
330 | |||
331 | |||
332 | return ret; | ||
333 | } | ||
334 | EXPORT_SYMBOL(iwl_power_disable_management); | ||
335 | |||
336 | /* Allow other iwl code to disable/enable power management active | ||
337 | * this will be useful for rate scale to disable PM during high | ||
338 | * volume activities | ||
339 | */ | ||
340 | int iwl_power_enable_management(struct iwl_priv *priv) | ||
341 | { | ||
342 | int ret = 0; | ||
343 | |||
344 | priv->power_data.power_disabled = 0; | ||
345 | ret = iwl_power_update_mode(priv, 0); | ||
346 | return ret; | ||
347 | } | ||
348 | EXPORT_SYMBOL(iwl_power_enable_management); | ||
349 | |||
350 | /* set user_power_setting */ | 258 | /* set user_power_setting */ |
351 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) | 259 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) |
352 | { | 260 | { |
353 | if (mode > IWL_POWER_MAX) | 261 | if (mode >= IWL_POWER_NUM) |
354 | return -EINVAL; | 262 | return -EINVAL; |
355 | 263 | ||
356 | priv->power_data.user_power_setting = mode; | 264 | priv->power_data.user_power_setting = mode; |
@@ -359,86 +267,12 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) | |||
359 | } | 267 | } |
360 | EXPORT_SYMBOL(iwl_power_set_user_mode); | 268 | EXPORT_SYMBOL(iwl_power_set_user_mode); |
361 | 269 | ||
362 | /* set system_power_setting. This should be set by over all | ||
363 | * PM application. | ||
364 | */ | ||
365 | int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) | ||
366 | { | ||
367 | if (mode < IWL_POWER_SYS_MAX) | ||
368 | priv->power_data.system_power_setting = mode; | ||
369 | else | ||
370 | return -EINVAL; | ||
371 | return iwl_power_update_mode(priv, 0); | ||
372 | } | ||
373 | EXPORT_SYMBOL(iwl_power_set_system_mode); | ||
374 | |||
375 | /* initialize to default */ | 270 | /* initialize to default */ |
376 | void iwl_power_initialize(struct iwl_priv *priv) | 271 | void iwl_power_initialize(struct iwl_priv *priv) |
377 | { | 272 | { |
378 | iwl_power_init_handle(priv); | 273 | iwl_power_init_handle(priv); |
379 | priv->power_data.user_power_setting = IWL_POWER_AUTO; | 274 | priv->power_data.user_power_setting = IWL_POWER_INDEX_1; |
380 | priv->power_data.system_power_setting = IWL_POWER_SYS_AUTO; | 275 | /* default to disabled until mac80211 says otherwise */ |
381 | priv->power_data.power_disabled = 0; | 276 | priv->power_data.power_disabled = 1; |
382 | priv->power_data.is_battery_active = 0; | ||
383 | priv->power_data.critical_power_setting = 0; | ||
384 | } | 277 | } |
385 | EXPORT_SYMBOL(iwl_power_initialize); | 278 | EXPORT_SYMBOL(iwl_power_initialize); |
386 | |||
387 | /* set critical_power_setting according to temperature value */ | ||
388 | int iwl_power_temperature_change(struct iwl_priv *priv) | ||
389 | { | ||
390 | int ret = 0; | ||
391 | s32 temperature = KELVIN_TO_CELSIUS(priv->last_temperature); | ||
392 | u16 new_critical = priv->power_data.critical_power_setting; | ||
393 | |||
394 | if (temperature > IWL_CT_KILL_TEMPERATURE) | ||
395 | return 0; | ||
396 | else if (temperature > IWL_MIN_POWER_TEMPERATURE) | ||
397 | new_critical = IWL_POWER_INDEX_5; | ||
398 | else if (temperature > IWL_REDUCED_POWER_TEMPERATURE) | ||
399 | new_critical = IWL_POWER_INDEX_3; | ||
400 | else | ||
401 | new_critical = IWL_POWER_MODE_CAM; | ||
402 | |||
403 | if (new_critical != priv->power_data.critical_power_setting) | ||
404 | priv->power_data.critical_power_setting = new_critical; | ||
405 | |||
406 | if (priv->power_data.critical_power_setting > | ||
407 | priv->power_data.power_mode) | ||
408 | ret = iwl_power_update_mode(priv, 0); | ||
409 | |||
410 | return ret; | ||
411 | } | ||
412 | EXPORT_SYMBOL(iwl_power_temperature_change); | ||
413 | |||
414 | static void iwl_bg_set_power_save(struct work_struct *work) | ||
415 | { | ||
416 | struct iwl_priv *priv = container_of(work, | ||
417 | struct iwl_priv, set_power_save.work); | ||
418 | IWL_DEBUG_POWER(priv, "update power\n"); | ||
419 | |||
420 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
421 | return; | ||
422 | |||
423 | mutex_lock(&priv->mutex); | ||
424 | |||
425 | /* on starting association we disable power management | ||
426 | * until association, if association failed then this | ||
427 | * timer will expire and enable PM again. | ||
428 | */ | ||
429 | if (!iwl_is_associated(priv)) | ||
430 | iwl_power_enable_management(priv); | ||
431 | |||
432 | mutex_unlock(&priv->mutex); | ||
433 | } | ||
434 | void iwl_setup_power_deferred_work(struct iwl_priv *priv) | ||
435 | { | ||
436 | INIT_DELAYED_WORK(&priv->set_power_save, iwl_bg_set_power_save); | ||
437 | } | ||
438 | EXPORT_SYMBOL(iwl_setup_power_deferred_work); | ||
439 | |||
440 | void iwl_power_cancel_timeout(struct iwl_priv *priv) | ||
441 | { | ||
442 | cancel_delayed_work(&priv->set_power_save); | ||
443 | } | ||
444 | EXPORT_SYMBOL(iwl_power_cancel_timeout); | ||