aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-power.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-05-08 16:44:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-11 15:23:59 -0400
commit7af2c460789a78d9c0d4dc7776fcb87acdc71052 (patch)
treec2551f5272a8274eaeca9d432435a03d8b19429f /drivers/net/wireless/iwlwifi/iwl-power.c
parentf0f74a0e65a69d4cc579e60f76a30b38ad7dbe06 (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.c228
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 */
75static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { 70static 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 */
86static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { 81static 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 */
96static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = { 91static 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 */
115static 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 */
137static void iwl_power_init_handle(struct iwl_priv *priv) 109static 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}
307EXPORT_SYMBOL(iwl_power_update_mode); 256EXPORT_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 */
313int 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}
334EXPORT_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 */
340int 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}
348EXPORT_SYMBOL(iwl_power_enable_management);
349
350/* set user_power_setting */ 258/* set user_power_setting */
351int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) 259int 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}
360EXPORT_SYMBOL(iwl_power_set_user_mode); 268EXPORT_SYMBOL(iwl_power_set_user_mode);
361 269
362/* set system_power_setting. This should be set by over all
363 * PM application.
364 */
365int 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}
373EXPORT_SYMBOL(iwl_power_set_system_mode);
374
375/* initialize to default */ 270/* initialize to default */
376void iwl_power_initialize(struct iwl_priv *priv) 271void 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}
385EXPORT_SYMBOL(iwl_power_initialize); 278EXPORT_SYMBOL(iwl_power_initialize);
386
387/* set critical_power_setting according to temperature value */
388int 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}
412EXPORT_SYMBOL(iwl_power_temperature_change);
413
414static 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}
434void iwl_setup_power_deferred_work(struct iwl_priv *priv)
435{
436 INIT_DELAYED_WORK(&priv->set_power_save, iwl_bg_set_power_save);
437}
438EXPORT_SYMBOL(iwl_setup_power_deferred_work);
439
440void iwl_power_cancel_timeout(struct iwl_priv *priv)
441{
442 cancel_delayed_work(&priv->set_power_save);
443}
444EXPORT_SYMBOL(iwl_power_cancel_timeout);