diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2009-10-16 17:25:58 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-10-27 16:48:34 -0400 |
commit | 4ad177b5c860dc0b1083eccc55957daf4a116b90 (patch) | |
tree | 379f270437a2152f7628f0dcafaf77b58a8b6afd /drivers/net/wireless/iwlwifi/iwl-power.c | |
parent | 9444b188022418c624ce32584c3b9544b500d15e (diff) |
iwlwifi: rework for static power save
For static power save, the actual intervals are calculated by driver based on
the default table and DTIM flag, then sent to uCode when the scheme
is changed.
Three tables are defined based on DTIM period.
1. DTIM 0 - 2
2. DTIM 3 - 10
3. DTIM > 11
The actual number of DTIM a station may miss may not exceed the
following:
. Only 1 DTIM may be skipped at PI=4 when allowed
. Only 2 DTIMs may be skipped at PI=5 when allowed
. DTIM may be skipped only 5 sec after last activity
. DTIM may be skipped only 30 sec after connection establishment
Only allow user to override the power_level when rf is ready to make sure
power level gets changed upon request.
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@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 | 75 |
1 files changed, 53 insertions, 22 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 9c6b14952061..150ff87af33b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c | |||
@@ -66,7 +66,7 @@ MODULE_PARM_DESC(no_sleep_autoadjust, | |||
66 | 66 | ||
67 | struct iwl_power_vec_entry { | 67 | struct iwl_power_vec_entry { |
68 | struct iwl_powertable_cmd cmd; | 68 | struct iwl_powertable_cmd cmd; |
69 | u8 no_dtim; | 69 | u8 no_dtim; /* number of skip dtim */ |
70 | }; | 70 | }; |
71 | 71 | ||
72 | #define IWL_DTIM_RANGE_0_MAX 2 | 72 | #define IWL_DTIM_RANGE_0_MAX 2 |
@@ -83,8 +83,9 @@ struct iwl_power_vec_entry { | |||
83 | cpu_to_le32(X4)} | 83 | cpu_to_le32(X4)} |
84 | /* default power management (not Tx power) table values */ | 84 | /* default power management (not Tx power) table values */ |
85 | /* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */ | 85 | /* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */ |
86 | /* DTIM 0 - 2 */ | ||
86 | static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { | 87 | static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { |
87 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, | 88 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 1, 2, 2, 0xFF)}, 0}, |
88 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, | 89 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, |
89 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, | 90 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, |
90 | {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1}, | 91 | {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1}, |
@@ -93,15 +94,17 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { | |||
93 | 94 | ||
94 | 95 | ||
95 | /* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */ | 96 | /* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */ |
97 | /* DTIM 3 - 10 */ | ||
96 | static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { | 98 | static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { |
97 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, | 99 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, |
98 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, | 100 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, |
99 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, | 101 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, |
100 | {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1}, | 102 | {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1}, |
101 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} | 103 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 6, 10, 10)}, 2} |
102 | }; | 104 | }; |
103 | 105 | ||
104 | /* for DTIM period > IWL_DTIM_RANGE_1_MAX */ | 106 | /* for DTIM period > IWL_DTIM_RANGE_1_MAX */ |
107 | /* DTIM 11 - */ | ||
105 | static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { | 108 | static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { |
106 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, | 109 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, |
107 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, | 110 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, |
@@ -115,13 +118,15 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, | |||
115 | enum iwl_power_level lvl, int period) | 118 | enum iwl_power_level lvl, int period) |
116 | { | 119 | { |
117 | const struct iwl_power_vec_entry *table; | 120 | const struct iwl_power_vec_entry *table; |
118 | int max_sleep, i; | 121 | int max_sleep[IWL_POWER_VEC_SIZE] = { 0 }; |
119 | bool skip; | 122 | int i; |
123 | u8 skip; | ||
124 | u32 slp_itrvl; | ||
120 | 125 | ||
121 | table = range_2; | 126 | table = range_2; |
122 | if (period < IWL_DTIM_RANGE_1_MAX) | 127 | if (period <= IWL_DTIM_RANGE_1_MAX) |
123 | table = range_1; | 128 | table = range_1; |
124 | if (period < IWL_DTIM_RANGE_0_MAX) | 129 | if (period <= IWL_DTIM_RANGE_0_MAX) |
125 | table = range_0; | 130 | table = range_0; |
126 | 131 | ||
127 | BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); | 132 | BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); |
@@ -129,34 +134,60 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, | |||
129 | *cmd = table[lvl].cmd; | 134 | *cmd = table[lvl].cmd; |
130 | 135 | ||
131 | if (period == 0) { | 136 | if (period == 0) { |
132 | skip = false; | 137 | skip = 0; |
133 | period = 1; | 138 | period = 1; |
139 | for (i = 0; i < IWL_POWER_VEC_SIZE; i++) | ||
140 | max_sleep[i] = 1; | ||
141 | |||
134 | } else { | 142 | } else { |
135 | skip = !!table[lvl].no_dtim; | 143 | skip = table[lvl].no_dtim; |
144 | for (i = 0; i < IWL_POWER_VEC_SIZE; i++) | ||
145 | max_sleep[i] = le32_to_cpu(cmd->sleep_interval[i]); | ||
146 | max_sleep[IWL_POWER_VEC_SIZE - 1] = skip + 1; | ||
136 | } | 147 | } |
137 | 148 | ||
138 | if (skip) { | 149 | slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]); |
139 | __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; | 150 | /* figure out the listen interval based on dtim period and skip */ |
140 | max_sleep = le32_to_cpu(slp_itrvl); | 151 | if (slp_itrvl == 0xFF) |
141 | if (max_sleep == 0xFF) | 152 | cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] = |
142 | max_sleep = period * (skip + 1); | 153 | cpu_to_le32(period * (skip + 1)); |
143 | else if (max_sleep > period) | 154 | |
144 | max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; | 155 | slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]); |
156 | if (slp_itrvl > period) | ||
157 | cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] = | ||
158 | cpu_to_le32((slp_itrvl / period) * period); | ||
159 | |||
160 | if (skip) | ||
145 | cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; | 161 | cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; |
146 | } else { | 162 | else |
147 | max_sleep = period; | ||
148 | cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; | 163 | cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; |
149 | } | ||
150 | 164 | ||
151 | for (i = 0; i < IWL_POWER_VEC_SIZE; i++) | 165 | slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]); |
152 | if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) | 166 | if (slp_itrvl > IWL_CONN_LISTEN_INTERVAL) |
153 | cmd->sleep_interval[i] = cpu_to_le32(max_sleep); | 167 | cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] = |
168 | cpu_to_le32(IWL_CONN_LISTEN_INTERVAL); | ||
169 | |||
170 | /* enforce max sleep interval */ | ||
171 | for (i = IWL_POWER_VEC_SIZE - 1; i >= 0 ; i--) { | ||
172 | if (le32_to_cpu(cmd->sleep_interval[i]) > | ||
173 | (max_sleep[i] * period)) | ||
174 | cmd->sleep_interval[i] = | ||
175 | cpu_to_le32(max_sleep[i] * period); | ||
176 | if (i != (IWL_POWER_VEC_SIZE - 1)) { | ||
177 | if (le32_to_cpu(cmd->sleep_interval[i]) > | ||
178 | le32_to_cpu(cmd->sleep_interval[i+1])) | ||
179 | cmd->sleep_interval[i] = | ||
180 | cmd->sleep_interval[i+1]; | ||
181 | } | ||
182 | } | ||
154 | 183 | ||
155 | if (priv->power_data.pci_pm) | 184 | if (priv->power_data.pci_pm) |
156 | cmd->flags |= IWL_POWER_PCI_PM_MSK; | 185 | cmd->flags |= IWL_POWER_PCI_PM_MSK; |
157 | else | 186 | else |
158 | cmd->flags &= ~IWL_POWER_PCI_PM_MSK; | 187 | cmd->flags &= ~IWL_POWER_PCI_PM_MSK; |
159 | 188 | ||
189 | IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n", | ||
190 | skip, period); | ||
160 | IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1); | 191 | IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1); |
161 | } | 192 | } |
162 | 193 | ||