aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
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