diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm')
33 files changed, 2202 insertions, 653 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index 807b250ec396..2acc44b40986 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile | |||
@@ -2,7 +2,7 @@ obj-$(CONFIG_IWLMVM) += iwlmvm.o | |||
2 | iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o | 2 | iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o |
3 | iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o | 3 | iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o |
4 | iwlmvm-y += scan.o time-event.o rs.o | 4 | iwlmvm-y += scan.o time-event.o rs.o |
5 | iwlmvm-y += power.o | 5 | iwlmvm-y += power.o bt-coex.o |
6 | iwlmvm-y += led.o | 6 | iwlmvm-y += led.o |
7 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o | 7 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o |
8 | iwlmvm-$(CONFIG_PM_SLEEP) += d3.o | 8 | iwlmvm-$(CONFIG_PM_SLEEP) += d3.o |
diff --git a/drivers/net/wireless/iwlwifi/mvm/binding.c b/drivers/net/wireless/iwlwifi/mvm/binding.c index 73d24aacb90a..93fd1457954b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/binding.c +++ b/drivers/net/wireless/iwlwifi/mvm/binding.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c new file mode 100644 index 000000000000..810bfa5f6de0 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c | |||
@@ -0,0 +1,589 @@ | |||
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 | #include <net/mac80211.h> | ||
65 | |||
66 | #include "fw-api-bt-coex.h" | ||
67 | #include "iwl-modparams.h" | ||
68 | #include "mvm.h" | ||
69 | #include "iwl-debug.h" | ||
70 | |||
71 | #define EVENT_PRIO_ANT(_evt, _prio, _shrd_ant) \ | ||
72 | [(_evt)] = (((_prio) << BT_COEX_PRIO_TBL_PRIO_POS) | \ | ||
73 | ((_shrd_ant) << BT_COEX_PRIO_TBL_SHRD_ANT_POS)) | ||
74 | |||
75 | static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { | ||
76 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB1, | ||
77 | BT_COEX_PRIO_TBL_PRIO_BYPASS, 0), | ||
78 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB2, | ||
79 | BT_COEX_PRIO_TBL_PRIO_BYPASS, 1), | ||
80 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1, | ||
81 | BT_COEX_PRIO_TBL_PRIO_LOW, 0), | ||
82 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2, | ||
83 | BT_COEX_PRIO_TBL_PRIO_LOW, 1), | ||
84 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1, | ||
85 | BT_COEX_PRIO_TBL_PRIO_HIGH, 0), | ||
86 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2, | ||
87 | BT_COEX_PRIO_TBL_PRIO_HIGH, 1), | ||
88 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_DTIM, | ||
89 | BT_COEX_PRIO_TBL_DISABLED, 0), | ||
90 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN52, | ||
91 | BT_COEX_PRIO_TBL_PRIO_COEX_OFF, 0), | ||
92 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN24, | ||
93 | BT_COEX_PRIO_TBL_PRIO_COEX_ON, 0), | ||
94 | EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_IDLE, | ||
95 | BT_COEX_PRIO_TBL_PRIO_COEX_IDLE, 0), | ||
96 | 0, 0, 0, 0, 0, 0, | ||
97 | }; | ||
98 | |||
99 | #undef EVENT_PRIO_ANT | ||
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) | ||
106 | #define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD (-65) | ||
107 | #define BT_REDUCED_TX_POWER_BIT BIT(7) | ||
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 | |||
115 | int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) | ||
116 | { | ||
117 | return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, CMD_SYNC, | ||
118 | sizeof(struct iwl_bt_coex_prio_tbl_cmd), | ||
119 | &iwl_bt_prio_tbl); | ||
120 | } | ||
121 | |||
122 | static int iwl_send_bt_env(struct iwl_mvm *mvm, u8 action, u8 type) | ||
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, | ||
145 | [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, | ||
146 | [BT_KILL_MSK_REDUCED_TXPOW] = 0, | ||
147 | }; | ||
148 | |||
149 | static const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = { | ||
150 | [BT_KILL_MSK_DEFAULT] = 0xffff0000, | ||
151 | [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, | ||
152 | [BT_KILL_MSK_REDUCED_TXPOW] = 0, | ||
153 | }; | ||
154 | |||
155 | #define IWL_BT_DEFAULT_BOOST (0xf0f0f0f0) | ||
156 | |||
157 | /* Tight Coex */ | ||
158 | static const __le32 iwl_tight_lookup[BT_COEX_LUT_SIZE] = { | ||
159 | cpu_to_le32(0xaaaaaaaa), | ||
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 | }; | ||
172 | |||
173 | /* Loose Coex */ | ||
174 | static const __le32 iwl_loose_lookup[BT_COEX_LUT_SIZE] = { | ||
175 | cpu_to_le32(0xaaaaaaaa), | ||
176 | cpu_to_le32(0xaaaaaaaa), | ||
177 | cpu_to_le32(0xaeaaaaaa), | ||
178 | cpu_to_le32(0xaaaaaaaa), | ||
179 | cpu_to_le32(0xcc00ff28), | ||
180 | cpu_to_le32(0x0000aaaa), | ||
181 | cpu_to_le32(0xcc00aaaa), | ||
182 | cpu_to_le32(0x0000aaaa), | ||
183 | cpu_to_le32(0x00000000), | ||
184 | cpu_to_le32(0x00000000), | ||
185 | cpu_to_le32(0xf0005000), | ||
186 | cpu_to_le32(0xf0005000), | ||
187 | }; | ||
188 | |||
189 | /* Full concurrency */ | ||
190 | static const __le32 iwl_concurrent_lookup[BT_COEX_LUT_SIZE] = { | ||
191 | cpu_to_le32(0xaaaaaaaa), | ||
192 | cpu_to_le32(0xaaaaaaaa), | ||
193 | cpu_to_le32(0xaaaaaaaa), | ||
194 | cpu_to_le32(0xaaaaaaaa), | ||
195 | cpu_to_le32(0xaaaaaaaa), | ||
196 | cpu_to_le32(0xaaaaaaaa), | ||
197 | cpu_to_le32(0xaaaaaaaa), | ||
198 | cpu_to_le32(0xaaaaaaaa), | ||
199 | cpu_to_le32(0x00000000), | ||
200 | cpu_to_le32(0x00000000), | ||
201 | cpu_to_le32(0x00000000), | ||
202 | cpu_to_le32(0x00000000), | ||
203 | }; | ||
204 | |||
205 | int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | ||
206 | { | ||
207 | struct iwl_bt_coex_cmd cmd = { | ||
208 | .max_kill = 5, | ||
209 | .bt3_time_t7_value = 1, | ||
210 | .bt3_prio_sample_time = 2, | ||
211 | .bt3_timer_t2_value = 0xc, | ||
212 | }; | ||
213 | int ret; | ||
214 | |||
215 | cmd.flags = iwlwifi_mod_params.bt_coex_active ? | ||
216 | BT_COEX_NW : BT_COEX_DISABLE; | ||
217 | cmd.flags |= BT_CH_PRIMARY_EN | BT_SYNC_2_BT_DISABLE; | ||
218 | |||
219 | cmd.valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE | | ||
220 | BT_VALID_BT_PRIO_BOOST | | ||
221 | BT_VALID_MAX_KILL | | ||
222 | BT_VALID_3W_TMRS | | ||
223 | BT_VALID_KILL_ACK | | ||
224 | BT_VALID_KILL_CTS | | ||
225 | BT_VALID_REDUCED_TX_POWER | | ||
226 | BT_VALID_LUT); | ||
227 | |||
228 | if (is_loose_coex()) | ||
229 | memcpy(&cmd.decision_lut, iwl_loose_lookup, | ||
230 | sizeof(iwl_tight_lookup)); | ||
231 | else | ||
232 | memcpy(&cmd.decision_lut, iwl_tight_lookup, | ||
233 | sizeof(iwl_tight_lookup)); | ||
234 | |||
235 | cmd.bt_prio_boost = cpu_to_le32(IWL_BT_DEFAULT_BOOST); | ||
236 | cmd.kill_ack_msk = | ||
237 | cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); | ||
238 | cmd.kill_cts_msk = | ||
239 | cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); | ||
240 | |||
241 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | ||
242 | |||
243 | /* go to CALIB state in internal BT-Coex state machine */ | ||
244 | ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN, | ||
245 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); | ||
246 | if (ret) | ||
247 | return ret; | ||
248 | |||
249 | ret = iwl_send_bt_env(mvm, BT_COEX_ENV_CLOSE, | ||
250 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); | ||
251 | if (ret) | ||
252 | return ret; | ||
253 | |||
254 | return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC, | ||
255 | sizeof(cmd), &cmd); | ||
256 | } | ||
257 | |||
258 | static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, | ||
259 | bool reduced_tx_power) | ||
260 | { | ||
261 | enum iwl_bt_kill_msk bt_kill_msk; | ||
262 | struct iwl_bt_coex_cmd cmd = {}; | ||
263 | struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; | ||
264 | |||
265 | lockdep_assert_held(&mvm->mutex); | ||
266 | |||
267 | if (reduced_tx_power) { | ||
268 | /* Reduced Tx power has precedence on the type of the profile */ | ||
269 | bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW; | ||
270 | } else { | ||
271 | /* Low latency BT profile is active: give higher prio to BT */ | ||
272 | if (BT_MBOX_MSG(notif, 3, SCO_STATE) || | ||
273 | BT_MBOX_MSG(notif, 3, A2DP_STATE) || | ||
274 | BT_MBOX_MSG(notif, 3, SNIFF_STATE)) | ||
275 | bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP; | ||
276 | else | ||
277 | bt_kill_msk = BT_KILL_MSK_DEFAULT; | ||
278 | } | ||
279 | |||
280 | IWL_DEBUG_COEX(mvm, | ||
281 | "Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n", | ||
282 | bt_kill_msk, | ||
283 | BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in", | ||
284 | BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in", | ||
285 | BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in"); | ||
286 | |||
287 | /* Don't send HCMD if there is no update */ | ||
288 | if (bt_kill_msk == mvm->bt_kill_msk) | ||
289 | return 0; | ||
290 | |||
291 | mvm->bt_kill_msk = bt_kill_msk; | ||
292 | cmd.kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); | ||
293 | cmd.kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); | ||
294 | cmd.valid_bit_msk = cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS); | ||
295 | |||
296 | IWL_DEBUG_COEX(mvm, "bt_kill_msk = %d\n", bt_kill_msk); | ||
297 | return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC, | ||
298 | sizeof(cmd), &cmd); | ||
299 | } | ||
300 | |||
301 | static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, | ||
302 | bool enable) | ||
303 | { | ||
304 | struct iwl_bt_coex_cmd cmd = { | ||
305 | .valid_bit_msk = cpu_to_le16(BT_VALID_REDUCED_TX_POWER), | ||
306 | .bt_reduced_tx_power = sta_id, | ||
307 | }; | ||
308 | struct ieee80211_sta *sta; | ||
309 | struct iwl_mvm_sta *mvmsta; | ||
310 | |||
311 | /* This can happen if the station has been removed right now */ | ||
312 | if (sta_id == IWL_MVM_STATION_COUNT) | ||
313 | return 0; | ||
314 | |||
315 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
316 | lockdep_is_held(&mvm->mutex)); | ||
317 | mvmsta = (void *)sta->drv_priv; | ||
318 | |||
319 | /* nothing to do */ | ||
320 | if (mvmsta->bt_reduced_txpower == enable) | ||
321 | return 0; | ||
322 | |||
323 | if (enable) | ||
324 | cmd.bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT; | ||
325 | |||
326 | IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n", | ||
327 | enable ? "en" : "dis", sta_id); | ||
328 | |||
329 | mvmsta->bt_reduced_txpower = enable; | ||
330 | |||
331 | /* Send ASYNC since this can be sent from an atomic context */ | ||
332 | return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_ASYNC, | ||
333 | sizeof(cmd), &cmd); | ||
334 | } | ||
335 | |||
336 | struct iwl_bt_iterator_data { | ||
337 | struct iwl_bt_coex_profile_notif *notif; | ||
338 | struct iwl_mvm *mvm; | ||
339 | u32 num_bss_ifaces; | ||
340 | bool reduced_tx_power; | ||
341 | }; | ||
342 | |||
343 | static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | ||
344 | struct ieee80211_vif *vif) | ||
345 | { | ||
346 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
347 | struct iwl_bt_iterator_data *data = _data; | ||
348 | struct iwl_mvm *mvm = data->mvm; | ||
349 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
350 | enum ieee80211_smps_mode smps_mode; | ||
351 | enum ieee80211_band band; | ||
352 | int ave_rssi; | ||
353 | |||
354 | if (vif->type != NL80211_IFTYPE_STATION) | ||
355 | return; | ||
356 | |||
357 | rcu_read_lock(); | ||
358 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
359 | if (chanctx_conf && chanctx_conf->def.chan) | ||
360 | band = chanctx_conf->def.chan->band; | ||
361 | else | ||
362 | band = -1; | ||
363 | rcu_read_unlock(); | ||
364 | |||
365 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | ||
366 | |||
367 | if (band != IEEE80211_BAND_2GHZ) { | ||
368 | ieee80211_request_smps(vif, smps_mode); | ||
369 | return; | ||
370 | } | ||
371 | |||
372 | if (data->notif->bt_status) | ||
373 | smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
374 | |||
375 | if (data->notif->bt_traffic_load >= IWL_BT_LOAD_FORCE_SISO_THRESHOLD) | ||
376 | smps_mode = IEEE80211_SMPS_STATIC; | ||
377 | |||
378 | IWL_DEBUG_COEX(data->mvm, | ||
379 | "mac %d: bt_status %d traffic_load %d smps_req %d\n", | ||
380 | mvmvif->id, data->notif->bt_status, | ||
381 | data->notif->bt_traffic_load, smps_mode); | ||
382 | |||
383 | ieee80211_request_smps(vif, smps_mode); | ||
384 | |||
385 | /* don't reduce the Tx power if in loose scheme */ | ||
386 | if (is_loose_coex()) | ||
387 | return; | ||
388 | |||
389 | data->num_bss_ifaces++; | ||
390 | |||
391 | /* reduced Txpower only if there are open BT connections, so ...*/ | ||
392 | if (!BT_MBOX_MSG(data->notif, 3, OPEN_CON_2)) { | ||
393 | /* ... cancel reduced Tx power ... */ | ||
394 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) | ||
395 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); | ||
396 | data->reduced_tx_power = false; | ||
397 | |||
398 | /* ... and there is no need to get reports on RSSI any more. */ | ||
399 | ieee80211_disable_rssi_reports(vif); | ||
400 | return; | ||
401 | } | ||
402 | |||
403 | ave_rssi = ieee80211_ave_rssi(vif); | ||
404 | |||
405 | /* if the RSSI isn't valid, fake it is very low */ | ||
406 | if (!ave_rssi) | ||
407 | ave_rssi = -100; | ||
408 | if (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) { | ||
409 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) | ||
410 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); | ||
411 | |||
412 | /* | ||
413 | * bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the | ||
414 | * BSS / P2P clients have rssi above threshold. | ||
415 | * We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before | ||
416 | * the iteration, if one interface's rssi isn't good enough, | ||
417 | * bt_kill_msk will be set to default values. | ||
418 | */ | ||
419 | } else if (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) { | ||
420 | if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) | ||
421 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); | ||
422 | |||
423 | /* | ||
424 | * One interface hasn't rssi above threshold, bt_kill_msk must | ||
425 | * be set to default values. | ||
426 | */ | ||
427 | data->reduced_tx_power = false; | ||
428 | } | ||
429 | |||
430 | /* Begin to monitor the RSSI: it may influence the reduced Tx power */ | ||
431 | ieee80211_enable_rssi_reports(vif, BT_DISABLE_REDUCED_TXPOWER_THRESHOLD, | ||
432 | BT_ENABLE_REDUCED_TXPOWER_THRESHOLD); | ||
433 | } | ||
434 | |||
435 | static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) | ||
436 | { | ||
437 | struct iwl_bt_iterator_data data = { | ||
438 | .mvm = mvm, | ||
439 | .notif = &mvm->last_bt_notif, | ||
440 | .reduced_tx_power = true, | ||
441 | }; | ||
442 | |||
443 | ieee80211_iterate_active_interfaces_atomic( | ||
444 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
445 | iwl_mvm_bt_notif_iterator, &data); | ||
446 | |||
447 | /* | ||
448 | * If there are no BSS / P2P client interfaces, reduced Tx Power is | ||
449 | * irrelevant since it is based on the RSSI coming from the beacon. | ||
450 | * Use BT_KILL_MSK_DEFAULT in that case. | ||
451 | */ | ||
452 | data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; | ||
453 | |||
454 | if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) | ||
455 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); | ||
456 | } | ||
457 | |||
458 | /* upon association, the fw will send in BT Coex notification */ | ||
459 | int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, | ||
460 | struct iwl_rx_cmd_buffer *rxb, | ||
461 | struct iwl_device_cmd *dev_cmd) | ||
462 | { | ||
463 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
464 | struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; | ||
465 | |||
466 | |||
467 | IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); | ||
468 | IWL_DEBUG_COEX(mvm, "\tBT %salive\n", notif->bt_status ? "" : "not "); | ||
469 | IWL_DEBUG_COEX(mvm, "\tBT open conn %d\n", notif->bt_open_conn); | ||
470 | IWL_DEBUG_COEX(mvm, "\tBT traffic load %d\n", notif->bt_traffic_load); | ||
471 | IWL_DEBUG_COEX(mvm, "\tBT agg traffic load %d\n", | ||
472 | notif->bt_agg_traffic_load); | ||
473 | IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); | ||
474 | |||
475 | /* remember this notification for future use: rssi fluctuations */ | ||
476 | memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif)); | ||
477 | |||
478 | iwl_mvm_bt_coex_notif_handle(mvm); | ||
479 | |||
480 | /* | ||
481 | * This is an async handler for a notification, returning anything other | ||
482 | * than 0 doesn't make sense even if HCMD failed. | ||
483 | */ | ||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, | ||
488 | struct ieee80211_vif *vif) | ||
489 | { | ||
490 | struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; | ||
491 | struct iwl_bt_iterator_data *data = _data; | ||
492 | struct iwl_mvm *mvm = data->mvm; | ||
493 | |||
494 | struct ieee80211_sta *sta; | ||
495 | struct iwl_mvm_sta *mvmsta; | ||
496 | |||
497 | if (vif->type != NL80211_IFTYPE_STATION || | ||
498 | mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) | ||
499 | return; | ||
500 | |||
501 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], | ||
502 | lockdep_is_held(&mvm->mutex)); | ||
503 | mvmsta = (void *)sta->drv_priv; | ||
504 | |||
505 | /* | ||
506 | * This interface doesn't support reduced Tx power (because of low | ||
507 | * RSSI probably), then set bt_kill_msk to default values. | ||
508 | */ | ||
509 | if (!mvmsta->bt_reduced_txpower) | ||
510 | data->reduced_tx_power = false; | ||
511 | /* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */ | ||
512 | } | ||
513 | |||
514 | void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
515 | enum ieee80211_rssi_event rssi_event) | ||
516 | { | ||
517 | struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; | ||
518 | struct iwl_bt_iterator_data data = { | ||
519 | .mvm = mvm, | ||
520 | .reduced_tx_power = true, | ||
521 | }; | ||
522 | int ret; | ||
523 | |||
524 | mutex_lock(&mvm->mutex); | ||
525 | |||
526 | /* Rssi update while not associated ?! */ | ||
527 | if (WARN_ON_ONCE(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)) | ||
528 | goto out_unlock; | ||
529 | |||
530 | /* No open connection - reports should be disabled */ | ||
531 | if (!BT_MBOX_MSG(&mvm->last_bt_notif, 3, OPEN_CON_2)) | ||
532 | goto out_unlock; | ||
533 | |||
534 | IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid, | ||
535 | rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW"); | ||
536 | |||
537 | /* | ||
538 | * Check if rssi is good enough for reduced Tx power, but not in loose | ||
539 | * scheme. | ||
540 | */ | ||
541 | if (rssi_event == RSSI_EVENT_LOW || is_loose_coex()) | ||
542 | ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, | ||
543 | false); | ||
544 | else | ||
545 | ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true); | ||
546 | |||
547 | if (ret) | ||
548 | IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n"); | ||
549 | |||
550 | ieee80211_iterate_active_interfaces_atomic( | ||
551 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
552 | iwl_mvm_bt_rssi_iterator, &data); | ||
553 | |||
554 | /* | ||
555 | * If there are no BSS / P2P client interfaces, reduced Tx Power is | ||
556 | * irrelevant since it is based on the RSSI coming from the beacon. | ||
557 | * Use BT_KILL_MSK_DEFAULT in that case. | ||
558 | */ | ||
559 | data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; | ||
560 | |||
561 | if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) | ||
562 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); | ||
563 | |||
564 | out_unlock: | ||
565 | mutex_unlock(&mvm->mutex); | ||
566 | } | ||
567 | |||
568 | void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
569 | { | ||
570 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
571 | enum ieee80211_band band; | ||
572 | |||
573 | rcu_read_lock(); | ||
574 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
575 | if (chanctx_conf && chanctx_conf->def.chan) | ||
576 | band = chanctx_conf->def.chan->band; | ||
577 | else | ||
578 | band = -1; | ||
579 | rcu_read_unlock(); | ||
580 | |||
581 | /* if we are in 2GHz we will get a notification from the fw */ | ||
582 | if (band == IEEE80211_BAND_2GHZ) | ||
583 | return; | ||
584 | |||
585 | /* else, we can remove all the constraints */ | ||
586 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | ||
587 | |||
588 | iwl_mvm_bt_coex_notif_handle(mvm); | ||
589 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index c64d864799cd..16bbdcc8627a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -61,8 +61,11 @@ | |||
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | 63 | ||
64 | #include <linux/etherdevice.h> | ||
65 | #include <linux/ip.h> | ||
64 | #include <net/cfg80211.h> | 66 | #include <net/cfg80211.h> |
65 | #include <net/ipv6.h> | 67 | #include <net/ipv6.h> |
68 | #include <net/tcp.h> | ||
66 | #include "iwl-modparams.h" | 69 | #include "iwl-modparams.h" |
67 | #include "fw-api.h" | 70 | #include "fw-api.h" |
68 | #include "mvm.h" | 71 | #include "mvm.h" |
@@ -192,6 +195,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, | |||
192 | sizeof(wkc), &wkc); | 195 | sizeof(wkc), &wkc); |
193 | data->error = ret != 0; | 196 | data->error = ret != 0; |
194 | 197 | ||
198 | mvm->ptk_ivlen = key->iv_len; | ||
199 | mvm->ptk_icvlen = key->icv_len; | ||
200 | mvm->gtk_ivlen = key->iv_len; | ||
201 | mvm->gtk_icvlen = key->icv_len; | ||
202 | |||
195 | /* don't upload key again */ | 203 | /* don't upload key again */ |
196 | goto out_unlock; | 204 | goto out_unlock; |
197 | } | 205 | } |
@@ -304,9 +312,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, | |||
304 | */ | 312 | */ |
305 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { | 313 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { |
306 | key->hw_key_idx = 0; | 314 | key->hw_key_idx = 0; |
315 | mvm->ptk_ivlen = key->iv_len; | ||
316 | mvm->ptk_icvlen = key->icv_len; | ||
307 | } else { | 317 | } else { |
308 | data->gtk_key_idx++; | 318 | data->gtk_key_idx++; |
309 | key->hw_key_idx = data->gtk_key_idx; | 319 | key->hw_key_idx = data->gtk_key_idx; |
320 | mvm->gtk_ivlen = key->iv_len; | ||
321 | mvm->gtk_icvlen = key->icv_len; | ||
310 | } | 322 | } |
311 | 323 | ||
312 | ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true); | 324 | ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true); |
@@ -392,6 +404,233 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | |||
392 | sizeof(cmd), &cmd); | 404 | sizeof(cmd), &cmd); |
393 | } | 405 | } |
394 | 406 | ||
407 | enum iwl_mvm_tcp_packet_type { | ||
408 | MVM_TCP_TX_SYN, | ||
409 | MVM_TCP_RX_SYNACK, | ||
410 | MVM_TCP_TX_DATA, | ||
411 | MVM_TCP_RX_ACK, | ||
412 | MVM_TCP_RX_WAKE, | ||
413 | MVM_TCP_TX_FIN, | ||
414 | }; | ||
415 | |||
416 | static __le16 pseudo_hdr_check(int len, __be32 saddr, __be32 daddr) | ||
417 | { | ||
418 | __sum16 check = tcp_v4_check(len, saddr, daddr, 0); | ||
419 | return cpu_to_le16(be16_to_cpu((__force __be16)check)); | ||
420 | } | ||
421 | |||
422 | static void iwl_mvm_build_tcp_packet(struct iwl_mvm *mvm, | ||
423 | struct ieee80211_vif *vif, | ||
424 | struct cfg80211_wowlan_tcp *tcp, | ||
425 | void *_pkt, u8 *mask, | ||
426 | __le16 *pseudo_hdr_csum, | ||
427 | enum iwl_mvm_tcp_packet_type ptype) | ||
428 | { | ||
429 | struct { | ||
430 | struct ethhdr eth; | ||
431 | struct iphdr ip; | ||
432 | struct tcphdr tcp; | ||
433 | u8 data[]; | ||
434 | } __packed *pkt = _pkt; | ||
435 | u16 ip_tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr); | ||
436 | int i; | ||
437 | |||
438 | pkt->eth.h_proto = cpu_to_be16(ETH_P_IP), | ||
439 | pkt->ip.version = 4; | ||
440 | pkt->ip.ihl = 5; | ||
441 | pkt->ip.protocol = IPPROTO_TCP; | ||
442 | |||
443 | switch (ptype) { | ||
444 | case MVM_TCP_TX_SYN: | ||
445 | case MVM_TCP_TX_DATA: | ||
446 | case MVM_TCP_TX_FIN: | ||
447 | memcpy(pkt->eth.h_dest, tcp->dst_mac, ETH_ALEN); | ||
448 | memcpy(pkt->eth.h_source, vif->addr, ETH_ALEN); | ||
449 | pkt->ip.ttl = 128; | ||
450 | pkt->ip.saddr = tcp->src; | ||
451 | pkt->ip.daddr = tcp->dst; | ||
452 | pkt->tcp.source = cpu_to_be16(tcp->src_port); | ||
453 | pkt->tcp.dest = cpu_to_be16(tcp->dst_port); | ||
454 | /* overwritten for TX SYN later */ | ||
455 | pkt->tcp.doff = sizeof(struct tcphdr) / 4; | ||
456 | pkt->tcp.window = cpu_to_be16(65000); | ||
457 | break; | ||
458 | case MVM_TCP_RX_SYNACK: | ||
459 | case MVM_TCP_RX_ACK: | ||
460 | case MVM_TCP_RX_WAKE: | ||
461 | memcpy(pkt->eth.h_dest, vif->addr, ETH_ALEN); | ||
462 | memcpy(pkt->eth.h_source, tcp->dst_mac, ETH_ALEN); | ||
463 | pkt->ip.saddr = tcp->dst; | ||
464 | pkt->ip.daddr = tcp->src; | ||
465 | pkt->tcp.source = cpu_to_be16(tcp->dst_port); | ||
466 | pkt->tcp.dest = cpu_to_be16(tcp->src_port); | ||
467 | break; | ||
468 | default: | ||
469 | WARN_ON(1); | ||
470 | return; | ||
471 | } | ||
472 | |||
473 | switch (ptype) { | ||
474 | case MVM_TCP_TX_SYN: | ||
475 | /* firmware assumes 8 option bytes - 8 NOPs for now */ | ||
476 | memset(pkt->data, 0x01, 8); | ||
477 | ip_tot_len += 8; | ||
478 | pkt->tcp.doff = (sizeof(struct tcphdr) + 8) / 4; | ||
479 | pkt->tcp.syn = 1; | ||
480 | break; | ||
481 | case MVM_TCP_TX_DATA: | ||
482 | ip_tot_len += tcp->payload_len; | ||
483 | memcpy(pkt->data, tcp->payload, tcp->payload_len); | ||
484 | pkt->tcp.psh = 1; | ||
485 | pkt->tcp.ack = 1; | ||
486 | break; | ||
487 | case MVM_TCP_TX_FIN: | ||
488 | pkt->tcp.fin = 1; | ||
489 | pkt->tcp.ack = 1; | ||
490 | break; | ||
491 | case MVM_TCP_RX_SYNACK: | ||
492 | pkt->tcp.syn = 1; | ||
493 | pkt->tcp.ack = 1; | ||
494 | break; | ||
495 | case MVM_TCP_RX_ACK: | ||
496 | pkt->tcp.ack = 1; | ||
497 | break; | ||
498 | case MVM_TCP_RX_WAKE: | ||
499 | ip_tot_len += tcp->wake_len; | ||
500 | pkt->tcp.psh = 1; | ||
501 | pkt->tcp.ack = 1; | ||
502 | memcpy(pkt->data, tcp->wake_data, tcp->wake_len); | ||
503 | break; | ||
504 | } | ||
505 | |||
506 | switch (ptype) { | ||
507 | case MVM_TCP_TX_SYN: | ||
508 | case MVM_TCP_TX_DATA: | ||
509 | case MVM_TCP_TX_FIN: | ||
510 | pkt->ip.tot_len = cpu_to_be16(ip_tot_len); | ||
511 | pkt->ip.check = ip_fast_csum(&pkt->ip, pkt->ip.ihl); | ||
512 | break; | ||
513 | case MVM_TCP_RX_WAKE: | ||
514 | for (i = 0; i < DIV_ROUND_UP(tcp->wake_len, 8); i++) { | ||
515 | u8 tmp = tcp->wake_mask[i]; | ||
516 | mask[i + 6] |= tmp << 6; | ||
517 | if (i + 1 < DIV_ROUND_UP(tcp->wake_len, 8)) | ||
518 | mask[i + 7] = tmp >> 2; | ||
519 | } | ||
520 | /* fall through for ethernet/IP/TCP headers mask */ | ||
521 | case MVM_TCP_RX_SYNACK: | ||
522 | case MVM_TCP_RX_ACK: | ||
523 | mask[0] = 0xff; /* match ethernet */ | ||
524 | /* | ||
525 | * match ethernet, ip.version, ip.ihl | ||
526 | * the ip.ihl half byte is really masked out by firmware | ||
527 | */ | ||
528 | mask[1] = 0x7f; | ||
529 | mask[2] = 0x80; /* match ip.protocol */ | ||
530 | mask[3] = 0xfc; /* match ip.saddr, ip.daddr */ | ||
531 | mask[4] = 0x3f; /* match ip.daddr, tcp.source, tcp.dest */ | ||
532 | mask[5] = 0x80; /* match tcp flags */ | ||
533 | /* leave rest (0 or set for MVM_TCP_RX_WAKE) */ | ||
534 | break; | ||
535 | }; | ||
536 | |||
537 | *pseudo_hdr_csum = pseudo_hdr_check(ip_tot_len - sizeof(struct iphdr), | ||
538 | pkt->ip.saddr, pkt->ip.daddr); | ||
539 | } | ||
540 | |||
541 | static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm, | ||
542 | struct ieee80211_vif *vif, | ||
543 | struct cfg80211_wowlan_tcp *tcp) | ||
544 | { | ||
545 | struct iwl_wowlan_remote_wake_config *cfg; | ||
546 | struct iwl_host_cmd cmd = { | ||
547 | .id = REMOTE_WAKE_CONFIG_CMD, | ||
548 | .len = { sizeof(*cfg), }, | ||
549 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
550 | .flags = CMD_SYNC, | ||
551 | }; | ||
552 | int ret; | ||
553 | |||
554 | if (!tcp) | ||
555 | return 0; | ||
556 | |||
557 | cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); | ||
558 | if (!cfg) | ||
559 | return -ENOMEM; | ||
560 | cmd.data[0] = cfg; | ||
561 | |||
562 | cfg->max_syn_retries = 10; | ||
563 | cfg->max_data_retries = 10; | ||
564 | cfg->tcp_syn_ack_timeout = 1; /* seconds */ | ||
565 | cfg->tcp_ack_timeout = 1; /* seconds */ | ||
566 | |||
567 | /* SYN (TX) */ | ||
568 | iwl_mvm_build_tcp_packet( | ||
569 | mvm, vif, tcp, cfg->syn_tx.data, NULL, | ||
570 | &cfg->syn_tx.info.tcp_pseudo_header_checksum, | ||
571 | MVM_TCP_TX_SYN); | ||
572 | cfg->syn_tx.info.tcp_payload_length = 0; | ||
573 | |||
574 | /* SYN/ACK (RX) */ | ||
575 | iwl_mvm_build_tcp_packet( | ||
576 | mvm, vif, tcp, cfg->synack_rx.data, cfg->synack_rx.rx_mask, | ||
577 | &cfg->synack_rx.info.tcp_pseudo_header_checksum, | ||
578 | MVM_TCP_RX_SYNACK); | ||
579 | cfg->synack_rx.info.tcp_payload_length = 0; | ||
580 | |||
581 | /* KEEPALIVE/ACK (TX) */ | ||
582 | iwl_mvm_build_tcp_packet( | ||
583 | mvm, vif, tcp, cfg->keepalive_tx.data, NULL, | ||
584 | &cfg->keepalive_tx.info.tcp_pseudo_header_checksum, | ||
585 | MVM_TCP_TX_DATA); | ||
586 | cfg->keepalive_tx.info.tcp_payload_length = | ||
587 | cpu_to_le16(tcp->payload_len); | ||
588 | cfg->sequence_number_offset = tcp->payload_seq.offset; | ||
589 | /* length must be 0..4, the field is little endian */ | ||
590 | cfg->sequence_number_length = tcp->payload_seq.len; | ||
591 | cfg->initial_sequence_number = cpu_to_le32(tcp->payload_seq.start); | ||
592 | cfg->keepalive_interval = cpu_to_le16(tcp->data_interval); | ||
593 | if (tcp->payload_tok.len) { | ||
594 | cfg->token_offset = tcp->payload_tok.offset; | ||
595 | cfg->token_length = tcp->payload_tok.len; | ||
596 | cfg->num_tokens = | ||
597 | cpu_to_le16(tcp->tokens_size % tcp->payload_tok.len); | ||
598 | memcpy(cfg->tokens, tcp->payload_tok.token_stream, | ||
599 | tcp->tokens_size); | ||
600 | } else { | ||
601 | /* set tokens to max value to almost never run out */ | ||
602 | cfg->num_tokens = cpu_to_le16(65535); | ||
603 | } | ||
604 | |||
605 | /* ACK (RX) */ | ||
606 | iwl_mvm_build_tcp_packet( | ||
607 | mvm, vif, tcp, cfg->keepalive_ack_rx.data, | ||
608 | cfg->keepalive_ack_rx.rx_mask, | ||
609 | &cfg->keepalive_ack_rx.info.tcp_pseudo_header_checksum, | ||
610 | MVM_TCP_RX_ACK); | ||
611 | cfg->keepalive_ack_rx.info.tcp_payload_length = 0; | ||
612 | |||
613 | /* WAKEUP (RX) */ | ||
614 | iwl_mvm_build_tcp_packet( | ||
615 | mvm, vif, tcp, cfg->wake_rx.data, cfg->wake_rx.rx_mask, | ||
616 | &cfg->wake_rx.info.tcp_pseudo_header_checksum, | ||
617 | MVM_TCP_RX_WAKE); | ||
618 | cfg->wake_rx.info.tcp_payload_length = | ||
619 | cpu_to_le16(tcp->wake_len); | ||
620 | |||
621 | /* FIN */ | ||
622 | iwl_mvm_build_tcp_packet( | ||
623 | mvm, vif, tcp, cfg->fin_tx.data, NULL, | ||
624 | &cfg->fin_tx.info.tcp_pseudo_header_checksum, | ||
625 | MVM_TCP_TX_FIN); | ||
626 | cfg->fin_tx.info.tcp_payload_length = 0; | ||
627 | |||
628 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
629 | kfree(cfg); | ||
630 | |||
631 | return ret; | ||
632 | } | ||
633 | |||
395 | struct iwl_d3_iter_data { | 634 | struct iwl_d3_iter_data { |
396 | struct iwl_mvm *mvm; | 635 | struct iwl_mvm *mvm; |
397 | struct ieee80211_vif *vif; | 636 | struct ieee80211_vif *vif; |
@@ -530,7 +769,14 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
530 | struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; | 769 | struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; |
531 | struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; | 770 | struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; |
532 | struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; | 771 | struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; |
533 | struct iwl_d3_manager_config d3_cfg_cmd = {}; | 772 | struct iwl_d3_manager_config d3_cfg_cmd = { |
773 | /* | ||
774 | * Program the minimum sleep time to 10 seconds, as many | ||
775 | * platforms have issues processing a wakeup signal while | ||
776 | * still being in the process of suspending. | ||
777 | */ | ||
778 | .min_sleep_time = cpu_to_le32(10 * 1000 * 1000), | ||
779 | }; | ||
534 | struct wowlan_key_data key_data = { | 780 | struct wowlan_key_data key_data = { |
535 | .use_rsc_tsc = false, | 781 | .use_rsc_tsc = false, |
536 | .tkip = &tkip_cmd, | 782 | .tkip = &tkip_cmd, |
@@ -627,9 +873,21 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
627 | cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH); | 873 | cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH); |
628 | 874 | ||
629 | if (wowlan->rfkill_release) | 875 | if (wowlan->rfkill_release) |
630 | d3_cfg_cmd.wakeup_flags |= | 876 | wowlan_config_cmd.wakeup_filter |= |
631 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); | 877 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); |
632 | 878 | ||
879 | if (wowlan->tcp) { | ||
880 | /* | ||
881 | * Set the "link change" (really "link lost") flag as well | ||
882 | * since that implies losing the TCP connection. | ||
883 | */ | ||
884 | wowlan_config_cmd.wakeup_filter |= | ||
885 | cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS | | ||
886 | IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE | | ||
887 | IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET | | ||
888 | IWL_WOWLAN_WAKEUP_LINK_CHANGE); | ||
889 | } | ||
890 | |||
633 | iwl_mvm_cancel_scan(mvm); | 891 | iwl_mvm_cancel_scan(mvm); |
634 | 892 | ||
635 | iwl_trans_stop_device(mvm->trans); | 893 | iwl_trans_stop_device(mvm->trans); |
@@ -649,6 +907,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
649 | /* We reprogram keys and shouldn't allocate new key indices */ | 907 | /* We reprogram keys and shouldn't allocate new key indices */ |
650 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); | 908 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); |
651 | 909 | ||
910 | mvm->ptk_ivlen = 0; | ||
911 | mvm->ptk_icvlen = 0; | ||
912 | mvm->ptk_ivlen = 0; | ||
913 | mvm->ptk_icvlen = 0; | ||
914 | |||
652 | /* | 915 | /* |
653 | * The D3 firmware still hardcodes the AP station ID for the | 916 | * The D3 firmware still hardcodes the AP station ID for the |
654 | * BSS we're associated with as 0. As a result, we have to move | 917 | * BSS we're associated with as 0. As a result, we have to move |
@@ -740,6 +1003,10 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
740 | if (ret) | 1003 | if (ret) |
741 | goto out; | 1004 | goto out; |
742 | 1005 | ||
1006 | ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp); | ||
1007 | if (ret) | ||
1008 | goto out; | ||
1009 | |||
743 | /* must be last -- this switches firmware state */ | 1010 | /* must be last -- this switches firmware state */ |
744 | ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC, | 1011 | ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC, |
745 | sizeof(d3_cfg_cmd), &d3_cfg_cmd); | 1012 | sizeof(d3_cfg_cmd), &d3_cfg_cmd); |
@@ -783,7 +1050,6 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
783 | struct iwl_wowlan_status *status; | 1050 | struct iwl_wowlan_status *status; |
784 | u32 reasons; | 1051 | u32 reasons; |
785 | int ret, len; | 1052 | int ret, len; |
786 | bool pkt8023 = false; | ||
787 | struct sk_buff *pkt = NULL; | 1053 | struct sk_buff *pkt = NULL; |
788 | 1054 | ||
789 | iwl_trans_read_mem_bytes(mvm->trans, base, | 1055 | iwl_trans_read_mem_bytes(mvm->trans, base, |
@@ -824,7 +1090,8 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
824 | status = (void *)cmd.resp_pkt->data; | 1090 | status = (void *)cmd.resp_pkt->data; |
825 | 1091 | ||
826 | if (len - sizeof(struct iwl_cmd_header) != | 1092 | if (len - sizeof(struct iwl_cmd_header) != |
827 | sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) { | 1093 | sizeof(*status) + |
1094 | ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) { | ||
828 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | 1095 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); |
829 | goto out; | 1096 | goto out; |
830 | } | 1097 | } |
@@ -836,61 +1103,105 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
836 | goto report; | 1103 | goto report; |
837 | } | 1104 | } |
838 | 1105 | ||
839 | if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) { | 1106 | if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) |
840 | wakeup.magic_pkt = true; | 1107 | wakeup.magic_pkt = true; |
841 | pkt8023 = true; | ||
842 | } | ||
843 | 1108 | ||
844 | if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) { | 1109 | if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) |
845 | wakeup.pattern_idx = | 1110 | wakeup.pattern_idx = |
846 | le16_to_cpu(status->pattern_number); | 1111 | le16_to_cpu(status->pattern_number); |
847 | pkt8023 = true; | ||
848 | } | ||
849 | 1112 | ||
850 | if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | | 1113 | if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | |
851 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) | 1114 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) |
852 | wakeup.disconnect = true; | 1115 | wakeup.disconnect = true; |
853 | 1116 | ||
854 | if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) { | 1117 | if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) |
855 | wakeup.gtk_rekey_failure = true; | 1118 | wakeup.gtk_rekey_failure = true; |
856 | pkt8023 = true; | ||
857 | } | ||
858 | 1119 | ||
859 | if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) { | 1120 | if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) |
860 | wakeup.rfkill_release = true; | 1121 | wakeup.rfkill_release = true; |
861 | pkt8023 = true; | ||
862 | } | ||
863 | 1122 | ||
864 | if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) { | 1123 | if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) |
865 | wakeup.eap_identity_req = true; | 1124 | wakeup.eap_identity_req = true; |
866 | pkt8023 = true; | ||
867 | } | ||
868 | 1125 | ||
869 | if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) { | 1126 | if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) |
870 | wakeup.four_way_handshake = true; | 1127 | wakeup.four_way_handshake = true; |
871 | pkt8023 = true; | 1128 | |
872 | } | 1129 | if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS) |
1130 | wakeup.tcp_connlost = true; | ||
1131 | |||
1132 | if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE) | ||
1133 | wakeup.tcp_nomoretokens = true; | ||
1134 | |||
1135 | if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET) | ||
1136 | wakeup.tcp_match = true; | ||
873 | 1137 | ||
874 | if (status->wake_packet_bufsize) { | 1138 | if (status->wake_packet_bufsize) { |
875 | u32 pktsize = le32_to_cpu(status->wake_packet_bufsize); | 1139 | int pktsize = le32_to_cpu(status->wake_packet_bufsize); |
876 | u32 pktlen = le32_to_cpu(status->wake_packet_length); | 1140 | int pktlen = le32_to_cpu(status->wake_packet_length); |
1141 | const u8 *pktdata = status->wake_packet; | ||
1142 | struct ieee80211_hdr *hdr = (void *)pktdata; | ||
1143 | int truncated = pktlen - pktsize; | ||
1144 | |||
1145 | /* this would be a firmware bug */ | ||
1146 | if (WARN_ON_ONCE(truncated < 0)) | ||
1147 | truncated = 0; | ||
1148 | |||
1149 | if (ieee80211_is_data(hdr->frame_control)) { | ||
1150 | int hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
1151 | int ivlen = 0, icvlen = 4; /* also FCS */ | ||
877 | 1152 | ||
878 | if (pkt8023) { | ||
879 | pkt = alloc_skb(pktsize, GFP_KERNEL); | 1153 | pkt = alloc_skb(pktsize, GFP_KERNEL); |
880 | if (!pkt) | 1154 | if (!pkt) |
881 | goto report; | 1155 | goto report; |
882 | memcpy(skb_put(pkt, pktsize), status->wake_packet, | 1156 | |
883 | pktsize); | 1157 | memcpy(skb_put(pkt, hdrlen), pktdata, hdrlen); |
1158 | pktdata += hdrlen; | ||
1159 | pktsize -= hdrlen; | ||
1160 | |||
1161 | if (ieee80211_has_protected(hdr->frame_control)) { | ||
1162 | if (is_multicast_ether_addr(hdr->addr1)) { | ||
1163 | ivlen = mvm->gtk_ivlen; | ||
1164 | icvlen += mvm->gtk_icvlen; | ||
1165 | } else { | ||
1166 | ivlen = mvm->ptk_ivlen; | ||
1167 | icvlen += mvm->ptk_icvlen; | ||
1168 | } | ||
1169 | } | ||
1170 | |||
1171 | /* if truncated, FCS/ICV is (partially) gone */ | ||
1172 | if (truncated >= icvlen) { | ||
1173 | icvlen = 0; | ||
1174 | truncated -= icvlen; | ||
1175 | } else { | ||
1176 | icvlen -= truncated; | ||
1177 | truncated = 0; | ||
1178 | } | ||
1179 | |||
1180 | pktsize -= ivlen + icvlen; | ||
1181 | pktdata += ivlen; | ||
1182 | |||
1183 | memcpy(skb_put(pkt, pktsize), pktdata, pktsize); | ||
1184 | |||
884 | if (ieee80211_data_to_8023(pkt, vif->addr, vif->type)) | 1185 | if (ieee80211_data_to_8023(pkt, vif->addr, vif->type)) |
885 | goto report; | 1186 | goto report; |
886 | wakeup.packet = pkt->data; | 1187 | wakeup.packet = pkt->data; |
887 | wakeup.packet_present_len = pkt->len; | 1188 | wakeup.packet_present_len = pkt->len; |
888 | wakeup.packet_len = pkt->len - (pktlen - pktsize); | 1189 | wakeup.packet_len = pkt->len - truncated; |
889 | wakeup.packet_80211 = false; | 1190 | wakeup.packet_80211 = false; |
890 | } else { | 1191 | } else { |
1192 | int fcslen = 4; | ||
1193 | |||
1194 | if (truncated >= 4) { | ||
1195 | truncated -= 4; | ||
1196 | fcslen = 0; | ||
1197 | } else { | ||
1198 | fcslen -= truncated; | ||
1199 | truncated = 0; | ||
1200 | } | ||
1201 | pktsize -= fcslen; | ||
891 | wakeup.packet = status->wake_packet; | 1202 | wakeup.packet = status->wake_packet; |
892 | wakeup.packet_present_len = pktsize; | 1203 | wakeup.packet_present_len = pktsize; |
893 | wakeup.packet_len = pktlen; | 1204 | wakeup.packet_len = pktlen - truncated; |
894 | wakeup.packet_80211 = true; | 1205 | wakeup.packet_80211 = true; |
895 | } | 1206 | } |
896 | } | 1207 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index c1bdb5582126..2053dccefcd6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -69,12 +69,6 @@ struct iwl_dbgfs_mvm_ctx { | |||
69 | struct ieee80211_vif *vif; | 69 | struct ieee80211_vif *vif; |
70 | }; | 70 | }; |
71 | 71 | ||
72 | static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file) | ||
73 | { | ||
74 | file->private_data = inode->i_private; | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static ssize_t iwl_dbgfs_tx_flush_write(struct file *file, | 72 | static ssize_t iwl_dbgfs_tx_flush_write(struct file *file, |
79 | const char __user *user_buf, | 73 | const char __user *user_buf, |
80 | size_t count, loff_t *ppos) | 74 | size_t count, loff_t *ppos) |
@@ -306,10 +300,191 @@ static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file, | |||
306 | return count; | 300 | return count; |
307 | } | 301 | } |
308 | 302 | ||
303 | static ssize_t iwl_dbgfs_mac_params_read(struct file *file, | ||
304 | char __user *user_buf, | ||
305 | size_t count, loff_t *ppos) | ||
306 | { | ||
307 | struct ieee80211_vif *vif = file->private_data; | ||
308 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
309 | struct iwl_mvm *mvm = mvmvif->dbgfs_data; | ||
310 | u8 ap_sta_id; | ||
311 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
312 | char buf[512]; | ||
313 | int bufsz = sizeof(buf); | ||
314 | int pos = 0; | ||
315 | int i; | ||
316 | |||
317 | mutex_lock(&mvm->mutex); | ||
318 | |||
319 | ap_sta_id = mvmvif->ap_sta_id; | ||
320 | |||
321 | pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n", | ||
322 | mvmvif->id, mvmvif->color); | ||
323 | pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n", | ||
324 | vif->bss_conf.bssid); | ||
325 | pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n"); | ||
326 | for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) { | ||
327 | pos += scnprintf(buf+pos, bufsz-pos, | ||
328 | "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n", | ||
329 | i, mvmvif->queue_params[i].txop, | ||
330 | mvmvif->queue_params[i].cw_min, | ||
331 | mvmvif->queue_params[i].cw_max, | ||
332 | mvmvif->queue_params[i].aifs, | ||
333 | mvmvif->queue_params[i].uapsd); | ||
334 | } | ||
335 | |||
336 | if (vif->type == NL80211_IFTYPE_STATION && | ||
337 | ap_sta_id != IWL_MVM_STATION_COUNT) { | ||
338 | struct ieee80211_sta *sta; | ||
339 | struct iwl_mvm_sta *mvm_sta; | ||
340 | |||
341 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id], | ||
342 | lockdep_is_held(&mvm->mutex)); | ||
343 | mvm_sta = (void *)sta->drv_priv; | ||
344 | pos += scnprintf(buf+pos, bufsz-pos, | ||
345 | "ap_sta_id %d - reduced Tx power %d\n", | ||
346 | ap_sta_id, mvm_sta->bt_reduced_txpower); | ||
347 | } | ||
348 | |||
349 | rcu_read_lock(); | ||
350 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
351 | if (chanctx_conf) { | ||
352 | pos += scnprintf(buf+pos, bufsz-pos, | ||
353 | "idle rx chains %d, active rx chains: %d\n", | ||
354 | chanctx_conf->rx_chains_static, | ||
355 | chanctx_conf->rx_chains_dynamic); | ||
356 | } | ||
357 | rcu_read_unlock(); | ||
358 | |||
359 | mutex_unlock(&mvm->mutex); | ||
360 | |||
361 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
362 | } | ||
363 | |||
364 | #define BT_MBOX_MSG(_notif, _num, _field) \ | ||
365 | ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\ | ||
366 | >> BT_MBOX##_num##_##_field##_POS) | ||
367 | |||
368 | |||
369 | #define BT_MBOX_PRINT(_num, _field, _end) \ | ||
370 | pos += scnprintf(buf + pos, bufsz - pos, \ | ||
371 | "\t%s: %d%s", \ | ||
372 | #_field, \ | ||
373 | BT_MBOX_MSG(notif, _num, _field), \ | ||
374 | true ? "\n" : ", "); | ||
375 | |||
376 | static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, | ||
377 | size_t count, loff_t *ppos) | ||
378 | { | ||
379 | struct iwl_mvm *mvm = file->private_data; | ||
380 | struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; | ||
381 | char *buf; | ||
382 | int ret, pos = 0, bufsz = sizeof(char) * 1024; | ||
383 | |||
384 | buf = kmalloc(bufsz, GFP_KERNEL); | ||
385 | if (!buf) | ||
386 | return -ENOMEM; | ||
387 | |||
388 | mutex_lock(&mvm->mutex); | ||
389 | |||
390 | pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n"); | ||
391 | |||
392 | BT_MBOX_PRINT(0, LE_SLAVE_LAT, false); | ||
393 | BT_MBOX_PRINT(0, LE_PROF1, false); | ||
394 | BT_MBOX_PRINT(0, LE_PROF2, false); | ||
395 | BT_MBOX_PRINT(0, LE_PROF_OTHER, false); | ||
396 | BT_MBOX_PRINT(0, CHL_SEQ_N, false); | ||
397 | BT_MBOX_PRINT(0, INBAND_S, false); | ||
398 | BT_MBOX_PRINT(0, LE_MIN_RSSI, false); | ||
399 | BT_MBOX_PRINT(0, LE_SCAN, false); | ||
400 | BT_MBOX_PRINT(0, LE_ADV, false); | ||
401 | BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false); | ||
402 | BT_MBOX_PRINT(0, OPEN_CON_1, true); | ||
403 | |||
404 | pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n"); | ||
405 | |||
406 | BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false); | ||
407 | BT_MBOX_PRINT(1, IP_SR, false); | ||
408 | BT_MBOX_PRINT(1, LE_MSTR, false); | ||
409 | BT_MBOX_PRINT(1, AGGR_TRFC_LD, false); | ||
410 | BT_MBOX_PRINT(1, MSG_TYPE, false); | ||
411 | BT_MBOX_PRINT(1, SSN, true); | ||
412 | |||
413 | pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n"); | ||
414 | |||
415 | BT_MBOX_PRINT(2, SNIFF_ACT, false); | ||
416 | BT_MBOX_PRINT(2, PAG, false); | ||
417 | BT_MBOX_PRINT(2, INQUIRY, false); | ||
418 | BT_MBOX_PRINT(2, CONN, false); | ||
419 | BT_MBOX_PRINT(2, SNIFF_INTERVAL, false); | ||
420 | BT_MBOX_PRINT(2, DISC, false); | ||
421 | BT_MBOX_PRINT(2, SCO_TX_ACT, false); | ||
422 | BT_MBOX_PRINT(2, SCO_RX_ACT, false); | ||
423 | BT_MBOX_PRINT(2, ESCO_RE_TX, false); | ||
424 | BT_MBOX_PRINT(2, SCO_DURATION, true); | ||
425 | |||
426 | pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n"); | ||
427 | |||
428 | BT_MBOX_PRINT(3, SCO_STATE, false); | ||
429 | BT_MBOX_PRINT(3, SNIFF_STATE, false); | ||
430 | BT_MBOX_PRINT(3, A2DP_STATE, false); | ||
431 | BT_MBOX_PRINT(3, ACL_STATE, false); | ||
432 | BT_MBOX_PRINT(3, MSTR_STATE, false); | ||
433 | BT_MBOX_PRINT(3, OBX_STATE, false); | ||
434 | BT_MBOX_PRINT(3, OPEN_CON_2, false); | ||
435 | BT_MBOX_PRINT(3, TRAFFIC_LOAD, false); | ||
436 | BT_MBOX_PRINT(3, CHL_SEQN_LSB, false); | ||
437 | BT_MBOX_PRINT(3, INBAND_P, false); | ||
438 | BT_MBOX_PRINT(3, MSG_TYPE_2, false); | ||
439 | BT_MBOX_PRINT(3, SSN_2, false); | ||
440 | BT_MBOX_PRINT(3, UPDATE_REQUEST, true); | ||
441 | |||
442 | pos += scnprintf(buf+pos, bufsz-pos, "bt_status = %d\n", | ||
443 | notif->bt_status); | ||
444 | pos += scnprintf(buf+pos, bufsz-pos, "bt_open_conn = %d\n", | ||
445 | notif->bt_open_conn); | ||
446 | pos += scnprintf(buf+pos, bufsz-pos, "bt_traffic_load = %d\n", | ||
447 | notif->bt_traffic_load); | ||
448 | pos += scnprintf(buf+pos, bufsz-pos, "bt_agg_traffic_load = %d\n", | ||
449 | notif->bt_agg_traffic_load); | ||
450 | pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n", | ||
451 | notif->bt_ci_compliance); | ||
452 | |||
453 | mutex_unlock(&mvm->mutex); | ||
454 | |||
455 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
456 | kfree(buf); | ||
457 | |||
458 | return ret; | ||
459 | } | ||
460 | #undef BT_MBOX_PRINT | ||
461 | |||
462 | static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, | ||
463 | const char __user *user_buf, | ||
464 | size_t count, loff_t *ppos) | ||
465 | { | ||
466 | struct iwl_mvm *mvm = file->private_data; | ||
467 | bool restart_fw = iwlwifi_mod_params.restart_fw; | ||
468 | int ret; | ||
469 | |||
470 | iwlwifi_mod_params.restart_fw = true; | ||
471 | |||
472 | mutex_lock(&mvm->mutex); | ||
473 | |||
474 | /* take the return value to make compiler happy - it will fail anyway */ | ||
475 | ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, CMD_SYNC, 0, NULL); | ||
476 | |||
477 | mutex_unlock(&mvm->mutex); | ||
478 | |||
479 | iwlwifi_mod_params.restart_fw = restart_fw; | ||
480 | |||
481 | return count; | ||
482 | } | ||
483 | |||
309 | #define MVM_DEBUGFS_READ_FILE_OPS(name) \ | 484 | #define MVM_DEBUGFS_READ_FILE_OPS(name) \ |
310 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | 485 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ |
311 | .read = iwl_dbgfs_##name##_read, \ | 486 | .read = iwl_dbgfs_##name##_read, \ |
312 | .open = iwl_dbgfs_open_file_generic, \ | 487 | .open = simple_open, \ |
313 | .llseek = generic_file_llseek, \ | 488 | .llseek = generic_file_llseek, \ |
314 | } | 489 | } |
315 | 490 | ||
@@ -317,14 +492,14 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ | |||
317 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | 492 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ |
318 | .write = iwl_dbgfs_##name##_write, \ | 493 | .write = iwl_dbgfs_##name##_write, \ |
319 | .read = iwl_dbgfs_##name##_read, \ | 494 | .read = iwl_dbgfs_##name##_read, \ |
320 | .open = iwl_dbgfs_open_file_generic, \ | 495 | .open = simple_open, \ |
321 | .llseek = generic_file_llseek, \ | 496 | .llseek = generic_file_llseek, \ |
322 | }; | 497 | }; |
323 | 498 | ||
324 | #define MVM_DEBUGFS_WRITE_FILE_OPS(name) \ | 499 | #define MVM_DEBUGFS_WRITE_FILE_OPS(name) \ |
325 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | 500 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ |
326 | .write = iwl_dbgfs_##name##_write, \ | 501 | .write = iwl_dbgfs_##name##_write, \ |
327 | .open = iwl_dbgfs_open_file_generic, \ | 502 | .open = simple_open, \ |
328 | .llseek = generic_file_llseek, \ | 503 | .llseek = generic_file_llseek, \ |
329 | }; | 504 | }; |
330 | 505 | ||
@@ -345,8 +520,13 @@ MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush); | |||
345 | MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain); | 520 | MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain); |
346 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram); | 521 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram); |
347 | MVM_DEBUGFS_READ_FILE_OPS(stations); | 522 | MVM_DEBUGFS_READ_FILE_OPS(stations); |
523 | MVM_DEBUGFS_READ_FILE_OPS(bt_notif); | ||
348 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow); | 524 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow); |
349 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow); | 525 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow); |
526 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart); | ||
527 | |||
528 | /* Interface specific debugfs entries */ | ||
529 | MVM_DEBUGFS_READ_FILE_OPS(mac_params); | ||
350 | 530 | ||
351 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | 531 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) |
352 | { | 532 | { |
@@ -358,8 +538,10 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | |||
358 | MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); | 538 | MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); |
359 | MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); | 539 | MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); |
360 | MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); | 540 | MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); |
541 | MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); | ||
361 | MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR); | 542 | MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR); |
362 | MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR); | 543 | MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR); |
544 | MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); | ||
363 | 545 | ||
364 | /* | 546 | /* |
365 | * Create a symlink with mac80211. It will be removed when mac80211 | 547 | * Create a symlink with mac80211. It will be removed when mac80211 |
@@ -376,3 +558,58 @@ err: | |||
376 | IWL_ERR(mvm, "Can't create the mvm debugfs directory\n"); | 558 | IWL_ERR(mvm, "Can't create the mvm debugfs directory\n"); |
377 | return -ENOMEM; | 559 | return -ENOMEM; |
378 | } | 560 | } |
561 | |||
562 | void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
563 | { | ||
564 | struct dentry *dbgfs_dir = vif->debugfs_dir; | ||
565 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
566 | char buf[100]; | ||
567 | |||
568 | if (!dbgfs_dir) | ||
569 | return; | ||
570 | |||
571 | mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); | ||
572 | mvmvif->dbgfs_data = mvm; | ||
573 | |||
574 | if (!mvmvif->dbgfs_dir) { | ||
575 | IWL_ERR(mvm, "Failed to create debugfs directory under %s\n", | ||
576 | dbgfs_dir->d_name.name); | ||
577 | return; | ||
578 | } | ||
579 | |||
580 | MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, | ||
581 | S_IRUSR); | ||
582 | |||
583 | /* | ||
584 | * Create symlink for convenience pointing to interface specific | ||
585 | * debugfs entries for the driver. For example, under | ||
586 | * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/ | ||
587 | * find | ||
588 | * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/ | ||
589 | */ | ||
590 | snprintf(buf, 100, "../../../%s/%s/%s/%s", | ||
591 | dbgfs_dir->d_parent->d_parent->d_name.name, | ||
592 | dbgfs_dir->d_parent->d_name.name, | ||
593 | dbgfs_dir->d_name.name, | ||
594 | mvmvif->dbgfs_dir->d_name.name); | ||
595 | |||
596 | mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name, | ||
597 | mvm->debugfs_dir, buf); | ||
598 | if (!mvmvif->dbgfs_slink) | ||
599 | IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n", | ||
600 | dbgfs_dir->d_name.name); | ||
601 | return; | ||
602 | err: | ||
603 | IWL_ERR(mvm, "Can't create debugfs entity\n"); | ||
604 | } | ||
605 | |||
606 | void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
607 | { | ||
608 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
609 | |||
610 | debugfs_remove(mvmvif->dbgfs_slink); | ||
611 | mvmvif->dbgfs_slink = NULL; | ||
612 | |||
613 | debugfs_remove_recursive(mvmvif->dbgfs_dir); | ||
614 | mvmvif->dbgfs_dir = NULL; | ||
615 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h new file mode 100644 index 000000000000..05c61d6f384e --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h | |||
@@ -0,0 +1,319 @@ | |||
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 | #ifndef __fw_api_bt_coex_h__ | ||
64 | #define __fw_api_bt_coex_h__ | ||
65 | |||
66 | #include <linux/types.h> | ||
67 | #include <linux/bitops.h> | ||
68 | |||
69 | #define BITS(nb) (BIT(nb) - 1) | ||
70 | |||
71 | /** | ||
72 | * enum iwl_bt_coex_flags - flags for BT_COEX command | ||
73 | * @BT_CH_PRIMARY_EN: | ||
74 | * @BT_CH_SECONDARY_EN: | ||
75 | * @BT_NOTIF_COEX_OFF: | ||
76 | * @BT_COEX_MODE_POS: | ||
77 | * @BT_COEX_MODE_MSK: | ||
78 | * @BT_COEX_DISABLE: | ||
79 | * @BT_COEX_2W: | ||
80 | * @BT_COEX_3W: | ||
81 | * @BT_COEX_NW: | ||
82 | * @BT_USE_DEFAULTS: | ||
83 | * @BT_SYNC_2_BT_DISABLE: | ||
84 | * @BT_COEX_CORUNNING_TBL_EN: | ||
85 | */ | ||
86 | enum iwl_bt_coex_flags { | ||
87 | BT_CH_PRIMARY_EN = BIT(0), | ||
88 | BT_CH_SECONDARY_EN = BIT(1), | ||
89 | BT_NOTIF_COEX_OFF = BIT(2), | ||
90 | BT_COEX_MODE_POS = 3, | ||
91 | BT_COEX_MODE_MSK = BITS(3) << BT_COEX_MODE_POS, | ||
92 | BT_COEX_DISABLE = 0x0 << BT_COEX_MODE_POS, | ||
93 | BT_COEX_2W = 0x1 << BT_COEX_MODE_POS, | ||
94 | BT_COEX_3W = 0x2 << BT_COEX_MODE_POS, | ||
95 | BT_COEX_NW = 0x3 << BT_COEX_MODE_POS, | ||
96 | BT_USE_DEFAULTS = BIT(6), | ||
97 | BT_SYNC_2_BT_DISABLE = BIT(7), | ||
98 | /* | ||
99 | * For future use - when the flags will be enlarged | ||
100 | * BT_COEX_CORUNNING_TBL_EN = BIT(8), | ||
101 | */ | ||
102 | }; | ||
103 | |||
104 | /* | ||
105 | * indicates what has changed in the BT_COEX command. | ||
106 | */ | ||
107 | enum iwl_bt_coex_valid_bit_msk { | ||
108 | BT_VALID_ENABLE = BIT(0), | ||
109 | BT_VALID_BT_PRIO_BOOST = BIT(1), | ||
110 | BT_VALID_MAX_KILL = BIT(2), | ||
111 | BT_VALID_3W_TMRS = BIT(3), | ||
112 | BT_VALID_KILL_ACK = BIT(4), | ||
113 | BT_VALID_KILL_CTS = BIT(5), | ||
114 | BT_VALID_REDUCED_TX_POWER = BIT(6), | ||
115 | BT_VALID_LUT = BIT(7), | ||
116 | BT_VALID_WIFI_RX_SW_PRIO_BOOST = BIT(8), | ||
117 | BT_VALID_WIFI_TX_SW_PRIO_BOOST = BIT(9), | ||
118 | BT_VALID_MULTI_PRIO_LUT = BIT(10), | ||
119 | BT_VALID_TRM_KICK_FILTER = BIT(11), | ||
120 | BT_VALID_CORUN_LUT_20 = BIT(12), | ||
121 | BT_VALID_CORUN_LUT_40 = BIT(13), | ||
122 | BT_VALID_ANT_ISOLATION = BIT(14), | ||
123 | BT_VALID_ANT_ISOLATION_THRS = BIT(15), | ||
124 | /* | ||
125 | * For future use - when the valid flags will be enlarged | ||
126 | * BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16), | ||
127 | * BT_VALID_TXRX_MAX_FREQ_0 = BIT(17), | ||
128 | */ | ||
129 | }; | ||
130 | |||
131 | /** | ||
132 | * enum iwl_bt_reduced_tx_power - allows to reduce txpower for WiFi frames. | ||
133 | * @BT_REDUCED_TX_POWER_CTL: reduce Tx power for control frames | ||
134 | * @BT_REDUCED_TX_POWER_DATA: reduce Tx power for data frames | ||
135 | * | ||
136 | * This mechanism allows to have BT and WiFi run concurrently. Since WiFi | ||
137 | * reduces its Tx power, it can work along with BT, hence reducing the amount | ||
138 | * of WiFi frames being killed by BT. | ||
139 | */ | ||
140 | enum iwl_bt_reduced_tx_power { | ||
141 | BT_REDUCED_TX_POWER_CTL = BIT(0), | ||
142 | BT_REDUCED_TX_POWER_DATA = BIT(1), | ||
143 | }; | ||
144 | |||
145 | #define BT_COEX_LUT_SIZE (12) | ||
146 | |||
147 | /** | ||
148 | * struct iwl_bt_coex_cmd - bt coex configuration command | ||
149 | * @flags:&enum iwl_bt_coex_flags | ||
150 | * @lead_time: | ||
151 | * @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 | ||
160 | * @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk | ||
161 | * @bt_prio_boost: values for PTA boost register | ||
162 | * @wifi_tx_prio_boost: SW boost of wifi tx priority | ||
163 | * @wifi_rx_prio_boost: SW boost of wifi rx priority | ||
164 | * | ||
165 | * The structure is used for the BT_COEX command. | ||
166 | */ | ||
167 | struct iwl_bt_coex_cmd { | ||
168 | u8 flags; | ||
169 | u8 lead_time; | ||
170 | u8 max_kill; | ||
171 | u8 bt3_time_t7_value; | ||
172 | __le32 kill_ack_msk; | ||
173 | __le32 kill_cts_msk; | ||
174 | u8 bt3_prio_sample_time; | ||
175 | u8 bt3_timer_t2_value; | ||
176 | __le16 bt4_reaction_time; | ||
177 | __le32 decision_lut[BT_COEX_LUT_SIZE]; | ||
178 | u8 bt_reduced_tx_power; | ||
179 | u8 reserved; | ||
180 | __le16 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 */ | ||
186 | |||
187 | #define BT_MBOX(n_dw, _msg, _pos, _nbits) \ | ||
188 | BT_MBOX##n_dw##_##_msg##_POS = (_pos), \ | ||
189 | BT_MBOX##n_dw##_##_msg = BITS(_nbits) << BT_MBOX##n_dw##_##_msg##_POS | ||
190 | |||
191 | enum iwl_bt_mxbox_dw0 { | ||
192 | BT_MBOX(0, LE_SLAVE_LAT, 0, 3), | ||
193 | BT_MBOX(0, LE_PROF1, 3, 1), | ||
194 | BT_MBOX(0, LE_PROF2, 4, 1), | ||
195 | BT_MBOX(0, LE_PROF_OTHER, 5, 1), | ||
196 | BT_MBOX(0, CHL_SEQ_N, 8, 4), | ||
197 | BT_MBOX(0, INBAND_S, 13, 1), | ||
198 | BT_MBOX(0, LE_MIN_RSSI, 16, 4), | ||
199 | BT_MBOX(0, LE_SCAN, 20, 1), | ||
200 | BT_MBOX(0, LE_ADV, 21, 1), | ||
201 | BT_MBOX(0, LE_MAX_TX_POWER, 24, 4), | ||
202 | BT_MBOX(0, OPEN_CON_1, 28, 2), | ||
203 | }; | ||
204 | |||
205 | enum iwl_bt_mxbox_dw1 { | ||
206 | BT_MBOX(1, BR_MAX_TX_POWER, 0, 4), | ||
207 | BT_MBOX(1, IP_SR, 4, 1), | ||
208 | BT_MBOX(1, LE_MSTR, 5, 1), | ||
209 | BT_MBOX(1, AGGR_TRFC_LD, 8, 6), | ||
210 | BT_MBOX(1, MSG_TYPE, 16, 3), | ||
211 | BT_MBOX(1, SSN, 19, 2), | ||
212 | }; | ||
213 | |||
214 | enum iwl_bt_mxbox_dw2 { | ||
215 | BT_MBOX(2, SNIFF_ACT, 0, 3), | ||
216 | BT_MBOX(2, PAG, 3, 1), | ||
217 | BT_MBOX(2, INQUIRY, 4, 1), | ||
218 | BT_MBOX(2, CONN, 5, 1), | ||
219 | BT_MBOX(2, SNIFF_INTERVAL, 8, 5), | ||
220 | BT_MBOX(2, DISC, 13, 1), | ||
221 | BT_MBOX(2, SCO_TX_ACT, 16, 2), | ||
222 | BT_MBOX(2, SCO_RX_ACT, 18, 2), | ||
223 | BT_MBOX(2, ESCO_RE_TX, 20, 2), | ||
224 | BT_MBOX(2, SCO_DURATION, 24, 6), | ||
225 | }; | ||
226 | |||
227 | enum iwl_bt_mxbox_dw3 { | ||
228 | BT_MBOX(3, SCO_STATE, 0, 1), | ||
229 | BT_MBOX(3, SNIFF_STATE, 1, 1), | ||
230 | BT_MBOX(3, A2DP_STATE, 2, 1), | ||
231 | BT_MBOX(3, ACL_STATE, 3, 1), | ||
232 | BT_MBOX(3, MSTR_STATE, 4, 1), | ||
233 | BT_MBOX(3, OBX_STATE, 5, 1), | ||
234 | BT_MBOX(3, OPEN_CON_2, 8, 2), | ||
235 | BT_MBOX(3, TRAFFIC_LOAD, 10, 2), | ||
236 | BT_MBOX(3, CHL_SEQN_LSB, 12, 1), | ||
237 | BT_MBOX(3, INBAND_P, 13, 1), | ||
238 | BT_MBOX(3, MSG_TYPE_2, 16, 3), | ||
239 | BT_MBOX(3, SSN_2, 19, 2), | ||
240 | BT_MBOX(3, UPDATE_REQUEST, 21, 1), | ||
241 | }; | ||
242 | |||
243 | #define BT_MBOX_MSG(_notif, _num, _field) \ | ||
244 | ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\ | ||
245 | >> BT_MBOX##_num##_##_field##_POS) | ||
246 | |||
247 | /** | ||
248 | * struct iwl_bt_coex_profile_notif - notification about BT coex | ||
249 | * @mbox_msg: message from BT to WiFi | ||
250 | * @:bt_status: 0 - off, 1 - on | ||
251 | * @:bt_open_conn: number of BT connections open | ||
252 | * @:bt_traffic_load: load of BT traffic | ||
253 | * @:bt_agg_traffic_load: aggregated load of BT traffic | ||
254 | * @:bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant | ||
255 | */ | ||
256 | struct iwl_bt_coex_profile_notif { | ||
257 | __le32 mbox_msg[4]; | ||
258 | u8 bt_status; | ||
259 | u8 bt_open_conn; | ||
260 | u8 bt_traffic_load; | ||
261 | u8 bt_agg_traffic_load; | ||
262 | u8 bt_ci_compliance; | ||
263 | u8 reserved[3]; | ||
264 | } __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_2 */ | ||
265 | |||
266 | enum iwl_bt_coex_prio_table_event { | ||
267 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0, | ||
268 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2 = 1, | ||
269 | BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1 = 2, | ||
270 | BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2 = 3, | ||
271 | BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1 = 4, | ||
272 | BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2 = 5, | ||
273 | BT_COEX_PRIO_TBL_EVT_DTIM = 6, | ||
274 | BT_COEX_PRIO_TBL_EVT_SCAN52 = 7, | ||
275 | BT_COEX_PRIO_TBL_EVT_SCAN24 = 8, | ||
276 | BT_COEX_PRIO_TBL_EVT_IDLE = 9, | ||
277 | BT_COEX_PRIO_TBL_EVT_MAX = 16, | ||
278 | }; /* BT_COEX_PRIO_TABLE_EVENTS_API_E_VER_1 */ | ||
279 | |||
280 | enum iwl_bt_coex_prio_table_prio { | ||
281 | BT_COEX_PRIO_TBL_DISABLED = 0, | ||
282 | BT_COEX_PRIO_TBL_PRIO_LOW = 1, | ||
283 | BT_COEX_PRIO_TBL_PRIO_HIGH = 2, | ||
284 | BT_COEX_PRIO_TBL_PRIO_BYPASS = 3, | ||
285 | BT_COEX_PRIO_TBL_PRIO_COEX_OFF = 4, | ||
286 | BT_COEX_PRIO_TBL_PRIO_COEX_ON = 5, | ||
287 | BT_COEX_PRIO_TBL_PRIO_COEX_IDLE = 6, | ||
288 | BT_COEX_PRIO_TBL_MAX = 8, | ||
289 | }; /* BT_COEX_PRIO_TABLE_PRIORITIES_API_E_VER_1 */ | ||
290 | |||
291 | #define BT_COEX_PRIO_TBL_SHRD_ANT_POS (0) | ||
292 | #define BT_COEX_PRIO_TBL_PRIO_POS (1) | ||
293 | #define BT_COEX_PRIO_TBL_RESERVED_POS (4) | ||
294 | |||
295 | /** | ||
296 | * struct iwl_bt_coex_prio_tbl_cmd - priority table for BT coex | ||
297 | * @prio_tbl: | ||
298 | */ | ||
299 | struct iwl_bt_coex_prio_tbl_cmd { | ||
300 | u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX]; | ||
301 | } __packed; | ||
302 | |||
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__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index cf6f9a02fb74..51e015d1dfb2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -258,7 +258,7 @@ enum iwl_wowlan_wakeup_reason { | |||
258 | IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE = BIT(8), | 258 | IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE = BIT(8), |
259 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS = BIT(9), | 259 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS = BIT(9), |
260 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE = BIT(10), | 260 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE = BIT(10), |
261 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_TCP_EXTERNAL = BIT(11), | 261 | /* BIT(11) reserved */ |
262 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12), | 262 | IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12), |
263 | }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */ | 263 | }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */ |
264 | 264 | ||
@@ -277,6 +277,55 @@ struct iwl_wowlan_status { | |||
277 | u8 wake_packet[]; /* can be truncated from _length to _bufsize */ | 277 | u8 wake_packet[]; /* can be truncated from _length to _bufsize */ |
278 | } __packed; /* WOWLAN_STATUSES_API_S_VER_4 */ | 278 | } __packed; /* WOWLAN_STATUSES_API_S_VER_4 */ |
279 | 279 | ||
280 | #define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64 | ||
281 | #define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128 | ||
282 | #define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS 2048 | ||
283 | |||
284 | struct iwl_tcp_packet_info { | ||
285 | __le16 tcp_pseudo_header_checksum; | ||
286 | __le16 tcp_payload_length; | ||
287 | } __packed; /* TCP_PACKET_INFO_API_S_VER_2 */ | ||
288 | |||
289 | struct iwl_tcp_packet { | ||
290 | struct iwl_tcp_packet_info info; | ||
291 | u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8]; | ||
292 | u8 data[IWL_WOWLAN_TCP_MAX_PACKET_LEN]; | ||
293 | } __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */ | ||
294 | |||
295 | struct iwl_remote_wake_packet { | ||
296 | struct iwl_tcp_packet_info info; | ||
297 | u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8]; | ||
298 | u8 data[IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN]; | ||
299 | } __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */ | ||
300 | |||
301 | struct iwl_wowlan_remote_wake_config { | ||
302 | __le32 connection_max_time; /* unused */ | ||
303 | /* TCP_PROTOCOL_CONFIG_API_S_VER_1 */ | ||
304 | u8 max_syn_retries; | ||
305 | u8 max_data_retries; | ||
306 | u8 tcp_syn_ack_timeout; | ||
307 | u8 tcp_ack_timeout; | ||
308 | |||
309 | struct iwl_tcp_packet syn_tx; | ||
310 | struct iwl_tcp_packet synack_rx; | ||
311 | struct iwl_tcp_packet keepalive_ack_rx; | ||
312 | struct iwl_tcp_packet fin_tx; | ||
313 | |||
314 | struct iwl_remote_wake_packet keepalive_tx; | ||
315 | struct iwl_remote_wake_packet wake_rx; | ||
316 | |||
317 | /* REMOTE_WAKE_OFFSET_INFO_API_S_VER_1 */ | ||
318 | u8 sequence_number_offset; | ||
319 | u8 sequence_number_length; | ||
320 | u8 token_offset; | ||
321 | u8 token_length; | ||
322 | /* REMOTE_WAKE_PROTOCOL_PARAMS_API_S_VER_1 */ | ||
323 | __le32 initial_sequence_number; | ||
324 | __le16 keepalive_interval; | ||
325 | __le16 num_tokens; | ||
326 | u8 tokens[IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS]; | ||
327 | } __packed; /* REMOTE_WAKE_CONFIG_API_S_VER_2 */ | ||
328 | |||
280 | /* TODO: NetDetect API */ | 329 | /* TODO: NetDetect API */ |
281 | 330 | ||
282 | #endif /* __fw_api_d3_h__ */ | 331 | #endif /* __fw_api_d3_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h index ae39b7dfda7b..d68640ea41d4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index be36b7604b7f..81fe45f46be7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -68,73 +68,53 @@ | |||
68 | 68 | ||
69 | /** | 69 | /** |
70 | * enum iwl_scan_flags - masks for power table command flags | 70 | * enum iwl_scan_flags - masks for power table command flags |
71 | * @POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off | ||
72 | * receiver and transmitter. '0' - does not allow. | ||
71 | * @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management, | 73 | * @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management, |
72 | * '1' Driver enables PM (use rest of parameters) | 74 | * '1' Driver enables PM (use rest of parameters) |
73 | * @POWER_FLAGS_SLEEP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM, | 75 | * @POWER_FLAGS_SKIP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM, |
74 | * '1' PM could sleep over DTIM till listen Interval. | 76 | * '1' PM could sleep over DTIM till listen Interval. |
75 | * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. | ||
76 | * @POWER_FLAGS_SNOOZE_ENA_MSK: Enable snoozing only if uAPSD is enabled and all | ||
77 | * access categories are both delivery and trigger enabled. | ||
78 | * @POWER_FLAGS_BT_SCO_ENA: Enable BT SCO coex only if uAPSD and | ||
79 | * PBW Snoozing enabled | ||
80 | * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask | 77 | * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask |
78 | * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. | ||
81 | */ | 79 | */ |
82 | enum iwl_power_flags { | 80 | enum iwl_power_flags { |
83 | POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(0), | 81 | POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0), |
84 | POWER_FLAGS_SLEEP_OVER_DTIM_MSK = BIT(1), | 82 | POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(1), |
85 | POWER_FLAGS_LPRX_ENA_MSK = BIT(2), | 83 | POWER_FLAGS_SKIP_OVER_DTIM_MSK = BIT(2), |
86 | POWER_FLAGS_SNOOZE_ENA_MSK = BIT(3), | 84 | POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(9), |
87 | POWER_FLAGS_BT_SCO_ENA = BIT(4), | 85 | POWER_FLAGS_LPRX_ENA_MSK = BIT(11), |
88 | POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(5) | ||
89 | }; | 86 | }; |
90 | 87 | ||
88 | #define IWL_POWER_VEC_SIZE 5 | ||
89 | |||
91 | /** | 90 | /** |
92 | * struct iwl_powertable_cmd - Power Table Command | 91 | * struct iwl_powertable_cmd - Power Table Command |
93 | * POWER_TABLE_CMD = 0x77 (command, has simple generic response) | 92 | * POWER_TABLE_CMD = 0x77 (command, has simple generic response) |
94 | * | 93 | * |
95 | * @id_and_color: MAC contex identifier | ||
96 | * @action: Action on context - no action, add new, | ||
97 | * modify existent, remove | ||
98 | * @flags: Power table command flags from POWER_FLAGS_* | 94 | * @flags: Power table command flags from POWER_FLAGS_* |
99 | * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. | 95 | * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. |
100 | * Minimum allowed:- 3 * DTIM | 96 | * Minimum allowed:- 3 * DTIM. Keep alive period must be |
97 | * set regardless of power scheme or current power state. | ||
98 | * FW use this value also when PM is disabled. | ||
101 | * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to | 99 | * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to |
102 | * PSM transition - legacy PM | 100 | * PSM transition - legacy PM |
103 | * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to | 101 | * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to |
104 | * PSM transition - legacy PM | 102 | * PSM transition - legacy PM |
105 | * @rx_data_timeout_uapsd: Minimum time (usec) from last Rx packet for AM to | 103 | * @sleep_interval: not in use |
106 | * PSM transition - uAPSD | 104 | * @keep_alive_beacons: not in use |
107 | * @tx_data_timeout_uapsd: Minimum time (usec) from last Tx packet for AM to | ||
108 | * PSM transition - uAPSD | ||
109 | * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. | 105 | * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. |
110 | * Default: 80dbm | 106 | * Default: 80dbm |
111 | * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set | ||
112 | * @snooze_interval: TBD | ||
113 | * @snooze_window: TBD | ||
114 | * @snooze_step: TBD | ||
115 | * @qndp_tid: TBD | ||
116 | * @uapsd_ac_flags: TBD | ||
117 | * @uapsd_max_sp: TBD | ||
118 | */ | 107 | */ |
119 | struct iwl_powertable_cmd { | 108 | struct iwl_powertable_cmd { |
120 | /* COMMON_INDEX_HDR_API_S_VER_1 */ | 109 | /* PM_POWER_TABLE_CMD_API_S_VER_5 */ |
121 | __le32 id_and_color; | ||
122 | __le32 action; | ||
123 | __le16 flags; | 110 | __le16 flags; |
124 | u8 reserved; | 111 | u8 keep_alive_seconds; |
125 | __le16 keep_alive_seconds; | 112 | u8 debug_flags; |
126 | __le32 rx_data_timeout; | 113 | __le32 rx_data_timeout; |
127 | __le32 tx_data_timeout; | 114 | __le32 tx_data_timeout; |
128 | __le32 rx_data_timeout_uapsd; | 115 | __le32 sleep_interval[IWL_POWER_VEC_SIZE]; |
129 | __le32 tx_data_timeout_uapsd; | 116 | __le32 keep_alive_beacons; |
130 | u8 lprx_rssi_threshold; | 117 | __le32 lprx_rssi_threshold; |
131 | u8 num_skip_dtim; | ||
132 | __le16 snooze_interval; | ||
133 | __le16 snooze_window; | ||
134 | u8 snooze_step; | ||
135 | u8 qndp_tid; | ||
136 | u8 uapsd_ac_flags; | ||
137 | u8 uapsd_max_sp; | ||
138 | } __packed; | 118 | } __packed; |
139 | 119 | ||
140 | #endif | 120 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h index aa3474d08231..fdd33bc0a594 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 670ac8f95e26..b60d14151721 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h index 0acb53dda22d..a30691a8a85b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index 2677914bf0a6..007a93b25bd7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -537,6 +537,12 @@ struct iwl_mac_beacon_cmd { | |||
537 | struct ieee80211_hdr frame[0]; | 537 | struct ieee80211_hdr frame[0]; |
538 | } __packed; | 538 | } __packed; |
539 | 539 | ||
540 | struct iwl_beacon_notif { | ||
541 | struct iwl_mvm_tx_resp beacon_notify_hdr; | ||
542 | __le64 tsf; | ||
543 | __le32 ibss_mgr_status; | ||
544 | } __packed; | ||
545 | |||
540 | /** | 546 | /** |
541 | * enum iwl_dump_control - dump (flush) control flags | 547 | * enum iwl_dump_control - dump (flush) control flags |
542 | * @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty | 548 | * @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 23eebda848b0..191dcae8ba47 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -70,6 +70,7 @@ | |||
70 | #include "fw-api-mac.h" | 70 | #include "fw-api-mac.h" |
71 | #include "fw-api-power.h" | 71 | #include "fw-api-power.h" |
72 | #include "fw-api-d3.h" | 72 | #include "fw-api-d3.h" |
73 | #include "fw-api-bt-coex.h" | ||
73 | 74 | ||
74 | /* queue and FIFO numbers by usage */ | 75 | /* queue and FIFO numbers by usage */ |
75 | enum { | 76 | enum { |
@@ -150,8 +151,10 @@ enum { | |||
150 | 151 | ||
151 | SET_CALIB_DEFAULT_CMD = 0x8e, | 152 | SET_CALIB_DEFAULT_CMD = 0x8e, |
152 | 153 | ||
154 | BEACON_NOTIFICATION = 0x90, | ||
153 | BEACON_TEMPLATE_CMD = 0x91, | 155 | BEACON_TEMPLATE_CMD = 0x91, |
154 | TX_ANT_CONFIGURATION_CMD = 0x98, | 156 | TX_ANT_CONFIGURATION_CMD = 0x98, |
157 | BT_CONFIG = 0x9b, | ||
155 | STATISTICS_NOTIFICATION = 0x9d, | 158 | STATISTICS_NOTIFICATION = 0x9d, |
156 | 159 | ||
157 | /* RF-KILL commands and notifications */ | 160 | /* RF-KILL commands and notifications */ |
@@ -162,6 +165,11 @@ enum { | |||
162 | REPLY_RX_MPDU_CMD = 0xc1, | 165 | REPLY_RX_MPDU_CMD = 0xc1, |
163 | BA_NOTIF = 0xc5, | 166 | BA_NOTIF = 0xc5, |
164 | 167 | ||
168 | /* BT Coex */ | ||
169 | BT_COEX_PRIO_TABLE = 0xcc, | ||
170 | BT_COEX_PROT_ENV = 0xcd, | ||
171 | BT_PROFILE_NOTIFICATION = 0xce, | ||
172 | |||
165 | REPLY_DEBUG_CMD = 0xf0, | 173 | REPLY_DEBUG_CMD = 0xf0, |
166 | DEBUG_LOG_MSG = 0xf7, | 174 | DEBUG_LOG_MSG = 0xf7, |
167 | 175 | ||
@@ -271,38 +279,7 @@ enum { | |||
271 | NVM_ACCESS_TARGET_EEPROM = 2, | 279 | NVM_ACCESS_TARGET_EEPROM = 2, |
272 | }; | 280 | }; |
273 | 281 | ||
274 | /** | 282 | /* Section types for NVM_ACCESS_CMD */ |
275 | * struct iwl_nvm_access_cmd_ver1 - Request the device to send the NVM. | ||
276 | * @op_code: 0 - read, 1 - write. | ||
277 | * @target: NVM_ACCESS_TARGET_*. should be 0 for read. | ||
278 | * @cache_refresh: 0 - None, 1- NVM. | ||
279 | * @offset: offset in the nvm data. | ||
280 | * @length: of the chunk. | ||
281 | * @data: empty on read, the NVM chunk on write | ||
282 | */ | ||
283 | struct iwl_nvm_access_cmd_ver1 { | ||
284 | u8 op_code; | ||
285 | u8 target; | ||
286 | u8 cache_refresh; | ||
287 | u8 reserved; | ||
288 | __le16 offset; | ||
289 | __le16 length; | ||
290 | u8 data[]; | ||
291 | } __packed; /* NVM_ACCESS_CMD_API_S_VER_1 */ | ||
292 | |||
293 | /** | ||
294 | * struct iwl_nvm_access_resp_ver1 - response to NVM_ACCESS_CMD | ||
295 | * @offset: the offset in the nvm data | ||
296 | * @length: of the chunk | ||
297 | * @data: the nvm chunk on when NVM_ACCESS_CMD was read, nothing on write | ||
298 | */ | ||
299 | struct iwl_nvm_access_resp_ver1 { | ||
300 | __le16 offset; | ||
301 | __le16 length; | ||
302 | u8 data[]; | ||
303 | } __packed; /* NVM_ACCESS_CMD_RESP_API_S_VER_1 */ | ||
304 | |||
305 | /* Section types for NVM_ACCESS_CMD version 2 */ | ||
306 | enum { | 283 | enum { |
307 | NVM_SECTION_TYPE_HW = 0, | 284 | NVM_SECTION_TYPE_HW = 0, |
308 | NVM_SECTION_TYPE_SW, | 285 | NVM_SECTION_TYPE_SW, |
@@ -323,7 +300,7 @@ enum { | |||
323 | * @length: in bytes, to read/write | 300 | * @length: in bytes, to read/write |
324 | * @data: if write operation, the data to write. On read its empty | 301 | * @data: if write operation, the data to write. On read its empty |
325 | */ | 302 | */ |
326 | struct iwl_nvm_access_cmd_ver2 { | 303 | struct iwl_nvm_access_cmd { |
327 | u8 op_code; | 304 | u8 op_code; |
328 | u8 target; | 305 | u8 target; |
329 | __le16 type; | 306 | __le16 type; |
@@ -340,7 +317,7 @@ struct iwl_nvm_access_cmd_ver2 { | |||
340 | * @status: 0 for success, fail otherwise | 317 | * @status: 0 for success, fail otherwise |
341 | * @data: if read operation, the data returned. Empty on write. | 318 | * @data: if read operation, the data returned. Empty on write. |
342 | */ | 319 | */ |
343 | struct iwl_nvm_access_resp_ver2 { | 320 | struct iwl_nvm_access_resp { |
344 | __le16 offset; | 321 | __le16 offset; |
345 | __le16 length; | 322 | __le16 length; |
346 | __le16 type; | 323 | __le16 type; |
@@ -503,15 +480,34 @@ enum { | |||
503 | TE_DEP_TSF = 2, | 480 | TE_DEP_TSF = 2, |
504 | TE_EVENT_SOCIOPATHIC = 4, | 481 | TE_EVENT_SOCIOPATHIC = 4, |
505 | }; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ | 482 | }; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ |
506 | 483 | /* | |
507 | /* When to send Time Event notifications and to whom (internal = FW) */ | 484 | * Supported Time event notifications configuration. |
485 | * A notification (both event and fragment) includes a status indicating weather | ||
486 | * the FW was able to schedule the event or not. For fragment start/end | ||
487 | * notification the status is always success. There is no start/end fragment | ||
488 | * notification for monolithic events. | ||
489 | * | ||
490 | * @TE_NOTIF_NONE: no notifications | ||
491 | * @TE_NOTIF_HOST_EVENT_START: request/receive notification on event start | ||
492 | * @TE_NOTIF_HOST_EVENT_END:request/receive notification on event end | ||
493 | * @TE_NOTIF_INTERNAL_EVENT_START: internal FW use | ||
494 | * @TE_NOTIF_INTERNAL_EVENT_END: internal FW use. | ||
495 | * @TE_NOTIF_HOST_FRAG_START: request/receive notification on frag start | ||
496 | * @TE_NOTIF_HOST_FRAG_END:request/receive notification on frag end | ||
497 | * @TE_NOTIF_INTERNAL_FRAG_START: internal FW use. | ||
498 | * @TE_NOTIF_INTERNAL_FRAG_END: internal FW use. | ||
499 | */ | ||
508 | enum { | 500 | enum { |
509 | TE_NOTIF_NONE = 0, | 501 | TE_NOTIF_NONE = 0, |
510 | TE_NOTIF_HOST_START = 0x1, | 502 | TE_NOTIF_HOST_EVENT_START = 0x1, |
511 | TE_NOTIF_HOST_END = 0x2, | 503 | TE_NOTIF_HOST_EVENT_END = 0x2, |
512 | TE_NOTIF_INTERNAL_START = 0x4, | 504 | TE_NOTIF_INTERNAL_EVENT_START = 0x4, |
513 | TE_NOTIF_INTERNAL_END = 0x8 | 505 | TE_NOTIF_INTERNAL_EVENT_END = 0x8, |
514 | }; /* MAC_EVENT_ACTION_API_E_VER_1 */ | 506 | TE_NOTIF_HOST_FRAG_START = 0x10, |
507 | TE_NOTIF_HOST_FRAG_END = 0x20, | ||
508 | TE_NOTIF_INTERNAL_FRAG_START = 0x40, | ||
509 | TE_NOTIF_INTERNAL_FRAG_END = 0x80 | ||
510 | }; /* MAC_EVENT_ACTION_API_E_VER_2 */ | ||
515 | 511 | ||
516 | /* | 512 | /* |
517 | * @TE_FRAG_NONE: fragmentation of the time event is NOT allowed. | 513 | * @TE_FRAG_NONE: fragmentation of the time event is NOT allowed. |
@@ -762,18 +758,20 @@ struct iwl_phy_context_cmd { | |||
762 | #define IWL_RX_INFO_PHY_CNT 8 | 758 | #define IWL_RX_INFO_PHY_CNT 8 |
763 | #define IWL_RX_INFO_AGC_IDX 1 | 759 | #define IWL_RX_INFO_AGC_IDX 1 |
764 | #define IWL_RX_INFO_RSSI_AB_IDX 2 | 760 | #define IWL_RX_INFO_RSSI_AB_IDX 2 |
765 | #define IWL_RX_INFO_RSSI_C_IDX 3 | 761 | #define IWL_OFDM_AGC_A_MSK 0x0000007f |
766 | #define IWL_OFDM_AGC_DB_MSK 0xfe00 | 762 | #define IWL_OFDM_AGC_A_POS 0 |
767 | #define IWL_OFDM_AGC_DB_POS 9 | 763 | #define IWL_OFDM_AGC_B_MSK 0x00003f80 |
764 | #define IWL_OFDM_AGC_B_POS 7 | ||
765 | #define IWL_OFDM_AGC_CODE_MSK 0x3fe00000 | ||
766 | #define IWL_OFDM_AGC_CODE_POS 20 | ||
768 | #define IWL_OFDM_RSSI_INBAND_A_MSK 0x00ff | 767 | #define IWL_OFDM_RSSI_INBAND_A_MSK 0x00ff |
769 | #define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00 | ||
770 | #define IWL_OFDM_RSSI_A_POS 0 | 768 | #define IWL_OFDM_RSSI_A_POS 0 |
769 | #define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00 | ||
770 | #define IWL_OFDM_RSSI_ALLBAND_A_POS 8 | ||
771 | #define IWL_OFDM_RSSI_INBAND_B_MSK 0xff0000 | 771 | #define IWL_OFDM_RSSI_INBAND_B_MSK 0xff0000 |
772 | #define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000 | ||
773 | #define IWL_OFDM_RSSI_B_POS 16 | 772 | #define IWL_OFDM_RSSI_B_POS 16 |
774 | #define IWL_OFDM_RSSI_INBAND_C_MSK 0x00ff | 773 | #define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000 |
775 | #define IWL_OFDM_RSSI_ALLBAND_C_MSK 0xff00 | 774 | #define IWL_OFDM_RSSI_ALLBAND_B_POS 24 |
776 | #define IWL_OFDM_RSSI_C_POS 0 | ||
777 | 775 | ||
778 | /** | 776 | /** |
779 | * struct iwl_rx_phy_info - phy info | 777 | * struct iwl_rx_phy_info - phy info |
@@ -792,6 +790,7 @@ struct iwl_phy_context_cmd { | |||
792 | * @byte_count: frame's byte-count | 790 | * @byte_count: frame's byte-count |
793 | * @frame_time: frame's time on the air, based on byte count and frame rate | 791 | * @frame_time: frame's time on the air, based on byte count and frame rate |
794 | * calculation | 792 | * calculation |
793 | * @mac_active_msk: what MACs were active when the frame was received | ||
795 | * | 794 | * |
796 | * Before each Rx, the device sends this data. It contains PHY information | 795 | * Before each Rx, the device sends this data. It contains PHY information |
797 | * about the reception of the packet. | 796 | * about the reception of the packet. |
@@ -809,7 +808,7 @@ struct iwl_rx_phy_info { | |||
809 | __le32 non_cfg_phy[IWL_RX_INFO_PHY_CNT]; | 808 | __le32 non_cfg_phy[IWL_RX_INFO_PHY_CNT]; |
810 | __le32 rate_n_flags; | 809 | __le32 rate_n_flags; |
811 | __le32 byte_count; | 810 | __le32 byte_count; |
812 | __le16 reserved2; | 811 | __le16 mac_active_msk; |
813 | __le16 frame_time; | 812 | __le16 frame_time; |
814 | } __packed; | 813 | } __packed; |
815 | 814 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index d3d959db03a9..e18c92dd60ec 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -79,17 +79,8 @@ | |||
79 | #define UCODE_VALID_OK cpu_to_le32(0x1) | 79 | #define UCODE_VALID_OK cpu_to_le32(0x1) |
80 | 80 | ||
81 | /* Default calibration values for WkP - set to INIT image w/o running */ | 81 | /* Default calibration values for WkP - set to INIT image w/o running */ |
82 | static const u8 wkp_calib_values_bb_filter[] = { 0xbf, 0x00, 0x5f, 0x00, 0x2f, | ||
83 | 0x00, 0x18, 0x00 }; | ||
84 | static const u8 wkp_calib_values_rx_dc[] = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, | ||
85 | 0x7f, 0x7f, 0x7f }; | ||
86 | static const u8 wkp_calib_values_tx_lo[] = { 0x00, 0x00, 0x00, 0x00 }; | ||
87 | static const u8 wkp_calib_values_tx_iq[] = { 0xff, 0x00, 0xff, 0x00, 0x00, | ||
88 | 0x00 }; | ||
89 | static const u8 wkp_calib_values_rx_iq[] = { 0xff, 0x00, 0x00, 0x00 }; | ||
90 | static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 }; | 82 | static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 }; |
91 | static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 }; | 83 | static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 }; |
92 | static const u8 wkp_calib_values_xtal[] = { 0xd2, 0xd2 }; | ||
93 | 84 | ||
94 | struct iwl_calib_default_data { | 85 | struct iwl_calib_default_data { |
95 | u16 size; | 86 | u16 size; |
@@ -99,12 +90,7 @@ struct iwl_calib_default_data { | |||
99 | #define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf} | 90 | #define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf} |
100 | 91 | ||
101 | static const struct iwl_calib_default_data wkp_calib_default_data[12] = { | 92 | static const struct iwl_calib_default_data wkp_calib_default_data[12] = { |
102 | [5] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_dc), | ||
103 | [6] = CALIB_SIZE_N_DATA(wkp_calib_values_bb_filter), | ||
104 | [7] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_lo), | ||
105 | [8] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq), | ||
106 | [9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew), | 93 | [9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew), |
107 | [10] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq), | ||
108 | [11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew), | 94 | [11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew), |
109 | }; | 95 | }; |
110 | 96 | ||
@@ -128,7 +114,7 @@ static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant) | |||
128 | .valid = cpu_to_le32(valid_tx_ant), | 114 | .valid = cpu_to_le32(valid_tx_ant), |
129 | }; | 115 | }; |
130 | 116 | ||
131 | IWL_DEBUG_HC(mvm, "select valid tx ant: %u\n", valid_tx_ant); | 117 | IWL_DEBUG_FW(mvm, "select valid tx ant: %u\n", valid_tx_ant); |
132 | return iwl_mvm_send_cmd_pdu(mvm, TX_ANT_CONFIGURATION_CMD, CMD_SYNC, | 118 | return iwl_mvm_send_cmd_pdu(mvm, TX_ANT_CONFIGURATION_CMD, CMD_SYNC, |
133 | sizeof(tx_ant_cmd), &tx_ant_cmd); | 119 | sizeof(tx_ant_cmd), &tx_ant_cmd); |
134 | } | 120 | } |
@@ -148,9 +134,10 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, | |||
148 | alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr); | 134 | alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr); |
149 | 135 | ||
150 | alive_data->valid = le16_to_cpu(palive->status) == IWL_ALIVE_STATUS_OK; | 136 | alive_data->valid = le16_to_cpu(palive->status) == IWL_ALIVE_STATUS_OK; |
151 | IWL_DEBUG_FW(mvm, "Alive ucode status 0x%04x revision 0x%01X 0x%01X\n", | 137 | IWL_DEBUG_FW(mvm, |
138 | "Alive ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n", | ||
152 | le16_to_cpu(palive->status), palive->ver_type, | 139 | le16_to_cpu(palive->status), palive->ver_type, |
153 | palive->ver_subtype); | 140 | palive->ver_subtype, palive->flags); |
154 | 141 | ||
155 | return true; | 142 | return true; |
156 | } | 143 | } |
@@ -241,20 +228,6 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, | |||
241 | 228 | ||
242 | return 0; | 229 | return 0; |
243 | } | 230 | } |
244 | #define IWL_HW_REV_ID_RAINBOW 0x2 | ||
245 | #define IWL_PROJ_TYPE_LHP 0x5 | ||
246 | |||
247 | static u32 iwl_mvm_build_phy_cfg(struct iwl_mvm *mvm) | ||
248 | { | ||
249 | struct iwl_nvm_data *data = mvm->nvm_data; | ||
250 | /* Temp calls to static definitions, will be changed to CSR calls */ | ||
251 | u8 hw_rev_id = IWL_HW_REV_ID_RAINBOW; | ||
252 | u8 project_type = IWL_PROJ_TYPE_LHP; | ||
253 | |||
254 | return data->radio_cfg_dash | (data->radio_cfg_step << 2) | | ||
255 | (hw_rev_id << 4) | ((project_type & 0x7f) << 6) | | ||
256 | (data->valid_tx_ant << 16) | (data->valid_rx_ant << 20); | ||
257 | } | ||
258 | 231 | ||
259 | static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) | 232 | static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) |
260 | { | 233 | { |
@@ -262,7 +235,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) | |||
262 | enum iwl_ucode_type ucode_type = mvm->cur_ucode; | 235 | enum iwl_ucode_type ucode_type = mvm->cur_ucode; |
263 | 236 | ||
264 | /* Set parameters */ | 237 | /* Set parameters */ |
265 | phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_build_phy_cfg(mvm)); | 238 | phy_cfg_cmd.phy_cfg = cpu_to_le32(mvm->fw->phy_config); |
266 | phy_cfg_cmd.calib_control.event_trigger = | 239 | phy_cfg_cmd.calib_control.event_trigger = |
267 | mvm->fw->default_calib[ucode_type].event_trigger; | 240 | mvm->fw->default_calib[ucode_type].event_trigger; |
268 | phy_cfg_cmd.calib_control.flow_trigger = | 241 | phy_cfg_cmd.calib_control.flow_trigger = |
@@ -275,103 +248,6 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) | |||
275 | sizeof(phy_cfg_cmd), &phy_cfg_cmd); | 248 | sizeof(phy_cfg_cmd), &phy_cfg_cmd); |
276 | } | 249 | } |
277 | 250 | ||
278 | /* Starting with the new PHY DB implementation - New calibs are enabled */ | ||
279 | /* Value - 0x405e7 */ | ||
280 | #define IWL_CALIB_DEFAULT_FLOW_INIT (IWL_CALIB_CFG_XTAL_IDX |\ | ||
281 | IWL_CALIB_CFG_TEMPERATURE_IDX |\ | ||
282 | IWL_CALIB_CFG_VOLTAGE_READ_IDX |\ | ||
283 | IWL_CALIB_CFG_DC_IDX |\ | ||
284 | IWL_CALIB_CFG_BB_FILTER_IDX |\ | ||
285 | IWL_CALIB_CFG_LO_LEAKAGE_IDX |\ | ||
286 | IWL_CALIB_CFG_TX_IQ_IDX |\ | ||
287 | IWL_CALIB_CFG_RX_IQ_IDX |\ | ||
288 | IWL_CALIB_CFG_AGC_IDX) | ||
289 | |||
290 | #define IWL_CALIB_DEFAULT_EVENT_INIT 0x0 | ||
291 | |||
292 | /* Value 0x41567 */ | ||
293 | #define IWL_CALIB_DEFAULT_FLOW_RUN (IWL_CALIB_CFG_XTAL_IDX |\ | ||
294 | IWL_CALIB_CFG_TEMPERATURE_IDX |\ | ||
295 | IWL_CALIB_CFG_VOLTAGE_READ_IDX |\ | ||
296 | IWL_CALIB_CFG_BB_FILTER_IDX |\ | ||
297 | IWL_CALIB_CFG_DC_IDX |\ | ||
298 | IWL_CALIB_CFG_TX_IQ_IDX |\ | ||
299 | IWL_CALIB_CFG_RX_IQ_IDX |\ | ||
300 | IWL_CALIB_CFG_SENSITIVITY_IDX |\ | ||
301 | IWL_CALIB_CFG_AGC_IDX) | ||
302 | |||
303 | #define IWL_CALIB_DEFAULT_EVENT_RUN (IWL_CALIB_CFG_XTAL_IDX |\ | ||
304 | IWL_CALIB_CFG_TEMPERATURE_IDX |\ | ||
305 | IWL_CALIB_CFG_VOLTAGE_READ_IDX |\ | ||
306 | IWL_CALIB_CFG_TX_PWR_IDX |\ | ||
307 | IWL_CALIB_CFG_DC_IDX |\ | ||
308 | IWL_CALIB_CFG_TX_IQ_IDX |\ | ||
309 | IWL_CALIB_CFG_SENSITIVITY_IDX) | ||
310 | |||
311 | /* | ||
312 | * Sets the calibrations trigger values that will be sent to the FW for runtime | ||
313 | * and init calibrations. | ||
314 | * The ones given in the FW TLV are not correct. | ||
315 | */ | ||
316 | static void iwl_set_default_calib_trigger(struct iwl_mvm *mvm) | ||
317 | { | ||
318 | struct iwl_tlv_calib_ctrl default_calib; | ||
319 | |||
320 | /* | ||
321 | * WkP FW TLV calib bits are wrong, overwrite them. | ||
322 | * This defines the dynamic calibrations which are implemented in the | ||
323 | * uCode both for init(flow) calculation and event driven calibs. | ||
324 | */ | ||
325 | |||
326 | /* Init Image */ | ||
327 | default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_INIT); | ||
328 | default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_INIT); | ||
329 | |||
330 | if (default_calib.event_trigger != | ||
331 | mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger) | ||
332 | IWL_ERR(mvm, | ||
333 | "Updating the event calib for INIT image: 0x%x -> 0x%x\n", | ||
334 | mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger, | ||
335 | default_calib.event_trigger); | ||
336 | if (default_calib.flow_trigger != | ||
337 | mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger) | ||
338 | IWL_ERR(mvm, | ||
339 | "Updating the flow calib for INIT image: 0x%x -> 0x%x\n", | ||
340 | mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger, | ||
341 | default_calib.flow_trigger); | ||
342 | |||
343 | memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_INIT], | ||
344 | &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); | ||
345 | IWL_ERR(mvm, | ||
346 | "Setting uCode init calibrations event 0x%x, trigger 0x%x\n", | ||
347 | default_calib.event_trigger, | ||
348 | default_calib.flow_trigger); | ||
349 | |||
350 | /* Run time image */ | ||
351 | default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_RUN); | ||
352 | default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_RUN); | ||
353 | |||
354 | if (default_calib.event_trigger != | ||
355 | mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger) | ||
356 | IWL_ERR(mvm, | ||
357 | "Updating the event calib for RT image: 0x%x -> 0x%x\n", | ||
358 | mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger, | ||
359 | default_calib.event_trigger); | ||
360 | if (default_calib.flow_trigger != | ||
361 | mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger) | ||
362 | IWL_ERR(mvm, | ||
363 | "Updating the flow calib for RT image: 0x%x -> 0x%x\n", | ||
364 | mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger, | ||
365 | default_calib.flow_trigger); | ||
366 | |||
367 | memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_REGULAR], | ||
368 | &default_calib, sizeof(struct iwl_tlv_calib_ctrl)); | ||
369 | IWL_ERR(mvm, | ||
370 | "Setting uCode runtime calibs event 0x%x, trigger 0x%x\n", | ||
371 | default_calib.event_trigger, | ||
372 | default_calib.flow_trigger); | ||
373 | } | ||
374 | |||
375 | static int iwl_set_default_calibrations(struct iwl_mvm *mvm) | 251 | static int iwl_set_default_calibrations(struct iwl_mvm *mvm) |
376 | { | 252 | { |
377 | u8 cmd_raw[16]; /* holds the variable size commands */ | 253 | u8 cmd_raw[16]; /* holds the variable size commands */ |
@@ -434,6 +310,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
434 | goto error; | 310 | goto error; |
435 | } | 311 | } |
436 | 312 | ||
313 | ret = iwl_send_bt_prio_tbl(mvm); | ||
314 | if (ret) | ||
315 | goto error; | ||
316 | |||
437 | if (read_nvm) { | 317 | if (read_nvm) { |
438 | /* Read nvm */ | 318 | /* Read nvm */ |
439 | ret = iwl_nvm_init(mvm); | 319 | ret = iwl_nvm_init(mvm); |
@@ -446,15 +326,15 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
446 | ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); | 326 | ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); |
447 | WARN_ON(ret); | 327 | WARN_ON(ret); |
448 | 328 | ||
449 | /* Override the calibrations from TLV and the const of fw */ | 329 | /* Send TX valid antennas before triggering calibrations */ |
450 | iwl_set_default_calib_trigger(mvm); | 330 | ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); |
331 | if (ret) | ||
332 | goto error; | ||
451 | 333 | ||
452 | /* WkP doesn't have all calibrations, need to set default values */ | 334 | /* need to set default values */ |
453 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { | 335 | ret = iwl_set_default_calibrations(mvm); |
454 | ret = iwl_set_default_calibrations(mvm); | 336 | if (ret) |
455 | if (ret) | 337 | goto error; |
456 | goto error; | ||
457 | } | ||
458 | 338 | ||
459 | /* | 339 | /* |
460 | * Send phy configurations command to init uCode | 340 | * Send phy configurations command to init uCode |
@@ -533,7 +413,15 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
533 | goto error; | 413 | goto error; |
534 | } | 414 | } |
535 | 415 | ||
536 | ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant); | 416 | ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); |
417 | if (ret) | ||
418 | goto error; | ||
419 | |||
420 | ret = iwl_send_bt_prio_tbl(mvm); | ||
421 | if (ret) | ||
422 | goto error; | ||
423 | |||
424 | ret = iwl_send_bt_init_conf(mvm); | ||
537 | if (ret) | 425 | if (ret) |
538 | goto error; | 426 | goto error; |
539 | 427 | ||
@@ -579,7 +467,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) | |||
579 | goto error; | 467 | goto error; |
580 | } | 468 | } |
581 | 469 | ||
582 | ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant); | 470 | ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); |
583 | if (ret) | 471 | if (ret) |
584 | goto error; | 472 | goto error; |
585 | 473 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/led.c b/drivers/net/wireless/iwlwifi/mvm/led.c index 011906e73a05..2269a9e5cc67 100644 --- a/drivers/net/wireless/iwlwifi/mvm/led.c +++ b/drivers/net/wireless/iwlwifi/mvm/led.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 1d20287b1120..e6eca4d66f6c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -196,7 +196,7 @@ u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, | |||
196 | u32 qmask, ac; | 196 | u32 qmask, ac; |
197 | 197 | ||
198 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) | 198 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) |
199 | return BIT(IWL_OFFCHANNEL_QUEUE); | 199 | return BIT(IWL_MVM_OFFCHANNEL_QUEUE); |
200 | 200 | ||
201 | qmask = (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) ? | 201 | qmask = (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) ? |
202 | BIT(vif->cab_queue) : 0; | 202 | BIT(vif->cab_queue) : 0; |
@@ -553,9 +553,9 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, | |||
553 | if (vif->bss_conf.qos) | 553 | if (vif->bss_conf.qos) |
554 | cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); | 554 | cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); |
555 | 555 | ||
556 | /* Don't use cts to self as the fw doesn't support it currently. */ | ||
556 | if (vif->bss_conf.use_cts_prot) | 557 | if (vif->bss_conf.use_cts_prot) |
557 | cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT | | 558 | cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT); |
558 | MAC_PROT_FLG_SELF_CTS_EN); | ||
559 | 559 | ||
560 | /* | 560 | /* |
561 | * I think that we should enable these 2 flags regardless the HT PROT | 561 | * I think that we should enable these 2 flags regardless the HT PROT |
@@ -651,6 +651,13 @@ static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm, | |||
651 | /* Fill the common data for all mac context types */ | 651 | /* Fill the common data for all mac context types */ |
652 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 652 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); |
653 | 653 | ||
654 | /* Allow beacons to pass through as long as we are not associated,or we | ||
655 | * do not have dtim period information */ | ||
656 | if (!vif->bss_conf.assoc || !vif->bss_conf.dtim_period) | ||
657 | cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON); | ||
658 | else | ||
659 | cmd.filter_flags &= ~cpu_to_le32(MAC_FILTER_IN_BEACON); | ||
660 | |||
654 | /* Fill the data specific for station mode */ | 661 | /* Fill the data specific for station mode */ |
655 | iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta); | 662 | iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta); |
656 | 663 | ||
@@ -687,7 +694,12 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, | |||
687 | WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); | 694 | WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); |
688 | 695 | ||
689 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 696 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); |
690 | /* No other data to be filled */ | 697 | |
698 | cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC | | ||
699 | MAC_FILTER_IN_CONTROL_AND_MGMT | | ||
700 | MAC_FILTER_IN_BEACON | | ||
701 | MAC_FILTER_IN_PROBE_REQUEST); | ||
702 | |||
691 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); | 703 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); |
692 | } | 704 | } |
693 | 705 | ||
@@ -716,7 +728,9 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm, | |||
716 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 728 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); |
717 | 729 | ||
718 | cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT); | 730 | cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT); |
719 | cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROMISC); | 731 | |
732 | /* Override the filter flags to accept only probe requests */ | ||
733 | cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST); | ||
720 | 734 | ||
721 | /* | 735 | /* |
722 | * This flag should be set to true when the P2P Device is | 736 | * This flag should be set to true when the P2P Device is |
@@ -791,7 +805,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, | |||
791 | TX_CMD_FLG_TSF); | 805 | TX_CMD_FLG_TSF); |
792 | 806 | ||
793 | mvm->mgmt_last_antenna_idx = | 807 | mvm->mgmt_last_antenna_idx = |
794 | iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant, | 808 | iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw), |
795 | mvm->mgmt_last_antenna_idx); | 809 | mvm->mgmt_last_antenna_idx); |
796 | 810 | ||
797 | beacon_cmd.tx.rate_n_flags = | 811 | beacon_cmd.tx.rate_n_flags = |
@@ -848,10 +862,10 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, | |||
848 | */ | 862 | */ |
849 | static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm, | 863 | static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm, |
850 | struct ieee80211_vif *vif, | 864 | struct ieee80211_vif *vif, |
851 | struct iwl_mac_data_ap *ctxt_ap) | 865 | struct iwl_mac_data_ap *ctxt_ap, |
866 | bool add) | ||
852 | { | 867 | { |
853 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 868 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
854 | u32 curr_dev_time; | ||
855 | 869 | ||
856 | ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int); | 870 | ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int); |
857 | ctxt_ap->bi_reciprocal = | 871 | ctxt_ap->bi_reciprocal = |
@@ -863,10 +877,19 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm, | |||
863 | vif->bss_conf.dtim_period)); | 877 | vif->bss_conf.dtim_period)); |
864 | 878 | ||
865 | ctxt_ap->mcast_qid = cpu_to_le32(vif->cab_queue); | 879 | ctxt_ap->mcast_qid = cpu_to_le32(vif->cab_queue); |
866 | curr_dev_time = iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG); | ||
867 | ctxt_ap->beacon_time = cpu_to_le32(curr_dev_time); | ||
868 | 880 | ||
869 | ctxt_ap->beacon_tsf = cpu_to_le64(curr_dev_time); | 881 | /* |
882 | * Only read the system time when the MAC is being added, when we | ||
883 | * just modify the MAC then we should keep the time -- the firmware | ||
884 | * can otherwise have a "jumping" TBTT. | ||
885 | */ | ||
886 | if (add) | ||
887 | mvmvif->ap_beacon_time = | ||
888 | iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG); | ||
889 | |||
890 | ctxt_ap->beacon_time = cpu_to_le32(mvmvif->ap_beacon_time); | ||
891 | |||
892 | ctxt_ap->beacon_tsf = 0; /* unused */ | ||
870 | 893 | ||
871 | /* TODO: Assume that the beacon id == mac context id */ | 894 | /* TODO: Assume that the beacon id == mac context id */ |
872 | ctxt_ap->beacon_template = cpu_to_le32(mvmvif->id); | 895 | ctxt_ap->beacon_template = cpu_to_le32(mvmvif->id); |
@@ -883,8 +906,12 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm, | |||
883 | /* Fill the common data for all mac context types */ | 906 | /* Fill the common data for all mac context types */ |
884 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 907 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); |
885 | 908 | ||
909 | /* Also enable probe requests to pass */ | ||
910 | cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST); | ||
911 | |||
886 | /* Fill the data specific for ap mode */ | 912 | /* Fill the data specific for ap mode */ |
887 | iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap); | 913 | iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap, |
914 | action == FW_CTXT_ACTION_ADD); | ||
888 | 915 | ||
889 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); | 916 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); |
890 | } | 917 | } |
@@ -902,7 +929,8 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm, | |||
902 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 929 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); |
903 | 930 | ||
904 | /* Fill the data specific for GO mode */ | 931 | /* Fill the data specific for GO mode */ |
905 | iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap); | 932 | iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap, |
933 | action == FW_CTXT_ACTION_ADD); | ||
906 | 934 | ||
907 | cmd.go.ctwin = cpu_to_le32(noa->oppps_ctwindow & | 935 | cmd.go.ctwin = cpu_to_le32(noa->oppps_ctwindow & |
908 | IEEE80211_P2P_OPPPS_CTWINDOW_MASK); | 936 | IEEE80211_P2P_OPPPS_CTWINDOW_MASK); |
@@ -996,3 +1024,22 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
996 | mvmvif->uploaded = false; | 1024 | mvmvif->uploaded = false; |
997 | return 0; | 1025 | return 0; |
998 | } | 1026 | } |
1027 | |||
1028 | int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | ||
1029 | struct iwl_rx_cmd_buffer *rxb, | ||
1030 | struct iwl_device_cmd *cmd) | ||
1031 | { | ||
1032 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1033 | struct iwl_beacon_notif *beacon = (void *)pkt->data; | ||
1034 | u16 status __maybe_unused = | ||
1035 | le16_to_cpu(beacon->beacon_notify_hdr.status.status); | ||
1036 | u32 rate __maybe_unused = | ||
1037 | le32_to_cpu(beacon->beacon_notify_hdr.initial_rate); | ||
1038 | |||
1039 | IWL_DEBUG_RX(mvm, "beacon status %#x retries:%d tsf:0x%16llX rate:%d\n", | ||
1040 | status & TX_STATUS_MSK, | ||
1041 | beacon->beacon_notify_hdr.failure_frame, | ||
1042 | le64_to_cpu(beacon->tsf), | ||
1043 | rate); | ||
1044 | return 0; | ||
1045 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 23460f4a4c75..fe031608fd91 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -65,7 +65,9 @@ | |||
65 | #include <linux/skbuff.h> | 65 | #include <linux/skbuff.h> |
66 | #include <linux/netdevice.h> | 66 | #include <linux/netdevice.h> |
67 | #include <linux/etherdevice.h> | 67 | #include <linux/etherdevice.h> |
68 | #include <linux/ip.h> | ||
68 | #include <net/mac80211.h> | 69 | #include <net/mac80211.h> |
70 | #include <net/tcp.h> | ||
69 | 71 | ||
70 | #include "iwl-op-mode.h" | 72 | #include "iwl-op-mode.h" |
71 | #include "iwl-io.h" | 73 | #include "iwl-io.h" |
@@ -102,10 +104,33 @@ static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = { | |||
102 | }, | 104 | }, |
103 | }; | 105 | }; |
104 | 106 | ||
107 | #ifdef CONFIG_PM_SLEEP | ||
108 | static const struct nl80211_wowlan_tcp_data_token_feature | ||
109 | iwl_mvm_wowlan_tcp_token_feature = { | ||
110 | .min_len = 0, | ||
111 | .max_len = 255, | ||
112 | .bufsize = IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS, | ||
113 | }; | ||
114 | |||
115 | static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = { | ||
116 | .tok = &iwl_mvm_wowlan_tcp_token_feature, | ||
117 | .data_payload_max = IWL_WOWLAN_TCP_MAX_PACKET_LEN - | ||
118 | sizeof(struct ethhdr) - | ||
119 | sizeof(struct iphdr) - | ||
120 | sizeof(struct tcphdr), | ||
121 | .data_interval_max = 65535, /* __le16 in API */ | ||
122 | .wake_payload_max = IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN - | ||
123 | sizeof(struct ethhdr) - | ||
124 | sizeof(struct iphdr) - | ||
125 | sizeof(struct tcphdr), | ||
126 | .seq = true, | ||
127 | }; | ||
128 | #endif | ||
129 | |||
105 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | 130 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) |
106 | { | 131 | { |
107 | struct ieee80211_hw *hw = mvm->hw; | 132 | struct ieee80211_hw *hw = mvm->hw; |
108 | int num_mac, ret; | 133 | int num_mac, ret, i; |
109 | 134 | ||
110 | /* Tell mac80211 our characteristics */ | 135 | /* Tell mac80211 our characteristics */ |
111 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | 136 | hw->flags = IEEE80211_HW_SIGNAL_DBM | |
@@ -118,8 +143,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
118 | IEEE80211_HW_AMPDU_AGGREGATION | | 143 | IEEE80211_HW_AMPDU_AGGREGATION | |
119 | IEEE80211_HW_TIMING_BEACON_ONLY; | 144 | IEEE80211_HW_TIMING_BEACON_ONLY; |
120 | 145 | ||
121 | hw->queues = IWL_FIRST_AMPDU_QUEUE; | 146 | hw->queues = IWL_MVM_FIRST_AGG_QUEUE; |
122 | hw->offchannel_tx_hw_queue = IWL_OFFCHANNEL_QUEUE; | 147 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; |
123 | hw->rate_control_algorithm = "iwl-mvm-rs"; | 148 | hw->rate_control_algorithm = "iwl-mvm-rs"; |
124 | 149 | ||
125 | /* | 150 | /* |
@@ -149,18 +174,22 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
149 | hw->wiphy->n_iface_combinations = | 174 | hw->wiphy->n_iface_combinations = |
150 | ARRAY_SIZE(iwl_mvm_iface_combinations); | 175 | ARRAY_SIZE(iwl_mvm_iface_combinations); |
151 | 176 | ||
152 | hw->wiphy->max_remain_on_channel_duration = 500; | 177 | hw->wiphy->max_remain_on_channel_duration = 10000; |
153 | hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; | 178 | hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; |
154 | 179 | ||
155 | /* Extract MAC address */ | 180 | /* Extract MAC address */ |
156 | memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN); | 181 | memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN); |
157 | hw->wiphy->addresses = mvm->addresses; | 182 | hw->wiphy->addresses = mvm->addresses; |
158 | hw->wiphy->n_addresses = 1; | 183 | hw->wiphy->n_addresses = 1; |
159 | num_mac = mvm->nvm_data->n_hw_addrs; | 184 | |
160 | if (num_mac > 1) { | 185 | /* Extract additional MAC addresses if available */ |
161 | memcpy(mvm->addresses[1].addr, mvm->addresses[0].addr, | 186 | num_mac = (mvm->nvm_data->n_hw_addrs > 1) ? |
187 | min(IWL_MVM_MAX_ADDRESSES, mvm->nvm_data->n_hw_addrs) : 1; | ||
188 | |||
189 | for (i = 1; i < num_mac; i++) { | ||
190 | memcpy(mvm->addresses[i].addr, mvm->addresses[i-1].addr, | ||
162 | ETH_ALEN); | 191 | ETH_ALEN); |
163 | mvm->addresses[1].addr[5]++; | 192 | mvm->addresses[i].addr[5]++; |
164 | hw->wiphy->n_addresses++; | 193 | hw->wiphy->n_addresses++; |
165 | } | 194 | } |
166 | 195 | ||
@@ -206,6 +235,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
206 | hw->wiphy->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS; | 235 | hw->wiphy->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS; |
207 | hw->wiphy->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN; | 236 | hw->wiphy->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN; |
208 | hw->wiphy->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN; | 237 | hw->wiphy->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN; |
238 | hw->wiphy->wowlan.tcp = &iwl_mvm_wowlan_tcp_support; | ||
209 | } | 239 | } |
210 | #endif | 240 | #endif |
211 | 241 | ||
@@ -227,7 +257,7 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, | |||
227 | goto drop; | 257 | goto drop; |
228 | } | 258 | } |
229 | 259 | ||
230 | if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_OFFCHANNEL_QUEUE && | 260 | if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && |
231 | !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) | 261 | !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) |
232 | goto drop; | 262 | goto drop; |
233 | 263 | ||
@@ -273,12 +303,18 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, | |||
273 | ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false); | 303 | ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false); |
274 | break; | 304 | break; |
275 | case IEEE80211_AMPDU_TX_START: | 305 | case IEEE80211_AMPDU_TX_START: |
306 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) { | ||
307 | ret = -EINVAL; | ||
308 | break; | ||
309 | } | ||
276 | ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn); | 310 | ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn); |
277 | break; | 311 | break; |
278 | case IEEE80211_AMPDU_TX_STOP_CONT: | 312 | case IEEE80211_AMPDU_TX_STOP_CONT: |
313 | ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid); | ||
314 | break; | ||
279 | case IEEE80211_AMPDU_TX_STOP_FLUSH: | 315 | case IEEE80211_AMPDU_TX_STOP_FLUSH: |
280 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: | 316 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: |
281 | ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid); | 317 | ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid); |
282 | break; | 318 | break; |
283 | case IEEE80211_AMPDU_TX_OPERATIONAL: | 319 | case IEEE80211_AMPDU_TX_OPERATIONAL: |
284 | ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size); | 320 | ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size); |
@@ -466,11 +502,15 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
466 | /* | 502 | /* |
467 | * TODO: remove this temporary code. | 503 | * TODO: remove this temporary code. |
468 | * Currently MVM FW supports power management only on single MAC. | 504 | * Currently MVM FW supports power management only on single MAC. |
469 | * Iterate and disable PM on all active interfaces. | 505 | * If new interface added, disable PM on existing interface. |
506 | * P2P device is a special case, since it is handled by FW similary to | ||
507 | * scan. If P2P deviced is added, PM remains enabled on existing | ||
508 | * interface. | ||
470 | * Note: the method below does not count the new interface being added | 509 | * Note: the method below does not count the new interface being added |
471 | * at this moment. | 510 | * at this moment. |
472 | */ | 511 | */ |
473 | mvm->vif_count++; | 512 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) |
513 | mvm->vif_count++; | ||
474 | if (mvm->vif_count > 1) { | 514 | if (mvm->vif_count > 1) { |
475 | IWL_DEBUG_MAC80211(mvm, | 515 | IWL_DEBUG_MAC80211(mvm, |
476 | "Disable power on existing interfaces\n"); | 516 | "Disable power on existing interfaces\n"); |
@@ -526,6 +566,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
526 | mvm->p2p_device_vif = vif; | 566 | mvm->p2p_device_vif = vif; |
527 | } | 567 | } |
528 | 568 | ||
569 | iwl_mvm_vif_dbgfs_register(mvm, vif); | ||
529 | goto out_unlock; | 570 | goto out_unlock; |
530 | 571 | ||
531 | out_unbind: | 572 | out_unbind: |
@@ -539,10 +580,11 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
539 | /* | 580 | /* |
540 | * TODO: remove this temporary code. | 581 | * TODO: remove this temporary code. |
541 | * Currently MVM FW supports power management only on single MAC. | 582 | * Currently MVM FW supports power management only on single MAC. |
542 | * Check if only one additional interface remains after rereasing | 583 | * Check if only one additional interface remains after releasing |
543 | * current one. Update power mode on the remaining interface. | 584 | * current one. Update power mode on the remaining interface. |
544 | */ | 585 | */ |
545 | mvm->vif_count--; | 586 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) |
587 | mvm->vif_count--; | ||
546 | IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", | 588 | IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", |
547 | mvm->vif_count); | 589 | mvm->vif_count); |
548 | if (mvm->vif_count == 1) { | 590 | if (mvm->vif_count == 1) { |
@@ -557,11 +599,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
557 | return ret; | 599 | return ret; |
558 | } | 600 | } |
559 | 601 | ||
560 | static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | 602 | static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, |
561 | struct ieee80211_vif *vif) | 603 | struct ieee80211_vif *vif) |
562 | { | 604 | { |
563 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
564 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
565 | u32 tfd_msk = 0, ac; | 605 | u32 tfd_msk = 0, ac; |
566 | 606 | ||
567 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | 607 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
@@ -594,12 +634,23 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | |||
594 | */ | 634 | */ |
595 | flush_work(&mvm->sta_drained_wk); | 635 | flush_work(&mvm->sta_drained_wk); |
596 | } | 636 | } |
637 | } | ||
638 | |||
639 | static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | ||
640 | struct ieee80211_vif *vif) | ||
641 | { | ||
642 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
643 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
644 | |||
645 | iwl_mvm_prepare_mac_removal(mvm, vif); | ||
597 | 646 | ||
598 | mutex_lock(&mvm->mutex); | 647 | mutex_lock(&mvm->mutex); |
599 | 648 | ||
649 | iwl_mvm_vif_dbgfs_clean(mvm, vif); | ||
650 | |||
600 | /* | 651 | /* |
601 | * For AP/GO interface, the tear down of the resources allocated to the | 652 | * For AP/GO interface, the tear down of the resources allocated to the |
602 | * interface should be handled as part of the bss_info_changed flow. | 653 | * interface is be handled as part of the stop_ap flow. |
603 | */ | 654 | */ |
604 | if (vif->type == NL80211_IFTYPE_AP) { | 655 | if (vif->type == NL80211_IFTYPE_AP) { |
605 | iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); | 656 | iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta); |
@@ -620,7 +671,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | |||
620 | * Check if only one additional interface remains after removing | 671 | * Check if only one additional interface remains after removing |
621 | * current one. Update power mode on the remaining interface. | 672 | * current one. Update power mode on the remaining interface. |
622 | */ | 673 | */ |
623 | if (mvm->vif_count) | 674 | if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE) |
624 | mvm->vif_count--; | 675 | mvm->vif_count--; |
625 | IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", | 676 | IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", |
626 | mvm->vif_count); | 677 | mvm->vif_count); |
@@ -670,6 +721,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
670 | IWL_ERR(mvm, "failed to update quotas\n"); | 721 | IWL_ERR(mvm, "failed to update quotas\n"); |
671 | return; | 722 | return; |
672 | } | 723 | } |
724 | iwl_mvm_bt_coex_vif_assoc(mvm, vif); | ||
673 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | 725 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { |
674 | /* remove AP station now that the MAC is unassoc */ | 726 | /* remove AP station now that the MAC is unassoc */ |
675 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); | 727 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); |
@@ -763,6 +815,8 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
763 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 815 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
764 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 816 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
765 | 817 | ||
818 | iwl_mvm_prepare_mac_removal(mvm, vif); | ||
819 | |||
766 | mutex_lock(&mvm->mutex); | 820 | mutex_lock(&mvm->mutex); |
767 | 821 | ||
768 | mvmvif->ap_active = false; | 822 | mvmvif->ap_active = false; |
@@ -886,7 +940,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, | |||
886 | */ | 940 | */ |
887 | break; | 941 | break; |
888 | case STA_NOTIFY_AWAKE: | 942 | case STA_NOTIFY_AWAKE: |
889 | if (WARN_ON(mvmsta->sta_id == IWL_INVALID_STATION)) | 943 | if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) |
890 | break; | 944 | break; |
891 | iwl_mvm_sta_modify_ps_wake(mvm, sta); | 945 | iwl_mvm_sta_modify_ps_wake(mvm, sta); |
892 | break; | 946 | break; |
@@ -1042,6 +1096,13 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, | |||
1042 | 1096 | ||
1043 | switch (cmd) { | 1097 | switch (cmd) { |
1044 | case SET_KEY: | 1098 | case SET_KEY: |
1099 | if (vif->type == NL80211_IFTYPE_AP && !sta) { | ||
1100 | /* GTK on AP interface is a TX-only key, return 0 */ | ||
1101 | ret = 0; | ||
1102 | key->hw_key_idx = STA_KEY_IDX_INVALID; | ||
1103 | break; | ||
1104 | } | ||
1105 | |||
1045 | IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n"); | 1106 | IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n"); |
1046 | ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, false); | 1107 | ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, false); |
1047 | if (ret) { | 1108 | if (ret) { |
@@ -1050,11 +1111,17 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, | |||
1050 | * can't add key for RX, but we don't need it | 1111 | * can't add key for RX, but we don't need it |
1051 | * in the device for TX so still return 0 | 1112 | * in the device for TX so still return 0 |
1052 | */ | 1113 | */ |
1114 | key->hw_key_idx = STA_KEY_IDX_INVALID; | ||
1053 | ret = 0; | 1115 | ret = 0; |
1054 | } | 1116 | } |
1055 | 1117 | ||
1056 | break; | 1118 | break; |
1057 | case DISABLE_KEY: | 1119 | case DISABLE_KEY: |
1120 | if (key->hw_key_idx == STA_KEY_IDX_INVALID) { | ||
1121 | ret = 0; | ||
1122 | break; | ||
1123 | } | ||
1124 | |||
1058 | IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n"); | 1125 | IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n"); |
1059 | ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key); | 1126 | ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key); |
1060 | break; | 1127 | break; |
@@ -1103,7 +1170,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, | |||
1103 | &chandef, 1, 1); | 1170 | &chandef, 1, 1); |
1104 | 1171 | ||
1105 | /* Schedule the time events */ | 1172 | /* Schedule the time events */ |
1106 | ret = iwl_mvm_start_p2p_roc(mvm, vif, duration); | 1173 | ret = iwl_mvm_start_p2p_roc(mvm, vif, duration, type); |
1107 | 1174 | ||
1108 | mutex_unlock(&mvm->mutex); | 1175 | mutex_unlock(&mvm->mutex); |
1109 | IWL_DEBUG_MAC80211(mvm, "leave\n"); | 1176 | IWL_DEBUG_MAC80211(mvm, "leave\n"); |
@@ -1207,6 +1274,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, | |||
1207 | * will handle quota settings. | 1274 | * will handle quota settings. |
1208 | */ | 1275 | */ |
1209 | if (vif->type == NL80211_IFTYPE_MONITOR) { | 1276 | if (vif->type == NL80211_IFTYPE_MONITOR) { |
1277 | mvmvif->monitor_active = true; | ||
1210 | ret = iwl_mvm_update_quotas(mvm, vif); | 1278 | ret = iwl_mvm_update_quotas(mvm, vif); |
1211 | if (ret) | 1279 | if (ret) |
1212 | goto out_remove_binding; | 1280 | goto out_remove_binding; |
@@ -1237,15 +1305,16 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, | |||
1237 | if (vif->type == NL80211_IFTYPE_AP) | 1305 | if (vif->type == NL80211_IFTYPE_AP) |
1238 | goto out_unlock; | 1306 | goto out_unlock; |
1239 | 1307 | ||
1240 | iwl_mvm_binding_remove_vif(mvm, vif); | ||
1241 | switch (vif->type) { | 1308 | switch (vif->type) { |
1242 | case NL80211_IFTYPE_MONITOR: | 1309 | case NL80211_IFTYPE_MONITOR: |
1243 | iwl_mvm_update_quotas(mvm, vif); | 1310 | mvmvif->monitor_active = false; |
1311 | iwl_mvm_update_quotas(mvm, NULL); | ||
1244 | break; | 1312 | break; |
1245 | default: | 1313 | default: |
1246 | break; | 1314 | break; |
1247 | } | 1315 | } |
1248 | 1316 | ||
1317 | iwl_mvm_binding_remove_vif(mvm, vif); | ||
1249 | out_unlock: | 1318 | out_unlock: |
1250 | mvmvif->phy_ctxt = NULL; | 1319 | mvmvif->phy_ctxt = NULL; |
1251 | mutex_unlock(&mvm->mutex); | 1320 | mutex_unlock(&mvm->mutex); |
@@ -1266,6 +1335,15 @@ static int iwl_mvm_set_tim(struct ieee80211_hw *hw, | |||
1266 | return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif); | 1335 | return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif); |
1267 | } | 1336 | } |
1268 | 1337 | ||
1338 | static void iwl_mvm_mac_rssi_callback(struct ieee80211_hw *hw, | ||
1339 | struct ieee80211_vif *vif, | ||
1340 | enum ieee80211_rssi_event rssi_event) | ||
1341 | { | ||
1342 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1343 | |||
1344 | iwl_mvm_bt_rssi_event(mvm, vif, rssi_event); | ||
1345 | } | ||
1346 | |||
1269 | struct ieee80211_ops iwl_mvm_hw_ops = { | 1347 | struct ieee80211_ops iwl_mvm_hw_ops = { |
1270 | .tx = iwl_mvm_mac_tx, | 1348 | .tx = iwl_mvm_mac_tx, |
1271 | .ampdu_action = iwl_mvm_mac_ampdu_action, | 1349 | .ampdu_action = iwl_mvm_mac_ampdu_action, |
@@ -1289,6 +1367,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = { | |||
1289 | .update_tkip_key = iwl_mvm_mac_update_tkip_key, | 1367 | .update_tkip_key = iwl_mvm_mac_update_tkip_key, |
1290 | .remain_on_channel = iwl_mvm_roc, | 1368 | .remain_on_channel = iwl_mvm_roc, |
1291 | .cancel_remain_on_channel = iwl_mvm_cancel_roc, | 1369 | .cancel_remain_on_channel = iwl_mvm_cancel_roc, |
1370 | .rssi_callback = iwl_mvm_mac_rssi_callback, | ||
1292 | 1371 | ||
1293 | .add_chanctx = iwl_mvm_add_chanctx, | 1372 | .add_chanctx = iwl_mvm_add_chanctx, |
1294 | .remove_chanctx = iwl_mvm_remove_chanctx, | 1373 | .remove_chanctx = iwl_mvm_remove_chanctx, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 4e339ccfa800..8269bc562951 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -79,8 +79,9 @@ | |||
79 | #include "fw-api.h" | 79 | #include "fw-api.h" |
80 | 80 | ||
81 | #define IWL_INVALID_MAC80211_QUEUE 0xff | 81 | #define IWL_INVALID_MAC80211_QUEUE 0xff |
82 | #define IWL_MVM_MAX_ADDRESSES 2 | 82 | #define IWL_MVM_MAX_ADDRESSES 5 |
83 | #define IWL_RSSI_OFFSET 44 | 83 | /* RSSI offset for WkP */ |
84 | #define IWL_RSSI_OFFSET 50 | ||
84 | 85 | ||
85 | enum iwl_mvm_tx_fifo { | 86 | enum iwl_mvm_tx_fifo { |
86 | IWL_MVM_TX_FIFO_BK = 0, | 87 | IWL_MVM_TX_FIFO_BK = 0, |
@@ -89,10 +90,6 @@ enum iwl_mvm_tx_fifo { | |||
89 | IWL_MVM_TX_FIFO_VO, | 90 | IWL_MVM_TX_FIFO_VO, |
90 | }; | 91 | }; |
91 | 92 | ||
92 | /* Placeholder */ | ||
93 | #define IWL_OFFCHANNEL_QUEUE 8 | ||
94 | #define IWL_FIRST_AMPDU_QUEUE 11 | ||
95 | |||
96 | extern struct ieee80211_ops iwl_mvm_hw_ops; | 93 | extern struct ieee80211_ops iwl_mvm_hw_ops; |
97 | /** | 94 | /** |
98 | * struct iwl_mvm_mod_params - module parameters for iwlmvm | 95 | * struct iwl_mvm_mod_params - module parameters for iwlmvm |
@@ -160,6 +157,8 @@ enum iwl_power_scheme { | |||
160 | * @uploaded: indicates the MAC context has been added to the device | 157 | * @uploaded: indicates the MAC context has been added to the device |
161 | * @ap_active: indicates that ap context is configured, and that the interface | 158 | * @ap_active: indicates that ap context is configured, and that the interface |
162 | * should get quota etc. | 159 | * should get quota etc. |
160 | * @monitor_active: indicates that monitor context is configured, and that the | ||
161 | * interface should get quota etc. | ||
163 | * @queue_params: QoS params for this MAC | 162 | * @queue_params: QoS params for this MAC |
164 | * @bcast_sta: station used for broadcast packets. Used by the following | 163 | * @bcast_sta: station used for broadcast packets. Used by the following |
165 | * vifs: P2P_DEVICE, GO and AP. | 164 | * vifs: P2P_DEVICE, GO and AP. |
@@ -172,6 +171,9 @@ struct iwl_mvm_vif { | |||
172 | 171 | ||
173 | bool uploaded; | 172 | bool uploaded; |
174 | bool ap_active; | 173 | bool ap_active; |
174 | bool monitor_active; | ||
175 | |||
176 | u32 ap_beacon_time; | ||
175 | 177 | ||
176 | enum iwl_tsf_id tsf_id; | 178 | enum iwl_tsf_id tsf_id; |
177 | 179 | ||
@@ -210,6 +212,7 @@ struct iwl_mvm_vif { | |||
210 | 212 | ||
211 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 213 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
212 | struct dentry *dbgfs_dir; | 214 | struct dentry *dbgfs_dir; |
215 | struct dentry *dbgfs_slink; | ||
213 | void *dbgfs_data; | 216 | void *dbgfs_data; |
214 | #endif | 217 | #endif |
215 | }; | 218 | }; |
@@ -278,10 +281,7 @@ struct iwl_mvm { | |||
278 | atomic_t queue_stop_count[IWL_MAX_HW_QUEUES]; | 281 | atomic_t queue_stop_count[IWL_MAX_HW_QUEUES]; |
279 | 282 | ||
280 | struct iwl_nvm_data *nvm_data; | 283 | struct iwl_nvm_data *nvm_data; |
281 | /* eeprom blob for debugfs/testmode */ | 284 | /* NVM sections */ |
282 | u8 *eeprom_blob; | ||
283 | size_t eeprom_blob_size; | ||
284 | /* NVM sections for 7000 family */ | ||
285 | struct iwl_nvm_section nvm_sections[NVM_NUM_OF_SECTIONS]; | 285 | struct iwl_nvm_section nvm_sections[NVM_NUM_OF_SECTIONS]; |
286 | 286 | ||
287 | /* EEPROM MAC addresses */ | 287 | /* EEPROM MAC addresses */ |
@@ -322,11 +322,26 @@ struct iwl_mvm { | |||
322 | * can hold 16 keys at most. Reflect this fact. | 322 | * can hold 16 keys at most. Reflect this fact. |
323 | */ | 323 | */ |
324 | unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; | 324 | unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; |
325 | |||
326 | /* | ||
327 | * This counter of created interfaces is referenced only in conjunction | ||
328 | * with FW limitation related to power management. Currently PM is | ||
329 | * supported only on a single interface. | ||
330 | * IMPORTANT: this variable counts all interfaces except P2P device. | ||
331 | */ | ||
325 | u8 vif_count; | 332 | u8 vif_count; |
326 | 333 | ||
327 | struct led_classdev led; | 334 | struct led_classdev led; |
328 | 335 | ||
329 | struct ieee80211_vif *p2p_device_vif; | 336 | struct ieee80211_vif *p2p_device_vif; |
337 | |||
338 | #ifdef CONFIG_PM_SLEEP | ||
339 | int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; | ||
340 | #endif | ||
341 | |||
342 | /* BT-Coex */ | ||
343 | u8 bt_kill_msk; | ||
344 | struct iwl_bt_coex_profile_notif last_bt_notif; | ||
330 | }; | 345 | }; |
331 | 346 | ||
332 | /* Extract MVM priv from op_mode and _hw */ | 347 | /* Extract MVM priv from op_mode and _hw */ |
@@ -440,6 +455,9 @@ u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, | |||
440 | struct ieee80211_vif *vif); | 455 | struct ieee80211_vif *vif); |
441 | int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, | 456 | int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, |
442 | struct ieee80211_vif *vif); | 457 | struct ieee80211_vif *vif); |
458 | int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | ||
459 | struct iwl_rx_cmd_buffer *rxb, | ||
460 | struct iwl_device_cmd *cmd); | ||
443 | 461 | ||
444 | /* Bindings */ | 462 | /* Bindings */ |
445 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 463 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
@@ -461,16 +479,22 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm); | |||
461 | /* MVM debugfs */ | 479 | /* MVM debugfs */ |
462 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 480 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
463 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); | 481 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); |
464 | int iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 482 | void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
465 | struct dentry *dbgfs_dir); | 483 | void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
466 | void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
467 | struct iwl_powertable_cmd *cmd); | ||
468 | #else | 484 | #else |
469 | static inline int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, | 485 | static inline int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, |
470 | struct dentry *dbgfs_dir) | 486 | struct dentry *dbgfs_dir) |
471 | { | 487 | { |
472 | return 0; | 488 | return 0; |
473 | } | 489 | } |
490 | static inline void | ||
491 | iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
492 | { | ||
493 | } | ||
494 | static inline void | ||
495 | iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
496 | { | ||
497 | } | ||
474 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | 498 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ |
475 | 499 | ||
476 | /* rate scaling */ | 500 | /* rate scaling */ |
@@ -480,6 +504,8 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | |||
480 | /* power managment */ | 504 | /* power managment */ |
481 | int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 505 | int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
482 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 506 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
507 | void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
508 | struct iwl_powertable_cmd *cmd); | ||
483 | 509 | ||
484 | int iwl_mvm_leds_init(struct iwl_mvm *mvm); | 510 | int iwl_mvm_leds_init(struct iwl_mvm *mvm); |
485 | void iwl_mvm_leds_exit(struct iwl_mvm *mvm); | 511 | void iwl_mvm_leds_exit(struct iwl_mvm *mvm); |
@@ -497,4 +523,14 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, | |||
497 | void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, | 523 | void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, |
498 | struct ieee80211_vif *vif, int idx); | 524 | struct ieee80211_vif *vif, int idx); |
499 | 525 | ||
526 | /* BT Coex */ | ||
527 | int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm); | ||
528 | int iwl_send_bt_init_conf(struct iwl_mvm *mvm); | ||
529 | int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, | ||
530 | struct iwl_rx_cmd_buffer *rxb, | ||
531 | struct iwl_device_cmd *cmd); | ||
532 | void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
533 | enum ieee80211_rssi_event rssi_event); | ||
534 | void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
535 | |||
500 | #endif /* __IWL_MVM_H__ */ | 536 | #endif /* __IWL_MVM_H__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 20016bcbdeab..b8ec02f89acc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -74,26 +74,11 @@ static const int nvm_to_read[] = { | |||
74 | NVM_SECTION_TYPE_PRODUCTION, | 74 | NVM_SECTION_TYPE_PRODUCTION, |
75 | }; | 75 | }; |
76 | 76 | ||
77 | /* used to simplify the shared operations on NCM_ACCESS_CMD versions */ | 77 | /* Default NVM size to read */ |
78 | union iwl_nvm_access_cmd { | 78 | #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024); |
79 | struct iwl_nvm_access_cmd_ver1 ver1; | ||
80 | struct iwl_nvm_access_cmd_ver2 ver2; | ||
81 | }; | ||
82 | union iwl_nvm_access_resp { | ||
83 | struct iwl_nvm_access_resp_ver1 ver1; | ||
84 | struct iwl_nvm_access_resp_ver2 ver2; | ||
85 | }; | ||
86 | |||
87 | static inline void iwl_nvm_fill_read_ver1(struct iwl_nvm_access_cmd_ver1 *cmd, | ||
88 | u16 offset, u16 length) | ||
89 | { | ||
90 | cmd->offset = cpu_to_le16(offset); | ||
91 | cmd->length = cpu_to_le16(length); | ||
92 | cmd->cache_refresh = 1; | ||
93 | } | ||
94 | 79 | ||
95 | static inline void iwl_nvm_fill_read_ver2(struct iwl_nvm_access_cmd_ver2 *cmd, | 80 | static inline void iwl_nvm_fill_read(struct iwl_nvm_access_cmd *cmd, |
96 | u16 offset, u16 length, u16 section) | 81 | u16 offset, u16 length, u16 section) |
97 | { | 82 | { |
98 | cmd->offset = cpu_to_le16(offset); | 83 | cmd->offset = cpu_to_le16(offset); |
99 | cmd->length = cpu_to_le16(length); | 84 | cmd->length = cpu_to_le16(length); |
@@ -103,8 +88,8 @@ static inline void iwl_nvm_fill_read_ver2(struct iwl_nvm_access_cmd_ver2 *cmd, | |||
103 | static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, | 88 | static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, |
104 | u16 offset, u16 length, u8 *data) | 89 | u16 offset, u16 length, u8 *data) |
105 | { | 90 | { |
106 | union iwl_nvm_access_cmd nvm_access_cmd; | 91 | struct iwl_nvm_access_cmd nvm_access_cmd = {}; |
107 | union iwl_nvm_access_resp *nvm_resp; | 92 | struct iwl_nvm_access_resp *nvm_resp; |
108 | struct iwl_rx_packet *pkt; | 93 | struct iwl_rx_packet *pkt; |
109 | struct iwl_host_cmd cmd = { | 94 | struct iwl_host_cmd cmd = { |
110 | .id = NVM_ACCESS_CMD, | 95 | .id = NVM_ACCESS_CMD, |
@@ -114,18 +99,8 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, | |||
114 | int ret, bytes_read, offset_read; | 99 | int ret, bytes_read, offset_read; |
115 | u8 *resp_data; | 100 | u8 *resp_data; |
116 | 101 | ||
117 | memset(&nvm_access_cmd, 0, sizeof(nvm_access_cmd)); | 102 | iwl_nvm_fill_read(&nvm_access_cmd, offset, length, section); |
118 | 103 | cmd.len[0] = sizeof(struct iwl_nvm_access_cmd); | |
119 | /* TODO: not sure family should be the decider, maybe FW version? */ | ||
120 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { | ||
121 | iwl_nvm_fill_read_ver2(&(nvm_access_cmd.ver2), | ||
122 | offset, length, section); | ||
123 | cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver2); | ||
124 | } else { | ||
125 | iwl_nvm_fill_read_ver1(&(nvm_access_cmd.ver1), | ||
126 | offset, length); | ||
127 | cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver1); | ||
128 | } | ||
129 | 104 | ||
130 | ret = iwl_mvm_send_cmd(mvm, &cmd); | 105 | ret = iwl_mvm_send_cmd(mvm, &cmd); |
131 | if (ret) | 106 | if (ret) |
@@ -141,17 +116,10 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, | |||
141 | 116 | ||
142 | /* Extract NVM response */ | 117 | /* Extract NVM response */ |
143 | nvm_resp = (void *)pkt->data; | 118 | nvm_resp = (void *)pkt->data; |
144 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { | 119 | ret = le16_to_cpu(nvm_resp->status); |
145 | ret = le16_to_cpu(nvm_resp->ver2.status); | 120 | bytes_read = le16_to_cpu(nvm_resp->length); |
146 | bytes_read = le16_to_cpu(nvm_resp->ver2.length); | 121 | offset_read = le16_to_cpu(nvm_resp->offset); |
147 | offset_read = le16_to_cpu(nvm_resp->ver2.offset); | 122 | resp_data = nvm_resp->data; |
148 | resp_data = nvm_resp->ver2.data; | ||
149 | } else { | ||
150 | ret = le16_to_cpu(nvm_resp->ver1.length) <= 0; | ||
151 | bytes_read = le16_to_cpu(nvm_resp->ver1.length); | ||
152 | offset_read = le16_to_cpu(nvm_resp->ver1.offset); | ||
153 | resp_data = nvm_resp->ver1.data; | ||
154 | } | ||
155 | if (ret) { | 123 | if (ret) { |
156 | IWL_ERR(mvm, | 124 | IWL_ERR(mvm, |
157 | "NVM access command failed with status %d (device: %s)\n", | 125 | "NVM access command failed with status %d (device: %s)\n", |
@@ -191,17 +159,10 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section, | |||
191 | { | 159 | { |
192 | u16 length, offset = 0; | 160 | u16 length, offset = 0; |
193 | int ret; | 161 | int ret; |
194 | bool old_eeprom = mvm->cfg->device_family != IWL_DEVICE_FAMILY_7000; | ||
195 | 162 | ||
196 | length = (iwlwifi_mod_params.amsdu_size_8K ? (8 * 1024) : (4 * 1024)) | 163 | /* Set nvm section read length */ |
197 | - sizeof(union iwl_nvm_access_cmd) | 164 | length = IWL_NVM_DEFAULT_CHUNK_SIZE; |
198 | - sizeof(struct iwl_rx_packet); | 165 | |
199 | /* | ||
200 | * if length is greater than EEPROM size, truncate it because uCode | ||
201 | * doesn't check it by itself, and exit the loop when reached. | ||
202 | */ | ||
203 | if (old_eeprom && length > mvm->cfg->base_params->eeprom_size) | ||
204 | length = mvm->cfg->base_params->eeprom_size; | ||
205 | ret = length; | 166 | ret = length; |
206 | 167 | ||
207 | /* Read the NVM until exhausted (reading less than requested) */ | 168 | /* Read the NVM until exhausted (reading less than requested) */ |
@@ -214,8 +175,6 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section, | |||
214 | return ret; | 175 | return ret; |
215 | } | 176 | } |
216 | offset += ret; | 177 | offset += ret; |
217 | if (old_eeprom && offset == mvm->cfg->base_params->eeprom_size) | ||
218 | break; | ||
219 | } | 178 | } |
220 | 179 | ||
221 | IWL_INFO(mvm, "NVM section %d read completed\n", section); | 180 | IWL_INFO(mvm, "NVM section %d read completed\n", section); |
@@ -249,63 +208,31 @@ int iwl_nvm_init(struct iwl_mvm *mvm) | |||
249 | int ret, i, section; | 208 | int ret, i, section; |
250 | u8 *nvm_buffer, *temp; | 209 | u8 *nvm_buffer, *temp; |
251 | 210 | ||
252 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { | 211 | /* TODO: find correct NVM max size for a section */ |
253 | /* TODO: find correct NVM max size for a section */ | 212 | nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, |
254 | nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, | 213 | GFP_KERNEL); |
255 | GFP_KERNEL); | 214 | if (!nvm_buffer) |
256 | if (!nvm_buffer) | 215 | return -ENOMEM; |
257 | return -ENOMEM; | 216 | for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) { |
258 | for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) { | 217 | section = nvm_to_read[i]; |
259 | section = nvm_to_read[i]; | 218 | /* we override the constness for initial read */ |
260 | /* we override the constness for initial read */ | 219 | ret = iwl_nvm_read_section(mvm, section, nvm_buffer); |
261 | ret = iwl_nvm_read_section(mvm, section, nvm_buffer); | ||
262 | if (ret < 0) | ||
263 | break; | ||
264 | temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); | ||
265 | if (!temp) { | ||
266 | ret = -ENOMEM; | ||
267 | break; | ||
268 | } | ||
269 | mvm->nvm_sections[section].data = temp; | ||
270 | mvm->nvm_sections[section].length = ret; | ||
271 | } | ||
272 | kfree(nvm_buffer); | ||
273 | if (ret < 0) | 220 | if (ret < 0) |
274 | return ret; | 221 | break; |
275 | } else { | 222 | temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); |
276 | /* allocate eeprom */ | 223 | if (!temp) { |
277 | mvm->eeprom_blob_size = mvm->cfg->base_params->eeprom_size; | 224 | ret = -ENOMEM; |
278 | IWL_DEBUG_EEPROM(mvm->trans->dev, "NVM size = %zd\n", | 225 | break; |
279 | mvm->eeprom_blob_size); | ||
280 | mvm->eeprom_blob = kzalloc(mvm->eeprom_blob_size, GFP_KERNEL); | ||
281 | if (!mvm->eeprom_blob) | ||
282 | return -ENOMEM; | ||
283 | |||
284 | ret = iwl_nvm_read_section(mvm, 0, mvm->eeprom_blob); | ||
285 | if (ret != mvm->eeprom_blob_size) { | ||
286 | IWL_ERR(mvm, "Read partial NVM %d/%zd\n", | ||
287 | ret, mvm->eeprom_blob_size); | ||
288 | kfree(mvm->eeprom_blob); | ||
289 | mvm->eeprom_blob = NULL; | ||
290 | return -EINVAL; | ||
291 | } | 226 | } |
227 | mvm->nvm_sections[section].data = temp; | ||
228 | mvm->nvm_sections[section].length = ret; | ||
292 | } | 229 | } |
230 | kfree(nvm_buffer); | ||
231 | if (ret < 0) | ||
232 | return ret; | ||
293 | 233 | ||
294 | ret = 0; | 234 | ret = 0; |
295 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) | 235 | mvm->nvm_data = iwl_parse_nvm_sections(mvm); |
296 | mvm->nvm_data = iwl_parse_nvm_sections(mvm); | ||
297 | else | ||
298 | mvm->nvm_data = | ||
299 | iwl_parse_eeprom_data(mvm->trans->dev, | ||
300 | mvm->cfg, | ||
301 | mvm->eeprom_blob, | ||
302 | mvm->eeprom_blob_size); | ||
303 | |||
304 | if (!mvm->nvm_data) { | ||
305 | kfree(mvm->eeprom_blob); | ||
306 | mvm->eeprom_blob = NULL; | ||
307 | ret = -ENOMEM; | ||
308 | } | ||
309 | 236 | ||
310 | return ret; | 237 | return ret; |
311 | } | 238 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index aa59adf87db3..fe031d304d1e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -143,21 +143,12 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) | |||
143 | u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; | 143 | u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; |
144 | u32 reg_val = 0; | 144 | u32 reg_val = 0; |
145 | 145 | ||
146 | /* | 146 | radio_cfg_type = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_TYPE) >> |
147 | * We can't upload the correct value to the INIT image | 147 | FW_PHY_CFG_RADIO_TYPE_POS; |
148 | * as we don't have nvm_data by that time. | 148 | radio_cfg_step = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_STEP) >> |
149 | * | 149 | FW_PHY_CFG_RADIO_STEP_POS; |
150 | * TODO: Figure out what we should do here | 150 | radio_cfg_dash = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_DASH) >> |
151 | */ | 151 | FW_PHY_CFG_RADIO_DASH_POS; |
152 | if (mvm->nvm_data) { | ||
153 | radio_cfg_type = mvm->nvm_data->radio_cfg_type; | ||
154 | radio_cfg_step = mvm->nvm_data->radio_cfg_step; | ||
155 | radio_cfg_dash = mvm->nvm_data->radio_cfg_dash; | ||
156 | } else { | ||
157 | radio_cfg_type = 0; | ||
158 | radio_cfg_step = 0; | ||
159 | radio_cfg_dash = 0; | ||
160 | } | ||
161 | 152 | ||
162 | /* SKU control */ | 153 | /* SKU control */ |
163 | reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) << | 154 | reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) << |
@@ -175,7 +166,6 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) | |||
175 | 166 | ||
176 | /* silicon bits */ | 167 | /* silicon bits */ |
177 | reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; | 168 | reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; |
178 | reg_val |= CSR_HW_IF_CONFIG_REG_BIT_MAC_SI; | ||
179 | 169 | ||
180 | iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, | 170 | iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, |
181 | CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | | 171 | CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | |
@@ -230,6 +220,9 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | |||
230 | RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), | 220 | RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), |
231 | RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), | 221 | RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), |
232 | 222 | ||
223 | RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true), | ||
224 | RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false), | ||
225 | |||
233 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), | 226 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), |
234 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), | 227 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), |
235 | 228 | ||
@@ -274,6 +267,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
274 | CMD(WEP_KEY), | 267 | CMD(WEP_KEY), |
275 | CMD(REPLY_RX_PHY_CMD), | 268 | CMD(REPLY_RX_PHY_CMD), |
276 | CMD(REPLY_RX_MPDU_CMD), | 269 | CMD(REPLY_RX_MPDU_CMD), |
270 | CMD(BEACON_NOTIFICATION), | ||
277 | CMD(BEACON_TEMPLATE_CMD), | 271 | CMD(BEACON_TEMPLATE_CMD), |
278 | CMD(STATISTICS_NOTIFICATION), | 272 | CMD(STATISTICS_NOTIFICATION), |
279 | CMD(TX_ANT_CONFIGURATION_CMD), | 273 | CMD(TX_ANT_CONFIGURATION_CMD), |
@@ -293,6 +287,11 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
293 | CMD(NET_DETECT_PROFILES_CMD), | 287 | CMD(NET_DETECT_PROFILES_CMD), |
294 | CMD(NET_DETECT_HOTSPOTS_CMD), | 288 | CMD(NET_DETECT_HOTSPOTS_CMD), |
295 | CMD(NET_DETECT_HOTSPOTS_QUERY_CMD), | 289 | CMD(NET_DETECT_HOTSPOTS_QUERY_CMD), |
290 | CMD(CARD_STATE_NOTIFICATION), | ||
291 | CMD(BT_COEX_PRIO_TABLE), | ||
292 | CMD(BT_COEX_PROT_ENV), | ||
293 | CMD(BT_PROFILE_NOTIFICATION), | ||
294 | CMD(BT_CONFIG), | ||
296 | }; | 295 | }; |
297 | #undef CMD | 296 | #undef CMD |
298 | 297 | ||
@@ -312,16 +311,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
312 | }; | 311 | }; |
313 | int err, scan_size; | 312 | int err, scan_size; |
314 | 313 | ||
315 | switch (cfg->device_family) { | ||
316 | case IWL_DEVICE_FAMILY_6030: | ||
317 | case IWL_DEVICE_FAMILY_6005: | ||
318 | case IWL_DEVICE_FAMILY_7000: | ||
319 | break; | ||
320 | default: | ||
321 | IWL_ERR(trans, "Trying to load mvm on an unsupported device\n"); | ||
322 | return NULL; | ||
323 | } | ||
324 | |||
325 | /******************************** | 314 | /******************************** |
326 | * 1. Allocating and configuring HW data | 315 | * 1. Allocating and configuring HW data |
327 | ********************************/ | 316 | ********************************/ |
@@ -363,8 +352,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
363 | trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); | 352 | trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); |
364 | trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; | 353 | trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; |
365 | 354 | ||
366 | /* TODO: this should really be a TLV */ | 355 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE) |
367 | if (cfg->device_family == IWL_DEVICE_FAMILY_7000) | ||
368 | trans_cfg.bc_table_dword = true; | 356 | trans_cfg.bc_table_dword = true; |
369 | 357 | ||
370 | if (!iwlwifi_mod_params.wd_disable) | 358 | if (!iwlwifi_mod_params.wd_disable) |
@@ -438,7 +426,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
438 | out_free: | 426 | out_free: |
439 | iwl_phy_db_free(mvm->phy_db); | 427 | iwl_phy_db_free(mvm->phy_db); |
440 | kfree(mvm->scan_cmd); | 428 | kfree(mvm->scan_cmd); |
441 | kfree(mvm->eeprom_blob); | ||
442 | iwl_trans_stop_hw(trans, true); | 429 | iwl_trans_stop_hw(trans, true); |
443 | ieee80211_free_hw(mvm->hw); | 430 | ieee80211_free_hw(mvm->hw); |
444 | return NULL; | 431 | return NULL; |
@@ -460,7 +447,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) | |||
460 | iwl_phy_db_free(mvm->phy_db); | 447 | iwl_phy_db_free(mvm->phy_db); |
461 | mvm->phy_db = NULL; | 448 | mvm->phy_db = NULL; |
462 | 449 | ||
463 | kfree(mvm->eeprom_blob); | ||
464 | iwl_free_nvm_data(mvm->nvm_data); | 450 | iwl_free_nvm_data(mvm->nvm_data); |
465 | for (i = 0; i < NVM_NUM_OF_SECTIONS; i++) | 451 | for (i = 0; i < NVM_NUM_OF_SECTIONS; i++) |
466 | kfree(mvm->nvm_sections[i].data); | 452 | kfree(mvm->nvm_sections[i].data); |
@@ -624,12 +610,8 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) | |||
624 | ieee80211_free_txskb(mvm->hw, skb); | 610 | ieee80211_free_txskb(mvm->hw, skb); |
625 | } | 611 | } |
626 | 612 | ||
627 | static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) | 613 | static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) |
628 | { | 614 | { |
629 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
630 | |||
631 | iwl_mvm_dump_nic_error_log(mvm); | ||
632 | |||
633 | iwl_abort_notification_waits(&mvm->notif_wait); | 615 | iwl_abort_notification_waits(&mvm->notif_wait); |
634 | 616 | ||
635 | /* | 617 | /* |
@@ -663,9 +645,21 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) | |||
663 | } | 645 | } |
664 | } | 646 | } |
665 | 647 | ||
648 | static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) | ||
649 | { | ||
650 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
651 | |||
652 | iwl_mvm_dump_nic_error_log(mvm); | ||
653 | |||
654 | iwl_mvm_nic_restart(mvm); | ||
655 | } | ||
656 | |||
666 | static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) | 657 | static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) |
667 | { | 658 | { |
659 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
660 | |||
668 | WARN_ON(1); | 661 | WARN_ON(1); |
662 | iwl_mvm_nic_restart(mvm); | ||
669 | } | 663 | } |
670 | 664 | ||
671 | static const struct iwl_op_mode_ops iwl_mvm_ops = { | 665 | static const struct iwl_op_mode_ops iwl_mvm_ops = { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index b428448f8ddf..0f0b44eabd93 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -142,7 +142,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, | |||
142 | struct cfg80211_chan_def *chandef, | 142 | struct cfg80211_chan_def *chandef, |
143 | u8 chains_static, u8 chains_dynamic) | 143 | u8 chains_static, u8 chains_dynamic) |
144 | { | 144 | { |
145 | u8 valid_rx_chains, active_cnt, idle_cnt; | 145 | u8 active_cnt, idle_cnt; |
146 | 146 | ||
147 | /* Set the channel info data */ | 147 | /* Set the channel info data */ |
148 | cmd->ci.band = (chandef->chan->band == IEEE80211_BAND_2GHZ ? | 148 | cmd->ci.band = (chandef->chan->band == IEEE80211_BAND_2GHZ ? |
@@ -158,17 +158,16 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, | |||
158 | * Need to add on chain noise calibration limitations, and | 158 | * Need to add on chain noise calibration limitations, and |
159 | * BT coex considerations. | 159 | * BT coex considerations. |
160 | */ | 160 | */ |
161 | valid_rx_chains = mvm->nvm_data->valid_rx_ant; | ||
162 | idle_cnt = chains_static; | 161 | idle_cnt = chains_static; |
163 | active_cnt = chains_dynamic; | 162 | active_cnt = chains_dynamic; |
164 | 163 | ||
165 | cmd->rxchain_info = cpu_to_le32(valid_rx_chains << | 164 | cmd->rxchain_info = cpu_to_le32(iwl_fw_valid_rx_ant(mvm->fw) << |
166 | PHY_RX_CHAIN_VALID_POS); | 165 | PHY_RX_CHAIN_VALID_POS); |
167 | cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); | 166 | cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); |
168 | cmd->rxchain_info |= cpu_to_le32(active_cnt << | 167 | cmd->rxchain_info |= cpu_to_le32(active_cnt << |
169 | PHY_RX_CHAIN_MIMO_CNT_POS); | 168 | PHY_RX_CHAIN_MIMO_CNT_POS); |
170 | 169 | ||
171 | cmd->txchain_info = cpu_to_le32(mvm->nvm_data->valid_tx_ant); | 170 | cmd->txchain_info = cpu_to_le32(iwl_fw_valid_tx_ant(mvm->fw)); |
172 | } | 171 | } |
173 | 172 | ||
174 | /* | 173 | /* |
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 5a92a4978795..9395ab2a1af2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -75,23 +75,49 @@ | |||
75 | 75 | ||
76 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 | 76 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 |
77 | 77 | ||
78 | static void iwl_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 78 | static void iwl_mvm_power_log(struct iwl_mvm *mvm, |
79 | struct iwl_powertable_cmd *cmd) | 79 | struct iwl_powertable_cmd *cmd) |
80 | { | ||
81 | IWL_DEBUG_POWER(mvm, | ||
82 | "Sending power table command for power level %d, flags = 0x%X\n", | ||
83 | iwlmvm_mod_params.power_scheme, | ||
84 | le16_to_cpu(cmd->flags)); | ||
85 | IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", cmd->keep_alive_seconds); | ||
86 | |||
87 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | ||
88 | IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", | ||
89 | le32_to_cpu(cmd->rx_data_timeout)); | ||
90 | IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", | ||
91 | le32_to_cpu(cmd->tx_data_timeout)); | ||
92 | IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", | ||
93 | cmd->lprx_rssi_threshold); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
98 | struct iwl_powertable_cmd *cmd) | ||
80 | { | 99 | { |
81 | struct ieee80211_hw *hw = mvm->hw; | 100 | struct ieee80211_hw *hw = mvm->hw; |
82 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
83 | struct ieee80211_chanctx_conf *chanctx_conf; | 101 | struct ieee80211_chanctx_conf *chanctx_conf; |
84 | struct ieee80211_channel *chan; | 102 | struct ieee80211_channel *chan; |
85 | int dtimper, dtimper_msec; | 103 | int dtimper, dtimper_msec; |
86 | int keep_alive; | 104 | int keep_alive; |
87 | bool radar_detect = false; | 105 | bool radar_detect = false; |
88 | 106 | ||
89 | cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | 107 | /* |
90 | mvmvif->color)); | 108 | * Regardless of power management state the driver must set |
91 | cmd->action = cpu_to_le32(FW_CTXT_ACTION_MODIFY); | 109 | * keep alive period. FW will use it for sending keep alive NDPs |
110 | * immediately after association. | ||
111 | */ | ||
112 | cmd->keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC; | ||
113 | |||
114 | if ((iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) || | ||
115 | !iwlwifi_mod_params.power_save) | ||
116 | return; | ||
117 | |||
118 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
92 | 119 | ||
93 | if ((!vif->bss_conf.ps) || | 120 | if (!vif->bss_conf.ps) |
94 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)) | ||
95 | return; | 121 | return; |
96 | 122 | ||
97 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); | 123 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); |
@@ -110,26 +136,23 @@ static void iwl_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
110 | 136 | ||
111 | /* Check skip over DTIM conditions */ | 137 | /* Check skip over DTIM conditions */ |
112 | if (!radar_detect && (dtimper <= 10) && | 138 | if (!radar_detect && (dtimper <= 10) && |
113 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP)) { | 139 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP)) |
114 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SLEEP_OVER_DTIM_MSK); | 140 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); |
115 | cmd->num_skip_dtim = 2; | ||
116 | } | ||
117 | 141 | ||
118 | /* Check that keep alive period is at least 3 * DTIM */ | 142 | /* Check that keep alive period is at least 3 * DTIM */ |
119 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; | 143 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; |
120 | keep_alive = max_t(int, 3 * dtimper_msec, | 144 | keep_alive = max_t(int, 3 * dtimper_msec, |
121 | MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC); | 145 | MSEC_PER_SEC * cmd->keep_alive_seconds); |
122 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); | 146 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); |
123 | 147 | cmd->keep_alive_seconds = keep_alive; | |
124 | cmd->keep_alive_seconds = cpu_to_le16(keep_alive); | ||
125 | 148 | ||
126 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP) { | 149 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP) { |
127 | /* TODO: Also for D3 (device sleep / WoWLAN) */ | 150 | /* TODO: Also for D3 (device sleep / WoWLAN) */ |
128 | cmd->rx_data_timeout = cpu_to_le32(10); | 151 | cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); |
129 | cmd->tx_data_timeout = cpu_to_le32(10); | 152 | cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); |
130 | } else { | 153 | } else { |
131 | cmd->rx_data_timeout = cpu_to_le32(50); | 154 | cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); |
132 | cmd->tx_data_timeout = cpu_to_le32(50); | 155 | cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); |
133 | } | 156 | } |
134 | } | 157 | } |
135 | 158 | ||
@@ -137,36 +160,11 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
137 | { | 160 | { |
138 | struct iwl_powertable_cmd cmd = {}; | 161 | struct iwl_powertable_cmd cmd = {}; |
139 | 162 | ||
140 | if (!iwlwifi_mod_params.power_save) { | ||
141 | IWL_DEBUG_POWER(mvm, "Power management is not allowed\n"); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 163 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
146 | return 0; | 164 | return 0; |
147 | 165 | ||
148 | iwl_power_build_cmd(mvm, vif, &cmd); | 166 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); |
149 | 167 | iwl_mvm_power_log(mvm, &cmd); | |
150 | IWL_DEBUG_POWER(mvm, | ||
151 | "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n", | ||
152 | cmd.id_and_color, iwlmvm_mod_params.power_scheme, | ||
153 | le16_to_cpu(cmd.flags)); | ||
154 | |||
155 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | ||
156 | IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", | ||
157 | le16_to_cpu(cmd.keep_alive_seconds)); | ||
158 | IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", | ||
159 | le32_to_cpu(cmd.rx_data_timeout)); | ||
160 | IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", | ||
161 | le32_to_cpu(cmd.tx_data_timeout)); | ||
162 | IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n", | ||
163 | le32_to_cpu(cmd.rx_data_timeout_uapsd)); | ||
164 | IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", | ||
165 | le32_to_cpu(cmd.tx_data_timeout_uapsd)); | ||
166 | IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", | ||
167 | cmd.lprx_rssi_threshold); | ||
168 | IWL_DEBUG_POWER(mvm, "DTIMs to skip = %u\n", cmd.num_skip_dtim); | ||
169 | } | ||
170 | 168 | ||
171 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | 169 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, |
172 | sizeof(cmd), &cmd); | 170 | sizeof(cmd), &cmd); |
@@ -175,33 +173,16 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
175 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 173 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
176 | { | 174 | { |
177 | struct iwl_powertable_cmd cmd = {}; | 175 | struct iwl_powertable_cmd cmd = {}; |
178 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
179 | |||
180 | if (!iwlwifi_mod_params.power_save) { | ||
181 | IWL_DEBUG_POWER(mvm, "Power management is not allowed\n"); | ||
182 | return 0; | ||
183 | } | ||
184 | 176 | ||
185 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 177 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
186 | return 0; | 178 | return 0; |
187 | 179 | ||
188 | cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | 180 | if ((iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) && |
189 | mvmvif->color)); | 181 | iwlwifi_mod_params.power_save) |
190 | cmd.action = cpu_to_le32(FW_CTXT_ACTION_MODIFY); | 182 | cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); |
191 | 183 | ||
192 | IWL_DEBUG_POWER(mvm, | 184 | iwl_mvm_power_log(mvm, &cmd); |
193 | "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n", | ||
194 | cmd.id_and_color, iwlmvm_mod_params.power_scheme, | ||
195 | le16_to_cpu(cmd.flags)); | ||
196 | 185 | ||
197 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, | 186 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, |
198 | sizeof(cmd), &cmd); | 187 | sizeof(cmd), &cmd); |
199 | } | 188 | } |
200 | |||
201 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
202 | void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
203 | struct iwl_powertable_cmd *cmd) | ||
204 | { | ||
205 | iwl_power_build_cmd(mvm, vif, cmd); | ||
206 | } | ||
207 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 925628468146..a1e3e923ea3e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -114,7 +114,8 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, | |||
114 | data->n_interfaces[id]++; | 114 | data->n_interfaces[id]++; |
115 | break; | 115 | break; |
116 | case NL80211_IFTYPE_MONITOR: | 116 | case NL80211_IFTYPE_MONITOR: |
117 | data->n_interfaces[id]++; | 117 | if (mvmvif->monitor_active) |
118 | data->n_interfaces[id]++; | ||
118 | break; | 119 | break; |
119 | case NL80211_IFTYPE_P2P_DEVICE: | 120 | case NL80211_IFTYPE_P2P_DEVICE: |
120 | break; | 121 | break; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 56b636d9ab30..55334d542e26 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
@@ -680,12 +680,14 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, | |||
680 | */ | 680 | */ |
681 | static bool rs_use_green(struct ieee80211_sta *sta) | 681 | static bool rs_use_green(struct ieee80211_sta *sta) |
682 | { | 682 | { |
683 | struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; | 683 | /* |
684 | 684 | * There's a bug somewhere in this code that causes the | |
685 | bool use_green = !(sta_priv->vif->bss_conf.ht_operation_mode & | 685 | * scaling to get stuck because GF+SGI can't be combined |
686 | IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); | 686 | * in SISO rates. Until we find that bug, disable GF, it |
687 | 687 | * has only limited benefit and we still interoperate with | |
688 | return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && use_green; | 688 | * GF APs since we can always receive GF transmissions. |
689 | */ | ||
690 | return false; | ||
689 | } | 691 | } |
690 | 692 | ||
691 | /** | 693 | /** |
@@ -791,7 +793,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, | |||
791 | 793 | ||
792 | if (num_of_ant(tbl->ant_type) > 1) | 794 | if (num_of_ant(tbl->ant_type) > 1) |
793 | tbl->ant_type = | 795 | tbl->ant_type = |
794 | first_antenna(mvm->nvm_data->valid_tx_ant); | 796 | first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); |
795 | 797 | ||
796 | tbl->is_ht40 = 0; | 798 | tbl->is_ht40 = 0; |
797 | tbl->is_SGI = 0; | 799 | tbl->is_SGI = 0; |
@@ -1233,7 +1235,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | |||
1233 | return -1; | 1235 | return -1; |
1234 | 1236 | ||
1235 | /* Need both Tx chains/antennas to support MIMO */ | 1237 | /* Need both Tx chains/antennas to support MIMO */ |
1236 | if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 2) | 1238 | if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2) |
1237 | return -1; | 1239 | return -1; |
1238 | 1240 | ||
1239 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n"); | 1241 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n"); |
@@ -1285,7 +1287,7 @@ static int rs_switch_to_mimo3(struct iwl_mvm *mvm, | |||
1285 | return -1; | 1287 | return -1; |
1286 | 1288 | ||
1287 | /* Need both Tx chains/antennas to support MIMO */ | 1289 | /* Need both Tx chains/antennas to support MIMO */ |
1288 | if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 3) | 1290 | if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 3) |
1289 | return -1; | 1291 | return -1; |
1290 | 1292 | ||
1291 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO3\n"); | 1293 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO3\n"); |
@@ -1379,7 +1381,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, | |||
1379 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | 1381 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - |
1380 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | 1382 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); |
1381 | u8 start_action; | 1383 | u8 start_action; |
1382 | u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; | 1384 | u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); |
1383 | u8 tx_chains_num = num_of_ant(valid_tx_ant); | 1385 | u8 tx_chains_num = num_of_ant(valid_tx_ant); |
1384 | int ret; | 1386 | int ret; |
1385 | u8 update_search_tbl_counter = 0; | 1387 | u8 update_search_tbl_counter = 0; |
@@ -1512,7 +1514,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, | |||
1512 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | 1514 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - |
1513 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | 1515 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); |
1514 | u8 start_action; | 1516 | u8 start_action; |
1515 | u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; | 1517 | u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); |
1516 | u8 tx_chains_num = num_of_ant(valid_tx_ant); | 1518 | u8 tx_chains_num = num_of_ant(valid_tx_ant); |
1517 | u8 update_search_tbl_counter = 0; | 1519 | u8 update_search_tbl_counter = 0; |
1518 | int ret; | 1520 | int ret; |
@@ -1647,7 +1649,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | |||
1647 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | 1649 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - |
1648 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | 1650 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); |
1649 | u8 start_action; | 1651 | u8 start_action; |
1650 | u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; | 1652 | u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); |
1651 | u8 tx_chains_num = num_of_ant(valid_tx_ant); | 1653 | u8 tx_chains_num = num_of_ant(valid_tx_ant); |
1652 | u8 update_search_tbl_counter = 0; | 1654 | u8 update_search_tbl_counter = 0; |
1653 | int ret; | 1655 | int ret; |
@@ -1784,7 +1786,7 @@ static int rs_move_mimo3_to_other(struct iwl_mvm *mvm, | |||
1784 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | 1786 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - |
1785 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | 1787 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); |
1786 | u8 start_action; | 1788 | u8 start_action; |
1787 | u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; | 1789 | u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); |
1788 | u8 tx_chains_num = num_of_ant(valid_tx_ant); | 1790 | u8 tx_chains_num = num_of_ant(valid_tx_ant); |
1789 | int ret; | 1791 | int ret; |
1790 | u8 update_search_tbl_counter = 0; | 1792 | u8 update_search_tbl_counter = 0; |
@@ -2447,7 +2449,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, | |||
2447 | 2449 | ||
2448 | i = lq_sta->last_txrate_idx; | 2450 | i = lq_sta->last_txrate_idx; |
2449 | 2451 | ||
2450 | valid_tx_ant = mvm->nvm_data->valid_tx_ant; | 2452 | valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); |
2451 | 2453 | ||
2452 | if (!lq_sta->search_better_tbl) | 2454 | if (!lq_sta->search_better_tbl) |
2453 | active_tbl = lq_sta->active_tbl; | 2455 | active_tbl = lq_sta->active_tbl; |
@@ -2637,15 +2639,15 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2637 | 2639 | ||
2638 | /* These values will be overridden later */ | 2640 | /* These values will be overridden later */ |
2639 | lq_sta->lq.single_stream_ant_msk = | 2641 | lq_sta->lq.single_stream_ant_msk = |
2640 | first_antenna(mvm->nvm_data->valid_tx_ant); | 2642 | first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); |
2641 | lq_sta->lq.dual_stream_ant_msk = | 2643 | lq_sta->lq.dual_stream_ant_msk = |
2642 | mvm->nvm_data->valid_tx_ant & | 2644 | iwl_fw_valid_tx_ant(mvm->fw) & |
2643 | ~first_antenna(mvm->nvm_data->valid_tx_ant); | 2645 | ~first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); |
2644 | if (!lq_sta->lq.dual_stream_ant_msk) { | 2646 | if (!lq_sta->lq.dual_stream_ant_msk) { |
2645 | lq_sta->lq.dual_stream_ant_msk = ANT_AB; | 2647 | lq_sta->lq.dual_stream_ant_msk = ANT_AB; |
2646 | } else if (num_of_ant(mvm->nvm_data->valid_tx_ant) == 2) { | 2648 | } else if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) == 2) { |
2647 | lq_sta->lq.dual_stream_ant_msk = | 2649 | lq_sta->lq.dual_stream_ant_msk = |
2648 | mvm->nvm_data->valid_tx_ant; | 2650 | iwl_fw_valid_tx_ant(mvm->fw); |
2649 | } | 2651 | } |
2650 | 2652 | ||
2651 | /* as default allow aggregation for all tids */ | 2653 | /* as default allow aggregation for all tids */ |
@@ -2706,7 +2708,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, | |||
2706 | index++; | 2708 | index++; |
2707 | repeat_rate--; | 2709 | repeat_rate--; |
2708 | if (mvm) | 2710 | if (mvm) |
2709 | valid_tx_ant = mvm->nvm_data->valid_tx_ant; | 2711 | valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); |
2710 | 2712 | ||
2711 | /* Fill rest of rate table */ | 2713 | /* Fill rest of rate table */ |
2712 | while (index < LINK_QUAL_MAX_RETRY_NUM) { | 2714 | while (index < LINK_QUAL_MAX_RETRY_NUM) { |
@@ -2811,7 +2813,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, | |||
2811 | u8 ant_sel_tx; | 2813 | u8 ant_sel_tx; |
2812 | 2814 | ||
2813 | mvm = lq_sta->drv; | 2815 | mvm = lq_sta->drv; |
2814 | valid_tx_ant = mvm->nvm_data->valid_tx_ant; | 2816 | valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); |
2815 | if (lq_sta->dbg_fixed_rate) { | 2817 | if (lq_sta->dbg_fixed_rate) { |
2816 | ant_sel_tx = | 2818 | ant_sel_tx = |
2817 | ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) | 2819 | ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) |
@@ -2882,9 +2884,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | |||
2882 | desc += sprintf(buff+desc, "fixed rate 0x%X\n", | 2884 | desc += sprintf(buff+desc, "fixed rate 0x%X\n", |
2883 | lq_sta->dbg_fixed_rate); | 2885 | lq_sta->dbg_fixed_rate); |
2884 | desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n", | 2886 | desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n", |
2885 | (mvm->nvm_data->valid_tx_ant & ANT_A) ? "ANT_A," : "", | 2887 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_A) ? "ANT_A," : "", |
2886 | (mvm->nvm_data->valid_tx_ant & ANT_B) ? "ANT_B," : "", | 2888 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "", |
2887 | (mvm->nvm_data->valid_tx_ant & ANT_C) ? "ANT_C" : ""); | 2889 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : ""); |
2888 | desc += sprintf(buff+desc, "lq type %s\n", | 2890 | desc += sprintf(buff+desc, "lq type %s\n", |
2889 | (is_legacy(tbl->lq_type)) ? "legacy" : "HT"); | 2891 | (is_legacy(tbl->lq_type)) ? "legacy" : "HT"); |
2890 | if (is_Ht(tbl->lq_type)) { | 2892 | if (is_Ht(tbl->lq_type)) { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 3f40ab05bbd8..4dfc21a3e83e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -131,33 +131,42 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, | |||
131 | static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm, | 131 | static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm, |
132 | struct iwl_rx_phy_info *phy_info) | 132 | struct iwl_rx_phy_info *phy_info) |
133 | { | 133 | { |
134 | u32 rssi_a, rssi_b, rssi_c, max_rssi, agc_db; | 134 | int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; |
135 | int rssi_all_band_a, rssi_all_band_b; | ||
136 | u32 agc_a, agc_b, max_agc; | ||
135 | u32 val; | 137 | u32 val; |
136 | 138 | ||
137 | /* Find max rssi among 3 possible receivers. | 139 | /* Find max rssi among 2 possible receivers. |
138 | * These values are measured by the Digital Signal Processor (DSP). | 140 | * These values are measured by the Digital Signal Processor (DSP). |
139 | * They should stay fairly constant even as the signal strength varies, | 141 | * They should stay fairly constant even as the signal strength varies, |
140 | * if the radio's Automatic Gain Control (AGC) is working right. | 142 | * if the radio's Automatic Gain Control (AGC) is working right. |
141 | * AGC value (see below) will provide the "interesting" info. | 143 | * AGC value (see below) will provide the "interesting" info. |
142 | */ | 144 | */ |
145 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); | ||
146 | agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS; | ||
147 | agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS; | ||
148 | max_agc = max_t(u32, agc_a, agc_b); | ||
149 | |||
143 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]); | 150 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]); |
144 | rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS; | 151 | rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS; |
145 | rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; | 152 | rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; |
146 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_C_IDX]); | 153 | rssi_all_band_a = (val & IWL_OFDM_RSSI_ALLBAND_A_MSK) >> |
147 | rssi_c = (val & IWL_OFDM_RSSI_INBAND_C_MSK) >> IWL_OFDM_RSSI_C_POS; | 154 | IWL_OFDM_RSSI_ALLBAND_A_POS; |
148 | 155 | rssi_all_band_b = (val & IWL_OFDM_RSSI_ALLBAND_B_MSK) >> | |
149 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); | 156 | IWL_OFDM_RSSI_ALLBAND_B_POS; |
150 | agc_db = (val & IWL_OFDM_AGC_DB_MSK) >> IWL_OFDM_AGC_DB_POS; | ||
151 | 157 | ||
152 | max_rssi = max_t(u32, rssi_a, rssi_b); | 158 | /* |
153 | max_rssi = max_t(u32, max_rssi, rssi_c); | 159 | * dBm = rssi dB - agc dB - constant. |
160 | * Higher AGC (higher radio gain) means lower signal. | ||
161 | */ | ||
162 | rssi_a_dbm = rssi_a - IWL_RSSI_OFFSET - agc_a; | ||
163 | rssi_b_dbm = rssi_b - IWL_RSSI_OFFSET - agc_b; | ||
164 | max_rssi_dbm = max_t(int, rssi_a_dbm, rssi_b_dbm); | ||
154 | 165 | ||
155 | IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d C %d Max %d AGC dB %d\n", | 166 | IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d Max %d AGCA %d AGCB %d\n", |
156 | rssi_a, rssi_b, rssi_c, max_rssi, agc_db); | 167 | rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b); |
157 | 168 | ||
158 | /* dBm = max_rssi dB - agc dB - constant. | 169 | return max_rssi_dbm; |
159 | * Higher AGC (higher radio gain) means lower signal. */ | ||
160 | return max_rssi - agc_db - IWL_RSSI_OFFSET; | ||
161 | } | 170 | } |
162 | 171 | ||
163 | /* | 172 | /* |
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 9b21b92aa8d1..2157b0f8ced5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -74,7 +74,7 @@ | |||
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 = mvm->nvm_data->valid_rx_ant; | 77 | u8 rx_ant = iwl_fw_valid_rx_ant(mvm->fw); |
78 | 78 | ||
79 | rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; | 79 | rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; |
80 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; | 80 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; |
@@ -115,7 +115,7 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band, | |||
115 | u32 tx_ant; | 115 | u32 tx_ant; |
116 | 116 | ||
117 | mvm->scan_last_antenna_idx = | 117 | mvm->scan_last_antenna_idx = |
118 | iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant, | 118 | iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw), |
119 | mvm->scan_last_antenna_idx); | 119 | mvm->scan_last_antenna_idx); |
120 | tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS; | 120 | tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS; |
121 | 121 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 52aecf20d0df..0fd96e4da461 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -101,8 +101,55 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
101 | } | 101 | } |
102 | add_sta_cmd.add_modify = update ? 1 : 0; | 102 | add_sta_cmd.add_modify = update ? 1 : 0; |
103 | 103 | ||
104 | /* STA_FLG_FAT_EN_MSK ? */ | 104 | add_sta_cmd.station_flags_msk |= cpu_to_le32(STA_FLG_FAT_EN_MSK | |
105 | /* STA_FLG_MIMO_EN_MSK ? */ | 105 | STA_FLG_MIMO_EN_MSK); |
106 | |||
107 | switch (sta->bandwidth) { | ||
108 | case IEEE80211_STA_RX_BW_160: | ||
109 | add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_160MHZ); | ||
110 | /* fall through */ | ||
111 | case IEEE80211_STA_RX_BW_80: | ||
112 | add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_80MHZ); | ||
113 | /* fall through */ | ||
114 | case IEEE80211_STA_RX_BW_40: | ||
115 | add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_40MHZ); | ||
116 | /* fall through */ | ||
117 | case IEEE80211_STA_RX_BW_20: | ||
118 | if (sta->ht_cap.ht_supported) | ||
119 | add_sta_cmd.station_flags |= | ||
120 | cpu_to_le32(STA_FLG_FAT_EN_20MHZ); | ||
121 | break; | ||
122 | } | ||
123 | |||
124 | switch (sta->rx_nss) { | ||
125 | case 1: | ||
126 | add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_SISO); | ||
127 | break; | ||
128 | case 2: | ||
129 | add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_MIMO2); | ||
130 | break; | ||
131 | case 3 ... 8: | ||
132 | add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_MIMO3); | ||
133 | break; | ||
134 | } | ||
135 | |||
136 | switch (sta->smps_mode) { | ||
137 | case IEEE80211_SMPS_AUTOMATIC: | ||
138 | case IEEE80211_SMPS_NUM_MODES: | ||
139 | WARN_ON(1); | ||
140 | break; | ||
141 | case IEEE80211_SMPS_STATIC: | ||
142 | /* override NSS */ | ||
143 | add_sta_cmd.station_flags &= ~cpu_to_le32(STA_FLG_MIMO_EN_MSK); | ||
144 | add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_SISO); | ||
145 | break; | ||
146 | case IEEE80211_SMPS_DYNAMIC: | ||
147 | add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_RTS_MIMO_PROT); | ||
148 | break; | ||
149 | case IEEE80211_SMPS_OFF: | ||
150 | /* nothing */ | ||
151 | break; | ||
152 | } | ||
106 | 153 | ||
107 | if (sta->ht_cap.ht_supported) { | 154 | if (sta->ht_cap.ht_supported) { |
108 | add_sta_cmd.station_flags_msk |= | 155 | add_sta_cmd.station_flags_msk |= |
@@ -340,6 +387,9 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | |||
340 | 387 | ||
341 | if (vif->type == NL80211_IFTYPE_STATION && | 388 | if (vif->type == NL80211_IFTYPE_STATION && |
342 | mvmvif->ap_sta_id == mvm_sta->sta_id) { | 389 | mvmvif->ap_sta_id == mvm_sta->sta_id) { |
390 | /* flush its queues here since we are freeing mvm_sta */ | ||
391 | ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true); | ||
392 | |||
343 | /* | 393 | /* |
344 | * Put a non-NULL since the fw station isn't removed. | 394 | * Put a non-NULL since the fw station isn't removed. |
345 | * It will be removed after the MAC will be set as | 395 | * It will be removed after the MAC will be set as |
@@ -348,9 +398,6 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | |||
348 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], | 398 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], |
349 | ERR_PTR(-EINVAL)); | 399 | ERR_PTR(-EINVAL)); |
350 | 400 | ||
351 | /* flush its queues here since we are freeing mvm_sta */ | ||
352 | ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true); | ||
353 | |||
354 | /* if we are associated - we can't remove the AP STA now */ | 401 | /* if we are associated - we can't remove the AP STA now */ |
355 | if (vif->bss_conf.assoc) | 402 | if (vif->bss_conf.assoc) |
356 | return ret; | 403 | return ret; |
@@ -770,6 +817,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
770 | u16 txq_id; | 817 | u16 txq_id; |
771 | int err; | 818 | int err; |
772 | 819 | ||
820 | |||
821 | /* | ||
822 | * If mac80211 is cleaning its state, then say that we finished since | ||
823 | * our state has been cleared anyway. | ||
824 | */ | ||
825 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | ||
826 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||
827 | return 0; | ||
828 | } | ||
829 | |||
773 | spin_lock_bh(&mvmsta->lock); | 830 | spin_lock_bh(&mvmsta->lock); |
774 | 831 | ||
775 | txq_id = tid_data->txq_id; | 832 | txq_id = tid_data->txq_id; |
@@ -824,6 +881,34 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
824 | return err; | 881 | return err; |
825 | } | 882 | } |
826 | 883 | ||
884 | int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
885 | struct ieee80211_sta *sta, u16 tid) | ||
886 | { | ||
887 | struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; | ||
888 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; | ||
889 | u16 txq_id; | ||
890 | |||
891 | /* | ||
892 | * First set the agg state to OFF to avoid calling | ||
893 | * ieee80211_stop_tx_ba_cb in iwl_mvm_check_ratid_empty. | ||
894 | */ | ||
895 | spin_lock_bh(&mvmsta->lock); | ||
896 | txq_id = tid_data->txq_id; | ||
897 | IWL_DEBUG_TX_QUEUES(mvm, "Flush AGG: sta %d tid %d q %d state %d\n", | ||
898 | mvmsta->sta_id, tid, txq_id, tid_data->state); | ||
899 | tid_data->state = IWL_AGG_OFF; | ||
900 | spin_unlock_bh(&mvmsta->lock); | ||
901 | |||
902 | if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true)) | ||
903 | IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); | ||
904 | |||
905 | iwl_trans_txq_disable(mvm->trans, tid_data->txq_id); | ||
906 | mvm->queue_to_mac80211[tid_data->txq_id] = | ||
907 | IWL_INVALID_MAC80211_QUEUE; | ||
908 | |||
909 | return 0; | ||
910 | } | ||
911 | |||
827 | static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm) | 912 | static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm) |
828 | { | 913 | { |
829 | int i; | 914 | int i; |
@@ -860,7 +945,7 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, | |||
860 | mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) | 945 | mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) |
861 | return mvmvif->ap_sta_id; | 946 | return mvmvif->ap_sta_id; |
862 | 947 | ||
863 | return IWL_INVALID_STATION; | 948 | return IWL_MVM_STATION_COUNT; |
864 | } | 949 | } |
865 | 950 | ||
866 | static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, | 951 | static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, |
@@ -1008,7 +1093,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, | |||
1008 | 1093 | ||
1009 | /* Get the station id from the mvm local station table */ | 1094 | /* Get the station id from the mvm local station table */ |
1010 | sta_id = iwl_mvm_get_key_sta_id(vif, sta); | 1095 | sta_id = iwl_mvm_get_key_sta_id(vif, sta); |
1011 | if (sta_id == IWL_INVALID_STATION) { | 1096 | if (sta_id == IWL_MVM_STATION_COUNT) { |
1012 | IWL_ERR(mvm, "Failed to find station id\n"); | 1097 | IWL_ERR(mvm, "Failed to find station id\n"); |
1013 | return -EINVAL; | 1098 | return -EINVAL; |
1014 | } | 1099 | } |
@@ -1103,7 +1188,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | |||
1103 | return -ENOENT; | 1188 | return -ENOENT; |
1104 | } | 1189 | } |
1105 | 1190 | ||
1106 | if (sta_id == IWL_INVALID_STATION) { | 1191 | if (sta_id == IWL_MVM_STATION_COUNT) { |
1107 | IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n"); | 1192 | IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n"); |
1108 | return 0; | 1193 | return 0; |
1109 | } | 1194 | } |
@@ -1169,7 +1254,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | |||
1169 | struct iwl_mvm_sta *mvm_sta; | 1254 | struct iwl_mvm_sta *mvm_sta; |
1170 | u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); | 1255 | u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); |
1171 | 1256 | ||
1172 | if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION)) | 1257 | if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) |
1173 | return; | 1258 | return; |
1174 | 1259 | ||
1175 | rcu_read_lock(); | 1260 | rcu_read_lock(); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 896f88ac8145..12abd2d71835 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -271,6 +271,7 @@ struct iwl_mvm_tid_data { | |||
271 | * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for | 271 | * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for |
272 | * tid. | 272 | * tid. |
273 | * @max_agg_bufsize: the maximal size of the AGG buffer for this station | 273 | * @max_agg_bufsize: the maximal size of the AGG buffer for this station |
274 | * @bt_reduced_txpower: is reduced tx power enabled for this station | ||
274 | * @lock: lock to protect the whole struct. Since %tid_data is access from Tx | 275 | * @lock: lock to protect the whole struct. Since %tid_data is access from Tx |
275 | * and from Tx response flow, it needs a spinlock. | 276 | * and from Tx response flow, it needs a spinlock. |
276 | * @pending_frames: number of frames for this STA on the shared Tx queues. | 277 | * @pending_frames: number of frames for this STA on the shared Tx queues. |
@@ -287,6 +288,7 @@ struct iwl_mvm_sta { | |||
287 | u32 mac_id_n_color; | 288 | u32 mac_id_n_color; |
288 | u16 tid_disable_agg; | 289 | u16 tid_disable_agg; |
289 | u8 max_agg_bufsize; | 290 | u8 max_agg_bufsize; |
291 | bool bt_reduced_txpower; | ||
290 | spinlock_t lock; | 292 | spinlock_t lock; |
291 | atomic_t pending_frames; | 293 | atomic_t pending_frames; |
292 | struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; | 294 | struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; |
@@ -348,6 +350,8 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
348 | struct ieee80211_sta *sta, u16 tid, u8 buf_size); | 350 | struct ieee80211_sta *sta, u16 tid, u8 buf_size); |
349 | int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 351 | int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
350 | struct ieee80211_sta *sta, u16 tid); | 352 | struct ieee80211_sta *sta, u16 tid); |
353 | int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
354 | struct ieee80211_sta *sta, u16 tid); | ||
351 | 355 | ||
352 | int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm); | 356 | int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm); |
353 | int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, | 357 | int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index e437e02c7149..ad9bbca99213 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -76,14 +76,12 @@ | |||
76 | #define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024)) | 76 | #define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024)) |
77 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) | 77 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) |
78 | 78 | ||
79 | /* For ROC use a TE type which has priority high enough to be scheduled when | 79 | /* |
80 | * there is a concurrent BSS or GO/AP. Currently, use a TE type that has | 80 | * For the high priority TE use a time event type that has similar priority to |
81 | * priority similar to the TE priority used for action scans by the FW. | 81 | * the FW's action scan priority. |
82 | * TODO: This needs to be changed, based on the reason for the ROC, i.e., use | ||
83 | * TE_P2P_DEVICE_DISCOVERABLE for remain on channel without mgmt skb, and use | ||
84 | * TE_P2P_DEVICE_ACTION_SCAN | ||
85 | */ | 82 | */ |
86 | #define IWL_MVM_ROC_TE_TYPE TE_P2P_DEVICE_ACTION_SCAN | 83 | #define IWL_MVM_ROC_TE_TYPE_NORMAL TE_P2P_DEVICE_DISCOVERABLE |
84 | #define IWL_MVM_ROC_TE_TYPE_MGMT_TX TE_P2P_CLIENT_ASSOC | ||
87 | 85 | ||
88 | void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, | 86 | void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, |
89 | struct iwl_mvm_time_event_data *te_data) | 87 | struct iwl_mvm_time_event_data *te_data) |
@@ -116,7 +114,7 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) | |||
116 | * issue as it will have to complete before the next command is | 114 | * issue as it will have to complete before the next command is |
117 | * executed, and a new time event means a new command. | 115 | * executed, and a new time event means a new command. |
118 | */ | 116 | */ |
119 | iwl_mvm_flush_tx_path(mvm, BIT(IWL_OFFCHANNEL_QUEUE), false); | 117 | iwl_mvm_flush_tx_path(mvm, BIT(IWL_MVM_OFFCHANNEL_QUEUE), false); |
120 | } | 118 | } |
121 | 119 | ||
122 | static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) | 120 | static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) |
@@ -168,7 +166,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
168 | WARN_ONCE(!le32_to_cpu(notif->status), | 166 | WARN_ONCE(!le32_to_cpu(notif->status), |
169 | "Failed to schedule time event\n"); | 167 | "Failed to schedule time event\n"); |
170 | 168 | ||
171 | if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_END) { | 169 | if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_END) { |
172 | IWL_DEBUG_TE(mvm, | 170 | IWL_DEBUG_TE(mvm, |
173 | "TE ended - current time %lu, estimated end %lu\n", | 171 | "TE ended - current time %lu, estimated end %lu\n", |
174 | jiffies, te_data->end_jiffies); | 172 | jiffies, te_data->end_jiffies); |
@@ -191,7 +189,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
191 | } | 189 | } |
192 | 190 | ||
193 | iwl_mvm_te_clear_data(mvm, te_data); | 191 | iwl_mvm_te_clear_data(mvm, te_data); |
194 | } else if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_START) { | 192 | } else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) { |
195 | te_data->running = true; | 193 | te_data->running = true; |
196 | te_data->end_jiffies = jiffies + | 194 | te_data->end_jiffies = jiffies + |
197 | TU_TO_JIFFIES(te_data->duration); | 195 | TU_TO_JIFFIES(te_data->duration); |
@@ -370,7 +368,8 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
370 | time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1)); | 368 | time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1)); |
371 | time_cmd.duration = cpu_to_le32(duration); | 369 | time_cmd.duration = cpu_to_le32(duration); |
372 | time_cmd.repeat = cpu_to_le32(1); | 370 | time_cmd.repeat = cpu_to_le32(1); |
373 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); | 371 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START | |
372 | TE_NOTIF_HOST_EVENT_END); | ||
374 | 373 | ||
375 | iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | 374 | iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
376 | } | 375 | } |
@@ -438,7 +437,7 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, | |||
438 | } | 437 | } |
439 | 438 | ||
440 | int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 439 | int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
441 | int duration) | 440 | int duration, enum ieee80211_roc_type type) |
442 | { | 441 | { |
443 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 442 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
444 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 443 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; |
@@ -459,27 +458,36 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
459 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); | 458 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); |
460 | time_cmd.id_and_color = | 459 | time_cmd.id_and_color = |
461 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | 460 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); |
462 | time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE); | 461 | |
462 | switch (type) { | ||
463 | case IEEE80211_ROC_TYPE_NORMAL: | ||
464 | time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE_NORMAL); | ||
465 | break; | ||
466 | case IEEE80211_ROC_TYPE_MGMT_TX: | ||
467 | time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE_MGMT_TX); | ||
468 | break; | ||
469 | default: | ||
470 | WARN_ONCE(1, "Got an invalid ROC type\n"); | ||
471 | return -EINVAL; | ||
472 | } | ||
463 | 473 | ||
464 | time_cmd.apply_time = cpu_to_le32(0); | 474 | time_cmd.apply_time = cpu_to_le32(0); |
465 | time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT); | 475 | time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT); |
466 | time_cmd.is_present = cpu_to_le32(1); | 476 | time_cmd.is_present = cpu_to_le32(1); |
467 | |||
468 | time_cmd.interval = cpu_to_le32(1); | 477 | time_cmd.interval = cpu_to_le32(1); |
469 | 478 | ||
470 | /* | 479 | /* |
471 | * IWL_MVM_ROC_TE_TYPE can have lower priority than other events | 480 | * The P2P Device TEs can have lower priority than other events |
472 | * that are being scheduled by the driver/fw, and thus it might not be | 481 | * that are being scheduled by the driver/fw, and thus it might not be |
473 | * scheduled. To improve the chances of it being scheduled, allow it to | 482 | * scheduled. To improve the chances of it being scheduled, allow them |
474 | * be fragmented. | 483 | * to be fragmented, and in addition allow them to be delayed. |
475 | * In addition, for the same reasons, allow to delay the scheduling of | ||
476 | * the time event. | ||
477 | */ | 484 | */ |
478 | time_cmd.max_frags = cpu_to_le32(MSEC_TO_TU(duration)/20); | 485 | time_cmd.max_frags = cpu_to_le32(MSEC_TO_TU(duration)/20); |
479 | time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2)); | 486 | time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2)); |
480 | time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); | 487 | time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); |
481 | time_cmd.repeat = cpu_to_le32(1); | 488 | time_cmd.repeat = cpu_to_le32(1); |
482 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); | 489 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START | |
490 | TE_NOTIF_HOST_EVENT_END); | ||
483 | 491 | ||
484 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | 492 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
485 | } | 493 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index 64fb57a5ab43..f86c51065ed3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -162,6 +162,7 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, | |||
162 | * that the vif type is NL80211_IFTYPE_P2P_DEVICE | 162 | * that the vif type is NL80211_IFTYPE_P2P_DEVICE |
163 | * @duration: the requested duration in millisecond for the fw to be on the | 163 | * @duration: the requested duration in millisecond for the fw to be on the |
164 | * channel that is bound to the vif. | 164 | * channel that is bound to the vif. |
165 | * @type: the remain on channel request type | ||
165 | * | 166 | * |
166 | * This function can be used to issue a remain on channel session, | 167 | * This function can be used to issue a remain on channel session, |
167 | * which means that the fw will stay in the channel for the request %duration | 168 | * which means that the fw will stay in the channel for the request %duration |
@@ -172,7 +173,7 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, | |||
172 | * another notification to the driver. | 173 | * another notification to the driver. |
173 | */ | 174 | */ |
174 | int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 175 | int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
175 | int duration); | 176 | int duration, enum ieee80211_roc_type type); |
176 | 177 | ||
177 | /** | 178 | /** |
178 | * iwl_mvm_stop_p2p_roc - stop remain on channel for p2p device functionlity | 179 | * iwl_mvm_stop_p2p_roc - stop remain on channel for p2p device functionlity |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 56df249b215e..479074303bd7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -205,7 +205,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, | |||
205 | rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx); | 205 | rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx); |
206 | 206 | ||
207 | mvm->mgmt_last_antenna_idx = | 207 | mvm->mgmt_last_antenna_idx = |
208 | iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant, | 208 | iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw), |
209 | mvm->mgmt_last_antenna_idx); | 209 | mvm->mgmt_last_antenna_idx); |
210 | rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; | 210 | rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; |
211 | 211 | ||
@@ -365,7 +365,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
365 | if (WARN_ON_ONCE(!mvmsta)) | 365 | if (WARN_ON_ONCE(!mvmsta)) |
366 | return -1; | 366 | return -1; |
367 | 367 | ||
368 | if (WARN_ON_ONCE(mvmsta->sta_id == IWL_INVALID_STATION)) | 368 | if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) |
369 | return -1; | 369 | return -1; |
370 | 370 | ||
371 | dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id); | 371 | dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id); |
@@ -417,7 +417,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
417 | spin_unlock(&mvmsta->lock); | 417 | spin_unlock(&mvmsta->lock); |
418 | 418 | ||
419 | if (mvmsta->vif->type == NL80211_IFTYPE_AP && | 419 | if (mvmsta->vif->type == NL80211_IFTYPE_AP && |
420 | txq_id < IWL_FIRST_AMPDU_QUEUE) | 420 | txq_id < IWL_MVM_FIRST_AGG_QUEUE) |
421 | atomic_inc(&mvmsta->pending_frames); | 421 | atomic_inc(&mvmsta->pending_frames); |
422 | 422 | ||
423 | return 0; | 423 | return 0; |
@@ -606,13 +606,9 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
606 | info); | 606 | info); |
607 | 607 | ||
608 | /* Single frame failure in an AMPDU queue => send BAR */ | 608 | /* Single frame failure in an AMPDU queue => send BAR */ |
609 | if (txq_id >= IWL_FIRST_AMPDU_QUEUE && | 609 | if (txq_id >= IWL_MVM_FIRST_AGG_QUEUE && |
610 | !(info->flags & IEEE80211_TX_STAT_ACK)) { | 610 | !(info->flags & IEEE80211_TX_STAT_ACK)) |
611 | /* there must be only one skb in the skb_list */ | ||
612 | WARN_ON_ONCE(skb_freed > 1 || | ||
613 | !skb_queue_empty(&skbs)); | ||
614 | info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; | 611 | info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; |
615 | } | ||
616 | 612 | ||
617 | /* W/A FW bug: seq_ctl is wrong when the queue is flushed */ | 613 | /* W/A FW bug: seq_ctl is wrong when the queue is flushed */ |
618 | if (status == TX_STATUS_FAIL_FIFO_FLUSHED) { | 614 | if (status == TX_STATUS_FAIL_FIFO_FLUSHED) { |
@@ -623,7 +619,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
623 | ieee80211_tx_status_ni(mvm->hw, skb); | 619 | ieee80211_tx_status_ni(mvm->hw, skb); |
624 | } | 620 | } |
625 | 621 | ||
626 | if (txq_id >= IWL_FIRST_AMPDU_QUEUE) { | 622 | if (txq_id >= IWL_MVM_FIRST_AGG_QUEUE) { |
627 | /* If this is an aggregation queue, we use the ssn since: | 623 | /* If this is an aggregation queue, we use the ssn since: |
628 | * ssn = wifi seq_num % 256. | 624 | * ssn = wifi seq_num % 256. |
629 | * The seq_ctl is the sequence control of the packet to which | 625 | * The seq_ctl is the sequence control of the packet to which |
@@ -645,10 +641,12 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
645 | } | 641 | } |
646 | 642 | ||
647 | IWL_DEBUG_TX_REPLY(mvm, | 643 | IWL_DEBUG_TX_REPLY(mvm, |
648 | "TXQ %d status %s (0x%08x)\n\t\t\t\tinitial_rate 0x%x " | 644 | "TXQ %d status %s (0x%08x)\n", |
649 | "retries %d, idx=%d ssn=%d next_reclaimed=0x%x seq_ctl=0x%x\n", | 645 | txq_id, iwl_mvm_get_tx_fail_reason(status), status); |
650 | txq_id, iwl_mvm_get_tx_fail_reason(status), | 646 | |
651 | status, le32_to_cpu(tx_resp->initial_rate), | 647 | IWL_DEBUG_TX_REPLY(mvm, |
648 | "\t\t\t\tinitial_rate 0x%x retries %d, idx=%d ssn=%d next_reclaimed=0x%x seq_ctl=0x%x\n", | ||
649 | le32_to_cpu(tx_resp->initial_rate), | ||
652 | tx_resp->failure_frame, SEQ_TO_INDEX(sequence), | 650 | tx_resp->failure_frame, SEQ_TO_INDEX(sequence), |
653 | ssn, next_reclaimed, seq_ctl); | 651 | ssn, next_reclaimed, seq_ctl); |
654 | 652 | ||
@@ -685,7 +683,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
685 | * If there are no pending frames for this STA, notify mac80211 that | 683 | * If there are no pending frames for this STA, notify mac80211 that |
686 | * this station can go to sleep in its STA table. | 684 | * this station can go to sleep in its STA table. |
687 | */ | 685 | */ |
688 | if (txq_id < IWL_FIRST_AMPDU_QUEUE && mvmsta && | 686 | if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && mvmsta && |
689 | !WARN_ON(skb_freed > 1) && | 687 | !WARN_ON(skb_freed > 1) && |
690 | mvmsta->vif->type == NL80211_IFTYPE_AP && | 688 | mvmsta->vif->type == NL80211_IFTYPE_AP && |
691 | atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) { | 689 | atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) { |
@@ -754,7 +752,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, | |||
754 | u16 sequence = le16_to_cpu(pkt->hdr.sequence); | 752 | u16 sequence = le16_to_cpu(pkt->hdr.sequence); |
755 | struct ieee80211_sta *sta; | 753 | struct ieee80211_sta *sta; |
756 | 754 | ||
757 | if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < IWL_FIRST_AMPDU_QUEUE)) | 755 | if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < IWL_MVM_FIRST_AGG_QUEUE)) |
758 | return; | 756 | return; |
759 | 757 | ||
760 | if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS)) | 758 | if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS)) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 000e842c2edd..0cc8d8c0d393 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | * The full GNU General Public License is included in this distribution | 24 | * The full GNU General Public License is included in this distribution |
25 | * in the file called LICENSE.GPL. | 25 | * in the file called COPYING. |
26 | * | 26 | * |
27 | * Contact Information: | 27 | * Contact Information: |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | 28 | * Intel Linux Wireless <ilw@linux.intel.com> |
@@ -462,7 +462,7 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | |||
462 | .data = { lq, }, | 462 | .data = { lq, }, |
463 | }; | 463 | }; |
464 | 464 | ||
465 | if (WARN_ON(lq->sta_id == IWL_INVALID_STATION)) | 465 | if (WARN_ON(lq->sta_id == IWL_MVM_STATION_COUNT)) |
466 | return -EINVAL; | 466 | return -EINVAL; |
467 | 467 | ||
468 | if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) | 468 | if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) |