diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm')
31 files changed, 3242 insertions, 995 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index 0fad98b85f60..5b630f12bbff 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c | |||
@@ -98,126 +98,258 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { | |||
98 | 98 | ||
99 | #undef EVENT_PRIO_ANT | 99 | #undef EVENT_PRIO_ANT |
100 | 100 | ||
101 | /* BT Antenna Coupling Threshold (dB) */ | ||
102 | #define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35) | ||
103 | #define IWL_BT_LOAD_FORCE_SISO_THRESHOLD (3) | ||
104 | |||
105 | #define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD (-62) | 101 | #define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD (-62) |
106 | #define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD (-65) | 102 | #define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD (-65) |
107 | #define BT_REDUCED_TX_POWER_BIT BIT(7) | 103 | #define BT_ANTENNA_COUPLING_THRESHOLD (30) |
108 | |||
109 | static inline bool is_loose_coex(void) | ||
110 | { | ||
111 | return iwlwifi_mod_params.ant_coupling > | ||
112 | IWL_BT_ANTENNA_COUPLING_THRESHOLD; | ||
113 | } | ||
114 | 104 | ||
115 | int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) | 105 | int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) |
116 | { | 106 | { |
107 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX)) | ||
108 | return 0; | ||
109 | |||
117 | return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, CMD_SYNC, | 110 | return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, CMD_SYNC, |
118 | sizeof(struct iwl_bt_coex_prio_tbl_cmd), | 111 | sizeof(struct iwl_bt_coex_prio_tbl_cmd), |
119 | &iwl_bt_prio_tbl); | 112 | &iwl_bt_prio_tbl); |
120 | } | 113 | } |
121 | 114 | ||
122 | static int iwl_send_bt_env(struct iwl_mvm *mvm, u8 action, u8 type) | 115 | const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = { |
123 | { | ||
124 | struct iwl_bt_coex_prot_env_cmd env_cmd; | ||
125 | int ret; | ||
126 | |||
127 | env_cmd.action = action; | ||
128 | env_cmd.type = type; | ||
129 | ret = iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PROT_ENV, CMD_SYNC, | ||
130 | sizeof(env_cmd), &env_cmd); | ||
131 | if (ret) | ||
132 | IWL_ERR(mvm, "failed to send BT env command\n"); | ||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | enum iwl_bt_kill_msk { | ||
137 | BT_KILL_MSK_DEFAULT, | ||
138 | BT_KILL_MSK_SCO_HID_A2DP, | ||
139 | BT_KILL_MSK_REDUCED_TXPOW, | ||
140 | BT_KILL_MSK_MAX, | ||
141 | }; | ||
142 | |||
143 | static const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = { | ||
144 | [BT_KILL_MSK_DEFAULT] = 0xffff0000, | 116 | [BT_KILL_MSK_DEFAULT] = 0xffff0000, |
145 | [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, | 117 | [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, |
146 | [BT_KILL_MSK_REDUCED_TXPOW] = 0, | 118 | [BT_KILL_MSK_REDUCED_TXPOW] = 0, |
147 | }; | 119 | }; |
148 | 120 | ||
149 | static const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = { | 121 | const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = { |
150 | [BT_KILL_MSK_DEFAULT] = 0xffff0000, | 122 | [BT_KILL_MSK_DEFAULT] = 0xffff0000, |
151 | [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, | 123 | [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, |
152 | [BT_KILL_MSK_REDUCED_TXPOW] = 0, | 124 | [BT_KILL_MSK_REDUCED_TXPOW] = 0, |
153 | }; | 125 | }; |
154 | 126 | ||
155 | #define IWL_BT_DEFAULT_BOOST (0xf0f0f0f0) | 127 | static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = { |
156 | 128 | cpu_to_le32(0xf0f0f0f0), | |
157 | /* Tight Coex */ | 129 | cpu_to_le32(0xc0c0c0c0), |
158 | static const __le32 iwl_tight_lookup[BT_COEX_LUT_SIZE] = { | 130 | cpu_to_le32(0xfcfcfcfc), |
159 | cpu_to_le32(0xaaaaaaaa), | 131 | cpu_to_le32(0xff00ff00), |
160 | cpu_to_le32(0xaaaaaaaa), | ||
161 | cpu_to_le32(0xaeaaaaaa), | ||
162 | cpu_to_le32(0xaaaaaaaa), | ||
163 | cpu_to_le32(0xcc00ff28), | ||
164 | cpu_to_le32(0x0000aaaa), | ||
165 | cpu_to_le32(0xcc00aaaa), | ||
166 | cpu_to_le32(0x0000aaaa), | ||
167 | cpu_to_le32(0xc0004000), | ||
168 | cpu_to_le32(0x00000000), | ||
169 | cpu_to_le32(0xf0005000), | ||
170 | cpu_to_le32(0xf0005000), | ||
171 | }; | 132 | }; |
172 | 133 | ||
173 | /* Loose Coex */ | 134 | static const __le32 iwl_single_shared_ant[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = { |
174 | static const __le32 iwl_loose_lookup[BT_COEX_LUT_SIZE] = { | 135 | { |
175 | cpu_to_le32(0xaaaaaaaa), | 136 | cpu_to_le32(0x40000000), |
176 | cpu_to_le32(0xaaaaaaaa), | 137 | cpu_to_le32(0x00000000), |
177 | cpu_to_le32(0xaaaaaaaa), | 138 | cpu_to_le32(0x44000000), |
178 | cpu_to_le32(0xaaaaaaaa), | 139 | cpu_to_le32(0x00000000), |
179 | cpu_to_le32(0xcc00ff28), | 140 | cpu_to_le32(0x40000000), |
180 | cpu_to_le32(0x0000aaaa), | 141 | cpu_to_le32(0x00000000), |
181 | cpu_to_le32(0xcc00aaaa), | 142 | cpu_to_le32(0x44000000), |
182 | cpu_to_le32(0x0000aaaa), | 143 | cpu_to_le32(0x00000000), |
183 | cpu_to_le32(0x00000000), | 144 | cpu_to_le32(0xc0004000), |
184 | cpu_to_le32(0x00000000), | 145 | cpu_to_le32(0xf0005000), |
185 | cpu_to_le32(0xf0005000), | 146 | cpu_to_le32(0xc0004000), |
186 | cpu_to_le32(0xf0005000), | 147 | cpu_to_le32(0xf0005000), |
148 | }, | ||
149 | { | ||
150 | cpu_to_le32(0x40000000), | ||
151 | cpu_to_le32(0x00000000), | ||
152 | cpu_to_le32(0x44000000), | ||
153 | cpu_to_le32(0x00000000), | ||
154 | cpu_to_le32(0x40000000), | ||
155 | cpu_to_le32(0x00000000), | ||
156 | cpu_to_le32(0x44000000), | ||
157 | cpu_to_le32(0x00000000), | ||
158 | cpu_to_le32(0xc0004000), | ||
159 | cpu_to_le32(0xf0005000), | ||
160 | cpu_to_le32(0xc0004000), | ||
161 | cpu_to_le32(0xf0005000), | ||
162 | }, | ||
163 | { | ||
164 | cpu_to_le32(0x40000000), | ||
165 | cpu_to_le32(0x00000000), | ||
166 | cpu_to_le32(0x44000000), | ||
167 | cpu_to_le32(0x00000000), | ||
168 | cpu_to_le32(0x40000000), | ||
169 | cpu_to_le32(0x00000000), | ||
170 | cpu_to_le32(0x44000000), | ||
171 | cpu_to_le32(0x00000000), | ||
172 | cpu_to_le32(0xc0004000), | ||
173 | cpu_to_le32(0xf0005000), | ||
174 | cpu_to_le32(0xc0004000), | ||
175 | cpu_to_le32(0xf0005000), | ||
176 | }, | ||
187 | }; | 177 | }; |
188 | 178 | ||
189 | /* Full concurrency */ | 179 | static const __le32 iwl_combined_lookup[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = { |
190 | static const __le32 iwl_concurrent_lookup[BT_COEX_LUT_SIZE] = { | 180 | { |
191 | cpu_to_le32(0xaaaaaaaa), | 181 | /* Tight */ |
192 | cpu_to_le32(0xaaaaaaaa), | 182 | cpu_to_le32(0xaaaaaaaa), |
193 | cpu_to_le32(0xaaaaaaaa), | 183 | cpu_to_le32(0xaaaaaaaa), |
194 | cpu_to_le32(0xaaaaaaaa), | 184 | cpu_to_le32(0xaeaaaaaa), |
195 | cpu_to_le32(0xaaaaaaaa), | 185 | cpu_to_le32(0xaaaaaaaa), |
196 | cpu_to_le32(0xaaaaaaaa), | 186 | cpu_to_le32(0xcc00ff28), |
197 | cpu_to_le32(0xaaaaaaaa), | 187 | cpu_to_le32(0x0000aaaa), |
198 | cpu_to_le32(0xaaaaaaaa), | 188 | cpu_to_le32(0xcc00aaaa), |
199 | cpu_to_le32(0x00000000), | 189 | cpu_to_le32(0x0000aaaa), |
200 | cpu_to_le32(0x00000000), | 190 | cpu_to_le32(0xc0004000), |
201 | cpu_to_le32(0x00000000), | 191 | cpu_to_le32(0x00000000), |
202 | cpu_to_le32(0x00000000), | 192 | cpu_to_le32(0xf0005000), |
193 | cpu_to_le32(0xf0005000), | ||
194 | }, | ||
195 | { | ||
196 | /* Loose */ | ||
197 | cpu_to_le32(0xaaaaaaaa), | ||
198 | cpu_to_le32(0xaaaaaaaa), | ||
199 | cpu_to_le32(0xaaaaaaaa), | ||
200 | cpu_to_le32(0xaaaaaaaa), | ||
201 | cpu_to_le32(0xcc00ff28), | ||
202 | cpu_to_le32(0x0000aaaa), | ||
203 | cpu_to_le32(0xcc00aaaa), | ||
204 | cpu_to_le32(0x0000aaaa), | ||
205 | cpu_to_le32(0x00000000), | ||
206 | cpu_to_le32(0x00000000), | ||
207 | cpu_to_le32(0xf0005000), | ||
208 | cpu_to_le32(0xf0005000), | ||
209 | }, | ||
210 | { | ||
211 | /* Tx Tx disabled */ | ||
212 | cpu_to_le32(0xaaaaaaaa), | ||
213 | cpu_to_le32(0xaaaaaaaa), | ||
214 | cpu_to_le32(0xaaaaaaaa), | ||
215 | cpu_to_le32(0xaaaaaaaa), | ||
216 | cpu_to_le32(0xcc00ff28), | ||
217 | cpu_to_le32(0x0000aaaa), | ||
218 | cpu_to_le32(0xcc00aaaa), | ||
219 | cpu_to_le32(0x0000aaaa), | ||
220 | cpu_to_le32(0xC0004000), | ||
221 | cpu_to_le32(0xC0004000), | ||
222 | cpu_to_le32(0xF0005000), | ||
223 | cpu_to_le32(0xF0005000), | ||
224 | }, | ||
203 | }; | 225 | }; |
204 | 226 | ||
205 | /* single shared antenna */ | 227 | /* 20MHz / 40MHz below / 40Mhz above*/ |
206 | static const __le32 iwl_single_shared_ant_lookup[BT_COEX_LUT_SIZE] = { | 228 | static const __le64 iwl_ci_mask[][3] = { |
207 | cpu_to_le32(0x40000000), | 229 | /* dummy entry for channel 0 */ |
208 | cpu_to_le32(0x00000000), | 230 | {cpu_to_le64(0), cpu_to_le64(0), cpu_to_le64(0)}, |
209 | cpu_to_le32(0x44000000), | 231 | { |
210 | cpu_to_le32(0x00000000), | 232 | cpu_to_le64(0x0000001FFFULL), |
211 | cpu_to_le32(0x40000000), | 233 | cpu_to_le64(0x0ULL), |
212 | cpu_to_le32(0x00000000), | 234 | cpu_to_le64(0x00007FFFFFULL), |
213 | cpu_to_le32(0x44000000), | 235 | }, |
214 | cpu_to_le32(0x00000000), | 236 | { |
215 | cpu_to_le32(0xC0004000), | 237 | cpu_to_le64(0x000000FFFFULL), |
216 | cpu_to_le32(0xF0005000), | 238 | cpu_to_le64(0x0ULL), |
217 | cpu_to_le32(0xC0004000), | 239 | cpu_to_le64(0x0003FFFFFFULL), |
218 | cpu_to_le32(0xF0005000), | 240 | }, |
241 | { | ||
242 | cpu_to_le64(0x000003FFFCULL), | ||
243 | cpu_to_le64(0x0ULL), | ||
244 | cpu_to_le64(0x000FFFFFFCULL), | ||
245 | }, | ||
246 | { | ||
247 | cpu_to_le64(0x00001FFFE0ULL), | ||
248 | cpu_to_le64(0x0ULL), | ||
249 | cpu_to_le64(0x007FFFFFE0ULL), | ||
250 | }, | ||
251 | { | ||
252 | cpu_to_le64(0x00007FFF80ULL), | ||
253 | cpu_to_le64(0x00007FFFFFULL), | ||
254 | cpu_to_le64(0x01FFFFFF80ULL), | ||
255 | }, | ||
256 | { | ||
257 | cpu_to_le64(0x0003FFFC00ULL), | ||
258 | cpu_to_le64(0x0003FFFFFFULL), | ||
259 | cpu_to_le64(0x0FFFFFFC00ULL), | ||
260 | }, | ||
261 | { | ||
262 | cpu_to_le64(0x000FFFF000ULL), | ||
263 | cpu_to_le64(0x000FFFFFFCULL), | ||
264 | cpu_to_le64(0x3FFFFFF000ULL), | ||
265 | }, | ||
266 | { | ||
267 | cpu_to_le64(0x007FFF8000ULL), | ||
268 | cpu_to_le64(0x007FFFFFE0ULL), | ||
269 | cpu_to_le64(0xFFFFFF8000ULL), | ||
270 | }, | ||
271 | { | ||
272 | cpu_to_le64(0x01FFFE0000ULL), | ||
273 | cpu_to_le64(0x01FFFFFF80ULL), | ||
274 | cpu_to_le64(0xFFFFFE0000ULL), | ||
275 | }, | ||
276 | { | ||
277 | cpu_to_le64(0x0FFFF00000ULL), | ||
278 | cpu_to_le64(0x0FFFFFFC00ULL), | ||
279 | cpu_to_le64(0x0ULL), | ||
280 | }, | ||
281 | { | ||
282 | cpu_to_le64(0x3FFFC00000ULL), | ||
283 | cpu_to_le64(0x3FFFFFF000ULL), | ||
284 | cpu_to_le64(0x0) | ||
285 | }, | ||
286 | { | ||
287 | cpu_to_le64(0xFFFE000000ULL), | ||
288 | cpu_to_le64(0xFFFFFF8000ULL), | ||
289 | cpu_to_le64(0x0) | ||
290 | }, | ||
291 | { | ||
292 | cpu_to_le64(0xFFF8000000ULL), | ||
293 | cpu_to_le64(0xFFFFFE0000ULL), | ||
294 | cpu_to_le64(0x0) | ||
295 | }, | ||
296 | { | ||
297 | cpu_to_le64(0xFE00000000ULL), | ||
298 | cpu_to_le64(0x0ULL), | ||
299 | cpu_to_le64(0x0) | ||
300 | }, | ||
219 | }; | 301 | }; |
220 | 302 | ||
303 | static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = { | ||
304 | cpu_to_le32(0x22002200), | ||
305 | cpu_to_le32(0x33113311), | ||
306 | }; | ||
307 | |||
308 | static enum iwl_bt_coex_lut_type | ||
309 | iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) | ||
310 | { | ||
311 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
312 | enum iwl_bt_coex_lut_type ret; | ||
313 | u16 phy_ctx_id; | ||
314 | |||
315 | /* | ||
316 | * Checking that we hold mvm->mutex is a good idea, but the rate | ||
317 | * control can't acquire the mutex since it runs in Tx path. | ||
318 | * So this is racy in that case, but in the worst case, the AMPDU | ||
319 | * size limit will be wrong for a short time which is not a big | ||
320 | * issue. | ||
321 | */ | ||
322 | |||
323 | rcu_read_lock(); | ||
324 | |||
325 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
326 | |||
327 | if (!chanctx_conf || | ||
328 | chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) { | ||
329 | rcu_read_unlock(); | ||
330 | return BT_COEX_LOOSE_LUT; | ||
331 | } | ||
332 | |||
333 | ret = BT_COEX_TX_DIS_LUT; | ||
334 | |||
335 | if (mvm->cfg->bt_shared_single_ant) { | ||
336 | rcu_read_unlock(); | ||
337 | return ret; | ||
338 | } | ||
339 | |||
340 | phy_ctx_id = *((u16 *)chanctx_conf->drv_priv); | ||
341 | |||
342 | if (mvm->last_bt_ci_cmd.primary_ch_phy_id == phy_ctx_id) | ||
343 | ret = le32_to_cpu(mvm->last_bt_notif.primary_ch_lut); | ||
344 | else if (mvm->last_bt_ci_cmd.secondary_ch_phy_id == phy_ctx_id) | ||
345 | ret = le32_to_cpu(mvm->last_bt_notif.secondary_ch_lut); | ||
346 | /* else - default = TX TX disallowed */ | ||
347 | |||
348 | rcu_read_unlock(); | ||
349 | |||
350 | return ret; | ||
351 | } | ||
352 | |||
221 | int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | 353 | int iwl_send_bt_init_conf(struct iwl_mvm *mvm) |
222 | { | 354 | { |
223 | struct iwl_bt_coex_cmd *bt_cmd; | 355 | struct iwl_bt_coex_cmd *bt_cmd; |
@@ -228,17 +360,10 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | |||
228 | .flags = CMD_SYNC, | 360 | .flags = CMD_SYNC, |
229 | }; | 361 | }; |
230 | int ret; | 362 | int ret; |
363 | u32 flags; | ||
231 | 364 | ||
232 | /* go to CALIB state in internal BT-Coex state machine */ | 365 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX)) |
233 | ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN, | 366 | return 0; |
234 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); | ||
235 | if (ret) | ||
236 | return ret; | ||
237 | |||
238 | ret = iwl_send_bt_env(mvm, BT_COEX_ENV_CLOSE, | ||
239 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); | ||
240 | if (ret) | ||
241 | return ret; | ||
242 | 367 | ||
243 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); | 368 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); |
244 | if (!bt_cmd) | 369 | if (!bt_cmd) |
@@ -246,40 +371,52 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | |||
246 | cmd.data[0] = bt_cmd; | 371 | cmd.data[0] = bt_cmd; |
247 | 372 | ||
248 | bt_cmd->max_kill = 5; | 373 | bt_cmd->max_kill = 5; |
249 | bt_cmd->bt3_time_t7_value = 1; | 374 | bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD, |
250 | bt_cmd->bt3_prio_sample_time = 2; | 375 | bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling, |
251 | bt_cmd->bt3_timer_t2_value = 0xc; | 376 | bt_cmd->bt4_tx_tx_delta_freq_thr = 15, |
377 | bt_cmd->bt4_tx_rx_max_freq0 = 15, | ||
252 | 378 | ||
253 | bt_cmd->flags = iwlwifi_mod_params.bt_coex_active ? | 379 | flags = iwlwifi_mod_params.bt_coex_active ? |
254 | BT_COEX_NW : BT_COEX_DISABLE; | 380 | BT_COEX_NW : BT_COEX_DISABLE; |
255 | bt_cmd->flags |= BT_CH_PRIMARY_EN | BT_SYNC_2_BT_DISABLE; | 381 | flags |= BT_CH_PRIMARY_EN | BT_CH_SECONDARY_EN | BT_SYNC_2_BT_DISABLE; |
382 | bt_cmd->flags = cpu_to_le32(flags); | ||
256 | 383 | ||
257 | bt_cmd->valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE | | 384 | bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE | |
258 | BT_VALID_BT_PRIO_BOOST | | 385 | BT_VALID_BT_PRIO_BOOST | |
259 | BT_VALID_MAX_KILL | | 386 | BT_VALID_MAX_KILL | |
260 | BT_VALID_3W_TMRS | | 387 | BT_VALID_3W_TMRS | |
261 | BT_VALID_KILL_ACK | | 388 | BT_VALID_KILL_ACK | |
262 | BT_VALID_KILL_CTS | | 389 | BT_VALID_KILL_CTS | |
263 | BT_VALID_REDUCED_TX_POWER | | 390 | BT_VALID_REDUCED_TX_POWER | |
264 | BT_VALID_LUT); | 391 | BT_VALID_LUT | |
392 | BT_VALID_WIFI_RX_SW_PRIO_BOOST | | ||
393 | BT_VALID_WIFI_TX_SW_PRIO_BOOST | | ||
394 | BT_VALID_MULTI_PRIO_LUT | | ||
395 | BT_VALID_CORUN_LUT_20 | | ||
396 | BT_VALID_CORUN_LUT_40 | | ||
397 | BT_VALID_ANT_ISOLATION | | ||
398 | BT_VALID_ANT_ISOLATION_THRS | | ||
399 | BT_VALID_TXTX_DELTA_FREQ_THRS | | ||
400 | BT_VALID_TXRX_MAX_FREQ_0); | ||
265 | 401 | ||
266 | if (mvm->cfg->bt_shared_single_ant) | 402 | if (mvm->cfg->bt_shared_single_ant) |
267 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant_lookup, | 403 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, |
268 | sizeof(iwl_single_shared_ant_lookup)); | 404 | sizeof(iwl_single_shared_ant)); |
269 | else if (is_loose_coex()) | ||
270 | memcpy(&bt_cmd->decision_lut, iwl_loose_lookup, | ||
271 | sizeof(iwl_tight_lookup)); | ||
272 | else | 405 | else |
273 | memcpy(&bt_cmd->decision_lut, iwl_tight_lookup, | 406 | memcpy(&bt_cmd->decision_lut, iwl_combined_lookup, |
274 | sizeof(iwl_tight_lookup)); | 407 | sizeof(iwl_combined_lookup)); |
275 | 408 | ||
276 | bt_cmd->bt_prio_boost = cpu_to_le32(IWL_BT_DEFAULT_BOOST); | 409 | memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost, |
410 | sizeof(iwl_bt_prio_boost)); | ||
411 | memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, | ||
412 | sizeof(iwl_bt_mprio_lut)); | ||
277 | bt_cmd->kill_ack_msk = | 413 | bt_cmd->kill_ack_msk = |
278 | cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); | 414 | cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); |
279 | bt_cmd->kill_cts_msk = | 415 | bt_cmd->kill_cts_msk = |
280 | cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); | 416 | cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); |
281 | 417 | ||
282 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | 418 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); |
419 | memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); | ||
283 | 420 | ||
284 | ret = iwl_mvm_send_cmd(mvm, &cmd); | 421 | ret = iwl_mvm_send_cmd(mvm, &cmd); |
285 | 422 | ||
@@ -334,13 +471,17 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, | |||
334 | if (!bt_cmd) | 471 | if (!bt_cmd) |
335 | return -ENOMEM; | 472 | return -ENOMEM; |
336 | cmd.data[0] = bt_cmd; | 473 | cmd.data[0] = bt_cmd; |
474 | bt_cmd->flags = cpu_to_le32(BT_COEX_NW); | ||
337 | 475 | ||
338 | bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); | 476 | bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); |
339 | bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); | 477 | bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); |
340 | bt_cmd->valid_bit_msk = | 478 | bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | |
341 | cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS); | 479 | BT_VALID_KILL_ACK | |
480 | BT_VALID_KILL_CTS); | ||
342 | 481 | ||
343 | IWL_DEBUG_COEX(mvm, "bt_kill_msk = %d\n", bt_kill_msk); | 482 | IWL_DEBUG_COEX(mvm, "ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x\n", |
483 | iwl_bt_ack_kill_msk[bt_kill_msk], | ||
484 | iwl_bt_cts_kill_msk[bt_kill_msk]); | ||
344 | 485 | ||
345 | ret = iwl_mvm_send_cmd(mvm, &cmd); | 486 | ret = iwl_mvm_send_cmd(mvm, &cmd); |
346 | 487 | ||
@@ -380,8 +521,10 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, | |||
380 | if (!bt_cmd) | 521 | if (!bt_cmd) |
381 | return -ENOMEM; | 522 | return -ENOMEM; |
382 | cmd.data[0] = bt_cmd; | 523 | cmd.data[0] = bt_cmd; |
524 | bt_cmd->flags = cpu_to_le32(BT_COEX_NW); | ||
383 | 525 | ||
384 | bt_cmd->valid_bit_msk = cpu_to_le16(BT_VALID_REDUCED_TX_POWER), | 526 | bt_cmd->valid_bit_msk = |
527 | cpu_to_le32(BT_VALID_ENABLE | BT_VALID_REDUCED_TX_POWER); | ||
385 | bt_cmd->bt_reduced_tx_power = sta_id; | 528 | bt_cmd->bt_reduced_tx_power = sta_id; |
386 | 529 | ||
387 | if (enable) | 530 | if (enable) |
@@ -403,8 +546,25 @@ struct iwl_bt_iterator_data { | |||
403 | struct iwl_mvm *mvm; | 546 | struct iwl_mvm *mvm; |
404 | u32 num_bss_ifaces; | 547 | u32 num_bss_ifaces; |
405 | bool reduced_tx_power; | 548 | bool reduced_tx_power; |
549 | struct ieee80211_chanctx_conf *primary; | ||
550 | struct ieee80211_chanctx_conf *secondary; | ||
406 | }; | 551 | }; |
407 | 552 | ||
553 | static inline | ||
554 | void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm, | ||
555 | struct ieee80211_vif *vif, | ||
556 | bool enable, int rssi) | ||
557 | { | ||
558 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
559 | |||
560 | mvmvif->bf_data.last_bt_coex_event = rssi; | ||
561 | mvmvif->bf_data.bt_coex_max_thold = | ||
562 | enable ? BT_ENABLE_REDUCED_TXPOWER_THRESHOLD : 0; | ||
563 | mvmvif->bf_data.bt_coex_min_thold = | ||
564 | enable ? BT_DISABLE_REDUCED_TXPOWER_THRESHOLD : 0; | ||
565 | } | ||
566 | |||
567 | /* must be called under rcu_read_lock */ | ||
408 | static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | 568 | static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, |
409 | struct ieee80211_vif *vif) | 569 | struct ieee80211_vif *vif) |
410 | { | 570 | { |
@@ -413,65 +573,94 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
413 | struct iwl_mvm *mvm = data->mvm; | 573 | struct iwl_mvm *mvm = data->mvm; |
414 | struct ieee80211_chanctx_conf *chanctx_conf; | 574 | struct ieee80211_chanctx_conf *chanctx_conf; |
415 | enum ieee80211_smps_mode smps_mode; | 575 | enum ieee80211_smps_mode smps_mode; |
416 | enum ieee80211_band band; | ||
417 | int ave_rssi; | 576 | int ave_rssi; |
418 | 577 | ||
419 | lockdep_assert_held(&mvm->mutex); | 578 | lockdep_assert_held(&mvm->mutex); |
420 | if (vif->type != NL80211_IFTYPE_STATION) | ||
421 | return; | ||
422 | 579 | ||
423 | rcu_read_lock(); | 580 | if (vif->type != NL80211_IFTYPE_STATION && |
424 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | 581 | vif->type != NL80211_IFTYPE_AP) |
425 | if (chanctx_conf && chanctx_conf->def.chan) | 582 | return; |
426 | band = chanctx_conf->def.chan->band; | ||
427 | else | ||
428 | band = -1; | ||
429 | rcu_read_unlock(); | ||
430 | 583 | ||
431 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 584 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
432 | 585 | ||
433 | /* non associated BSSes aren't to be considered */ | 586 | chanctx_conf = rcu_dereference(vif->chanctx_conf); |
434 | if (!vif->bss_conf.assoc) | 587 | |
588 | /* If channel context is invalid or not on 2.4GHz .. */ | ||
589 | if ((!chanctx_conf || | ||
590 | chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { | ||
591 | /* ... and it is an associated STATION, relax constraints */ | ||
592 | if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc) | ||
593 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
594 | smps_mode); | ||
595 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); | ||
435 | return; | 596 | return; |
597 | } | ||
598 | |||
599 | /* SoftAP / GO will always be primary */ | ||
600 | if (vif->type == NL80211_IFTYPE_AP) { | ||
601 | if (!mvmvif->ap_ibss_active) | ||
602 | return; | ||
603 | |||
604 | /* the Ack / Cts kill mask must be default if AP / GO */ | ||
605 | data->reduced_tx_power = false; | ||
436 | 606 | ||
437 | if (band != IEEE80211_BAND_2GHZ) { | 607 | if (chanctx_conf == data->primary) |
438 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | 608 | return; |
439 | smps_mode); | 609 | |
610 | /* downgrade the current primary no matter what its type is */ | ||
611 | data->secondary = data->primary; | ||
612 | data->primary = chanctx_conf; | ||
440 | return; | 613 | return; |
441 | } | 614 | } |
442 | 615 | ||
443 | if (data->notif->bt_status) | 616 | data->num_bss_ifaces++; |
444 | smps_mode = IEEE80211_SMPS_DYNAMIC; | 617 | |
618 | /* we are now a STA / P2P Client, and take associated ones only */ | ||
619 | if (!vif->bss_conf.assoc) | ||
620 | return; | ||
621 | |||
622 | /* STA / P2P Client, try to be primary if first vif */ | ||
623 | if (!data->primary || data->primary == chanctx_conf) | ||
624 | data->primary = chanctx_conf; | ||
625 | else if (!data->secondary) | ||
626 | /* if secondary is not NULL, it might be a GO */ | ||
627 | data->secondary = chanctx_conf; | ||
445 | 628 | ||
446 | if (data->notif->bt_traffic_load >= IWL_BT_LOAD_FORCE_SISO_THRESHOLD) | 629 | if (le32_to_cpu(data->notif->bt_activity_grading) >= BT_HIGH_TRAFFIC) |
447 | smps_mode = IEEE80211_SMPS_STATIC; | 630 | smps_mode = IEEE80211_SMPS_STATIC; |
631 | else if (le32_to_cpu(data->notif->bt_activity_grading) >= | ||
632 | BT_LOW_TRAFFIC) | ||
633 | smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
448 | 634 | ||
449 | IWL_DEBUG_COEX(data->mvm, | 635 | IWL_DEBUG_COEX(data->mvm, |
450 | "mac %d: bt_status %d traffic_load %d smps_req %d\n", | 636 | "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", |
451 | mvmvif->id, data->notif->bt_status, | 637 | mvmvif->id, data->notif->bt_status, |
452 | data->notif->bt_traffic_load, smps_mode); | 638 | data->notif->bt_activity_grading, smps_mode); |
453 | 639 | ||
454 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); | 640 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); |
455 | 641 | ||
456 | /* don't reduce the Tx power if in loose scheme */ | 642 | /* don't reduce the Tx power if in loose scheme */ |
457 | if (is_loose_coex()) | 643 | if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || |
644 | mvm->cfg->bt_shared_single_ant) { | ||
645 | data->reduced_tx_power = false; | ||
646 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); | ||
458 | return; | 647 | return; |
648 | } | ||
459 | 649 | ||
460 | data->num_bss_ifaces++; | 650 | /* reduced Txpower only if BT is on, so ...*/ |
461 | 651 | if (!data->notif->bt_status) { | |
462 | /* reduced Txpower only if there are open BT connections, so ...*/ | ||
463 | if (!BT_MBOX_MSG(data->notif, 3, OPEN_CON_2)) { | ||
464 | /* ... cancel reduced Tx power ... */ | 652 | /* ... cancel reduced Tx power ... */ |
465 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) | 653 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) |
466 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); | 654 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); |
467 | data->reduced_tx_power = false; | 655 | data->reduced_tx_power = false; |
468 | 656 | ||
469 | /* ... and there is no need to get reports on RSSI any more. */ | 657 | /* ... and there is no need to get reports on RSSI any more. */ |
470 | ieee80211_disable_rssi_reports(vif); | 658 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); |
471 | return; | 659 | return; |
472 | } | 660 | } |
473 | 661 | ||
474 | ave_rssi = ieee80211_ave_rssi(vif); | 662 | /* try to get the avg rssi from fw */ |
663 | ave_rssi = mvmvif->bf_data.ave_beacon_signal; | ||
475 | 664 | ||
476 | /* if the RSSI isn't valid, fake it is very low */ | 665 | /* if the RSSI isn't valid, fake it is very low */ |
477 | if (!ave_rssi) | 666 | if (!ave_rssi) |
@@ -499,8 +688,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
499 | } | 688 | } |
500 | 689 | ||
501 | /* Begin to monitor the RSSI: it may influence the reduced Tx power */ | 690 | /* Begin to monitor the RSSI: it may influence the reduced Tx power */ |
502 | ieee80211_enable_rssi_reports(vif, BT_DISABLE_REDUCED_TXPOWER_THRESHOLD, | 691 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi); |
503 | BT_ENABLE_REDUCED_TXPOWER_THRESHOLD); | ||
504 | } | 692 | } |
505 | 693 | ||
506 | static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) | 694 | static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) |
@@ -510,11 +698,72 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) | |||
510 | .notif = &mvm->last_bt_notif, | 698 | .notif = &mvm->last_bt_notif, |
511 | .reduced_tx_power = true, | 699 | .reduced_tx_power = true, |
512 | }; | 700 | }; |
701 | struct iwl_bt_coex_ci_cmd cmd = {}; | ||
702 | u8 ci_bw_idx; | ||
513 | 703 | ||
704 | rcu_read_lock(); | ||
514 | ieee80211_iterate_active_interfaces_atomic( | 705 | ieee80211_iterate_active_interfaces_atomic( |
515 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | 706 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, |
516 | iwl_mvm_bt_notif_iterator, &data); | 707 | iwl_mvm_bt_notif_iterator, &data); |
517 | 708 | ||
709 | if (data.primary) { | ||
710 | struct ieee80211_chanctx_conf *chan = data.primary; | ||
711 | if (WARN_ON(!chan->def.chan)) { | ||
712 | rcu_read_unlock(); | ||
713 | return; | ||
714 | } | ||
715 | |||
716 | if (chan->def.width < NL80211_CHAN_WIDTH_40) { | ||
717 | ci_bw_idx = 0; | ||
718 | cmd.co_run_bw_primary = 0; | ||
719 | } else { | ||
720 | cmd.co_run_bw_primary = 1; | ||
721 | if (chan->def.center_freq1 > | ||
722 | chan->def.chan->center_freq) | ||
723 | ci_bw_idx = 2; | ||
724 | else | ||
725 | ci_bw_idx = 1; | ||
726 | } | ||
727 | |||
728 | cmd.bt_primary_ci = | ||
729 | iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; | ||
730 | cmd.primary_ch_phy_id = *((u16 *)data.primary->drv_priv); | ||
731 | } | ||
732 | |||
733 | if (data.secondary) { | ||
734 | struct ieee80211_chanctx_conf *chan = data.secondary; | ||
735 | if (WARN_ON(!data.secondary->def.chan)) { | ||
736 | rcu_read_unlock(); | ||
737 | return; | ||
738 | } | ||
739 | |||
740 | if (chan->def.width < NL80211_CHAN_WIDTH_40) { | ||
741 | ci_bw_idx = 0; | ||
742 | cmd.co_run_bw_secondary = 0; | ||
743 | } else { | ||
744 | cmd.co_run_bw_secondary = 1; | ||
745 | if (chan->def.center_freq1 > | ||
746 | chan->def.chan->center_freq) | ||
747 | ci_bw_idx = 2; | ||
748 | else | ||
749 | ci_bw_idx = 1; | ||
750 | } | ||
751 | |||
752 | cmd.bt_secondary_ci = | ||
753 | iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; | ||
754 | cmd.secondary_ch_phy_id = *((u16 *)data.primary->drv_priv); | ||
755 | } | ||
756 | |||
757 | rcu_read_unlock(); | ||
758 | |||
759 | /* Don't spam the fw with the same command over and over */ | ||
760 | if (memcmp(&cmd, &mvm->last_bt_ci_cmd, sizeof(cmd))) { | ||
761 | if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_CI, CMD_SYNC, | ||
762 | sizeof(cmd), &cmd)) | ||
763 | IWL_ERR(mvm, "Failed to send BT_CI cmd"); | ||
764 | memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd)); | ||
765 | } | ||
766 | |||
518 | /* | 767 | /* |
519 | * If there are no BSS / P2P client interfaces, reduced Tx Power is | 768 | * If there are no BSS / P2P client interfaces, reduced Tx Power is |
520 | * irrelevant since it is based on the RSSI coming from the beacon. | 769 | * irrelevant since it is based on the RSSI coming from the beacon. |
@@ -536,12 +785,18 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, | |||
536 | 785 | ||
537 | 786 | ||
538 | IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); | 787 | IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); |
539 | IWL_DEBUG_COEX(mvm, "\tBT %salive\n", notif->bt_status ? "" : "not "); | 788 | IWL_DEBUG_COEX(mvm, "\tBT status: %s\n", |
789 | notif->bt_status ? "ON" : "OFF"); | ||
540 | IWL_DEBUG_COEX(mvm, "\tBT open conn %d\n", notif->bt_open_conn); | 790 | IWL_DEBUG_COEX(mvm, "\tBT open conn %d\n", notif->bt_open_conn); |
541 | IWL_DEBUG_COEX(mvm, "\tBT traffic load %d\n", notif->bt_traffic_load); | 791 | IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); |
792 | IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n", | ||
793 | le32_to_cpu(notif->primary_ch_lut)); | ||
794 | IWL_DEBUG_COEX(mvm, "\tBT secondary_ch_lut %d\n", | ||
795 | le32_to_cpu(notif->secondary_ch_lut)); | ||
796 | IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n", | ||
797 | le32_to_cpu(notif->bt_activity_grading)); | ||
542 | IWL_DEBUG_COEX(mvm, "\tBT agg traffic load %d\n", | 798 | IWL_DEBUG_COEX(mvm, "\tBT agg traffic load %d\n", |
543 | notif->bt_agg_traffic_load); | 799 | notif->bt_agg_traffic_load); |
544 | IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); | ||
545 | 800 | ||
546 | /* remember this notification for future use: rssi fluctuations */ | 801 | /* remember this notification for future use: rssi fluctuations */ |
547 | memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif)); | 802 | memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif)); |
@@ -565,6 +820,18 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, | |||
565 | struct ieee80211_sta *sta; | 820 | struct ieee80211_sta *sta; |
566 | struct iwl_mvm_sta *mvmsta; | 821 | struct iwl_mvm_sta *mvmsta; |
567 | 822 | ||
823 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
824 | |||
825 | rcu_read_lock(); | ||
826 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
827 | /* If channel context is invalid or not on 2.4GHz - don't count it */ | ||
828 | if (!chanctx_conf || | ||
829 | chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) { | ||
830 | rcu_read_unlock(); | ||
831 | return; | ||
832 | } | ||
833 | rcu_read_unlock(); | ||
834 | |||
568 | if (vif->type != NL80211_IFTYPE_STATION || | 835 | if (vif->type != NL80211_IFTYPE_STATION || |
569 | mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) | 836 | mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) |
570 | return; | 837 | return; |
@@ -594,15 +861,15 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
594 | }; | 861 | }; |
595 | int ret; | 862 | int ret; |
596 | 863 | ||
597 | mutex_lock(&mvm->mutex); | 864 | lockdep_assert_held(&mvm->mutex); |
598 | 865 | ||
599 | /* Rssi update while not associated ?! */ | 866 | /* Rssi update while not associated ?! */ |
600 | if (WARN_ON_ONCE(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)) | 867 | if (WARN_ON_ONCE(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)) |
601 | goto out_unlock; | 868 | return; |
602 | 869 | ||
603 | /* No open connection - reports should be disabled */ | 870 | /* No BT - reports should be disabled */ |
604 | if (!BT_MBOX_MSG(&mvm->last_bt_notif, 3, OPEN_CON_2)) | 871 | if (!mvm->last_bt_notif.bt_status) |
605 | goto out_unlock; | 872 | return; |
606 | 873 | ||
607 | IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid, | 874 | IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid, |
608 | rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW"); | 875 | rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW"); |
@@ -611,7 +878,8 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
611 | * Check if rssi is good enough for reduced Tx power, but not in loose | 878 | * Check if rssi is good enough for reduced Tx power, but not in loose |
612 | * scheme. | 879 | * scheme. |
613 | */ | 880 | */ |
614 | if (rssi_event == RSSI_EVENT_LOW || is_loose_coex()) | 881 | if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant || |
882 | iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT) | ||
615 | ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, | 883 | ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, |
616 | false); | 884 | false); |
617 | else | 885 | else |
@@ -633,12 +901,52 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
633 | 901 | ||
634 | if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) | 902 | if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) |
635 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); | 903 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); |
904 | } | ||
905 | |||
906 | #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) | ||
907 | #define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200) | ||
636 | 908 | ||
637 | out_unlock: | 909 | u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm, |
638 | mutex_unlock(&mvm->mutex); | 910 | struct ieee80211_sta *sta) |
911 | { | ||
912 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | ||
913 | enum iwl_bt_coex_lut_type lut_type; | ||
914 | |||
915 | if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < | ||
916 | BT_LOW_TRAFFIC) | ||
917 | return LINK_QUAL_AGG_TIME_LIMIT_DEF; | ||
918 | |||
919 | lut_type = iwl_get_coex_type(mvm, mvmsta->vif); | ||
920 | |||
921 | if (lut_type == BT_COEX_LOOSE_LUT) | ||
922 | return LINK_QUAL_AGG_TIME_LIMIT_DEF; | ||
923 | |||
924 | /* tight coex, high bt traffic, reduce AGG time limit */ | ||
925 | return LINK_QUAL_AGG_TIME_LIMIT_BT_ACT; | ||
926 | } | ||
927 | |||
928 | bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, | ||
929 | struct ieee80211_sta *sta) | ||
930 | { | ||
931 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | ||
932 | |||
933 | if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < | ||
934 | BT_HIGH_TRAFFIC) | ||
935 | return true; | ||
936 | |||
937 | /* | ||
938 | * In Tight, BT can't Rx while we Tx, so use both antennas since BT is | ||
939 | * already killed. | ||
940 | * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while we | ||
941 | * Tx. | ||
942 | */ | ||
943 | return iwl_get_coex_type(mvm, mvmsta->vif) == BT_COEX_TIGHT_LUT; | ||
639 | } | 944 | } |
640 | 945 | ||
641 | void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 946 | void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) |
642 | { | 947 | { |
948 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX)) | ||
949 | return; | ||
950 | |||
643 | iwl_mvm_bt_coex_notif_handle(mvm); | 951 | iwl_mvm_bt_coex_notif_handle(mvm); |
644 | } | 952 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 2bf29f7992ee..4b6d670c3509 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h | |||
@@ -70,7 +70,9 @@ | |||
70 | #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC) | 70 | #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC) |
71 | #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC) | 71 | #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC) |
72 | #define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20 | 72 | #define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20 |
73 | #define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 20 | 73 | #define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 8 |
74 | #define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30 | ||
75 | #define IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS 20 | ||
74 | #define IWL_MVM_PS_HEAVY_TX_THLD_PERCENT 50 | 76 | #define IWL_MVM_PS_HEAVY_TX_THLD_PERCENT 50 |
75 | #define IWL_MVM_PS_HEAVY_RX_THLD_PERCENT 50 | 77 | #define IWL_MVM_PS_HEAVY_RX_THLD_PERCENT 50 |
76 | #define IWL_MVM_PS_SNOOZE_INTERVAL 25 | 78 | #define IWL_MVM_PS_SNOOZE_INTERVAL 25 |
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 417639f77b01..6f45966817bb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -67,6 +67,7 @@ | |||
67 | #include <net/cfg80211.h> | 67 | #include <net/cfg80211.h> |
68 | #include <net/ipv6.h> | 68 | #include <net/ipv6.h> |
69 | #include <net/tcp.h> | 69 | #include <net/tcp.h> |
70 | #include <net/addrconf.h> | ||
70 | #include "iwl-modparams.h" | 71 | #include "iwl-modparams.h" |
71 | #include "fw-api.h" | 72 | #include "fw-api.h" |
72 | #include "mvm.h" | 73 | #include "mvm.h" |
@@ -381,14 +382,74 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | |||
381 | union { | 382 | union { |
382 | struct iwl_proto_offload_cmd_v1 v1; | 383 | struct iwl_proto_offload_cmd_v1 v1; |
383 | struct iwl_proto_offload_cmd_v2 v2; | 384 | struct iwl_proto_offload_cmd_v2 v2; |
385 | struct iwl_proto_offload_cmd_v3_small v3s; | ||
386 | struct iwl_proto_offload_cmd_v3_large v3l; | ||
384 | } cmd = {}; | 387 | } cmd = {}; |
388 | struct iwl_host_cmd hcmd = { | ||
389 | .id = PROT_OFFLOAD_CONFIG_CMD, | ||
390 | .flags = CMD_SYNC, | ||
391 | .data[0] = &cmd, | ||
392 | .dataflags[0] = IWL_HCMD_DFL_DUP, | ||
393 | }; | ||
385 | struct iwl_proto_offload_cmd_common *common; | 394 | struct iwl_proto_offload_cmd_common *common; |
386 | u32 enabled = 0, size; | 395 | u32 enabled = 0, size; |
396 | u32 capa_flags = mvm->fw->ucode_capa.flags; | ||
387 | #if IS_ENABLED(CONFIG_IPV6) | 397 | #if IS_ENABLED(CONFIG_IPV6) |
388 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 398 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
389 | int i; | 399 | int i; |
390 | 400 | ||
391 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { | 401 | if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL || |
402 | capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { | ||
403 | struct iwl_ns_config *nsc; | ||
404 | struct iwl_targ_addr *addrs; | ||
405 | int n_nsc, n_addrs; | ||
406 | int c; | ||
407 | |||
408 | if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { | ||
409 | nsc = cmd.v3s.ns_config; | ||
410 | n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S; | ||
411 | addrs = cmd.v3s.targ_addrs; | ||
412 | n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S; | ||
413 | } else { | ||
414 | nsc = cmd.v3l.ns_config; | ||
415 | n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L; | ||
416 | addrs = cmd.v3l.targ_addrs; | ||
417 | n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L; | ||
418 | } | ||
419 | |||
420 | if (mvmvif->num_target_ipv6_addrs) | ||
421 | enabled |= IWL_D3_PROTO_OFFLOAD_NS; | ||
422 | |||
423 | /* | ||
424 | * For each address we have (and that will fit) fill a target | ||
425 | * address struct and combine for NS offload structs with the | ||
426 | * solicited node addresses. | ||
427 | */ | ||
428 | for (i = 0, c = 0; | ||
429 | i < mvmvif->num_target_ipv6_addrs && | ||
430 | i < n_addrs && c < n_nsc; i++) { | ||
431 | struct in6_addr solicited_addr; | ||
432 | int j; | ||
433 | |||
434 | addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i], | ||
435 | &solicited_addr); | ||
436 | for (j = 0; j < c; j++) | ||
437 | if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr, | ||
438 | &solicited_addr) == 0) | ||
439 | break; | ||
440 | if (j == c) | ||
441 | c++; | ||
442 | addrs[i].addr = mvmvif->target_ipv6_addrs[i]; | ||
443 | addrs[i].config_num = cpu_to_le32(j); | ||
444 | nsc[j].dest_ipv6_addr = solicited_addr; | ||
445 | memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN); | ||
446 | } | ||
447 | |||
448 | if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) | ||
449 | cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i); | ||
450 | else | ||
451 | cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i); | ||
452 | } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { | ||
392 | if (mvmvif->num_target_ipv6_addrs) { | 453 | if (mvmvif->num_target_ipv6_addrs) { |
393 | enabled |= IWL_D3_PROTO_OFFLOAD_NS; | 454 | enabled |= IWL_D3_PROTO_OFFLOAD_NS; |
394 | memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); | 455 | memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); |
@@ -419,7 +480,13 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | |||
419 | } | 480 | } |
420 | #endif | 481 | #endif |
421 | 482 | ||
422 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { | 483 | if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { |
484 | common = &cmd.v3s.common; | ||
485 | size = sizeof(cmd.v3s); | ||
486 | } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { | ||
487 | common = &cmd.v3l.common; | ||
488 | size = sizeof(cmd.v3l); | ||
489 | } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { | ||
423 | common = &cmd.v2.common; | 490 | common = &cmd.v2.common; |
424 | size = sizeof(cmd.v2); | 491 | size = sizeof(cmd.v2); |
425 | } else { | 492 | } else { |
@@ -438,8 +505,8 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | |||
438 | 505 | ||
439 | common->enabled = cpu_to_le32(enabled); | 506 | common->enabled = cpu_to_le32(enabled); |
440 | 507 | ||
441 | return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC, | 508 | hcmd.len[0] = size; |
442 | size, &cmd); | 509 | return iwl_mvm_send_cmd(mvm, &hcmd); |
443 | } | 510 | } |
444 | 511 | ||
445 | enum iwl_mvm_tcp_packet_type { | 512 | enum iwl_mvm_tcp_packet_type { |
@@ -793,6 +860,74 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
793 | return 0; | 860 | return 0; |
794 | } | 861 | } |
795 | 862 | ||
863 | static int iwl_mvm_get_last_nonqos_seq(struct iwl_mvm *mvm, | ||
864 | struct ieee80211_vif *vif) | ||
865 | { | ||
866 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
867 | struct iwl_nonqos_seq_query_cmd query_cmd = { | ||
868 | .get_set_flag = cpu_to_le32(IWL_NONQOS_SEQ_GET), | ||
869 | .mac_id_n_color = | ||
870 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
871 | mvmvif->color)), | ||
872 | }; | ||
873 | struct iwl_host_cmd cmd = { | ||
874 | .id = NON_QOS_TX_COUNTER_CMD, | ||
875 | .flags = CMD_SYNC | CMD_WANT_SKB, | ||
876 | }; | ||
877 | int err; | ||
878 | u32 size; | ||
879 | |||
880 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) { | ||
881 | cmd.data[0] = &query_cmd; | ||
882 | cmd.len[0] = sizeof(query_cmd); | ||
883 | } | ||
884 | |||
885 | err = iwl_mvm_send_cmd(mvm, &cmd); | ||
886 | if (err) | ||
887 | return err; | ||
888 | |||
889 | size = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||
890 | size -= sizeof(cmd.resp_pkt->hdr); | ||
891 | if (size < sizeof(__le16)) { | ||
892 | err = -EINVAL; | ||
893 | } else { | ||
894 | err = le16_to_cpup((__le16 *)cmd.resp_pkt->data); | ||
895 | /* new API returns next, not last-used seqno */ | ||
896 | if (mvm->fw->ucode_capa.flags & | ||
897 | IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) | ||
898 | err -= 0x10; | ||
899 | } | ||
900 | |||
901 | iwl_free_resp(&cmd); | ||
902 | return err; | ||
903 | } | ||
904 | |||
905 | void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
906 | { | ||
907 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
908 | struct iwl_nonqos_seq_query_cmd query_cmd = { | ||
909 | .get_set_flag = cpu_to_le32(IWL_NONQOS_SEQ_SET), | ||
910 | .mac_id_n_color = | ||
911 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
912 | mvmvif->color)), | ||
913 | .value = cpu_to_le16(mvmvif->seqno), | ||
914 | }; | ||
915 | |||
916 | /* return if called during restart, not resume from D3 */ | ||
917 | if (!mvmvif->seqno_valid) | ||
918 | return; | ||
919 | |||
920 | mvmvif->seqno_valid = false; | ||
921 | |||
922 | if (!(mvm->fw->ucode_capa.flags & | ||
923 | IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API)) | ||
924 | return; | ||
925 | |||
926 | if (iwl_mvm_send_cmd_pdu(mvm, NON_QOS_TX_COUNTER_CMD, CMD_SYNC, | ||
927 | sizeof(query_cmd), &query_cmd)) | ||
928 | IWL_ERR(mvm, "failed to set non-QoS seqno\n"); | ||
929 | } | ||
930 | |||
796 | static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | 931 | static int __iwl_mvm_suspend(struct ieee80211_hw *hw, |
797 | struct cfg80211_wowlan *wowlan, | 932 | struct cfg80211_wowlan *wowlan, |
798 | bool test) | 933 | bool test) |
@@ -829,7 +964,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
829 | }; | 964 | }; |
830 | int ret, i; | 965 | int ret, i; |
831 | int len __maybe_unused; | 966 | int len __maybe_unused; |
832 | u16 seq; | ||
833 | u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT; | 967 | u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT; |
834 | 968 | ||
835 | if (!wowlan) { | 969 | if (!wowlan) { |
@@ -872,26 +1006,15 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
872 | 1006 | ||
873 | mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; | 1007 | mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; |
874 | 1008 | ||
875 | /* | ||
876 | * The D3 firmware still hardcodes the AP station ID for the | ||
877 | * BSS we're associated with as 0. Store the real STA ID here | ||
878 | * and assign 0. When we leave this function, we'll restore | ||
879 | * the original value for the resume code. | ||
880 | */ | ||
881 | old_ap_sta_id = mvm_ap_sta->sta_id; | ||
882 | mvm_ap_sta->sta_id = 0; | ||
883 | mvmvif->ap_sta_id = 0; | ||
884 | |||
885 | /* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */ | 1009 | /* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */ |
886 | 1010 | ||
887 | wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported; | 1011 | wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported; |
888 | 1012 | ||
889 | /* | 1013 | /* Query the last used seqno and set it */ |
890 | * We know the last used seqno, and the uCode expects to know that | 1014 | ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); |
891 | * one, it will increment before TX. | 1015 | if (ret < 0) |
892 | */ | 1016 | goto out_noreset; |
893 | seq = mvm_ap_sta->last_seq_ctl & IEEE80211_SCTL_SEQ; | 1017 | wowlan_config_cmd.non_qos_seq = cpu_to_le16(ret); |
894 | wowlan_config_cmd.non_qos_seq = cpu_to_le16(seq); | ||
895 | 1018 | ||
896 | /* | 1019 | /* |
897 | * For QoS counters, we store the one to use next, so subtract 0x10 | 1020 | * For QoS counters, we store the one to use next, so subtract 0x10 |
@@ -899,7 +1022,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
899 | * increment after using the value (i.e. store the next value to use). | 1022 | * increment after using the value (i.e. store the next value to use). |
900 | */ | 1023 | */ |
901 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { | 1024 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { |
902 | seq = mvm_ap_sta->tid_data[i].seq_number; | 1025 | u16 seq = mvm_ap_sta->tid_data[i].seq_number; |
903 | seq -= 0x10; | 1026 | seq -= 0x10; |
904 | wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq); | 1027 | wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq); |
905 | } | 1028 | } |
@@ -945,6 +1068,16 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
945 | iwl_trans_stop_device(mvm->trans); | 1068 | iwl_trans_stop_device(mvm->trans); |
946 | 1069 | ||
947 | /* | 1070 | /* |
1071 | * The D3 firmware still hardcodes the AP station ID for the | ||
1072 | * BSS we're associated with as 0. Store the real STA ID here | ||
1073 | * and assign 0. When we leave this function, we'll restore | ||
1074 | * the original value for the resume code. | ||
1075 | */ | ||
1076 | old_ap_sta_id = mvm_ap_sta->sta_id; | ||
1077 | mvm_ap_sta->sta_id = 0; | ||
1078 | mvmvif->ap_sta_id = 0; | ||
1079 | |||
1080 | /* | ||
948 | * Set the HW restart bit -- this is mostly true as we're | 1081 | * Set the HW restart bit -- this is mostly true as we're |
949 | * going to load new firmware and reprogram that, though | 1082 | * going to load new firmware and reprogram that, though |
950 | * the reprogramming is going to be manual to avoid adding | 1083 | * the reprogramming is going to be manual to avoid adding |
@@ -1059,6 +1192,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1059 | if (ret) | 1192 | if (ret) |
1060 | goto out; | 1193 | goto out; |
1061 | 1194 | ||
1195 | ret = iwl_mvm_power_update_device_mode(mvm); | ||
1196 | if (ret) | ||
1197 | goto out; | ||
1198 | |||
1062 | ret = iwl_mvm_power_update_mode(mvm, vif); | 1199 | ret = iwl_mvm_power_update_mode(mvm, vif); |
1063 | if (ret) | 1200 | if (ret) |
1064 | goto out; | 1201 | goto out; |
@@ -1109,16 +1246,26 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
1109 | return __iwl_mvm_suspend(hw, wowlan, false); | 1246 | return __iwl_mvm_suspend(hw, wowlan, false); |
1110 | } | 1247 | } |
1111 | 1248 | ||
1249 | /* converted data from the different status responses */ | ||
1250 | struct iwl_wowlan_status_data { | ||
1251 | u16 pattern_number; | ||
1252 | u16 qos_seq_ctr[8]; | ||
1253 | u32 wakeup_reasons; | ||
1254 | u32 wake_packet_length; | ||
1255 | u32 wake_packet_bufsize; | ||
1256 | const u8 *wake_packet; | ||
1257 | }; | ||
1258 | |||
1112 | static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, | 1259 | static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, |
1113 | struct ieee80211_vif *vif, | 1260 | struct ieee80211_vif *vif, |
1114 | struct iwl_wowlan_status *status) | 1261 | struct iwl_wowlan_status_data *status) |
1115 | { | 1262 | { |
1116 | struct sk_buff *pkt = NULL; | 1263 | struct sk_buff *pkt = NULL; |
1117 | struct cfg80211_wowlan_wakeup wakeup = { | 1264 | struct cfg80211_wowlan_wakeup wakeup = { |
1118 | .pattern_idx = -1, | 1265 | .pattern_idx = -1, |
1119 | }; | 1266 | }; |
1120 | struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup; | 1267 | struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup; |
1121 | u32 reasons = le32_to_cpu(status->wakeup_reasons); | 1268 | u32 reasons = status->wakeup_reasons; |
1122 | 1269 | ||
1123 | if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) { | 1270 | if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) { |
1124 | wakeup_report = NULL; | 1271 | wakeup_report = NULL; |
@@ -1130,7 +1277,7 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, | |||
1130 | 1277 | ||
1131 | if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) | 1278 | if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) |
1132 | wakeup.pattern_idx = | 1279 | wakeup.pattern_idx = |
1133 | le16_to_cpu(status->pattern_number); | 1280 | status->pattern_number; |
1134 | 1281 | ||
1135 | if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | | 1282 | if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | |
1136 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) | 1283 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) |
@@ -1158,8 +1305,8 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, | |||
1158 | wakeup.tcp_match = true; | 1305 | wakeup.tcp_match = true; |
1159 | 1306 | ||
1160 | if (status->wake_packet_bufsize) { | 1307 | if (status->wake_packet_bufsize) { |
1161 | int pktsize = le32_to_cpu(status->wake_packet_bufsize); | 1308 | int pktsize = status->wake_packet_bufsize; |
1162 | int pktlen = le32_to_cpu(status->wake_packet_length); | 1309 | int pktlen = status->wake_packet_length; |
1163 | const u8 *pktdata = status->wake_packet; | 1310 | const u8 *pktdata = status->wake_packet; |
1164 | struct ieee80211_hdr *hdr = (void *)pktdata; | 1311 | struct ieee80211_hdr *hdr = (void *)pktdata; |
1165 | int truncated = pktlen - pktsize; | 1312 | int truncated = pktlen - pktsize; |
@@ -1239,8 +1386,229 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, | |||
1239 | kfree_skb(pkt); | 1386 | kfree_skb(pkt); |
1240 | } | 1387 | } |
1241 | 1388 | ||
1389 | static void iwl_mvm_aes_sc_to_seq(struct aes_sc *sc, | ||
1390 | struct ieee80211_key_seq *seq) | ||
1391 | { | ||
1392 | u64 pn; | ||
1393 | |||
1394 | pn = le64_to_cpu(sc->pn); | ||
1395 | seq->ccmp.pn[0] = pn >> 40; | ||
1396 | seq->ccmp.pn[1] = pn >> 32; | ||
1397 | seq->ccmp.pn[2] = pn >> 24; | ||
1398 | seq->ccmp.pn[3] = pn >> 16; | ||
1399 | seq->ccmp.pn[4] = pn >> 8; | ||
1400 | seq->ccmp.pn[5] = pn; | ||
1401 | } | ||
1402 | |||
1403 | static void iwl_mvm_tkip_sc_to_seq(struct tkip_sc *sc, | ||
1404 | struct ieee80211_key_seq *seq) | ||
1405 | { | ||
1406 | seq->tkip.iv32 = le32_to_cpu(sc->iv32); | ||
1407 | seq->tkip.iv16 = le16_to_cpu(sc->iv16); | ||
1408 | } | ||
1409 | |||
1410 | static void iwl_mvm_set_aes_rx_seq(struct aes_sc *scs, | ||
1411 | struct ieee80211_key_conf *key) | ||
1412 | { | ||
1413 | int tid; | ||
1414 | |||
1415 | BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS); | ||
1416 | |||
1417 | for (tid = 0; tid < IWL_NUM_RSC; tid++) { | ||
1418 | struct ieee80211_key_seq seq = {}; | ||
1419 | |||
1420 | iwl_mvm_aes_sc_to_seq(&scs[tid], &seq); | ||
1421 | ieee80211_set_key_rx_seq(key, tid, &seq); | ||
1422 | } | ||
1423 | } | ||
1424 | |||
1425 | static void iwl_mvm_set_tkip_rx_seq(struct tkip_sc *scs, | ||
1426 | struct ieee80211_key_conf *key) | ||
1427 | { | ||
1428 | int tid; | ||
1429 | |||
1430 | BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS); | ||
1431 | |||
1432 | for (tid = 0; tid < IWL_NUM_RSC; tid++) { | ||
1433 | struct ieee80211_key_seq seq = {}; | ||
1434 | |||
1435 | iwl_mvm_tkip_sc_to_seq(&scs[tid], &seq); | ||
1436 | ieee80211_set_key_rx_seq(key, tid, &seq); | ||
1437 | } | ||
1438 | } | ||
1439 | |||
1440 | static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, | ||
1441 | struct iwl_wowlan_status_v6 *status) | ||
1442 | { | ||
1443 | union iwl_all_tsc_rsc *rsc = &status->gtk.rsc.all_tsc_rsc; | ||
1444 | |||
1445 | switch (key->cipher) { | ||
1446 | case WLAN_CIPHER_SUITE_CCMP: | ||
1447 | iwl_mvm_set_aes_rx_seq(rsc->aes.multicast_rsc, key); | ||
1448 | break; | ||
1449 | case WLAN_CIPHER_SUITE_TKIP: | ||
1450 | iwl_mvm_set_tkip_rx_seq(rsc->tkip.multicast_rsc, key); | ||
1451 | break; | ||
1452 | default: | ||
1453 | WARN_ON(1); | ||
1454 | } | ||
1455 | } | ||
1456 | |||
1457 | struct iwl_mvm_d3_gtk_iter_data { | ||
1458 | struct iwl_wowlan_status_v6 *status; | ||
1459 | void *last_gtk; | ||
1460 | u32 cipher; | ||
1461 | bool find_phase, unhandled_cipher; | ||
1462 | int num_keys; | ||
1463 | }; | ||
1464 | |||
1465 | static void iwl_mvm_d3_update_gtks(struct ieee80211_hw *hw, | ||
1466 | struct ieee80211_vif *vif, | ||
1467 | struct ieee80211_sta *sta, | ||
1468 | struct ieee80211_key_conf *key, | ||
1469 | void *_data) | ||
1470 | { | ||
1471 | struct iwl_mvm_d3_gtk_iter_data *data = _data; | ||
1472 | |||
1473 | if (data->unhandled_cipher) | ||
1474 | return; | ||
1475 | |||
1476 | switch (key->cipher) { | ||
1477 | case WLAN_CIPHER_SUITE_WEP40: | ||
1478 | case WLAN_CIPHER_SUITE_WEP104: | ||
1479 | /* ignore WEP completely, nothing to do */ | ||
1480 | return; | ||
1481 | case WLAN_CIPHER_SUITE_CCMP: | ||
1482 | case WLAN_CIPHER_SUITE_TKIP: | ||
1483 | /* we support these */ | ||
1484 | break; | ||
1485 | default: | ||
1486 | /* everything else (even CMAC for MFP) - disconnect from AP */ | ||
1487 | data->unhandled_cipher = true; | ||
1488 | return; | ||
1489 | } | ||
1490 | |||
1491 | data->num_keys++; | ||
1492 | |||
1493 | /* | ||
1494 | * pairwise key - update sequence counters only; | ||
1495 | * note that this assumes no TDLS sessions are active | ||
1496 | */ | ||
1497 | if (sta) { | ||
1498 | struct ieee80211_key_seq seq = {}; | ||
1499 | union iwl_all_tsc_rsc *sc = &data->status->gtk.rsc.all_tsc_rsc; | ||
1500 | |||
1501 | if (data->find_phase) | ||
1502 | return; | ||
1503 | |||
1504 | switch (key->cipher) { | ||
1505 | case WLAN_CIPHER_SUITE_CCMP: | ||
1506 | iwl_mvm_aes_sc_to_seq(&sc->aes.tsc, &seq); | ||
1507 | iwl_mvm_set_aes_rx_seq(sc->aes.unicast_rsc, key); | ||
1508 | break; | ||
1509 | case WLAN_CIPHER_SUITE_TKIP: | ||
1510 | iwl_mvm_tkip_sc_to_seq(&sc->tkip.tsc, &seq); | ||
1511 | iwl_mvm_set_tkip_rx_seq(sc->tkip.unicast_rsc, key); | ||
1512 | break; | ||
1513 | } | ||
1514 | ieee80211_set_key_tx_seq(key, &seq); | ||
1515 | |||
1516 | /* that's it for this key */ | ||
1517 | return; | ||
1518 | } | ||
1519 | |||
1520 | if (data->find_phase) { | ||
1521 | data->last_gtk = key; | ||
1522 | data->cipher = key->cipher; | ||
1523 | return; | ||
1524 | } | ||
1525 | |||
1526 | if (data->status->num_of_gtk_rekeys) | ||
1527 | ieee80211_remove_key(key); | ||
1528 | else if (data->last_gtk == key) | ||
1529 | iwl_mvm_set_key_rx_seq(key, data->status); | ||
1530 | } | ||
1531 | |||
1532 | static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, | ||
1533 | struct ieee80211_vif *vif, | ||
1534 | struct iwl_wowlan_status_v6 *status) | ||
1535 | { | ||
1536 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1537 | struct iwl_mvm_d3_gtk_iter_data gtkdata = { | ||
1538 | .status = status, | ||
1539 | }; | ||
1540 | |||
1541 | if (!status || !vif->bss_conf.bssid) | ||
1542 | return false; | ||
1543 | |||
1544 | /* find last GTK that we used initially, if any */ | ||
1545 | gtkdata.find_phase = true; | ||
1546 | ieee80211_iter_keys(mvm->hw, vif, | ||
1547 | iwl_mvm_d3_update_gtks, >kdata); | ||
1548 | /* not trying to keep connections with MFP/unhandled ciphers */ | ||
1549 | if (gtkdata.unhandled_cipher) | ||
1550 | return false; | ||
1551 | if (!gtkdata.num_keys) | ||
1552 | return true; | ||
1553 | if (!gtkdata.last_gtk) | ||
1554 | return false; | ||
1555 | |||
1556 | /* | ||
1557 | * invalidate all other GTKs that might still exist and update | ||
1558 | * the one that we used | ||
1559 | */ | ||
1560 | gtkdata.find_phase = false; | ||
1561 | ieee80211_iter_keys(mvm->hw, vif, | ||
1562 | iwl_mvm_d3_update_gtks, >kdata); | ||
1563 | |||
1564 | if (status->num_of_gtk_rekeys) { | ||
1565 | struct ieee80211_key_conf *key; | ||
1566 | struct { | ||
1567 | struct ieee80211_key_conf conf; | ||
1568 | u8 key[32]; | ||
1569 | } conf = { | ||
1570 | .conf.cipher = gtkdata.cipher, | ||
1571 | .conf.keyidx = status->gtk.key_index, | ||
1572 | }; | ||
1573 | |||
1574 | switch (gtkdata.cipher) { | ||
1575 | case WLAN_CIPHER_SUITE_CCMP: | ||
1576 | conf.conf.keylen = WLAN_KEY_LEN_CCMP; | ||
1577 | memcpy(conf.conf.key, status->gtk.decrypt_key, | ||
1578 | WLAN_KEY_LEN_CCMP); | ||
1579 | break; | ||
1580 | case WLAN_CIPHER_SUITE_TKIP: | ||
1581 | conf.conf.keylen = WLAN_KEY_LEN_TKIP; | ||
1582 | memcpy(conf.conf.key, status->gtk.decrypt_key, 16); | ||
1583 | /* leave TX MIC key zeroed, we don't use it anyway */ | ||
1584 | memcpy(conf.conf.key + | ||
1585 | NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, | ||
1586 | status->gtk.tkip_mic_key, 8); | ||
1587 | break; | ||
1588 | } | ||
1589 | |||
1590 | key = ieee80211_gtk_rekey_add(vif, &conf.conf); | ||
1591 | if (IS_ERR(key)) | ||
1592 | return false; | ||
1593 | iwl_mvm_set_key_rx_seq(key, status); | ||
1594 | } | ||
1595 | |||
1596 | if (status->num_of_gtk_rekeys) { | ||
1597 | __be64 replay_ctr = | ||
1598 | cpu_to_be64(le64_to_cpu(status->replay_ctr)); | ||
1599 | ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid, | ||
1600 | (void *)&replay_ctr, GFP_KERNEL); | ||
1601 | } | ||
1602 | |||
1603 | mvmvif->seqno_valid = true; | ||
1604 | /* +0x10 because the set API expects next-to-use, not last-used */ | ||
1605 | mvmvif->seqno = le16_to_cpu(status->non_qos_seq_ctr) + 0x10; | ||
1606 | |||
1607 | return true; | ||
1608 | } | ||
1609 | |||
1242 | /* releases the MVM mutex */ | 1610 | /* releases the MVM mutex */ |
1243 | static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | 1611 | static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, |
1244 | struct ieee80211_vif *vif) | 1612 | struct ieee80211_vif *vif) |
1245 | { | 1613 | { |
1246 | u32 base = mvm->error_event_table; | 1614 | u32 base = mvm->error_event_table; |
@@ -1253,8 +1621,12 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
1253 | .id = WOWLAN_GET_STATUSES, | 1621 | .id = WOWLAN_GET_STATUSES, |
1254 | .flags = CMD_SYNC | CMD_WANT_SKB, | 1622 | .flags = CMD_SYNC | CMD_WANT_SKB, |
1255 | }; | 1623 | }; |
1256 | struct iwl_wowlan_status *status; | 1624 | struct iwl_wowlan_status_data status; |
1257 | int ret, len; | 1625 | struct iwl_wowlan_status_v6 *status_v6; |
1626 | int ret, len, status_size, i; | ||
1627 | bool keep; | ||
1628 | struct ieee80211_sta *ap_sta; | ||
1629 | struct iwl_mvm_sta *mvm_ap_sta; | ||
1258 | 1630 | ||
1259 | iwl_trans_read_mem_bytes(mvm->trans, base, | 1631 | iwl_trans_read_mem_bytes(mvm->trans, base, |
1260 | &err_info, sizeof(err_info)); | 1632 | &err_info, sizeof(err_info)); |
@@ -1287,32 +1659,83 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
1287 | if (!cmd.resp_pkt) | 1659 | if (!cmd.resp_pkt) |
1288 | goto out_unlock; | 1660 | goto out_unlock; |
1289 | 1661 | ||
1662 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) | ||
1663 | status_size = sizeof(struct iwl_wowlan_status_v6); | ||
1664 | else | ||
1665 | status_size = sizeof(struct iwl_wowlan_status_v4); | ||
1666 | |||
1290 | len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | 1667 | len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; |
1291 | if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) { | 1668 | if (len - sizeof(struct iwl_cmd_header) < status_size) { |
1292 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | 1669 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); |
1293 | goto out_free_resp; | 1670 | goto out_free_resp; |
1294 | } | 1671 | } |
1295 | 1672 | ||
1296 | status = (void *)cmd.resp_pkt->data; | 1673 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) { |
1674 | status_v6 = (void *)cmd.resp_pkt->data; | ||
1675 | |||
1676 | status.pattern_number = le16_to_cpu(status_v6->pattern_number); | ||
1677 | for (i = 0; i < 8; i++) | ||
1678 | status.qos_seq_ctr[i] = | ||
1679 | le16_to_cpu(status_v6->qos_seq_ctr[i]); | ||
1680 | status.wakeup_reasons = le32_to_cpu(status_v6->wakeup_reasons); | ||
1681 | status.wake_packet_length = | ||
1682 | le32_to_cpu(status_v6->wake_packet_length); | ||
1683 | status.wake_packet_bufsize = | ||
1684 | le32_to_cpu(status_v6->wake_packet_bufsize); | ||
1685 | status.wake_packet = status_v6->wake_packet; | ||
1686 | } else { | ||
1687 | struct iwl_wowlan_status_v4 *status_v4; | ||
1688 | status_v6 = NULL; | ||
1689 | status_v4 = (void *)cmd.resp_pkt->data; | ||
1690 | |||
1691 | status.pattern_number = le16_to_cpu(status_v4->pattern_number); | ||
1692 | for (i = 0; i < 8; i++) | ||
1693 | status.qos_seq_ctr[i] = | ||
1694 | le16_to_cpu(status_v4->qos_seq_ctr[i]); | ||
1695 | status.wakeup_reasons = le32_to_cpu(status_v4->wakeup_reasons); | ||
1696 | status.wake_packet_length = | ||
1697 | le32_to_cpu(status_v4->wake_packet_length); | ||
1698 | status.wake_packet_bufsize = | ||
1699 | le32_to_cpu(status_v4->wake_packet_bufsize); | ||
1700 | status.wake_packet = status_v4->wake_packet; | ||
1701 | } | ||
1297 | 1702 | ||
1298 | if (len - sizeof(struct iwl_cmd_header) != | 1703 | if (len - sizeof(struct iwl_cmd_header) != |
1299 | sizeof(*status) + | 1704 | status_size + ALIGN(status.wake_packet_bufsize, 4)) { |
1300 | ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) { | ||
1301 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | 1705 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); |
1302 | goto out_free_resp; | 1706 | goto out_free_resp; |
1303 | } | 1707 | } |
1304 | 1708 | ||
1709 | /* still at hard-coded place 0 for D3 image */ | ||
1710 | ap_sta = rcu_dereference_protected( | ||
1711 | mvm->fw_id_to_mac_id[0], | ||
1712 | lockdep_is_held(&mvm->mutex)); | ||
1713 | if (IS_ERR_OR_NULL(ap_sta)) | ||
1714 | goto out_free_resp; | ||
1715 | |||
1716 | mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; | ||
1717 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { | ||
1718 | u16 seq = status.qos_seq_ctr[i]; | ||
1719 | /* firmware stores last-used value, we store next value */ | ||
1720 | seq += 0x10; | ||
1721 | mvm_ap_sta->tid_data[i].seq_number = seq; | ||
1722 | } | ||
1723 | |||
1305 | /* now we have all the data we need, unlock to avoid mac80211 issues */ | 1724 | /* now we have all the data we need, unlock to avoid mac80211 issues */ |
1306 | mutex_unlock(&mvm->mutex); | 1725 | mutex_unlock(&mvm->mutex); |
1307 | 1726 | ||
1308 | iwl_mvm_report_wakeup_reasons(mvm, vif, status); | 1727 | iwl_mvm_report_wakeup_reasons(mvm, vif, &status); |
1728 | |||
1729 | keep = iwl_mvm_setup_connection_keep(mvm, vif, status_v6); | ||
1730 | |||
1309 | iwl_free_resp(&cmd); | 1731 | iwl_free_resp(&cmd); |
1310 | return; | 1732 | return keep; |
1311 | 1733 | ||
1312 | out_free_resp: | 1734 | out_free_resp: |
1313 | iwl_free_resp(&cmd); | 1735 | iwl_free_resp(&cmd); |
1314 | out_unlock: | 1736 | out_unlock: |
1315 | mutex_unlock(&mvm->mutex); | 1737 | mutex_unlock(&mvm->mutex); |
1738 | return false; | ||
1316 | } | 1739 | } |
1317 | 1740 | ||
1318 | static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) | 1741 | static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) |
@@ -1335,6 +1758,17 @@ static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) | |||
1335 | #endif | 1758 | #endif |
1336 | } | 1759 | } |
1337 | 1760 | ||
1761 | static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac, | ||
1762 | struct ieee80211_vif *vif) | ||
1763 | { | ||
1764 | /* skip the one we keep connection on */ | ||
1765 | if (data == vif) | ||
1766 | return; | ||
1767 | |||
1768 | if (vif->type == NL80211_IFTYPE_STATION) | ||
1769 | ieee80211_resume_disconnect(vif); | ||
1770 | } | ||
1771 | |||
1338 | static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | 1772 | static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) |
1339 | { | 1773 | { |
1340 | struct iwl_d3_iter_data resume_iter_data = { | 1774 | struct iwl_d3_iter_data resume_iter_data = { |
@@ -1343,6 +1777,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | |||
1343 | struct ieee80211_vif *vif = NULL; | 1777 | struct ieee80211_vif *vif = NULL; |
1344 | int ret; | 1778 | int ret; |
1345 | enum iwl_d3_status d3_status; | 1779 | enum iwl_d3_status d3_status; |
1780 | bool keep = false; | ||
1346 | 1781 | ||
1347 | mutex_lock(&mvm->mutex); | 1782 | mutex_lock(&mvm->mutex); |
1348 | 1783 | ||
@@ -1368,7 +1803,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | |||
1368 | /* query SRAM first in case we want event logging */ | 1803 | /* query SRAM first in case we want event logging */ |
1369 | iwl_mvm_read_d3_sram(mvm); | 1804 | iwl_mvm_read_d3_sram(mvm); |
1370 | 1805 | ||
1371 | iwl_mvm_query_wakeup_reasons(mvm, vif); | 1806 | keep = iwl_mvm_query_wakeup_reasons(mvm, vif); |
1372 | /* has unlocked the mutex, so skip that */ | 1807 | /* has unlocked the mutex, so skip that */ |
1373 | goto out; | 1808 | goto out; |
1374 | 1809 | ||
@@ -1376,8 +1811,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | |||
1376 | mutex_unlock(&mvm->mutex); | 1811 | mutex_unlock(&mvm->mutex); |
1377 | 1812 | ||
1378 | out: | 1813 | out: |
1379 | if (!test && vif) | 1814 | if (!test) |
1380 | ieee80211_resume_disconnect(vif); | 1815 | ieee80211_iterate_active_interfaces_rtnl(mvm->hw, |
1816 | IEEE80211_IFACE_ITER_NORMAL, | ||
1817 | iwl_mvm_d3_disconnect_iter, keep ? vif : NULL); | ||
1381 | 1818 | ||
1382 | /* return 1 to reconfigure the device */ | 1819 | /* return 1 to reconfigure the device */ |
1383 | set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | 1820 | set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index aac81b8984b0..0675f0c8ef93 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
@@ -246,58 +246,56 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, | |||
246 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 246 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
247 | } | 247 | } |
248 | 248 | ||
249 | static ssize_t iwl_dbgfs_power_down_allow_write(struct file *file, | 249 | static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file, |
250 | const char __user *user_buf, | 250 | char __user *user_buf, |
251 | size_t count, loff_t *ppos) | 251 | size_t count, loff_t *ppos) |
252 | { | 252 | { |
253 | struct iwl_mvm *mvm = file->private_data; | 253 | struct iwl_mvm *mvm = file->private_data; |
254 | char buf[8] = {}; | 254 | char buf[64]; |
255 | int allow; | 255 | int bufsz = sizeof(buf); |
256 | 256 | int pos = 0; | |
257 | if (!mvm->ucode_loaded) | ||
258 | return -EIO; | ||
259 | |||
260 | if (copy_from_user(buf, user_buf, sizeof(buf))) | ||
261 | return -EFAULT; | ||
262 | |||
263 | if (sscanf(buf, "%d", &allow) != 1) | ||
264 | return -EINVAL; | ||
265 | |||
266 | IWL_DEBUG_POWER(mvm, "%s device power down\n", | ||
267 | allow ? "allow" : "prevent"); | ||
268 | 257 | ||
269 | /* | 258 | pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d0=%d\n", |
270 | * TODO: Send REPLY_DEBUG_CMD (0xf0) when FW support it | 259 | mvm->disable_power_off); |
271 | */ | 260 | pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d3=%d\n", |
261 | mvm->disable_power_off_d3); | ||
272 | 262 | ||
273 | return count; | 263 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
274 | } | 264 | } |
275 | 265 | ||
276 | static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file, | 266 | static ssize_t iwl_dbgfs_disable_power_off_write(struct file *file, |
277 | const char __user *user_buf, | 267 | const char __user *user_buf, |
278 | size_t count, loff_t *ppos) | 268 | size_t count, loff_t *ppos) |
279 | { | 269 | { |
280 | struct iwl_mvm *mvm = file->private_data; | 270 | struct iwl_mvm *mvm = file->private_data; |
281 | char buf[8] = {}; | 271 | char buf[64] = {}; |
282 | int allow; | 272 | int ret; |
273 | int val; | ||
283 | 274 | ||
284 | if (copy_from_user(buf, user_buf, sizeof(buf))) | 275 | if (!mvm->ucode_loaded) |
276 | return -EIO; | ||
277 | |||
278 | count = min_t(size_t, count, sizeof(buf) - 1); | ||
279 | if (copy_from_user(buf, user_buf, count)) | ||
285 | return -EFAULT; | 280 | return -EFAULT; |
286 | 281 | ||
287 | if (sscanf(buf, "%d", &allow) != 1) | 282 | if (!strncmp("disable_power_off_d0=", buf, 21)) { |
283 | if (sscanf(buf + 21, "%d", &val) != 1) | ||
284 | return -EINVAL; | ||
285 | mvm->disable_power_off = val; | ||
286 | } else if (!strncmp("disable_power_off_d3=", buf, 21)) { | ||
287 | if (sscanf(buf + 21, "%d", &val) != 1) | ||
288 | return -EINVAL; | ||
289 | mvm->disable_power_off_d3 = val; | ||
290 | } else { | ||
288 | return -EINVAL; | 291 | return -EINVAL; |
292 | } | ||
289 | 293 | ||
290 | IWL_DEBUG_POWER(mvm, "%s device power down in d3\n", | 294 | mutex_lock(&mvm->mutex); |
291 | allow ? "allow" : "prevent"); | 295 | ret = iwl_mvm_power_update_device_mode(mvm); |
292 | 296 | mutex_unlock(&mvm->mutex); | |
293 | /* | ||
294 | * TODO: When WoWLAN FW alive notification happens, driver will send | ||
295 | * REPLY_DEBUG_CMD setting power_down_allow flag according to | ||
296 | * mvm->prevent_power_down_d3 | ||
297 | */ | ||
298 | mvm->prevent_power_down_d3 = !allow; | ||
299 | 297 | ||
300 | return count; | 298 | return ret ?: count; |
301 | } | 299 | } |
302 | 300 | ||
303 | static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, | 301 | static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, |
@@ -371,7 +369,8 @@ static ssize_t iwl_dbgfs_pm_params_write(struct file *file, | |||
371 | int val; | 369 | int val; |
372 | int ret; | 370 | int ret; |
373 | 371 | ||
374 | if (copy_from_user(buf, user_buf, sizeof(buf))) | 372 | count = min_t(size_t, count, sizeof(buf) - 1); |
373 | if (copy_from_user(buf, user_buf, count)) | ||
375 | return -EFAULT; | 374 | return -EFAULT; |
376 | 375 | ||
377 | if (!strncmp("keep_alive=", buf, 11)) { | 376 | if (!strncmp("keep_alive=", buf, 11)) { |
@@ -394,7 +393,9 @@ static ssize_t iwl_dbgfs_pm_params_write(struct file *file, | |||
394 | if (sscanf(buf + 16, "%d", &val) != 1) | 393 | if (sscanf(buf + 16, "%d", &val) != 1) |
395 | return -EINVAL; | 394 | return -EINVAL; |
396 | param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT; | 395 | param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT; |
397 | } else if (!strncmp("disable_power_off=", buf, 18)) { | 396 | } else if (!strncmp("disable_power_off=", buf, 18) && |
397 | !(mvm->fw->ucode_capa.flags & | ||
398 | IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) { | ||
398 | if (sscanf(buf + 18, "%d", &val) != 1) | 399 | if (sscanf(buf + 18, "%d", &val) != 1) |
399 | return -EINVAL; | 400 | return -EINVAL; |
400 | param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF; | 401 | param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF; |
@@ -581,15 +582,21 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, | |||
581 | BT_MBOX_PRINT(3, UPDATE_REQUEST, true); | 582 | BT_MBOX_PRINT(3, UPDATE_REQUEST, true); |
582 | 583 | ||
583 | pos += scnprintf(buf+pos, bufsz-pos, "bt_status = %d\n", | 584 | pos += scnprintf(buf+pos, bufsz-pos, "bt_status = %d\n", |
584 | notif->bt_status); | 585 | notif->bt_status); |
585 | pos += scnprintf(buf+pos, bufsz-pos, "bt_open_conn = %d\n", | 586 | pos += scnprintf(buf+pos, bufsz-pos, "bt_open_conn = %d\n", |
586 | notif->bt_open_conn); | 587 | notif->bt_open_conn); |
587 | pos += scnprintf(buf+pos, bufsz-pos, "bt_traffic_load = %d\n", | 588 | pos += scnprintf(buf+pos, bufsz-pos, "bt_traffic_load = %d\n", |
588 | notif->bt_traffic_load); | 589 | notif->bt_traffic_load); |
589 | pos += scnprintf(buf+pos, bufsz-pos, "bt_agg_traffic_load = %d\n", | 590 | pos += scnprintf(buf+pos, bufsz-pos, "bt_agg_traffic_load = %d\n", |
590 | notif->bt_agg_traffic_load); | 591 | notif->bt_agg_traffic_load); |
591 | pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n", | 592 | pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n", |
592 | notif->bt_ci_compliance); | 593 | notif->bt_ci_compliance); |
594 | pos += scnprintf(buf+pos, bufsz-pos, "primary_ch_lut = %d\n", | ||
595 | le32_to_cpu(notif->primary_ch_lut)); | ||
596 | pos += scnprintf(buf+pos, bufsz-pos, "secondary_ch_lut = %d\n", | ||
597 | le32_to_cpu(notif->secondary_ch_lut)); | ||
598 | pos += scnprintf(buf+pos, bufsz-pos, "bt_activity_grading = %d\n", | ||
599 | le32_to_cpu(notif->bt_activity_grading)); | ||
593 | 600 | ||
594 | mutex_unlock(&mvm->mutex); | 601 | mutex_unlock(&mvm->mutex); |
595 | 602 | ||
@@ -600,6 +607,38 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, | |||
600 | } | 607 | } |
601 | #undef BT_MBOX_PRINT | 608 | #undef BT_MBOX_PRINT |
602 | 609 | ||
610 | static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, | ||
611 | size_t count, loff_t *ppos) | ||
612 | { | ||
613 | struct iwl_mvm *mvm = file->private_data; | ||
614 | struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; | ||
615 | char buf[256]; | ||
616 | int bufsz = sizeof(buf); | ||
617 | int pos = 0; | ||
618 | |||
619 | mutex_lock(&mvm->mutex); | ||
620 | |||
621 | pos += scnprintf(buf+pos, bufsz-pos, "Channel inhibition CMD\n"); | ||
622 | pos += scnprintf(buf+pos, bufsz-pos, | ||
623 | "\tPrimary Channel Bitmap 0x%016llx Fat: %d\n", | ||
624 | le64_to_cpu(cmd->bt_primary_ci), | ||
625 | !!cmd->co_run_bw_primary); | ||
626 | pos += scnprintf(buf+pos, bufsz-pos, | ||
627 | "\tSecondary Channel Bitmap 0x%016llx Fat: %d\n", | ||
628 | le64_to_cpu(cmd->bt_secondary_ci), | ||
629 | !!cmd->co_run_bw_secondary); | ||
630 | |||
631 | pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); | ||
632 | pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", | ||
633 | iwl_bt_ack_kill_msk[mvm->bt_kill_msk]); | ||
634 | pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n", | ||
635 | iwl_bt_cts_kill_msk[mvm->bt_kill_msk]); | ||
636 | |||
637 | mutex_unlock(&mvm->mutex); | ||
638 | |||
639 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
640 | } | ||
641 | |||
603 | #define PRINT_STATS_LE32(_str, _val) \ | 642 | #define PRINT_STATS_LE32(_str, _val) \ |
604 | pos += scnprintf(buf + pos, bufsz - pos, \ | 643 | pos += scnprintf(buf + pos, bufsz - pos, \ |
605 | fmt_table, _str, \ | 644 | fmt_table, _str, \ |
@@ -615,9 +654,11 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, | |||
615 | int pos = 0; | 654 | int pos = 0; |
616 | char *buf; | 655 | char *buf; |
617 | int ret; | 656 | int ret; |
618 | int bufsz = sizeof(struct mvm_statistics_rx_phy) * 20 + | 657 | /* 43 is the size of each data line, 33 is the size of each header */ |
619 | sizeof(struct mvm_statistics_rx_non_phy) * 10 + | 658 | size_t bufsz = |
620 | sizeof(struct mvm_statistics_rx_ht_phy) * 10 + 200; | 659 | ((sizeof(struct mvm_statistics_rx) / sizeof(__le32)) * 43) + |
660 | (4 * 33) + 1; | ||
661 | |||
621 | struct mvm_statistics_rx_phy *ofdm; | 662 | struct mvm_statistics_rx_phy *ofdm; |
622 | struct mvm_statistics_rx_phy *cck; | 663 | struct mvm_statistics_rx_phy *cck; |
623 | struct mvm_statistics_rx_non_phy *general; | 664 | struct mvm_statistics_rx_non_phy *general; |
@@ -712,6 +753,7 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, | |||
712 | PRINT_STATS_LE32("beacon_energy_b", general->beacon_energy_b); | 753 | PRINT_STATS_LE32("beacon_energy_b", general->beacon_energy_b); |
713 | PRINT_STATS_LE32("beacon_energy_c", general->beacon_energy_c); | 754 | PRINT_STATS_LE32("beacon_energy_c", general->beacon_energy_c); |
714 | PRINT_STATS_LE32("num_bt_kills", general->num_bt_kills); | 755 | PRINT_STATS_LE32("num_bt_kills", general->num_bt_kills); |
756 | PRINT_STATS_LE32("mac_id", general->mac_id); | ||
715 | PRINT_STATS_LE32("directed_data_mpdu", general->directed_data_mpdu); | 757 | PRINT_STATS_LE32("directed_data_mpdu", general->directed_data_mpdu); |
716 | 758 | ||
717 | pos += scnprintf(buf + pos, bufsz - pos, fmt_header, | 759 | pos += scnprintf(buf + pos, bufsz - pos, fmt_header, |
@@ -757,6 +799,59 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, | |||
757 | return count; | 799 | return count; |
758 | } | 800 | } |
759 | 801 | ||
802 | static ssize_t | ||
803 | iwl_dbgfs_scan_ant_rxchain_read(struct file *file, | ||
804 | char __user *user_buf, | ||
805 | size_t count, loff_t *ppos) | ||
806 | { | ||
807 | struct iwl_mvm *mvm = file->private_data; | ||
808 | int pos = 0; | ||
809 | char buf[32]; | ||
810 | const size_t bufsz = sizeof(buf); | ||
811 | |||
812 | /* print which antennas were set for the scan command by the user */ | ||
813 | pos += scnprintf(buf + pos, bufsz - pos, "Antennas for scan: "); | ||
814 | if (mvm->scan_rx_ant & ANT_A) | ||
815 | pos += scnprintf(buf + pos, bufsz - pos, "A"); | ||
816 | if (mvm->scan_rx_ant & ANT_B) | ||
817 | pos += scnprintf(buf + pos, bufsz - pos, "B"); | ||
818 | if (mvm->scan_rx_ant & ANT_C) | ||
819 | pos += scnprintf(buf + pos, bufsz - pos, "C"); | ||
820 | pos += scnprintf(buf + pos, bufsz - pos, " (%hhx)\n", mvm->scan_rx_ant); | ||
821 | |||
822 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
823 | } | ||
824 | |||
825 | static ssize_t | ||
826 | iwl_dbgfs_scan_ant_rxchain_write(struct file *file, | ||
827 | const char __user *user_buf, | ||
828 | size_t count, loff_t *ppos) | ||
829 | { | ||
830 | struct iwl_mvm *mvm = file->private_data; | ||
831 | char buf[8]; | ||
832 | int buf_size; | ||
833 | u8 scan_rx_ant; | ||
834 | |||
835 | memset(buf, 0, sizeof(buf)); | ||
836 | buf_size = min(count, sizeof(buf) - 1); | ||
837 | |||
838 | /* get the argument from the user and check if it is valid */ | ||
839 | if (copy_from_user(buf, user_buf, buf_size)) | ||
840 | return -EFAULT; | ||
841 | if (sscanf(buf, "%hhx", &scan_rx_ant) != 1) | ||
842 | return -EINVAL; | ||
843 | if (scan_rx_ant > ANT_ABC) | ||
844 | return -EINVAL; | ||
845 | if (scan_rx_ant & ~iwl_fw_valid_rx_ant(mvm->fw)) | ||
846 | return -EINVAL; | ||
847 | |||
848 | /* change the rx antennas for scan command */ | ||
849 | mvm->scan_rx_ant = scan_rx_ant; | ||
850 | |||
851 | return count; | ||
852 | } | ||
853 | |||
854 | |||
760 | static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif, | 855 | static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif, |
761 | enum iwl_dbgfs_bf_mask param, int value) | 856 | enum iwl_dbgfs_bf_mask param, int value) |
762 | { | 857 | { |
@@ -968,7 +1063,8 @@ static ssize_t iwl_dbgfs_d3_sram_write(struct file *file, | |||
968 | char buf[8] = {}; | 1063 | char buf[8] = {}; |
969 | int store; | 1064 | int store; |
970 | 1065 | ||
971 | if (copy_from_user(buf, user_buf, sizeof(buf))) | 1066 | count = min_t(size_t, count, sizeof(buf) - 1); |
1067 | if (copy_from_user(buf, user_buf, count)) | ||
972 | return -EFAULT; | 1068 | return -EFAULT; |
973 | 1069 | ||
974 | if (sscanf(buf, "%d", &store) != 1) | 1070 | if (sscanf(buf, "%d", &store) != 1) |
@@ -1063,10 +1159,12 @@ MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain); | |||
1063 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram); | 1159 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram); |
1064 | MVM_DEBUGFS_READ_FILE_OPS(stations); | 1160 | MVM_DEBUGFS_READ_FILE_OPS(stations); |
1065 | MVM_DEBUGFS_READ_FILE_OPS(bt_notif); | 1161 | MVM_DEBUGFS_READ_FILE_OPS(bt_notif); |
1066 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow); | 1162 | MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); |
1067 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow); | 1163 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off); |
1068 | MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); | 1164 | MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); |
1069 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart); | 1165 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart); |
1166 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain); | ||
1167 | |||
1070 | #ifdef CONFIG_PM_SLEEP | 1168 | #ifdef CONFIG_PM_SLEEP |
1071 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram); | 1169 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram); |
1072 | #endif | 1170 | #endif |
@@ -1087,10 +1185,14 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | |||
1087 | MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); | 1185 | MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); |
1088 | MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); | 1186 | MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); |
1089 | MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); | 1187 | MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); |
1090 | MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR); | 1188 | MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); |
1091 | MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR); | 1189 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD) |
1190 | MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, | ||
1191 | S_IRUSR | S_IWUSR); | ||
1092 | MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); | 1192 | MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); |
1093 | MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); | 1193 | MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); |
1194 | MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, | ||
1195 | S_IWUSR | S_IRUSR); | ||
1094 | #ifdef CONFIG_PM_SLEEP | 1196 | #ifdef CONFIG_PM_SLEEP |
1095 | MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); | 1197 | MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); |
1096 | MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR); | 1198 | MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h index 05c61d6f384e..4ea5e24ca92d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h | |||
@@ -82,6 +82,8 @@ | |||
82 | * @BT_USE_DEFAULTS: | 82 | * @BT_USE_DEFAULTS: |
83 | * @BT_SYNC_2_BT_DISABLE: | 83 | * @BT_SYNC_2_BT_DISABLE: |
84 | * @BT_COEX_CORUNNING_TBL_EN: | 84 | * @BT_COEX_CORUNNING_TBL_EN: |
85 | * | ||
86 | * The COEX_MODE must be set for each command. Even if it is not changed. | ||
85 | */ | 87 | */ |
86 | enum iwl_bt_coex_flags { | 88 | enum iwl_bt_coex_flags { |
87 | BT_CH_PRIMARY_EN = BIT(0), | 89 | BT_CH_PRIMARY_EN = BIT(0), |
@@ -95,14 +97,16 @@ enum iwl_bt_coex_flags { | |||
95 | BT_COEX_NW = 0x3 << BT_COEX_MODE_POS, | 97 | BT_COEX_NW = 0x3 << BT_COEX_MODE_POS, |
96 | BT_USE_DEFAULTS = BIT(6), | 98 | BT_USE_DEFAULTS = BIT(6), |
97 | BT_SYNC_2_BT_DISABLE = BIT(7), | 99 | BT_SYNC_2_BT_DISABLE = BIT(7), |
98 | /* | 100 | BT_COEX_CORUNNING_TBL_EN = BIT(8), |
99 | * For future use - when the flags will be enlarged | 101 | BT_COEX_MPLUT_TBL_EN = BIT(9), |
100 | * BT_COEX_CORUNNING_TBL_EN = BIT(8), | 102 | /* Bit 10 is reserved */ |
101 | */ | 103 | BT_COEX_WF_PRIO_BOOST_CHECK_EN = BIT(11), |
102 | }; | 104 | }; |
103 | 105 | ||
104 | /* | 106 | /* |
105 | * indicates what has changed in the BT_COEX command. | 107 | * indicates what has changed in the BT_COEX command. |
108 | * BT_VALID_ENABLE must be set for each command. Commands without this bit will | ||
109 | * discarded by the firmware | ||
106 | */ | 110 | */ |
107 | enum iwl_bt_coex_valid_bit_msk { | 111 | enum iwl_bt_coex_valid_bit_msk { |
108 | BT_VALID_ENABLE = BIT(0), | 112 | BT_VALID_ENABLE = BIT(0), |
@@ -121,11 +125,8 @@ enum iwl_bt_coex_valid_bit_msk { | |||
121 | BT_VALID_CORUN_LUT_40 = BIT(13), | 125 | BT_VALID_CORUN_LUT_40 = BIT(13), |
122 | BT_VALID_ANT_ISOLATION = BIT(14), | 126 | BT_VALID_ANT_ISOLATION = BIT(14), |
123 | BT_VALID_ANT_ISOLATION_THRS = BIT(15), | 127 | BT_VALID_ANT_ISOLATION_THRS = BIT(15), |
124 | /* | 128 | BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16), |
125 | * For future use - when the valid flags will be enlarged | 129 | BT_VALID_TXRX_MAX_FREQ_0 = BIT(17), |
126 | * BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16), | ||
127 | * BT_VALID_TXRX_MAX_FREQ_0 = BIT(17), | ||
128 | */ | ||
129 | }; | 130 | }; |
130 | 131 | ||
131 | /** | 132 | /** |
@@ -142,48 +143,88 @@ enum iwl_bt_reduced_tx_power { | |||
142 | BT_REDUCED_TX_POWER_DATA = BIT(1), | 143 | BT_REDUCED_TX_POWER_DATA = BIT(1), |
143 | }; | 144 | }; |
144 | 145 | ||
146 | enum iwl_bt_coex_lut_type { | ||
147 | BT_COEX_TIGHT_LUT = 0, | ||
148 | BT_COEX_LOOSE_LUT, | ||
149 | BT_COEX_TX_DIS_LUT, | ||
150 | |||
151 | BT_COEX_MAX_LUT, | ||
152 | }; | ||
153 | |||
145 | #define BT_COEX_LUT_SIZE (12) | 154 | #define BT_COEX_LUT_SIZE (12) |
155 | #define BT_COEX_CORUN_LUT_SIZE (32) | ||
156 | #define BT_COEX_MULTI_PRIO_LUT_SIZE (2) | ||
157 | #define BT_COEX_BOOST_SIZE (4) | ||
158 | #define BT_REDUCED_TX_POWER_BIT BIT(7) | ||
146 | 159 | ||
147 | /** | 160 | /** |
148 | * struct iwl_bt_coex_cmd - bt coex configuration command | 161 | * struct iwl_bt_coex_cmd - bt coex configuration command |
149 | * @flags:&enum iwl_bt_coex_flags | 162 | * @flags:&enum iwl_bt_coex_flags |
150 | * @lead_time: | ||
151 | * @max_kill: | 163 | * @max_kill: |
152 | * @bt3_time_t7_value: | ||
153 | * @kill_ack_msk: | ||
154 | * @kill_cts_msk: | ||
155 | * @bt3_prio_sample_time: | ||
156 | * @bt3_timer_t2_value: | ||
157 | * @bt4_reaction_time: | ||
158 | * @decision_lut[12]: | ||
159 | * @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power | 164 | * @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power |
160 | * @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk | 165 | * @bt4_antenna_isolation: |
161 | * @bt_prio_boost: values for PTA boost register | 166 | * @bt4_antenna_isolation_thr: |
167 | * @bt4_tx_tx_delta_freq_thr: | ||
168 | * @bt4_tx_rx_max_freq0: | ||
169 | * @bt_prio_boost: | ||
162 | * @wifi_tx_prio_boost: SW boost of wifi tx priority | 170 | * @wifi_tx_prio_boost: SW boost of wifi tx priority |
163 | * @wifi_rx_prio_boost: SW boost of wifi rx priority | 171 | * @wifi_rx_prio_boost: SW boost of wifi rx priority |
172 | * @kill_ack_msk: | ||
173 | * @kill_cts_msk: | ||
174 | * @decision_lut: | ||
175 | * @bt4_multiprio_lut: | ||
176 | * @bt4_corun_lut20: | ||
177 | * @bt4_corun_lut40: | ||
178 | * @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk | ||
164 | * | 179 | * |
165 | * The structure is used for the BT_COEX command. | 180 | * The structure is used for the BT_COEX command. |
166 | */ | 181 | */ |
167 | struct iwl_bt_coex_cmd { | 182 | struct iwl_bt_coex_cmd { |
168 | u8 flags; | 183 | __le32 flags; |
169 | u8 lead_time; | ||
170 | u8 max_kill; | 184 | u8 max_kill; |
171 | u8 bt3_time_t7_value; | 185 | u8 bt_reduced_tx_power; |
186 | u8 reserved[2]; | ||
187 | |||
188 | u8 bt4_antenna_isolation; | ||
189 | u8 bt4_antenna_isolation_thr; | ||
190 | u8 bt4_tx_tx_delta_freq_thr; | ||
191 | u8 bt4_tx_rx_max_freq0; | ||
192 | |||
193 | __le32 bt_prio_boost[BT_COEX_BOOST_SIZE]; | ||
194 | __le32 wifi_tx_prio_boost; | ||
195 | __le32 wifi_rx_prio_boost; | ||
172 | __le32 kill_ack_msk; | 196 | __le32 kill_ack_msk; |
173 | __le32 kill_cts_msk; | 197 | __le32 kill_cts_msk; |
174 | u8 bt3_prio_sample_time; | 198 | |
175 | u8 bt3_timer_t2_value; | 199 | __le32 decision_lut[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE]; |
176 | __le16 bt4_reaction_time; | 200 | __le32 bt4_multiprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE]; |
177 | __le32 decision_lut[BT_COEX_LUT_SIZE]; | 201 | __le32 bt4_corun_lut20[BT_COEX_CORUN_LUT_SIZE]; |
178 | u8 bt_reduced_tx_power; | 202 | __le32 bt4_corun_lut40[BT_COEX_CORUN_LUT_SIZE]; |
179 | u8 reserved; | 203 | |
180 | __le16 valid_bit_msk; | 204 | __le32 valid_bit_msk; |
181 | __le32 bt_prio_boost; | ||
182 | u8 reserved2; | ||
183 | u8 wifi_tx_prio_boost; | ||
184 | __le16 wifi_rx_prio_boost; | ||
185 | } __packed; /* BT_COEX_CMD_API_S_VER_3 */ | 205 | } __packed; /* BT_COEX_CMD_API_S_VER_3 */ |
186 | 206 | ||
207 | /** | ||
208 | * struct iwl_bt_coex_ci_cmd - bt coex channel inhibition command | ||
209 | * @bt_primary_ci: | ||
210 | * @bt_secondary_ci: | ||
211 | * @co_run_bw_primary: | ||
212 | * @co_run_bw_secondary: | ||
213 | * @primary_ch_phy_id: | ||
214 | * @secondary_ch_phy_id: | ||
215 | * | ||
216 | * Used for BT_COEX_CI command | ||
217 | */ | ||
218 | struct iwl_bt_coex_ci_cmd { | ||
219 | __le64 bt_primary_ci; | ||
220 | __le64 bt_secondary_ci; | ||
221 | |||
222 | u8 co_run_bw_primary; | ||
223 | u8 co_run_bw_secondary; | ||
224 | u8 primary_ch_phy_id; | ||
225 | u8 secondary_ch_phy_id; | ||
226 | } __packed; /* BT_CI_MSG_API_S_VER_1 */ | ||
227 | |||
187 | #define BT_MBOX(n_dw, _msg, _pos, _nbits) \ | 228 | #define BT_MBOX(n_dw, _msg, _pos, _nbits) \ |
188 | BT_MBOX##n_dw##_##_msg##_POS = (_pos), \ | 229 | BT_MBOX##n_dw##_##_msg##_POS = (_pos), \ |
189 | BT_MBOX##n_dw##_##_msg = BITS(_nbits) << BT_MBOX##n_dw##_##_msg##_POS | 230 | BT_MBOX##n_dw##_##_msg = BITS(_nbits) << BT_MBOX##n_dw##_##_msg##_POS |
@@ -244,23 +285,39 @@ enum iwl_bt_mxbox_dw3 { | |||
244 | ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\ | 285 | ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\ |
245 | >> BT_MBOX##_num##_##_field##_POS) | 286 | >> BT_MBOX##_num##_##_field##_POS) |
246 | 287 | ||
288 | enum iwl_bt_activity_grading { | ||
289 | BT_OFF = 0, | ||
290 | BT_ON_NO_CONNECTION = 1, | ||
291 | BT_LOW_TRAFFIC = 2, | ||
292 | BT_HIGH_TRAFFIC = 3, | ||
293 | }; | ||
294 | |||
247 | /** | 295 | /** |
248 | * struct iwl_bt_coex_profile_notif - notification about BT coex | 296 | * struct iwl_bt_coex_profile_notif - notification about BT coex |
249 | * @mbox_msg: message from BT to WiFi | 297 | * @mbox_msg: message from BT to WiFi |
250 | * @:bt_status: 0 - off, 1 - on | 298 | * @msg_idx: the index of the message |
251 | * @:bt_open_conn: number of BT connections open | 299 | * @bt_status: 0 - off, 1 - on |
252 | * @:bt_traffic_load: load of BT traffic | 300 | * @bt_open_conn: number of BT connections open |
253 | * @:bt_agg_traffic_load: aggregated load of BT traffic | 301 | * @bt_traffic_load: load of BT traffic |
254 | * @:bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant | 302 | * @bt_agg_traffic_load: aggregated load of BT traffic |
303 | * @bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant | ||
304 | * @primary_ch_lut: LUT used for primary channel | ||
305 | * @secondary_ch_lut: LUT used for secondary channel | ||
306 | * @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading | ||
255 | */ | 307 | */ |
256 | struct iwl_bt_coex_profile_notif { | 308 | struct iwl_bt_coex_profile_notif { |
257 | __le32 mbox_msg[4]; | 309 | __le32 mbox_msg[4]; |
310 | __le32 msg_idx; | ||
258 | u8 bt_status; | 311 | u8 bt_status; |
259 | u8 bt_open_conn; | 312 | u8 bt_open_conn; |
260 | u8 bt_traffic_load; | 313 | u8 bt_traffic_load; |
261 | u8 bt_agg_traffic_load; | 314 | u8 bt_agg_traffic_load; |
262 | u8 bt_ci_compliance; | 315 | u8 bt_ci_compliance; |
263 | u8 reserved[3]; | 316 | u8 reserved[3]; |
317 | |||
318 | __le32 primary_ch_lut; | ||
319 | __le32 secondary_ch_lut; | ||
320 | __le32 bt_activity_grading; | ||
264 | } __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_2 */ | 321 | } __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_2 */ |
265 | 322 | ||
266 | enum iwl_bt_coex_prio_table_event { | 323 | enum iwl_bt_coex_prio_table_event { |
@@ -300,20 +357,4 @@ struct iwl_bt_coex_prio_tbl_cmd { | |||
300 | u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX]; | 357 | u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX]; |
301 | } __packed; | 358 | } __packed; |
302 | 359 | ||
303 | enum iwl_bt_coex_env_action { | ||
304 | BT_COEX_ENV_CLOSE = 0, | ||
305 | BT_COEX_ENV_OPEN = 1, | ||
306 | }; /* BT_COEX_PROT_ENV_ACTION_API_E_VER_1 */ | ||
307 | |||
308 | /** | ||
309 | * struct iwl_bt_coex_prot_env_cmd - BT Protection Envelope | ||
310 | * @action: enum %iwl_bt_coex_env_action | ||
311 | * @type: enum %iwl_bt_coex_prio_table_event | ||
312 | */ | ||
313 | struct iwl_bt_coex_prot_env_cmd { | ||
314 | u8 action; /* 0 = closed, 1 = open */ | ||
315 | u8 type; /* 0 .. 15 */ | ||
316 | u8 reserved[2]; | ||
317 | } __packed; | ||
318 | |||
319 | #endif /* __fw_api_bt_coex_h__ */ | 360 | #endif /* __fw_api_bt_coex_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index df72fcdf8170..4e7dd8cf87dc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | |||
@@ -100,7 +100,12 @@ enum iwl_proto_offloads { | |||
100 | 100 | ||
101 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2 | 101 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2 |
102 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2 6 | 102 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2 6 |
103 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX 6 | 103 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L 12 |
104 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S 4 | ||
105 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX 12 | ||
106 | |||
107 | #define IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L 4 | ||
108 | #define IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S 2 | ||
104 | 109 | ||
105 | /** | 110 | /** |
106 | * struct iwl_proto_offload_cmd_common - ARP/NS offload common part | 111 | * struct iwl_proto_offload_cmd_common - ARP/NS offload common part |
@@ -155,6 +160,43 @@ struct iwl_proto_offload_cmd_v2 { | |||
155 | u8 reserved2[3]; | 160 | u8 reserved2[3]; |
156 | } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_2 */ | 161 | } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_2 */ |
157 | 162 | ||
163 | struct iwl_ns_config { | ||
164 | struct in6_addr source_ipv6_addr; | ||
165 | struct in6_addr dest_ipv6_addr; | ||
166 | u8 target_mac_addr[ETH_ALEN]; | ||
167 | __le16 reserved; | ||
168 | } __packed; /* NS_OFFLOAD_CONFIG */ | ||
169 | |||
170 | struct iwl_targ_addr { | ||
171 | struct in6_addr addr; | ||
172 | __le32 config_num; | ||
173 | } __packed; /* TARGET_IPV6_ADDRESS */ | ||
174 | |||
175 | /** | ||
176 | * struct iwl_proto_offload_cmd_v3_small - ARP/NS offload configuration | ||
177 | * @common: common/IPv4 configuration | ||
178 | * @target_ipv6_addr: target IPv6 addresses | ||
179 | * @ns_config: NS offload configurations | ||
180 | */ | ||
181 | struct iwl_proto_offload_cmd_v3_small { | ||
182 | struct iwl_proto_offload_cmd_common common; | ||
183 | __le32 num_valid_ipv6_addrs; | ||
184 | struct iwl_targ_addr targ_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S]; | ||
185 | struct iwl_ns_config ns_config[IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S]; | ||
186 | } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_3 */ | ||
187 | |||
188 | /** | ||
189 | * struct iwl_proto_offload_cmd_v3_large - ARP/NS offload configuration | ||
190 | * @common: common/IPv4 configuration | ||
191 | * @target_ipv6_addr: target IPv6 addresses | ||
192 | * @ns_config: NS offload configurations | ||
193 | */ | ||
194 | struct iwl_proto_offload_cmd_v3_large { | ||
195 | struct iwl_proto_offload_cmd_common common; | ||
196 | __le32 num_valid_ipv6_addrs; | ||
197 | struct iwl_targ_addr targ_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L]; | ||
198 | struct iwl_ns_config ns_config[IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L]; | ||
199 | } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_3 */ | ||
158 | 200 | ||
159 | /* | 201 | /* |
160 | * WOWLAN_PATTERNS | 202 | * WOWLAN_PATTERNS |
@@ -293,7 +335,7 @@ enum iwl_wowlan_wakeup_reason { | |||
293 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12), | 335 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12), |
294 | }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */ | 336 | }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */ |
295 | 337 | ||
296 | struct iwl_wowlan_status { | 338 | struct iwl_wowlan_status_v4 { |
297 | __le64 replay_ctr; | 339 | __le64 replay_ctr; |
298 | __le16 pattern_number; | 340 | __le16 pattern_number; |
299 | __le16 non_qos_seq_ctr; | 341 | __le16 non_qos_seq_ctr; |
@@ -308,6 +350,29 @@ struct iwl_wowlan_status { | |||
308 | u8 wake_packet[]; /* can be truncated from _length to _bufsize */ | 350 | u8 wake_packet[]; /* can be truncated from _length to _bufsize */ |
309 | } __packed; /* WOWLAN_STATUSES_API_S_VER_4 */ | 351 | } __packed; /* WOWLAN_STATUSES_API_S_VER_4 */ |
310 | 352 | ||
353 | struct iwl_wowlan_gtk_status { | ||
354 | u8 key_index; | ||
355 | u8 reserved[3]; | ||
356 | u8 decrypt_key[16]; | ||
357 | u8 tkip_mic_key[8]; | ||
358 | struct iwl_wowlan_rsc_tsc_params_cmd rsc; | ||
359 | } __packed; | ||
360 | |||
361 | struct iwl_wowlan_status_v6 { | ||
362 | struct iwl_wowlan_gtk_status gtk; | ||
363 | __le64 replay_ctr; | ||
364 | __le16 pattern_number; | ||
365 | __le16 non_qos_seq_ctr; | ||
366 | __le16 qos_seq_ctr[8]; | ||
367 | __le32 wakeup_reasons; | ||
368 | __le32 num_of_gtk_rekeys; | ||
369 | __le32 transmitted_ndps; | ||
370 | __le32 received_beacons; | ||
371 | __le32 wake_packet_length; | ||
372 | __le32 wake_packet_bufsize; | ||
373 | u8 wake_packet[]; /* can be truncated from _length to _bufsize */ | ||
374 | } __packed; /* WOWLAN_STATUSES_API_S_VER_6 */ | ||
375 | |||
311 | #define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64 | 376 | #define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64 |
312 | #define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128 | 377 | #define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128 |
313 | #define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS 2048 | 378 | #define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS 2048 |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h index 98b1feb43d38..39c3148bdfa8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h | |||
@@ -170,12 +170,14 @@ struct iwl_mac_data_ap { | |||
170 | * @beacon_tsf: beacon transmit time in TSF | 170 | * @beacon_tsf: beacon transmit time in TSF |
171 | * @bi: beacon interval in TU | 171 | * @bi: beacon interval in TU |
172 | * @bi_reciprocal: 2^32 / bi | 172 | * @bi_reciprocal: 2^32 / bi |
173 | * @beacon_template: beacon template ID | ||
173 | */ | 174 | */ |
174 | struct iwl_mac_data_ibss { | 175 | struct iwl_mac_data_ibss { |
175 | __le32 beacon_time; | 176 | __le32 beacon_time; |
176 | __le64 beacon_tsf; | 177 | __le64 beacon_tsf; |
177 | __le32 bi; | 178 | __le32 bi; |
178 | __le32 bi_reciprocal; | 179 | __le32 bi_reciprocal; |
180 | __le32 beacon_template; | ||
179 | } __packed; /* IBSS_MAC_DATA_API_S_VER_1 */ | 181 | } __packed; /* IBSS_MAC_DATA_API_S_VER_1 */ |
180 | 182 | ||
181 | /** | 183 | /** |
@@ -372,4 +374,13 @@ static inline u32 iwl_mvm_reciprocal(u32 v) | |||
372 | return 0xFFFFFFFF / v; | 374 | return 0xFFFFFFFF / v; |
373 | } | 375 | } |
374 | 376 | ||
377 | #define IWL_NONQOS_SEQ_GET 0x1 | ||
378 | #define IWL_NONQOS_SEQ_SET 0x2 | ||
379 | struct iwl_nonqos_seq_query_cmd { | ||
380 | __le32 get_set_flag; | ||
381 | __le32 mac_id_n_color; | ||
382 | __le16 value; | ||
383 | __le16 reserved; | ||
384 | } __packed; /* NON_QOS_TX_COUNTER_GET_SET_API_S_VER_1 */ | ||
385 | |||
375 | #endif /* __fw_api_mac_h__ */ | 386 | #endif /* __fw_api_mac_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 8e7ab41079ca..5cb93ae5cd2f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | |||
@@ -132,6 +132,33 @@ struct iwl_powertable_cmd { | |||
132 | } __packed; | 132 | } __packed; |
133 | 133 | ||
134 | /** | 134 | /** |
135 | * enum iwl_device_power_flags - masks for device power command flags | ||
136 | * @DEVIC_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off | ||
137 | * receiver and transmitter. '0' - does not allow. This flag should be | ||
138 | * always set to '1' unless one need to disable actual power down for debug | ||
139 | * purposes. | ||
140 | * @DEVICE_POWER_FLAGS_CAM_MSK: '1' CAM (Continuous Active Mode) is set, meaning | ||
141 | * that power management is disabled. '0' Power management is enabled, one | ||
142 | * of power schemes is applied. | ||
143 | */ | ||
144 | enum iwl_device_power_flags { | ||
145 | DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0), | ||
146 | DEVICE_POWER_FLAGS_CAM_MSK = BIT(13), | ||
147 | }; | ||
148 | |||
149 | /** | ||
150 | * struct iwl_device_power_cmd - device wide power command. | ||
151 | * DEVICE_POWER_CMD = 0x77 (command, has simple generic response) | ||
152 | * | ||
153 | * @flags: Power table command flags from DEVICE_POWER_FLAGS_* | ||
154 | */ | ||
155 | struct iwl_device_power_cmd { | ||
156 | /* PM_POWER_TABLE_CMD_API_S_VER_6 */ | ||
157 | __le16 flags; | ||
158 | __le16 reserved; | ||
159 | } __packed; | ||
160 | |||
161 | /** | ||
135 | * struct iwl_mac_power_cmd - New power command containing uAPSD support | 162 | * struct iwl_mac_power_cmd - New power command containing uAPSD support |
136 | * MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response) | 163 | * MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response) |
137 | * @id_and_color: MAC contex identifier | 164 | * @id_and_color: MAC contex identifier |
@@ -290,7 +317,7 @@ struct iwl_beacon_filter_cmd { | |||
290 | #define IWL_BF_ESCAPE_TIMER_MIN 0 | 317 | #define IWL_BF_ESCAPE_TIMER_MIN 0 |
291 | 318 | ||
292 | #define IWL_BA_ESCAPE_TIMER_DEFAULT 6 | 319 | #define IWL_BA_ESCAPE_TIMER_DEFAULT 6 |
293 | #define IWL_BA_ESCAPE_TIMER_D3 6 | 320 | #define IWL_BA_ESCAPE_TIMER_D3 9 |
294 | #define IWL_BA_ESCAPE_TIMER_MAX 1024 | 321 | #define IWL_BA_ESCAPE_TIMER_MAX 1024 |
295 | #define IWL_BA_ESCAPE_TIMER_MIN 0 | 322 | #define IWL_BA_ESCAPE_TIMER_MIN 0 |
296 | 323 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h index fdd33bc0a594..538f1c7a5966 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h | |||
@@ -68,6 +68,7 @@ | |||
68 | /* | 68 | /* |
69 | * These serve as indexes into | 69 | * These serve as indexes into |
70 | * struct iwl_rate_info fw_rate_idx_to_plcp[IWL_RATE_COUNT]; | 70 | * struct iwl_rate_info fw_rate_idx_to_plcp[IWL_RATE_COUNT]; |
71 | * TODO: avoid overlap between legacy and HT rates | ||
71 | */ | 72 | */ |
72 | enum { | 73 | enum { |
73 | IWL_RATE_1M_INDEX = 0, | 74 | IWL_RATE_1M_INDEX = 0, |
@@ -78,18 +79,31 @@ enum { | |||
78 | IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, | 79 | IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, |
79 | IWL_RATE_6M_INDEX, | 80 | IWL_RATE_6M_INDEX, |
80 | IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, | 81 | IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, |
82 | IWL_RATE_MCS_0_INDEX = IWL_RATE_6M_INDEX, | ||
83 | IWL_FIRST_HT_RATE = IWL_RATE_MCS_0_INDEX, | ||
84 | IWL_FIRST_VHT_RATE = IWL_RATE_MCS_0_INDEX, | ||
81 | IWL_RATE_9M_INDEX, | 85 | IWL_RATE_9M_INDEX, |
82 | IWL_RATE_12M_INDEX, | 86 | IWL_RATE_12M_INDEX, |
87 | IWL_RATE_MCS_1_INDEX = IWL_RATE_12M_INDEX, | ||
83 | IWL_RATE_18M_INDEX, | 88 | IWL_RATE_18M_INDEX, |
89 | IWL_RATE_MCS_2_INDEX = IWL_RATE_18M_INDEX, | ||
84 | IWL_RATE_24M_INDEX, | 90 | IWL_RATE_24M_INDEX, |
91 | IWL_RATE_MCS_3_INDEX = IWL_RATE_24M_INDEX, | ||
85 | IWL_RATE_36M_INDEX, | 92 | IWL_RATE_36M_INDEX, |
93 | IWL_RATE_MCS_4_INDEX = IWL_RATE_36M_INDEX, | ||
86 | IWL_RATE_48M_INDEX, | 94 | IWL_RATE_48M_INDEX, |
95 | IWL_RATE_MCS_5_INDEX = IWL_RATE_48M_INDEX, | ||
87 | IWL_RATE_54M_INDEX, | 96 | IWL_RATE_54M_INDEX, |
97 | IWL_RATE_MCS_6_INDEX = IWL_RATE_54M_INDEX, | ||
88 | IWL_LAST_NON_HT_RATE = IWL_RATE_54M_INDEX, | 98 | IWL_LAST_NON_HT_RATE = IWL_RATE_54M_INDEX, |
89 | IWL_RATE_60M_INDEX, | 99 | IWL_RATE_60M_INDEX, |
90 | IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX, | 100 | IWL_RATE_MCS_7_INDEX = IWL_RATE_60M_INDEX, |
101 | IWL_LAST_HT_RATE = IWL_RATE_MCS_7_INDEX, | ||
102 | IWL_RATE_MCS_8_INDEX, | ||
103 | IWL_RATE_MCS_9_INDEX, | ||
104 | IWL_LAST_VHT_RATE = IWL_RATE_MCS_9_INDEX, | ||
91 | IWL_RATE_COUNT_LEGACY = IWL_LAST_NON_HT_RATE + 1, | 105 | IWL_RATE_COUNT_LEGACY = IWL_LAST_NON_HT_RATE + 1, |
92 | IWL_RATE_COUNT, | 106 | IWL_RATE_COUNT = IWL_LAST_VHT_RATE + 1, |
93 | }; | 107 | }; |
94 | 108 | ||
95 | #define IWL_RATE_BIT_MSK(r) BIT(IWL_RATE_##r##M_INDEX) | 109 | #define IWL_RATE_BIT_MSK(r) BIT(IWL_RATE_##r##M_INDEX) |
@@ -108,6 +122,7 @@ enum { | |||
108 | IWL_RATE_2M_PLCP = 20, | 122 | IWL_RATE_2M_PLCP = 20, |
109 | IWL_RATE_5M_PLCP = 55, | 123 | IWL_RATE_5M_PLCP = 55, |
110 | IWL_RATE_11M_PLCP = 110, | 124 | IWL_RATE_11M_PLCP = 110, |
125 | IWL_RATE_INVM_PLCP = -1, | ||
111 | }; | 126 | }; |
112 | 127 | ||
113 | /* | 128 | /* |
@@ -164,6 +179,8 @@ enum { | |||
164 | * which is the duplicate 20 MHz MCS (bit 5 set, all others zero.) | 179 | * which is the duplicate 20 MHz MCS (bit 5 set, all others zero.) |
165 | */ | 180 | */ |
166 | #define RATE_HT_MCS_RATE_CODE_MSK 0x7 | 181 | #define RATE_HT_MCS_RATE_CODE_MSK 0x7 |
182 | #define RATE_HT_MCS_NSS_POS 3 | ||
183 | #define RATE_HT_MCS_NSS_MSK (3 << RATE_HT_MCS_NSS_POS) | ||
167 | 184 | ||
168 | /* Bit 10: (1) Use Green Field preamble */ | 185 | /* Bit 10: (1) Use Green Field preamble */ |
169 | #define RATE_HT_MCS_GF_POS 10 | 186 | #define RATE_HT_MCS_GF_POS 10 |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 83cb9b992ea4..c3782b48ded1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | |||
@@ -356,6 +356,7 @@ struct iwl_scan_complete_notif { | |||
356 | /* scan offload */ | 356 | /* scan offload */ |
357 | #define IWL_MAX_SCAN_CHANNELS 40 | 357 | #define IWL_MAX_SCAN_CHANNELS 40 |
358 | #define IWL_SCAN_MAX_BLACKLIST_LEN 64 | 358 | #define IWL_SCAN_MAX_BLACKLIST_LEN 64 |
359 | #define IWL_SCAN_SHORT_BLACKLIST_LEN 16 | ||
359 | #define IWL_SCAN_MAX_PROFILES 11 | 360 | #define IWL_SCAN_MAX_PROFILES 11 |
360 | #define SCAN_OFFLOAD_PROBE_REQ_SIZE 512 | 361 | #define SCAN_OFFLOAD_PROBE_REQ_SIZE 512 |
361 | 362 | ||
@@ -368,6 +369,12 @@ struct iwl_scan_complete_notif { | |||
368 | #define IWL_FULL_SCAN_MULTIPLIER 5 | 369 | #define IWL_FULL_SCAN_MULTIPLIER 5 |
369 | #define IWL_FAST_SCHED_SCAN_ITERATIONS 3 | 370 | #define IWL_FAST_SCHED_SCAN_ITERATIONS 3 |
370 | 371 | ||
372 | enum scan_framework_client { | ||
373 | SCAN_CLIENT_SCHED_SCAN = BIT(0), | ||
374 | SCAN_CLIENT_NETDETECT = BIT(1), | ||
375 | SCAN_CLIENT_ASSET_TRACKING = BIT(2), | ||
376 | }; | ||
377 | |||
371 | /** | 378 | /** |
372 | * struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6 | 379 | * struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6 |
373 | * @scan_flags: see enum iwl_scan_flags | 380 | * @scan_flags: see enum iwl_scan_flags |
@@ -449,11 +456,12 @@ struct iwl_scan_offload_cfg { | |||
449 | * iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S | 456 | * iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S |
450 | * @ssid: MAC address to filter out | 457 | * @ssid: MAC address to filter out |
451 | * @reported_rssi: AP rssi reported to the host | 458 | * @reported_rssi: AP rssi reported to the host |
459 | * @client_bitmap: clients ignore this entry - enum scan_framework_client | ||
452 | */ | 460 | */ |
453 | struct iwl_scan_offload_blacklist { | 461 | struct iwl_scan_offload_blacklist { |
454 | u8 ssid[ETH_ALEN]; | 462 | u8 ssid[ETH_ALEN]; |
455 | u8 reported_rssi; | 463 | u8 reported_rssi; |
456 | u8 reserved; | 464 | u8 client_bitmap; |
457 | } __packed; | 465 | } __packed; |
458 | 466 | ||
459 | enum iwl_scan_offload_network_type { | 467 | enum iwl_scan_offload_network_type { |
@@ -475,6 +483,7 @@ enum iwl_scan_offload_band_selection { | |||
475 | * @aut_alg: authentication olgorithm to match - bitmap | 483 | * @aut_alg: authentication olgorithm to match - bitmap |
476 | * @network_type: enum iwl_scan_offload_network_type | 484 | * @network_type: enum iwl_scan_offload_network_type |
477 | * @band_selection: enum iwl_scan_offload_band_selection | 485 | * @band_selection: enum iwl_scan_offload_band_selection |
486 | * @client_bitmap: clients waiting for match - enum scan_framework_client | ||
478 | */ | 487 | */ |
479 | struct iwl_scan_offload_profile { | 488 | struct iwl_scan_offload_profile { |
480 | u8 ssid_index; | 489 | u8 ssid_index; |
@@ -482,7 +491,8 @@ struct iwl_scan_offload_profile { | |||
482 | u8 auth_alg; | 491 | u8 auth_alg; |
483 | u8 network_type; | 492 | u8 network_type; |
484 | u8 band_selection; | 493 | u8 band_selection; |
485 | u8 reserved[3]; | 494 | u8 client_bitmap; |
495 | u8 reserved[2]; | ||
486 | } __packed; | 496 | } __packed; |
487 | 497 | ||
488 | /** | 498 | /** |
@@ -491,13 +501,18 @@ struct iwl_scan_offload_profile { | |||
491 | * @profiles: profiles to search for match | 501 | * @profiles: profiles to search for match |
492 | * @blacklist_len: length of blacklist | 502 | * @blacklist_len: length of blacklist |
493 | * @num_profiles: num of profiles in the list | 503 | * @num_profiles: num of profiles in the list |
504 | * @match_notify: clients waiting for match found notification | ||
505 | * @pass_match: clients waiting for the results | ||
506 | * @active_clients: active clients bitmap - enum scan_framework_client | ||
494 | */ | 507 | */ |
495 | struct iwl_scan_offload_profile_cfg { | 508 | struct iwl_scan_offload_profile_cfg { |
496 | struct iwl_scan_offload_blacklist blacklist[IWL_SCAN_MAX_BLACKLIST_LEN]; | ||
497 | struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES]; | 509 | struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES]; |
498 | u8 blacklist_len; | 510 | u8 blacklist_len; |
499 | u8 num_profiles; | 511 | u8 num_profiles; |
500 | u8 reserved[2]; | 512 | u8 match_notify; |
513 | u8 pass_match; | ||
514 | u8 active_clients; | ||
515 | u8 reserved[3]; | ||
501 | } __packed; | 516 | } __packed; |
502 | 517 | ||
503 | /** | 518 | /** |
@@ -560,4 +575,15 @@ struct iwl_scan_offload_complete { | |||
560 | u8 reserved; | 575 | u8 reserved; |
561 | } __packed; | 576 | } __packed; |
562 | 577 | ||
578 | /** | ||
579 | * iwl_sched_scan_results - SCAN_OFFLOAD_MATCH_FOUND_NTF_API_S_VER_1 | ||
580 | * @ssid_bitmap: SSIDs indexes found in this iteration | ||
581 | * @client_bitmap: clients that are active and wait for this notification | ||
582 | */ | ||
583 | struct iwl_sched_scan_results { | ||
584 | __le16 ssid_bitmap; | ||
585 | u8 client_bitmap; | ||
586 | u8 reserved; | ||
587 | }; | ||
588 | |||
563 | #endif | 589 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h index a30691a8a85b..4aca5933a65d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h | |||
@@ -247,7 +247,7 @@ struct iwl_mvm_keyinfo { | |||
247 | } __packed; | 247 | } __packed; |
248 | 248 | ||
249 | /** | 249 | /** |
250 | * struct iwl_mvm_add_sta_cmd - Add / modify a station in the fw's station table | 250 | * struct iwl_mvm_add_sta_cmd_v5 - Add/modify a station in the fw's sta table. |
251 | * ( REPLY_ADD_STA = 0x18 ) | 251 | * ( REPLY_ADD_STA = 0x18 ) |
252 | * @add_modify: 1: modify existing, 0: add new station | 252 | * @add_modify: 1: modify existing, 0: add new station |
253 | * @unicast_tx_key_id: unicast tx key id. Relevant only when unicast key sent | 253 | * @unicast_tx_key_id: unicast tx key id. Relevant only when unicast key sent |
@@ -286,7 +286,7 @@ struct iwl_mvm_keyinfo { | |||
286 | * ADD_STA sets up the table entry for one station, either creating a new | 286 | * ADD_STA sets up the table entry for one station, either creating a new |
287 | * entry, or modifying a pre-existing one. | 287 | * entry, or modifying a pre-existing one. |
288 | */ | 288 | */ |
289 | struct iwl_mvm_add_sta_cmd { | 289 | struct iwl_mvm_add_sta_cmd_v5 { |
290 | u8 add_modify; | 290 | u8 add_modify; |
291 | u8 unicast_tx_key_id; | 291 | u8 unicast_tx_key_id; |
292 | u8 multicast_tx_key_id; | 292 | u8 multicast_tx_key_id; |
@@ -313,6 +313,57 @@ struct iwl_mvm_add_sta_cmd { | |||
313 | } __packed; /* ADD_STA_CMD_API_S_VER_5 */ | 313 | } __packed; /* ADD_STA_CMD_API_S_VER_5 */ |
314 | 314 | ||
315 | /** | 315 | /** |
316 | * struct iwl_mvm_add_sta_cmd_v6 - Add / modify a station | ||
317 | * VER_6 of this command is quite similar to VER_5 except | ||
318 | * exclusion of all fields related to the security key installation. | ||
319 | */ | ||
320 | struct iwl_mvm_add_sta_cmd_v6 { | ||
321 | u8 add_modify; | ||
322 | u8 reserved1; | ||
323 | __le16 tid_disable_tx; | ||
324 | __le32 mac_id_n_color; | ||
325 | u8 addr[ETH_ALEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */ | ||
326 | __le16 reserved2; | ||
327 | u8 sta_id; | ||
328 | u8 modify_mask; | ||
329 | __le16 reserved3; | ||
330 | __le32 station_flags; | ||
331 | __le32 station_flags_msk; | ||
332 | u8 add_immediate_ba_tid; | ||
333 | u8 remove_immediate_ba_tid; | ||
334 | __le16 add_immediate_ba_ssn; | ||
335 | __le16 sleep_tx_count; | ||
336 | __le16 sleep_state_flags; | ||
337 | __le16 assoc_id; | ||
338 | __le16 beamform_flags; | ||
339 | __le32 tfd_queue_msk; | ||
340 | } __packed; /* ADD_STA_CMD_API_S_VER_6 */ | ||
341 | |||
342 | /** | ||
343 | * struct iwl_mvm_add_sta_key_cmd - add/modify sta key | ||
344 | * ( REPLY_ADD_STA_KEY = 0x17 ) | ||
345 | * @sta_id: index of station in uCode's station table | ||
346 | * @key_offset: key offset in key storage | ||
347 | * @key_flags: type %iwl_sta_key_flag | ||
348 | * @key: key material data | ||
349 | * @key2: key material data | ||
350 | * @rx_secur_seq_cnt: RX security sequence counter for the key | ||
351 | * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection | ||
352 | * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx | ||
353 | */ | ||
354 | struct iwl_mvm_add_sta_key_cmd { | ||
355 | u8 sta_id; | ||
356 | u8 key_offset; | ||
357 | __le16 key_flags; | ||
358 | u8 key[16]; | ||
359 | u8 key2[16]; | ||
360 | u8 rx_secur_seq_cnt[16]; | ||
361 | u8 tkip_rx_tsc_byte2; | ||
362 | u8 reserved; | ||
363 | __le16 tkip_rx_ttak[5]; | ||
364 | } __packed; /* ADD_MODIFY_STA_KEY_API_S_VER_1 */ | ||
365 | |||
366 | /** | ||
316 | * enum iwl_mvm_add_sta_rsp_status - status in the response to ADD_STA command | 367 | * enum iwl_mvm_add_sta_rsp_status - status in the response to ADD_STA command |
317 | * @ADD_STA_SUCCESS: operation was executed successfully | 368 | * @ADD_STA_SUCCESS: operation was executed successfully |
318 | * @ADD_STA_STATIONS_OVERLOAD: no room left in the fw's station table | 369 | * @ADD_STA_STATIONS_OVERLOAD: no room left in the fw's station table |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 66264cc5a016..bad5a552dd8d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -72,17 +72,17 @@ | |||
72 | #include "fw-api-d3.h" | 72 | #include "fw-api-d3.h" |
73 | #include "fw-api-bt-coex.h" | 73 | #include "fw-api-bt-coex.h" |
74 | 74 | ||
75 | /* queue and FIFO numbers by usage */ | 75 | /* maximal number of Tx queues in any platform */ |
76 | #define IWL_MVM_MAX_QUEUES 20 | ||
77 | |||
78 | /* Tx queue numbers */ | ||
76 | enum { | 79 | enum { |
77 | IWL_MVM_OFFCHANNEL_QUEUE = 8, | 80 | IWL_MVM_OFFCHANNEL_QUEUE = 8, |
78 | IWL_MVM_CMD_QUEUE = 9, | 81 | IWL_MVM_CMD_QUEUE = 9, |
79 | IWL_MVM_AUX_QUEUE = 15, | ||
80 | IWL_MVM_FIRST_AGG_QUEUE = 16, | ||
81 | IWL_MVM_NUM_QUEUES = 20, | ||
82 | IWL_MVM_LAST_AGG_QUEUE = IWL_MVM_NUM_QUEUES - 1, | ||
83 | IWL_MVM_CMD_FIFO = 7 | ||
84 | }; | 82 | }; |
85 | 83 | ||
84 | #define IWL_MVM_CMD_FIFO 7 | ||
85 | |||
86 | #define IWL_MVM_STATION_COUNT 16 | 86 | #define IWL_MVM_STATION_COUNT 16 |
87 | 87 | ||
88 | /* commands */ | 88 | /* commands */ |
@@ -97,6 +97,7 @@ enum { | |||
97 | DBG_CFG = 0x9, | 97 | DBG_CFG = 0x9, |
98 | 98 | ||
99 | /* station table */ | 99 | /* station table */ |
100 | ADD_STA_KEY = 0x17, | ||
100 | ADD_STA = 0x18, | 101 | ADD_STA = 0x18, |
101 | REMOVE_STA = 0x19, | 102 | REMOVE_STA = 0x19, |
102 | 103 | ||
@@ -114,6 +115,7 @@ enum { | |||
114 | TIME_EVENT_NOTIFICATION = 0x2a, | 115 | TIME_EVENT_NOTIFICATION = 0x2a, |
115 | BINDING_CONTEXT_CMD = 0x2b, | 116 | BINDING_CONTEXT_CMD = 0x2b, |
116 | TIME_QUOTA_CMD = 0x2c, | 117 | TIME_QUOTA_CMD = 0x2c, |
118 | NON_QOS_TX_COUNTER_CMD = 0x2d, | ||
117 | 119 | ||
118 | LQ_CMD = 0x4e, | 120 | LQ_CMD = 0x4e, |
119 | 121 | ||
@@ -130,6 +132,7 @@ enum { | |||
130 | SCAN_OFFLOAD_COMPLETE = 0x6D, | 132 | SCAN_OFFLOAD_COMPLETE = 0x6D, |
131 | SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, | 133 | SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, |
132 | SCAN_OFFLOAD_CONFIG_CMD = 0x6f, | 134 | SCAN_OFFLOAD_CONFIG_CMD = 0x6f, |
135 | MATCH_FOUND_NOTIFICATION = 0xd9, | ||
133 | 136 | ||
134 | /* Phy */ | 137 | /* Phy */ |
135 | PHY_CONFIGURATION_CMD = 0x6a, | 138 | PHY_CONFIGURATION_CMD = 0x6a, |
@@ -178,6 +181,7 @@ enum { | |||
178 | BT_COEX_PRIO_TABLE = 0xcc, | 181 | BT_COEX_PRIO_TABLE = 0xcc, |
179 | BT_COEX_PROT_ENV = 0xcd, | 182 | BT_COEX_PROT_ENV = 0xcd, |
180 | BT_PROFILE_NOTIFICATION = 0xce, | 183 | BT_PROFILE_NOTIFICATION = 0xce, |
184 | BT_COEX_CI = 0x5d, | ||
181 | 185 | ||
182 | REPLY_BEACON_FILTERING_CMD = 0xd2, | 186 | REPLY_BEACON_FILTERING_CMD = 0xd2, |
183 | 187 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index c76299a3a1e0..83fc5ca04433 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -199,7 +199,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, | |||
199 | */ | 199 | */ |
200 | 200 | ||
201 | for (i = 0; i < IWL_MAX_HW_QUEUES; i++) { | 201 | for (i = 0; i < IWL_MAX_HW_QUEUES; i++) { |
202 | if (i < IWL_MVM_FIRST_AGG_QUEUE && i != IWL_MVM_CMD_QUEUE) | 202 | if (i < mvm->first_agg_queue && i != IWL_MVM_CMD_QUEUE) |
203 | mvm->queue_to_mac80211[i] = i; | 203 | mvm->queue_to_mac80211[i] = i; |
204 | else | 204 | else |
205 | mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE; | 205 | mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE; |
@@ -243,7 +243,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
243 | 243 | ||
244 | lockdep_assert_held(&mvm->mutex); | 244 | lockdep_assert_held(&mvm->mutex); |
245 | 245 | ||
246 | if (mvm->init_ucode_run) | 246 | if (mvm->init_ucode_complete) |
247 | return 0; | 247 | return 0; |
248 | 248 | ||
249 | iwl_init_notification_wait(&mvm->notif_wait, | 249 | iwl_init_notification_wait(&mvm->notif_wait, |
@@ -264,6 +264,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
264 | if (ret) | 264 | if (ret) |
265 | goto error; | 265 | goto error; |
266 | 266 | ||
267 | /* Read the NVM only at driver load time, no need to do this twice */ | ||
267 | if (read_nvm) { | 268 | if (read_nvm) { |
268 | /* Read nvm */ | 269 | /* Read nvm */ |
269 | ret = iwl_nvm_init(mvm); | 270 | ret = iwl_nvm_init(mvm); |
@@ -273,6 +274,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
273 | } | 274 | } |
274 | } | 275 | } |
275 | 276 | ||
277 | /* In case we read the NVM from external file, load it to the NIC */ | ||
278 | if (iwlwifi_mod_params.nvm_file) | ||
279 | iwl_mvm_load_nvm_to_nic(mvm); | ||
280 | |||
276 | ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); | 281 | ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); |
277 | WARN_ON(ret); | 282 | WARN_ON(ret); |
278 | 283 | ||
@@ -310,7 +315,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
310 | ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait, | 315 | ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait, |
311 | MVM_UCODE_CALIB_TIMEOUT); | 316 | MVM_UCODE_CALIB_TIMEOUT); |
312 | if (!ret) | 317 | if (!ret) |
313 | mvm->init_ucode_run = true; | 318 | mvm->init_ucode_complete = true; |
314 | goto out; | 319 | goto out; |
315 | 320 | ||
316 | error: | 321 | error: |
@@ -353,8 +358,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
353 | if (ret) | 358 | if (ret) |
354 | return ret; | 359 | return ret; |
355 | 360 | ||
356 | /* If we were in RFKILL during module loading, load init ucode now */ | 361 | /* |
357 | if (!mvm->init_ucode_run) { | 362 | * If we haven't completed the run of the init ucode during |
363 | * module loading, load init ucode now | ||
364 | * (for example, if we were in RFKILL) | ||
365 | */ | ||
366 | if (!mvm->init_ucode_complete) { | ||
358 | ret = iwl_run_init_mvm_ucode(mvm, false); | 367 | ret = iwl_run_init_mvm_ucode(mvm, false); |
359 | if (ret && !iwlmvm_mod_params.init_dbg) { | 368 | if (ret && !iwlmvm_mod_params.init_dbg) { |
360 | IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); | 369 | IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); |
@@ -424,6 +433,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
424 | goto error; | 433 | goto error; |
425 | } | 434 | } |
426 | 435 | ||
436 | ret = iwl_mvm_power_update_device_mode(mvm); | ||
437 | if (ret) | ||
438 | goto error; | ||
439 | |||
427 | IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); | 440 | IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); |
428 | return 0; | 441 | return 0; |
429 | error: | 442 | error: |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 5fe23a5ea9b6..ab5a7ac90dcd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -80,7 +80,7 @@ struct iwl_mvm_mac_iface_iterator_data { | |||
80 | struct ieee80211_vif *vif; | 80 | struct ieee80211_vif *vif; |
81 | unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)]; | 81 | unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)]; |
82 | unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)]; | 82 | unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)]; |
83 | unsigned long used_hw_queues[BITS_TO_LONGS(IWL_MVM_FIRST_AGG_QUEUE)]; | 83 | unsigned long used_hw_queues[BITS_TO_LONGS(IWL_MVM_MAX_QUEUES)]; |
84 | enum iwl_tsf_id preferred_tsf; | 84 | enum iwl_tsf_id preferred_tsf; |
85 | bool found_vif; | 85 | bool found_vif; |
86 | }; | 86 | }; |
@@ -218,7 +218,7 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
218 | .preferred_tsf = NUM_TSF_IDS, | 218 | .preferred_tsf = NUM_TSF_IDS, |
219 | .used_hw_queues = { | 219 | .used_hw_queues = { |
220 | BIT(IWL_MVM_OFFCHANNEL_QUEUE) | | 220 | BIT(IWL_MVM_OFFCHANNEL_QUEUE) | |
221 | BIT(IWL_MVM_AUX_QUEUE) | | 221 | BIT(mvm->aux_queue) | |
222 | BIT(IWL_MVM_CMD_QUEUE) | 222 | BIT(IWL_MVM_CMD_QUEUE) |
223 | }, | 223 | }, |
224 | .found_vif = false, | 224 | .found_vif = false, |
@@ -242,9 +242,17 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
242 | * that we should share it with another interface. | 242 | * that we should share it with another interface. |
243 | */ | 243 | */ |
244 | 244 | ||
245 | /* Currently, MAC ID 0 should be used only for the managed vif */ | 245 | /* Currently, MAC ID 0 should be used only for the managed/IBSS vif */ |
246 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 246 | switch (vif->type) { |
247 | case NL80211_IFTYPE_ADHOC: | ||
248 | break; | ||
249 | case NL80211_IFTYPE_STATION: | ||
250 | if (!vif->p2p) | ||
251 | break; | ||
252 | /* fall through */ | ||
253 | default: | ||
247 | __clear_bit(0, data.available_mac_ids); | 254 | __clear_bit(0, data.available_mac_ids); |
255 | } | ||
248 | 256 | ||
249 | ieee80211_iterate_active_interfaces_atomic( | 257 | ieee80211_iterate_active_interfaces_atomic( |
250 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | 258 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
@@ -302,9 +310,9 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
302 | /* Find available queues, and allocate them to the ACs */ | 310 | /* Find available queues, and allocate them to the ACs */ |
303 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 311 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
304 | u8 queue = find_first_zero_bit(data.used_hw_queues, | 312 | u8 queue = find_first_zero_bit(data.used_hw_queues, |
305 | IWL_MVM_FIRST_AGG_QUEUE); | 313 | mvm->first_agg_queue); |
306 | 314 | ||
307 | if (queue >= IWL_MVM_FIRST_AGG_QUEUE) { | 315 | if (queue >= mvm->first_agg_queue) { |
308 | IWL_ERR(mvm, "Failed to allocate queue\n"); | 316 | IWL_ERR(mvm, "Failed to allocate queue\n"); |
309 | ret = -EIO; | 317 | ret = -EIO; |
310 | goto exit_fail; | 318 | goto exit_fail; |
@@ -317,9 +325,9 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
317 | /* Allocate the CAB queue for softAP and GO interfaces */ | 325 | /* Allocate the CAB queue for softAP and GO interfaces */ |
318 | if (vif->type == NL80211_IFTYPE_AP) { | 326 | if (vif->type == NL80211_IFTYPE_AP) { |
319 | u8 queue = find_first_zero_bit(data.used_hw_queues, | 327 | u8 queue = find_first_zero_bit(data.used_hw_queues, |
320 | IWL_MVM_FIRST_AGG_QUEUE); | 328 | mvm->first_agg_queue); |
321 | 329 | ||
322 | if (queue >= IWL_MVM_FIRST_AGG_QUEUE) { | 330 | if (queue >= mvm->first_agg_queue) { |
323 | IWL_ERR(mvm, "Failed to allocate cab queue\n"); | 331 | IWL_ERR(mvm, "Failed to allocate cab queue\n"); |
324 | ret = -EIO; | 332 | ret = -EIO; |
325 | goto exit_fail; | 333 | goto exit_fail; |
@@ -559,8 +567,12 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, | |||
559 | cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); | 567 | cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); |
560 | 568 | ||
561 | /* Don't use cts to self as the fw doesn't support it currently. */ | 569 | /* Don't use cts to self as the fw doesn't support it currently. */ |
562 | if (vif->bss_conf.use_cts_prot) | 570 | if (vif->bss_conf.use_cts_prot) { |
563 | cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT); | 571 | cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT); |
572 | if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8) | ||
573 | cmd->protection_flags |= | ||
574 | cpu_to_le32(MAC_PROT_FLG_SELF_CTS_EN); | ||
575 | } | ||
564 | 576 | ||
565 | /* | 577 | /* |
566 | * I think that we should enable these 2 flags regardless the HT PROT | 578 | * I think that we should enable these 2 flags regardless the HT PROT |
@@ -712,6 +724,31 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, | |||
712 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); | 724 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); |
713 | } | 725 | } |
714 | 726 | ||
727 | static int iwl_mvm_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm, | ||
728 | struct ieee80211_vif *vif, | ||
729 | u32 action) | ||
730 | { | ||
731 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
732 | struct iwl_mac_ctx_cmd cmd = {}; | ||
733 | |||
734 | WARN_ON(vif->type != NL80211_IFTYPE_ADHOC); | ||
735 | |||
736 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | ||
737 | |||
738 | cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_BEACON | | ||
739 | MAC_FILTER_IN_PROBE_REQUEST); | ||
740 | |||
741 | /* cmd.ibss.beacon_time/cmd.ibss.beacon_tsf are curently ignored */ | ||
742 | cmd.ibss.bi = cpu_to_le32(vif->bss_conf.beacon_int); | ||
743 | cmd.ibss.bi_reciprocal = | ||
744 | cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int)); | ||
745 | |||
746 | /* TODO: Assumes that the beacon id == mac context id */ | ||
747 | cmd.ibss.beacon_template = cpu_to_le32(mvmvif->id); | ||
748 | |||
749 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); | ||
750 | } | ||
751 | |||
715 | struct iwl_mvm_go_iterator_data { | 752 | struct iwl_mvm_go_iterator_data { |
716 | bool go_active; | 753 | bool go_active; |
717 | }; | 754 | }; |
@@ -721,7 +758,8 @@ static void iwl_mvm_go_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) | |||
721 | struct iwl_mvm_go_iterator_data *data = _data; | 758 | struct iwl_mvm_go_iterator_data *data = _data; |
722 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 759 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
723 | 760 | ||
724 | if (vif->type == NL80211_IFTYPE_AP && vif->p2p && mvmvif->ap_active) | 761 | if (vif->type == NL80211_IFTYPE_AP && vif->p2p && |
762 | mvmvif->ap_ibss_active) | ||
725 | data->go_active = true; | 763 | data->go_active = true; |
726 | } | 764 | } |
727 | 765 | ||
@@ -833,9 +871,10 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, | |||
833 | cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(rate)); | 871 | cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(rate)); |
834 | 872 | ||
835 | /* Set up TX beacon command fields */ | 873 | /* Set up TX beacon command fields */ |
836 | iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd, | 874 | if (vif->type == NL80211_IFTYPE_AP) |
837 | beacon->data, | 875 | iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd, |
838 | beacon_skb_len); | 876 | beacon->data, |
877 | beacon_skb_len); | ||
839 | 878 | ||
840 | /* Submit command */ | 879 | /* Submit command */ |
841 | cmd.len[0] = sizeof(beacon_cmd); | 880 | cmd.len[0] = sizeof(beacon_cmd); |
@@ -848,14 +887,15 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, | |||
848 | return iwl_mvm_send_cmd(mvm, &cmd); | 887 | return iwl_mvm_send_cmd(mvm, &cmd); |
849 | } | 888 | } |
850 | 889 | ||
851 | /* The beacon template for the AP/GO context has changed and needs update */ | 890 | /* The beacon template for the AP/GO/IBSS has changed and needs update */ |
852 | int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, | 891 | int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, |
853 | struct ieee80211_vif *vif) | 892 | struct ieee80211_vif *vif) |
854 | { | 893 | { |
855 | struct sk_buff *beacon; | 894 | struct sk_buff *beacon; |
856 | int ret; | 895 | int ret; |
857 | 896 | ||
858 | WARN_ON(vif->type != NL80211_IFTYPE_AP); | 897 | WARN_ON(vif->type != NL80211_IFTYPE_AP && |
898 | vif->type != NL80211_IFTYPE_ADHOC); | ||
859 | 899 | ||
860 | beacon = ieee80211_beacon_get(mvm->hw, vif); | 900 | beacon = ieee80211_beacon_get(mvm->hw, vif); |
861 | if (!beacon) | 901 | if (!beacon) |
@@ -1018,6 +1058,8 @@ static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
1018 | return iwl_mvm_mac_ctxt_cmd_listener(mvm, vif, action); | 1058 | return iwl_mvm_mac_ctxt_cmd_listener(mvm, vif, action); |
1019 | case NL80211_IFTYPE_P2P_DEVICE: | 1059 | case NL80211_IFTYPE_P2P_DEVICE: |
1020 | return iwl_mvm_mac_ctxt_cmd_p2p_device(mvm, vif, action); | 1060 | return iwl_mvm_mac_ctxt_cmd_p2p_device(mvm, vif, action); |
1061 | case NL80211_IFTYPE_ADHOC: | ||
1062 | return iwl_mvm_mac_ctxt_cmd_ibss(mvm, vif, action); | ||
1021 | default: | 1063 | default: |
1022 | break; | 1064 | break; |
1023 | } | 1065 | } |
@@ -1038,6 +1080,9 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
1038 | if (ret) | 1080 | if (ret) |
1039 | return ret; | 1081 | return ret; |
1040 | 1082 | ||
1083 | /* will only do anything at resume from D3 time */ | ||
1084 | iwl_mvm_set_last_nonqos_seq(mvm, vif); | ||
1085 | |||
1041 | mvmvif->uploaded = true; | 1086 | mvmvif->uploaded = true; |
1042 | return 0; | 1087 | return 0; |
1043 | } | 1088 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 9833cdf6177c..f40685c3764e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -77,6 +77,7 @@ | |||
77 | #include "iwl-eeprom-parse.h" | 77 | #include "iwl-eeprom-parse.h" |
78 | #include "fw-api-scan.h" | 78 | #include "fw-api-scan.h" |
79 | #include "iwl-phy-db.h" | 79 | #include "iwl-phy-db.h" |
80 | #include "testmode.h" | ||
80 | 81 | ||
81 | static const struct ieee80211_iface_limit iwl_mvm_limits[] = { | 82 | static const struct ieee80211_iface_limit iwl_mvm_limits[] = { |
82 | { | 83 | { |
@@ -138,6 +139,14 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) | |||
138 | } | 139 | } |
139 | } | 140 | } |
140 | 141 | ||
142 | static int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm) | ||
143 | { | ||
144 | /* we create the 802.11 header and SSID element */ | ||
145 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID) | ||
146 | return mvm->fw->ucode_capa.max_probe_length - 24 - 2; | ||
147 | return mvm->fw->ucode_capa.max_probe_length - 24 - 34; | ||
148 | } | ||
149 | |||
141 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | 150 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) |
142 | { | 151 | { |
143 | struct ieee80211_hw *hw = mvm->hw; | 152 | struct ieee80211_hw *hw = mvm->hw; |
@@ -158,7 +167,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
158 | IEEE80211_HW_SUPPORTS_STATIC_SMPS | | 167 | IEEE80211_HW_SUPPORTS_STATIC_SMPS | |
159 | IEEE80211_HW_SUPPORTS_UAPSD; | 168 | IEEE80211_HW_SUPPORTS_UAPSD; |
160 | 169 | ||
161 | hw->queues = IWL_MVM_FIRST_AGG_QUEUE; | 170 | hw->queues = mvm->first_agg_queue; |
162 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; | 171 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; |
163 | hw->rate_control_algorithm = "iwl-mvm-rs"; | 172 | hw->rate_control_algorithm = "iwl-mvm-rs"; |
164 | 173 | ||
@@ -181,6 +190,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
181 | BIT(NL80211_IFTYPE_P2P_GO) | | 190 | BIT(NL80211_IFTYPE_P2P_GO) | |
182 | BIT(NL80211_IFTYPE_P2P_DEVICE); | 191 | BIT(NL80211_IFTYPE_P2P_DEVICE); |
183 | 192 | ||
193 | /* IBSS has bugs in older versions */ | ||
194 | if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8) | ||
195 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); | ||
196 | |||
184 | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | | 197 | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | |
185 | WIPHY_FLAG_DISABLE_BEACON_HINTS | | 198 | WIPHY_FLAG_DISABLE_BEACON_HINTS | |
186 | WIPHY_FLAG_IBSS_RSN; | 199 | WIPHY_FLAG_IBSS_RSN; |
@@ -212,9 +225,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
212 | 225 | ||
213 | iwl_mvm_reset_phy_ctxts(mvm); | 226 | iwl_mvm_reset_phy_ctxts(mvm); |
214 | 227 | ||
215 | /* we create the 802.11 header and a max-length SSID element */ | 228 | hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm); |
216 | hw->wiphy->max_scan_ie_len = | 229 | |
217 | mvm->fw->ucode_capa.max_probe_length - 24 - 34; | ||
218 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; | 230 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; |
219 | 231 | ||
220 | if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels) | 232 | if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels) |
@@ -231,6 +243,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
231 | else | 243 | else |
232 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | 244 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; |
233 | 245 | ||
246 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) { | ||
247 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | ||
248 | hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; | ||
249 | hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; | ||
250 | /* we create the 802.11 header and zero length SSID IE. */ | ||
251 | hw->wiphy->max_sched_scan_ie_len = | ||
252 | SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2; | ||
253 | } | ||
254 | |||
234 | hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | | 255 | hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | |
235 | NL80211_FEATURE_P2P_GO_OPPPS; | 256 | NL80211_FEATURE_P2P_GO_OPPPS; |
236 | 257 | ||
@@ -548,7 +569,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
548 | * In short: there's not much we can do at this point, other than | 569 | * In short: there's not much we can do at this point, other than |
549 | * allocating resources :) | 570 | * allocating resources :) |
550 | */ | 571 | */ |
551 | if (vif->type == NL80211_IFTYPE_AP) { | 572 | if (vif->type == NL80211_IFTYPE_AP || |
573 | vif->type == NL80211_IFTYPE_ADHOC) { | ||
552 | u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); | 574 | u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); |
553 | ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, | 575 | ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, |
554 | qmask); | 576 | qmask); |
@@ -698,7 +720,14 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | |||
698 | * For AP/GO interface, the tear down of the resources allocated to the | 720 | * For AP/GO interface, the tear down of the resources allocated to the |
699 | * interface is be handled as part of the stop_ap flow. | 721 | * interface is be handled as part of the stop_ap flow. |
700 | */ | 722 | */ |
701 | if (vif->type == NL80211_IFTYPE_AP) { | 723 | if (vif->type == NL80211_IFTYPE_AP || |
724 | vif->type == NL80211_IFTYPE_ADHOC) { | ||
725 | #ifdef CONFIG_NL80211_TESTMODE | ||
726 | if (vif == mvm->noa_vif) { | ||
727 | mvm->noa_vif = NULL; | ||
728 | mvm->noa_duration = 0; | ||
729 | } | ||
730 | #endif | ||
702 | iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); | 731 | iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); |
703 | goto out_release; | 732 | goto out_release; |
704 | } | 733 | } |
@@ -796,6 +825,27 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
796 | return; | 825 | return; |
797 | } | 826 | } |
798 | iwl_mvm_configure_mcast_filter(mvm, vif); | 827 | iwl_mvm_configure_mcast_filter(mvm, vif); |
828 | |||
829 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, | ||
830 | &mvm->status)) { | ||
831 | /* | ||
832 | * If we're restarting then the firmware will | ||
833 | * obviously have lost synchronisation with | ||
834 | * the AP. It will attempt to synchronise by | ||
835 | * itself, but we can make it more reliable by | ||
836 | * scheduling a session protection time event. | ||
837 | * | ||
838 | * The firmware needs to receive a beacon to | ||
839 | * catch up with synchronisation, use 110% of | ||
840 | * the beacon interval. | ||
841 | * | ||
842 | * Set a large maximum delay to allow for more | ||
843 | * than a single interface. | ||
844 | */ | ||
845 | u32 dur = (11 * vif->bss_conf.beacon_int) / 10; | ||
846 | iwl_mvm_protect_session(mvm, vif, dur, dur, | ||
847 | 5 * dur); | ||
848 | } | ||
799 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | 849 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { |
800 | /* remove AP station now that the MAC is unassoc */ | 850 | /* remove AP station now that the MAC is unassoc */ |
801 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); | 851 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); |
@@ -819,7 +869,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
819 | if (ret) | 869 | if (ret) |
820 | IWL_ERR(mvm, "failed to update power mode\n"); | 870 | IWL_ERR(mvm, "failed to update power mode\n"); |
821 | } | 871 | } |
822 | iwl_mvm_bt_coex_vif_assoc(mvm, vif); | 872 | iwl_mvm_bt_coex_vif_change(mvm); |
823 | } else if (changes & BSS_CHANGED_BEACON_INFO) { | 873 | } else if (changes & BSS_CHANGED_BEACON_INFO) { |
824 | /* | 874 | /* |
825 | * We received a beacon _after_ association so | 875 | * We received a beacon _after_ association so |
@@ -848,7 +898,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
848 | } | 898 | } |
849 | } | 899 | } |
850 | 900 | ||
851 | static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | 901 | static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, |
902 | struct ieee80211_vif *vif) | ||
852 | { | 903 | { |
853 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 904 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
854 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 905 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
@@ -871,7 +922,7 @@ static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
871 | if (ret) | 922 | if (ret) |
872 | goto out_remove; | 923 | goto out_remove; |
873 | 924 | ||
874 | mvmvif->ap_active = true; | 925 | mvmvif->ap_ibss_active = true; |
875 | 926 | ||
876 | /* Send the bcast station. At this stage the TBTT and DTIM time events | 927 | /* Send the bcast station. At this stage the TBTT and DTIM time events |
877 | * are added and applied to the scheduler */ | 928 | * are added and applied to the scheduler */ |
@@ -883,10 +934,12 @@ static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
883 | if (ret) | 934 | if (ret) |
884 | goto out_rm_bcast; | 935 | goto out_rm_bcast; |
885 | 936 | ||
886 | /* Need to update the P2P Device MAC */ | 937 | /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ |
887 | if (vif->p2p && mvm->p2p_device_vif) | 938 | if (vif->p2p && mvm->p2p_device_vif) |
888 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); | 939 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); |
889 | 940 | ||
941 | iwl_mvm_bt_coex_vif_change(mvm); | ||
942 | |||
890 | mutex_unlock(&mvm->mutex); | 943 | mutex_unlock(&mvm->mutex); |
891 | return 0; | 944 | return 0; |
892 | 945 | ||
@@ -901,7 +954,8 @@ out_unlock: | |||
901 | return ret; | 954 | return ret; |
902 | } | 955 | } |
903 | 956 | ||
904 | static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | 957 | static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, |
958 | struct ieee80211_vif *vif) | ||
905 | { | 959 | { |
906 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 960 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
907 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 961 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
@@ -910,9 +964,11 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
910 | 964 | ||
911 | mutex_lock(&mvm->mutex); | 965 | mutex_lock(&mvm->mutex); |
912 | 966 | ||
913 | mvmvif->ap_active = false; | 967 | mvmvif->ap_ibss_active = false; |
968 | |||
969 | iwl_mvm_bt_coex_vif_change(mvm); | ||
914 | 970 | ||
915 | /* Need to update the P2P Device MAC */ | 971 | /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ |
916 | if (vif->p2p && mvm->p2p_device_vif) | 972 | if (vif->p2p && mvm->p2p_device_vif) |
917 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); | 973 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); |
918 | 974 | ||
@@ -924,10 +980,11 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
924 | mutex_unlock(&mvm->mutex); | 980 | mutex_unlock(&mvm->mutex); |
925 | } | 981 | } |
926 | 982 | ||
927 | static void iwl_mvm_bss_info_changed_ap(struct iwl_mvm *mvm, | 983 | static void |
928 | struct ieee80211_vif *vif, | 984 | iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, |
929 | struct ieee80211_bss_conf *bss_conf, | 985 | struct ieee80211_vif *vif, |
930 | u32 changes) | 986 | struct ieee80211_bss_conf *bss_conf, |
987 | u32 changes) | ||
931 | { | 988 | { |
932 | /* Need to send a new beacon template to the FW */ | 989 | /* Need to send a new beacon template to the FW */ |
933 | if (changes & BSS_CHANGED_BEACON) { | 990 | if (changes & BSS_CHANGED_BEACON) { |
@@ -950,7 +1007,8 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, | |||
950 | iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes); | 1007 | iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes); |
951 | break; | 1008 | break; |
952 | case NL80211_IFTYPE_AP: | 1009 | case NL80211_IFTYPE_AP: |
953 | iwl_mvm_bss_info_changed_ap(mvm, vif, bss_conf, changes); | 1010 | case NL80211_IFTYPE_ADHOC: |
1011 | iwl_mvm_bss_info_changed_ap_ibss(mvm, vif, bss_conf, changes); | ||
954 | break; | 1012 | break; |
955 | default: | 1013 | default: |
956 | /* shouldn't happen */ | 1014 | /* shouldn't happen */ |
@@ -1163,7 +1221,54 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, | |||
1163 | 1221 | ||
1164 | mutex_lock(&mvm->mutex); | 1222 | mutex_lock(&mvm->mutex); |
1165 | /* Try really hard to protect the session and hear a beacon */ | 1223 | /* Try really hard to protect the session and hear a beacon */ |
1166 | iwl_mvm_protect_session(mvm, vif, duration, min_duration); | 1224 | iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500); |
1225 | mutex_unlock(&mvm->mutex); | ||
1226 | } | ||
1227 | |||
1228 | static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | ||
1229 | struct ieee80211_vif *vif, | ||
1230 | struct cfg80211_sched_scan_request *req, | ||
1231 | struct ieee80211_sched_scan_ies *ies) | ||
1232 | { | ||
1233 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1234 | int ret; | ||
1235 | |||
1236 | mutex_lock(&mvm->mutex); | ||
1237 | |||
1238 | if (mvm->scan_status != IWL_MVM_SCAN_NONE) { | ||
1239 | IWL_DEBUG_SCAN(mvm, | ||
1240 | "SCHED SCAN request during internal scan - abort\n"); | ||
1241 | ret = -EBUSY; | ||
1242 | goto out; | ||
1243 | } | ||
1244 | |||
1245 | mvm->scan_status = IWL_MVM_SCAN_SCHED; | ||
1246 | |||
1247 | ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); | ||
1248 | if (ret) | ||
1249 | goto err; | ||
1250 | |||
1251 | ret = iwl_mvm_config_sched_scan_profiles(mvm, req); | ||
1252 | if (ret) | ||
1253 | goto err; | ||
1254 | |||
1255 | ret = iwl_mvm_sched_scan_start(mvm, req); | ||
1256 | if (!ret) | ||
1257 | goto out; | ||
1258 | err: | ||
1259 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
1260 | out: | ||
1261 | mutex_unlock(&mvm->mutex); | ||
1262 | return ret; | ||
1263 | } | ||
1264 | |||
1265 | static void iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, | ||
1266 | struct ieee80211_vif *vif) | ||
1267 | { | ||
1268 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1269 | |||
1270 | mutex_lock(&mvm->mutex); | ||
1271 | iwl_mvm_sched_scan_stop(mvm); | ||
1167 | mutex_unlock(&mvm->mutex); | 1272 | mutex_unlock(&mvm->mutex); |
1168 | } | 1273 | } |
1169 | 1274 | ||
@@ -1207,8 +1312,13 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, | |||
1207 | 1312 | ||
1208 | switch (cmd) { | 1313 | switch (cmd) { |
1209 | case SET_KEY: | 1314 | case SET_KEY: |
1210 | if (vif->type == NL80211_IFTYPE_AP && !sta) { | 1315 | if ((vif->type == NL80211_IFTYPE_ADHOC || |
1211 | /* GTK on AP interface is a TX-only key, return 0 */ | 1316 | vif->type == NL80211_IFTYPE_AP) && !sta) { |
1317 | /* | ||
1318 | * GTK on AP interface is a TX-only key, return 0; | ||
1319 | * on IBSS they're per-station and because we're lazy | ||
1320 | * we don't support them for RX, so do the same. | ||
1321 | */ | ||
1212 | ret = 0; | 1322 | ret = 0; |
1213 | key->hw_key_idx = STA_KEY_IDX_INVALID; | 1323 | key->hw_key_idx = STA_KEY_IDX_INVALID; |
1214 | break; | 1324 | break; |
@@ -1252,6 +1362,9 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw, | |||
1252 | { | 1362 | { |
1253 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1363 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1254 | 1364 | ||
1365 | if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID) | ||
1366 | return; | ||
1367 | |||
1255 | iwl_mvm_update_tkip_key(mvm, vif, keyconf, sta, iv32, phase1key); | 1368 | iwl_mvm_update_tkip_key(mvm, vif, keyconf, sta, iv32, phase1key); |
1256 | } | 1369 | } |
1257 | 1370 | ||
@@ -1445,6 +1558,7 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, | |||
1445 | iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def, | 1558 | iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def, |
1446 | ctx->rx_chains_static, | 1559 | ctx->rx_chains_static, |
1447 | ctx->rx_chains_dynamic); | 1560 | ctx->rx_chains_dynamic); |
1561 | iwl_mvm_bt_coex_vif_change(mvm); | ||
1448 | mutex_unlock(&mvm->mutex); | 1562 | mutex_unlock(&mvm->mutex); |
1449 | } | 1563 | } |
1450 | 1564 | ||
@@ -1464,14 +1578,14 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, | |||
1464 | 1578 | ||
1465 | switch (vif->type) { | 1579 | switch (vif->type) { |
1466 | case NL80211_IFTYPE_AP: | 1580 | case NL80211_IFTYPE_AP: |
1581 | case NL80211_IFTYPE_ADHOC: | ||
1467 | /* | 1582 | /* |
1468 | * The AP binding flow is handled as part of the start_ap flow | 1583 | * The AP binding flow is handled as part of the start_ap flow |
1469 | * (in bss_info_changed). | 1584 | * (in bss_info_changed), similarly for IBSS. |
1470 | */ | 1585 | */ |
1471 | ret = 0; | 1586 | ret = 0; |
1472 | goto out_unlock; | 1587 | goto out_unlock; |
1473 | case NL80211_IFTYPE_STATION: | 1588 | case NL80211_IFTYPE_STATION: |
1474 | case NL80211_IFTYPE_ADHOC: | ||
1475 | case NL80211_IFTYPE_MONITOR: | 1589 | case NL80211_IFTYPE_MONITOR: |
1476 | break; | 1590 | break; |
1477 | default: | 1591 | default: |
@@ -1517,10 +1631,10 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, | |||
1517 | 1631 | ||
1518 | iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); | 1632 | iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); |
1519 | 1633 | ||
1520 | if (vif->type == NL80211_IFTYPE_AP) | ||
1521 | goto out_unlock; | ||
1522 | |||
1523 | switch (vif->type) { | 1634 | switch (vif->type) { |
1635 | case NL80211_IFTYPE_AP: | ||
1636 | case NL80211_IFTYPE_ADHOC: | ||
1637 | goto out_unlock; | ||
1524 | case NL80211_IFTYPE_MONITOR: | 1638 | case NL80211_IFTYPE_MONITOR: |
1525 | mvmvif->monitor_active = false; | 1639 | mvmvif->monitor_active = false; |
1526 | iwl_mvm_update_quotas(mvm, NULL); | 1640 | iwl_mvm_update_quotas(mvm, NULL); |
@@ -1550,14 +1664,72 @@ static int iwl_mvm_set_tim(struct ieee80211_hw *hw, | |||
1550 | return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif); | 1664 | return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif); |
1551 | } | 1665 | } |
1552 | 1666 | ||
1553 | static void iwl_mvm_mac_rssi_callback(struct ieee80211_hw *hw, | 1667 | #ifdef CONFIG_NL80211_TESTMODE |
1668 | static const struct nla_policy iwl_mvm_tm_policy[IWL_MVM_TM_ATTR_MAX + 1] = { | ||
1669 | [IWL_MVM_TM_ATTR_CMD] = { .type = NLA_U32 }, | ||
1670 | [IWL_MVM_TM_ATTR_NOA_DURATION] = { .type = NLA_U32 }, | ||
1671 | [IWL_MVM_TM_ATTR_BEACON_FILTER_STATE] = { .type = NLA_U32 }, | ||
1672 | }; | ||
1673 | |||
1674 | static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, | ||
1554 | struct ieee80211_vif *vif, | 1675 | struct ieee80211_vif *vif, |
1555 | enum ieee80211_rssi_event rssi_event) | 1676 | void *data, int len) |
1677 | { | ||
1678 | struct nlattr *tb[IWL_MVM_TM_ATTR_MAX + 1]; | ||
1679 | int err; | ||
1680 | u32 noa_duration; | ||
1681 | |||
1682 | err = nla_parse(tb, IWL_MVM_TM_ATTR_MAX, data, len, iwl_mvm_tm_policy); | ||
1683 | if (err) | ||
1684 | return err; | ||
1685 | |||
1686 | if (!tb[IWL_MVM_TM_ATTR_CMD]) | ||
1687 | return -EINVAL; | ||
1688 | |||
1689 | switch (nla_get_u32(tb[IWL_MVM_TM_ATTR_CMD])) { | ||
1690 | case IWL_MVM_TM_CMD_SET_NOA: | ||
1691 | if (!vif || vif->type != NL80211_IFTYPE_AP || !vif->p2p || | ||
1692 | !vif->bss_conf.enable_beacon || | ||
1693 | !tb[IWL_MVM_TM_ATTR_NOA_DURATION]) | ||
1694 | return -EINVAL; | ||
1695 | |||
1696 | noa_duration = nla_get_u32(tb[IWL_MVM_TM_ATTR_NOA_DURATION]); | ||
1697 | if (noa_duration >= vif->bss_conf.beacon_int) | ||
1698 | return -EINVAL; | ||
1699 | |||
1700 | mvm->noa_duration = noa_duration; | ||
1701 | mvm->noa_vif = vif; | ||
1702 | |||
1703 | return iwl_mvm_update_quotas(mvm, NULL); | ||
1704 | case IWL_MVM_TM_CMD_SET_BEACON_FILTER: | ||
1705 | /* must be associated client vif - ignore authorized */ | ||
1706 | if (!vif || vif->type != NL80211_IFTYPE_STATION || | ||
1707 | !vif->bss_conf.assoc || !vif->bss_conf.dtim_period || | ||
1708 | !tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE]) | ||
1709 | return -EINVAL; | ||
1710 | |||
1711 | if (nla_get_u32(tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE])) | ||
1712 | return iwl_mvm_enable_beacon_filter(mvm, vif); | ||
1713 | return iwl_mvm_disable_beacon_filter(mvm, vif); | ||
1714 | } | ||
1715 | |||
1716 | return -EOPNOTSUPP; | ||
1717 | } | ||
1718 | |||
1719 | static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, | ||
1720 | struct ieee80211_vif *vif, | ||
1721 | void *data, int len) | ||
1556 | { | 1722 | { |
1557 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1723 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1724 | int err; | ||
1558 | 1725 | ||
1559 | iwl_mvm_bt_rssi_event(mvm, vif, rssi_event); | 1726 | mutex_lock(&mvm->mutex); |
1727 | err = __iwl_mvm_mac_testmode_cmd(mvm, vif, data, len); | ||
1728 | mutex_unlock(&mvm->mutex); | ||
1729 | |||
1730 | return err; | ||
1560 | } | 1731 | } |
1732 | #endif | ||
1561 | 1733 | ||
1562 | struct ieee80211_ops iwl_mvm_hw_ops = { | 1734 | struct ieee80211_ops iwl_mvm_hw_ops = { |
1563 | .tx = iwl_mvm_mac_tx, | 1735 | .tx = iwl_mvm_mac_tx, |
@@ -1578,23 +1750,27 @@ struct ieee80211_ops iwl_mvm_hw_ops = { | |||
1578 | .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, | 1750 | .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, |
1579 | .conf_tx = iwl_mvm_mac_conf_tx, | 1751 | .conf_tx = iwl_mvm_mac_conf_tx, |
1580 | .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, | 1752 | .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, |
1753 | .sched_scan_start = iwl_mvm_mac_sched_scan_start, | ||
1754 | .sched_scan_stop = iwl_mvm_mac_sched_scan_stop, | ||
1581 | .set_key = iwl_mvm_mac_set_key, | 1755 | .set_key = iwl_mvm_mac_set_key, |
1582 | .update_tkip_key = iwl_mvm_mac_update_tkip_key, | 1756 | .update_tkip_key = iwl_mvm_mac_update_tkip_key, |
1583 | .remain_on_channel = iwl_mvm_roc, | 1757 | .remain_on_channel = iwl_mvm_roc, |
1584 | .cancel_remain_on_channel = iwl_mvm_cancel_roc, | 1758 | .cancel_remain_on_channel = iwl_mvm_cancel_roc, |
1585 | .rssi_callback = iwl_mvm_mac_rssi_callback, | ||
1586 | |||
1587 | .add_chanctx = iwl_mvm_add_chanctx, | 1759 | .add_chanctx = iwl_mvm_add_chanctx, |
1588 | .remove_chanctx = iwl_mvm_remove_chanctx, | 1760 | .remove_chanctx = iwl_mvm_remove_chanctx, |
1589 | .change_chanctx = iwl_mvm_change_chanctx, | 1761 | .change_chanctx = iwl_mvm_change_chanctx, |
1590 | .assign_vif_chanctx = iwl_mvm_assign_vif_chanctx, | 1762 | .assign_vif_chanctx = iwl_mvm_assign_vif_chanctx, |
1591 | .unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx, | 1763 | .unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx, |
1592 | 1764 | ||
1593 | .start_ap = iwl_mvm_start_ap, | 1765 | .start_ap = iwl_mvm_start_ap_ibss, |
1594 | .stop_ap = iwl_mvm_stop_ap, | 1766 | .stop_ap = iwl_mvm_stop_ap_ibss, |
1767 | .join_ibss = iwl_mvm_start_ap_ibss, | ||
1768 | .leave_ibss = iwl_mvm_stop_ap_ibss, | ||
1595 | 1769 | ||
1596 | .set_tim = iwl_mvm_set_tim, | 1770 | .set_tim = iwl_mvm_set_tim, |
1597 | 1771 | ||
1772 | CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) | ||
1773 | |||
1598 | #ifdef CONFIG_PM_SLEEP | 1774 | #ifdef CONFIG_PM_SLEEP |
1599 | /* look at d3.c */ | 1775 | /* look at d3.c */ |
1600 | .suspend = iwl_mvm_suspend, | 1776 | .suspend = iwl_mvm_suspend, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index b0389279cc1e..6235cb729f5c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -162,6 +162,7 @@ enum iwl_power_scheme { | |||
162 | struct iwl_mvm_power_ops { | 162 | struct iwl_mvm_power_ops { |
163 | int (*power_update_mode)(struct iwl_mvm *mvm, | 163 | int (*power_update_mode)(struct iwl_mvm *mvm, |
164 | struct ieee80211_vif *vif); | 164 | struct ieee80211_vif *vif); |
165 | int (*power_update_device_mode)(struct iwl_mvm *mvm); | ||
165 | int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 166 | int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
166 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 167 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
167 | int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 168 | int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
@@ -241,12 +242,18 @@ enum iwl_mvm_smps_type_request { | |||
241 | * @last_beacon_signal: last beacon rssi signal in dbm | 242 | * @last_beacon_signal: last beacon rssi signal in dbm |
242 | * @ave_beacon_signal: average beacon signal | 243 | * @ave_beacon_signal: average beacon signal |
243 | * @last_cqm_event: rssi of the last cqm event | 244 | * @last_cqm_event: rssi of the last cqm event |
245 | * @bt_coex_min_thold: minimum threshold for BT coex | ||
246 | * @bt_coex_max_thold: maximum threshold for BT coex | ||
247 | * @last_bt_coex_event: rssi of the last BT coex event | ||
244 | */ | 248 | */ |
245 | struct iwl_mvm_vif_bf_data { | 249 | struct iwl_mvm_vif_bf_data { |
246 | bool bf_enabled; | 250 | bool bf_enabled; |
247 | bool ba_enabled; | 251 | bool ba_enabled; |
248 | s8 ave_beacon_signal; | 252 | s8 ave_beacon_signal; |
249 | s8 last_cqm_event; | 253 | s8 last_cqm_event; |
254 | s8 bt_coex_min_thold; | ||
255 | s8 bt_coex_max_thold; | ||
256 | s8 last_bt_coex_event; | ||
250 | }; | 257 | }; |
251 | 258 | ||
252 | /** | 259 | /** |
@@ -255,8 +262,8 @@ struct iwl_mvm_vif_bf_data { | |||
255 | * @color: to solve races upon MAC addition and removal | 262 | * @color: to solve races upon MAC addition and removal |
256 | * @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA | 263 | * @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA |
257 | * @uploaded: indicates the MAC context has been added to the device | 264 | * @uploaded: indicates the MAC context has been added to the device |
258 | * @ap_active: indicates that ap context is configured, and that the interface | 265 | * @ap_ibss_active: indicates that AP/IBSS is configured and that the interface |
259 | * should get quota etc. | 266 | * should get quota etc. |
260 | * @monitor_active: indicates that monitor context is configured, and that the | 267 | * @monitor_active: indicates that monitor context is configured, and that the |
261 | * interface should get quota etc. | 268 | * interface should get quota etc. |
262 | * @queue_params: QoS params for this MAC | 269 | * @queue_params: QoS params for this MAC |
@@ -272,7 +279,7 @@ struct iwl_mvm_vif { | |||
272 | u8 ap_sta_id; | 279 | u8 ap_sta_id; |
273 | 280 | ||
274 | bool uploaded; | 281 | bool uploaded; |
275 | bool ap_active; | 282 | bool ap_ibss_active; |
276 | bool monitor_active; | 283 | bool monitor_active; |
277 | struct iwl_mvm_vif_bf_data bf_data; | 284 | struct iwl_mvm_vif_bf_data bf_data; |
278 | 285 | ||
@@ -306,6 +313,9 @@ struct iwl_mvm_vif { | |||
306 | 313 | ||
307 | int tx_key_idx; | 314 | int tx_key_idx; |
308 | 315 | ||
316 | bool seqno_valid; | ||
317 | u16 seqno; | ||
318 | |||
309 | #if IS_ENABLED(CONFIG_IPV6) | 319 | #if IS_ENABLED(CONFIG_IPV6) |
310 | /* IPv6 addresses for WoWLAN */ | 320 | /* IPv6 addresses for WoWLAN */ |
311 | struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX]; | 321 | struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX]; |
@@ -333,6 +343,7 @@ iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif) | |||
333 | enum iwl_scan_status { | 343 | enum iwl_scan_status { |
334 | IWL_MVM_SCAN_NONE, | 344 | IWL_MVM_SCAN_NONE, |
335 | IWL_MVM_SCAN_OS, | 345 | IWL_MVM_SCAN_OS, |
346 | IWL_MVM_SCAN_SCHED, | ||
336 | }; | 347 | }; |
337 | 348 | ||
338 | /** | 349 | /** |
@@ -434,7 +445,7 @@ struct iwl_mvm { | |||
434 | 445 | ||
435 | enum iwl_ucode_type cur_ucode; | 446 | enum iwl_ucode_type cur_ucode; |
436 | bool ucode_loaded; | 447 | bool ucode_loaded; |
437 | bool init_ucode_run; | 448 | bool init_ucode_complete; |
438 | u32 error_event_table; | 449 | u32 error_event_table; |
439 | u32 log_event_table; | 450 | u32 log_event_table; |
440 | 451 | ||
@@ -470,6 +481,9 @@ struct iwl_mvm { | |||
470 | enum iwl_scan_status scan_status; | 481 | enum iwl_scan_status scan_status; |
471 | struct iwl_scan_cmd *scan_cmd; | 482 | struct iwl_scan_cmd *scan_cmd; |
472 | 483 | ||
484 | /* rx chain antennas set through debugfs for the scan command */ | ||
485 | u8 scan_rx_ant; | ||
486 | |||
473 | /* Internal station */ | 487 | /* Internal station */ |
474 | struct iwl_mvm_int_sta aux_sta; | 488 | struct iwl_mvm_int_sta aux_sta; |
475 | 489 | ||
@@ -479,7 +493,8 @@ struct iwl_mvm { | |||
479 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 493 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
480 | struct dentry *debugfs_dir; | 494 | struct dentry *debugfs_dir; |
481 | u32 dbgfs_sram_offset, dbgfs_sram_len; | 495 | u32 dbgfs_sram_offset, dbgfs_sram_len; |
482 | bool prevent_power_down_d3; | 496 | bool disable_power_off; |
497 | bool disable_power_off_d3; | ||
483 | #endif | 498 | #endif |
484 | 499 | ||
485 | struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX]; | 500 | struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX]; |
@@ -523,12 +538,23 @@ struct iwl_mvm { | |||
523 | /* BT-Coex */ | 538 | /* BT-Coex */ |
524 | u8 bt_kill_msk; | 539 | u8 bt_kill_msk; |
525 | struct iwl_bt_coex_profile_notif last_bt_notif; | 540 | struct iwl_bt_coex_profile_notif last_bt_notif; |
541 | struct iwl_bt_coex_ci_cmd last_bt_ci_cmd; | ||
526 | 542 | ||
527 | /* Thermal Throttling and CTkill */ | 543 | /* Thermal Throttling and CTkill */ |
528 | struct iwl_mvm_tt_mgmt thermal_throttle; | 544 | struct iwl_mvm_tt_mgmt thermal_throttle; |
529 | s32 temperature; /* Celsius */ | 545 | s32 temperature; /* Celsius */ |
530 | 546 | ||
531 | const struct iwl_mvm_power_ops *pm_ops; | 547 | const struct iwl_mvm_power_ops *pm_ops; |
548 | |||
549 | #ifdef CONFIG_NL80211_TESTMODE | ||
550 | u32 noa_duration; | ||
551 | struct ieee80211_vif *noa_vif; | ||
552 | #endif | ||
553 | |||
554 | /* Tx queues */ | ||
555 | u8 aux_queue; | ||
556 | u8 first_agg_queue; | ||
557 | u8 last_agg_queue; | ||
532 | }; | 558 | }; |
533 | 559 | ||
534 | /* Extract MVM priv from op_mode and _hw */ | 560 | /* Extract MVM priv from op_mode and _hw */ |
@@ -570,6 +596,9 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm); | |||
570 | /* Utils */ | 596 | /* Utils */ |
571 | int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags, | 597 | int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags, |
572 | enum ieee80211_band band); | 598 | enum ieee80211_band band); |
599 | void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags, | ||
600 | enum ieee80211_band band, | ||
601 | struct ieee80211_tx_rate *r); | ||
573 | u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); | 602 | u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); |
574 | void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); | 603 | void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); |
575 | void iwl_mvm_dump_sram(struct iwl_mvm *mvm); | 604 | void iwl_mvm_dump_sram(struct iwl_mvm *mvm); |
@@ -608,6 +637,7 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, | |||
608 | 637 | ||
609 | /* NVM */ | 638 | /* NVM */ |
610 | int iwl_nvm_init(struct iwl_mvm *mvm); | 639 | int iwl_nvm_init(struct iwl_mvm *mvm); |
640 | int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm); | ||
611 | 641 | ||
612 | int iwl_mvm_up(struct iwl_mvm *mvm); | 642 | int iwl_mvm_up(struct iwl_mvm *mvm); |
613 | int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm); | 643 | int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm); |
@@ -682,6 +712,23 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
682 | struct iwl_device_cmd *cmd); | 712 | struct iwl_device_cmd *cmd); |
683 | void iwl_mvm_cancel_scan(struct iwl_mvm *mvm); | 713 | void iwl_mvm_cancel_scan(struct iwl_mvm *mvm); |
684 | 714 | ||
715 | /* Scheduled scan */ | ||
716 | int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, | ||
717 | struct iwl_rx_cmd_buffer *rxb, | ||
718 | struct iwl_device_cmd *cmd); | ||
719 | int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, | ||
720 | struct ieee80211_vif *vif, | ||
721 | struct cfg80211_sched_scan_request *req, | ||
722 | struct ieee80211_sched_scan_ies *ies); | ||
723 | int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, | ||
724 | struct cfg80211_sched_scan_request *req); | ||
725 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | ||
726 | struct cfg80211_sched_scan_request *req); | ||
727 | void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm); | ||
728 | int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm, | ||
729 | struct iwl_rx_cmd_buffer *rxb, | ||
730 | struct iwl_device_cmd *cmd); | ||
731 | |||
685 | /* MVM debugfs */ | 732 | /* MVM debugfs */ |
686 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 733 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
687 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); | 734 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); |
@@ -720,6 +767,13 @@ static inline int iwl_mvm_power_disable(struct iwl_mvm *mvm, | |||
720 | return mvm->pm_ops->power_disable(mvm, vif); | 767 | return mvm->pm_ops->power_disable(mvm, vif); |
721 | } | 768 | } |
722 | 769 | ||
770 | static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm) | ||
771 | { | ||
772 | if (mvm->pm_ops->power_update_device_mode) | ||
773 | return mvm->pm_ops->power_update_device_mode(mvm); | ||
774 | return 0; | ||
775 | } | ||
776 | |||
723 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 777 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
724 | static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm, | 778 | static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm, |
725 | struct ieee80211_vif *vif, | 779 | struct ieee80211_vif *vif, |
@@ -745,6 +799,15 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, | |||
745 | void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, | 799 | void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, |
746 | struct ieee80211_vif *vif, int idx); | 800 | struct ieee80211_vif *vif, int idx); |
747 | extern const struct file_operations iwl_dbgfs_d3_test_ops; | 801 | extern const struct file_operations iwl_dbgfs_d3_test_ops; |
802 | #ifdef CONFIG_PM_SLEEP | ||
803 | void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, | ||
804 | struct ieee80211_vif *vif); | ||
805 | #else | ||
806 | static inline void | ||
807 | iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
808 | { | ||
809 | } | ||
810 | #endif | ||
748 | 811 | ||
749 | /* BT Coex */ | 812 | /* BT Coex */ |
750 | int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm); | 813 | int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm); |
@@ -754,7 +817,20 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, | |||
754 | struct iwl_device_cmd *cmd); | 817 | struct iwl_device_cmd *cmd); |
755 | void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 818 | void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
756 | enum ieee80211_rssi_event rssi_event); | 819 | enum ieee80211_rssi_event rssi_event); |
757 | void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 820 | void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm); |
821 | u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm, | ||
822 | struct ieee80211_sta *sta); | ||
823 | bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, | ||
824 | struct ieee80211_sta *sta); | ||
825 | |||
826 | enum iwl_bt_kill_msk { | ||
827 | BT_KILL_MSK_DEFAULT, | ||
828 | BT_KILL_MSK_SCO_HID_A2DP, | ||
829 | BT_KILL_MSK_REDUCED_TXPOW, | ||
830 | BT_KILL_MSK_MAX, | ||
831 | }; | ||
832 | extern const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX]; | ||
833 | extern const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX]; | ||
758 | 834 | ||
759 | /* beacon filtering */ | 835 | /* beacon filtering */ |
760 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 836 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index edb94ea31654..2beffd028b67 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c | |||
@@ -77,7 +77,7 @@ static const int nvm_to_read[] = { | |||
77 | 77 | ||
78 | /* Default NVM size to read */ | 78 | /* Default NVM size to read */ |
79 | #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) | 79 | #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) |
80 | #define IWL_MAX_NVM_SECTION_SIZE 6000 | 80 | #define IWL_MAX_NVM_SECTION_SIZE 7000 |
81 | 81 | ||
82 | #define NVM_WRITE_OPCODE 1 | 82 | #define NVM_WRITE_OPCODE 1 |
83 | #define NVM_READ_OPCODE 0 | 83 | #define NVM_READ_OPCODE 0 |
@@ -259,6 +259,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) | |||
259 | #define MAX_NVM_FILE_LEN 16384 | 259 | #define MAX_NVM_FILE_LEN 16384 |
260 | 260 | ||
261 | /* | 261 | /* |
262 | * Reads external NVM from a file into mvm->nvm_sections | ||
263 | * | ||
262 | * HOW TO CREATE THE NVM FILE FORMAT: | 264 | * HOW TO CREATE THE NVM FILE FORMAT: |
263 | * ------------------------------ | 265 | * ------------------------------ |
264 | * 1. create hex file, format: | 266 | * 1. create hex file, format: |
@@ -277,20 +279,23 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) | |||
277 | * | 279 | * |
278 | * 4. save as "iNVM_xxx.bin" under /lib/firmware | 280 | * 4. save as "iNVM_xxx.bin" under /lib/firmware |
279 | */ | 281 | */ |
280 | static int iwl_mvm_load_external_nvm(struct iwl_mvm *mvm) | 282 | static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) |
281 | { | 283 | { |
282 | int ret, section_id, section_size; | 284 | int ret, section_size; |
285 | u16 section_id; | ||
283 | const struct firmware *fw_entry; | 286 | const struct firmware *fw_entry; |
284 | const struct { | 287 | const struct { |
285 | __le16 word1; | 288 | __le16 word1; |
286 | __le16 word2; | 289 | __le16 word2; |
287 | u8 data[]; | 290 | u8 data[]; |
288 | } *file_sec; | 291 | } *file_sec; |
289 | const u8 *eof; | 292 | const u8 *eof, *temp; |
290 | 293 | ||
291 | #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) | 294 | #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) |
292 | #define NVM_WORD2_ID(x) (x >> 12) | 295 | #define NVM_WORD2_ID(x) (x >> 12) |
293 | 296 | ||
297 | IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); | ||
298 | |||
294 | /* | 299 | /* |
295 | * Obtain NVM image via request_firmware. Since we already used | 300 | * Obtain NVM image via request_firmware. Since we already used |
296 | * request_firmware_nowait() for the firmware binary load and only | 301 | * request_firmware_nowait() for the firmware binary load and only |
@@ -362,12 +367,18 @@ static int iwl_mvm_load_external_nvm(struct iwl_mvm *mvm) | |||
362 | break; | 367 | break; |
363 | } | 368 | } |
364 | 369 | ||
365 | ret = iwl_nvm_write_section(mvm, section_id, file_sec->data, | 370 | temp = kmemdup(file_sec->data, section_size, GFP_KERNEL); |
366 | section_size); | 371 | if (!temp) { |
367 | if (ret < 0) { | 372 | ret = -ENOMEM; |
368 | IWL_ERR(mvm, "iwl_mvm_send_cmd failed: %d\n", ret); | 373 | break; |
374 | } | ||
375 | if (WARN_ON(section_id >= NVM_NUM_OF_SECTIONS)) { | ||
376 | IWL_ERR(mvm, "Invalid NVM section ID\n"); | ||
377 | ret = -EINVAL; | ||
369 | break; | 378 | break; |
370 | } | 379 | } |
380 | mvm->nvm_sections[section_id].data = temp; | ||
381 | mvm->nvm_sections[section_id].length = section_size; | ||
371 | 382 | ||
372 | /* advance to the next section */ | 383 | /* advance to the next section */ |
373 | file_sec = (void *)(file_sec->data + section_size); | 384 | file_sec = (void *)(file_sec->data + section_size); |
@@ -377,6 +388,28 @@ out: | |||
377 | return ret; | 388 | return ret; |
378 | } | 389 | } |
379 | 390 | ||
391 | /* Loads the NVM data stored in mvm->nvm_sections into the NIC */ | ||
392 | int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm) | ||
393 | { | ||
394 | int i, ret; | ||
395 | u16 section_id; | ||
396 | struct iwl_nvm_section *sections = mvm->nvm_sections; | ||
397 | |||
398 | IWL_DEBUG_EEPROM(mvm->trans->dev, "'Write to NVM\n"); | ||
399 | |||
400 | for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) { | ||
401 | section_id = nvm_to_read[i]; | ||
402 | ret = iwl_nvm_write_section(mvm, section_id, | ||
403 | sections[section_id].data, | ||
404 | sections[section_id].length); | ||
405 | if (ret < 0) { | ||
406 | IWL_ERR(mvm, "iwl_mvm_send_cmd failed: %d\n", ret); | ||
407 | break; | ||
408 | } | ||
409 | } | ||
410 | return ret; | ||
411 | } | ||
412 | |||
380 | int iwl_nvm_init(struct iwl_mvm *mvm) | 413 | int iwl_nvm_init(struct iwl_mvm *mvm) |
381 | { | 414 | { |
382 | int ret, i, section; | 415 | int ret, i, section; |
@@ -385,36 +418,36 @@ int iwl_nvm_init(struct iwl_mvm *mvm) | |||
385 | /* load external NVM if configured */ | 418 | /* load external NVM if configured */ |
386 | if (iwlwifi_mod_params.nvm_file) { | 419 | if (iwlwifi_mod_params.nvm_file) { |
387 | /* move to External NVM flow */ | 420 | /* move to External NVM flow */ |
388 | ret = iwl_mvm_load_external_nvm(mvm); | 421 | ret = iwl_mvm_read_external_nvm(mvm); |
389 | if (ret) | 422 | if (ret) |
390 | return ret; | 423 | return ret; |
391 | } | 424 | } else { |
392 | 425 | /* Read From FW NVM */ | |
393 | /* Read From FW NVM */ | 426 | IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); |
394 | IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); | 427 | |
395 | 428 | /* TODO: find correct NVM max size for a section */ | |
396 | /* TODO: find correct NVM max size for a section */ | 429 | nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, |
397 | nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, | 430 | GFP_KERNEL); |
398 | GFP_KERNEL); | 431 | if (!nvm_buffer) |
399 | if (!nvm_buffer) | 432 | return -ENOMEM; |
400 | return -ENOMEM; | 433 | for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) { |
401 | for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) { | 434 | section = nvm_to_read[i]; |
402 | section = nvm_to_read[i]; | 435 | /* we override the constness for initial read */ |
403 | /* we override the constness for initial read */ | 436 | ret = iwl_nvm_read_section(mvm, section, nvm_buffer); |
404 | ret = iwl_nvm_read_section(mvm, section, nvm_buffer); | 437 | if (ret < 0) |
405 | if (ret < 0) | 438 | break; |
406 | break; | 439 | temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); |
407 | temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); | 440 | if (!temp) { |
408 | if (!temp) { | 441 | ret = -ENOMEM; |
409 | ret = -ENOMEM; | 442 | break; |
410 | break; | 443 | } |
444 | mvm->nvm_sections[section].data = temp; | ||
445 | mvm->nvm_sections[section].length = ret; | ||
411 | } | 446 | } |
412 | mvm->nvm_sections[section].data = temp; | 447 | kfree(nvm_buffer); |
413 | mvm->nvm_sections[section].length = ret; | 448 | if (ret < 0) |
449 | return ret; | ||
414 | } | 450 | } |
415 | kfree(nvm_buffer); | ||
416 | if (ret < 0) | ||
417 | return ret; | ||
418 | 451 | ||
419 | mvm->nvm_data = iwl_parse_nvm_sections(mvm); | 452 | mvm->nvm_data = iwl_parse_nvm_sections(mvm); |
420 | if (!mvm->nvm_data) | 453 | if (!mvm->nvm_data) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 2fcc8ef88a68..59b7cb3c6134 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -224,6 +224,10 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | |||
224 | 224 | ||
225 | RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), | 225 | RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), |
226 | RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), | 226 | RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), |
227 | RX_HANDLER(SCAN_OFFLOAD_COMPLETE, | ||
228 | iwl_mvm_rx_scan_offload_complete_notif, false), | ||
229 | RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_sched_scan_results, | ||
230 | false), | ||
227 | 231 | ||
228 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), | 232 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), |
229 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), | 233 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), |
@@ -249,6 +253,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
249 | CMD(TIME_EVENT_NOTIFICATION), | 253 | CMD(TIME_EVENT_NOTIFICATION), |
250 | CMD(BINDING_CONTEXT_CMD), | 254 | CMD(BINDING_CONTEXT_CMD), |
251 | CMD(TIME_QUOTA_CMD), | 255 | CMD(TIME_QUOTA_CMD), |
256 | CMD(NON_QOS_TX_COUNTER_CMD), | ||
252 | CMD(RADIO_VERSION_NOTIFICATION), | 257 | CMD(RADIO_VERSION_NOTIFICATION), |
253 | CMD(SCAN_REQUEST_CMD), | 258 | CMD(SCAN_REQUEST_CMD), |
254 | CMD(SCAN_ABORT_CMD), | 259 | CMD(SCAN_ABORT_CMD), |
@@ -260,10 +265,12 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
260 | CMD(CALIB_RES_NOTIF_PHY_DB), | 265 | CMD(CALIB_RES_NOTIF_PHY_DB), |
261 | CMD(SET_CALIB_DEFAULT_CMD), | 266 | CMD(SET_CALIB_DEFAULT_CMD), |
262 | CMD(CALIBRATION_COMPLETE_NOTIFICATION), | 267 | CMD(CALIBRATION_COMPLETE_NOTIFICATION), |
268 | CMD(ADD_STA_KEY), | ||
263 | CMD(ADD_STA), | 269 | CMD(ADD_STA), |
264 | CMD(REMOVE_STA), | 270 | CMD(REMOVE_STA), |
265 | CMD(LQ_CMD), | 271 | CMD(LQ_CMD), |
266 | CMD(SCAN_OFFLOAD_CONFIG_CMD), | 272 | CMD(SCAN_OFFLOAD_CONFIG_CMD), |
273 | CMD(MATCH_FOUND_NOTIFICATION), | ||
267 | CMD(SCAN_OFFLOAD_REQUEST_CMD), | 274 | CMD(SCAN_OFFLOAD_REQUEST_CMD), |
268 | CMD(SCAN_OFFLOAD_ABORT_CMD), | 275 | CMD(SCAN_OFFLOAD_ABORT_CMD), |
269 | CMD(SCAN_OFFLOAD_COMPLETE), | 276 | CMD(SCAN_OFFLOAD_COMPLETE), |
@@ -303,6 +310,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
303 | CMD(REPLY_BEACON_FILTERING_CMD), | 310 | CMD(REPLY_BEACON_FILTERING_CMD), |
304 | CMD(REPLY_THERMAL_MNG_BACKOFF), | 311 | CMD(REPLY_THERMAL_MNG_BACKOFF), |
305 | CMD(MAC_PM_POWER_TABLE), | 312 | CMD(MAC_PM_POWER_TABLE), |
313 | CMD(BT_COEX_CI), | ||
306 | }; | 314 | }; |
307 | #undef CMD | 315 | #undef CMD |
308 | 316 | ||
@@ -344,6 +352,14 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
344 | 352 | ||
345 | mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0; | 353 | mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0; |
346 | 354 | ||
355 | mvm->aux_queue = 15; | ||
356 | mvm->first_agg_queue = 16; | ||
357 | mvm->last_agg_queue = mvm->cfg->base_params->num_of_queues - 1; | ||
358 | if (mvm->cfg->base_params->num_of_queues == 16) { | ||
359 | mvm->aux_queue = 11; | ||
360 | mvm->first_agg_queue = 12; | ||
361 | } | ||
362 | |||
347 | mutex_init(&mvm->mutex); | 363 | mutex_init(&mvm->mutex); |
348 | spin_lock_init(&mvm->async_handlers_lock); | 364 | spin_lock_init(&mvm->async_handlers_lock); |
349 | INIT_LIST_HEAD(&mvm->time_event_list); | 365 | INIT_LIST_HEAD(&mvm->time_event_list); |
@@ -401,24 +417,32 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
401 | IWL_INFO(mvm, "Detected %s, REV=0x%X\n", | 417 | IWL_INFO(mvm, "Detected %s, REV=0x%X\n", |
402 | mvm->cfg->name, mvm->trans->hw_rev); | 418 | mvm->cfg->name, mvm->trans->hw_rev); |
403 | 419 | ||
404 | err = iwl_trans_start_hw(mvm->trans); | ||
405 | if (err) | ||
406 | goto out_free; | ||
407 | |||
408 | iwl_mvm_tt_initialize(mvm); | 420 | iwl_mvm_tt_initialize(mvm); |
409 | 421 | ||
410 | mutex_lock(&mvm->mutex); | 422 | /* |
411 | err = iwl_run_init_mvm_ucode(mvm, true); | 423 | * If the NVM exists in an external file, |
412 | mutex_unlock(&mvm->mutex); | 424 | * there is no need to unnecessarily power up the NIC at driver load |
413 | /* returns 0 if successful, 1 if success but in rfkill */ | 425 | */ |
414 | if (err < 0 && !iwlmvm_mod_params.init_dbg) { | 426 | if (iwlwifi_mod_params.nvm_file) { |
415 | IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); | 427 | iwl_nvm_init(mvm); |
416 | goto out_free; | 428 | } else { |
417 | } | 429 | err = iwl_trans_start_hw(mvm->trans); |
430 | if (err) | ||
431 | goto out_free; | ||
432 | |||
433 | mutex_lock(&mvm->mutex); | ||
434 | err = iwl_run_init_mvm_ucode(mvm, true); | ||
435 | mutex_unlock(&mvm->mutex); | ||
436 | /* returns 0 if successful, 1 if success but in rfkill */ | ||
437 | if (err < 0 && !iwlmvm_mod_params.init_dbg) { | ||
438 | IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); | ||
439 | goto out_free; | ||
440 | } | ||
418 | 441 | ||
419 | /* Stop the hw after the ALIVE and NVM has been read */ | 442 | /* Stop the hw after the ALIVE and NVM has been read */ |
420 | if (!iwlmvm_mod_params.init_dbg) | 443 | if (!iwlmvm_mod_params.init_dbg) |
421 | iwl_trans_stop_hw(mvm->trans, false); | 444 | iwl_trans_stop_hw(mvm->trans, false); |
445 | } | ||
422 | 446 | ||
423 | scan_size = sizeof(struct iwl_scan_cmd) + | 447 | scan_size = sizeof(struct iwl_scan_cmd) + |
424 | mvm->fw->ucode_capa.max_probe_length + | 448 | mvm->fw->ucode_capa.max_probe_length + |
@@ -449,7 +473,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
449 | out_free: | 473 | out_free: |
450 | iwl_phy_db_free(mvm->phy_db); | 474 | iwl_phy_db_free(mvm->phy_db); |
451 | kfree(mvm->scan_cmd); | 475 | kfree(mvm->scan_cmd); |
452 | iwl_trans_stop_hw(trans, true); | 476 | if (!iwlwifi_mod_params.nvm_file) |
477 | iwl_trans_stop_hw(trans, true); | ||
453 | ieee80211_free_hw(mvm->hw); | 478 | ieee80211_free_hw(mvm->hw); |
454 | return NULL; | 479 | return NULL; |
455 | } | 480 | } |
@@ -715,6 +740,9 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) | |||
715 | case IWL_MVM_SCAN_OS: | 740 | case IWL_MVM_SCAN_OS: |
716 | ieee80211_scan_completed(mvm->hw, true); | 741 | ieee80211_scan_completed(mvm->hw, true); |
717 | break; | 742 | break; |
743 | case IWL_MVM_SCAN_SCHED: | ||
744 | ieee80211_sched_scan_stopped(mvm->hw); | ||
745 | break; | ||
718 | } | 746 | } |
719 | 747 | ||
720 | if (mvm->restart_fw > 0) | 748 | if (mvm->restart_fw > 0) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index d58e393324ef..550824aa84ea 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c | |||
@@ -300,11 +300,6 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
300 | } | 300 | } |
301 | 301 | ||
302 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) { | 302 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) { |
303 | cmd->rx_data_timeout_uapsd = | ||
304 | cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT); | ||
305 | cmd->tx_data_timeout_uapsd = | ||
306 | cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT); | ||
307 | |||
308 | if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) | | 303 | if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) | |
309 | BIT(IEEE80211_AC_VI) | | 304 | BIT(IEEE80211_AC_VI) | |
310 | BIT(IEEE80211_AC_BE) | | 305 | BIT(IEEE80211_AC_BE) | |
@@ -319,10 +314,31 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
319 | } | 314 | } |
320 | 315 | ||
321 | cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP; | 316 | cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP; |
322 | cmd->heavy_tx_thld_packets = | 317 | |
323 | IWL_MVM_PS_HEAVY_TX_THLD_PACKETS; | 318 | if (mvm->cur_ucode == IWL_UCODE_WOWLAN || cmd->flags & |
324 | cmd->heavy_rx_thld_packets = | 319 | cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) { |
325 | IWL_MVM_PS_HEAVY_RX_THLD_PACKETS; | 320 | cmd->rx_data_timeout_uapsd = |
321 | cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT); | ||
322 | cmd->tx_data_timeout_uapsd = | ||
323 | cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT); | ||
324 | } else { | ||
325 | cmd->rx_data_timeout_uapsd = | ||
326 | cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT); | ||
327 | cmd->tx_data_timeout_uapsd = | ||
328 | cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT); | ||
329 | } | ||
330 | |||
331 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) { | ||
332 | cmd->heavy_tx_thld_packets = | ||
333 | IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS; | ||
334 | cmd->heavy_rx_thld_packets = | ||
335 | IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS; | ||
336 | } else { | ||
337 | cmd->heavy_tx_thld_packets = | ||
338 | IWL_MVM_PS_HEAVY_TX_THLD_PACKETS; | ||
339 | cmd->heavy_rx_thld_packets = | ||
340 | IWL_MVM_PS_HEAVY_RX_THLD_PACKETS; | ||
341 | } | ||
326 | cmd->heavy_tx_thld_percentage = | 342 | cmd->heavy_tx_thld_percentage = |
327 | IWL_MVM_PS_HEAVY_TX_THLD_PERCENT; | 343 | IWL_MVM_PS_HEAVY_TX_THLD_PERCENT; |
328 | cmd->heavy_rx_thld_percentage = | 344 | cmd->heavy_rx_thld_percentage = |
@@ -430,6 +446,32 @@ static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm, | |||
430 | sizeof(cmd), &cmd); | 446 | sizeof(cmd), &cmd); |
431 | } | 447 | } |
432 | 448 | ||
449 | static int iwl_mvm_power_update_device(struct iwl_mvm *mvm) | ||
450 | { | ||
451 | struct iwl_device_power_cmd cmd = { | ||
452 | .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), | ||
453 | }; | ||
454 | |||
455 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) | ||
456 | return 0; | ||
457 | |||
458 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) | ||
459 | cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK); | ||
460 | |||
461 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
462 | if ((mvm->cur_ucode == IWL_UCODE_WOWLAN) ? mvm->disable_power_off_d3 : | ||
463 | mvm->disable_power_off) | ||
464 | cmd.flags &= | ||
465 | cpu_to_le16(~DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
466 | #endif | ||
467 | IWL_DEBUG_POWER(mvm, | ||
468 | "Sending device power command with flags = 0x%X\n", | ||
469 | cmd.flags); | ||
470 | |||
471 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, sizeof(cmd), | ||
472 | &cmd); | ||
473 | } | ||
474 | |||
433 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 475 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
434 | static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, | 476 | static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, |
435 | struct ieee80211_vif *vif, char *buf, | 477 | struct ieee80211_vif *vif, char *buf, |
@@ -440,10 +482,11 @@ static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, | |||
440 | 482 | ||
441 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | 483 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); |
442 | 484 | ||
443 | pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", | 485 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) |
444 | (cmd.flags & | 486 | pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", |
445 | cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? | 487 | (cmd.flags & |
446 | 0 : 1); | 488 | cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? |
489 | 0 : 1); | ||
447 | pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", | 490 | pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", |
448 | iwlmvm_mod_params.power_scheme); | 491 | iwlmvm_mod_params.power_scheme); |
449 | pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", | 492 | pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", |
@@ -609,6 +652,7 @@ int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, | |||
609 | 652 | ||
610 | const struct iwl_mvm_power_ops pm_mac_ops = { | 653 | const struct iwl_mvm_power_ops pm_mac_ops = { |
611 | .power_update_mode = iwl_mvm_power_mac_update_mode, | 654 | .power_update_mode = iwl_mvm_power_mac_update_mode, |
655 | .power_update_device_mode = iwl_mvm_power_update_device, | ||
612 | .power_disable = iwl_mvm_power_mac_disable, | 656 | .power_disable = iwl_mvm_power_mac_disable, |
613 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 657 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
614 | .power_dbgfs_read = iwl_mvm_power_mac_dbgfs_read, | 658 | .power_dbgfs_read = iwl_mvm_power_mac_dbgfs_read, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 5c6ae16ec52b..17e2bc827f9a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c | |||
@@ -110,7 +110,8 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, | |||
110 | data->n_interfaces[id]++; | 110 | data->n_interfaces[id]++; |
111 | break; | 111 | break; |
112 | case NL80211_IFTYPE_AP: | 112 | case NL80211_IFTYPE_AP: |
113 | if (mvmvif->ap_active) | 113 | case NL80211_IFTYPE_ADHOC: |
114 | if (mvmvif->ap_ibss_active) | ||
114 | data->n_interfaces[id]++; | 115 | data->n_interfaces[id]++; |
115 | break; | 116 | break; |
116 | case NL80211_IFTYPE_MONITOR: | 117 | case NL80211_IFTYPE_MONITOR: |
@@ -119,16 +120,45 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, | |||
119 | break; | 120 | break; |
120 | case NL80211_IFTYPE_P2P_DEVICE: | 121 | case NL80211_IFTYPE_P2P_DEVICE: |
121 | break; | 122 | break; |
122 | case NL80211_IFTYPE_ADHOC: | ||
123 | if (vif->bss_conf.ibss_joined) | ||
124 | data->n_interfaces[id]++; | ||
125 | break; | ||
126 | default: | 123 | default: |
127 | WARN_ON_ONCE(1); | 124 | WARN_ON_ONCE(1); |
128 | break; | 125 | break; |
129 | } | 126 | } |
130 | } | 127 | } |
131 | 128 | ||
129 | static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm, | ||
130 | struct iwl_time_quota_cmd *cmd) | ||
131 | { | ||
132 | #ifdef CONFIG_NL80211_TESTMODE | ||
133 | struct iwl_mvm_vif *mvmvif; | ||
134 | int i, phy_id = -1, beacon_int = 0; | ||
135 | |||
136 | if (!mvm->noa_duration || !mvm->noa_vif) | ||
137 | return; | ||
138 | |||
139 | mvmvif = iwl_mvm_vif_from_mac80211(mvm->noa_vif); | ||
140 | if (!mvmvif->ap_ibss_active) | ||
141 | return; | ||
142 | |||
143 | phy_id = mvmvif->phy_ctxt->id; | ||
144 | beacon_int = mvm->noa_vif->bss_conf.beacon_int; | ||
145 | |||
146 | for (i = 0; i < MAX_BINDINGS; i++) { | ||
147 | u32 id_n_c = le32_to_cpu(cmd->quotas[i].id_and_color); | ||
148 | u32 id = (id_n_c & FW_CTXT_ID_MSK) >> FW_CTXT_ID_POS; | ||
149 | u32 quota = le32_to_cpu(cmd->quotas[i].quota); | ||
150 | |||
151 | if (id != phy_id) | ||
152 | continue; | ||
153 | |||
154 | quota *= (beacon_int - mvm->noa_duration); | ||
155 | quota /= beacon_int; | ||
156 | |||
157 | cmd->quotas[i].quota = cpu_to_le32(quota); | ||
158 | } | ||
159 | #endif | ||
160 | } | ||
161 | |||
132 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | 162 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) |
133 | { | 163 | { |
134 | struct iwl_time_quota_cmd cmd = {}; | 164 | struct iwl_time_quota_cmd cmd = {}; |
@@ -196,6 +226,8 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | |||
196 | /* Give the remainder of the session to the first binding */ | 226 | /* Give the remainder of the session to the first binding */ |
197 | le32_add_cpu(&cmd.quotas[0].quota, quota_rem); | 227 | le32_add_cpu(&cmd.quotas[0].quota, quota_rem); |
198 | 228 | ||
229 | iwl_mvm_adjust_quota_for_noa(mvm, &cmd); | ||
230 | |||
199 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, | 231 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, |
200 | sizeof(cmd), &cmd); | 232 | sizeof(cmd), &cmd); |
201 | if (ret) | 233 | if (ret) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 4ffaa3fa153f..a0b4cc8d9c3b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
@@ -82,13 +82,24 @@ static const u8 ant_toggle_lookup[] = { | |||
82 | [ANT_ABC] = ANT_ABC, | 82 | [ANT_ABC] = ANT_ABC, |
83 | }; | 83 | }; |
84 | 84 | ||
85 | #define IWL_DECLARE_RATE_INFO(r, s, rp, rn) \ | 85 | #define IWL_DECLARE_RATE_INFO(r, s, rp, rn) \ |
86 | [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ | 86 | [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ |
87 | IWL_RATE_SISO_##s##M_PLCP, \ | 87 | IWL_RATE_HT_SISO_MCS_##s##_PLCP, \ |
88 | IWL_RATE_MIMO2_##s##M_PLCP,\ | 88 | IWL_RATE_HT_MIMO2_MCS_##s##_PLCP, \ |
89 | IWL_RATE_##rp##M_INDEX, \ | 89 | IWL_RATE_VHT_SISO_MCS_##s##_PLCP, \ |
90 | IWL_RATE_VHT_MIMO2_MCS_##s##_PLCP,\ | ||
91 | IWL_RATE_##rp##M_INDEX, \ | ||
90 | IWL_RATE_##rn##M_INDEX } | 92 | IWL_RATE_##rn##M_INDEX } |
91 | 93 | ||
94 | #define IWL_DECLARE_MCS_RATE(s) \ | ||
95 | [IWL_RATE_MCS_##s##_INDEX] = { IWL_RATE_INVM_PLCP, \ | ||
96 | IWL_RATE_HT_SISO_MCS_##s##_PLCP, \ | ||
97 | IWL_RATE_HT_MIMO2_MCS_##s##_PLCP, \ | ||
98 | IWL_RATE_VHT_SISO_MCS_##s##_PLCP, \ | ||
99 | IWL_RATE_VHT_MIMO2_MCS_##s##_PLCP, \ | ||
100 | IWL_RATE_INVM_INDEX, \ | ||
101 | IWL_RATE_INVM_INDEX } | ||
102 | |||
92 | /* | 103 | /* |
93 | * Parameter order: | 104 | * Parameter order: |
94 | * rate, ht rate, prev rate, next rate | 105 | * rate, ht rate, prev rate, next rate |
@@ -102,16 +113,17 @@ static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = { | |||
102 | IWL_DECLARE_RATE_INFO(2, INV, 1, 5), /* 2mbps */ | 113 | IWL_DECLARE_RATE_INFO(2, INV, 1, 5), /* 2mbps */ |
103 | IWL_DECLARE_RATE_INFO(5, INV, 2, 11), /*5.5mbps */ | 114 | IWL_DECLARE_RATE_INFO(5, INV, 2, 11), /*5.5mbps */ |
104 | IWL_DECLARE_RATE_INFO(11, INV, 9, 12), /* 11mbps */ | 115 | IWL_DECLARE_RATE_INFO(11, INV, 9, 12), /* 11mbps */ |
105 | IWL_DECLARE_RATE_INFO(6, 6, 5, 11), /* 6mbps */ | 116 | IWL_DECLARE_RATE_INFO(6, 0, 5, 11), /* 6mbps ; MCS 0 */ |
106 | IWL_DECLARE_RATE_INFO(9, 6, 6, 11), /* 9mbps */ | 117 | IWL_DECLARE_RATE_INFO(9, INV, 6, 11), /* 9mbps */ |
107 | IWL_DECLARE_RATE_INFO(12, 12, 11, 18), /* 12mbps */ | 118 | IWL_DECLARE_RATE_INFO(12, 1, 11, 18), /* 12mbps ; MCS 1 */ |
108 | IWL_DECLARE_RATE_INFO(18, 18, 12, 24), /* 18mbps */ | 119 | IWL_DECLARE_RATE_INFO(18, 2, 12, 24), /* 18mbps ; MCS 2 */ |
109 | IWL_DECLARE_RATE_INFO(24, 24, 18, 36), /* 24mbps */ | 120 | IWL_DECLARE_RATE_INFO(24, 3, 18, 36), /* 24mbps ; MCS 3 */ |
110 | IWL_DECLARE_RATE_INFO(36, 36, 24, 48), /* 36mbps */ | 121 | IWL_DECLARE_RATE_INFO(36, 4, 24, 48), /* 36mbps ; MCS 4 */ |
111 | IWL_DECLARE_RATE_INFO(48, 48, 36, 54), /* 48mbps */ | 122 | IWL_DECLARE_RATE_INFO(48, 5, 36, 54), /* 48mbps ; MCS 5 */ |
112 | IWL_DECLARE_RATE_INFO(54, 54, 48, INV), /* 54mbps */ | 123 | IWL_DECLARE_RATE_INFO(54, 6, 48, INV), /* 54mbps ; MCS 6 */ |
113 | IWL_DECLARE_RATE_INFO(60, 60, 48, INV), /* 60mbps */ | 124 | IWL_DECLARE_MCS_RATE(7), /* MCS 7 */ |
114 | /* FIXME:RS: ^^ should be INV (legacy) */ | 125 | IWL_DECLARE_MCS_RATE(8), /* MCS 8 */ |
126 | IWL_DECLARE_MCS_RATE(9), /* MCS 9 */ | ||
115 | }; | 127 | }; |
116 | 128 | ||
117 | static inline u8 rs_extract_rate(u32 rate_n_flags) | 129 | static inline u8 rs_extract_rate(u32 rate_n_flags) |
@@ -124,26 +136,30 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) | |||
124 | { | 136 | { |
125 | int idx = 0; | 137 | int idx = 0; |
126 | 138 | ||
127 | /* HT rate format */ | ||
128 | if (rate_n_flags & RATE_MCS_HT_MSK) { | 139 | if (rate_n_flags & RATE_MCS_HT_MSK) { |
129 | idx = rs_extract_rate(rate_n_flags); | 140 | idx = rate_n_flags & RATE_HT_MCS_RATE_CODE_MSK; |
130 | 141 | idx += IWL_RATE_MCS_0_INDEX; | |
131 | WARN_ON_ONCE(idx >= IWL_RATE_MIMO3_6M_PLCP); | ||
132 | if (idx >= IWL_RATE_MIMO2_6M_PLCP) | ||
133 | idx = idx - IWL_RATE_MIMO2_6M_PLCP; | ||
134 | 142 | ||
135 | idx += IWL_FIRST_OFDM_RATE; | 143 | /* skip 9M not supported in HT*/ |
136 | /* skip 9M not supported in ht*/ | ||
137 | if (idx >= IWL_RATE_9M_INDEX) | 144 | if (idx >= IWL_RATE_9M_INDEX) |
138 | idx += 1; | 145 | idx += 1; |
139 | if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE)) | 146 | if ((idx >= IWL_FIRST_HT_RATE) && (idx <= IWL_LAST_HT_RATE)) |
140 | return idx; | 147 | return idx; |
148 | } else if (rate_n_flags & RATE_MCS_VHT_MSK) { | ||
149 | idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; | ||
150 | idx += IWL_RATE_MCS_0_INDEX; | ||
141 | 151 | ||
142 | /* legacy rate format, search for match in table */ | 152 | /* skip 9M not supported in VHT*/ |
153 | if (idx >= IWL_RATE_9M_INDEX) | ||
154 | idx++; | ||
155 | if ((idx >= IWL_FIRST_VHT_RATE) && (idx <= IWL_LAST_VHT_RATE)) | ||
156 | return idx; | ||
143 | } else { | 157 | } else { |
158 | /* legacy rate format, search for match in table */ | ||
159 | |||
160 | u8 legacy_rate = rs_extract_rate(rate_n_flags); | ||
144 | for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) | 161 | for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) |
145 | if (iwl_rates[idx].plcp == | 162 | if (iwl_rates[idx].plcp == legacy_rate) |
146 | rs_extract_rate(rate_n_flags)) | ||
147 | return idx; | 163 | return idx; |
148 | } | 164 | } |
149 | 165 | ||
@@ -155,6 +171,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
155 | struct ieee80211_sta *sta, | 171 | struct ieee80211_sta *sta, |
156 | struct iwl_lq_sta *lq_sta); | 172 | struct iwl_lq_sta *lq_sta); |
157 | static void rs_fill_link_cmd(struct iwl_mvm *mvm, | 173 | static void rs_fill_link_cmd(struct iwl_mvm *mvm, |
174 | struct ieee80211_sta *sta, | ||
158 | struct iwl_lq_sta *lq_sta, u32 rate_n_flags); | 175 | struct iwl_lq_sta *lq_sta, u32 rate_n_flags); |
159 | static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); | 176 | static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); |
160 | 177 | ||
@@ -180,35 +197,52 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, | |||
180 | */ | 197 | */ |
181 | 198 | ||
182 | static s32 expected_tpt_legacy[IWL_RATE_COUNT] = { | 199 | static s32 expected_tpt_legacy[IWL_RATE_COUNT] = { |
183 | 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0 | 200 | 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0, 0, 0 |
184 | }; | 201 | }; |
185 | 202 | ||
186 | static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = { | 203 | /* Expected TpT tables. 4 indexes: |
187 | {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202}, /* Norm */ | 204 | * 0 - NGI, 1 - SGI, 2 - AGG+NGI, 3 - AGG+SGI |
188 | {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210}, /* SGI */ | 205 | */ |
189 | {0, 0, 0, 0, 47, 0, 91, 133, 171, 242, 305, 334, 362}, /* AGG */ | 206 | static s32 expected_tpt_siso_20MHz[4][IWL_RATE_COUNT] = { |
190 | {0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */ | 207 | {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202, 216, 0}, |
208 | {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210, 225, 0}, | ||
209 | {0, 0, 0, 0, 49, 0, 97, 145, 192, 285, 375, 420, 464, 551, 0}, | ||
210 | {0, 0, 0, 0, 54, 0, 108, 160, 213, 315, 415, 465, 513, 608, 0}, | ||
191 | }; | 211 | }; |
192 | 212 | ||
193 | static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = { | 213 | static s32 expected_tpt_siso_40MHz[4][IWL_RATE_COUNT] = { |
194 | {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */ | 214 | {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257, 269, 275}, |
195 | {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */ | 215 | {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264, 275, 280}, |
196 | {0, 0, 0, 0, 94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */ | 216 | {0, 0, 0, 0, 101, 0, 199, 295, 389, 570, 744, 828, 911, 1070, 1173}, |
197 | {0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */ | 217 | {0, 0, 0, 0, 112, 0, 220, 326, 429, 629, 819, 912, 1000, 1173, 1284}, |
218 | }; | ||
219 | |||
220 | static s32 expected_tpt_siso_80MHz[4][IWL_RATE_COUNT] = { | ||
221 | {0, 0, 0, 0, 130, 0, 191, 223, 244, 273, 288, 294, 298, 305, 308}, | ||
222 | {0, 0, 0, 0, 138, 0, 200, 231, 251, 279, 293, 298, 302, 308, 312}, | ||
223 | {0, 0, 0, 0, 217, 0, 429, 634, 834, 1220, 1585, 1760, 1931, 2258, 2466}, | ||
224 | {0, 0, 0, 0, 241, 0, 475, 701, 921, 1343, 1741, 1931, 2117, 2468, 2691}, | ||
198 | }; | 225 | }; |
199 | 226 | ||
200 | static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { | 227 | static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { |
201 | {0, 0, 0, 0, 74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */ | 228 | {0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250, 261, 0}, |
202 | {0, 0, 0, 0, 81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */ | 229 | {0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256, 267, 0}, |
203 | {0, 0, 0, 0, 89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */ | 230 | {0, 0, 0, 0, 98, 0, 193, 286, 375, 550, 718, 799, 878, 1032, 0}, |
204 | {0, 0, 0, 0, 97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/ | 231 | {0, 0, 0, 0, 109, 0, 214, 316, 414, 607, 790, 879, 965, 1132, 0}, |
205 | }; | 232 | }; |
206 | 233 | ||
207 | static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { | 234 | static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { |
208 | {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */ | 235 | {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289, 296, 300}, |
209 | {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */ | 236 | {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293, 300, 303}, |
210 | {0, 0, 0, 0, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */ | 237 | {0, 0, 0, 0, 200, 0, 390, 571, 741, 1067, 1365, 1505, 1640, 1894, 2053}, |
211 | {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */ | 238 | {0, 0, 0, 0, 221, 0, 430, 630, 816, 1169, 1490, 1641, 1784, 2053, 2221}, |
239 | }; | ||
240 | |||
241 | static s32 expected_tpt_mimo2_80MHz[4][IWL_RATE_COUNT] = { | ||
242 | {0, 0, 0, 0, 182, 0, 240, 264, 278, 299, 308, 311, 313, 317, 319}, | ||
243 | {0, 0, 0, 0, 190, 0, 247, 269, 282, 302, 310, 313, 315, 319, 320}, | ||
244 | {0, 0, 0, 0, 428, 0, 833, 1215, 1577, 2254, 2863, 3147, 3418, 3913, 4219}, | ||
245 | {0, 0, 0, 0, 474, 0, 920, 1338, 1732, 2464, 3116, 3418, 3705, 4225, 4545}, | ||
212 | }; | 246 | }; |
213 | 247 | ||
214 | /* mbps, mcs */ | 248 | /* mbps, mcs */ |
@@ -263,7 +297,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm, | |||
263 | lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate); | 297 | lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate); |
264 | 298 | ||
265 | if (lq_sta->dbg_fixed_rate) { | 299 | if (lq_sta->dbg_fixed_rate) { |
266 | rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate); | 300 | rs_fill_link_cmd(NULL, NULL, lq_sta, lq_sta->dbg_fixed_rate); |
267 | iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false); | 301 | iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false); |
268 | } | 302 | } |
269 | } | 303 | } |
@@ -275,17 +309,6 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm, | |||
275 | { | 309 | { |
276 | int ret = -EAGAIN; | 310 | int ret = -EAGAIN; |
277 | 311 | ||
278 | /* | ||
279 | * Don't create TX aggregation sessions when in high | ||
280 | * BT traffic, as they would just be disrupted by BT. | ||
281 | */ | ||
282 | if (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= 2) { | ||
283 | IWL_DEBUG_COEX(mvm, "BT traffic (%d), no aggregation allowed\n", | ||
284 | BT_MBOX_MSG(&mvm->last_bt_notif, | ||
285 | 3, TRAFFIC_LOAD)); | ||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | IWL_DEBUG_HT(mvm, "Starting Tx agg: STA: %pM tid: %d\n", | 312 | IWL_DEBUG_HT(mvm, "Starting Tx agg: STA: %pM tid: %d\n", |
290 | sta->addr, tid); | 313 | sta->addr, tid); |
291 | ret = ieee80211_start_tx_ba_session(sta, tid, 5000); | 314 | ret = ieee80211_start_tx_ba_session(sta, tid, 5000); |
@@ -416,49 +439,54 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, | |||
416 | */ | 439 | */ |
417 | /* FIXME:RS:remove this function and put the flags statically in the table */ | 440 | /* FIXME:RS:remove this function and put the flags statically in the table */ |
418 | static u32 rate_n_flags_from_tbl(struct iwl_mvm *mvm, | 441 | static u32 rate_n_flags_from_tbl(struct iwl_mvm *mvm, |
419 | struct iwl_scale_tbl_info *tbl, | 442 | struct iwl_scale_tbl_info *tbl, int index) |
420 | int index, u8 use_green) | ||
421 | { | 443 | { |
422 | u32 rate_n_flags = 0; | 444 | u32 rate_n_flags = 0; |
423 | 445 | ||
446 | rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) & | ||
447 | RATE_MCS_ANT_ABC_MSK); | ||
448 | |||
424 | if (is_legacy(tbl->lq_type)) { | 449 | if (is_legacy(tbl->lq_type)) { |
425 | rate_n_flags = iwl_rates[index].plcp; | 450 | rate_n_flags |= iwl_rates[index].plcp; |
426 | if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) | 451 | if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) |
427 | rate_n_flags |= RATE_MCS_CCK_MSK; | 452 | rate_n_flags |= RATE_MCS_CCK_MSK; |
428 | } else if (is_Ht(tbl->lq_type)) { | 453 | return rate_n_flags; |
429 | if (index > IWL_LAST_OFDM_RATE) { | 454 | } |
455 | |||
456 | if (is_ht(tbl->lq_type)) { | ||
457 | if (index < IWL_FIRST_HT_RATE || index > IWL_LAST_HT_RATE) { | ||
430 | IWL_ERR(mvm, "Invalid HT rate index %d\n", index); | 458 | IWL_ERR(mvm, "Invalid HT rate index %d\n", index); |
431 | index = IWL_LAST_OFDM_RATE; | 459 | index = IWL_LAST_HT_RATE; |
432 | } | 460 | } |
433 | rate_n_flags = RATE_MCS_HT_MSK; | 461 | rate_n_flags |= RATE_MCS_HT_MSK; |
434 | 462 | ||
435 | if (is_siso(tbl->lq_type)) | 463 | if (is_ht_siso(tbl->lq_type)) |
436 | rate_n_flags |= iwl_rates[index].plcp_siso; | 464 | rate_n_flags |= iwl_rates[index].plcp_ht_siso; |
437 | else if (is_mimo2(tbl->lq_type)) | 465 | else if (is_ht_mimo2(tbl->lq_type)) |
438 | rate_n_flags |= iwl_rates[index].plcp_mimo2; | 466 | rate_n_flags |= iwl_rates[index].plcp_ht_mimo2; |
439 | else | 467 | else |
440 | WARN_ON_ONCE(1); | 468 | WARN_ON_ONCE(1); |
469 | } else if (is_vht(tbl->lq_type)) { | ||
470 | if (index < IWL_FIRST_VHT_RATE || index > IWL_LAST_VHT_RATE) { | ||
471 | IWL_ERR(mvm, "Invalid VHT rate index %d\n", index); | ||
472 | index = IWL_LAST_VHT_RATE; | ||
473 | } | ||
474 | rate_n_flags |= RATE_MCS_VHT_MSK; | ||
475 | if (is_vht_siso(tbl->lq_type)) | ||
476 | rate_n_flags |= iwl_rates[index].plcp_vht_siso; | ||
477 | else if (is_vht_mimo2(tbl->lq_type)) | ||
478 | rate_n_flags |= iwl_rates[index].plcp_vht_mimo2; | ||
479 | else | ||
480 | WARN_ON_ONCE(1); | ||
481 | |||
441 | } else { | 482 | } else { |
442 | IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type); | 483 | IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type); |
443 | } | 484 | } |
444 | 485 | ||
445 | rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) & | 486 | rate_n_flags |= tbl->bw; |
446 | RATE_MCS_ANT_ABC_MSK); | 487 | if (tbl->is_SGI) |
447 | 488 | rate_n_flags |= RATE_MCS_SGI_MSK; | |
448 | if (is_Ht(tbl->lq_type)) { | 489 | |
449 | if (tbl->is_ht40) | ||
450 | rate_n_flags |= RATE_MCS_CHAN_WIDTH_40; | ||
451 | if (tbl->is_SGI) | ||
452 | rate_n_flags |= RATE_MCS_SGI_MSK; | ||
453 | |||
454 | if (use_green) { | ||
455 | rate_n_flags |= RATE_HT_MCS_GF_MSK; | ||
456 | if (is_siso(tbl->lq_type) && tbl->is_SGI) { | ||
457 | rate_n_flags &= ~RATE_MCS_SGI_MSK; | ||
458 | IWL_ERR(mvm, "GF was set with SGI:SISO\n"); | ||
459 | } | ||
460 | } | ||
461 | } | ||
462 | return rate_n_flags; | 490 | return rate_n_flags; |
463 | } | 491 | } |
464 | 492 | ||
@@ -473,7 +501,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, | |||
473 | { | 501 | { |
474 | u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK); | 502 | u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK); |
475 | u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags); | 503 | u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags); |
476 | u8 mcs; | 504 | u8 nss; |
477 | 505 | ||
478 | memset(tbl, 0, offsetof(struct iwl_scale_tbl_info, win)); | 506 | memset(tbl, 0, offsetof(struct iwl_scale_tbl_info, win)); |
479 | *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); | 507 | *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); |
@@ -483,41 +511,62 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, | |||
483 | return -EINVAL; | 511 | return -EINVAL; |
484 | } | 512 | } |
485 | tbl->is_SGI = 0; /* default legacy setup */ | 513 | tbl->is_SGI = 0; /* default legacy setup */ |
486 | tbl->is_ht40 = 0; | 514 | tbl->bw = 0; |
487 | tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); | 515 | tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); |
488 | tbl->lq_type = LQ_NONE; | 516 | tbl->lq_type = LQ_NONE; |
489 | tbl->max_search = IWL_MAX_SEARCH; | 517 | tbl->max_search = IWL_MAX_SEARCH; |
490 | 518 | ||
491 | /* legacy rate format */ | 519 | /* Legacy */ |
492 | if (!(rate_n_flags & RATE_MCS_HT_MSK)) { | 520 | if (!(rate_n_flags & RATE_MCS_HT_MSK) && |
521 | !(rate_n_flags & RATE_MCS_VHT_MSK)) { | ||
493 | if (num_of_ant == 1) { | 522 | if (num_of_ant == 1) { |
494 | if (band == IEEE80211_BAND_5GHZ) | 523 | if (band == IEEE80211_BAND_5GHZ) |
495 | tbl->lq_type = LQ_A; | 524 | tbl->lq_type = LQ_LEGACY_A; |
496 | else | 525 | else |
497 | tbl->lq_type = LQ_G; | 526 | tbl->lq_type = LQ_LEGACY_G; |
498 | } | 527 | } |
499 | /* HT rate format */ | 528 | |
500 | } else { | 529 | return 0; |
501 | if (rate_n_flags & RATE_MCS_SGI_MSK) | 530 | } |
502 | tbl->is_SGI = 1; | 531 | |
503 | 532 | /* HT or VHT */ | |
504 | if (rate_n_flags & RATE_MCS_CHAN_WIDTH_40) /* TODO */ | 533 | if (rate_n_flags & RATE_MCS_SGI_MSK) |
505 | tbl->is_ht40 = 1; | 534 | tbl->is_SGI = 1; |
506 | 535 | ||
507 | mcs = rs_extract_rate(rate_n_flags); | 536 | tbl->bw = rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK; |
508 | 537 | ||
509 | /* SISO */ | 538 | if (rate_n_flags & RATE_MCS_HT_MSK) { |
510 | if (mcs <= IWL_RATE_SISO_60M_PLCP) { | 539 | nss = ((rate_n_flags & RATE_HT_MCS_NSS_MSK) >> |
511 | if (num_of_ant == 1) | 540 | RATE_HT_MCS_NSS_POS) + 1; |
512 | tbl->lq_type = LQ_SISO; /*else NONE*/ | 541 | |
513 | /* MIMO2 */ | 542 | if (nss == 1) { |
514 | } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) { | 543 | tbl->lq_type = LQ_HT_SISO; |
515 | if (num_of_ant == 2) | 544 | WARN_ON_ONCE(num_of_ant != 1); |
516 | tbl->lq_type = LQ_MIMO2; | 545 | } else if (nss == 2) { |
546 | tbl->lq_type = LQ_HT_MIMO2; | ||
547 | WARN_ON_ONCE(num_of_ant != 2); | ||
548 | } else { | ||
549 | WARN_ON_ONCE(1); | ||
550 | } | ||
551 | } else if (rate_n_flags & RATE_MCS_VHT_MSK) { | ||
552 | nss = ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> | ||
553 | RATE_VHT_MCS_NSS_POS) + 1; | ||
554 | |||
555 | if (nss == 1) { | ||
556 | tbl->lq_type = LQ_VHT_SISO; | ||
557 | WARN_ON_ONCE(num_of_ant != 1); | ||
558 | } else if (nss == 2) { | ||
559 | tbl->lq_type = LQ_VHT_MIMO2; | ||
560 | WARN_ON_ONCE(num_of_ant != 2); | ||
517 | } else { | 561 | } else { |
518 | WARN_ON_ONCE(num_of_ant == 3); | 562 | WARN_ON_ONCE(1); |
519 | } | 563 | } |
520 | } | 564 | } |
565 | |||
566 | WARN_ON_ONCE(tbl->bw == RATE_MCS_CHAN_WIDTH_160); | ||
567 | WARN_ON_ONCE(tbl->bw == RATE_MCS_CHAN_WIDTH_80 && | ||
568 | !is_vht(tbl->lq_type)); | ||
569 | |||
521 | return 0; | 570 | return 0; |
522 | } | 571 | } |
523 | 572 | ||
@@ -550,22 +599,6 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, | |||
550 | } | 599 | } |
551 | 600 | ||
552 | /** | 601 | /** |
553 | * Green-field mode is valid if the station supports it and | ||
554 | * there are no non-GF stations present in the BSS. | ||
555 | */ | ||
556 | static bool rs_use_green(struct ieee80211_sta *sta) | ||
557 | { | ||
558 | /* | ||
559 | * There's a bug somewhere in this code that causes the | ||
560 | * scaling to get stuck because GF+SGI can't be combined | ||
561 | * in SISO rates. Until we find that bug, disable GF, it | ||
562 | * has only limited benefit and we still interoperate with | ||
563 | * GF APs since we can always receive GF transmissions. | ||
564 | */ | ||
565 | return false; | ||
566 | } | ||
567 | |||
568 | /** | ||
569 | * rs_get_supported_rates - get the available rates | 602 | * rs_get_supported_rates - get the available rates |
570 | * | 603 | * |
571 | * if management frame or broadcast frame only return | 604 | * if management frame or broadcast frame only return |
@@ -576,16 +609,15 @@ static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta, | |||
576 | struct ieee80211_hdr *hdr, | 609 | struct ieee80211_hdr *hdr, |
577 | enum iwl_table_type rate_type) | 610 | enum iwl_table_type rate_type) |
578 | { | 611 | { |
579 | if (is_legacy(rate_type)) { | 612 | if (is_legacy(rate_type)) |
580 | return lq_sta->active_legacy_rate; | 613 | return lq_sta->active_legacy_rate; |
581 | } else { | 614 | else if (is_siso(rate_type)) |
582 | if (is_siso(rate_type)) | 615 | return lq_sta->active_siso_rate; |
583 | return lq_sta->active_siso_rate; | 616 | else if (is_mimo2(rate_type)) |
584 | else { | 617 | return lq_sta->active_mimo2_rate; |
585 | WARN_ON_ONCE(!is_mimo2(rate_type)); | 618 | |
586 | return lq_sta->active_mimo2_rate; | 619 | WARN_ON_ONCE(1); |
587 | } | 620 | return 0; |
588 | } | ||
589 | } | 621 | } |
590 | 622 | ||
591 | static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask, | 623 | static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask, |
@@ -652,7 +684,6 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, | |||
652 | u16 rate_mask; | 684 | u16 rate_mask; |
653 | u16 high_low; | 685 | u16 high_low; |
654 | u8 switch_to_legacy = 0; | 686 | u8 switch_to_legacy = 0; |
655 | u8 is_green = lq_sta->is_green; | ||
656 | struct iwl_mvm *mvm = lq_sta->drv; | 687 | struct iwl_mvm *mvm = lq_sta->drv; |
657 | 688 | ||
658 | /* check if we need to switch from HT to legacy rates. | 689 | /* check if we need to switch from HT to legacy rates. |
@@ -662,15 +693,15 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, | |||
662 | switch_to_legacy = 1; | 693 | switch_to_legacy = 1; |
663 | scale_index = rs_ht_to_legacy[scale_index]; | 694 | scale_index = rs_ht_to_legacy[scale_index]; |
664 | if (lq_sta->band == IEEE80211_BAND_5GHZ) | 695 | if (lq_sta->band == IEEE80211_BAND_5GHZ) |
665 | tbl->lq_type = LQ_A; | 696 | tbl->lq_type = LQ_LEGACY_A; |
666 | else | 697 | else |
667 | tbl->lq_type = LQ_G; | 698 | tbl->lq_type = LQ_LEGACY_G; |
668 | 699 | ||
669 | if (num_of_ant(tbl->ant_type) > 1) | 700 | if (num_of_ant(tbl->ant_type) > 1) |
670 | tbl->ant_type = | 701 | tbl->ant_type = |
671 | first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); | 702 | first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); |
672 | 703 | ||
673 | tbl->is_ht40 = 0; | 704 | tbl->bw = 0; |
674 | tbl->is_SGI = 0; | 705 | tbl->is_SGI = 0; |
675 | tbl->max_search = IWL_MAX_SEARCH; | 706 | tbl->max_search = IWL_MAX_SEARCH; |
676 | } | 707 | } |
@@ -701,7 +732,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, | |||
701 | low = scale_index; | 732 | low = scale_index; |
702 | 733 | ||
703 | out: | 734 | out: |
704 | return rate_n_flags_from_tbl(lq_sta->drv, tbl, low, is_green); | 735 | return rate_n_flags_from_tbl(lq_sta->drv, tbl, low); |
705 | } | 736 | } |
706 | 737 | ||
707 | /* | 738 | /* |
@@ -714,6 +745,18 @@ static bool table_type_matches(struct iwl_scale_tbl_info *a, | |||
714 | (a->is_SGI == b->is_SGI); | 745 | (a->is_SGI == b->is_SGI); |
715 | } | 746 | } |
716 | 747 | ||
748 | static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags) | ||
749 | { | ||
750 | if (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
751 | return RATE_MCS_CHAN_WIDTH_40; | ||
752 | else if (flags & IEEE80211_TX_RC_80_MHZ_WIDTH) | ||
753 | return RATE_MCS_CHAN_WIDTH_80; | ||
754 | else if (flags & IEEE80211_TX_RC_160_MHZ_WIDTH) | ||
755 | return RATE_MCS_CHAN_WIDTH_160; | ||
756 | |||
757 | return RATE_MCS_CHAN_WIDTH_20; | ||
758 | } | ||
759 | |||
717 | /* | 760 | /* |
718 | * mac80211 sends us Tx status | 761 | * mac80211 sends us Tx status |
719 | */ | 762 | */ |
@@ -783,16 +826,23 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, | |||
783 | */ | 826 | */ |
784 | if (info->band == IEEE80211_BAND_2GHZ) | 827 | if (info->band == IEEE80211_BAND_2GHZ) |
785 | mac_index += IWL_FIRST_OFDM_RATE; | 828 | mac_index += IWL_FIRST_OFDM_RATE; |
829 | } else if (mac_flags & IEEE80211_TX_RC_VHT_MCS) { | ||
830 | mac_index &= RATE_VHT_MCS_RATE_CODE_MSK; | ||
831 | if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE)) | ||
832 | mac_index++; | ||
786 | } | 833 | } |
834 | |||
787 | /* Here we actually compare this rate to the latest LQ command */ | 835 | /* Here we actually compare this rate to the latest LQ command */ |
788 | if ((mac_index < 0) || | 836 | if ((mac_index < 0) || |
789 | (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || | 837 | (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || |
790 | (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || | 838 | (tbl_type.bw != rs_ch_width_from_mac_flags(mac_flags)) || |
791 | (tbl_type.ant_type != info->status.antenna) || | 839 | (tbl_type.ant_type != info->status.antenna) || |
792 | (!!(tx_rate & RATE_MCS_HT_MSK) != | 840 | (!!(tx_rate & RATE_MCS_HT_MSK) != |
793 | !!(mac_flags & IEEE80211_TX_RC_MCS)) || | 841 | !!(mac_flags & IEEE80211_TX_RC_MCS)) || |
842 | (!!(tx_rate & RATE_MCS_VHT_MSK) != | ||
843 | !!(mac_flags & IEEE80211_TX_RC_VHT_MCS)) || | ||
794 | (!!(tx_rate & RATE_HT_MCS_GF_MSK) != | 844 | (!!(tx_rate & RATE_HT_MCS_GF_MSK) != |
795 | !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || | 845 | !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || |
796 | (rs_index != mac_index)) { | 846 | (rs_index != mac_index)) { |
797 | IWL_DEBUG_RATE(mvm, | 847 | IWL_DEBUG_RATE(mvm, |
798 | "initial rate %d does not match %d (0x%x)\n", | 848 | "initial rate %d does not match %d (0x%x)\n", |
@@ -947,7 +997,8 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | |||
947 | s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; | 997 | s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; |
948 | 998 | ||
949 | /* Check for invalid LQ type */ | 999 | /* Check for invalid LQ type */ |
950 | if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) { | 1000 | if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_ht(tbl->lq_type) && |
1001 | !(is_vht(tbl->lq_type)))) { | ||
951 | tbl->expected_tpt = expected_tpt_legacy; | 1002 | tbl->expected_tpt = expected_tpt_legacy; |
952 | return; | 1003 | return; |
953 | } | 1004 | } |
@@ -958,18 +1009,40 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | |||
958 | return; | 1009 | return; |
959 | } | 1010 | } |
960 | 1011 | ||
1012 | ht_tbl_pointer = expected_tpt_mimo2_20MHz; | ||
961 | /* Choose among many HT tables depending on number of streams | 1013 | /* Choose among many HT tables depending on number of streams |
962 | * (SISO/MIMO2), channel width (20/40), SGI, and aggregation | 1014 | * (SISO/MIMO2), channel width (20/40/80), SGI, and aggregation |
963 | * status */ | 1015 | * status */ |
964 | if (is_siso(tbl->lq_type) && !tbl->is_ht40) | 1016 | if (is_siso(tbl->lq_type)) { |
965 | ht_tbl_pointer = expected_tpt_siso20MHz; | 1017 | switch (tbl->bw) { |
966 | else if (is_siso(tbl->lq_type)) | 1018 | case RATE_MCS_CHAN_WIDTH_20: |
967 | ht_tbl_pointer = expected_tpt_siso40MHz; | 1019 | ht_tbl_pointer = expected_tpt_siso_20MHz; |
968 | else if (is_mimo2(tbl->lq_type) && !tbl->is_ht40) | 1020 | break; |
969 | ht_tbl_pointer = expected_tpt_mimo2_20MHz; | 1021 | case RATE_MCS_CHAN_WIDTH_40: |
970 | else { | 1022 | ht_tbl_pointer = expected_tpt_siso_40MHz; |
971 | WARN_ON_ONCE(!is_mimo2(tbl->lq_type)); | 1023 | break; |
972 | ht_tbl_pointer = expected_tpt_mimo2_40MHz; | 1024 | case RATE_MCS_CHAN_WIDTH_80: |
1025 | ht_tbl_pointer = expected_tpt_siso_80MHz; | ||
1026 | break; | ||
1027 | default: | ||
1028 | WARN_ON_ONCE(1); | ||
1029 | } | ||
1030 | } else if (is_mimo2(tbl->lq_type)) { | ||
1031 | switch (tbl->bw) { | ||
1032 | case RATE_MCS_CHAN_WIDTH_20: | ||
1033 | ht_tbl_pointer = expected_tpt_mimo2_20MHz; | ||
1034 | break; | ||
1035 | case RATE_MCS_CHAN_WIDTH_40: | ||
1036 | ht_tbl_pointer = expected_tpt_mimo2_40MHz; | ||
1037 | break; | ||
1038 | case RATE_MCS_CHAN_WIDTH_80: | ||
1039 | ht_tbl_pointer = expected_tpt_mimo2_80MHz; | ||
1040 | break; | ||
1041 | default: | ||
1042 | WARN_ON_ONCE(1); | ||
1043 | } | ||
1044 | } else { | ||
1045 | WARN_ON_ONCE(1); | ||
973 | } | 1046 | } |
974 | 1047 | ||
975 | if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */ | 1048 | if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */ |
@@ -1084,9 +1157,47 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, | |||
1084 | return new_rate; | 1157 | return new_rate; |
1085 | } | 1158 | } |
1086 | 1159 | ||
1087 | static bool iwl_is_ht40_tx_allowed(struct ieee80211_sta *sta) | 1160 | /* Move to the next action and wrap around to the first action in case |
1161 | * we're at the last action. Assumes actions start at 0. | ||
1162 | */ | ||
1163 | static inline void rs_move_next_action(struct iwl_scale_tbl_info *tbl, | ||
1164 | u8 last_action) | ||
1165 | { | ||
1166 | BUILD_BUG_ON(IWL_LEGACY_FIRST_ACTION != 0); | ||
1167 | BUILD_BUG_ON(IWL_SISO_FIRST_ACTION != 0); | ||
1168 | BUILD_BUG_ON(IWL_MIMO2_FIRST_ACTION != 0); | ||
1169 | |||
1170 | tbl->action = (tbl->action + 1) % (last_action + 1); | ||
1171 | } | ||
1172 | |||
1173 | static void rs_set_bw_from_sta(struct iwl_scale_tbl_info *tbl, | ||
1174 | struct ieee80211_sta *sta) | ||
1175 | { | ||
1176 | if (sta->bandwidth >= IEEE80211_STA_RX_BW_80) | ||
1177 | tbl->bw = RATE_MCS_CHAN_WIDTH_80; | ||
1178 | else if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) | ||
1179 | tbl->bw = RATE_MCS_CHAN_WIDTH_40; | ||
1180 | else | ||
1181 | tbl->bw = RATE_MCS_CHAN_WIDTH_20; | ||
1182 | } | ||
1183 | |||
1184 | static bool rs_sgi_allowed(struct iwl_scale_tbl_info *tbl, | ||
1185 | struct ieee80211_sta *sta) | ||
1088 | { | 1186 | { |
1089 | return sta->bandwidth >= IEEE80211_STA_RX_BW_40; | 1187 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; |
1188 | struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; | ||
1189 | |||
1190 | if (is_ht20(tbl) && (ht_cap->cap & | ||
1191 | IEEE80211_HT_CAP_SGI_20)) | ||
1192 | return true; | ||
1193 | if (is_ht40(tbl) && (ht_cap->cap & | ||
1194 | IEEE80211_HT_CAP_SGI_40)) | ||
1195 | return true; | ||
1196 | if (is_ht80(tbl) && (vht_cap->cap & | ||
1197 | IEEE80211_VHT_CAP_SHORT_GI_80)) | ||
1198 | return true; | ||
1199 | |||
1200 | return false; | ||
1090 | } | 1201 | } |
1091 | 1202 | ||
1092 | /* | 1203 | /* |
@@ -1099,7 +1210,6 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | |||
1099 | { | 1210 | { |
1100 | u16 rate_mask; | 1211 | u16 rate_mask; |
1101 | s32 rate; | 1212 | s32 rate; |
1102 | s8 is_green = lq_sta->is_green; | ||
1103 | 1213 | ||
1104 | if (!sta->ht_cap.ht_supported) | 1214 | if (!sta->ht_cap.ht_supported) |
1105 | return -1; | 1215 | return -1; |
@@ -1113,16 +1223,12 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | |||
1113 | 1223 | ||
1114 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n"); | 1224 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n"); |
1115 | 1225 | ||
1116 | tbl->lq_type = LQ_MIMO2; | 1226 | tbl->lq_type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2; |
1117 | tbl->action = 0; | 1227 | tbl->action = 0; |
1118 | tbl->max_search = IWL_MAX_SEARCH; | 1228 | tbl->max_search = IWL_MAX_SEARCH; |
1119 | rate_mask = lq_sta->active_mimo2_rate; | 1229 | rate_mask = lq_sta->active_mimo2_rate; |
1120 | 1230 | ||
1121 | if (iwl_is_ht40_tx_allowed(sta)) | 1231 | rs_set_bw_from_sta(tbl, sta); |
1122 | tbl->is_ht40 = 1; | ||
1123 | else | ||
1124 | tbl->is_ht40 = 0; | ||
1125 | |||
1126 | rs_set_expected_tpt_table(lq_sta, tbl); | 1232 | rs_set_expected_tpt_table(lq_sta, tbl); |
1127 | 1233 | ||
1128 | rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); | 1234 | rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); |
@@ -1134,10 +1240,10 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | |||
1134 | rate, rate_mask); | 1240 | rate, rate_mask); |
1135 | return -1; | 1241 | return -1; |
1136 | } | 1242 | } |
1137 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green); | 1243 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate); |
1138 | 1244 | ||
1139 | IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n", | 1245 | IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n", |
1140 | tbl->current_rate, is_green); | 1246 | tbl->current_rate); |
1141 | return 0; | 1247 | return 0; |
1142 | } | 1248 | } |
1143 | 1249 | ||
@@ -1150,7 +1256,6 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm, | |||
1150 | struct iwl_scale_tbl_info *tbl, int index) | 1256 | struct iwl_scale_tbl_info *tbl, int index) |
1151 | { | 1257 | { |
1152 | u16 rate_mask; | 1258 | u16 rate_mask; |
1153 | u8 is_green = lq_sta->is_green; | ||
1154 | s32 rate; | 1259 | s32 rate; |
1155 | 1260 | ||
1156 | if (!sta->ht_cap.ht_supported) | 1261 | if (!sta->ht_cap.ht_supported) |
@@ -1158,19 +1263,12 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm, | |||
1158 | 1263 | ||
1159 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to SISO\n"); | 1264 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to SISO\n"); |
1160 | 1265 | ||
1161 | tbl->lq_type = LQ_SISO; | 1266 | tbl->lq_type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; |
1162 | tbl->action = 0; | 1267 | tbl->action = 0; |
1163 | tbl->max_search = IWL_MAX_SEARCH; | 1268 | tbl->max_search = IWL_MAX_SEARCH; |
1164 | rate_mask = lq_sta->active_siso_rate; | 1269 | rate_mask = lq_sta->active_siso_rate; |
1165 | 1270 | ||
1166 | if (iwl_is_ht40_tx_allowed(sta)) | 1271 | rs_set_bw_from_sta(tbl, sta); |
1167 | tbl->is_ht40 = 1; | ||
1168 | else | ||
1169 | tbl->is_ht40 = 0; | ||
1170 | |||
1171 | if (is_green) | ||
1172 | tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/ | ||
1173 | |||
1174 | rs_set_expected_tpt_table(lq_sta, tbl); | 1272 | rs_set_expected_tpt_table(lq_sta, tbl); |
1175 | rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); | 1273 | rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); |
1176 | 1274 | ||
@@ -1181,9 +1279,9 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm, | |||
1181 | rate, rate_mask); | 1279 | rate, rate_mask); |
1182 | return -1; | 1280 | return -1; |
1183 | } | 1281 | } |
1184 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green); | 1282 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate); |
1185 | IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n", | 1283 | IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n", |
1186 | tbl->current_rate, is_green); | 1284 | tbl->current_rate); |
1187 | return 0; | 1285 | return 0; |
1188 | } | 1286 | } |
1189 | 1287 | ||
@@ -1211,14 +1309,10 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, | |||
1211 | while (1) { | 1309 | while (1) { |
1212 | lq_sta->action_counter++; | 1310 | lq_sta->action_counter++; |
1213 | switch (tbl->action) { | 1311 | switch (tbl->action) { |
1214 | case IWL_LEGACY_SWITCH_ANTENNA1: | 1312 | case IWL_LEGACY_SWITCH_ANTENNA: |
1215 | case IWL_LEGACY_SWITCH_ANTENNA2: | ||
1216 | IWL_DEBUG_RATE(mvm, "LQ: Legacy toggle Antenna\n"); | 1313 | IWL_DEBUG_RATE(mvm, "LQ: Legacy toggle Antenna\n"); |
1217 | 1314 | ||
1218 | if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 && | 1315 | if (tx_chains_num <= 1) |
1219 | tx_chains_num <= 1) || | ||
1220 | (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 && | ||
1221 | tx_chains_num <= 2)) | ||
1222 | break; | 1316 | break; |
1223 | 1317 | ||
1224 | /* Don't change antenna if success has been great */ | 1318 | /* Don't change antenna if success has been great */ |
@@ -1273,9 +1367,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, | |||
1273 | default: | 1367 | default: |
1274 | WARN_ON_ONCE(1); | 1368 | WARN_ON_ONCE(1); |
1275 | } | 1369 | } |
1276 | tbl->action++; | 1370 | rs_move_next_action(tbl, IWL_LEGACY_LAST_ACTION); |
1277 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) | ||
1278 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; | ||
1279 | 1371 | ||
1280 | if (tbl->action == start_action) | 1372 | if (tbl->action == start_action) |
1281 | break; | 1373 | break; |
@@ -1285,9 +1377,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, | |||
1285 | 1377 | ||
1286 | out: | 1378 | out: |
1287 | lq_sta->search_better_tbl = 1; | 1379 | lq_sta->search_better_tbl = 1; |
1288 | tbl->action++; | 1380 | rs_move_next_action(tbl, IWL_LEGACY_LAST_ACTION); |
1289 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) | ||
1290 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; | ||
1291 | if (update_search_tbl_counter) | 1381 | if (update_search_tbl_counter) |
1292 | search_tbl->action = tbl->action; | 1382 | search_tbl->action = tbl->action; |
1293 | return 0; | 1383 | return 0; |
@@ -1300,12 +1390,10 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, | |||
1300 | struct iwl_lq_sta *lq_sta, | 1390 | struct iwl_lq_sta *lq_sta, |
1301 | struct ieee80211_sta *sta, int index) | 1391 | struct ieee80211_sta *sta, int index) |
1302 | { | 1392 | { |
1303 | u8 is_green = lq_sta->is_green; | ||
1304 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1393 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
1305 | struct iwl_scale_tbl_info *search_tbl = | 1394 | struct iwl_scale_tbl_info *search_tbl = |
1306 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | 1395 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); |
1307 | struct iwl_rate_scale_data *window = &(tbl->win[index]); | 1396 | struct iwl_rate_scale_data *window = &(tbl->win[index]); |
1308 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | ||
1309 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | 1397 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - |
1310 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | 1398 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); |
1311 | u8 start_action; | 1399 | u8 start_action; |
@@ -1314,40 +1402,17 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, | |||
1314 | u8 update_search_tbl_counter = 0; | 1402 | u8 update_search_tbl_counter = 0; |
1315 | int ret; | 1403 | int ret; |
1316 | 1404 | ||
1317 | switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { | 1405 | if (tbl->action == IWL_SISO_SWITCH_MIMO2 && |
1318 | case IWL_BT_COEX_TRAFFIC_LOAD_NONE: | 1406 | !iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) |
1319 | /* nothing */ | 1407 | tbl->action = IWL_SISO_SWITCH_ANTENNA; |
1320 | break; | ||
1321 | case IWL_BT_COEX_TRAFFIC_LOAD_LOW: | ||
1322 | /* avoid antenna B unless MIMO */ | ||
1323 | if (tbl->action == IWL_SISO_SWITCH_ANTENNA2) | ||
1324 | tbl->action = IWL_SISO_SWITCH_MIMO2; | ||
1325 | break; | ||
1326 | case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: | ||
1327 | case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: | ||
1328 | /* avoid antenna B and MIMO */ | ||
1329 | valid_tx_ant = | ||
1330 | first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); | ||
1331 | if (tbl->action != IWL_SISO_SWITCH_ANTENNA1) | ||
1332 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; | ||
1333 | break; | ||
1334 | default: | ||
1335 | IWL_ERR(mvm, "Invalid BT load %d", | ||
1336 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)); | ||
1337 | break; | ||
1338 | } | ||
1339 | 1408 | ||
1340 | start_action = tbl->action; | 1409 | start_action = tbl->action; |
1341 | while (1) { | 1410 | while (1) { |
1342 | lq_sta->action_counter++; | 1411 | lq_sta->action_counter++; |
1343 | switch (tbl->action) { | 1412 | switch (tbl->action) { |
1344 | case IWL_SISO_SWITCH_ANTENNA1: | 1413 | case IWL_SISO_SWITCH_ANTENNA: |
1345 | case IWL_SISO_SWITCH_ANTENNA2: | ||
1346 | IWL_DEBUG_RATE(mvm, "LQ: SISO toggle Antenna\n"); | 1414 | IWL_DEBUG_RATE(mvm, "LQ: SISO toggle Antenna\n"); |
1347 | if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 && | 1415 | if (tx_chains_num <= 1) |
1348 | tx_chains_num <= 1) || | ||
1349 | (tbl->action == IWL_SISO_SWITCH_ANTENNA2 && | ||
1350 | tx_chains_num <= 2)) | ||
1351 | break; | 1416 | break; |
1352 | 1417 | ||
1353 | if (window->success_ratio >= IWL_RS_GOOD_RATIO && | 1418 | if (window->success_ratio >= IWL_RS_GOOD_RATIO && |
@@ -1380,23 +1445,12 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, | |||
1380 | goto out; | 1445 | goto out; |
1381 | break; | 1446 | break; |
1382 | case IWL_SISO_SWITCH_GI: | 1447 | case IWL_SISO_SWITCH_GI: |
1383 | if (!tbl->is_ht40 && !(ht_cap->cap & | 1448 | if (!rs_sgi_allowed(tbl, sta)) |
1384 | IEEE80211_HT_CAP_SGI_20)) | ||
1385 | break; | ||
1386 | if (tbl->is_ht40 && !(ht_cap->cap & | ||
1387 | IEEE80211_HT_CAP_SGI_40)) | ||
1388 | break; | 1449 | break; |
1389 | 1450 | ||
1390 | IWL_DEBUG_RATE(mvm, "LQ: SISO toggle SGI/NGI\n"); | 1451 | IWL_DEBUG_RATE(mvm, "LQ: SISO toggle SGI/NGI\n"); |
1391 | 1452 | ||
1392 | memcpy(search_tbl, tbl, sz); | 1453 | memcpy(search_tbl, tbl, sz); |
1393 | if (is_green) { | ||
1394 | if (!tbl->is_SGI) | ||
1395 | break; | ||
1396 | else | ||
1397 | IWL_ERR(mvm, | ||
1398 | "SGI was set in GF+SISO\n"); | ||
1399 | } | ||
1400 | search_tbl->is_SGI = !tbl->is_SGI; | 1454 | search_tbl->is_SGI = !tbl->is_SGI; |
1401 | rs_set_expected_tpt_table(lq_sta, search_tbl); | 1455 | rs_set_expected_tpt_table(lq_sta, search_tbl); |
1402 | if (tbl->is_SGI) { | 1456 | if (tbl->is_SGI) { |
@@ -1405,16 +1459,13 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, | |||
1405 | break; | 1459 | break; |
1406 | } | 1460 | } |
1407 | search_tbl->current_rate = | 1461 | search_tbl->current_rate = |
1408 | rate_n_flags_from_tbl(mvm, search_tbl, | 1462 | rate_n_flags_from_tbl(mvm, search_tbl, index); |
1409 | index, is_green); | ||
1410 | update_search_tbl_counter = 1; | 1463 | update_search_tbl_counter = 1; |
1411 | goto out; | 1464 | goto out; |
1412 | default: | 1465 | default: |
1413 | WARN_ON_ONCE(1); | 1466 | WARN_ON_ONCE(1); |
1414 | } | 1467 | } |
1415 | tbl->action++; | 1468 | rs_move_next_action(tbl, IWL_SISO_LAST_ACTION); |
1416 | if (tbl->action > IWL_SISO_SWITCH_GI) | ||
1417 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; | ||
1418 | 1469 | ||
1419 | if (tbl->action == start_action) | 1470 | if (tbl->action == start_action) |
1420 | break; | 1471 | break; |
@@ -1424,9 +1475,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, | |||
1424 | 1475 | ||
1425 | out: | 1476 | out: |
1426 | lq_sta->search_better_tbl = 1; | 1477 | lq_sta->search_better_tbl = 1; |
1427 | tbl->action++; | 1478 | rs_move_next_action(tbl, IWL_SISO_LAST_ACTION); |
1428 | if (tbl->action > IWL_SISO_SWITCH_GI) | ||
1429 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; | ||
1430 | if (update_search_tbl_counter) | 1479 | if (update_search_tbl_counter) |
1431 | search_tbl->action = tbl->action; | 1480 | search_tbl->action = tbl->action; |
1432 | 1481 | ||
@@ -1440,63 +1489,20 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | |||
1440 | struct iwl_lq_sta *lq_sta, | 1489 | struct iwl_lq_sta *lq_sta, |
1441 | struct ieee80211_sta *sta, int index) | 1490 | struct ieee80211_sta *sta, int index) |
1442 | { | 1491 | { |
1443 | s8 is_green = lq_sta->is_green; | ||
1444 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1492 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
1445 | struct iwl_scale_tbl_info *search_tbl = | 1493 | struct iwl_scale_tbl_info *search_tbl = |
1446 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | 1494 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); |
1447 | struct iwl_rate_scale_data *window = &(tbl->win[index]); | ||
1448 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | ||
1449 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | 1495 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - |
1450 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | 1496 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); |
1451 | u8 start_action; | 1497 | u8 start_action; |
1452 | u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); | 1498 | u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); |
1453 | u8 tx_chains_num = num_of_ant(valid_tx_ant); | ||
1454 | u8 update_search_tbl_counter = 0; | 1499 | u8 update_search_tbl_counter = 0; |
1455 | int ret; | 1500 | int ret; |
1456 | 1501 | ||
1457 | switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { | ||
1458 | case IWL_BT_COEX_TRAFFIC_LOAD_NONE: | ||
1459 | /* nothing */ | ||
1460 | break; | ||
1461 | case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: | ||
1462 | case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: | ||
1463 | /* avoid antenna B and MIMO */ | ||
1464 | if (tbl->action != IWL_MIMO2_SWITCH_SISO_A) | ||
1465 | tbl->action = IWL_MIMO2_SWITCH_SISO_A; | ||
1466 | break; | ||
1467 | case IWL_BT_COEX_TRAFFIC_LOAD_LOW: | ||
1468 | /* avoid antenna B unless MIMO */ | ||
1469 | if (tbl->action == IWL_MIMO2_SWITCH_SISO_B) | ||
1470 | tbl->action = IWL_MIMO2_SWITCH_SISO_A; | ||
1471 | break; | ||
1472 | default: | ||
1473 | IWL_ERR(mvm, "Invalid BT load %d", | ||
1474 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)); | ||
1475 | break; | ||
1476 | } | ||
1477 | |||
1478 | start_action = tbl->action; | 1502 | start_action = tbl->action; |
1479 | while (1) { | 1503 | while (1) { |
1480 | lq_sta->action_counter++; | 1504 | lq_sta->action_counter++; |
1481 | switch (tbl->action) { | 1505 | switch (tbl->action) { |
1482 | case IWL_MIMO2_SWITCH_ANTENNA1: | ||
1483 | case IWL_MIMO2_SWITCH_ANTENNA2: | ||
1484 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle Antennas\n"); | ||
1485 | |||
1486 | if (tx_chains_num <= 2) | ||
1487 | break; | ||
1488 | |||
1489 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) | ||
1490 | break; | ||
1491 | |||
1492 | memcpy(search_tbl, tbl, sz); | ||
1493 | if (rs_toggle_antenna(valid_tx_ant, | ||
1494 | &search_tbl->current_rate, | ||
1495 | search_tbl)) { | ||
1496 | update_search_tbl_counter = 1; | ||
1497 | goto out; | ||
1498 | } | ||
1499 | break; | ||
1500 | case IWL_MIMO2_SWITCH_SISO_A: | 1506 | case IWL_MIMO2_SWITCH_SISO_A: |
1501 | case IWL_MIMO2_SWITCH_SISO_B: | 1507 | case IWL_MIMO2_SWITCH_SISO_B: |
1502 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n"); | 1508 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n"); |
@@ -1521,11 +1527,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | |||
1521 | break; | 1527 | break; |
1522 | 1528 | ||
1523 | case IWL_MIMO2_SWITCH_GI: | 1529 | case IWL_MIMO2_SWITCH_GI: |
1524 | if (!tbl->is_ht40 && !(ht_cap->cap & | 1530 | if (!rs_sgi_allowed(tbl, sta)) |
1525 | IEEE80211_HT_CAP_SGI_20)) | ||
1526 | break; | ||
1527 | if (tbl->is_ht40 && !(ht_cap->cap & | ||
1528 | IEEE80211_HT_CAP_SGI_40)) | ||
1529 | break; | 1531 | break; |
1530 | 1532 | ||
1531 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle SGI/NGI\n"); | 1533 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle SGI/NGI\n"); |
@@ -1546,16 +1548,13 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | |||
1546 | break; | 1548 | break; |
1547 | } | 1549 | } |
1548 | search_tbl->current_rate = | 1550 | search_tbl->current_rate = |
1549 | rate_n_flags_from_tbl(mvm, search_tbl, | 1551 | rate_n_flags_from_tbl(mvm, search_tbl, index); |
1550 | index, is_green); | ||
1551 | update_search_tbl_counter = 1; | 1552 | update_search_tbl_counter = 1; |
1552 | goto out; | 1553 | goto out; |
1553 | default: | 1554 | default: |
1554 | WARN_ON_ONCE(1); | 1555 | WARN_ON_ONCE(1); |
1555 | } | 1556 | } |
1556 | tbl->action++; | 1557 | rs_move_next_action(tbl, IWL_MIMO2_LAST_ACTION); |
1557 | if (tbl->action > IWL_MIMO2_SWITCH_GI) | ||
1558 | tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; | ||
1559 | 1558 | ||
1560 | if (tbl->action == start_action) | 1559 | if (tbl->action == start_action) |
1561 | break; | 1560 | break; |
@@ -1564,9 +1563,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | |||
1564 | return 0; | 1563 | return 0; |
1565 | out: | 1564 | out: |
1566 | lq_sta->search_better_tbl = 1; | 1565 | lq_sta->search_better_tbl = 1; |
1567 | tbl->action++; | 1566 | rs_move_next_action(tbl, IWL_MIMO2_LAST_ACTION); |
1568 | if (tbl->action > IWL_MIMO2_SWITCH_GI) | ||
1569 | tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; | ||
1570 | if (update_search_tbl_counter) | 1567 | if (update_search_tbl_counter) |
1571 | search_tbl->action = tbl->action; | 1568 | search_tbl->action = tbl->action; |
1572 | 1569 | ||
@@ -1660,15 +1657,16 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) | |||
1660 | * setup rate table in uCode | 1657 | * setup rate table in uCode |
1661 | */ | 1658 | */ |
1662 | static void rs_update_rate_tbl(struct iwl_mvm *mvm, | 1659 | static void rs_update_rate_tbl(struct iwl_mvm *mvm, |
1660 | struct ieee80211_sta *sta, | ||
1663 | struct iwl_lq_sta *lq_sta, | 1661 | struct iwl_lq_sta *lq_sta, |
1664 | struct iwl_scale_tbl_info *tbl, | 1662 | struct iwl_scale_tbl_info *tbl, |
1665 | int index, u8 is_green) | 1663 | int index) |
1666 | { | 1664 | { |
1667 | u32 rate; | 1665 | u32 rate; |
1668 | 1666 | ||
1669 | /* Update uCode's rate table. */ | 1667 | /* Update uCode's rate table. */ |
1670 | rate = rate_n_flags_from_tbl(mvm, tbl, index, is_green); | 1668 | rate = rate_n_flags_from_tbl(mvm, tbl, index); |
1671 | rs_fill_link_cmd(mvm, lq_sta, rate); | 1669 | rs_fill_link_cmd(mvm, sta, lq_sta, rate); |
1672 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); | 1670 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); |
1673 | } | 1671 | } |
1674 | 1672 | ||
@@ -1712,7 +1710,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1712 | u8 update_lq = 0; | 1710 | u8 update_lq = 0; |
1713 | struct iwl_scale_tbl_info *tbl, *tbl1; | 1711 | struct iwl_scale_tbl_info *tbl, *tbl1; |
1714 | u16 rate_scale_index_msk = 0; | 1712 | u16 rate_scale_index_msk = 0; |
1715 | u8 is_green = 0; | ||
1716 | u8 active_tbl = 0; | 1713 | u8 active_tbl = 0; |
1717 | u8 done_search = 0; | 1714 | u8 done_search = 0; |
1718 | u16 high_low; | 1715 | u16 high_low; |
@@ -1754,11 +1751,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1754 | active_tbl = 1 - lq_sta->active_tbl; | 1751 | active_tbl = 1 - lq_sta->active_tbl; |
1755 | 1752 | ||
1756 | tbl = &(lq_sta->lq_info[active_tbl]); | 1753 | tbl = &(lq_sta->lq_info[active_tbl]); |
1757 | if (is_legacy(tbl->lq_type)) | ||
1758 | lq_sta->is_green = 0; | ||
1759 | else | ||
1760 | lq_sta->is_green = rs_use_green(sta); | ||
1761 | is_green = lq_sta->is_green; | ||
1762 | 1754 | ||
1763 | /* current tx rate */ | 1755 | /* current tx rate */ |
1764 | index = lq_sta->last_txrate_idx; | 1756 | index = lq_sta->last_txrate_idx; |
@@ -1797,7 +1789,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1797 | tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | 1789 | tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); |
1798 | /* get "active" rate info */ | 1790 | /* get "active" rate info */ |
1799 | index = iwl_hwrate_to_plcp_idx(tbl->current_rate); | 1791 | index = iwl_hwrate_to_plcp_idx(tbl->current_rate); |
1800 | rs_update_rate_tbl(mvm, lq_sta, tbl, index, is_green); | 1792 | rs_update_rate_tbl(mvm, sta, lq_sta, tbl, index); |
1801 | } | 1793 | } |
1802 | return; | 1794 | return; |
1803 | } | 1795 | } |
@@ -1978,24 +1970,24 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1978 | (current_tpt > (100 * tbl->expected_tpt[low])))) | 1970 | (current_tpt > (100 * tbl->expected_tpt[low])))) |
1979 | scale_action = 0; | 1971 | scale_action = 0; |
1980 | 1972 | ||
1981 | if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= | 1973 | if ((le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) >= |
1982 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && (is_mimo(tbl->lq_type))) { | 1974 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && (is_mimo(tbl->lq_type))) { |
1983 | if (lq_sta->last_bt_traffic > | 1975 | if (lq_sta->last_bt_traffic > |
1984 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { | 1976 | le32_to_cpu(mvm->last_bt_notif.bt_activity_grading)) { |
1985 | /* | 1977 | /* |
1986 | * don't set scale_action, don't want to scale up if | 1978 | * don't set scale_action, don't want to scale up if |
1987 | * the rate scale doesn't otherwise think that is a | 1979 | * the rate scale doesn't otherwise think that is a |
1988 | * good idea. | 1980 | * good idea. |
1989 | */ | 1981 | */ |
1990 | } else if (lq_sta->last_bt_traffic <= | 1982 | } else if (lq_sta->last_bt_traffic <= |
1991 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { | 1983 | le32_to_cpu(mvm->last_bt_notif.bt_activity_grading)) { |
1992 | scale_action = -1; | 1984 | scale_action = -1; |
1993 | } | 1985 | } |
1994 | } | 1986 | } |
1995 | lq_sta->last_bt_traffic = | 1987 | lq_sta->last_bt_traffic = |
1996 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD); | 1988 | le32_to_cpu(mvm->last_bt_notif.bt_activity_grading); |
1997 | 1989 | ||
1998 | if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= | 1990 | if ((le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) >= |
1999 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && is_mimo(tbl->lq_type)) { | 1991 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && is_mimo(tbl->lq_type)) { |
2000 | /* search for a new modulation */ | 1992 | /* search for a new modulation */ |
2001 | rs_stay_in_table(lq_sta, true); | 1993 | rs_stay_in_table(lq_sta, true); |
@@ -2032,7 +2024,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
2032 | lq_update: | 2024 | lq_update: |
2033 | /* Replace uCode's rate table for the destination station. */ | 2025 | /* Replace uCode's rate table for the destination station. */ |
2034 | if (update_lq) | 2026 | if (update_lq) |
2035 | rs_update_rate_tbl(mvm, lq_sta, tbl, index, is_green); | 2027 | rs_update_rate_tbl(mvm, sta, lq_sta, tbl, index); |
2036 | 2028 | ||
2037 | rs_stay_in_table(lq_sta, false); | 2029 | rs_stay_in_table(lq_sta, false); |
2038 | 2030 | ||
@@ -2071,7 +2063,7 @@ lq_update: | |||
2071 | IWL_DEBUG_RATE(mvm, | 2063 | IWL_DEBUG_RATE(mvm, |
2072 | "Switch current mcs: %X index: %d\n", | 2064 | "Switch current mcs: %X index: %d\n", |
2073 | tbl->current_rate, index); | 2065 | tbl->current_rate, index); |
2074 | rs_fill_link_cmd(mvm, lq_sta, tbl->current_rate); | 2066 | rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate); |
2075 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); | 2067 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); |
2076 | } else { | 2068 | } else { |
2077 | done_search = 1; | 2069 | done_search = 1; |
@@ -2113,7 +2105,7 @@ lq_update: | |||
2113 | } | 2105 | } |
2114 | 2106 | ||
2115 | out: | 2107 | out: |
2116 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, index, is_green); | 2108 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, index); |
2117 | lq_sta->last_txrate_idx = index; | 2109 | lq_sta->last_txrate_idx = index; |
2118 | } | 2110 | } |
2119 | 2111 | ||
@@ -2140,7 +2132,6 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, | |||
2140 | int rate_idx; | 2132 | int rate_idx; |
2141 | int i; | 2133 | int i; |
2142 | u32 rate; | 2134 | u32 rate; |
2143 | u8 use_green = rs_use_green(sta); | ||
2144 | u8 active_tbl = 0; | 2135 | u8 active_tbl = 0; |
2145 | u8 valid_tx_ant; | 2136 | u8 valid_tx_ant; |
2146 | 2137 | ||
@@ -2172,10 +2163,10 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, | |||
2172 | if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type)) | 2163 | if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type)) |
2173 | rs_toggle_antenna(valid_tx_ant, &rate, tbl); | 2164 | rs_toggle_antenna(valid_tx_ant, &rate, tbl); |
2174 | 2165 | ||
2175 | rate = rate_n_flags_from_tbl(mvm, tbl, rate_idx, use_green); | 2166 | rate = rate_n_flags_from_tbl(mvm, tbl, rate_idx); |
2176 | tbl->current_rate = rate; | 2167 | tbl->current_rate = rate; |
2177 | rs_set_expected_tpt_table(lq_sta, tbl); | 2168 | rs_set_expected_tpt_table(lq_sta, tbl); |
2178 | rs_fill_link_cmd(NULL, lq_sta, rate); | 2169 | rs_fill_link_cmd(NULL, NULL, lq_sta, rate); |
2179 | /* TODO restore station should remember the lq cmd */ | 2170 | /* TODO restore station should remember the lq cmd */ |
2180 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_SYNC, true); | 2171 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_SYNC, true); |
2181 | } | 2172 | } |
@@ -2190,7 +2181,6 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, | |||
2190 | struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); | 2181 | struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); |
2191 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 2182 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
2192 | struct iwl_lq_sta *lq_sta = mvm_sta; | 2183 | struct iwl_lq_sta *lq_sta = mvm_sta; |
2193 | int rate_idx; | ||
2194 | 2184 | ||
2195 | IWL_DEBUG_RATE_LIMIT(mvm, "rate scale calculate new rate for skb\n"); | 2185 | IWL_DEBUG_RATE_LIMIT(mvm, "rate scale calculate new rate for skb\n"); |
2196 | 2186 | ||
@@ -2215,36 +2205,9 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, | |||
2215 | if (rate_control_send_low(sta, mvm_sta, txrc)) | 2205 | if (rate_control_send_low(sta, mvm_sta, txrc)) |
2216 | return; | 2206 | return; |
2217 | 2207 | ||
2218 | rate_idx = lq_sta->last_txrate_idx; | 2208 | iwl_mvm_hwrate_to_tx_rate(lq_sta->last_rate_n_flags, |
2219 | 2209 | info->band, &info->control.rates[0]); | |
2220 | if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) { | 2210 | |
2221 | rate_idx -= IWL_FIRST_OFDM_RATE; | ||
2222 | /* 6M and 9M shared same MCS index */ | ||
2223 | rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0; | ||
2224 | WARN_ON_ONCE(rs_extract_rate(lq_sta->last_rate_n_flags) >= | ||
2225 | IWL_RATE_MIMO3_6M_PLCP); | ||
2226 | if (rs_extract_rate(lq_sta->last_rate_n_flags) >= | ||
2227 | IWL_RATE_MIMO2_6M_PLCP) | ||
2228 | rate_idx = rate_idx + MCS_INDEX_PER_STREAM; | ||
2229 | info->control.rates[0].flags = IEEE80211_TX_RC_MCS; | ||
2230 | if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK) | ||
2231 | info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI; | ||
2232 | if (lq_sta->last_rate_n_flags & RATE_MCS_CHAN_WIDTH_40) /* TODO */ | ||
2233 | info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
2234 | if (lq_sta->last_rate_n_flags & RATE_HT_MCS_GF_MSK) | ||
2235 | info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD; | ||
2236 | } else { | ||
2237 | /* Check for invalid rates */ | ||
2238 | if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) || | ||
2239 | ((sband->band == IEEE80211_BAND_5GHZ) && | ||
2240 | (rate_idx < IWL_FIRST_OFDM_RATE))) | ||
2241 | rate_idx = rate_lowest_index(sband, sta); | ||
2242 | /* On valid 5 GHz rate, adjust index */ | ||
2243 | else if (sband->band == IEEE80211_BAND_5GHZ) | ||
2244 | rate_idx -= IWL_FIRST_OFDM_RATE; | ||
2245 | info->control.rates[0].flags = 0; | ||
2246 | } | ||
2247 | info->control.rates[0].idx = rate_idx; | ||
2248 | info->control.rates[0].count = 1; | 2211 | info->control.rates[0].count = 1; |
2249 | } | 2212 | } |
2250 | 2213 | ||
@@ -2261,6 +2224,24 @@ static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, | |||
2261 | return &sta_priv->lq_sta; | 2224 | return &sta_priv->lq_sta; |
2262 | } | 2225 | } |
2263 | 2226 | ||
2227 | static int rs_vht_highest_rx_mcs_index(struct ieee80211_sta_vht_cap *vht_cap, | ||
2228 | int nss) | ||
2229 | { | ||
2230 | u16 rx_mcs = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) & | ||
2231 | (0x3 << (2 * (nss - 1))); | ||
2232 | rx_mcs >>= (2 * (nss - 1)); | ||
2233 | |||
2234 | if (rx_mcs == IEEE80211_VHT_MCS_SUPPORT_0_7) | ||
2235 | return IWL_RATE_MCS_7_INDEX; | ||
2236 | else if (rx_mcs == IEEE80211_VHT_MCS_SUPPORT_0_8) | ||
2237 | return IWL_RATE_MCS_8_INDEX; | ||
2238 | else if (rx_mcs == IEEE80211_VHT_MCS_SUPPORT_0_9) | ||
2239 | return IWL_RATE_MCS_9_INDEX; | ||
2240 | |||
2241 | WARN_ON_ONCE(rx_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED); | ||
2242 | return -1; | ||
2243 | } | ||
2244 | |||
2264 | /* | 2245 | /* |
2265 | * Called after adding a new station to initialize rate scaling | 2246 | * Called after adding a new station to initialize rate scaling |
2266 | */ | 2247 | */ |
@@ -2270,6 +2251,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2270 | int i, j; | 2251 | int i, j; |
2271 | struct ieee80211_hw *hw = mvm->hw; | 2252 | struct ieee80211_hw *hw = mvm->hw; |
2272 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | 2253 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; |
2254 | struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; | ||
2273 | struct iwl_mvm_sta *sta_priv; | 2255 | struct iwl_mvm_sta *sta_priv; |
2274 | struct iwl_lq_sta *lq_sta; | 2256 | struct iwl_lq_sta *lq_sta; |
2275 | struct ieee80211_supported_band *sband; | 2257 | struct ieee80211_supported_band *sband; |
@@ -2298,7 +2280,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2298 | 2280 | ||
2299 | lq_sta->max_rate_idx = -1; | 2281 | lq_sta->max_rate_idx = -1; |
2300 | lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; | 2282 | lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; |
2301 | lq_sta->is_green = rs_use_green(sta); | ||
2302 | lq_sta->band = sband->band; | 2283 | lq_sta->band = sband->band; |
2303 | /* | 2284 | /* |
2304 | * active legacy rates as per supported rates bitmap | 2285 | * active legacy rates as per supported rates bitmap |
@@ -2308,25 +2289,54 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2308 | for_each_set_bit(i, &supp, BITS_PER_LONG) | 2289 | for_each_set_bit(i, &supp, BITS_PER_LONG) |
2309 | lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value); | 2290 | lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value); |
2310 | 2291 | ||
2311 | /* | 2292 | /* TODO: should probably account for rx_highest for both HT/VHT */ |
2312 | * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), | 2293 | if (!vht_cap || !vht_cap->vht_supported) { |
2313 | * supp_rates[] does not; shift to convert format, force 9 MBits off. | 2294 | /* active_siso_rate mask includes 9 MBits (bit 5), |
2314 | */ | 2295 | * and CCK (bits 0-3), supp_rates[] does not; |
2315 | lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1; | 2296 | * shift to convert format, force 9 MBits off. |
2316 | lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1; | 2297 | */ |
2317 | lq_sta->active_siso_rate &= ~((u16)0x2); | 2298 | lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1; |
2318 | lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; | 2299 | lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1; |
2300 | lq_sta->active_siso_rate &= ~((u16)0x2); | ||
2301 | lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; | ||
2302 | |||
2303 | /* Same here */ | ||
2304 | lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1; | ||
2305 | lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1; | ||
2306 | lq_sta->active_mimo2_rate &= ~((u16)0x2); | ||
2307 | lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; | ||
2308 | |||
2309 | lq_sta->is_vht = false; | ||
2310 | } else { | ||
2311 | int highest_mcs = rs_vht_highest_rx_mcs_index(vht_cap, 1); | ||
2312 | if (highest_mcs >= IWL_RATE_MCS_0_INDEX) { | ||
2313 | for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) { | ||
2314 | if (i == IWL_RATE_9M_INDEX) | ||
2315 | continue; | ||
2316 | |||
2317 | lq_sta->active_siso_rate |= BIT(i); | ||
2318 | } | ||
2319 | } | ||
2320 | |||
2321 | highest_mcs = rs_vht_highest_rx_mcs_index(vht_cap, 2); | ||
2322 | if (highest_mcs >= IWL_RATE_MCS_0_INDEX) { | ||
2323 | for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) { | ||
2324 | if (i == IWL_RATE_9M_INDEX) | ||
2325 | continue; | ||
2319 | 2326 | ||
2320 | /* Same here */ | 2327 | lq_sta->active_mimo2_rate |= BIT(i); |
2321 | lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1; | 2328 | } |
2322 | lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1; | 2329 | } |
2323 | lq_sta->active_mimo2_rate &= ~((u16)0x2); | 2330 | |
2324 | lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; | 2331 | /* TODO: avoid MCS9 in 20Mhz which isn't valid for 11ac */ |
2332 | lq_sta->is_vht = true; | ||
2333 | } | ||
2325 | 2334 | ||
2326 | IWL_DEBUG_RATE(mvm, | 2335 | IWL_DEBUG_RATE(mvm, |
2327 | "SISO-RATE=%X MIMO2-RATE=%X\n", | 2336 | "SISO-RATE=%X MIMO2-RATE=%X VHT=%d\n", |
2328 | lq_sta->active_siso_rate, | 2337 | lq_sta->active_siso_rate, |
2329 | lq_sta->active_mimo2_rate); | 2338 | lq_sta->active_mimo2_rate, |
2339 | lq_sta->is_vht); | ||
2330 | 2340 | ||
2331 | /* These values will be overridden later */ | 2341 | /* These values will be overridden later */ |
2332 | lq_sta->lq.single_stream_ant_msk = | 2342 | lq_sta->lq.single_stream_ant_msk = |
@@ -2358,6 +2368,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2358 | } | 2368 | } |
2359 | 2369 | ||
2360 | static void rs_fill_link_cmd(struct iwl_mvm *mvm, | 2370 | static void rs_fill_link_cmd(struct iwl_mvm *mvm, |
2371 | struct ieee80211_sta *sta, | ||
2361 | struct iwl_lq_sta *lq_sta, u32 new_rate) | 2372 | struct iwl_lq_sta *lq_sta, u32 new_rate) |
2362 | { | 2373 | { |
2363 | struct iwl_scale_tbl_info tbl_type; | 2374 | struct iwl_scale_tbl_info tbl_type; |
@@ -2429,7 +2440,6 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, | |||
2429 | rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type, | 2440 | rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type, |
2430 | &rate_idx); | 2441 | &rate_idx); |
2431 | 2442 | ||
2432 | |||
2433 | /* Indicate to uCode which entries might be MIMO. | 2443 | /* Indicate to uCode which entries might be MIMO. |
2434 | * If initial rate was MIMO, this will finally end up | 2444 | * If initial rate was MIMO, this will finally end up |
2435 | * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */ | 2445 | * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */ |
@@ -2455,7 +2465,9 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, | |||
2455 | } | 2465 | } |
2456 | 2466 | ||
2457 | /* Don't allow HT rates after next pass. | 2467 | /* Don't allow HT rates after next pass. |
2458 | * rs_get_lower_rate() will change type to LQ_A or LQ_G. */ | 2468 | * rs_get_lower_rate() will change type to LQ_LEGACY_A |
2469 | * or LQ_LEGACY_G. | ||
2470 | */ | ||
2459 | use_ht_possible = 0; | 2471 | use_ht_possible = 0; |
2460 | 2472 | ||
2461 | /* Override next rate if needed for debug purposes */ | 2473 | /* Override next rate if needed for debug purposes */ |
@@ -2474,12 +2486,9 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, | |||
2474 | lq_cmd->agg_time_limit = | 2486 | lq_cmd->agg_time_limit = |
2475 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | 2487 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); |
2476 | 2488 | ||
2477 | /* | 2489 | if (sta) |
2478 | * overwrite if needed, pass aggregation time limit | 2490 | lq_cmd->agg_time_limit = |
2479 | * to uCode in uSec - This is racy - but heh, at least it helps... | 2491 | cpu_to_le16(iwl_mvm_bt_coex_agg_time_limit(mvm, sta)); |
2480 | */ | ||
2481 | if (mvm && BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= 2) | ||
2482 | lq_cmd->agg_time_limit = cpu_to_le16(1200); | ||
2483 | } | 2492 | } |
2484 | 2493 | ||
2485 | static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | 2494 | static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
@@ -2586,16 +2595,18 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | |||
2586 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "", | 2595 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "", |
2587 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : ""); | 2596 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : ""); |
2588 | desc += sprintf(buff+desc, "lq type %s\n", | 2597 | desc += sprintf(buff+desc, "lq type %s\n", |
2589 | (is_legacy(tbl->lq_type)) ? "legacy" : "HT"); | 2598 | (is_legacy(tbl->lq_type)) ? "legacy" : |
2590 | if (is_Ht(tbl->lq_type)) { | 2599 | is_vht(tbl->lq_type) ? "VHT" : "HT"); |
2600 | if (is_ht(tbl->lq_type)) { | ||
2591 | desc += sprintf(buff+desc, " %s", | 2601 | desc += sprintf(buff+desc, " %s", |
2592 | (is_siso(tbl->lq_type)) ? "SISO" : "MIMO2"); | 2602 | (is_siso(tbl->lq_type)) ? "SISO" : "MIMO2"); |
2593 | desc += sprintf(buff+desc, " %s", | 2603 | desc += sprintf(buff+desc, " %s", |
2594 | (tbl->is_ht40) ? "40MHz" : "20MHz"); | 2604 | (is_ht20(tbl)) ? "20MHz" : |
2595 | desc += sprintf(buff+desc, " %s %s %s\n", | 2605 | (is_ht40(tbl)) ? "40MHz" : |
2606 | (is_ht80(tbl)) ? "80Mhz" : "BAD BW"); | ||
2607 | desc += sprintf(buff+desc, " %s %s\n", | ||
2596 | (tbl->is_SGI) ? "SGI" : "", | 2608 | (tbl->is_SGI) ? "SGI" : "", |
2597 | (lq_sta->is_green) ? "GF enabled" : "", | 2609 | (lq_sta->is_agg) ? "AGG on" : ""); |
2598 | (lq_sta->is_agg) ? "AGG on" : ""); | ||
2599 | } | 2610 | } |
2600 | desc += sprintf(buff+desc, "last tx rate=0x%X\n", | 2611 | desc += sprintf(buff+desc, "last tx rate=0x%X\n", |
2601 | lq_sta->last_rate_n_flags); | 2612 | lq_sta->last_rate_n_flags); |
@@ -2653,7 +2664,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, | |||
2653 | int desc = 0; | 2664 | int desc = 0; |
2654 | int i, j; | 2665 | int i, j; |
2655 | ssize_t ret; | 2666 | ssize_t ret; |
2656 | 2667 | struct iwl_scale_tbl_info *tbl; | |
2657 | struct iwl_lq_sta *lq_sta = file->private_data; | 2668 | struct iwl_lq_sta *lq_sta = file->private_data; |
2658 | 2669 | ||
2659 | buff = kmalloc(1024, GFP_KERNEL); | 2670 | buff = kmalloc(1024, GFP_KERNEL); |
@@ -2661,21 +2672,23 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, | |||
2661 | return -ENOMEM; | 2672 | return -ENOMEM; |
2662 | 2673 | ||
2663 | for (i = 0; i < LQ_SIZE; i++) { | 2674 | for (i = 0; i < LQ_SIZE; i++) { |
2675 | tbl = &(lq_sta->lq_info[i]); | ||
2664 | desc += sprintf(buff+desc, | 2676 | desc += sprintf(buff+desc, |
2665 | "%s type=%d SGI=%d HT40=%d DUP=0 GF=%d\n" | 2677 | "%s type=%d SGI=%d BW=%s DUP=0\n" |
2666 | "rate=0x%X\n", | 2678 | "rate=0x%X\n", |
2667 | lq_sta->active_tbl == i ? "*" : "x", | 2679 | lq_sta->active_tbl == i ? "*" : "x", |
2668 | lq_sta->lq_info[i].lq_type, | 2680 | tbl->lq_type, |
2669 | lq_sta->lq_info[i].is_SGI, | 2681 | tbl->is_SGI, |
2670 | lq_sta->lq_info[i].is_ht40, | 2682 | is_ht20(tbl) ? "20Mhz" : |
2671 | lq_sta->is_green, | 2683 | is_ht40(tbl) ? "40Mhz" : |
2672 | lq_sta->lq_info[i].current_rate); | 2684 | is_ht80(tbl) ? "80Mhz" : "ERR", |
2685 | tbl->current_rate); | ||
2673 | for (j = 0; j < IWL_RATE_COUNT; j++) { | 2686 | for (j = 0; j < IWL_RATE_COUNT; j++) { |
2674 | desc += sprintf(buff+desc, | 2687 | desc += sprintf(buff+desc, |
2675 | "counter=%d success=%d %%=%d\n", | 2688 | "counter=%d success=%d %%=%d\n", |
2676 | lq_sta->lq_info[i].win[j].counter, | 2689 | tbl->win[j].counter, |
2677 | lq_sta->lq_info[i].win[j].success_counter, | 2690 | tbl->win[j].success_counter, |
2678 | lq_sta->lq_info[i].win[j].success_ratio); | 2691 | tbl->win[j].success_ratio); |
2679 | } | 2692 | } |
2680 | } | 2693 | } |
2681 | ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); | 2694 | ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 465d40ee176f..5d5344f7070b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h | |||
@@ -35,9 +35,11 @@ | |||
35 | #include "iwl-trans.h" | 35 | #include "iwl-trans.h" |
36 | 36 | ||
37 | struct iwl_rs_rate_info { | 37 | struct iwl_rs_rate_info { |
38 | u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ | 38 | u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ |
39 | u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ | 39 | u8 plcp_ht_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ |
40 | u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ | 40 | u8 plcp_ht_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ |
41 | u8 plcp_vht_siso; | ||
42 | u8 plcp_vht_mimo2; | ||
41 | u8 prev_rs; /* previous rate used in rs algo */ | 43 | u8 prev_rs; /* previous rate used in rs algo */ |
42 | u8 next_rs; /* next rate used in rs algo */ | 44 | u8 next_rs; /* next rate used in rs algo */ |
43 | }; | 45 | }; |
@@ -83,35 +85,52 @@ enum { | |||
83 | #define IWL_RATE_11M_MASK (1 << IWL_RATE_11M_INDEX) | 85 | #define IWL_RATE_11M_MASK (1 << IWL_RATE_11M_INDEX) |
84 | 86 | ||
85 | 87 | ||
86 | /* uCode API values for OFDM high-throughput (HT) bit rates */ | 88 | /* uCode API values for HT/VHT bit rates */ |
87 | enum { | 89 | enum { |
88 | IWL_RATE_SISO_6M_PLCP = 0, | 90 | IWL_RATE_HT_SISO_MCS_0_PLCP = 0, |
89 | IWL_RATE_SISO_12M_PLCP = 1, | 91 | IWL_RATE_HT_SISO_MCS_1_PLCP = 1, |
90 | IWL_RATE_SISO_18M_PLCP = 2, | 92 | IWL_RATE_HT_SISO_MCS_2_PLCP = 2, |
91 | IWL_RATE_SISO_24M_PLCP = 3, | 93 | IWL_RATE_HT_SISO_MCS_3_PLCP = 3, |
92 | IWL_RATE_SISO_36M_PLCP = 4, | 94 | IWL_RATE_HT_SISO_MCS_4_PLCP = 4, |
93 | IWL_RATE_SISO_48M_PLCP = 5, | 95 | IWL_RATE_HT_SISO_MCS_5_PLCP = 5, |
94 | IWL_RATE_SISO_54M_PLCP = 6, | 96 | IWL_RATE_HT_SISO_MCS_6_PLCP = 6, |
95 | IWL_RATE_SISO_60M_PLCP = 7, | 97 | IWL_RATE_HT_SISO_MCS_7_PLCP = 7, |
96 | IWL_RATE_MIMO2_6M_PLCP = 0x8, | 98 | IWL_RATE_HT_MIMO2_MCS_0_PLCP = 0x8, |
97 | IWL_RATE_MIMO2_12M_PLCP = 0x9, | 99 | IWL_RATE_HT_MIMO2_MCS_1_PLCP = 0x9, |
98 | IWL_RATE_MIMO2_18M_PLCP = 0xa, | 100 | IWL_RATE_HT_MIMO2_MCS_2_PLCP = 0xA, |
99 | IWL_RATE_MIMO2_24M_PLCP = 0xb, | 101 | IWL_RATE_HT_MIMO2_MCS_3_PLCP = 0xB, |
100 | IWL_RATE_MIMO2_36M_PLCP = 0xc, | 102 | IWL_RATE_HT_MIMO2_MCS_4_PLCP = 0xC, |
101 | IWL_RATE_MIMO2_48M_PLCP = 0xd, | 103 | IWL_RATE_HT_MIMO2_MCS_5_PLCP = 0xD, |
102 | IWL_RATE_MIMO2_54M_PLCP = 0xe, | 104 | IWL_RATE_HT_MIMO2_MCS_6_PLCP = 0xE, |
103 | IWL_RATE_MIMO2_60M_PLCP = 0xf, | 105 | IWL_RATE_HT_MIMO2_MCS_7_PLCP = 0xF, |
104 | IWL_RATE_MIMO3_6M_PLCP = 0x10, | 106 | IWL_RATE_VHT_SISO_MCS_0_PLCP = 0, |
105 | IWL_RATE_MIMO3_12M_PLCP = 0x11, | 107 | IWL_RATE_VHT_SISO_MCS_1_PLCP = 1, |
106 | IWL_RATE_MIMO3_18M_PLCP = 0x12, | 108 | IWL_RATE_VHT_SISO_MCS_2_PLCP = 2, |
107 | IWL_RATE_MIMO3_24M_PLCP = 0x13, | 109 | IWL_RATE_VHT_SISO_MCS_3_PLCP = 3, |
108 | IWL_RATE_MIMO3_36M_PLCP = 0x14, | 110 | IWL_RATE_VHT_SISO_MCS_4_PLCP = 4, |
109 | IWL_RATE_MIMO3_48M_PLCP = 0x15, | 111 | IWL_RATE_VHT_SISO_MCS_5_PLCP = 5, |
110 | IWL_RATE_MIMO3_54M_PLCP = 0x16, | 112 | IWL_RATE_VHT_SISO_MCS_6_PLCP = 6, |
111 | IWL_RATE_MIMO3_60M_PLCP = 0x17, | 113 | IWL_RATE_VHT_SISO_MCS_7_PLCP = 7, |
112 | IWL_RATE_SISO_INVM_PLCP, | 114 | IWL_RATE_VHT_SISO_MCS_8_PLCP = 8, |
113 | IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, | 115 | IWL_RATE_VHT_SISO_MCS_9_PLCP = 9, |
114 | IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, | 116 | IWL_RATE_VHT_MIMO2_MCS_0_PLCP = 0x10, |
117 | IWL_RATE_VHT_MIMO2_MCS_1_PLCP = 0x11, | ||
118 | IWL_RATE_VHT_MIMO2_MCS_2_PLCP = 0x12, | ||
119 | IWL_RATE_VHT_MIMO2_MCS_3_PLCP = 0x13, | ||
120 | IWL_RATE_VHT_MIMO2_MCS_4_PLCP = 0x14, | ||
121 | IWL_RATE_VHT_MIMO2_MCS_5_PLCP = 0x15, | ||
122 | IWL_RATE_VHT_MIMO2_MCS_6_PLCP = 0x16, | ||
123 | IWL_RATE_VHT_MIMO2_MCS_7_PLCP = 0x17, | ||
124 | IWL_RATE_VHT_MIMO2_MCS_8_PLCP = 0x18, | ||
125 | IWL_RATE_VHT_MIMO2_MCS_9_PLCP = 0x19, | ||
126 | IWL_RATE_HT_SISO_MCS_INV_PLCP, | ||
127 | IWL_RATE_HT_MIMO2_MCS_INV_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, | ||
128 | IWL_RATE_VHT_SISO_MCS_INV_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, | ||
129 | IWL_RATE_VHT_MIMO2_MCS_INV_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, | ||
130 | IWL_RATE_HT_SISO_MCS_8_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, | ||
131 | IWL_RATE_HT_SISO_MCS_9_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, | ||
132 | IWL_RATE_HT_MIMO2_MCS_8_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, | ||
133 | IWL_RATE_HT_MIMO2_MCS_9_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, | ||
115 | }; | 134 | }; |
116 | 135 | ||
117 | #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) | 136 | #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) |
@@ -139,25 +158,33 @@ enum { | |||
139 | #define IWL_RATE_DECREASE_TH 1920 /* 15% */ | 158 | #define IWL_RATE_DECREASE_TH 1920 /* 15% */ |
140 | 159 | ||
141 | /* possible actions when in legacy mode */ | 160 | /* possible actions when in legacy mode */ |
142 | #define IWL_LEGACY_SWITCH_ANTENNA1 0 | 161 | enum { |
143 | #define IWL_LEGACY_SWITCH_ANTENNA2 1 | 162 | IWL_LEGACY_SWITCH_ANTENNA, |
144 | #define IWL_LEGACY_SWITCH_SISO 2 | 163 | IWL_LEGACY_SWITCH_SISO, |
145 | #define IWL_LEGACY_SWITCH_MIMO2 3 | 164 | IWL_LEGACY_SWITCH_MIMO2, |
165 | IWL_LEGACY_FIRST_ACTION = IWL_LEGACY_SWITCH_ANTENNA, | ||
166 | IWL_LEGACY_LAST_ACTION = IWL_LEGACY_SWITCH_MIMO2, | ||
167 | }; | ||
146 | 168 | ||
147 | /* possible actions when in siso mode */ | 169 | /* possible actions when in siso mode */ |
148 | #define IWL_SISO_SWITCH_ANTENNA1 0 | 170 | enum { |
149 | #define IWL_SISO_SWITCH_ANTENNA2 1 | 171 | IWL_SISO_SWITCH_ANTENNA, |
150 | #define IWL_SISO_SWITCH_MIMO2 2 | 172 | IWL_SISO_SWITCH_MIMO2, |
151 | #define IWL_SISO_SWITCH_GI 3 | 173 | IWL_SISO_SWITCH_GI, |
174 | IWL_SISO_FIRST_ACTION = IWL_SISO_SWITCH_ANTENNA, | ||
175 | IWL_SISO_LAST_ACTION = IWL_SISO_SWITCH_GI, | ||
176 | }; | ||
152 | 177 | ||
153 | /* possible actions when in mimo mode */ | 178 | /* possible actions when in mimo mode */ |
154 | #define IWL_MIMO2_SWITCH_ANTENNA1 0 | 179 | enum { |
155 | #define IWL_MIMO2_SWITCH_ANTENNA2 1 | 180 | IWL_MIMO2_SWITCH_SISO_A, |
156 | #define IWL_MIMO2_SWITCH_SISO_A 2 | 181 | IWL_MIMO2_SWITCH_SISO_B, |
157 | #define IWL_MIMO2_SWITCH_SISO_B 3 | 182 | IWL_MIMO2_SWITCH_GI, |
158 | #define IWL_MIMO2_SWITCH_GI 4 | 183 | IWL_MIMO2_FIRST_ACTION = IWL_MIMO2_SWITCH_SISO_A, |
184 | IWL_MIMO2_LAST_ACTION = IWL_MIMO2_SWITCH_GI, | ||
185 | }; | ||
159 | 186 | ||
160 | #define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_GI | 187 | #define IWL_MAX_SEARCH IWL_MIMO2_LAST_ACTION |
161 | 188 | ||
162 | #define IWL_ACTION_LIMIT 3 /* # possible actions */ | 189 | #define IWL_ACTION_LIMIT 3 /* # possible actions */ |
163 | 190 | ||
@@ -188,20 +215,31 @@ enum { | |||
188 | 215 | ||
189 | enum iwl_table_type { | 216 | enum iwl_table_type { |
190 | LQ_NONE, | 217 | LQ_NONE, |
191 | LQ_G, /* legacy types */ | 218 | LQ_LEGACY_G, /* legacy types */ |
192 | LQ_A, | 219 | LQ_LEGACY_A, |
193 | LQ_SISO, /* high-throughput types */ | 220 | LQ_HT_SISO, /* HT types */ |
194 | LQ_MIMO2, | 221 | LQ_HT_MIMO2, |
222 | LQ_VHT_SISO, /* VHT types */ | ||
223 | LQ_VHT_MIMO2, | ||
195 | LQ_MAX, | 224 | LQ_MAX, |
196 | }; | 225 | }; |
197 | 226 | ||
198 | #define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) | 227 | #define is_legacy(tbl) (((tbl) == LQ_LEGACY_G) || ((tbl) == LQ_LEGACY_A)) |
199 | #define is_siso(tbl) ((tbl) == LQ_SISO) | 228 | #define is_ht_siso(tbl) ((tbl) == LQ_HT_SISO) |
200 | #define is_mimo2(tbl) ((tbl) == LQ_MIMO2) | 229 | #define is_ht_mimo2(tbl) ((tbl) == LQ_HT_MIMO2) |
201 | #define is_mimo(tbl) is_mimo2(tbl) | 230 | #define is_vht_siso(tbl) ((tbl) == LQ_VHT_SISO) |
202 | #define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl)) | 231 | #define is_vht_mimo2(tbl) ((tbl) == LQ_VHT_MIMO2) |
203 | #define is_a_band(tbl) ((tbl) == LQ_A) | 232 | #define is_siso(tbl) (is_ht_siso(tbl) || is_vht_siso(tbl)) |
204 | #define is_g_and(tbl) ((tbl) == LQ_G) | 233 | #define is_mimo2(tbl) (is_ht_mimo2(tbl) || is_vht_mimo2(tbl)) |
234 | #define is_mimo(tbl) (is_mimo2(tbl)) | ||
235 | #define is_ht(tbl) (is_ht_siso(tbl) || is_ht_mimo2(tbl)) | ||
236 | #define is_vht(tbl) (is_vht_siso(tbl) || is_vht_mimo2(tbl)) | ||
237 | #define is_a_band(tbl) ((tbl) == LQ_LEGACY_A) | ||
238 | #define is_g_band(tbl) ((tbl) == LQ_LEGACY_G) | ||
239 | |||
240 | #define is_ht20(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_20) | ||
241 | #define is_ht40(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_40) | ||
242 | #define is_ht80(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_80) | ||
205 | 243 | ||
206 | #define IWL_MAX_MCS_DISPLAY_SIZE 12 | 244 | #define IWL_MAX_MCS_DISPLAY_SIZE 12 |
207 | 245 | ||
@@ -232,7 +270,7 @@ struct iwl_scale_tbl_info { | |||
232 | enum iwl_table_type lq_type; | 270 | enum iwl_table_type lq_type; |
233 | u8 ant_type; | 271 | u8 ant_type; |
234 | u8 is_SGI; /* 1 = short guard interval */ | 272 | u8 is_SGI; /* 1 = short guard interval */ |
235 | u8 is_ht40; /* 1 = 40 MHz channel width */ | 273 | u32 bw; /* channel bandwidth; RATE_MCS_CHAN_WIDTH_XX */ |
236 | u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ | 274 | u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ |
237 | u8 max_search; /* maximun number of tables we can search */ | 275 | u8 max_search; /* maximun number of tables we can search */ |
238 | s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ | 276 | s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ |
@@ -262,7 +300,7 @@ struct iwl_lq_sta { | |||
262 | u64 flush_timer; /* time staying in mode before new search */ | 300 | u64 flush_timer; /* time staying in mode before new search */ |
263 | 301 | ||
264 | u8 action_counter; /* # mode-switch actions tried */ | 302 | u8 action_counter; /* # mode-switch actions tried */ |
265 | u8 is_green; | 303 | bool is_vht; |
266 | enum ieee80211_band band; | 304 | enum ieee80211_band band; |
267 | 305 | ||
268 | /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ | 306 | /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 2a8cb5a60535..a4af5019a496 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c | |||
@@ -422,6 +422,27 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac, | |||
422 | 422 | ||
423 | mvmvif->bf_data.ave_beacon_signal = sig; | 423 | mvmvif->bf_data.ave_beacon_signal = sig; |
424 | 424 | ||
425 | /* BT Coex */ | ||
426 | if (mvmvif->bf_data.bt_coex_min_thold != | ||
427 | mvmvif->bf_data.bt_coex_max_thold) { | ||
428 | last_event = mvmvif->bf_data.last_bt_coex_event; | ||
429 | if (sig > mvmvif->bf_data.bt_coex_max_thold && | ||
430 | (last_event <= mvmvif->bf_data.bt_coex_min_thold || | ||
431 | last_event == 0)) { | ||
432 | mvmvif->bf_data.last_bt_coex_event = sig; | ||
433 | IWL_DEBUG_RX(mvm, "cqm_iterator bt coex high %d\n", | ||
434 | sig); | ||
435 | iwl_mvm_bt_rssi_event(mvm, vif, RSSI_EVENT_HIGH); | ||
436 | } else if (sig < mvmvif->bf_data.bt_coex_min_thold && | ||
437 | (last_event >= mvmvif->bf_data.bt_coex_max_thold || | ||
438 | last_event == 0)) { | ||
439 | mvmvif->bf_data.last_bt_coex_event = sig; | ||
440 | IWL_DEBUG_RX(mvm, "cqm_iterator bt coex low %d\n", | ||
441 | sig); | ||
442 | iwl_mvm_bt_rssi_event(mvm, vif, RSSI_EVENT_LOW); | ||
443 | } | ||
444 | } | ||
445 | |||
425 | if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) | 446 | if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) |
426 | return; | 447 | return; |
427 | 448 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 621fb71f282a..dff7592e1ff8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
@@ -74,8 +74,12 @@ | |||
74 | static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) | 74 | static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) |
75 | { | 75 | { |
76 | u16 rx_chain; | 76 | u16 rx_chain; |
77 | u8 rx_ant = iwl_fw_valid_rx_ant(mvm->fw); | 77 | u8 rx_ant; |
78 | 78 | ||
79 | if (mvm->scan_rx_ant != ANT_NONE) | ||
80 | rx_ant = mvm->scan_rx_ant; | ||
81 | else | ||
82 | rx_ant = iwl_fw_valid_rx_ant(mvm->fw); | ||
79 | rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; | 83 | rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; |
80 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; | 84 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; |
81 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; | 85 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; |
@@ -93,10 +97,10 @@ static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif) | |||
93 | 97 | ||
94 | static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif) | 98 | static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif) |
95 | { | 99 | { |
96 | if (vif->bss_conf.assoc) | 100 | if (!vif->bss_conf.assoc) |
97 | return cpu_to_le32(vif->bss_conf.beacon_int); | ||
98 | else | ||
99 | return 0; | 101 | return 0; |
102 | |||
103 | return cpu_to_le32(ieee80211_tu_to_usec(vif->bss_conf.beacon_int)); | ||
100 | } | 104 | } |
101 | 105 | ||
102 | static inline __le32 | 106 | static inline __le32 |
@@ -133,11 +137,12 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band, | |||
133 | * request. | 137 | * request. |
134 | */ | 138 | */ |
135 | static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd, | 139 | static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd, |
136 | struct cfg80211_scan_request *req) | 140 | struct cfg80211_scan_request *req, |
141 | int first) | ||
137 | { | 142 | { |
138 | int fw_idx, req_idx; | 143 | int fw_idx, req_idx; |
139 | 144 | ||
140 | for (req_idx = req->n_ssids - 1, fw_idx = 0; req_idx > 0; | 145 | for (req_idx = req->n_ssids - 1, fw_idx = 0; req_idx >= first; |
141 | req_idx--, fw_idx++) { | 146 | req_idx--, fw_idx++) { |
142 | cmd->direct_scan[fw_idx].id = WLAN_EID_SSID; | 147 | cmd->direct_scan[fw_idx].id = WLAN_EID_SSID; |
143 | cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len; | 148 | cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len; |
@@ -153,9 +158,9 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd, | |||
153 | * just to notify that this scan is active and not passive. | 158 | * just to notify that this scan is active and not passive. |
154 | * In order to notify the FW of the number of SSIDs we wish to scan (including | 159 | * In order to notify the FW of the number of SSIDs we wish to scan (including |
155 | * the zero-length one), we need to set the corresponding bits in chan->type, | 160 | * the zero-length one), we need to set the corresponding bits in chan->type, |
156 | * one for each SSID, and set the active bit (first). The first SSID is already | 161 | * one for each SSID, and set the active bit (first). If the first SSID is |
157 | * included in the probe template, so we need to set only req->n_ssids - 1 bits | 162 | * already included in the probe template, so we need to set only |
158 | * in addition to the first bit. | 163 | * req->n_ssids - 1 bits in addition to the first bit. |
159 | */ | 164 | */ |
160 | static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids) | 165 | static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids) |
161 | { | 166 | { |
@@ -170,7 +175,8 @@ static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band) | |||
170 | } | 175 | } |
171 | 176 | ||
172 | static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, | 177 | static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, |
173 | struct cfg80211_scan_request *req) | 178 | struct cfg80211_scan_request *req, |
179 | bool basic_ssid) | ||
174 | { | 180 | { |
175 | u16 passive_dwell = iwl_mvm_get_passive_dwell(req->channels[0]->band); | 181 | u16 passive_dwell = iwl_mvm_get_passive_dwell(req->channels[0]->band); |
176 | u16 active_dwell = iwl_mvm_get_active_dwell(req->channels[0]->band, | 182 | u16 active_dwell = iwl_mvm_get_active_dwell(req->channels[0]->band, |
@@ -178,10 +184,14 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, | |||
178 | struct iwl_scan_channel *chan = (struct iwl_scan_channel *) | 184 | struct iwl_scan_channel *chan = (struct iwl_scan_channel *) |
179 | (cmd->data + le16_to_cpu(cmd->tx_cmd.len)); | 185 | (cmd->data + le16_to_cpu(cmd->tx_cmd.len)); |
180 | int i; | 186 | int i; |
187 | int type = BIT(req->n_ssids) - 1; | ||
188 | |||
189 | if (!basic_ssid) | ||
190 | type |= BIT(req->n_ssids); | ||
181 | 191 | ||
182 | for (i = 0; i < cmd->channel_count; i++) { | 192 | for (i = 0; i < cmd->channel_count; i++) { |
183 | chan->channel = cpu_to_le16(req->channels[i]->hw_value); | 193 | chan->channel = cpu_to_le16(req->channels[i]->hw_value); |
184 | chan->type = cpu_to_le32(BIT(req->n_ssids) - 1); | 194 | chan->type = cpu_to_le32(type); |
185 | if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) | 195 | if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) |
186 | chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE); | 196 | chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE); |
187 | chan->active_dwell = cpu_to_le16(active_dwell); | 197 | chan->active_dwell = cpu_to_le16(active_dwell); |
@@ -268,6 +278,8 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, | |||
268 | u32 status; | 278 | u32 status; |
269 | int ssid_len = 0; | 279 | int ssid_len = 0; |
270 | u8 *ssid = NULL; | 280 | u8 *ssid = NULL; |
281 | bool basic_ssid = !(mvm->fw->ucode_capa.flags & | ||
282 | IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID); | ||
271 | 283 | ||
272 | lockdep_assert_held(&mvm->mutex); | 284 | lockdep_assert_held(&mvm->mutex); |
273 | BUG_ON(mvm->scan_cmd == NULL); | 285 | BUG_ON(mvm->scan_cmd == NULL); |
@@ -302,14 +314,16 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, | |||
302 | if (req->n_ssids > 0) { | 314 | if (req->n_ssids > 0) { |
303 | cmd->passive2active = cpu_to_le16(1); | 315 | cmd->passive2active = cpu_to_le16(1); |
304 | cmd->scan_flags |= SCAN_FLAGS_PASSIVE2ACTIVE; | 316 | cmd->scan_flags |= SCAN_FLAGS_PASSIVE2ACTIVE; |
305 | ssid = req->ssids[0].ssid; | 317 | if (basic_ssid) { |
306 | ssid_len = req->ssids[0].ssid_len; | 318 | ssid = req->ssids[0].ssid; |
319 | ssid_len = req->ssids[0].ssid_len; | ||
320 | } | ||
307 | } else { | 321 | } else { |
308 | cmd->passive2active = 0; | 322 | cmd->passive2active = 0; |
309 | cmd->scan_flags &= ~SCAN_FLAGS_PASSIVE2ACTIVE; | 323 | cmd->scan_flags &= ~SCAN_FLAGS_PASSIVE2ACTIVE; |
310 | } | 324 | } |
311 | 325 | ||
312 | iwl_mvm_scan_fill_ssids(cmd, req); | 326 | iwl_mvm_scan_fill_ssids(cmd, req, basic_ssid ? 1 : 0); |
313 | 327 | ||
314 | cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL); | 328 | cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL); |
315 | cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id; | 329 | cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id; |
@@ -326,7 +340,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, | |||
326 | req->ie, req->ie_len, | 340 | req->ie, req->ie_len, |
327 | mvm->fw->ucode_capa.max_probe_length)); | 341 | mvm->fw->ucode_capa.max_probe_length)); |
328 | 342 | ||
329 | iwl_mvm_scan_fill_channels(cmd, req); | 343 | iwl_mvm_scan_fill_channels(cmd, req, basic_ssid); |
330 | 344 | ||
331 | cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) + | 345 | cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) + |
332 | le16_to_cpu(cmd->tx_cmd.len) + | 346 | le16_to_cpu(cmd->tx_cmd.len) + |
@@ -377,6 +391,21 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
377 | return 0; | 391 | return 0; |
378 | } | 392 | } |
379 | 393 | ||
394 | int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm, | ||
395 | struct iwl_rx_cmd_buffer *rxb, | ||
396 | struct iwl_device_cmd *cmd) | ||
397 | { | ||
398 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
399 | struct iwl_sched_scan_results *notif = (void *)pkt->data; | ||
400 | |||
401 | if (notif->client_bitmap & SCAN_CLIENT_SCHED_SCAN) { | ||
402 | IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n"); | ||
403 | ieee80211_sched_scan_results(mvm->hw); | ||
404 | } | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
380 | static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait, | 409 | static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait, |
381 | struct iwl_rx_packet *pkt, void *data) | 410 | struct iwl_rx_packet *pkt, void *data) |
382 | { | 411 | { |
@@ -447,3 +476,406 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm) | |||
447 | out_remove_notif: | 476 | out_remove_notif: |
448 | iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort); | 477 | iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort); |
449 | } | 478 | } |
479 | |||
480 | int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, | ||
481 | struct iwl_rx_cmd_buffer *rxb, | ||
482 | struct iwl_device_cmd *cmd) | ||
483 | { | ||
484 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
485 | struct iwl_scan_offload_complete *scan_notif = (void *)pkt->data; | ||
486 | |||
487 | IWL_DEBUG_SCAN(mvm, "Scheduled scan completed, status %s\n", | ||
488 | scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? | ||
489 | "completed" : "aborted"); | ||
490 | |||
491 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
492 | ieee80211_sched_scan_stopped(mvm->hw); | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm, | ||
498 | struct ieee80211_vif *vif, | ||
499 | struct ieee80211_sched_scan_ies *ies, | ||
500 | enum ieee80211_band band, | ||
501 | struct iwl_tx_cmd *cmd, | ||
502 | u8 *data) | ||
503 | { | ||
504 | u16 cmd_len; | ||
505 | |||
506 | cmd->tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL); | ||
507 | cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); | ||
508 | cmd->sta_id = mvm->aux_sta.sta_id; | ||
509 | |||
510 | cmd->rate_n_flags = iwl_mvm_scan_rate_n_flags(mvm, band, false); | ||
511 | |||
512 | cmd_len = iwl_mvm_fill_probe_req((struct ieee80211_mgmt *)data, | ||
513 | vif->addr, | ||
514 | 1, NULL, 0, | ||
515 | ies->ie[band], ies->len[band], | ||
516 | SCAN_OFFLOAD_PROBE_REQ_SIZE); | ||
517 | cmd->len = cpu_to_le16(cmd_len); | ||
518 | } | ||
519 | |||
520 | static void iwl_build_scan_cmd(struct iwl_mvm *mvm, | ||
521 | struct ieee80211_vif *vif, | ||
522 | struct cfg80211_sched_scan_request *req, | ||
523 | struct iwl_scan_offload_cmd *scan) | ||
524 | { | ||
525 | scan->channel_count = | ||
526 | mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels + | ||
527 | mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; | ||
528 | scan->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME); | ||
529 | scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); | ||
530 | scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT; | ||
531 | scan->rx_chain = iwl_mvm_scan_rx_chain(mvm); | ||
532 | scan->max_out_time = cpu_to_le32(200 * 1024); | ||
533 | scan->suspend_time = iwl_mvm_scan_suspend_time(vif); | ||
534 | scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP | | ||
535 | MAC_FILTER_IN_BEACON); | ||
536 | scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND); | ||
537 | scan->rep_count = cpu_to_le32(1); | ||
538 | } | ||
539 | |||
540 | static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list) | ||
541 | { | ||
542 | int i; | ||
543 | |||
544 | for (i = 0; i < PROBE_OPTION_MAX; i++) { | ||
545 | if (!ssid_list[i].len) | ||
546 | break; | ||
547 | if (ssid_list[i].len == ssid_len && | ||
548 | !memcmp(ssid_list->ssid, ssid, ssid_len)) | ||
549 | return i; | ||
550 | } | ||
551 | return -1; | ||
552 | } | ||
553 | |||
554 | static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req, | ||
555 | struct iwl_scan_offload_cmd *scan, | ||
556 | u32 *ssid_bitmap) | ||
557 | { | ||
558 | int i, j; | ||
559 | int index; | ||
560 | |||
561 | /* | ||
562 | * copy SSIDs from match list. | ||
563 | * iwl_config_sched_scan_profiles() uses the order of these ssids to | ||
564 | * config match list. | ||
565 | */ | ||
566 | for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) { | ||
567 | scan->direct_scan[i].id = WLAN_EID_SSID; | ||
568 | scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len; | ||
569 | memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid, | ||
570 | scan->direct_scan[i].len); | ||
571 | } | ||
572 | |||
573 | /* add SSIDs from scan SSID list */ | ||
574 | *ssid_bitmap = 0; | ||
575 | for (j = 0; j < req->n_ssids && i < PROBE_OPTION_MAX; j++) { | ||
576 | index = iwl_ssid_exist(req->ssids[j].ssid, | ||
577 | req->ssids[j].ssid_len, | ||
578 | scan->direct_scan); | ||
579 | if (index < 0) { | ||
580 | if (!req->ssids[j].ssid_len) | ||
581 | continue; | ||
582 | scan->direct_scan[i].id = WLAN_EID_SSID; | ||
583 | scan->direct_scan[i].len = req->ssids[j].ssid_len; | ||
584 | memcpy(scan->direct_scan[i].ssid, req->ssids[j].ssid, | ||
585 | scan->direct_scan[i].len); | ||
586 | *ssid_bitmap |= BIT(i + 1); | ||
587 | i++; | ||
588 | } else { | ||
589 | *ssid_bitmap |= BIT(index + 1); | ||
590 | } | ||
591 | } | ||
592 | } | ||
593 | |||
594 | static void iwl_build_channel_cfg(struct iwl_mvm *mvm, | ||
595 | struct cfg80211_sched_scan_request *req, | ||
596 | struct iwl_scan_channel_cfg *channels, | ||
597 | enum ieee80211_band band, | ||
598 | int *head, int *tail, | ||
599 | u32 ssid_bitmap) | ||
600 | { | ||
601 | struct ieee80211_supported_band *s_band; | ||
602 | int n_probes = req->n_ssids; | ||
603 | int n_channels = req->n_channels; | ||
604 | u8 active_dwell, passive_dwell; | ||
605 | int i, j, index = 0; | ||
606 | bool partial; | ||
607 | |||
608 | /* | ||
609 | * We have to configure all supported channels, even if we don't want to | ||
610 | * scan on them, but we have to send channels in the order that we want | ||
611 | * to scan. So add requested channels to head of the list and others to | ||
612 | * the end. | ||
613 | */ | ||
614 | active_dwell = iwl_mvm_get_active_dwell(band, n_probes); | ||
615 | passive_dwell = iwl_mvm_get_passive_dwell(band); | ||
616 | s_band = &mvm->nvm_data->bands[band]; | ||
617 | |||
618 | for (i = 0; i < s_band->n_channels && *head <= *tail; i++) { | ||
619 | partial = false; | ||
620 | for (j = 0; j < n_channels; j++) | ||
621 | if (s_band->channels[i].center_freq == | ||
622 | req->channels[j]->center_freq) { | ||
623 | index = *head; | ||
624 | (*head)++; | ||
625 | /* | ||
626 | * Channels that came with the request will be | ||
627 | * in partial scan . | ||
628 | */ | ||
629 | partial = true; | ||
630 | break; | ||
631 | } | ||
632 | if (!partial) { | ||
633 | index = *tail; | ||
634 | (*tail)--; | ||
635 | } | ||
636 | channels->channel_number[index] = | ||
637 | cpu_to_le16(ieee80211_frequency_to_channel( | ||
638 | s_band->channels[i].center_freq)); | ||
639 | channels->dwell_time[index][0] = active_dwell; | ||
640 | channels->dwell_time[index][1] = passive_dwell; | ||
641 | |||
642 | channels->iter_count[index] = cpu_to_le16(1); | ||
643 | channels->iter_interval[index] = 0; | ||
644 | |||
645 | if (!(s_band->channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) | ||
646 | channels->type[index] |= | ||
647 | cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE); | ||
648 | |||
649 | channels->type[index] |= | ||
650 | cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_FULL); | ||
651 | if (partial) | ||
652 | channels->type[index] |= | ||
653 | cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL); | ||
654 | |||
655 | if (s_band->channels[i].flags & IEEE80211_CHAN_NO_HT40) | ||
656 | channels->type[index] |= | ||
657 | cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_NARROW); | ||
658 | |||
659 | /* scan for all SSIDs from req->ssids */ | ||
660 | channels->type[index] |= cpu_to_le32(ssid_bitmap); | ||
661 | } | ||
662 | } | ||
663 | |||
664 | int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, | ||
665 | struct ieee80211_vif *vif, | ||
666 | struct cfg80211_sched_scan_request *req, | ||
667 | struct ieee80211_sched_scan_ies *ies) | ||
668 | { | ||
669 | int supported_bands = 0; | ||
670 | int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels; | ||
671 | int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; | ||
672 | int head = 0; | ||
673 | int tail = band_2ghz + band_5ghz; | ||
674 | u32 ssid_bitmap; | ||
675 | int cmd_len; | ||
676 | int ret; | ||
677 | |||
678 | struct iwl_scan_offload_cfg *scan_cfg; | ||
679 | struct iwl_host_cmd cmd = { | ||
680 | .id = SCAN_OFFLOAD_CONFIG_CMD, | ||
681 | .flags = CMD_SYNC, | ||
682 | }; | ||
683 | |||
684 | lockdep_assert_held(&mvm->mutex); | ||
685 | |||
686 | if (band_2ghz) | ||
687 | supported_bands++; | ||
688 | if (band_5ghz) | ||
689 | supported_bands++; | ||
690 | |||
691 | cmd_len = sizeof(struct iwl_scan_offload_cfg) + | ||
692 | supported_bands * SCAN_OFFLOAD_PROBE_REQ_SIZE; | ||
693 | |||
694 | scan_cfg = kzalloc(cmd_len, GFP_KERNEL); | ||
695 | if (!scan_cfg) | ||
696 | return -ENOMEM; | ||
697 | |||
698 | iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd); | ||
699 | scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len); | ||
700 | |||
701 | iwl_scan_offload_build_ssid(req, &scan_cfg->scan_cmd, &ssid_bitmap); | ||
702 | /* build tx frames for supported bands */ | ||
703 | if (band_2ghz) { | ||
704 | iwl_scan_offload_build_tx_cmd(mvm, vif, ies, | ||
705 | IEEE80211_BAND_2GHZ, | ||
706 | &scan_cfg->scan_cmd.tx_cmd[0], | ||
707 | scan_cfg->data); | ||
708 | iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg, | ||
709 | IEEE80211_BAND_2GHZ, &head, &tail, | ||
710 | ssid_bitmap); | ||
711 | } | ||
712 | if (band_5ghz) { | ||
713 | iwl_scan_offload_build_tx_cmd(mvm, vif, ies, | ||
714 | IEEE80211_BAND_5GHZ, | ||
715 | &scan_cfg->scan_cmd.tx_cmd[1], | ||
716 | scan_cfg->data + | ||
717 | SCAN_OFFLOAD_PROBE_REQ_SIZE); | ||
718 | iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg, | ||
719 | IEEE80211_BAND_5GHZ, &head, &tail, | ||
720 | ssid_bitmap); | ||
721 | } | ||
722 | |||
723 | cmd.data[0] = scan_cfg; | ||
724 | cmd.len[0] = cmd_len; | ||
725 | cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; | ||
726 | |||
727 | IWL_DEBUG_SCAN(mvm, "Sending scheduled scan config\n"); | ||
728 | |||
729 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
730 | kfree(scan_cfg); | ||
731 | return ret; | ||
732 | } | ||
733 | |||
734 | int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, | ||
735 | struct cfg80211_sched_scan_request *req) | ||
736 | { | ||
737 | struct iwl_scan_offload_profile *profile; | ||
738 | struct iwl_scan_offload_profile_cfg *profile_cfg; | ||
739 | struct iwl_scan_offload_blacklist *blacklist; | ||
740 | struct iwl_host_cmd cmd = { | ||
741 | .id = SCAN_OFFLOAD_UPDATE_PROFILES_CMD, | ||
742 | .flags = CMD_SYNC, | ||
743 | .len[1] = sizeof(*profile_cfg), | ||
744 | .dataflags[0] = IWL_HCMD_DFL_NOCOPY, | ||
745 | .dataflags[1] = IWL_HCMD_DFL_NOCOPY, | ||
746 | }; | ||
747 | int blacklist_len; | ||
748 | int i; | ||
749 | int ret; | ||
750 | |||
751 | if (WARN_ON(req->n_match_sets > IWL_SCAN_MAX_PROFILES)) | ||
752 | return -EIO; | ||
753 | |||
754 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SHORT_BL) | ||
755 | blacklist_len = IWL_SCAN_SHORT_BLACKLIST_LEN; | ||
756 | else | ||
757 | blacklist_len = IWL_SCAN_MAX_BLACKLIST_LEN; | ||
758 | |||
759 | blacklist = kzalloc(sizeof(*blacklist) * blacklist_len, GFP_KERNEL); | ||
760 | if (!blacklist) | ||
761 | return -ENOMEM; | ||
762 | |||
763 | profile_cfg = kzalloc(sizeof(*profile_cfg), GFP_KERNEL); | ||
764 | if (!profile_cfg) { | ||
765 | ret = -ENOMEM; | ||
766 | goto free_blacklist; | ||
767 | } | ||
768 | |||
769 | cmd.data[0] = blacklist; | ||
770 | cmd.len[0] = sizeof(*blacklist) * blacklist_len; | ||
771 | cmd.data[1] = profile_cfg; | ||
772 | |||
773 | /* No blacklist configuration */ | ||
774 | |||
775 | profile_cfg->num_profiles = req->n_match_sets; | ||
776 | profile_cfg->active_clients = SCAN_CLIENT_SCHED_SCAN; | ||
777 | profile_cfg->pass_match = SCAN_CLIENT_SCHED_SCAN; | ||
778 | profile_cfg->match_notify = SCAN_CLIENT_SCHED_SCAN; | ||
779 | |||
780 | for (i = 0; i < req->n_match_sets; i++) { | ||
781 | profile = &profile_cfg->profiles[i]; | ||
782 | profile->ssid_index = i; | ||
783 | /* Support any cipher and auth algorithm */ | ||
784 | profile->unicast_cipher = 0xff; | ||
785 | profile->auth_alg = 0xff; | ||
786 | profile->network_type = IWL_NETWORK_TYPE_ANY; | ||
787 | profile->band_selection = IWL_SCAN_OFFLOAD_SELECT_ANY; | ||
788 | profile->client_bitmap = SCAN_CLIENT_SCHED_SCAN; | ||
789 | } | ||
790 | |||
791 | IWL_DEBUG_SCAN(mvm, "Sending scheduled scan profile config\n"); | ||
792 | |||
793 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
794 | kfree(profile_cfg); | ||
795 | free_blacklist: | ||
796 | kfree(blacklist); | ||
797 | |||
798 | return ret; | ||
799 | } | ||
800 | |||
801 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | ||
802 | struct cfg80211_sched_scan_request *req) | ||
803 | { | ||
804 | struct iwl_scan_offload_req scan_req = { | ||
805 | .watchdog = IWL_SCHED_SCAN_WATCHDOG, | ||
806 | |||
807 | .schedule_line[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS, | ||
808 | .schedule_line[0].delay = req->interval / 1000, | ||
809 | .schedule_line[0].full_scan_mul = 1, | ||
810 | |||
811 | .schedule_line[1].iterations = 0xff, | ||
812 | .schedule_line[1].delay = req->interval / 1000, | ||
813 | .schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER, | ||
814 | }; | ||
815 | |||
816 | if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { | ||
817 | IWL_DEBUG_SCAN(mvm, | ||
818 | "Sending scheduled scan with filtering, filter len %d\n", | ||
819 | req->n_match_sets); | ||
820 | scan_req.flags |= | ||
821 | cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID); | ||
822 | } else { | ||
823 | IWL_DEBUG_SCAN(mvm, | ||
824 | "Sending Scheduled scan without filtering\n"); | ||
825 | } | ||
826 | |||
827 | return iwl_mvm_send_cmd_pdu(mvm, SCAN_OFFLOAD_REQUEST_CMD, CMD_SYNC, | ||
828 | sizeof(scan_req), &scan_req); | ||
829 | } | ||
830 | |||
831 | static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm) | ||
832 | { | ||
833 | int ret; | ||
834 | struct iwl_host_cmd cmd = { | ||
835 | .id = SCAN_OFFLOAD_ABORT_CMD, | ||
836 | .flags = CMD_SYNC, | ||
837 | }; | ||
838 | u32 status; | ||
839 | |||
840 | /* Exit instantly with error when device is not ready | ||
841 | * to receive scan abort command or it does not perform | ||
842 | * scheduled scan currently */ | ||
843 | if (mvm->scan_status != IWL_MVM_SCAN_SCHED) | ||
844 | return -EIO; | ||
845 | |||
846 | ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status); | ||
847 | if (ret) | ||
848 | return ret; | ||
849 | |||
850 | if (status != CAN_ABORT_STATUS) { | ||
851 | /* | ||
852 | * The scan abort will return 1 for success or | ||
853 | * 2 for "failure". A failure condition can be | ||
854 | * due to simply not being in an active scan which | ||
855 | * can occur if we send the scan abort before the | ||
856 | * microcode has notified us that a scan is completed. | ||
857 | */ | ||
858 | IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status); | ||
859 | ret = -EIO; | ||
860 | } | ||
861 | |||
862 | return ret; | ||
863 | } | ||
864 | |||
865 | void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm) | ||
866 | { | ||
867 | int ret; | ||
868 | |||
869 | lockdep_assert_held(&mvm->mutex); | ||
870 | |||
871 | if (mvm->scan_status != IWL_MVM_SCAN_SCHED) { | ||
872 | IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n"); | ||
873 | return; | ||
874 | } | ||
875 | |||
876 | ret = iwl_mvm_send_sched_scan_abort(mvm); | ||
877 | if (ret) | ||
878 | IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret); | ||
879 | else | ||
880 | IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n"); | ||
881 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 44add291531b..329952363a54 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -66,6 +66,115 @@ | |||
66 | #include "sta.h" | 66 | #include "sta.h" |
67 | #include "rs.h" | 67 | #include "rs.h" |
68 | 68 | ||
69 | static void iwl_mvm_add_sta_cmd_v6_to_v5(struct iwl_mvm_add_sta_cmd_v6 *cmd_v6, | ||
70 | struct iwl_mvm_add_sta_cmd_v5 *cmd_v5) | ||
71 | { | ||
72 | memset(cmd_v5, 0, sizeof(*cmd_v5)); | ||
73 | |||
74 | cmd_v5->add_modify = cmd_v6->add_modify; | ||
75 | cmd_v5->tid_disable_tx = cmd_v6->tid_disable_tx; | ||
76 | cmd_v5->mac_id_n_color = cmd_v6->mac_id_n_color; | ||
77 | memcpy(cmd_v5->addr, cmd_v6->addr, ETH_ALEN); | ||
78 | cmd_v5->sta_id = cmd_v6->sta_id; | ||
79 | cmd_v5->modify_mask = cmd_v6->modify_mask; | ||
80 | cmd_v5->station_flags = cmd_v6->station_flags; | ||
81 | cmd_v5->station_flags_msk = cmd_v6->station_flags_msk; | ||
82 | cmd_v5->add_immediate_ba_tid = cmd_v6->add_immediate_ba_tid; | ||
83 | cmd_v5->remove_immediate_ba_tid = cmd_v6->remove_immediate_ba_tid; | ||
84 | cmd_v5->add_immediate_ba_ssn = cmd_v6->add_immediate_ba_ssn; | ||
85 | cmd_v5->sleep_tx_count = cmd_v6->sleep_tx_count; | ||
86 | cmd_v5->sleep_state_flags = cmd_v6->sleep_state_flags; | ||
87 | cmd_v5->assoc_id = cmd_v6->assoc_id; | ||
88 | cmd_v5->beamform_flags = cmd_v6->beamform_flags; | ||
89 | cmd_v5->tfd_queue_msk = cmd_v6->tfd_queue_msk; | ||
90 | } | ||
91 | |||
92 | static void | ||
93 | iwl_mvm_add_sta_key_to_add_sta_cmd_v5(struct iwl_mvm_add_sta_key_cmd *key_cmd, | ||
94 | struct iwl_mvm_add_sta_cmd_v5 *sta_cmd, | ||
95 | u32 mac_id_n_color) | ||
96 | { | ||
97 | memset(sta_cmd, 0, sizeof(*sta_cmd)); | ||
98 | |||
99 | sta_cmd->sta_id = key_cmd->sta_id; | ||
100 | sta_cmd->add_modify = STA_MODE_MODIFY; | ||
101 | sta_cmd->modify_mask = STA_MODIFY_KEY; | ||
102 | sta_cmd->mac_id_n_color = cpu_to_le32(mac_id_n_color); | ||
103 | |||
104 | sta_cmd->key.key_offset = key_cmd->key_offset; | ||
105 | sta_cmd->key.key_flags = key_cmd->key_flags; | ||
106 | memcpy(sta_cmd->key.key, key_cmd->key, sizeof(sta_cmd->key.key)); | ||
107 | sta_cmd->key.tkip_rx_tsc_byte2 = key_cmd->tkip_rx_tsc_byte2; | ||
108 | memcpy(sta_cmd->key.tkip_rx_ttak, key_cmd->tkip_rx_ttak, | ||
109 | sizeof(sta_cmd->key.tkip_rx_ttak)); | ||
110 | } | ||
111 | |||
112 | static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm, | ||
113 | struct iwl_mvm_add_sta_cmd_v6 *cmd, | ||
114 | int *status) | ||
115 | { | ||
116 | struct iwl_mvm_add_sta_cmd_v5 cmd_v5; | ||
117 | |||
118 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD) | ||
119 | return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(*cmd), | ||
120 | cmd, status); | ||
121 | |||
122 | iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5); | ||
123 | |||
124 | return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd_v5), | ||
125 | &cmd_v5, status); | ||
126 | } | ||
127 | |||
128 | static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags, | ||
129 | struct iwl_mvm_add_sta_cmd_v6 *cmd) | ||
130 | { | ||
131 | struct iwl_mvm_add_sta_cmd_v5 cmd_v5; | ||
132 | |||
133 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD) | ||
134 | return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, | ||
135 | sizeof(*cmd), cmd); | ||
136 | |||
137 | iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5); | ||
138 | |||
139 | return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(cmd_v5), | ||
140 | &cmd_v5); | ||
141 | } | ||
142 | |||
143 | static int | ||
144 | iwl_mvm_send_add_sta_key_cmd_status(struct iwl_mvm *mvm, | ||
145 | struct iwl_mvm_add_sta_key_cmd *cmd, | ||
146 | u32 mac_id_n_color, | ||
147 | int *status) | ||
148 | { | ||
149 | struct iwl_mvm_add_sta_cmd_v5 sta_cmd; | ||
150 | |||
151 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD) | ||
152 | return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, | ||
153 | sizeof(*cmd), cmd, status); | ||
154 | |||
155 | iwl_mvm_add_sta_key_to_add_sta_cmd_v5(cmd, &sta_cmd, mac_id_n_color); | ||
156 | |||
157 | return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(sta_cmd), | ||
158 | &sta_cmd, status); | ||
159 | } | ||
160 | |||
161 | static int iwl_mvm_send_add_sta_key_cmd(struct iwl_mvm *mvm, | ||
162 | u32 flags, | ||
163 | struct iwl_mvm_add_sta_key_cmd *cmd, | ||
164 | u32 mac_id_n_color) | ||
165 | { | ||
166 | struct iwl_mvm_add_sta_cmd_v5 sta_cmd; | ||
167 | |||
168 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD) | ||
169 | return iwl_mvm_send_cmd_pdu(mvm, ADD_STA_KEY, flags, | ||
170 | sizeof(*cmd), cmd); | ||
171 | |||
172 | iwl_mvm_add_sta_key_to_add_sta_cmd_v5(cmd, &sta_cmd, mac_id_n_color); | ||
173 | |||
174 | return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(sta_cmd), | ||
175 | &sta_cmd); | ||
176 | } | ||
177 | |||
69 | static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm) | 178 | static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm) |
70 | { | 179 | { |
71 | int sta_id; | 180 | int sta_id; |
@@ -87,7 +196,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
87 | bool update) | 196 | bool update) |
88 | { | 197 | { |
89 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 198 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
90 | struct iwl_mvm_add_sta_cmd add_sta_cmd; | 199 | struct iwl_mvm_add_sta_cmd_v6 add_sta_cmd; |
91 | int ret; | 200 | int ret; |
92 | u32 status; | 201 | u32 status; |
93 | u32 agg_size = 0, mpdu_dens = 0; | 202 | u32 agg_size = 0, mpdu_dens = 0; |
@@ -175,8 +284,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
175 | cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT); | 284 | cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT); |
176 | 285 | ||
177 | status = ADD_STA_SUCCESS; | 286 | status = ADD_STA_SUCCESS; |
178 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(add_sta_cmd), | 287 | ret = iwl_mvm_send_add_sta_cmd_status(mvm, &add_sta_cmd, &status); |
179 | &add_sta_cmd, &status); | ||
180 | if (ret) | 288 | if (ret) |
181 | return ret; | 289 | return ret; |
182 | 290 | ||
@@ -229,8 +337,12 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
229 | if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) | 337 | if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) |
230 | mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]); | 338 | mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]); |
231 | 339 | ||
232 | /* for HW restart - need to reset the seq_number etc... */ | 340 | /* for HW restart - reset everything but the sequence number */ |
233 | memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data)); | 341 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { |
342 | u16 seq = mvm_sta->tid_data[i].seq_number; | ||
343 | memset(&mvm_sta->tid_data[i], 0, sizeof(mvm_sta->tid_data[i])); | ||
344 | mvm_sta->tid_data[i].seq_number = seq; | ||
345 | } | ||
234 | 346 | ||
235 | ret = iwl_mvm_sta_send_to_fw(mvm, sta, false); | 347 | ret = iwl_mvm_sta_send_to_fw(mvm, sta, false); |
236 | if (ret) | 348 | if (ret) |
@@ -256,7 +368,7 @@ int iwl_mvm_update_sta(struct iwl_mvm *mvm, | |||
256 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | 368 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, |
257 | bool drain) | 369 | bool drain) |
258 | { | 370 | { |
259 | struct iwl_mvm_add_sta_cmd cmd = {}; | 371 | struct iwl_mvm_add_sta_cmd_v6 cmd = {}; |
260 | int ret; | 372 | int ret; |
261 | u32 status; | 373 | u32 status; |
262 | 374 | ||
@@ -269,8 +381,7 @@ int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | |||
269 | cmd.station_flags_msk = cpu_to_le32(STA_FLG_DRAIN_FLOW); | 381 | cmd.station_flags_msk = cpu_to_le32(STA_FLG_DRAIN_FLOW); |
270 | 382 | ||
271 | status = ADD_STA_SUCCESS; | 383 | status = ADD_STA_SUCCESS; |
272 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), | 384 | ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status); |
273 | &cmd, &status); | ||
274 | if (ret) | 385 | if (ret) |
275 | return ret; | 386 | return ret; |
276 | 387 | ||
@@ -469,13 +580,13 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, | |||
469 | const u8 *addr, | 580 | const u8 *addr, |
470 | u16 mac_id, u16 color) | 581 | u16 mac_id, u16 color) |
471 | { | 582 | { |
472 | struct iwl_mvm_add_sta_cmd cmd; | 583 | struct iwl_mvm_add_sta_cmd_v6 cmd; |
473 | int ret; | 584 | int ret; |
474 | u32 status; | 585 | u32 status; |
475 | 586 | ||
476 | lockdep_assert_held(&mvm->mutex); | 587 | lockdep_assert_held(&mvm->mutex); |
477 | 588 | ||
478 | memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd)); | 589 | memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v6)); |
479 | cmd.sta_id = sta->sta_id; | 590 | cmd.sta_id = sta->sta_id; |
480 | cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, | 591 | cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, |
481 | color)); | 592 | color)); |
@@ -485,8 +596,7 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, | |||
485 | if (addr) | 596 | if (addr) |
486 | memcpy(cmd.addr, addr, ETH_ALEN); | 597 | memcpy(cmd.addr, addr, ETH_ALEN); |
487 | 598 | ||
488 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), | 599 | ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status); |
489 | &cmd, &status); | ||
490 | if (ret) | 600 | if (ret) |
491 | return ret; | 601 | return ret; |
492 | 602 | ||
@@ -534,10 +644,14 @@ int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
534 | struct iwl_mvm_int_sta *bsta) | 644 | struct iwl_mvm_int_sta *bsta) |
535 | { | 645 | { |
536 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 646 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
537 | static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | 647 | static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; |
648 | static const u8 *baddr = _baddr; | ||
538 | 649 | ||
539 | lockdep_assert_held(&mvm->mutex); | 650 | lockdep_assert_held(&mvm->mutex); |
540 | 651 | ||
652 | if (vif->type == NL80211_IFTYPE_ADHOC) | ||
653 | baddr = vif->bss_conf.bssid; | ||
654 | |||
541 | if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_STATION_COUNT)) | 655 | if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_STATION_COUNT)) |
542 | return -ENOSPC; | 656 | return -ENOSPC; |
543 | 657 | ||
@@ -614,7 +728,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
614 | int tid, u16 ssn, bool start) | 728 | int tid, u16 ssn, bool start) |
615 | { | 729 | { |
616 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 730 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
617 | struct iwl_mvm_add_sta_cmd cmd = {}; | 731 | struct iwl_mvm_add_sta_cmd_v6 cmd = {}; |
618 | int ret; | 732 | int ret; |
619 | u32 status; | 733 | u32 status; |
620 | 734 | ||
@@ -638,8 +752,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
638 | STA_MODIFY_REMOVE_BA_TID; | 752 | STA_MODIFY_REMOVE_BA_TID; |
639 | 753 | ||
640 | status = ADD_STA_SUCCESS; | 754 | status = ADD_STA_SUCCESS; |
641 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), | 755 | ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status); |
642 | &cmd, &status); | ||
643 | if (ret) | 756 | if (ret) |
644 | return ret; | 757 | return ret; |
645 | 758 | ||
@@ -674,7 +787,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
674 | int tid, u8 queue, bool start) | 787 | int tid, u8 queue, bool start) |
675 | { | 788 | { |
676 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 789 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
677 | struct iwl_mvm_add_sta_cmd cmd = {}; | 790 | struct iwl_mvm_add_sta_cmd_v6 cmd = {}; |
678 | int ret; | 791 | int ret; |
679 | u32 status; | 792 | u32 status; |
680 | 793 | ||
@@ -696,8 +809,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
696 | cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg); | 809 | cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg); |
697 | 810 | ||
698 | status = ADD_STA_SUCCESS; | 811 | status = ADD_STA_SUCCESS; |
699 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), | 812 | ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status); |
700 | &cmd, &status); | ||
701 | if (ret) | 813 | if (ret) |
702 | return ret; | 814 | return ret; |
703 | 815 | ||
@@ -743,13 +855,13 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
743 | 855 | ||
744 | lockdep_assert_held(&mvm->mutex); | 856 | lockdep_assert_held(&mvm->mutex); |
745 | 857 | ||
746 | for (txq_id = IWL_MVM_FIRST_AGG_QUEUE; | 858 | for (txq_id = mvm->first_agg_queue; |
747 | txq_id <= IWL_MVM_LAST_AGG_QUEUE; txq_id++) | 859 | txq_id <= mvm->last_agg_queue; txq_id++) |
748 | if (mvm->queue_to_mac80211[txq_id] == | 860 | if (mvm->queue_to_mac80211[txq_id] == |
749 | IWL_INVALID_MAC80211_QUEUE) | 861 | IWL_INVALID_MAC80211_QUEUE) |
750 | break; | 862 | break; |
751 | 863 | ||
752 | if (txq_id > IWL_MVM_LAST_AGG_QUEUE) { | 864 | if (txq_id > mvm->last_agg_queue) { |
753 | IWL_ERR(mvm, "Failed to allocate agg queue\n"); | 865 | IWL_ERR(mvm, "Failed to allocate agg queue\n"); |
754 | return -EIO; | 866 | return -EIO; |
755 | } | 867 | } |
@@ -987,10 +1099,11 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, | |||
987 | u32 cmd_flags) | 1099 | u32 cmd_flags) |
988 | { | 1100 | { |
989 | __le16 key_flags; | 1101 | __le16 key_flags; |
990 | struct iwl_mvm_add_sta_cmd cmd = {}; | 1102 | struct iwl_mvm_add_sta_key_cmd cmd = {}; |
991 | int ret, status; | 1103 | int ret, status; |
992 | u16 keyidx; | 1104 | u16 keyidx; |
993 | int i; | 1105 | int i; |
1106 | u32 mac_id_n_color = mvm_sta->mac_id_n_color; | ||
994 | 1107 | ||
995 | keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & | 1108 | keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & |
996 | STA_KEY_FLG_KEYID_MSK; | 1109 | STA_KEY_FLG_KEYID_MSK; |
@@ -1000,14 +1113,14 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, | |||
1000 | switch (keyconf->cipher) { | 1113 | switch (keyconf->cipher) { |
1001 | case WLAN_CIPHER_SUITE_TKIP: | 1114 | case WLAN_CIPHER_SUITE_TKIP: |
1002 | key_flags |= cpu_to_le16(STA_KEY_FLG_TKIP); | 1115 | key_flags |= cpu_to_le16(STA_KEY_FLG_TKIP); |
1003 | cmd.key.tkip_rx_tsc_byte2 = tkip_iv32; | 1116 | cmd.tkip_rx_tsc_byte2 = tkip_iv32; |
1004 | for (i = 0; i < 5; i++) | 1117 | for (i = 0; i < 5; i++) |
1005 | cmd.key.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]); | 1118 | cmd.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]); |
1006 | memcpy(cmd.key.key, keyconf->key, keyconf->keylen); | 1119 | memcpy(cmd.key, keyconf->key, keyconf->keylen); |
1007 | break; | 1120 | break; |
1008 | case WLAN_CIPHER_SUITE_CCMP: | 1121 | case WLAN_CIPHER_SUITE_CCMP: |
1009 | key_flags |= cpu_to_le16(STA_KEY_FLG_CCM); | 1122 | key_flags |= cpu_to_le16(STA_KEY_FLG_CCM); |
1010 | memcpy(cmd.key.key, keyconf->key, keyconf->keylen); | 1123 | memcpy(cmd.key, keyconf->key, keyconf->keylen); |
1011 | break; | 1124 | break; |
1012 | default: | 1125 | default: |
1013 | WARN_ON(1); | 1126 | WARN_ON(1); |
@@ -1017,20 +1130,18 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, | |||
1017 | if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | 1130 | if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) |
1018 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); | 1131 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); |
1019 | 1132 | ||
1020 | cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); | 1133 | cmd.key_offset = keyconf->hw_key_idx; |
1021 | cmd.key.key_offset = keyconf->hw_key_idx; | 1134 | cmd.key_flags = key_flags; |
1022 | cmd.key.key_flags = key_flags; | ||
1023 | cmd.add_modify = STA_MODE_MODIFY; | ||
1024 | cmd.modify_mask = STA_MODIFY_KEY; | ||
1025 | cmd.sta_id = sta_id; | 1135 | cmd.sta_id = sta_id; |
1026 | 1136 | ||
1027 | status = ADD_STA_SUCCESS; | 1137 | status = ADD_STA_SUCCESS; |
1028 | if (cmd_flags == CMD_SYNC) | 1138 | if (cmd_flags == CMD_SYNC) |
1029 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), | 1139 | ret = iwl_mvm_send_add_sta_key_cmd_status(mvm, &cmd, |
1030 | &cmd, &status); | 1140 | mac_id_n_color, |
1141 | &status); | ||
1031 | else | 1142 | else |
1032 | ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, | 1143 | ret = iwl_mvm_send_add_sta_key_cmd(mvm, CMD_ASYNC, &cmd, |
1033 | sizeof(cmd), &cmd); | 1144 | mac_id_n_color); |
1034 | 1145 | ||
1035 | switch (status) { | 1146 | switch (status) { |
1036 | case ADD_STA_SUCCESS: | 1147 | case ADD_STA_SUCCESS: |
@@ -1197,7 +1308,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | |||
1197 | struct ieee80211_key_conf *keyconf) | 1308 | struct ieee80211_key_conf *keyconf) |
1198 | { | 1309 | { |
1199 | struct iwl_mvm_sta *mvm_sta; | 1310 | struct iwl_mvm_sta *mvm_sta; |
1200 | struct iwl_mvm_add_sta_cmd cmd = {}; | 1311 | struct iwl_mvm_add_sta_key_cmd cmd = {}; |
1201 | __le16 key_flags; | 1312 | __le16 key_flags; |
1202 | int ret, status; | 1313 | int ret, status; |
1203 | u8 sta_id; | 1314 | u8 sta_id; |
@@ -1252,17 +1363,14 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | |||
1252 | if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | 1363 | if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) |
1253 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); | 1364 | key_flags |= cpu_to_le16(STA_KEY_MULTICAST); |
1254 | 1365 | ||
1255 | cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); | 1366 | cmd.key_flags = key_flags; |
1256 | cmd.key.key_flags = key_flags; | 1367 | cmd.key_offset = keyconf->hw_key_idx; |
1257 | cmd.key.key_offset = keyconf->hw_key_idx; | ||
1258 | cmd.sta_id = sta_id; | 1368 | cmd.sta_id = sta_id; |
1259 | 1369 | ||
1260 | cmd.modify_mask = STA_MODIFY_KEY; | ||
1261 | cmd.add_modify = STA_MODE_MODIFY; | ||
1262 | |||
1263 | status = ADD_STA_SUCCESS; | 1370 | status = ADD_STA_SUCCESS; |
1264 | ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd), | 1371 | ret = iwl_mvm_send_add_sta_key_cmd_status(mvm, &cmd, |
1265 | &cmd, &status); | 1372 | mvm_sta->mac_id_n_color, |
1373 | &status); | ||
1266 | 1374 | ||
1267 | switch (status) { | 1375 | switch (status) { |
1268 | case ADD_STA_SUCCESS: | 1376 | case ADD_STA_SUCCESS: |
@@ -1309,7 +1417,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, | |||
1309 | struct ieee80211_sta *sta) | 1417 | struct ieee80211_sta *sta) |
1310 | { | 1418 | { |
1311 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | 1419 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; |
1312 | struct iwl_mvm_add_sta_cmd cmd = { | 1420 | struct iwl_mvm_add_sta_cmd_v6 cmd = { |
1313 | .add_modify = STA_MODE_MODIFY, | 1421 | .add_modify = STA_MODE_MODIFY, |
1314 | .sta_id = mvmsta->sta_id, | 1422 | .sta_id = mvmsta->sta_id, |
1315 | .station_flags_msk = cpu_to_le32(STA_FLG_PS), | 1423 | .station_flags_msk = cpu_to_le32(STA_FLG_PS), |
@@ -1317,7 +1425,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, | |||
1317 | }; | 1425 | }; |
1318 | int ret; | 1426 | int ret; |
1319 | 1427 | ||
1320 | ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); | 1428 | ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd); |
1321 | if (ret) | 1429 | if (ret) |
1322 | IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); | 1430 | IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); |
1323 | } | 1431 | } |
@@ -1331,7 +1439,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, | |||
1331 | (reason == IEEE80211_FRAME_RELEASE_UAPSD) ? | 1439 | (reason == IEEE80211_FRAME_RELEASE_UAPSD) ? |
1332 | STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL; | 1440 | STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL; |
1333 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | 1441 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; |
1334 | struct iwl_mvm_add_sta_cmd cmd = { | 1442 | struct iwl_mvm_add_sta_cmd_v6 cmd = { |
1335 | .add_modify = STA_MODE_MODIFY, | 1443 | .add_modify = STA_MODE_MODIFY, |
1336 | .sta_id = mvmsta->sta_id, | 1444 | .sta_id = mvmsta->sta_id, |
1337 | .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT, | 1445 | .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT, |
@@ -1346,7 +1454,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, | |||
1346 | int ret; | 1454 | int ret; |
1347 | 1455 | ||
1348 | /* TODO: somehow the fw doesn't seem to take PS_POLL into account */ | 1456 | /* TODO: somehow the fw doesn't seem to take PS_POLL into account */ |
1349 | ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); | 1457 | ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd); |
1350 | if (ret) | 1458 | if (ret) |
1351 | IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); | 1459 | IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); |
1352 | } | 1460 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 94b265eb32b8..4dfc359a4bdd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h | |||
@@ -293,10 +293,6 @@ struct iwl_mvm_sta { | |||
293 | struct iwl_lq_sta lq_sta; | 293 | struct iwl_lq_sta lq_sta; |
294 | struct ieee80211_vif *vif; | 294 | struct ieee80211_vif *vif; |
295 | 295 | ||
296 | #ifdef CONFIG_PM_SLEEP | ||
297 | u16 last_seq_ctl; | ||
298 | #endif | ||
299 | |||
300 | /* Temporary, until the new TLC will control the Tx protection */ | 296 | /* Temporary, until the new TLC will control the Tx protection */ |
301 | s8 tx_protection; | 297 | s8 tx_protection; |
302 | bool tt_tx_protection; | 298 | bool tt_tx_protection; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/testmode.h b/drivers/net/wireless/iwlwifi/mvm/testmode.h new file mode 100644 index 000000000000..eb74391d91ca --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/testmode.h | |||
@@ -0,0 +1,95 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called COPYING. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #ifndef __IWL_MVM_TESTMODE_H__ | ||
65 | #define __IWL_MVM_TESTMODE_H__ | ||
66 | |||
67 | /** | ||
68 | * enum iwl_mvm_testmode_attrs - testmode attributes inside NL80211_ATTR_TESTDATA | ||
69 | * @IWL_MVM_TM_ATTR_UNSPEC: (invalid attribute) | ||
70 | * @IWL_MVM_TM_ATTR_CMD: sub command, see &enum iwl_mvm_testmode_commands (u32) | ||
71 | * @IWL_MVM_TM_ATTR_NOA_DURATION: requested NoA duration (u32) | ||
72 | * @IWL_MVM_TM_ATTR_BEACON_FILTER_STATE: beacon filter state (0 or 1, u32) | ||
73 | */ | ||
74 | enum iwl_mvm_testmode_attrs { | ||
75 | IWL_MVM_TM_ATTR_UNSPEC, | ||
76 | IWL_MVM_TM_ATTR_CMD, | ||
77 | IWL_MVM_TM_ATTR_NOA_DURATION, | ||
78 | IWL_MVM_TM_ATTR_BEACON_FILTER_STATE, | ||
79 | |||
80 | /* keep last */ | ||
81 | NUM_IWL_MVM_TM_ATTRS, | ||
82 | IWL_MVM_TM_ATTR_MAX = NUM_IWL_MVM_TM_ATTRS - 1, | ||
83 | }; | ||
84 | |||
85 | /** | ||
86 | * enum iwl_mvm_testmode_commands - MVM testmode commands | ||
87 | * @IWL_MVM_TM_CMD_SET_NOA: set NoA on GO vif for testing | ||
88 | * @IWL_MVM_TM_CMD_SET_BEACON_FILTER: turn beacon filtering off/on | ||
89 | */ | ||
90 | enum iwl_mvm_testmode_commands { | ||
91 | IWL_MVM_TM_CMD_SET_NOA, | ||
92 | IWL_MVM_TM_CMD_SET_BEACON_FILTER, | ||
93 | }; | ||
94 | |||
95 | #endif /* __IWL_MVM_TESTMODE_H__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 76a3c177e100..33cf56fdfc41 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
@@ -387,7 +387,8 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, | |||
387 | 387 | ||
388 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, | 388 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, |
389 | struct ieee80211_vif *vif, | 389 | struct ieee80211_vif *vif, |
390 | u32 duration, u32 min_duration) | 390 | u32 duration, u32 min_duration, |
391 | u32 max_delay) | ||
391 | { | 392 | { |
392 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 393 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
393 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 394 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; |
@@ -426,7 +427,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
426 | cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); | 427 | cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); |
427 | 428 | ||
428 | time_cmd.max_frags = TE_V2_FRAG_NONE; | 429 | time_cmd.max_frags = TE_V2_FRAG_NONE; |
429 | time_cmd.max_delay = cpu_to_le32(500); | 430 | time_cmd.max_delay = cpu_to_le32(max_delay); |
430 | /* TODO: why do we need to interval = bi if it is not periodic? */ | 431 | /* TODO: why do we need to interval = bi if it is not periodic? */ |
431 | time_cmd.interval = cpu_to_le32(1); | 432 | time_cmd.interval = cpu_to_le32(1); |
432 | time_cmd.duration = cpu_to_le32(duration); | 433 | time_cmd.duration = cpu_to_le32(duration); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index f86c51065ed3..d9c8d6cfa2db 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h | |||
@@ -123,6 +123,7 @@ | |||
123 | * @duration: the duration of the session in TU. | 123 | * @duration: the duration of the session in TU. |
124 | * @min_duration: will start a new session if the current session will end | 124 | * @min_duration: will start a new session if the current session will end |
125 | * in less than min_duration. | 125 | * in less than min_duration. |
126 | * @max_delay: maximum delay before starting the time event (in TU) | ||
126 | * | 127 | * |
127 | * This function can be used to start a session protection which means that the | 128 | * This function can be used to start a session protection which means that the |
128 | * fw will stay on the channel for %duration_ms milliseconds. This function | 129 | * fw will stay on the channel for %duration_ms milliseconds. This function |
@@ -133,7 +134,8 @@ | |||
133 | */ | 134 | */ |
134 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, | 135 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, |
135 | struct ieee80211_vif *vif, | 136 | struct ieee80211_vif *vif, |
136 | u32 duration, u32 min_duration); | 137 | u32 duration, u32 min_duration, |
138 | u32 max_delay); | ||
137 | 139 | ||
138 | /** | 140 | /** |
139 | * iwl_mvm_stop_session_protection - cancel the session protection. | 141 | * iwl_mvm_stop_session_protection - cancel the session protection. |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index e05440d90319..43d97c33a75a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -417,7 +417,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
417 | 417 | ||
418 | spin_unlock(&mvmsta->lock); | 418 | spin_unlock(&mvmsta->lock); |
419 | 419 | ||
420 | if (txq_id < IWL_MVM_FIRST_AGG_QUEUE) | 420 | if (txq_id < mvm->first_agg_queue) |
421 | atomic_inc(&mvm->pending_frames[mvmsta->sta_id]); | 421 | atomic_inc(&mvm->pending_frames[mvmsta->sta_id]); |
422 | 422 | ||
423 | return 0; | 423 | return 0; |
@@ -511,16 +511,10 @@ const char *iwl_mvm_get_tx_fail_reason(u32 status) | |||
511 | } | 511 | } |
512 | #endif /* CONFIG_IWLWIFI_DEBUG */ | 512 | #endif /* CONFIG_IWLWIFI_DEBUG */ |
513 | 513 | ||
514 | /** | 514 | void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags, |
515 | * translate ucode response to mac80211 tx status control values | 515 | enum ieee80211_band band, |
516 | */ | 516 | struct ieee80211_tx_rate *r) |
517 | static void iwl_mvm_hwrate_to_tx_control(u32 rate_n_flags, | ||
518 | struct ieee80211_tx_info *info) | ||
519 | { | 517 | { |
520 | struct ieee80211_tx_rate *r = &info->status.rates[0]; | ||
521 | |||
522 | info->status.antenna = | ||
523 | ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); | ||
524 | if (rate_n_flags & RATE_HT_MCS_GF_MSK) | 518 | if (rate_n_flags & RATE_HT_MCS_GF_MSK) |
525 | r->flags |= IEEE80211_TX_RC_GREEN_FIELD; | 519 | r->flags |= IEEE80211_TX_RC_GREEN_FIELD; |
526 | switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { | 520 | switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { |
@@ -549,10 +543,23 @@ static void iwl_mvm_hwrate_to_tx_control(u32 rate_n_flags, | |||
549 | r->flags |= IEEE80211_TX_RC_VHT_MCS; | 543 | r->flags |= IEEE80211_TX_RC_VHT_MCS; |
550 | } else { | 544 | } else { |
551 | r->idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, | 545 | r->idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, |
552 | info->band); | 546 | band); |
553 | } | 547 | } |
554 | } | 548 | } |
555 | 549 | ||
550 | /** | ||
551 | * translate ucode response to mac80211 tx status control values | ||
552 | */ | ||
553 | static void iwl_mvm_hwrate_to_tx_status(u32 rate_n_flags, | ||
554 | struct ieee80211_tx_info *info) | ||
555 | { | ||
556 | struct ieee80211_tx_rate *r = &info->status.rates[0]; | ||
557 | |||
558 | info->status.antenna = | ||
559 | ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); | ||
560 | iwl_mvm_hwrate_to_tx_rate(rate_n_flags, info->band, r); | ||
561 | } | ||
562 | |||
556 | static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | 563 | static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, |
557 | struct iwl_rx_packet *pkt) | 564 | struct iwl_rx_packet *pkt) |
558 | { | 565 | { |
@@ -602,11 +609,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
602 | } | 609 | } |
603 | 610 | ||
604 | info->status.rates[0].count = tx_resp->failure_frame + 1; | 611 | info->status.rates[0].count = tx_resp->failure_frame + 1; |
605 | iwl_mvm_hwrate_to_tx_control(le32_to_cpu(tx_resp->initial_rate), | 612 | iwl_mvm_hwrate_to_tx_status(le32_to_cpu(tx_resp->initial_rate), |
606 | info); | 613 | info); |
607 | 614 | ||
608 | /* Single frame failure in an AMPDU queue => send BAR */ | 615 | /* Single frame failure in an AMPDU queue => send BAR */ |
609 | if (txq_id >= IWL_MVM_FIRST_AGG_QUEUE && | 616 | if (txq_id >= mvm->first_agg_queue && |
610 | !(info->flags & IEEE80211_TX_STAT_ACK)) | 617 | !(info->flags & IEEE80211_TX_STAT_ACK)) |
611 | info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; | 618 | info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; |
612 | 619 | ||
@@ -619,7 +626,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
619 | ieee80211_tx_status_ni(mvm->hw, skb); | 626 | ieee80211_tx_status_ni(mvm->hw, skb); |
620 | } | 627 | } |
621 | 628 | ||
622 | if (txq_id >= IWL_MVM_FIRST_AGG_QUEUE) { | 629 | if (txq_id >= mvm->first_agg_queue) { |
623 | /* If this is an aggregation queue, we use the ssn since: | 630 | /* If this is an aggregation queue, we use the ssn since: |
624 | * ssn = wifi seq_num % 256. | 631 | * ssn = wifi seq_num % 256. |
625 | * The seq_ctl is the sequence control of the packet to which | 632 | * The seq_ctl is the sequence control of the packet to which |
@@ -668,10 +675,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
668 | iwl_mvm_check_ratid_empty(mvm, sta, tid); | 675 | iwl_mvm_check_ratid_empty(mvm, sta, tid); |
669 | spin_unlock_bh(&mvmsta->lock); | 676 | spin_unlock_bh(&mvmsta->lock); |
670 | } | 677 | } |
671 | |||
672 | #ifdef CONFIG_PM_SLEEP | ||
673 | mvmsta->last_seq_ctl = seq_ctl; | ||
674 | #endif | ||
675 | } else { | 678 | } else { |
676 | sta = NULL; | 679 | sta = NULL; |
677 | mvmsta = NULL; | 680 | mvmsta = NULL; |
@@ -681,7 +684,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
681 | * If the txq is not an AMPDU queue, there is no chance we freed | 684 | * If the txq is not an AMPDU queue, there is no chance we freed |
682 | * several skbs. Check that out... | 685 | * several skbs. Check that out... |
683 | */ | 686 | */ |
684 | if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && !WARN_ON(skb_freed > 1) && | 687 | if (txq_id < mvm->first_agg_queue && !WARN_ON(skb_freed > 1) && |
685 | atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) { | 688 | atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) { |
686 | if (mvmsta) { | 689 | if (mvmsta) { |
687 | /* | 690 | /* |
@@ -777,7 +780,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, | |||
777 | u16 sequence = le16_to_cpu(pkt->hdr.sequence); | 780 | u16 sequence = le16_to_cpu(pkt->hdr.sequence); |
778 | struct ieee80211_sta *sta; | 781 | struct ieee80211_sta *sta; |
779 | 782 | ||
780 | if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < IWL_MVM_FIRST_AGG_QUEUE)) | 783 | if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < mvm->first_agg_queue)) |
781 | return; | 784 | return; |
782 | 785 | ||
783 | if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS)) | 786 | if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS)) |
@@ -904,8 +907,8 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
904 | info->flags |= IEEE80211_TX_STAT_AMPDU; | 907 | info->flags |= IEEE80211_TX_STAT_AMPDU; |
905 | info->status.ampdu_ack_len = ba_notif->txed_2_done; | 908 | info->status.ampdu_ack_len = ba_notif->txed_2_done; |
906 | info->status.ampdu_len = ba_notif->txed; | 909 | info->status.ampdu_len = ba_notif->txed; |
907 | iwl_mvm_hwrate_to_tx_control(tid_data->rate_n_flags, | 910 | iwl_mvm_hwrate_to_tx_status(tid_data->rate_n_flags, |
908 | info); | 911 | info); |
909 | } | 912 | } |
910 | } | 913 | } |
911 | 914 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index a9c357491434..ed69e9b78e82 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c | |||
@@ -466,7 +466,7 @@ void iwl_mvm_dump_sram(struct iwl_mvm *mvm) | |||
466 | ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; | 466 | ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; |
467 | len = img->sec[IWL_UCODE_SECTION_DATA].len; | 467 | len = img->sec[IWL_UCODE_SECTION_DATA].len; |
468 | 468 | ||
469 | buf = kzalloc(len, GFP_KERNEL); | 469 | buf = kzalloc(len, GFP_ATOMIC); |
470 | if (!buf) | 470 | if (!buf) |
471 | return; | 471 | return; |
472 | 472 | ||