aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2009-10-16 17:25:58 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-10-27 16:48:34 -0400
commit4ad177b5c860dc0b1083eccc55957daf4a116b90 (patch)
tree379f270437a2152f7628f0dcafaf77b58a8b6afd /drivers
parent9444b188022418c624ce32584c3b9544b500d15e (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')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c75
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h2
3 files changed, 59 insertions, 23 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index e78cd26b809f..8784911fd56e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -809,9 +809,12 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
809 if (value != -1 && (value < 0 || value >= IWL_POWER_NUM)) 809 if (value != -1 && (value < 0 || value >= IWL_POWER_NUM))
810 return -EINVAL; 810 return -EINVAL;
811 811
812 if (!iwl_is_ready_rf(priv))
813 return -EAGAIN;
814
812 priv->power_data.debug_sleep_level_override = value; 815 priv->power_data.debug_sleep_level_override = value;
813 816
814 iwl_power_update_mode(priv, false); 817 iwl_power_update_mode(priv, true);
815 818
816 return count; 819 return count;
817} 820}
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
67struct iwl_power_vec_entry { 67struct 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 */
86static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { 87static 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 */
96static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { 98static 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 - */
105static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { 108static 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
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index 310c32e8f698..0755518f86e1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -30,6 +30,8 @@
30 30
31#include "iwl-commands.h" 31#include "iwl-commands.h"
32 32
33#define IWL_CONN_LISTEN_INTERVAL 10
34
33#define IWL_ABSOLUTE_ZERO 0 35#define IWL_ABSOLUTE_ZERO 0
34#define IWL_ABSOLUTE_MAX 0xFFFFFFFF 36#define IWL_ABSOLUTE_MAX 0xFFFFFFFF
35#define IWL_TT_INCREASE_MARGIN 5 37#define IWL_TT_INCREASE_MARGIN 5