diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-debugfs.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.c | 75 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.h | 2 |
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 | ||
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 | ||
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 |