aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
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
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')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c26
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c228
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c20
7 files changed, 48 insertions, 292 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 43bc8a66864..13a35dc710a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -1838,7 +1838,6 @@ void iwl_post_associate(struct iwl_priv *priv)
1838 if (!priv->vif || !priv->is_open) 1838 if (!priv->vif || !priv->is_open)
1839 return; 1839 return;
1840 1840
1841 iwl_power_cancel_timeout(priv);
1842 iwl_scan_cancel_timeout(priv, 200); 1841 iwl_scan_cancel_timeout(priv, 200);
1843 1842
1844 conf = ieee80211_get_hw_conf(priv->hw); 1843 conf = ieee80211_get_hw_conf(priv->hw);
@@ -1914,7 +1913,7 @@ void iwl_post_associate(struct iwl_priv *priv)
1914 * If chain noise has already been run, then we need to enable 1913 * If chain noise has already been run, then we need to enable
1915 * power management here */ 1914 * power management here */
1916 if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) 1915 if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
1917 iwl_power_enable_management(priv); 1916 iwl_power_update_mode(priv, 0);
1918 1917
1919 /* Enable Rx differential gain and sensitivity calibrations */ 1918 /* Enable Rx differential gain and sensitivity calibrations */
1920 iwl_chain_noise_reset(priv); 1919 iwl_chain_noise_reset(priv);
@@ -2465,26 +2464,11 @@ static ssize_t show_power_level(struct device *d,
2465{ 2464{
2466 struct iwl_priv *priv = dev_get_drvdata(d); 2465 struct iwl_priv *priv = dev_get_drvdata(d);
2467 int mode = priv->power_data.user_power_setting; 2466 int mode = priv->power_data.user_power_setting;
2468 int system = priv->power_data.system_power_setting;
2469 int level = priv->power_data.power_mode; 2467 int level = priv->power_data.power_mode;
2470 char *p = buf; 2468 char *p = buf;
2471 2469
2472 switch (system) { 2470 p += sprintf(p, "INDEX:%d\t", level);
2473 case IWL_POWER_SYS_AUTO: 2471 p += sprintf(p, "USER:%d\n", mode);
2474 p += sprintf(p, "SYSTEM:auto");
2475 break;
2476 case IWL_POWER_SYS_AC:
2477 p += sprintf(p, "SYSTEM:ac");
2478 break;
2479 case IWL_POWER_SYS_BATTERY:
2480 p += sprintf(p, "SYSTEM:battery");
2481 break;
2482 }
2483
2484 p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ?
2485 "fixed" : "auto");
2486 p += sprintf(p, "\tINDEX:%d", level);
2487 p += sprintf(p, "\n");
2488 return p - buf + 1; 2472 return p - buf + 1;
2489} 2473}
2490 2474
@@ -2553,7 +2537,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
2553 INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); 2537 INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
2554 2538
2555 iwl_setup_scan_deferred_work(priv); 2539 iwl_setup_scan_deferred_work(priv);
2556 iwl_setup_power_deferred_work(priv);
2557 2540
2558 if (priv->cfg->ops->lib->setup_deferred_work) 2541 if (priv->cfg->ops->lib->setup_deferred_work)
2559 priv->cfg->ops->lib->setup_deferred_work(priv); 2542 priv->cfg->ops->lib->setup_deferred_work(priv);
@@ -2573,7 +2556,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
2573 2556
2574 cancel_delayed_work_sync(&priv->init_alive_start); 2557 cancel_delayed_work_sync(&priv->init_alive_start);
2575 cancel_delayed_work(&priv->scan_check); 2558 cancel_delayed_work(&priv->scan_check);
2576 cancel_delayed_work_sync(&priv->set_power_save);
2577 cancel_delayed_work(&priv->alive_start); 2559 cancel_delayed_work(&priv->alive_start);
2578 cancel_work_sync(&priv->beacon_update); 2560 cancel_work_sync(&priv->beacon_update);
2579 del_timer_sync(&priv->statistics_periodic); 2561 del_timer_sync(&priv->statistics_periodic);
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index 735f3f19928..a5d63672ad3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -857,7 +857,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
857 priv->cfg->ops->lib->update_chain_flags(priv); 857 priv->cfg->ops->lib->update_chain_flags(priv);
858 858
859 data->state = IWL_CHAIN_NOISE_DONE; 859 data->state = IWL_CHAIN_NOISE_DONE;
860 iwl_power_enable_management(priv); 860 iwl_power_update_mode(priv, 0);
861} 861}
862EXPORT_SYMBOL(iwl_chain_noise_calibration); 862EXPORT_SYMBOL(iwl_chain_noise_calibration);
863 863
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index aa1e1dc95ef..112bfa50b8f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1352,7 +1352,6 @@ int iwl_init_drv(struct iwl_priv *priv)
1352 priv->ibss_beacon = NULL; 1352 priv->ibss_beacon = NULL;
1353 1353
1354 spin_lock_init(&priv->lock); 1354 spin_lock_init(&priv->lock);
1355 spin_lock_init(&priv->power_data.lock);
1356 spin_lock_init(&priv->sta_lock); 1355 spin_lock_init(&priv->sta_lock);
1357 spin_lock_init(&priv->hcmd_lock); 1356 spin_lock_init(&priv->hcmd_lock);
1358 1357
@@ -2576,14 +2575,13 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
2576 iwl_set_rate(priv); 2575 iwl_set_rate(priv);
2577 } 2576 }
2578 2577
2579 if (changed & IEEE80211_CONF_CHANGE_PS) { 2578 if (changed & IEEE80211_CONF_CHANGE_PS &&
2580 if (conf->flags & IEEE80211_CONF_PS) 2579 priv->iw_mode == NL80211_IFTYPE_STATION) {
2581 ret = iwl_power_set_user_mode(priv, IWL_POWER_INDEX_3); 2580 priv->power_data.power_disabled =
2582 else 2581 !(conf->flags & IEEE80211_CONF_PS);
2583 ret = iwl_power_set_user_mode(priv, IWL_POWER_MODE_CAM); 2582 ret = iwl_power_update_mode(priv, 0);
2584 if (ret) 2583 if (ret)
2585 IWL_DEBUG_MAC80211(priv, "Error setting power level\n"); 2584 IWL_DEBUG_MAC80211(priv, "Error setting power level\n");
2586
2587 } 2585 }
2588 2586
2589 if (changed & IEEE80211_CONF_CHANGE_POWER) { 2587 if (changed & IEEE80211_CONF_CHANGE_POWER) {
@@ -2719,21 +2717,7 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
2719 iwlcore_commit_rxon(priv); 2717 iwlcore_commit_rxon(priv);
2720 } 2718 }
2721 2719
2722 iwl_power_update_mode(priv, 0);
2723
2724 /* Per mac80211.h: This is only used in IBSS mode... */
2725 if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { 2720 if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
2726
2727 /* switch to CAM during association period.
2728 * the ucode will block any association/authentication
2729 * frome during assiciation period if it can not hear
2730 * the AP because of PM. the timer enable PM back is
2731 * association do not complete
2732 */
2733 if (priv->hw->conf.channel->flags &
2734 (IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_RADAR))
2735 iwl_power_disable_management(priv, 3000);
2736
2737 IWL_DEBUG_MAC80211(priv, "leave - not in IBSS\n"); 2721 IWL_DEBUG_MAC80211(priv, "leave - not in IBSS\n");
2738 mutex_unlock(&priv->mutex); 2722 mutex_unlock(&priv->mutex);
2739 return; 2723 return;
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 0f2c1b21751..3049ba25c3f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1075,7 +1075,6 @@ struct iwl_priv {
1075 1075
1076 struct tasklet_struct irq_tasklet; 1076 struct tasklet_struct irq_tasklet;
1077 1077
1078 struct delayed_work set_power_save;
1079 struct delayed_work init_alive_start; 1078 struct delayed_work init_alive_start;
1080 struct delayed_work alive_start; 1079 struct delayed_work alive_start;
1081 struct delayed_work scan_check; 1080 struct delayed_work scan_check;
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index c913069a249..f2ea3f05f6e 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);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index 18963392121..37ba3bb7a25 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -40,56 +40,29 @@ enum {
40 IWL_POWER_INDEX_3, 40 IWL_POWER_INDEX_3,
41 IWL_POWER_INDEX_4, 41 IWL_POWER_INDEX_4,
42 IWL_POWER_INDEX_5, 42 IWL_POWER_INDEX_5,
43 IWL_POWER_AUTO, 43 IWL_POWER_NUM
44 IWL_POWER_MAX = IWL_POWER_AUTO,
45}; 44};
46 45
47enum {
48 IWL_POWER_SYS_AUTO,
49 IWL_POWER_SYS_AC,
50 IWL_POWER_SYS_BATTERY,
51 IWL_POWER_SYS_MAX,
52};
53
54
55/* Power management (not Tx power) structures */ 46/* Power management (not Tx power) structures */
56 47
57#define NOSLP cpu_to_le16(0), 0, 0
58#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
59#define SLP_TOUT(T) cpu_to_le32((T) * MSEC_TO_USEC)
60#define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \
61 cpu_to_le32(X1), \
62 cpu_to_le32(X2), \
63 cpu_to_le32(X3), \
64 cpu_to_le32(X4)}
65struct iwl_power_vec_entry { 48struct iwl_power_vec_entry {
66 struct iwl_powertable_cmd cmd; 49 struct iwl_powertable_cmd cmd;
67 u8 no_dtim; 50 u8 no_dtim;
68}; 51};
69 52
70struct iwl_power_mgr { 53struct iwl_power_mgr {
71 spinlock_t lock; 54 struct iwl_power_vec_entry pwr_range_0[IWL_POWER_NUM];
72 struct iwl_power_vec_entry pwr_range_0[IWL_POWER_MAX]; 55 struct iwl_power_vec_entry pwr_range_1[IWL_POWER_NUM];
73 struct iwl_power_vec_entry pwr_range_1[IWL_POWER_MAX]; 56 struct iwl_power_vec_entry pwr_range_2[IWL_POWER_NUM];
74 struct iwl_power_vec_entry pwr_range_2[IWL_POWER_MAX];
75 u32 dtim_period; 57 u32 dtim_period;
76 /* final power level that used to calculate final power command */ 58 /* final power level that used to calculate final power command */
77 u8 power_mode; 59 u8 power_mode;
78 u8 user_power_setting; /* set by user through mac80211 or sysfs */ 60 u8 user_power_setting; /* set by user through sysfs */
79 u8 system_power_setting; /* set by kernel system tools */ 61 u8 power_disabled; /* set by mac80211's CONF_PS */
80 u8 critical_power_setting; /* set if driver over heated */
81 u8 is_battery_active; /* DC/AC power */
82 u8 power_disabled; /* flag to disable using power saving level */
83}; 62};
84 63
85void iwl_setup_power_deferred_work(struct iwl_priv *priv);
86void iwl_power_cancel_timeout(struct iwl_priv *priv);
87int iwl_power_update_mode(struct iwl_priv *priv, bool force); 64int iwl_power_update_mode(struct iwl_priv *priv, bool force);
88int iwl_power_disable_management(struct iwl_priv *priv, u32 ms);
89int iwl_power_enable_management(struct iwl_priv *priv);
90int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); 65int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);
91int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode);
92void iwl_power_initialize(struct iwl_priv *priv); 66void iwl_power_initialize(struct iwl_priv *priv);
93int iwl_power_temperature_change(struct iwl_priv *priv);
94 67
95#endif /* __iwl_power_setting_h__ */ 68#endif /* __iwl_power_setting_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 271e5d1f842..c32ec809053 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -3845,26 +3845,11 @@ static ssize_t show_power_level(struct device *d,
3845{ 3845{
3846 struct iwl_priv *priv = dev_get_drvdata(d); 3846 struct iwl_priv *priv = dev_get_drvdata(d);
3847 int mode = priv->power_data.user_power_setting; 3847 int mode = priv->power_data.user_power_setting;
3848 int system = priv->power_data.system_power_setting;
3849 int level = priv->power_data.power_mode; 3848 int level = priv->power_data.power_mode;
3850 char *p = buf; 3849 char *p = buf;
3851 3850
3852 switch (system) { 3851 p += sprintf(p, "INDEX:%d\t", level);
3853 case IWL_POWER_SYS_AUTO: 3852 p += sprintf(p, "USER:%d\n", mode);
3854 p += sprintf(p, "SYSTEM:auto");
3855 break;
3856 case IWL_POWER_SYS_AC:
3857 p += sprintf(p, "SYSTEM:ac");
3858 break;
3859 case IWL_POWER_SYS_BATTERY:
3860 p += sprintf(p, "SYSTEM:battery");
3861 break;
3862 }
3863
3864 p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ?
3865 "fixed" : "auto");
3866 p += sprintf(p, "\tINDEX:%d", level);
3867 p += sprintf(p, "\n");
3868 return p - buf + 1; 3853 return p - buf + 1;
3869} 3854}
3870 3855
@@ -4108,7 +4093,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
4108 priv->ibss_beacon = NULL; 4093 priv->ibss_beacon = NULL;
4109 4094
4110 spin_lock_init(&priv->lock); 4095 spin_lock_init(&priv->lock);
4111 spin_lock_init(&priv->power_data.lock);
4112 spin_lock_init(&priv->sta_lock); 4096 spin_lock_init(&priv->sta_lock);
4113 spin_lock_init(&priv->hcmd_lock); 4097 spin_lock_init(&priv->hcmd_lock);
4114 4098