diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-05 17:54:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-05 17:54:29 -0400 |
commit | cc998ff8811530be521f6b316f37ab7676a07938 (patch) | |
tree | a054b3bf4b2ef406bf756a6cfc9be2f9115f17ae /drivers/net/wireless/iwlwifi/mvm | |
parent | 57d730924d5cc2c3e280af16a9306587c3a511db (diff) | |
parent | 0d40f75bdab241868c0eb6f97aef9f8b3a66f7b3 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking changes from David Miller:
"Noteworthy changes this time around:
1) Multicast rejoin support for team driver, from Jiri Pirko.
2) Centralize and simplify TCP RTT measurement handling in order to
reduce the impact of bad RTO seeding from SYN/ACKs. Also, when
both timestamps and local RTT measurements are available prefer
the later because there are broken middleware devices which
scramble the timestamp.
From Yuchung Cheng.
3) Add TCP_NOTSENT_LOWAT socket option to limit the amount of kernel
memory consumed to queue up unsend user data. From Eric Dumazet.
4) Add a "physical port ID" abstraction for network devices, from
Jiri Pirko.
5) Add a "suppress" operation to influence fib_rules lookups, from
Stefan Tomanek.
6) Add a networking development FAQ, from Paul Gortmaker.
7) Extend the information provided by tcp_probe and add ipv6 support,
from Daniel Borkmann.
8) Use RCU locking more extensively in openvswitch data paths, from
Pravin B Shelar.
9) Add SCTP support to openvswitch, from Joe Stringer.
10) Add EF10 chip support to SFC driver, from Ben Hutchings.
11) Add new SYNPROXY netfilter target, from Patrick McHardy.
12) Compute a rate approximation for sending in TCP sockets, and use
this to more intelligently coalesce TSO frames. Furthermore, add
a new packet scheduler which takes advantage of this estimate when
available. From Eric Dumazet.
13) Allow AF_PACKET fanouts with random selection, from Daniel
Borkmann.
14) Add ipv6 support to vxlan driver, from Cong Wang"
Resolved conflicts as per discussion.
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1218 commits)
openvswitch: Fix alignment of struct sw_flow_key.
netfilter: Fix build errors with xt_socket.c
tcp: Add missing braces to do_tcp_setsockopt
caif: Add missing braces to multiline if in cfctrl_linkup_request
bnx2x: Add missing braces in bnx2x:bnx2x_link_initialize
vxlan: Fix kernel panic on device delete.
net: mvneta: implement ->ndo_do_ioctl() to support PHY ioctls
net: mvneta: properly disable HW PHY polling and ensure adjust_link() works
icplus: Use netif_running to determine device state
ethernet/arc/arc_emac: Fix huge delays in large file copies
tuntap: orphan frags before trying to set tx timestamp
tuntap: purge socket error queue on detach
qlcnic: use standard NAPI weights
ipv6:introduce function to find route for redirect
bnx2x: VF RSS support - VF side
bnx2x: VF RSS support - PF side
vxlan: Notify drivers for listening UDP port changes
net: usbnet: update addr_assign_type if appropriate
driver/net: enic: update enic maintainers and driver
driver/net: enic: Exposing symbols for Cisco's low latency driver
...
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm')
27 files changed, 2117 insertions, 1179 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index ff856e543ae8..6d73817850ce 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 bt-coex.o | 5 | iwlmvm-y += power.o power_legacy.o bt-coex.o |
6 | iwlmvm-y += led.o tt.o | 6 | iwlmvm-y += led.o tt.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/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index dbd622a3929c..0fad98b85f60 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c | |||
@@ -220,66 +220,87 @@ static const __le32 iwl_single_shared_ant_lookup[BT_COEX_LUT_SIZE] = { | |||
220 | 220 | ||
221 | int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | 221 | int iwl_send_bt_init_conf(struct iwl_mvm *mvm) |
222 | { | 222 | { |
223 | struct iwl_bt_coex_cmd cmd = { | 223 | struct iwl_bt_coex_cmd *bt_cmd; |
224 | .max_kill = 5, | 224 | struct iwl_host_cmd cmd = { |
225 | .bt3_time_t7_value = 1, | 225 | .id = BT_CONFIG, |
226 | .bt3_prio_sample_time = 2, | 226 | .len = { sizeof(*bt_cmd), }, |
227 | .bt3_timer_t2_value = 0xc, | 227 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, |
228 | .flags = CMD_SYNC, | ||
228 | }; | 229 | }; |
229 | int ret; | 230 | int ret; |
230 | 231 | ||
231 | cmd.flags = iwlwifi_mod_params.bt_coex_active ? | 232 | /* go to CALIB state in internal BT-Coex state machine */ |
233 | ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN, | ||
234 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); | ||
235 | if (ret) | ||
236 | return ret; | ||
237 | |||
238 | ret = iwl_send_bt_env(mvm, BT_COEX_ENV_CLOSE, | ||
239 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); | ||
240 | if (ret) | ||
241 | return ret; | ||
242 | |||
243 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); | ||
244 | if (!bt_cmd) | ||
245 | return -ENOMEM; | ||
246 | cmd.data[0] = bt_cmd; | ||
247 | |||
248 | bt_cmd->max_kill = 5; | ||
249 | bt_cmd->bt3_time_t7_value = 1; | ||
250 | bt_cmd->bt3_prio_sample_time = 2; | ||
251 | bt_cmd->bt3_timer_t2_value = 0xc; | ||
252 | |||
253 | bt_cmd->flags = iwlwifi_mod_params.bt_coex_active ? | ||
232 | BT_COEX_NW : BT_COEX_DISABLE; | 254 | BT_COEX_NW : BT_COEX_DISABLE; |
233 | cmd.flags |= BT_CH_PRIMARY_EN | BT_SYNC_2_BT_DISABLE; | 255 | bt_cmd->flags |= BT_CH_PRIMARY_EN | BT_SYNC_2_BT_DISABLE; |
234 | 256 | ||
235 | cmd.valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE | | 257 | bt_cmd->valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE | |
236 | BT_VALID_BT_PRIO_BOOST | | 258 | BT_VALID_BT_PRIO_BOOST | |
237 | BT_VALID_MAX_KILL | | 259 | BT_VALID_MAX_KILL | |
238 | BT_VALID_3W_TMRS | | 260 | BT_VALID_3W_TMRS | |
239 | BT_VALID_KILL_ACK | | 261 | BT_VALID_KILL_ACK | |
240 | BT_VALID_KILL_CTS | | 262 | BT_VALID_KILL_CTS | |
241 | BT_VALID_REDUCED_TX_POWER | | 263 | BT_VALID_REDUCED_TX_POWER | |
242 | BT_VALID_LUT); | 264 | BT_VALID_LUT); |
243 | 265 | ||
244 | if (mvm->cfg->bt_shared_single_ant) | 266 | if (mvm->cfg->bt_shared_single_ant) |
245 | memcpy(&cmd.decision_lut, iwl_single_shared_ant_lookup, | 267 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant_lookup, |
246 | sizeof(iwl_single_shared_ant_lookup)); | 268 | sizeof(iwl_single_shared_ant_lookup)); |
247 | else if (is_loose_coex()) | 269 | else if (is_loose_coex()) |
248 | memcpy(&cmd.decision_lut, iwl_loose_lookup, | 270 | memcpy(&bt_cmd->decision_lut, iwl_loose_lookup, |
249 | sizeof(iwl_tight_lookup)); | 271 | sizeof(iwl_tight_lookup)); |
250 | else | 272 | else |
251 | memcpy(&cmd.decision_lut, iwl_tight_lookup, | 273 | memcpy(&bt_cmd->decision_lut, iwl_tight_lookup, |
252 | sizeof(iwl_tight_lookup)); | 274 | sizeof(iwl_tight_lookup)); |
253 | 275 | ||
254 | cmd.bt_prio_boost = cpu_to_le32(IWL_BT_DEFAULT_BOOST); | 276 | bt_cmd->bt_prio_boost = cpu_to_le32(IWL_BT_DEFAULT_BOOST); |
255 | cmd.kill_ack_msk = | 277 | bt_cmd->kill_ack_msk = |
256 | cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); | 278 | cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); |
257 | cmd.kill_cts_msk = | 279 | bt_cmd->kill_cts_msk = |
258 | cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); | 280 | cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); |
259 | 281 | ||
260 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | 282 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); |
261 | 283 | ||
262 | /* go to CALIB state in internal BT-Coex state machine */ | 284 | ret = iwl_mvm_send_cmd(mvm, &cmd); |
263 | ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN, | ||
264 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); | ||
265 | if (ret) | ||
266 | return ret; | ||
267 | |||
268 | ret = iwl_send_bt_env(mvm, BT_COEX_ENV_CLOSE, | ||
269 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); | ||
270 | if (ret) | ||
271 | return ret; | ||
272 | 285 | ||
273 | return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC, | 286 | kfree(bt_cmd); |
274 | sizeof(cmd), &cmd); | 287 | return ret; |
275 | } | 288 | } |
276 | 289 | ||
277 | static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, | 290 | static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, |
278 | bool reduced_tx_power) | 291 | bool reduced_tx_power) |
279 | { | 292 | { |
280 | enum iwl_bt_kill_msk bt_kill_msk; | 293 | enum iwl_bt_kill_msk bt_kill_msk; |
281 | struct iwl_bt_coex_cmd cmd = {}; | 294 | struct iwl_bt_coex_cmd *bt_cmd; |
282 | struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; | 295 | struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; |
296 | struct iwl_host_cmd cmd = { | ||
297 | .id = BT_CONFIG, | ||
298 | .data[0] = &bt_cmd, | ||
299 | .len = { sizeof(*bt_cmd), }, | ||
300 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
301 | .flags = CMD_SYNC, | ||
302 | }; | ||
303 | int ret = 0; | ||
283 | 304 | ||
284 | lockdep_assert_held(&mvm->mutex); | 305 | lockdep_assert_held(&mvm->mutex); |
285 | 306 | ||
@@ -308,24 +329,40 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, | |||
308 | return 0; | 329 | return 0; |
309 | 330 | ||
310 | mvm->bt_kill_msk = bt_kill_msk; | 331 | mvm->bt_kill_msk = bt_kill_msk; |
311 | cmd.kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); | 332 | |
312 | cmd.kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); | 333 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); |
313 | cmd.valid_bit_msk = cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS); | 334 | if (!bt_cmd) |
335 | return -ENOMEM; | ||
336 | cmd.data[0] = bt_cmd; | ||
337 | |||
338 | bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); | ||
339 | bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); | ||
340 | bt_cmd->valid_bit_msk = | ||
341 | cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS); | ||
314 | 342 | ||
315 | IWL_DEBUG_COEX(mvm, "bt_kill_msk = %d\n", bt_kill_msk); | 343 | IWL_DEBUG_COEX(mvm, "bt_kill_msk = %d\n", bt_kill_msk); |
316 | return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC, | 344 | |
317 | sizeof(cmd), &cmd); | 345 | ret = iwl_mvm_send_cmd(mvm, &cmd); |
346 | |||
347 | kfree(bt_cmd); | ||
348 | return ret; | ||
318 | } | 349 | } |
319 | 350 | ||
320 | static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, | 351 | static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, |
321 | bool enable) | 352 | bool enable) |
322 | { | 353 | { |
323 | struct iwl_bt_coex_cmd cmd = { | 354 | struct iwl_bt_coex_cmd *bt_cmd; |
324 | .valid_bit_msk = cpu_to_le16(BT_VALID_REDUCED_TX_POWER), | 355 | /* Send ASYNC since this can be sent from an atomic context */ |
325 | .bt_reduced_tx_power = sta_id, | 356 | struct iwl_host_cmd cmd = { |
357 | .id = BT_CONFIG, | ||
358 | .len = { sizeof(*bt_cmd), }, | ||
359 | .dataflags = { IWL_HCMD_DFL_DUP, }, | ||
360 | .flags = CMD_ASYNC, | ||
326 | }; | 361 | }; |
362 | |||
327 | struct ieee80211_sta *sta; | 363 | struct ieee80211_sta *sta; |
328 | struct iwl_mvm_sta *mvmsta; | 364 | struct iwl_mvm_sta *mvmsta; |
365 | int ret; | ||
329 | 366 | ||
330 | /* This can happen if the station has been removed right now */ | 367 | /* This can happen if the station has been removed right now */ |
331 | if (sta_id == IWL_MVM_STATION_COUNT) | 368 | if (sta_id == IWL_MVM_STATION_COUNT) |
@@ -339,17 +376,26 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, | |||
339 | if (mvmsta->bt_reduced_txpower == enable) | 376 | if (mvmsta->bt_reduced_txpower == enable) |
340 | return 0; | 377 | return 0; |
341 | 378 | ||
379 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_ATOMIC); | ||
380 | if (!bt_cmd) | ||
381 | return -ENOMEM; | ||
382 | cmd.data[0] = bt_cmd; | ||
383 | |||
384 | bt_cmd->valid_bit_msk = cpu_to_le16(BT_VALID_REDUCED_TX_POWER), | ||
385 | bt_cmd->bt_reduced_tx_power = sta_id; | ||
386 | |||
342 | if (enable) | 387 | if (enable) |
343 | cmd.bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT; | 388 | bt_cmd->bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT; |
344 | 389 | ||
345 | IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n", | 390 | IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n", |
346 | enable ? "en" : "dis", sta_id); | 391 | enable ? "en" : "dis", sta_id); |
347 | 392 | ||
348 | mvmsta->bt_reduced_txpower = enable; | 393 | mvmsta->bt_reduced_txpower = enable; |
349 | 394 | ||
350 | /* Send ASYNC since this can be sent from an atomic context */ | 395 | ret = iwl_mvm_send_cmd(mvm, &cmd); |
351 | return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_ASYNC, | 396 | |
352 | sizeof(cmd), &cmd); | 397 | kfree(bt_cmd); |
398 | return ret; | ||
353 | } | 399 | } |
354 | 400 | ||
355 | struct iwl_bt_iterator_data { | 401 | struct iwl_bt_iterator_data { |
@@ -384,6 +430,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
384 | 430 | ||
385 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 431 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
386 | 432 | ||
433 | /* non associated BSSes aren't to be considered */ | ||
434 | if (!vif->bss_conf.assoc) | ||
435 | return; | ||
436 | |||
387 | if (band != IEEE80211_BAND_2GHZ) { | 437 | if (band != IEEE80211_BAND_2GHZ) { |
388 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | 438 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, |
389 | smps_mode); | 439 | smps_mode); |
@@ -523,6 +573,8 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, | |||
523 | lockdep_is_held(&mvm->mutex)); | 573 | lockdep_is_held(&mvm->mutex)); |
524 | mvmsta = (void *)sta->drv_priv; | 574 | mvmsta = (void *)sta->drv_priv; |
525 | 575 | ||
576 | data->num_bss_ifaces++; | ||
577 | |||
526 | /* | 578 | /* |
527 | * This interface doesn't support reduced Tx power (because of low | 579 | * This interface doesn't support reduced Tx power (because of low |
528 | * RSSI probably), then set bt_kill_msk to default values. | 580 | * RSSI probably), then set bt_kill_msk to default values. |
@@ -588,23 +640,5 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
588 | 640 | ||
589 | void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 641 | void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
590 | { | 642 | { |
591 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
592 | enum ieee80211_band band; | ||
593 | |||
594 | rcu_read_lock(); | ||
595 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
596 | if (chanctx_conf && chanctx_conf->def.chan) | ||
597 | band = chanctx_conf->def.chan->band; | ||
598 | else | ||
599 | band = -1; | ||
600 | rcu_read_unlock(); | ||
601 | |||
602 | /* if we are in 2GHz we will get a notification from the fw */ | ||
603 | if (band == IEEE80211_BAND_2GHZ) | ||
604 | return; | ||
605 | |||
606 | /* else, we can remove all the constraints */ | ||
607 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | ||
608 | |||
609 | iwl_mvm_bt_coex_notif_handle(mvm); | 643 | iwl_mvm_bt_coex_notif_handle(mvm); |
610 | } | 644 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h new file mode 100644 index 000000000000..2bf29f7992ee --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h | |||
@@ -0,0 +1,80 @@ | |||
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 __MVM_CONSTANTS_H | ||
64 | #define __MVM_CONSTANTS_H | ||
65 | |||
66 | #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) | ||
67 | #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) | ||
68 | #define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC) | ||
69 | #define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC) | ||
70 | #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC) | ||
71 | #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC) | ||
72 | #define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20 | ||
73 | #define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 20 | ||
74 | #define IWL_MVM_PS_HEAVY_TX_THLD_PERCENT 50 | ||
75 | #define IWL_MVM_PS_HEAVY_RX_THLD_PERCENT 50 | ||
76 | #define IWL_MVM_PS_SNOOZE_INTERVAL 25 | ||
77 | #define IWL_MVM_PS_SNOOZE_WINDOW 50 | ||
78 | #define IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW 25 | ||
79 | |||
80 | #endif /* __MVM_CONSTANTS_H */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 83da884cf303..417639f77b01 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -105,7 +105,7 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, | |||
105 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | 105 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
106 | mvmvif->target_ipv6_addrs[idx] = ifa->addr; | 106 | mvmvif->target_ipv6_addrs[idx] = ifa->addr; |
107 | idx++; | 107 | idx++; |
108 | if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS) | 108 | if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX) |
109 | break; | 109 | break; |
110 | } | 110 | } |
111 | read_unlock_bh(&idev->lock); | 111 | read_unlock_bh(&idev->lock); |
@@ -378,36 +378,68 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, | |||
378 | static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | 378 | static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, |
379 | struct ieee80211_vif *vif) | 379 | struct ieee80211_vif *vif) |
380 | { | 380 | { |
381 | struct iwl_proto_offload_cmd cmd = {}; | 381 | union { |
382 | struct iwl_proto_offload_cmd_v1 v1; | ||
383 | struct iwl_proto_offload_cmd_v2 v2; | ||
384 | } cmd = {}; | ||
385 | struct iwl_proto_offload_cmd_common *common; | ||
386 | u32 enabled = 0, size; | ||
382 | #if IS_ENABLED(CONFIG_IPV6) | 387 | #if IS_ENABLED(CONFIG_IPV6) |
383 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 388 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
384 | int i; | 389 | int i; |
385 | 390 | ||
386 | if (mvmvif->num_target_ipv6_addrs) { | 391 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { |
387 | cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_NS); | 392 | if (mvmvif->num_target_ipv6_addrs) { |
388 | memcpy(cmd.ndp_mac_addr, vif->addr, ETH_ALEN); | 393 | enabled |= IWL_D3_PROTO_OFFLOAD_NS; |
389 | } | 394 | memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); |
395 | } | ||
396 | |||
397 | BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) != | ||
398 | sizeof(mvmvif->target_ipv6_addrs[0])); | ||
390 | 399 | ||
391 | BUILD_BUG_ON(sizeof(cmd.target_ipv6_addr[i]) != | 400 | for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, |
392 | sizeof(mvmvif->target_ipv6_addrs[i])); | 401 | IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++) |
402 | memcpy(cmd.v2.target_ipv6_addr[i], | ||
403 | &mvmvif->target_ipv6_addrs[i], | ||
404 | sizeof(cmd.v2.target_ipv6_addr[i])); | ||
405 | } else { | ||
406 | if (mvmvif->num_target_ipv6_addrs) { | ||
407 | enabled |= IWL_D3_PROTO_OFFLOAD_NS; | ||
408 | memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN); | ||
409 | } | ||
393 | 410 | ||
394 | for (i = 0; i < mvmvif->num_target_ipv6_addrs; i++) | 411 | BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) != |
395 | memcpy(cmd.target_ipv6_addr[i], | 412 | sizeof(mvmvif->target_ipv6_addrs[0])); |
396 | &mvmvif->target_ipv6_addrs[i], | 413 | |
397 | sizeof(cmd.target_ipv6_addr[i])); | 414 | for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, |
415 | IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++) | ||
416 | memcpy(cmd.v1.target_ipv6_addr[i], | ||
417 | &mvmvif->target_ipv6_addrs[i], | ||
418 | sizeof(cmd.v1.target_ipv6_addr[i])); | ||
419 | } | ||
398 | #endif | 420 | #endif |
399 | 421 | ||
422 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { | ||
423 | common = &cmd.v2.common; | ||
424 | size = sizeof(cmd.v2); | ||
425 | } else { | ||
426 | common = &cmd.v1.common; | ||
427 | size = sizeof(cmd.v1); | ||
428 | } | ||
429 | |||
400 | if (vif->bss_conf.arp_addr_cnt) { | 430 | if (vif->bss_conf.arp_addr_cnt) { |
401 | cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_ARP); | 431 | enabled |= IWL_D3_PROTO_OFFLOAD_ARP; |
402 | cmd.host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; | 432 | common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; |
403 | memcpy(cmd.arp_mac_addr, vif->addr, ETH_ALEN); | 433 | memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); |
404 | } | 434 | } |
405 | 435 | ||
406 | if (!cmd.enabled) | 436 | if (!enabled) |
407 | return 0; | 437 | return 0; |
408 | 438 | ||
439 | common->enabled = cpu_to_le32(enabled); | ||
440 | |||
409 | return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC, | 441 | return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC, |
410 | sizeof(cmd), &cmd); | 442 | size, &cmd); |
411 | } | 443 | } |
412 | 444 | ||
413 | enum iwl_mvm_tcp_packet_type { | 445 | enum iwl_mvm_tcp_packet_type { |
@@ -1077,73 +1109,16 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
1077 | return __iwl_mvm_suspend(hw, wowlan, false); | 1109 | return __iwl_mvm_suspend(hw, wowlan, false); |
1078 | } | 1110 | } |
1079 | 1111 | ||
1080 | static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | 1112 | static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, |
1081 | struct ieee80211_vif *vif) | 1113 | struct ieee80211_vif *vif, |
1114 | struct iwl_wowlan_status *status) | ||
1082 | { | 1115 | { |
1083 | u32 base = mvm->error_event_table; | 1116 | struct sk_buff *pkt = NULL; |
1084 | struct error_table_start { | ||
1085 | /* cf. struct iwl_error_event_table */ | ||
1086 | u32 valid; | ||
1087 | u32 error_id; | ||
1088 | } err_info; | ||
1089 | struct cfg80211_wowlan_wakeup wakeup = { | 1117 | struct cfg80211_wowlan_wakeup wakeup = { |
1090 | .pattern_idx = -1, | 1118 | .pattern_idx = -1, |
1091 | }; | 1119 | }; |
1092 | struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup; | 1120 | struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup; |
1093 | struct iwl_host_cmd cmd = { | 1121 | u32 reasons = le32_to_cpu(status->wakeup_reasons); |
1094 | .id = WOWLAN_GET_STATUSES, | ||
1095 | .flags = CMD_SYNC | CMD_WANT_SKB, | ||
1096 | }; | ||
1097 | struct iwl_wowlan_status *status; | ||
1098 | u32 reasons; | ||
1099 | int ret, len; | ||
1100 | struct sk_buff *pkt = NULL; | ||
1101 | |||
1102 | iwl_trans_read_mem_bytes(mvm->trans, base, | ||
1103 | &err_info, sizeof(err_info)); | ||
1104 | |||
1105 | if (err_info.valid) { | ||
1106 | IWL_INFO(mvm, "error table is valid (%d)\n", | ||
1107 | err_info.valid); | ||
1108 | if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { | ||
1109 | wakeup.rfkill_release = true; | ||
1110 | ieee80211_report_wowlan_wakeup(vif, &wakeup, | ||
1111 | GFP_KERNEL); | ||
1112 | } | ||
1113 | return; | ||
1114 | } | ||
1115 | |||
1116 | /* only for tracing for now */ | ||
1117 | ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL); | ||
1118 | if (ret) | ||
1119 | IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); | ||
1120 | |||
1121 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
1122 | if (ret) { | ||
1123 | IWL_ERR(mvm, "failed to query status (%d)\n", ret); | ||
1124 | return; | ||
1125 | } | ||
1126 | |||
1127 | /* RF-kill already asserted again... */ | ||
1128 | if (!cmd.resp_pkt) | ||
1129 | return; | ||
1130 | |||
1131 | len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||
1132 | if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) { | ||
1133 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||
1134 | goto out; | ||
1135 | } | ||
1136 | |||
1137 | status = (void *)cmd.resp_pkt->data; | ||
1138 | |||
1139 | if (len - sizeof(struct iwl_cmd_header) != | ||
1140 | sizeof(*status) + | ||
1141 | ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) { | ||
1142 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||
1143 | goto out; | ||
1144 | } | ||
1145 | |||
1146 | reasons = le32_to_cpu(status->wakeup_reasons); | ||
1147 | 1122 | ||
1148 | if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) { | 1123 | if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) { |
1149 | wakeup_report = NULL; | 1124 | wakeup_report = NULL; |
@@ -1206,6 +1181,12 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
1206 | pktsize -= hdrlen; | 1181 | pktsize -= hdrlen; |
1207 | 1182 | ||
1208 | if (ieee80211_has_protected(hdr->frame_control)) { | 1183 | if (ieee80211_has_protected(hdr->frame_control)) { |
1184 | /* | ||
1185 | * This is unlocked and using gtk_i(c)vlen, | ||
1186 | * but since everything is under RTNL still | ||
1187 | * that's not really a problem - changing | ||
1188 | * it would be difficult. | ||
1189 | */ | ||
1209 | if (is_multicast_ether_addr(hdr->addr1)) { | 1190 | if (is_multicast_ether_addr(hdr->addr1)) { |
1210 | ivlen = mvm->gtk_ivlen; | 1191 | ivlen = mvm->gtk_ivlen; |
1211 | icvlen += mvm->gtk_icvlen; | 1192 | icvlen += mvm->gtk_icvlen; |
@@ -1256,9 +1237,82 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
1256 | report: | 1237 | report: |
1257 | ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL); | 1238 | ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL); |
1258 | kfree_skb(pkt); | 1239 | kfree_skb(pkt); |
1240 | } | ||
1259 | 1241 | ||
1260 | out: | 1242 | /* releases the MVM mutex */ |
1243 | static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | ||
1244 | struct ieee80211_vif *vif) | ||
1245 | { | ||
1246 | u32 base = mvm->error_event_table; | ||
1247 | struct error_table_start { | ||
1248 | /* cf. struct iwl_error_event_table */ | ||
1249 | u32 valid; | ||
1250 | u32 error_id; | ||
1251 | } err_info; | ||
1252 | struct iwl_host_cmd cmd = { | ||
1253 | .id = WOWLAN_GET_STATUSES, | ||
1254 | .flags = CMD_SYNC | CMD_WANT_SKB, | ||
1255 | }; | ||
1256 | struct iwl_wowlan_status *status; | ||
1257 | int ret, len; | ||
1258 | |||
1259 | iwl_trans_read_mem_bytes(mvm->trans, base, | ||
1260 | &err_info, sizeof(err_info)); | ||
1261 | |||
1262 | if (err_info.valid) { | ||
1263 | IWL_INFO(mvm, "error table is valid (%d)\n", | ||
1264 | err_info.valid); | ||
1265 | if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { | ||
1266 | struct cfg80211_wowlan_wakeup wakeup = { | ||
1267 | .rfkill_release = true, | ||
1268 | }; | ||
1269 | ieee80211_report_wowlan_wakeup(vif, &wakeup, | ||
1270 | GFP_KERNEL); | ||
1271 | } | ||
1272 | goto out_unlock; | ||
1273 | } | ||
1274 | |||
1275 | /* only for tracing for now */ | ||
1276 | ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL); | ||
1277 | if (ret) | ||
1278 | IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); | ||
1279 | |||
1280 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
1281 | if (ret) { | ||
1282 | IWL_ERR(mvm, "failed to query status (%d)\n", ret); | ||
1283 | goto out_unlock; | ||
1284 | } | ||
1285 | |||
1286 | /* RF-kill already asserted again... */ | ||
1287 | if (!cmd.resp_pkt) | ||
1288 | goto out_unlock; | ||
1289 | |||
1290 | len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||
1291 | if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) { | ||
1292 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||
1293 | goto out_free_resp; | ||
1294 | } | ||
1295 | |||
1296 | status = (void *)cmd.resp_pkt->data; | ||
1297 | |||
1298 | if (len - sizeof(struct iwl_cmd_header) != | ||
1299 | sizeof(*status) + | ||
1300 | ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) { | ||
1301 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||
1302 | goto out_free_resp; | ||
1303 | } | ||
1304 | |||
1305 | /* now we have all the data we need, unlock to avoid mac80211 issues */ | ||
1306 | mutex_unlock(&mvm->mutex); | ||
1307 | |||
1308 | iwl_mvm_report_wakeup_reasons(mvm, vif, status); | ||
1309 | iwl_free_resp(&cmd); | ||
1310 | return; | ||
1311 | |||
1312 | out_free_resp: | ||
1261 | iwl_free_resp(&cmd); | 1313 | iwl_free_resp(&cmd); |
1314 | out_unlock: | ||
1315 | mutex_unlock(&mvm->mutex); | ||
1262 | } | 1316 | } |
1263 | 1317 | ||
1264 | static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) | 1318 | static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) |
@@ -1315,10 +1369,13 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | |||
1315 | iwl_mvm_read_d3_sram(mvm); | 1369 | iwl_mvm_read_d3_sram(mvm); |
1316 | 1370 | ||
1317 | iwl_mvm_query_wakeup_reasons(mvm, vif); | 1371 | iwl_mvm_query_wakeup_reasons(mvm, vif); |
1372 | /* has unlocked the mutex, so skip that */ | ||
1373 | goto out; | ||
1318 | 1374 | ||
1319 | out_unlock: | 1375 | out_unlock: |
1320 | mutex_unlock(&mvm->mutex); | 1376 | mutex_unlock(&mvm->mutex); |
1321 | 1377 | ||
1378 | out: | ||
1322 | if (!test && vif) | 1379 | if (!test && vif) |
1323 | ieee80211_resume_disconnect(vif); | 1380 | ieee80211_resume_disconnect(vif); |
1324 | 1381 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index c24a744910ac..aac81b8984b0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
@@ -352,6 +352,10 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, | |||
352 | IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val); | 352 | IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val); |
353 | dbgfs_pm->lprx_rssi_threshold = val; | 353 | dbgfs_pm->lprx_rssi_threshold = val; |
354 | break; | 354 | break; |
355 | case MVM_DEBUGFS_PM_SNOOZE_ENABLE: | ||
356 | IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val); | ||
357 | dbgfs_pm->snooze_ena = val; | ||
358 | break; | ||
355 | } | 359 | } |
356 | } | 360 | } |
357 | 361 | ||
@@ -405,6 +409,10 @@ static ssize_t iwl_dbgfs_pm_params_write(struct file *file, | |||
405 | POWER_LPRX_RSSI_THRESHOLD_MIN) | 409 | POWER_LPRX_RSSI_THRESHOLD_MIN) |
406 | return -EINVAL; | 410 | return -EINVAL; |
407 | param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD; | 411 | param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD; |
412 | } else if (!strncmp("snooze_enable=", buf, 14)) { | ||
413 | if (sscanf(buf + 14, "%d", &val) != 1) | ||
414 | return -EINVAL; | ||
415 | param = MVM_DEBUGFS_PM_SNOOZE_ENABLE; | ||
408 | } else { | 416 | } else { |
409 | return -EINVAL; | 417 | return -EINVAL; |
410 | } | 418 | } |
@@ -424,40 +432,11 @@ static ssize_t iwl_dbgfs_pm_params_read(struct file *file, | |||
424 | struct ieee80211_vif *vif = file->private_data; | 432 | struct ieee80211_vif *vif = file->private_data; |
425 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 433 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
426 | struct iwl_mvm *mvm = mvmvif->dbgfs_data; | 434 | struct iwl_mvm *mvm = mvmvif->dbgfs_data; |
427 | struct iwl_powertable_cmd cmd = {}; | 435 | char buf[512]; |
428 | char buf[256]; | ||
429 | int bufsz = sizeof(buf); | 436 | int bufsz = sizeof(buf); |
430 | int pos = 0; | 437 | int pos; |
431 | 438 | ||
432 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | 439 | pos = iwl_mvm_power_dbgfs_read(mvm, vif, buf, bufsz); |
433 | |||
434 | pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", | ||
435 | (cmd.flags & | ||
436 | cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? | ||
437 | 0 : 1); | ||
438 | pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", | ||
439 | le32_to_cpu(cmd.skip_dtim_periods)); | ||
440 | pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", | ||
441 | iwlmvm_mod_params.power_scheme); | ||
442 | pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", | ||
443 | le16_to_cpu(cmd.flags)); | ||
444 | pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n", | ||
445 | cmd.keep_alive_seconds); | ||
446 | |||
447 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | ||
448 | pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n", | ||
449 | (cmd.flags & | ||
450 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? | ||
451 | 1 : 0); | ||
452 | pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n", | ||
453 | le32_to_cpu(cmd.rx_data_timeout)); | ||
454 | pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n", | ||
455 | le32_to_cpu(cmd.tx_data_timeout)); | ||
456 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) | ||
457 | pos += scnprintf(buf+pos, bufsz-pos, | ||
458 | "lprx_rssi_threshold = %d\n", | ||
459 | le32_to_cpu(cmd.lprx_rssi_threshold)); | ||
460 | } | ||
461 | 440 | ||
462 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 441 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
463 | } | 442 | } |
@@ -621,25 +600,160 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, | |||
621 | } | 600 | } |
622 | #undef BT_MBOX_PRINT | 601 | #undef BT_MBOX_PRINT |
623 | 602 | ||
603 | #define PRINT_STATS_LE32(_str, _val) \ | ||
604 | pos += scnprintf(buf + pos, bufsz - pos, \ | ||
605 | fmt_table, _str, \ | ||
606 | le32_to_cpu(_val)) | ||
607 | |||
608 | static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, | ||
609 | char __user *user_buf, size_t count, | ||
610 | loff_t *ppos) | ||
611 | { | ||
612 | struct iwl_mvm *mvm = file->private_data; | ||
613 | static const char *fmt_table = "\t%-30s %10u\n"; | ||
614 | static const char *fmt_header = "%-32s\n"; | ||
615 | int pos = 0; | ||
616 | char *buf; | ||
617 | int ret; | ||
618 | int bufsz = sizeof(struct mvm_statistics_rx_phy) * 20 + | ||
619 | sizeof(struct mvm_statistics_rx_non_phy) * 10 + | ||
620 | sizeof(struct mvm_statistics_rx_ht_phy) * 10 + 200; | ||
621 | struct mvm_statistics_rx_phy *ofdm; | ||
622 | struct mvm_statistics_rx_phy *cck; | ||
623 | struct mvm_statistics_rx_non_phy *general; | ||
624 | struct mvm_statistics_rx_ht_phy *ht; | ||
625 | |||
626 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
627 | if (!buf) | ||
628 | return -ENOMEM; | ||
629 | |||
630 | mutex_lock(&mvm->mutex); | ||
631 | |||
632 | ofdm = &mvm->rx_stats.ofdm; | ||
633 | cck = &mvm->rx_stats.cck; | ||
634 | general = &mvm->rx_stats.general; | ||
635 | ht = &mvm->rx_stats.ofdm_ht; | ||
636 | |||
637 | pos += scnprintf(buf + pos, bufsz - pos, fmt_header, | ||
638 | "Statistics_Rx - OFDM"); | ||
639 | PRINT_STATS_LE32("ina_cnt", ofdm->ina_cnt); | ||
640 | PRINT_STATS_LE32("fina_cnt", ofdm->fina_cnt); | ||
641 | PRINT_STATS_LE32("plcp_err", ofdm->plcp_err); | ||
642 | PRINT_STATS_LE32("crc32_err", ofdm->crc32_err); | ||
643 | PRINT_STATS_LE32("overrun_err", ofdm->overrun_err); | ||
644 | PRINT_STATS_LE32("early_overrun_err", ofdm->early_overrun_err); | ||
645 | PRINT_STATS_LE32("crc32_good", ofdm->crc32_good); | ||
646 | PRINT_STATS_LE32("false_alarm_cnt", ofdm->false_alarm_cnt); | ||
647 | PRINT_STATS_LE32("fina_sync_err_cnt", ofdm->fina_sync_err_cnt); | ||
648 | PRINT_STATS_LE32("sfd_timeout", ofdm->sfd_timeout); | ||
649 | PRINT_STATS_LE32("fina_timeout", ofdm->fina_timeout); | ||
650 | PRINT_STATS_LE32("unresponded_rts", ofdm->unresponded_rts); | ||
651 | PRINT_STATS_LE32("rxe_frame_lmt_overrun", | ||
652 | ofdm->rxe_frame_limit_overrun); | ||
653 | PRINT_STATS_LE32("sent_ack_cnt", ofdm->sent_ack_cnt); | ||
654 | PRINT_STATS_LE32("sent_cts_cnt", ofdm->sent_cts_cnt); | ||
655 | PRINT_STATS_LE32("sent_ba_rsp_cnt", ofdm->sent_ba_rsp_cnt); | ||
656 | PRINT_STATS_LE32("dsp_self_kill", ofdm->dsp_self_kill); | ||
657 | PRINT_STATS_LE32("mh_format_err", ofdm->mh_format_err); | ||
658 | PRINT_STATS_LE32("re_acq_main_rssi_sum", ofdm->re_acq_main_rssi_sum); | ||
659 | PRINT_STATS_LE32("reserved", ofdm->reserved); | ||
660 | |||
661 | pos += scnprintf(buf + pos, bufsz - pos, fmt_header, | ||
662 | "Statistics_Rx - CCK"); | ||
663 | PRINT_STATS_LE32("ina_cnt", cck->ina_cnt); | ||
664 | PRINT_STATS_LE32("fina_cnt", cck->fina_cnt); | ||
665 | PRINT_STATS_LE32("plcp_err", cck->plcp_err); | ||
666 | PRINT_STATS_LE32("crc32_err", cck->crc32_err); | ||
667 | PRINT_STATS_LE32("overrun_err", cck->overrun_err); | ||
668 | PRINT_STATS_LE32("early_overrun_err", cck->early_overrun_err); | ||
669 | PRINT_STATS_LE32("crc32_good", cck->crc32_good); | ||
670 | PRINT_STATS_LE32("false_alarm_cnt", cck->false_alarm_cnt); | ||
671 | PRINT_STATS_LE32("fina_sync_err_cnt", cck->fina_sync_err_cnt); | ||
672 | PRINT_STATS_LE32("sfd_timeout", cck->sfd_timeout); | ||
673 | PRINT_STATS_LE32("fina_timeout", cck->fina_timeout); | ||
674 | PRINT_STATS_LE32("unresponded_rts", cck->unresponded_rts); | ||
675 | PRINT_STATS_LE32("rxe_frame_lmt_overrun", | ||
676 | cck->rxe_frame_limit_overrun); | ||
677 | PRINT_STATS_LE32("sent_ack_cnt", cck->sent_ack_cnt); | ||
678 | PRINT_STATS_LE32("sent_cts_cnt", cck->sent_cts_cnt); | ||
679 | PRINT_STATS_LE32("sent_ba_rsp_cnt", cck->sent_ba_rsp_cnt); | ||
680 | PRINT_STATS_LE32("dsp_self_kill", cck->dsp_self_kill); | ||
681 | PRINT_STATS_LE32("mh_format_err", cck->mh_format_err); | ||
682 | PRINT_STATS_LE32("re_acq_main_rssi_sum", cck->re_acq_main_rssi_sum); | ||
683 | PRINT_STATS_LE32("reserved", cck->reserved); | ||
684 | |||
685 | pos += scnprintf(buf + pos, bufsz - pos, fmt_header, | ||
686 | "Statistics_Rx - GENERAL"); | ||
687 | PRINT_STATS_LE32("bogus_cts", general->bogus_cts); | ||
688 | PRINT_STATS_LE32("bogus_ack", general->bogus_ack); | ||
689 | PRINT_STATS_LE32("non_bssid_frames", general->non_bssid_frames); | ||
690 | PRINT_STATS_LE32("filtered_frames", general->filtered_frames); | ||
691 | PRINT_STATS_LE32("non_channel_beacons", general->non_channel_beacons); | ||
692 | PRINT_STATS_LE32("channel_beacons", general->channel_beacons); | ||
693 | PRINT_STATS_LE32("num_missed_bcon", general->num_missed_bcon); | ||
694 | PRINT_STATS_LE32("adc_rx_saturation_time", | ||
695 | general->adc_rx_saturation_time); | ||
696 | PRINT_STATS_LE32("ina_detection_search_time", | ||
697 | general->ina_detection_search_time); | ||
698 | PRINT_STATS_LE32("beacon_silence_rssi_a", | ||
699 | general->beacon_silence_rssi_a); | ||
700 | PRINT_STATS_LE32("beacon_silence_rssi_b", | ||
701 | general->beacon_silence_rssi_b); | ||
702 | PRINT_STATS_LE32("beacon_silence_rssi_c", | ||
703 | general->beacon_silence_rssi_c); | ||
704 | PRINT_STATS_LE32("interference_data_flag", | ||
705 | general->interference_data_flag); | ||
706 | PRINT_STATS_LE32("channel_load", general->channel_load); | ||
707 | PRINT_STATS_LE32("dsp_false_alarms", general->dsp_false_alarms); | ||
708 | PRINT_STATS_LE32("beacon_rssi_a", general->beacon_rssi_a); | ||
709 | PRINT_STATS_LE32("beacon_rssi_b", general->beacon_rssi_b); | ||
710 | PRINT_STATS_LE32("beacon_rssi_c", general->beacon_rssi_c); | ||
711 | PRINT_STATS_LE32("beacon_energy_a", general->beacon_energy_a); | ||
712 | PRINT_STATS_LE32("beacon_energy_b", general->beacon_energy_b); | ||
713 | PRINT_STATS_LE32("beacon_energy_c", general->beacon_energy_c); | ||
714 | PRINT_STATS_LE32("num_bt_kills", general->num_bt_kills); | ||
715 | PRINT_STATS_LE32("directed_data_mpdu", general->directed_data_mpdu); | ||
716 | |||
717 | pos += scnprintf(buf + pos, bufsz - pos, fmt_header, | ||
718 | "Statistics_Rx - HT"); | ||
719 | PRINT_STATS_LE32("plcp_err", ht->plcp_err); | ||
720 | PRINT_STATS_LE32("overrun_err", ht->overrun_err); | ||
721 | PRINT_STATS_LE32("early_overrun_err", ht->early_overrun_err); | ||
722 | PRINT_STATS_LE32("crc32_good", ht->crc32_good); | ||
723 | PRINT_STATS_LE32("crc32_err", ht->crc32_err); | ||
724 | PRINT_STATS_LE32("mh_format_err", ht->mh_format_err); | ||
725 | PRINT_STATS_LE32("agg_crc32_good", ht->agg_crc32_good); | ||
726 | PRINT_STATS_LE32("agg_mpdu_cnt", ht->agg_mpdu_cnt); | ||
727 | PRINT_STATS_LE32("agg_cnt", ht->agg_cnt); | ||
728 | PRINT_STATS_LE32("unsupport_mcs", ht->unsupport_mcs); | ||
729 | |||
730 | mutex_unlock(&mvm->mutex); | ||
731 | |||
732 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
733 | kfree(buf); | ||
734 | |||
735 | return ret; | ||
736 | } | ||
737 | #undef PRINT_STAT_LE32 | ||
738 | |||
624 | static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, | 739 | static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, |
625 | const char __user *user_buf, | 740 | const char __user *user_buf, |
626 | size_t count, loff_t *ppos) | 741 | size_t count, loff_t *ppos) |
627 | { | 742 | { |
628 | struct iwl_mvm *mvm = file->private_data; | 743 | struct iwl_mvm *mvm = file->private_data; |
629 | bool restart_fw = iwlwifi_mod_params.restart_fw; | ||
630 | int ret; | 744 | int ret; |
631 | 745 | ||
632 | iwlwifi_mod_params.restart_fw = true; | ||
633 | |||
634 | mutex_lock(&mvm->mutex); | 746 | mutex_lock(&mvm->mutex); |
635 | 747 | ||
748 | /* allow one more restart that we're provoking here */ | ||
749 | if (mvm->restart_fw >= 0) | ||
750 | mvm->restart_fw++; | ||
751 | |||
636 | /* take the return value to make compiler happy - it will fail anyway */ | 752 | /* take the return value to make compiler happy - it will fail anyway */ |
637 | ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, CMD_SYNC, 0, NULL); | 753 | ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, CMD_SYNC, 0, NULL); |
638 | 754 | ||
639 | mutex_unlock(&mvm->mutex); | 755 | mutex_unlock(&mvm->mutex); |
640 | 756 | ||
641 | iwlwifi_mod_params.restart_fw = restart_fw; | ||
642 | |||
643 | return count; | 757 | return count; |
644 | } | 758 | } |
645 | 759 | ||
@@ -661,8 +775,14 @@ static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif, | |||
661 | case MVM_DEBUGFS_BF_ROAMING_STATE: | 775 | case MVM_DEBUGFS_BF_ROAMING_STATE: |
662 | dbgfs_bf->bf_roaming_state = value; | 776 | dbgfs_bf->bf_roaming_state = value; |
663 | break; | 777 | break; |
664 | case MVM_DEBUGFS_BF_TEMPERATURE_DELTA: | 778 | case MVM_DEBUGFS_BF_TEMP_THRESHOLD: |
665 | dbgfs_bf->bf_temperature_delta = value; | 779 | dbgfs_bf->bf_temp_threshold = value; |
780 | break; | ||
781 | case MVM_DEBUGFS_BF_TEMP_FAST_FILTER: | ||
782 | dbgfs_bf->bf_temp_fast_filter = value; | ||
783 | break; | ||
784 | case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER: | ||
785 | dbgfs_bf->bf_temp_slow_filter = value; | ||
666 | break; | 786 | break; |
667 | case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER: | 787 | case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER: |
668 | dbgfs_bf->bf_enable_beacon_filter = value; | 788 | dbgfs_bf->bf_enable_beacon_filter = value; |
@@ -721,13 +841,27 @@ static ssize_t iwl_dbgfs_bf_params_write(struct file *file, | |||
721 | value > IWL_BF_ROAMING_STATE_MAX) | 841 | value > IWL_BF_ROAMING_STATE_MAX) |
722 | return -EINVAL; | 842 | return -EINVAL; |
723 | param = MVM_DEBUGFS_BF_ROAMING_STATE; | 843 | param = MVM_DEBUGFS_BF_ROAMING_STATE; |
724 | } else if (!strncmp("bf_temperature_delta=", buf, 21)) { | 844 | } else if (!strncmp("bf_temp_threshold=", buf, 18)) { |
725 | if (sscanf(buf+21, "%d", &value) != 1) | 845 | if (sscanf(buf+18, "%d", &value) != 1) |
846 | return -EINVAL; | ||
847 | if (value < IWL_BF_TEMP_THRESHOLD_MIN || | ||
848 | value > IWL_BF_TEMP_THRESHOLD_MAX) | ||
726 | return -EINVAL; | 849 | return -EINVAL; |
727 | if (value < IWL_BF_TEMPERATURE_DELTA_MIN || | 850 | param = MVM_DEBUGFS_BF_TEMP_THRESHOLD; |
728 | value > IWL_BF_TEMPERATURE_DELTA_MAX) | 851 | } else if (!strncmp("bf_temp_fast_filter=", buf, 20)) { |
852 | if (sscanf(buf+20, "%d", &value) != 1) | ||
729 | return -EINVAL; | 853 | return -EINVAL; |
730 | param = MVM_DEBUGFS_BF_TEMPERATURE_DELTA; | 854 | if (value < IWL_BF_TEMP_FAST_FILTER_MIN || |
855 | value > IWL_BF_TEMP_FAST_FILTER_MAX) | ||
856 | return -EINVAL; | ||
857 | param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER; | ||
858 | } else if (!strncmp("bf_temp_slow_filter=", buf, 20)) { | ||
859 | if (sscanf(buf+20, "%d", &value) != 1) | ||
860 | return -EINVAL; | ||
861 | if (value < IWL_BF_TEMP_SLOW_FILTER_MIN || | ||
862 | value > IWL_BF_TEMP_SLOW_FILTER_MAX) | ||
863 | return -EINVAL; | ||
864 | param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER; | ||
731 | } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) { | 865 | } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) { |
732 | if (sscanf(buf+24, "%d", &value) != 1) | 866 | if (sscanf(buf+24, "%d", &value) != 1) |
733 | return -EINVAL; | 867 | return -EINVAL; |
@@ -769,10 +903,7 @@ static ssize_t iwl_dbgfs_bf_params_write(struct file *file, | |||
769 | if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) { | 903 | if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) { |
770 | ret = iwl_mvm_disable_beacon_filter(mvm, vif); | 904 | ret = iwl_mvm_disable_beacon_filter(mvm, vif); |
771 | } else { | 905 | } else { |
772 | if (mvmvif->bf_enabled) | 906 | ret = iwl_mvm_enable_beacon_filter(mvm, vif); |
773 | ret = iwl_mvm_enable_beacon_filter(mvm, vif); | ||
774 | else | ||
775 | ret = iwl_mvm_disable_beacon_filter(mvm, vif); | ||
776 | } | 907 | } |
777 | mutex_unlock(&mvm->mutex); | 908 | mutex_unlock(&mvm->mutex); |
778 | 909 | ||
@@ -789,41 +920,41 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file, | |||
789 | int pos = 0; | 920 | int pos = 0; |
790 | const size_t bufsz = sizeof(buf); | 921 | const size_t bufsz = sizeof(buf); |
791 | struct iwl_beacon_filter_cmd cmd = { | 922 | struct iwl_beacon_filter_cmd cmd = { |
792 | .bf_energy_delta = IWL_BF_ENERGY_DELTA_DEFAULT, | 923 | IWL_BF_CMD_CONFIG_DEFAULTS, |
793 | .bf_roaming_energy_delta = IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT, | 924 | .bf_enable_beacon_filter = |
794 | .bf_roaming_state = IWL_BF_ROAMING_STATE_DEFAULT, | 925 | cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT), |
795 | .bf_temperature_delta = IWL_BF_TEMPERATURE_DELTA_DEFAULT, | 926 | .ba_enable_beacon_abort = |
796 | .bf_enable_beacon_filter = IWL_BF_ENABLE_BEACON_FILTER_DEFAULT, | 927 | cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT), |
797 | .bf_debug_flag = IWL_BF_DEBUG_FLAG_DEFAULT, | ||
798 | .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT), | ||
799 | .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT), | ||
800 | .ba_enable_beacon_abort = IWL_BA_ENABLE_BEACON_ABORT_DEFAULT, | ||
801 | }; | 928 | }; |
802 | 929 | ||
803 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); | 930 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); |
804 | if (mvmvif->bf_enabled) | 931 | if (mvmvif->bf_data.bf_enabled) |
805 | cmd.bf_enable_beacon_filter = 1; | 932 | cmd.bf_enable_beacon_filter = cpu_to_le32(1); |
806 | else | 933 | else |
807 | cmd.bf_enable_beacon_filter = 0; | 934 | cmd.bf_enable_beacon_filter = 0; |
808 | 935 | ||
809 | pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n", | 936 | pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n", |
810 | cmd.bf_energy_delta); | 937 | le32_to_cpu(cmd.bf_energy_delta)); |
811 | pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n", | 938 | pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n", |
812 | cmd.bf_roaming_energy_delta); | 939 | le32_to_cpu(cmd.bf_roaming_energy_delta)); |
813 | pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n", | 940 | pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n", |
814 | cmd.bf_roaming_state); | 941 | le32_to_cpu(cmd.bf_roaming_state)); |
815 | pos += scnprintf(buf+pos, bufsz-pos, "bf_temperature_delta = %d\n", | 942 | pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n", |
816 | cmd.bf_temperature_delta); | 943 | le32_to_cpu(cmd.bf_temp_threshold)); |
944 | pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n", | ||
945 | le32_to_cpu(cmd.bf_temp_fast_filter)); | ||
946 | pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n", | ||
947 | le32_to_cpu(cmd.bf_temp_slow_filter)); | ||
817 | pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n", | 948 | pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n", |
818 | cmd.bf_enable_beacon_filter); | 949 | le32_to_cpu(cmd.bf_enable_beacon_filter)); |
819 | pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n", | 950 | pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n", |
820 | cmd.bf_debug_flag); | 951 | le32_to_cpu(cmd.bf_debug_flag)); |
821 | pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n", | 952 | pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n", |
822 | cmd.bf_escape_timer); | 953 | le32_to_cpu(cmd.bf_escape_timer)); |
823 | pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n", | 954 | pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n", |
824 | cmd.ba_escape_timer); | 955 | le32_to_cpu(cmd.ba_escape_timer)); |
825 | pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n", | 956 | pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n", |
826 | cmd.ba_enable_beacon_abort); | 957 | le32_to_cpu(cmd.ba_enable_beacon_abort)); |
827 | 958 | ||
828 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 959 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
829 | } | 960 | } |
@@ -934,6 +1065,7 @@ MVM_DEBUGFS_READ_FILE_OPS(stations); | |||
934 | MVM_DEBUGFS_READ_FILE_OPS(bt_notif); | 1065 | MVM_DEBUGFS_READ_FILE_OPS(bt_notif); |
935 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow); | 1066 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow); |
936 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow); | 1067 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow); |
1068 | MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); | ||
937 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart); | 1069 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart); |
938 | #ifdef CONFIG_PM_SLEEP | 1070 | #ifdef CONFIG_PM_SLEEP |
939 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram); | 1071 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram); |
@@ -957,6 +1089,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | |||
957 | MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); | 1089 | MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); |
958 | MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR); | 1090 | MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR); |
959 | MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR); | 1091 | MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR); |
1092 | MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); | ||
960 | MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); | 1093 | MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); |
961 | #ifdef CONFIG_PM_SLEEP | 1094 | #ifdef CONFIG_PM_SLEEP |
962 | MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); | 1095 | MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index 6f8b2c16ae17..df72fcdf8170 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | |||
@@ -98,34 +98,63 @@ enum iwl_proto_offloads { | |||
98 | IWL_D3_PROTO_OFFLOAD_NS = BIT(1), | 98 | IWL_D3_PROTO_OFFLOAD_NS = BIT(1), |
99 | }; | 99 | }; |
100 | 100 | ||
101 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS 2 | 101 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2 |
102 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2 6 | ||
103 | #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX 6 | ||
102 | 104 | ||
103 | /** | 105 | /** |
104 | * struct iwl_proto_offload_cmd - ARP/NS offload configuration | 106 | * struct iwl_proto_offload_cmd_common - ARP/NS offload common part |
105 | * @enabled: enable flags | 107 | * @enabled: enable flags |
106 | * @remote_ipv4_addr: remote address to answer to (or zero if all) | 108 | * @remote_ipv4_addr: remote address to answer to (or zero if all) |
107 | * @host_ipv4_addr: our IPv4 address to respond to queries for | 109 | * @host_ipv4_addr: our IPv4 address to respond to queries for |
108 | * @arp_mac_addr: our MAC address for ARP responses | 110 | * @arp_mac_addr: our MAC address for ARP responses |
109 | * @remote_ipv6_addr: remote address to answer to (or zero if all) | 111 | * @reserved: unused |
110 | * @solicited_node_ipv6_addr: broken -- solicited node address exists | ||
111 | * for each target address | ||
112 | * @target_ipv6_addr: our target addresses | ||
113 | * @ndp_mac_addr: neighbor soliciation response MAC address | ||
114 | */ | 112 | */ |
115 | struct iwl_proto_offload_cmd { | 113 | struct iwl_proto_offload_cmd_common { |
116 | __le32 enabled; | 114 | __le32 enabled; |
117 | __be32 remote_ipv4_addr; | 115 | __be32 remote_ipv4_addr; |
118 | __be32 host_ipv4_addr; | 116 | __be32 host_ipv4_addr; |
119 | u8 arp_mac_addr[ETH_ALEN]; | 117 | u8 arp_mac_addr[ETH_ALEN]; |
120 | __le16 reserved1; | 118 | __le16 reserved; |
119 | } __packed; | ||
121 | 120 | ||
121 | /** | ||
122 | * struct iwl_proto_offload_cmd_v1 - ARP/NS offload configuration | ||
123 | * @common: common/IPv4 configuration | ||
124 | * @remote_ipv6_addr: remote address to answer to (or zero if all) | ||
125 | * @solicited_node_ipv6_addr: broken -- solicited node address exists | ||
126 | * for each target address | ||
127 | * @target_ipv6_addr: our target addresses | ||
128 | * @ndp_mac_addr: neighbor soliciation response MAC address | ||
129 | */ | ||
130 | struct iwl_proto_offload_cmd_v1 { | ||
131 | struct iwl_proto_offload_cmd_common common; | ||
122 | u8 remote_ipv6_addr[16]; | 132 | u8 remote_ipv6_addr[16]; |
123 | u8 solicited_node_ipv6_addr[16]; | 133 | u8 solicited_node_ipv6_addr[16]; |
124 | u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS][16]; | 134 | u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1][16]; |
125 | u8 ndp_mac_addr[ETH_ALEN]; | 135 | u8 ndp_mac_addr[ETH_ALEN]; |
126 | __le16 reserved2; | 136 | __le16 reserved2; |
127 | } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_1 */ | 137 | } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_1 */ |
128 | 138 | ||
139 | /** | ||
140 | * struct iwl_proto_offload_cmd_v2 - ARP/NS offload configuration | ||
141 | * @common: common/IPv4 configuration | ||
142 | * @remote_ipv6_addr: remote address to answer to (or zero if all) | ||
143 | * @solicited_node_ipv6_addr: broken -- solicited node address exists | ||
144 | * for each target address | ||
145 | * @target_ipv6_addr: our target addresses | ||
146 | * @ndp_mac_addr: neighbor soliciation response MAC address | ||
147 | */ | ||
148 | struct iwl_proto_offload_cmd_v2 { | ||
149 | struct iwl_proto_offload_cmd_common common; | ||
150 | u8 remote_ipv6_addr[16]; | ||
151 | u8 solicited_node_ipv6_addr[16]; | ||
152 | u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2][16]; | ||
153 | u8 ndp_mac_addr[ETH_ALEN]; | ||
154 | u8 numValidIPv6Addresses; | ||
155 | u8 reserved2[3]; | ||
156 | } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_2 */ | ||
157 | |||
129 | 158 | ||
130 | /* | 159 | /* |
131 | * WOWLAN_PATTERNS | 160 | * WOWLAN_PATTERNS |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index a6da359a80c3..8e7ab41079ca 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | |||
@@ -79,6 +79,10 @@ | |||
79 | * '1' Driver enables PM (use rest of parameters) | 79 | * '1' Driver enables PM (use rest of parameters) |
80 | * @POWER_FLAGS_SKIP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM, | 80 | * @POWER_FLAGS_SKIP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM, |
81 | * '1' PM could sleep over DTIM till listen Interval. | 81 | * '1' PM could sleep over DTIM till listen Interval. |
82 | * @POWER_FLAGS_SNOOZE_ENA_MSK: Enable snoozing only if uAPSD is enabled and all | ||
83 | * access categories are both delivery and trigger enabled. | ||
84 | * @POWER_FLAGS_BT_SCO_ENA: Enable BT SCO coex only if uAPSD and | ||
85 | * PBW Snoozing enabled | ||
82 | * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask | 86 | * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask |
83 | * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. | 87 | * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. |
84 | */ | 88 | */ |
@@ -86,6 +90,8 @@ enum iwl_power_flags { | |||
86 | POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0), | 90 | POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0), |
87 | POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(1), | 91 | POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(1), |
88 | POWER_FLAGS_SKIP_OVER_DTIM_MSK = BIT(2), | 92 | POWER_FLAGS_SKIP_OVER_DTIM_MSK = BIT(2), |
93 | POWER_FLAGS_SNOOZE_ENA_MSK = BIT(5), | ||
94 | POWER_FLAGS_BT_SCO_ENA = BIT(8), | ||
89 | POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(9), | 95 | POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(9), |
90 | POWER_FLAGS_LPRX_ENA_MSK = BIT(11), | 96 | POWER_FLAGS_LPRX_ENA_MSK = BIT(11), |
91 | }; | 97 | }; |
@@ -93,7 +99,8 @@ enum iwl_power_flags { | |||
93 | #define IWL_POWER_VEC_SIZE 5 | 99 | #define IWL_POWER_VEC_SIZE 5 |
94 | 100 | ||
95 | /** | 101 | /** |
96 | * struct iwl_powertable_cmd - Power Table Command | 102 | * struct iwl_powertable_cmd - legacy power command. Beside old API support this |
103 | * is used also with a new power API for device wide power settings. | ||
97 | * POWER_TABLE_CMD = 0x77 (command, has simple generic response) | 104 | * POWER_TABLE_CMD = 0x77 (command, has simple generic response) |
98 | * | 105 | * |
99 | * @flags: Power table command flags from POWER_FLAGS_* | 106 | * @flags: Power table command flags from POWER_FLAGS_* |
@@ -125,6 +132,76 @@ struct iwl_powertable_cmd { | |||
125 | } __packed; | 132 | } __packed; |
126 | 133 | ||
127 | /** | 134 | /** |
135 | * struct iwl_mac_power_cmd - New power command containing uAPSD support | ||
136 | * MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response) | ||
137 | * @id_and_color: MAC contex identifier | ||
138 | * @flags: Power table command flags from POWER_FLAGS_* | ||
139 | * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. | ||
140 | * Minimum allowed:- 3 * DTIM. Keep alive period must be | ||
141 | * set regardless of power scheme or current power state. | ||
142 | * FW use this value also when PM is disabled. | ||
143 | * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to | ||
144 | * PSM transition - legacy PM | ||
145 | * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to | ||
146 | * PSM transition - legacy PM | ||
147 | * @sleep_interval: not in use | ||
148 | * @skip_dtim_periods: Number of DTIM periods to skip if Skip over DTIM flag | ||
149 | * is set. For example, if it is required to skip over | ||
150 | * one DTIM, this value need to be set to 2 (DTIM periods). | ||
151 | * @rx_data_timeout_uapsd: Minimum time (usec) from last Rx packet for AM to | ||
152 | * PSM transition - uAPSD | ||
153 | * @tx_data_timeout_uapsd: Minimum time (usec) from last Tx packet for AM to | ||
154 | * PSM transition - uAPSD | ||
155 | * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. | ||
156 | * Default: 80dbm | ||
157 | * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set | ||
158 | * @snooze_interval: Maximum time between attempts to retrieve buffered data | ||
159 | * from the AP [msec] | ||
160 | * @snooze_window: A window of time in which PBW snoozing insures that all | ||
161 | * packets received. It is also the minimum time from last | ||
162 | * received unicast RX packet, before client stops snoozing | ||
163 | * for data. [msec] | ||
164 | * @snooze_step: TBD | ||
165 | * @qndp_tid: TID client shall use for uAPSD QNDP triggers | ||
166 | * @uapsd_ac_flags: Set trigger-enabled and delivery-enabled indication for | ||
167 | * each corresponding AC. | ||
168 | * Use IEEE80211_WMM_IE_STA_QOSINFO_AC* for correct values. | ||
169 | * @uapsd_max_sp: Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct | ||
170 | * values. | ||
171 | * @heavy_tx_thld_packets: TX threshold measured in number of packets | ||
172 | * @heavy_rx_thld_packets: RX threshold measured in number of packets | ||
173 | * @heavy_tx_thld_percentage: TX threshold measured in load's percentage | ||
174 | * @heavy_rx_thld_percentage: RX threshold measured in load's percentage | ||
175 | * @limited_ps_threshold: | ||
176 | */ | ||
177 | struct iwl_mac_power_cmd { | ||
178 | /* CONTEXT_DESC_API_T_VER_1 */ | ||
179 | __le32 id_and_color; | ||
180 | |||
181 | /* CLIENT_PM_POWER_TABLE_S_VER_1 */ | ||
182 | __le16 flags; | ||
183 | __le16 keep_alive_seconds; | ||
184 | __le32 rx_data_timeout; | ||
185 | __le32 tx_data_timeout; | ||
186 | __le32 rx_data_timeout_uapsd; | ||
187 | __le32 tx_data_timeout_uapsd; | ||
188 | u8 lprx_rssi_threshold; | ||
189 | u8 skip_dtim_periods; | ||
190 | __le16 snooze_interval; | ||
191 | __le16 snooze_window; | ||
192 | u8 snooze_step; | ||
193 | u8 qndp_tid; | ||
194 | u8 uapsd_ac_flags; | ||
195 | u8 uapsd_max_sp; | ||
196 | u8 heavy_tx_thld_packets; | ||
197 | u8 heavy_rx_thld_packets; | ||
198 | u8 heavy_tx_thld_percentage; | ||
199 | u8 heavy_rx_thld_percentage; | ||
200 | u8 limited_ps_threshold; | ||
201 | u8 reserved; | ||
202 | } __packed; | ||
203 | |||
204 | /** | ||
128 | * struct iwl_beacon_filter_cmd | 205 | * struct iwl_beacon_filter_cmd |
129 | * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) | 206 | * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) |
130 | * @id_and_color: MAC contex identifier | 207 | * @id_and_color: MAC contex identifier |
@@ -143,11 +220,21 @@ struct iwl_powertable_cmd { | |||
143 | * calculated for current beacon is less than the threshold, use | 220 | * calculated for current beacon is less than the threshold, use |
144 | * Roaming Energy Delta Threshold, otherwise use normal Energy Delta | 221 | * Roaming Energy Delta Threshold, otherwise use normal Energy Delta |
145 | * Threshold. Typical energy threshold is -72dBm. | 222 | * Threshold. Typical energy threshold is -72dBm. |
146 | * @bf_temperature_delta: Send Beacon to driver if delta in temperature values | 223 | * @bf_temp_threshold: This threshold determines the type of temperature |
147 | * calculated for this and the last passed beacon is greater than this | 224 | * filtering (Slow or Fast) that is selected (Units are in Celsuis): |
148 | * threshold. Zero value means that the temperature changeis ignored for | 225 | * If the current temperature is above this threshold - Fast filter |
226 | * will be used, If the current temperature is below this threshold - | ||
227 | * Slow filter will be used. | ||
228 | * @bf_temp_fast_filter: Send Beacon to driver if delta in temperature values | ||
229 | * calculated for this and the last passed beacon is greater than this | ||
230 | * threshold. Zero value means that the temperature change is ignored for | ||
149 | * beacon filtering; beacons will not be forced to be sent to driver | 231 | * beacon filtering; beacons will not be forced to be sent to driver |
150 | * regardless of whether its temerature has been changed. | 232 | * regardless of whether its temerature has been changed. |
233 | * @bf_temp_slow_filter: Send Beacon to driver if delta in temperature values | ||
234 | * calculated for this and the last passed beacon is greater than this | ||
235 | * threshold. Zero value means that the temperature change is ignored for | ||
236 | * beacon filtering; beacons will not be forced to be sent to driver | ||
237 | * regardless of whether its temerature has been changed. | ||
151 | * @bf_enable_beacon_filter: 1, beacon filtering is enabled; 0, disabled. | 238 | * @bf_enable_beacon_filter: 1, beacon filtering is enabled; 0, disabled. |
152 | * @bf_filter_escape_timer: Send beacons to to driver if no beacons were passed | 239 | * @bf_filter_escape_timer: Send beacons to to driver if no beacons were passed |
153 | * for a specific period of time. Units: Beacons. | 240 | * for a specific period of time. Units: Beacons. |
@@ -156,17 +243,17 @@ struct iwl_powertable_cmd { | |||
156 | * @ba_enable_beacon_abort: 1, beacon abort is enabled; 0, disabled. | 243 | * @ba_enable_beacon_abort: 1, beacon abort is enabled; 0, disabled. |
157 | */ | 244 | */ |
158 | struct iwl_beacon_filter_cmd { | 245 | struct iwl_beacon_filter_cmd { |
159 | u8 bf_energy_delta; | 246 | __le32 bf_energy_delta; |
160 | u8 bf_roaming_energy_delta; | 247 | __le32 bf_roaming_energy_delta; |
161 | u8 bf_roaming_state; | 248 | __le32 bf_roaming_state; |
162 | u8 bf_temperature_delta; | 249 | __le32 bf_temp_threshold; |
163 | u8 bf_enable_beacon_filter; | 250 | __le32 bf_temp_fast_filter; |
164 | u8 bf_debug_flag; | 251 | __le32 bf_temp_slow_filter; |
165 | __le16 reserved1; | 252 | __le32 bf_enable_beacon_filter; |
253 | __le32 bf_debug_flag; | ||
166 | __le32 bf_escape_timer; | 254 | __le32 bf_escape_timer; |
167 | __le32 ba_escape_timer; | 255 | __le32 ba_escape_timer; |
168 | u8 ba_enable_beacon_abort; | 256 | __le32 ba_enable_beacon_abort; |
169 | u8 reserved2[3]; | ||
170 | } __packed; | 257 | } __packed; |
171 | 258 | ||
172 | /* Beacon filtering and beacon abort */ | 259 | /* Beacon filtering and beacon abort */ |
@@ -182,9 +269,17 @@ struct iwl_beacon_filter_cmd { | |||
182 | #define IWL_BF_ROAMING_STATE_MAX 255 | 269 | #define IWL_BF_ROAMING_STATE_MAX 255 |
183 | #define IWL_BF_ROAMING_STATE_MIN 0 | 270 | #define IWL_BF_ROAMING_STATE_MIN 0 |
184 | 271 | ||
185 | #define IWL_BF_TEMPERATURE_DELTA_DEFAULT 5 | 272 | #define IWL_BF_TEMP_THRESHOLD_DEFAULT 112 |
186 | #define IWL_BF_TEMPERATURE_DELTA_MAX 255 | 273 | #define IWL_BF_TEMP_THRESHOLD_MAX 255 |
187 | #define IWL_BF_TEMPERATURE_DELTA_MIN 0 | 274 | #define IWL_BF_TEMP_THRESHOLD_MIN 0 |
275 | |||
276 | #define IWL_BF_TEMP_FAST_FILTER_DEFAULT 1 | ||
277 | #define IWL_BF_TEMP_FAST_FILTER_MAX 255 | ||
278 | #define IWL_BF_TEMP_FAST_FILTER_MIN 0 | ||
279 | |||
280 | #define IWL_BF_TEMP_SLOW_FILTER_DEFAULT 5 | ||
281 | #define IWL_BF_TEMP_SLOW_FILTER_MAX 255 | ||
282 | #define IWL_BF_TEMP_SLOW_FILTER_MIN 0 | ||
188 | 283 | ||
189 | #define IWL_BF_ENABLE_BEACON_FILTER_DEFAULT 1 | 284 | #define IWL_BF_ENABLE_BEACON_FILTER_DEFAULT 1 |
190 | 285 | ||
@@ -194,19 +289,23 @@ struct iwl_beacon_filter_cmd { | |||
194 | #define IWL_BF_ESCAPE_TIMER_MAX 1024 | 289 | #define IWL_BF_ESCAPE_TIMER_MAX 1024 |
195 | #define IWL_BF_ESCAPE_TIMER_MIN 0 | 290 | #define IWL_BF_ESCAPE_TIMER_MIN 0 |
196 | 291 | ||
197 | #define IWL_BA_ESCAPE_TIMER_DEFAULT 3 | 292 | #define IWL_BA_ESCAPE_TIMER_DEFAULT 6 |
293 | #define IWL_BA_ESCAPE_TIMER_D3 6 | ||
198 | #define IWL_BA_ESCAPE_TIMER_MAX 1024 | 294 | #define IWL_BA_ESCAPE_TIMER_MAX 1024 |
199 | #define IWL_BA_ESCAPE_TIMER_MIN 0 | 295 | #define IWL_BA_ESCAPE_TIMER_MIN 0 |
200 | 296 | ||
201 | #define IWL_BA_ENABLE_BEACON_ABORT_DEFAULT 1 | 297 | #define IWL_BA_ENABLE_BEACON_ABORT_DEFAULT 1 |
202 | 298 | ||
203 | #define IWL_BF_CMD_CONFIG_DEFAULTS \ | 299 | #define IWL_BF_CMD_CONFIG_DEFAULTS \ |
204 | .bf_energy_delta = IWL_BF_ENERGY_DELTA_DEFAULT, \ | 300 | .bf_energy_delta = cpu_to_le32(IWL_BF_ENERGY_DELTA_DEFAULT), \ |
205 | .bf_roaming_energy_delta = IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT, \ | 301 | .bf_roaming_energy_delta = \ |
206 | .bf_roaming_state = IWL_BF_ROAMING_STATE_DEFAULT, \ | 302 | cpu_to_le32(IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT), \ |
207 | .bf_temperature_delta = IWL_BF_TEMPERATURE_DELTA_DEFAULT, \ | 303 | .bf_roaming_state = cpu_to_le32(IWL_BF_ROAMING_STATE_DEFAULT), \ |
208 | .bf_debug_flag = IWL_BF_DEBUG_FLAG_DEFAULT, \ | 304 | .bf_temp_threshold = cpu_to_le32(IWL_BF_TEMP_THRESHOLD_DEFAULT), \ |
209 | .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT), \ | 305 | .bf_temp_fast_filter = cpu_to_le32(IWL_BF_TEMP_FAST_FILTER_DEFAULT), \ |
306 | .bf_temp_slow_filter = cpu_to_le32(IWL_BF_TEMP_SLOW_FILTER_DEFAULT), \ | ||
307 | .bf_debug_flag = cpu_to_le32(IWL_BF_DEBUG_FLAG_DEFAULT), \ | ||
308 | .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT), \ | ||
210 | .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT) | 309 | .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT) |
211 | 310 | ||
212 | #endif | 311 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 365095a0c3b3..83cb9b992ea4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | |||
@@ -137,6 +137,8 @@ struct iwl_ssid_ie { | |||
137 | *@SCAN_FLAGS_DELAYED_SCAN_LOWBAND: | 137 | *@SCAN_FLAGS_DELAYED_SCAN_LOWBAND: |
138 | *@SCAN_FLAGS_DELAYED_SCAN_HIGHBAND: | 138 | *@SCAN_FLAGS_DELAYED_SCAN_HIGHBAND: |
139 | *@SCAN_FLAGS_FRAGMENTED_SCAN: | 139 | *@SCAN_FLAGS_FRAGMENTED_SCAN: |
140 | *@SCAN_FLAGS_PASSIVE2ACTIVE: use active scan on channels that was active | ||
141 | * in the past hour, even if they are marked as passive. | ||
140 | */ | 142 | */ |
141 | enum iwl_scan_flags { | 143 | enum iwl_scan_flags { |
142 | SCAN_FLAGS_PERIODIC_SCAN = BIT(0), | 144 | SCAN_FLAGS_PERIODIC_SCAN = BIT(0), |
@@ -144,6 +146,7 @@ enum iwl_scan_flags { | |||
144 | SCAN_FLAGS_DELAYED_SCAN_LOWBAND = BIT(2), | 146 | SCAN_FLAGS_DELAYED_SCAN_LOWBAND = BIT(2), |
145 | SCAN_FLAGS_DELAYED_SCAN_HIGHBAND = BIT(3), | 147 | SCAN_FLAGS_DELAYED_SCAN_HIGHBAND = BIT(3), |
146 | SCAN_FLAGS_FRAGMENTED_SCAN = BIT(4), | 148 | SCAN_FLAGS_FRAGMENTED_SCAN = BIT(4), |
149 | SCAN_FLAGS_PASSIVE2ACTIVE = BIT(5), | ||
147 | }; | 150 | }; |
148 | 151 | ||
149 | /** | 152 | /** |
@@ -178,7 +181,7 @@ enum iwl_scan_type { | |||
178 | * @quiet_time: in msecs, dwell this time for active scan on quiet channels | 181 | * @quiet_time: in msecs, dwell this time for active scan on quiet channels |
179 | * @quiet_plcp_th: quiet PLCP threshold (channel is quiet if less than | 182 | * @quiet_plcp_th: quiet PLCP threshold (channel is quiet if less than |
180 | * this number of packets were received (typically 1) | 183 | * this number of packets were received (typically 1) |
181 | * @passive2active: is auto switching from passive to active allowed (0 or 1) | 184 | * @passive2active: is auto switching from passive to active during scan allowed |
182 | * @rxchain_sel_flags: RXON_RX_CHAIN_* | 185 | * @rxchain_sel_flags: RXON_RX_CHAIN_* |
183 | * @max_out_time: in usecs, max out of serving channel time | 186 | * @max_out_time: in usecs, max out of serving channel time |
184 | * @suspend_time: how long to pause scan when returning to service channel: | 187 | * @suspend_time: how long to pause scan when returning to service channel: |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index 700cce731770..d606197bde8f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | |||
@@ -91,7 +91,6 @@ | |||
91 | * @TX_CMD_FLG_RESP_TO_DRV: zero this if the response should go only to FW | 91 | * @TX_CMD_FLG_RESP_TO_DRV: zero this if the response should go only to FW |
92 | * @TX_CMD_FLG_CCMP_AGG: this frame uses CCMP for aggregation acceleration | 92 | * @TX_CMD_FLG_CCMP_AGG: this frame uses CCMP for aggregation acceleration |
93 | * @TX_CMD_FLG_TKIP_MIC_DONE: FW already performed TKIP MIC calculation | 93 | * @TX_CMD_FLG_TKIP_MIC_DONE: FW already performed TKIP MIC calculation |
94 | * @TX_CMD_FLG_CTS_ONLY: send CTS only, no data after that | ||
95 | * @TX_CMD_FLG_DUR: disable duration overwriting used in PS-Poll Assoc-id | 94 | * @TX_CMD_FLG_DUR: disable duration overwriting used in PS-Poll Assoc-id |
96 | * @TX_CMD_FLG_FW_DROP: FW should mark frame to be dropped | 95 | * @TX_CMD_FLG_FW_DROP: FW should mark frame to be dropped |
97 | * @TX_CMD_FLG_EXEC_PAPD: execute PAPD | 96 | * @TX_CMD_FLG_EXEC_PAPD: execute PAPD |
@@ -120,7 +119,6 @@ enum iwl_tx_flags { | |||
120 | TX_CMD_FLG_RESP_TO_DRV = BIT(21), | 119 | TX_CMD_FLG_RESP_TO_DRV = BIT(21), |
121 | TX_CMD_FLG_CCMP_AGG = BIT(22), | 120 | TX_CMD_FLG_CCMP_AGG = BIT(22), |
122 | TX_CMD_FLG_TKIP_MIC_DONE = BIT(23), | 121 | TX_CMD_FLG_TKIP_MIC_DONE = BIT(23), |
123 | TX_CMD_FLG_CTS_ONLY = BIT(24), | ||
124 | TX_CMD_FLG_DUR = BIT(25), | 122 | TX_CMD_FLG_DUR = BIT(25), |
125 | TX_CMD_FLG_FW_DROP = BIT(26), | 123 | TX_CMD_FLG_FW_DROP = BIT(26), |
126 | TX_CMD_FLG_EXEC_PAPD = BIT(27), | 124 | TX_CMD_FLG_EXEC_PAPD = BIT(27), |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index cbfb3beae783..66264cc5a016 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -136,7 +136,7 @@ enum { | |||
136 | CALIB_RES_NOTIF_PHY_DB = 0x6b, | 136 | CALIB_RES_NOTIF_PHY_DB = 0x6b, |
137 | /* PHY_DB_CMD = 0x6c, */ | 137 | /* PHY_DB_CMD = 0x6c, */ |
138 | 138 | ||
139 | /* Power */ | 139 | /* Power - legacy power table command */ |
140 | POWER_TABLE_CMD = 0x77, | 140 | POWER_TABLE_CMD = 0x77, |
141 | 141 | ||
142 | /* Thermal Throttling*/ | 142 | /* Thermal Throttling*/ |
@@ -159,6 +159,7 @@ enum { | |||
159 | TX_ANT_CONFIGURATION_CMD = 0x98, | 159 | TX_ANT_CONFIGURATION_CMD = 0x98, |
160 | BT_CONFIG = 0x9b, | 160 | BT_CONFIG = 0x9b, |
161 | STATISTICS_NOTIFICATION = 0x9d, | 161 | STATISTICS_NOTIFICATION = 0x9d, |
162 | REDUCE_TX_POWER_CMD = 0x9f, | ||
162 | 163 | ||
163 | /* RF-KILL commands and notifications */ | 164 | /* RF-KILL commands and notifications */ |
164 | CARD_STATE_CMD = 0xa0, | 165 | CARD_STATE_CMD = 0xa0, |
@@ -166,6 +167,9 @@ enum { | |||
166 | 167 | ||
167 | MISSED_BEACONS_NOTIFICATION = 0xa2, | 168 | MISSED_BEACONS_NOTIFICATION = 0xa2, |
168 | 169 | ||
170 | /* Power - new power table command */ | ||
171 | MAC_PM_POWER_TABLE = 0xa9, | ||
172 | |||
169 | REPLY_RX_PHY_CMD = 0xc0, | 173 | REPLY_RX_PHY_CMD = 0xc0, |
170 | REPLY_RX_MPDU_CMD = 0xc1, | 174 | REPLY_RX_MPDU_CMD = 0xc1, |
171 | BA_NOTIF = 0xc5, | 175 | BA_NOTIF = 0xc5, |
@@ -223,6 +227,19 @@ struct iwl_tx_ant_cfg_cmd { | |||
223 | __le32 valid; | 227 | __le32 valid; |
224 | } __packed; | 228 | } __packed; |
225 | 229 | ||
230 | /** | ||
231 | * struct iwl_reduce_tx_power_cmd - TX power reduction command | ||
232 | * REDUCE_TX_POWER_CMD = 0x9f | ||
233 | * @flags: (reserved for future implementation) | ||
234 | * @mac_context_id: id of the mac ctx for which we are reducing TX power. | ||
235 | * @pwr_restriction: TX power restriction in dBms. | ||
236 | */ | ||
237 | struct iwl_reduce_tx_power_cmd { | ||
238 | u8 flags; | ||
239 | u8 mac_context_id; | ||
240 | __le16 pwr_restriction; | ||
241 | } __packed; /* TX_REDUCED_POWER_API_S_VER_1 */ | ||
242 | |||
226 | /* | 243 | /* |
227 | * Calibration control struct. | 244 | * Calibration control struct. |
228 | * Sent as part of the phy configuration command. | 245 | * Sent as part of the phy configuration command. |
@@ -482,71 +499,199 @@ enum iwl_time_event_type { | |||
482 | TE_MAX | 499 | TE_MAX |
483 | }; /* MAC_EVENT_TYPE_API_E_VER_1 */ | 500 | }; /* MAC_EVENT_TYPE_API_E_VER_1 */ |
484 | 501 | ||
502 | |||
503 | |||
504 | /* Time event - defines for command API v1 */ | ||
505 | |||
506 | /* | ||
507 | * @TE_V1_FRAG_NONE: fragmentation of the time event is NOT allowed. | ||
508 | * @TE_V1_FRAG_SINGLE: fragmentation of the time event is allowed, but only | ||
509 | * the first fragment is scheduled. | ||
510 | * @TE_V1_FRAG_DUAL: fragmentation of the time event is allowed, but only | ||
511 | * the first 2 fragments are scheduled. | ||
512 | * @TE_V1_FRAG_ENDLESS: fragmentation of the time event is allowed, and any | ||
513 | * number of fragments are valid. | ||
514 | * | ||
515 | * Other than the constant defined above, specifying a fragmentation value 'x' | ||
516 | * means that the event can be fragmented but only the first 'x' will be | ||
517 | * scheduled. | ||
518 | */ | ||
519 | enum { | ||
520 | TE_V1_FRAG_NONE = 0, | ||
521 | TE_V1_FRAG_SINGLE = 1, | ||
522 | TE_V1_FRAG_DUAL = 2, | ||
523 | TE_V1_FRAG_ENDLESS = 0xffffffff | ||
524 | }; | ||
525 | |||
526 | /* If a Time Event can be fragmented, this is the max number of fragments */ | ||
527 | #define TE_V1_FRAG_MAX_MSK 0x0fffffff | ||
528 | /* Repeat the time event endlessly (until removed) */ | ||
529 | #define TE_V1_REPEAT_ENDLESS 0xffffffff | ||
530 | /* If a Time Event has bounded repetitions, this is the maximal value */ | ||
531 | #define TE_V1_REPEAT_MAX_MSK_V1 0x0fffffff | ||
532 | |||
485 | /* Time Event dependencies: none, on another TE, or in a specific time */ | 533 | /* Time Event dependencies: none, on another TE, or in a specific time */ |
486 | enum { | 534 | enum { |
487 | TE_INDEPENDENT = 0, | 535 | TE_V1_INDEPENDENT = 0, |
488 | TE_DEP_OTHER = 1, | 536 | TE_V1_DEP_OTHER = BIT(0), |
489 | TE_DEP_TSF = 2, | 537 | TE_V1_DEP_TSF = BIT(1), |
490 | TE_EVENT_SOCIOPATHIC = 4, | 538 | TE_V1_EVENT_SOCIOPATHIC = BIT(2), |
491 | }; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ | 539 | }; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ |
540 | |||
492 | /* | 541 | /* |
542 | * @TE_V1_NOTIF_NONE: no notifications | ||
543 | * @TE_V1_NOTIF_HOST_EVENT_START: request/receive notification on event start | ||
544 | * @TE_V1_NOTIF_HOST_EVENT_END:request/receive notification on event end | ||
545 | * @TE_V1_NOTIF_INTERNAL_EVENT_START: internal FW use | ||
546 | * @TE_V1_NOTIF_INTERNAL_EVENT_END: internal FW use. | ||
547 | * @TE_V1_NOTIF_HOST_FRAG_START: request/receive notification on frag start | ||
548 | * @TE_V1_NOTIF_HOST_FRAG_END:request/receive notification on frag end | ||
549 | * @TE_V1_NOTIF_INTERNAL_FRAG_START: internal FW use. | ||
550 | * @TE_V1_NOTIF_INTERNAL_FRAG_END: internal FW use. | ||
551 | * | ||
493 | * Supported Time event notifications configuration. | 552 | * Supported Time event notifications configuration. |
494 | * A notification (both event and fragment) includes a status indicating weather | 553 | * A notification (both event and fragment) includes a status indicating weather |
495 | * the FW was able to schedule the event or not. For fragment start/end | 554 | * the FW was able to schedule the event or not. For fragment start/end |
496 | * notification the status is always success. There is no start/end fragment | 555 | * notification the status is always success. There is no start/end fragment |
497 | * notification for monolithic events. | 556 | * notification for monolithic events. |
498 | * | ||
499 | * @TE_NOTIF_NONE: no notifications | ||
500 | * @TE_NOTIF_HOST_EVENT_START: request/receive notification on event start | ||
501 | * @TE_NOTIF_HOST_EVENT_END:request/receive notification on event end | ||
502 | * @TE_NOTIF_INTERNAL_EVENT_START: internal FW use | ||
503 | * @TE_NOTIF_INTERNAL_EVENT_END: internal FW use. | ||
504 | * @TE_NOTIF_HOST_FRAG_START: request/receive notification on frag start | ||
505 | * @TE_NOTIF_HOST_FRAG_END:request/receive notification on frag end | ||
506 | * @TE_NOTIF_INTERNAL_FRAG_START: internal FW use. | ||
507 | * @TE_NOTIF_INTERNAL_FRAG_END: internal FW use. | ||
508 | */ | 557 | */ |
509 | enum { | 558 | enum { |
510 | TE_NOTIF_NONE = 0, | 559 | TE_V1_NOTIF_NONE = 0, |
511 | TE_NOTIF_HOST_EVENT_START = 0x1, | 560 | TE_V1_NOTIF_HOST_EVENT_START = BIT(0), |
512 | TE_NOTIF_HOST_EVENT_END = 0x2, | 561 | TE_V1_NOTIF_HOST_EVENT_END = BIT(1), |
513 | TE_NOTIF_INTERNAL_EVENT_START = 0x4, | 562 | TE_V1_NOTIF_INTERNAL_EVENT_START = BIT(2), |
514 | TE_NOTIF_INTERNAL_EVENT_END = 0x8, | 563 | TE_V1_NOTIF_INTERNAL_EVENT_END = BIT(3), |
515 | TE_NOTIF_HOST_FRAG_START = 0x10, | 564 | TE_V1_NOTIF_HOST_FRAG_START = BIT(4), |
516 | TE_NOTIF_HOST_FRAG_END = 0x20, | 565 | TE_V1_NOTIF_HOST_FRAG_END = BIT(5), |
517 | TE_NOTIF_INTERNAL_FRAG_START = 0x40, | 566 | TE_V1_NOTIF_INTERNAL_FRAG_START = BIT(6), |
518 | TE_NOTIF_INTERNAL_FRAG_END = 0x80 | 567 | TE_V1_NOTIF_INTERNAL_FRAG_END = BIT(7), |
519 | }; /* MAC_EVENT_ACTION_API_E_VER_2 */ | 568 | }; /* MAC_EVENT_ACTION_API_E_VER_2 */ |
520 | 569 | ||
570 | |||
571 | /** | ||
572 | * struct iwl_time_event_cmd_api_v1 - configuring Time Events | ||
573 | * with struct MAC_TIME_EVENT_DATA_API_S_VER_1 (see also | ||
574 | * with version 2. determined by IWL_UCODE_TLV_FLAGS) | ||
575 | * ( TIME_EVENT_CMD = 0x29 ) | ||
576 | * @id_and_color: ID and color of the relevant MAC | ||
577 | * @action: action to perform, one of FW_CTXT_ACTION_* | ||
578 | * @id: this field has two meanings, depending on the action: | ||
579 | * If the action is ADD, then it means the type of event to add. | ||
580 | * For all other actions it is the unique event ID assigned when the | ||
581 | * event was added by the FW. | ||
582 | * @apply_time: When to start the Time Event (in GP2) | ||
583 | * @max_delay: maximum delay to event's start (apply time), in TU | ||
584 | * @depends_on: the unique ID of the event we depend on (if any) | ||
585 | * @interval: interval between repetitions, in TU | ||
586 | * @interval_reciprocal: 2^32 / interval | ||
587 | * @duration: duration of event in TU | ||
588 | * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS | ||
589 | * @dep_policy: one of TE_V1_INDEPENDENT, TE_V1_DEP_OTHER, TE_V1_DEP_TSF | ||
590 | * and TE_V1_EVENT_SOCIOPATHIC | ||
591 | * @is_present: 0 or 1, are we present or absent during the Time Event | ||
592 | * @max_frags: maximal number of fragments the Time Event can be divided to | ||
593 | * @notify: notifications using TE_V1_NOTIF_* (whom to notify when) | ||
594 | */ | ||
595 | struct iwl_time_event_cmd_v1 { | ||
596 | /* COMMON_INDEX_HDR_API_S_VER_1 */ | ||
597 | __le32 id_and_color; | ||
598 | __le32 action; | ||
599 | __le32 id; | ||
600 | /* MAC_TIME_EVENT_DATA_API_S_VER_1 */ | ||
601 | __le32 apply_time; | ||
602 | __le32 max_delay; | ||
603 | __le32 dep_policy; | ||
604 | __le32 depends_on; | ||
605 | __le32 is_present; | ||
606 | __le32 max_frags; | ||
607 | __le32 interval; | ||
608 | __le32 interval_reciprocal; | ||
609 | __le32 duration; | ||
610 | __le32 repeat; | ||
611 | __le32 notify; | ||
612 | } __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_1 */ | ||
613 | |||
614 | |||
615 | /* Time event - defines for command API v2 */ | ||
616 | |||
521 | /* | 617 | /* |
522 | * @TE_FRAG_NONE: fragmentation of the time event is NOT allowed. | 618 | * @TE_V2_FRAG_NONE: fragmentation of the time event is NOT allowed. |
523 | * @TE_FRAG_SINGLE: fragmentation of the time event is allowed, but only | 619 | * @TE_V2_FRAG_SINGLE: fragmentation of the time event is allowed, but only |
524 | * the first fragment is scheduled. | 620 | * the first fragment is scheduled. |
525 | * @TE_FRAG_DUAL: fragmentation of the time event is allowed, but only | 621 | * @TE_V2_FRAG_DUAL: fragmentation of the time event is allowed, but only |
526 | * the first 2 fragments are scheduled. | 622 | * the first 2 fragments are scheduled. |
527 | * @TE_FRAG_ENDLESS: fragmentation of the time event is allowed, and any number | 623 | * @TE_V2_FRAG_ENDLESS: fragmentation of the time event is allowed, and any |
528 | * of fragments are valid. | 624 | * number of fragments are valid. |
529 | * | 625 | * |
530 | * Other than the constant defined above, specifying a fragmentation value 'x' | 626 | * Other than the constant defined above, specifying a fragmentation value 'x' |
531 | * means that the event can be fragmented but only the first 'x' will be | 627 | * means that the event can be fragmented but only the first 'x' will be |
532 | * scheduled. | 628 | * scheduled. |
533 | */ | 629 | */ |
534 | enum { | 630 | enum { |
535 | TE_FRAG_NONE = 0, | 631 | TE_V2_FRAG_NONE = 0, |
536 | TE_FRAG_SINGLE = 1, | 632 | TE_V2_FRAG_SINGLE = 1, |
537 | TE_FRAG_DUAL = 2, | 633 | TE_V2_FRAG_DUAL = 2, |
538 | TE_FRAG_ENDLESS = 0xffffffff | 634 | TE_V2_FRAG_MAX = 0xfe, |
635 | TE_V2_FRAG_ENDLESS = 0xff | ||
539 | }; | 636 | }; |
540 | 637 | ||
541 | /* Repeat the time event endlessly (until removed) */ | 638 | /* Repeat the time event endlessly (until removed) */ |
542 | #define TE_REPEAT_ENDLESS (0xffffffff) | 639 | #define TE_V2_REPEAT_ENDLESS 0xff |
543 | /* If a Time Event has bounded repetitions, this is the maximal value */ | 640 | /* If a Time Event has bounded repetitions, this is the maximal value */ |
544 | #define TE_REPEAT_MAX_MSK (0x0fffffff) | 641 | #define TE_V2_REPEAT_MAX 0xfe |
545 | /* If a Time Event can be fragmented, this is the max number of fragments */ | 642 | |
546 | #define TE_FRAG_MAX_MSK (0x0fffffff) | 643 | #define TE_V2_PLACEMENT_POS 12 |
644 | #define TE_V2_ABSENCE_POS 15 | ||
645 | |||
646 | /* Time event policy values (for time event cmd api v2) | ||
647 | * A notification (both event and fragment) includes a status indicating weather | ||
648 | * the FW was able to schedule the event or not. For fragment start/end | ||
649 | * notification the status is always success. There is no start/end fragment | ||
650 | * notification for monolithic events. | ||
651 | * | ||
652 | * @TE_V2_DEFAULT_POLICY: independent, social, present, unoticable | ||
653 | * @TE_V2_NOTIF_HOST_EVENT_START: request/receive notification on event start | ||
654 | * @TE_V2_NOTIF_HOST_EVENT_END:request/receive notification on event end | ||
655 | * @TE_V2_NOTIF_INTERNAL_EVENT_START: internal FW use | ||
656 | * @TE_V2_NOTIF_INTERNAL_EVENT_END: internal FW use. | ||
657 | * @TE_V2_NOTIF_HOST_FRAG_START: request/receive notification on frag start | ||
658 | * @TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end | ||
659 | * @TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use. | ||
660 | * @TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use. | ||
661 | * @TE_V2_DEP_OTHER: depends on another time event | ||
662 | * @TE_V2_DEP_TSF: depends on a specific time | ||
663 | * @TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC | ||
664 | * @TE_V2_ABSENCE: are we present or absent during the Time Event. | ||
665 | */ | ||
666 | enum { | ||
667 | TE_V2_DEFAULT_POLICY = 0x0, | ||
668 | |||
669 | /* notifications (event start/stop, fragment start/stop) */ | ||
670 | TE_V2_NOTIF_HOST_EVENT_START = BIT(0), | ||
671 | TE_V2_NOTIF_HOST_EVENT_END = BIT(1), | ||
672 | TE_V2_NOTIF_INTERNAL_EVENT_START = BIT(2), | ||
673 | TE_V2_NOTIF_INTERNAL_EVENT_END = BIT(3), | ||
674 | |||
675 | TE_V2_NOTIF_HOST_FRAG_START = BIT(4), | ||
676 | TE_V2_NOTIF_HOST_FRAG_END = BIT(5), | ||
677 | TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6), | ||
678 | TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7), | ||
679 | |||
680 | TE_V2_NOTIF_MSK = 0xff, | ||
681 | |||
682 | /* placement characteristics */ | ||
683 | TE_V2_DEP_OTHER = BIT(TE_V2_PLACEMENT_POS), | ||
684 | TE_V2_DEP_TSF = BIT(TE_V2_PLACEMENT_POS + 1), | ||
685 | TE_V2_EVENT_SOCIOPATHIC = BIT(TE_V2_PLACEMENT_POS + 2), | ||
686 | |||
687 | /* are we present or absent during the Time Event. */ | ||
688 | TE_V2_ABSENCE = BIT(TE_V2_ABSENCE_POS), | ||
689 | }; | ||
547 | 690 | ||
548 | /** | 691 | /** |
549 | * struct iwl_time_event_cmd - configuring Time Events | 692 | * struct iwl_time_event_cmd_api_v2 - configuring Time Events |
693 | * with struct MAC_TIME_EVENT_DATA_API_S_VER_2 (see also | ||
694 | * with version 1. determined by IWL_UCODE_TLV_FLAGS) | ||
550 | * ( TIME_EVENT_CMD = 0x29 ) | 695 | * ( TIME_EVENT_CMD = 0x29 ) |
551 | * @id_and_color: ID and color of the relevant MAC | 696 | * @id_and_color: ID and color of the relevant MAC |
552 | * @action: action to perform, one of FW_CTXT_ACTION_* | 697 | * @action: action to perform, one of FW_CTXT_ACTION_* |
@@ -558,32 +703,30 @@ enum { | |||
558 | * @max_delay: maximum delay to event's start (apply time), in TU | 703 | * @max_delay: maximum delay to event's start (apply time), in TU |
559 | * @depends_on: the unique ID of the event we depend on (if any) | 704 | * @depends_on: the unique ID of the event we depend on (if any) |
560 | * @interval: interval between repetitions, in TU | 705 | * @interval: interval between repetitions, in TU |
561 | * @interval_reciprocal: 2^32 / interval | ||
562 | * @duration: duration of event in TU | 706 | * @duration: duration of event in TU |
563 | * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS | 707 | * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS |
564 | * @dep_policy: one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF | ||
565 | * @is_present: 0 or 1, are we present or absent during the Time Event | ||
566 | * @max_frags: maximal number of fragments the Time Event can be divided to | 708 | * @max_frags: maximal number of fragments the Time Event can be divided to |
567 | * @notify: notifications using TE_NOTIF_* (whom to notify when) | 709 | * @policy: defines whether uCode shall notify the host or other uCode modules |
710 | * on event and/or fragment start and/or end | ||
711 | * using one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF | ||
712 | * TE_EVENT_SOCIOPATHIC | ||
713 | * using TE_ABSENCE and using TE_NOTIF_* | ||
568 | */ | 714 | */ |
569 | struct iwl_time_event_cmd { | 715 | struct iwl_time_event_cmd_v2 { |
570 | /* COMMON_INDEX_HDR_API_S_VER_1 */ | 716 | /* COMMON_INDEX_HDR_API_S_VER_1 */ |
571 | __le32 id_and_color; | 717 | __le32 id_and_color; |
572 | __le32 action; | 718 | __le32 action; |
573 | __le32 id; | 719 | __le32 id; |
574 | /* MAC_TIME_EVENT_DATA_API_S_VER_1 */ | 720 | /* MAC_TIME_EVENT_DATA_API_S_VER_2 */ |
575 | __le32 apply_time; | 721 | __le32 apply_time; |
576 | __le32 max_delay; | 722 | __le32 max_delay; |
577 | __le32 dep_policy; | ||
578 | __le32 depends_on; | 723 | __le32 depends_on; |
579 | __le32 is_present; | ||
580 | __le32 max_frags; | ||
581 | __le32 interval; | 724 | __le32 interval; |
582 | __le32 interval_reciprocal; | ||
583 | __le32 duration; | 725 | __le32 duration; |
584 | __le32 repeat; | 726 | u8 repeat; |
585 | __le32 notify; | 727 | u8 max_frags; |
586 | } __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_1 */ | 728 | __le16 policy; |
729 | } __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_2 */ | ||
587 | 730 | ||
588 | /** | 731 | /** |
589 | * struct iwl_time_event_resp - response structure to iwl_time_event_cmd | 732 | * struct iwl_time_event_resp - response structure to iwl_time_event_cmd |
@@ -765,6 +908,14 @@ struct iwl_phy_context_cmd { | |||
765 | } __packed; /* PHY_CONTEXT_CMD_API_VER_1 */ | 908 | } __packed; /* PHY_CONTEXT_CMD_API_VER_1 */ |
766 | 909 | ||
767 | #define IWL_RX_INFO_PHY_CNT 8 | 910 | #define IWL_RX_INFO_PHY_CNT 8 |
911 | #define IWL_RX_INFO_ENERGY_ANT_ABC_IDX 1 | ||
912 | #define IWL_RX_INFO_ENERGY_ANT_A_MSK 0x000000ff | ||
913 | #define IWL_RX_INFO_ENERGY_ANT_B_MSK 0x0000ff00 | ||
914 | #define IWL_RX_INFO_ENERGY_ANT_C_MSK 0x00ff0000 | ||
915 | #define IWL_RX_INFO_ENERGY_ANT_A_POS 0 | ||
916 | #define IWL_RX_INFO_ENERGY_ANT_B_POS 8 | ||
917 | #define IWL_RX_INFO_ENERGY_ANT_C_POS 16 | ||
918 | |||
768 | #define IWL_RX_INFO_AGC_IDX 1 | 919 | #define IWL_RX_INFO_AGC_IDX 1 |
769 | #define IWL_RX_INFO_RSSI_AB_IDX 2 | 920 | #define IWL_RX_INFO_RSSI_AB_IDX 2 |
770 | #define IWL_OFDM_AGC_A_MSK 0x0000007f | 921 | #define IWL_OFDM_AGC_A_MSK 0x0000007f |
@@ -1170,7 +1321,7 @@ struct mvm_statistics_general { | |||
1170 | struct mvm_statistics_general_common common; | 1321 | struct mvm_statistics_general_common common; |
1171 | __le32 beacon_filtered; | 1322 | __le32 beacon_filtered; |
1172 | __le32 missed_beacons; | 1323 | __le32 missed_beacons; |
1173 | __s8 beacon_filter_everage_energy; | 1324 | __s8 beacon_filter_average_energy; |
1174 | __s8 beacon_filter_reason; | 1325 | __s8 beacon_filter_reason; |
1175 | __s8 beacon_filter_current_energy; | 1326 | __s8 beacon_filter_current_energy; |
1176 | __s8 beacon_filter_reserved; | 1327 | __s8 beacon_filter_reserved; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index cd7c0032cc58..c76299a3a1e0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -78,22 +78,6 @@ | |||
78 | 78 | ||
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 */ | ||
82 | static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 }; | ||
83 | static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 }; | ||
84 | |||
85 | struct iwl_calib_default_data { | ||
86 | u16 size; | ||
87 | void *data; | ||
88 | }; | ||
89 | |||
90 | #define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf} | ||
91 | |||
92 | static const struct iwl_calib_default_data wkp_calib_default_data[12] = { | ||
93 | [9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew), | ||
94 | [11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew), | ||
95 | }; | ||
96 | |||
97 | struct iwl_mvm_alive_data { | 81 | struct iwl_mvm_alive_data { |
98 | bool valid; | 82 | bool valid; |
99 | u32 scd_base_addr; | 83 | u32 scd_base_addr; |
@@ -248,40 +232,6 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) | |||
248 | sizeof(phy_cfg_cmd), &phy_cfg_cmd); | 232 | sizeof(phy_cfg_cmd), &phy_cfg_cmd); |
249 | } | 233 | } |
250 | 234 | ||
251 | static int iwl_set_default_calibrations(struct iwl_mvm *mvm) | ||
252 | { | ||
253 | u8 cmd_raw[16]; /* holds the variable size commands */ | ||
254 | struct iwl_set_calib_default_cmd *cmd = | ||
255 | (struct iwl_set_calib_default_cmd *)cmd_raw; | ||
256 | int ret, i; | ||
257 | |||
258 | /* Setting default values for calibrations we don't run */ | ||
259 | for (i = 0; i < ARRAY_SIZE(wkp_calib_default_data); i++) { | ||
260 | u16 cmd_len; | ||
261 | |||
262 | if (wkp_calib_default_data[i].size == 0) | ||
263 | continue; | ||
264 | |||
265 | memset(cmd_raw, 0, sizeof(cmd_raw)); | ||
266 | cmd_len = wkp_calib_default_data[i].size + sizeof(cmd); | ||
267 | cmd->calib_index = cpu_to_le16(i); | ||
268 | cmd->length = cpu_to_le16(wkp_calib_default_data[i].size); | ||
269 | if (WARN_ONCE(cmd_len > sizeof(cmd_raw), | ||
270 | "Need to enlarge cmd_raw to %d\n", cmd_len)) | ||
271 | break; | ||
272 | memcpy(cmd->data, wkp_calib_default_data[i].data, | ||
273 | wkp_calib_default_data[i].size); | ||
274 | ret = iwl_mvm_send_cmd_pdu(mvm, SET_CALIB_DEFAULT_CMD, 0, | ||
275 | sizeof(*cmd) + | ||
276 | wkp_calib_default_data[i].size, | ||
277 | cmd); | ||
278 | if (ret) | ||
279 | return ret; | ||
280 | } | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | 235 | int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) |
286 | { | 236 | { |
287 | struct iwl_notification_wait calib_wait; | 237 | struct iwl_notification_wait calib_wait; |
@@ -342,11 +292,6 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
342 | if (ret) | 292 | if (ret) |
343 | goto error; | 293 | goto error; |
344 | 294 | ||
345 | /* need to set default values */ | ||
346 | ret = iwl_set_default_calibrations(mvm); | ||
347 | if (ret) | ||
348 | goto error; | ||
349 | |||
350 | /* | 295 | /* |
351 | * Send phy configurations command to init uCode | 296 | * Send phy configurations command to init uCode |
352 | * to start the 16.0 uCode init image internal calibrations. | 297 | * to start the 16.0 uCode init image internal calibrations. |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 94aae9c8562c..5fe23a5ea9b6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -264,7 +264,8 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
264 | return 0; | 264 | return 0; |
265 | 265 | ||
266 | /* Therefore, in recovery, we can't get here */ | 266 | /* Therefore, in recovery, we can't get here */ |
267 | WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)); | 267 | if (WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) |
268 | return -EBUSY; | ||
268 | 269 | ||
269 | mvmvif->id = find_first_bit(data.available_mac_ids, | 270 | mvmvif->id = find_first_bit(data.available_mac_ids, |
270 | NUM_MAC_INDEX_DRIVER); | 271 | NUM_MAC_INDEX_DRIVER); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index f19baf0dea6b..9833cdf6177c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -153,7 +153,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
153 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | | 153 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | |
154 | IEEE80211_HW_AMPDU_AGGREGATION | | 154 | IEEE80211_HW_AMPDU_AGGREGATION | |
155 | IEEE80211_HW_TIMING_BEACON_ONLY | | 155 | IEEE80211_HW_TIMING_BEACON_ONLY | |
156 | IEEE80211_HW_CONNECTION_MONITOR; | 156 | IEEE80211_HW_CONNECTION_MONITOR | |
157 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | | ||
158 | IEEE80211_HW_SUPPORTS_STATIC_SMPS | | ||
159 | IEEE80211_HW_SUPPORTS_UAPSD; | ||
157 | 160 | ||
158 | hw->queues = IWL_MVM_FIRST_AGG_QUEUE; | 161 | hw->queues = IWL_MVM_FIRST_AGG_QUEUE; |
159 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; | 162 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; |
@@ -188,6 +191,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
188 | 191 | ||
189 | hw->wiphy->max_remain_on_channel_duration = 10000; | 192 | hw->wiphy->max_remain_on_channel_duration = 10000; |
190 | hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; | 193 | hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; |
194 | hw->uapsd_queues = IWL_UAPSD_AC_INFO; | ||
195 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; | ||
191 | 196 | ||
192 | /* Extract MAC address */ | 197 | /* Extract MAC address */ |
193 | memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN); | 198 | memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN); |
@@ -506,7 +511,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
506 | 511 | ||
507 | mutex_lock(&mvm->mutex); | 512 | mutex_lock(&mvm->mutex); |
508 | 513 | ||
509 | /* Allocate resources for the MAC context, and add it the the fw */ | 514 | /* Allocate resources for the MAC context, and add it to the fw */ |
510 | ret = iwl_mvm_mac_ctxt_init(mvm, vif); | 515 | ret = iwl_mvm_mac_ctxt_init(mvm, vif); |
511 | if (ret) | 516 | if (ret) |
512 | goto out_unlock; | 517 | goto out_unlock; |
@@ -552,6 +557,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
552 | goto out_release; | 557 | goto out_release; |
553 | } | 558 | } |
554 | 559 | ||
560 | iwl_mvm_vif_dbgfs_register(mvm, vif); | ||
555 | goto out_unlock; | 561 | goto out_unlock; |
556 | } | 562 | } |
557 | 563 | ||
@@ -566,16 +572,18 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
566 | iwl_mvm_power_update_mode(mvm, vif); | 572 | iwl_mvm_power_update_mode(mvm, vif); |
567 | 573 | ||
568 | /* beacon filtering */ | 574 | /* beacon filtering */ |
575 | ret = iwl_mvm_disable_beacon_filter(mvm, vif); | ||
576 | if (ret) | ||
577 | goto out_remove_mac; | ||
578 | |||
569 | if (!mvm->bf_allowed_vif && | 579 | if (!mvm->bf_allowed_vif && |
570 | vif->type == NL80211_IFTYPE_STATION && !vif->p2p){ | 580 | vif->type == NL80211_IFTYPE_STATION && !vif->p2p && |
581 | mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED){ | ||
571 | mvm->bf_allowed_vif = mvmvif; | 582 | mvm->bf_allowed_vif = mvmvif; |
572 | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; | 583 | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | |
584 | IEEE80211_VIF_SUPPORTS_CQM_RSSI; | ||
573 | } | 585 | } |
574 | 586 | ||
575 | ret = iwl_mvm_disable_beacon_filter(mvm, vif); | ||
576 | if (ret) | ||
577 | goto out_release; | ||
578 | |||
579 | /* | 587 | /* |
580 | * P2P_DEVICE interface does not have a channel context assigned to it, | 588 | * P2P_DEVICE interface does not have a channel context assigned to it, |
581 | * so a dedicated PHY context is allocated to it and the corresponding | 589 | * so a dedicated PHY context is allocated to it and the corresponding |
@@ -586,7 +594,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
586 | mvmvif->phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); | 594 | mvmvif->phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); |
587 | if (!mvmvif->phy_ctxt) { | 595 | if (!mvmvif->phy_ctxt) { |
588 | ret = -ENOSPC; | 596 | ret = -ENOSPC; |
589 | goto out_remove_mac; | 597 | goto out_free_bf; |
590 | } | 598 | } |
591 | 599 | ||
592 | iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); | 600 | iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); |
@@ -610,6 +618,12 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
610 | iwl_mvm_binding_remove_vif(mvm, vif); | 618 | iwl_mvm_binding_remove_vif(mvm, vif); |
611 | out_unref_phy: | 619 | out_unref_phy: |
612 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); | 620 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); |
621 | out_free_bf: | ||
622 | if (mvm->bf_allowed_vif == mvmvif) { | ||
623 | mvm->bf_allowed_vif = NULL; | ||
624 | vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER | | ||
625 | IEEE80211_VIF_SUPPORTS_CQM_RSSI); | ||
626 | } | ||
613 | out_remove_mac: | 627 | out_remove_mac: |
614 | mvmvif->phy_ctxt = NULL; | 628 | mvmvif->phy_ctxt = NULL; |
615 | iwl_mvm_mac_ctxt_remove(mvm, vif); | 629 | iwl_mvm_mac_ctxt_remove(mvm, vif); |
@@ -674,7 +688,8 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | |||
674 | 688 | ||
675 | if (mvm->bf_allowed_vif == mvmvif) { | 689 | if (mvm->bf_allowed_vif == mvmvif) { |
676 | mvm->bf_allowed_vif = NULL; | 690 | mvm->bf_allowed_vif = NULL; |
677 | vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; | 691 | vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER | |
692 | IEEE80211_VIF_SUPPORTS_CQM_RSSI); | ||
678 | } | 693 | } |
679 | 694 | ||
680 | iwl_mvm_vif_dbgfs_clean(mvm, vif); | 695 | iwl_mvm_vif_dbgfs_clean(mvm, vif); |
@@ -719,6 +734,20 @@ out_release: | |||
719 | mutex_unlock(&mvm->mutex); | 734 | mutex_unlock(&mvm->mutex); |
720 | } | 735 | } |
721 | 736 | ||
737 | static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
738 | s8 tx_power) | ||
739 | { | ||
740 | /* FW is in charge of regulatory enforcement */ | ||
741 | struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = { | ||
742 | .mac_context_id = iwl_mvm_vif_from_mac80211(vif)->id, | ||
743 | .pwr_restriction = cpu_to_le16(tx_power), | ||
744 | }; | ||
745 | |||
746 | return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, CMD_SYNC, | ||
747 | sizeof(reduce_txpwr_cmd), | ||
748 | &reduce_txpwr_cmd); | ||
749 | } | ||
750 | |||
722 | static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed) | 751 | static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed) |
723 | { | 752 | { |
724 | return 0; | 753 | return 0; |
@@ -766,7 +795,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
766 | IWL_ERR(mvm, "failed to update quotas\n"); | 795 | IWL_ERR(mvm, "failed to update quotas\n"); |
767 | return; | 796 | return; |
768 | } | 797 | } |
769 | iwl_mvm_bt_coex_vif_assoc(mvm, vif); | ||
770 | iwl_mvm_configure_mcast_filter(mvm, vif); | 798 | iwl_mvm_configure_mcast_filter(mvm, vif); |
771 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | 799 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { |
772 | /* remove AP station now that the MAC is unassoc */ | 800 | /* remove AP station now that the MAC is unassoc */ |
@@ -779,9 +807,19 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
779 | if (ret) | 807 | if (ret) |
780 | IWL_ERR(mvm, "failed to update quotas\n"); | 808 | IWL_ERR(mvm, "failed to update quotas\n"); |
781 | } | 809 | } |
782 | ret = iwl_mvm_power_update_mode(mvm, vif); | 810 | |
783 | if (ret) | 811 | /* reset rssi values */ |
784 | IWL_ERR(mvm, "failed to update power mode\n"); | 812 | mvmvif->bf_data.ave_beacon_signal = 0; |
813 | |||
814 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD)) { | ||
815 | /* Workaround for FW bug, otherwise FW disables device | ||
816 | * power save upon disassociation | ||
817 | */ | ||
818 | ret = iwl_mvm_power_update_mode(mvm, vif); | ||
819 | if (ret) | ||
820 | IWL_ERR(mvm, "failed to update power mode\n"); | ||
821 | } | ||
822 | iwl_mvm_bt_coex_vif_assoc(mvm, vif); | ||
785 | } else if (changes & BSS_CHANGED_BEACON_INFO) { | 823 | } else if (changes & BSS_CHANGED_BEACON_INFO) { |
786 | /* | 824 | /* |
787 | * We received a beacon _after_ association so | 825 | * We received a beacon _after_ association so |
@@ -789,11 +827,25 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
789 | */ | 827 | */ |
790 | iwl_mvm_remove_time_event(mvm, mvmvif, | 828 | iwl_mvm_remove_time_event(mvm, mvmvif, |
791 | &mvmvif->time_event_data); | 829 | &mvmvif->time_event_data); |
792 | } else if (changes & BSS_CHANGED_PS) { | 830 | } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_QOS)) { |
793 | ret = iwl_mvm_power_update_mode(mvm, vif); | 831 | ret = iwl_mvm_power_update_mode(mvm, vif); |
794 | if (ret) | 832 | if (ret) |
795 | IWL_ERR(mvm, "failed to update power mode\n"); | 833 | IWL_ERR(mvm, "failed to update power mode\n"); |
796 | } | 834 | } |
835 | if (changes & BSS_CHANGED_TXPOWER) { | ||
836 | IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n", | ||
837 | bss_conf->txpower); | ||
838 | iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower); | ||
839 | } | ||
840 | |||
841 | if (changes & BSS_CHANGED_CQM) { | ||
842 | IWL_DEBUG_MAC80211(mvm, "cqm info_changed"); | ||
843 | /* reset cqm events tracking */ | ||
844 | mvmvif->bf_data.last_cqm_event = 0; | ||
845 | ret = iwl_mvm_update_beacon_filter(mvm, vif); | ||
846 | if (ret) | ||
847 | IWL_ERR(mvm, "failed to update CQM thresholds\n"); | ||
848 | } | ||
797 | } | 849 | } |
798 | 850 | ||
799 | static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | 851 | static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 420e82d379d9..b0389279cc1e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -76,6 +76,7 @@ | |||
76 | #include "iwl-trans.h" | 76 | #include "iwl-trans.h" |
77 | #include "sta.h" | 77 | #include "sta.h" |
78 | #include "fw-api.h" | 78 | #include "fw-api.h" |
79 | #include "constants.h" | ||
79 | 80 | ||
80 | #define IWL_INVALID_MAC80211_QUEUE 0xff | 81 | #define IWL_INVALID_MAC80211_QUEUE 0xff |
81 | #define IWL_MVM_MAX_ADDRESSES 5 | 82 | #define IWL_MVM_MAX_ADDRESSES 5 |
@@ -91,6 +92,9 @@ enum iwl_mvm_tx_fifo { | |||
91 | }; | 92 | }; |
92 | 93 | ||
93 | extern struct ieee80211_ops iwl_mvm_hw_ops; | 94 | extern struct ieee80211_ops iwl_mvm_hw_ops; |
95 | extern const struct iwl_mvm_power_ops pm_legacy_ops; | ||
96 | extern const struct iwl_mvm_power_ops pm_mac_ops; | ||
97 | |||
94 | /** | 98 | /** |
95 | * struct iwl_mvm_mod_params - module parameters for iwlmvm | 99 | * struct iwl_mvm_mod_params - module parameters for iwlmvm |
96 | * @init_dbg: if true, then the NIC won't be stopped if the INIT fw asserted. | 100 | * @init_dbg: if true, then the NIC won't be stopped if the INIT fw asserted. |
@@ -149,6 +153,22 @@ enum iwl_power_scheme { | |||
149 | }; | 153 | }; |
150 | 154 | ||
151 | #define IWL_CONN_MAX_LISTEN_INTERVAL 70 | 155 | #define IWL_CONN_MAX_LISTEN_INTERVAL 70 |
156 | #define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ | ||
157 | IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ | ||
158 | IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ | ||
159 | IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) | ||
160 | #define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2 | ||
161 | |||
162 | struct iwl_mvm_power_ops { | ||
163 | int (*power_update_mode)(struct iwl_mvm *mvm, | ||
164 | struct ieee80211_vif *vif); | ||
165 | int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
166 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
167 | int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
168 | char *buf, int bufsz); | ||
169 | #endif | ||
170 | }; | ||
171 | |||
152 | 172 | ||
153 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 173 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
154 | enum iwl_dbgfs_pm_mask { | 174 | enum iwl_dbgfs_pm_mask { |
@@ -160,10 +180,11 @@ enum iwl_dbgfs_pm_mask { | |||
160 | MVM_DEBUGFS_PM_DISABLE_POWER_OFF = BIT(5), | 180 | MVM_DEBUGFS_PM_DISABLE_POWER_OFF = BIT(5), |
161 | MVM_DEBUGFS_PM_LPRX_ENA = BIT(6), | 181 | MVM_DEBUGFS_PM_LPRX_ENA = BIT(6), |
162 | MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7), | 182 | MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7), |
183 | MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8), | ||
163 | }; | 184 | }; |
164 | 185 | ||
165 | struct iwl_dbgfs_pm { | 186 | struct iwl_dbgfs_pm { |
166 | u8 keep_alive_seconds; | 187 | u16 keep_alive_seconds; |
167 | u32 rx_data_timeout; | 188 | u32 rx_data_timeout; |
168 | u32 tx_data_timeout; | 189 | u32 tx_data_timeout; |
169 | bool skip_over_dtim; | 190 | bool skip_over_dtim; |
@@ -171,6 +192,7 @@ struct iwl_dbgfs_pm { | |||
171 | bool disable_power_off; | 192 | bool disable_power_off; |
172 | bool lprx_ena; | 193 | bool lprx_ena; |
173 | u32 lprx_rssi_threshold; | 194 | u32 lprx_rssi_threshold; |
195 | bool snooze_ena; | ||
174 | int mask; | 196 | int mask; |
175 | }; | 197 | }; |
176 | 198 | ||
@@ -180,24 +202,28 @@ enum iwl_dbgfs_bf_mask { | |||
180 | MVM_DEBUGFS_BF_ENERGY_DELTA = BIT(0), | 202 | MVM_DEBUGFS_BF_ENERGY_DELTA = BIT(0), |
181 | MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA = BIT(1), | 203 | MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA = BIT(1), |
182 | MVM_DEBUGFS_BF_ROAMING_STATE = BIT(2), | 204 | MVM_DEBUGFS_BF_ROAMING_STATE = BIT(2), |
183 | MVM_DEBUGFS_BF_TEMPERATURE_DELTA = BIT(3), | 205 | MVM_DEBUGFS_BF_TEMP_THRESHOLD = BIT(3), |
184 | MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER = BIT(4), | 206 | MVM_DEBUGFS_BF_TEMP_FAST_FILTER = BIT(4), |
185 | MVM_DEBUGFS_BF_DEBUG_FLAG = BIT(5), | 207 | MVM_DEBUGFS_BF_TEMP_SLOW_FILTER = BIT(5), |
186 | MVM_DEBUGFS_BF_ESCAPE_TIMER = BIT(6), | 208 | MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER = BIT(6), |
187 | MVM_DEBUGFS_BA_ESCAPE_TIMER = BIT(7), | 209 | MVM_DEBUGFS_BF_DEBUG_FLAG = BIT(7), |
188 | MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT = BIT(8), | 210 | MVM_DEBUGFS_BF_ESCAPE_TIMER = BIT(8), |
211 | MVM_DEBUGFS_BA_ESCAPE_TIMER = BIT(9), | ||
212 | MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT = BIT(10), | ||
189 | }; | 213 | }; |
190 | 214 | ||
191 | struct iwl_dbgfs_bf { | 215 | struct iwl_dbgfs_bf { |
192 | u8 bf_energy_delta; | 216 | u32 bf_energy_delta; |
193 | u8 bf_roaming_energy_delta; | 217 | u32 bf_roaming_energy_delta; |
194 | u8 bf_roaming_state; | 218 | u32 bf_roaming_state; |
195 | u8 bf_temperature_delta; | 219 | u32 bf_temp_threshold; |
196 | u8 bf_enable_beacon_filter; | 220 | u32 bf_temp_fast_filter; |
197 | u8 bf_debug_flag; | 221 | u32 bf_temp_slow_filter; |
222 | u32 bf_enable_beacon_filter; | ||
223 | u32 bf_debug_flag; | ||
198 | u32 bf_escape_timer; | 224 | u32 bf_escape_timer; |
199 | u32 ba_escape_timer; | 225 | u32 ba_escape_timer; |
200 | u8 ba_enable_beacon_abort; | 226 | u32 ba_enable_beacon_abort; |
201 | int mask; | 227 | int mask; |
202 | }; | 228 | }; |
203 | #endif | 229 | #endif |
@@ -209,6 +235,21 @@ enum iwl_mvm_smps_type_request { | |||
209 | }; | 235 | }; |
210 | 236 | ||
211 | /** | 237 | /** |
238 | * struct iwl_mvm_vif_bf_data - beacon filtering related data | ||
239 | * @bf_enabled: indicates if beacon filtering is enabled | ||
240 | * @ba_enabled: indicated if beacon abort is enabled | ||
241 | * @last_beacon_signal: last beacon rssi signal in dbm | ||
242 | * @ave_beacon_signal: average beacon signal | ||
243 | * @last_cqm_event: rssi of the last cqm event | ||
244 | */ | ||
245 | struct iwl_mvm_vif_bf_data { | ||
246 | bool bf_enabled; | ||
247 | bool ba_enabled; | ||
248 | s8 ave_beacon_signal; | ||
249 | s8 last_cqm_event; | ||
250 | }; | ||
251 | |||
252 | /** | ||
212 | * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context | 253 | * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context |
213 | * @id: between 0 and 3 | 254 | * @id: between 0 and 3 |
214 | * @color: to solve races upon MAC addition and removal | 255 | * @color: to solve races upon MAC addition and removal |
@@ -233,8 +274,7 @@ struct iwl_mvm_vif { | |||
233 | bool uploaded; | 274 | bool uploaded; |
234 | bool ap_active; | 275 | bool ap_active; |
235 | bool monitor_active; | 276 | bool monitor_active; |
236 | /* indicate whether beacon filtering is enabled */ | 277 | struct iwl_mvm_vif_bf_data bf_data; |
237 | bool bf_enabled; | ||
238 | 278 | ||
239 | u32 ap_beacon_time; | 279 | u32 ap_beacon_time; |
240 | 280 | ||
@@ -268,7 +308,7 @@ struct iwl_mvm_vif { | |||
268 | 308 | ||
269 | #if IS_ENABLED(CONFIG_IPV6) | 309 | #if IS_ENABLED(CONFIG_IPV6) |
270 | /* IPv6 addresses for WoWLAN */ | 310 | /* IPv6 addresses for WoWLAN */ |
271 | struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS]; | 311 | struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX]; |
272 | int num_target_ipv6_addrs; | 312 | int num_target_ipv6_addrs; |
273 | #endif | 313 | #endif |
274 | #endif | 314 | #endif |
@@ -402,6 +442,8 @@ struct iwl_mvm { | |||
402 | 442 | ||
403 | struct iwl_notif_wait_data notif_wait; | 443 | struct iwl_notif_wait_data notif_wait; |
404 | 444 | ||
445 | struct mvm_statistics_rx rx_stats; | ||
446 | |||
405 | unsigned long transport_queue_stop; | 447 | unsigned long transport_queue_stop; |
406 | u8 queue_to_mac80211[IWL_MAX_HW_QUEUES]; | 448 | u8 queue_to_mac80211[IWL_MAX_HW_QUEUES]; |
407 | atomic_t queue_stop_count[IWL_MAX_HW_QUEUES]; | 449 | atomic_t queue_stop_count[IWL_MAX_HW_QUEUES]; |
@@ -459,6 +501,9 @@ struct iwl_mvm { | |||
459 | */ | 501 | */ |
460 | u8 vif_count; | 502 | u8 vif_count; |
461 | 503 | ||
504 | /* -1 for always, 0 for never, >0 for that many times */ | ||
505 | s8 restart_fw; | ||
506 | |||
462 | struct led_classdev led; | 507 | struct led_classdev led; |
463 | 508 | ||
464 | struct ieee80211_vif *p2p_device_vif; | 509 | struct ieee80211_vif *p2p_device_vif; |
@@ -482,6 +527,8 @@ struct iwl_mvm { | |||
482 | /* Thermal Throttling and CTkill */ | 527 | /* Thermal Throttling and CTkill */ |
483 | struct iwl_mvm_tt_mgmt thermal_throttle; | 528 | struct iwl_mvm_tt_mgmt thermal_throttle; |
484 | s32 temperature; /* Celsius */ | 529 | s32 temperature; /* Celsius */ |
530 | |||
531 | const struct iwl_mvm_power_ops *pm_ops; | ||
485 | }; | 532 | }; |
486 | 533 | ||
487 | /* Extract MVM priv from op_mode and _hw */ | 534 | /* Extract MVM priv from op_mode and _hw */ |
@@ -525,6 +572,7 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags, | |||
525 | enum ieee80211_band band); | 572 | enum ieee80211_band band); |
526 | u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); | 573 | u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); |
527 | void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); | 574 | void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); |
575 | void iwl_mvm_dump_sram(struct iwl_mvm *mvm); | ||
528 | u8 first_antenna(u8 mask); | 576 | u8 first_antenna(u8 mask); |
529 | u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); | 577 | u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); |
530 | 578 | ||
@@ -660,10 +708,26 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | |||
660 | u8 flags, bool init); | 708 | u8 flags, bool init); |
661 | 709 | ||
662 | /* power managment */ | 710 | /* power managment */ |
663 | int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 711 | static inline int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, |
664 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 712 | struct ieee80211_vif *vif) |
665 | void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 713 | { |
666 | struct iwl_powertable_cmd *cmd); | 714 | return mvm->pm_ops->power_update_mode(mvm, vif); |
715 | } | ||
716 | |||
717 | static inline int iwl_mvm_power_disable(struct iwl_mvm *mvm, | ||
718 | struct ieee80211_vif *vif) | ||
719 | { | ||
720 | return mvm->pm_ops->power_disable(mvm, vif); | ||
721 | } | ||
722 | |||
723 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
724 | static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm, | ||
725 | struct ieee80211_vif *vif, | ||
726 | char *buf, int bufsz) | ||
727 | { | ||
728 | return mvm->pm_ops->power_dbgfs_read(mvm, vif, buf, bufsz); | ||
729 | } | ||
730 | #endif | ||
667 | 731 | ||
668 | int iwl_mvm_leds_init(struct iwl_mvm *mvm); | 732 | int iwl_mvm_leds_init(struct iwl_mvm *mvm); |
669 | void iwl_mvm_leds_exit(struct iwl_mvm *mvm); | 733 | void iwl_mvm_leds_exit(struct iwl_mvm *mvm); |
@@ -707,6 +771,12 @@ int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, | |||
707 | struct ieee80211_vif *vif); | 771 | struct ieee80211_vif *vif); |
708 | int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | 772 | int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, |
709 | struct ieee80211_vif *vif); | 773 | struct ieee80211_vif *vif); |
774 | int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, | ||
775 | struct iwl_beacon_filter_cmd *cmd); | ||
776 | int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, | ||
777 | struct ieee80211_vif *vif, bool enable); | ||
778 | int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, | ||
779 | struct ieee80211_vif *vif); | ||
710 | 780 | ||
711 | /* SMPS */ | 781 | /* SMPS */ |
712 | void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 782 | void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index af79a14063a9..2fcc8ef88a68 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -275,6 +275,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
275 | CMD(BEACON_NOTIFICATION), | 275 | CMD(BEACON_NOTIFICATION), |
276 | CMD(BEACON_TEMPLATE_CMD), | 276 | CMD(BEACON_TEMPLATE_CMD), |
277 | CMD(STATISTICS_NOTIFICATION), | 277 | CMD(STATISTICS_NOTIFICATION), |
278 | CMD(REDUCE_TX_POWER_CMD), | ||
278 | CMD(TX_ANT_CONFIGURATION_CMD), | 279 | CMD(TX_ANT_CONFIGURATION_CMD), |
279 | CMD(D3_CONFIG_CMD), | 280 | CMD(D3_CONFIG_CMD), |
280 | CMD(PROT_OFFLOAD_CONFIG_CMD), | 281 | CMD(PROT_OFFLOAD_CONFIG_CMD), |
@@ -301,6 +302,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
301 | CMD(MCAST_FILTER_CMD), | 302 | CMD(MCAST_FILTER_CMD), |
302 | CMD(REPLY_BEACON_FILTERING_CMD), | 303 | CMD(REPLY_BEACON_FILTERING_CMD), |
303 | CMD(REPLY_THERMAL_MNG_BACKOFF), | 304 | CMD(REPLY_THERMAL_MNG_BACKOFF), |
305 | CMD(MAC_PM_POWER_TABLE), | ||
304 | }; | 306 | }; |
305 | #undef CMD | 307 | #undef CMD |
306 | 308 | ||
@@ -340,6 +342,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
340 | mvm->fw = fw; | 342 | mvm->fw = fw; |
341 | mvm->hw = hw; | 343 | mvm->hw = hw; |
342 | 344 | ||
345 | mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0; | ||
346 | |||
343 | mutex_init(&mvm->mutex); | 347 | mutex_init(&mvm->mutex); |
344 | spin_lock_init(&mvm->async_handlers_lock); | 348 | spin_lock_init(&mvm->async_handlers_lock); |
345 | INIT_LIST_HEAD(&mvm->time_event_list); | 349 | INIT_LIST_HEAD(&mvm->time_event_list); |
@@ -431,6 +435,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
431 | if (err) | 435 | if (err) |
432 | goto out_unregister; | 436 | goto out_unregister; |
433 | 437 | ||
438 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD) | ||
439 | mvm->pm_ops = &pm_mac_ops; | ||
440 | else | ||
441 | mvm->pm_ops = &pm_legacy_ops; | ||
442 | |||
443 | memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); | ||
444 | |||
434 | return op_mode; | 445 | return op_mode; |
435 | 446 | ||
436 | out_unregister: | 447 | out_unregister: |
@@ -638,6 +649,22 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) | |||
638 | ieee80211_free_txskb(mvm->hw, skb); | 649 | ieee80211_free_txskb(mvm->hw, skb); |
639 | } | 650 | } |
640 | 651 | ||
652 | struct iwl_mvm_reprobe { | ||
653 | struct device *dev; | ||
654 | struct work_struct work; | ||
655 | }; | ||
656 | |||
657 | static void iwl_mvm_reprobe_wk(struct work_struct *wk) | ||
658 | { | ||
659 | struct iwl_mvm_reprobe *reprobe; | ||
660 | |||
661 | reprobe = container_of(wk, struct iwl_mvm_reprobe, work); | ||
662 | if (device_reprobe(reprobe->dev)) | ||
663 | dev_err(reprobe->dev, "reprobe failed!\n"); | ||
664 | kfree(reprobe); | ||
665 | module_put(THIS_MODULE); | ||
666 | } | ||
667 | |||
641 | static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) | 668 | static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) |
642 | { | 669 | { |
643 | iwl_abort_notification_waits(&mvm->notif_wait); | 670 | iwl_abort_notification_waits(&mvm->notif_wait); |
@@ -649,9 +676,30 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) | |||
649 | * can't recover this since we're already half suspended. | 676 | * can't recover this since we're already half suspended. |
650 | */ | 677 | */ |
651 | if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | 678 | if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { |
652 | IWL_ERR(mvm, "Firmware error during reconfiguration! Abort.\n"); | 679 | struct iwl_mvm_reprobe *reprobe; |
653 | } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && | 680 | |
654 | iwlwifi_mod_params.restart_fw) { | 681 | IWL_ERR(mvm, |
682 | "Firmware error during reconfiguration - reprobe!\n"); | ||
683 | |||
684 | /* | ||
685 | * get a module reference to avoid doing this while unloading | ||
686 | * anyway and to avoid scheduling a work with code that's | ||
687 | * being removed. | ||
688 | */ | ||
689 | if (!try_module_get(THIS_MODULE)) { | ||
690 | IWL_ERR(mvm, "Module is being unloaded - abort\n"); | ||
691 | return; | ||
692 | } | ||
693 | |||
694 | reprobe = kzalloc(sizeof(*reprobe), GFP_ATOMIC); | ||
695 | if (!reprobe) { | ||
696 | module_put(THIS_MODULE); | ||
697 | return; | ||
698 | } | ||
699 | reprobe->dev = mvm->trans->dev; | ||
700 | INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); | ||
701 | schedule_work(&reprobe->work); | ||
702 | } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && mvm->restart_fw) { | ||
655 | /* | 703 | /* |
656 | * This is a bit racy, but worst case we tell mac80211 about | 704 | * This is a bit racy, but worst case we tell mac80211 about |
657 | * a stopped/aborted (sched) scan when that was already done | 705 | * a stopped/aborted (sched) scan when that was already done |
@@ -669,6 +717,8 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) | |||
669 | break; | 717 | break; |
670 | } | 718 | } |
671 | 719 | ||
720 | if (mvm->restart_fw > 0) | ||
721 | mvm->restart_fw--; | ||
672 | ieee80211_restart_hw(mvm->hw); | 722 | ieee80211_restart_hw(mvm->hw); |
673 | } | 723 | } |
674 | } | 724 | } |
@@ -678,6 +728,8 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) | |||
678 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | 728 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); |
679 | 729 | ||
680 | iwl_mvm_dump_nic_error_log(mvm); | 730 | iwl_mvm_dump_nic_error_log(mvm); |
731 | if (!mvm->restart_fw) | ||
732 | iwl_mvm_dump_sram(mvm); | ||
681 | 733 | ||
682 | iwl_mvm_nic_restart(mvm); | 734 | iwl_mvm_nic_restart(mvm); |
683 | } | 735 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index e7ca965a89b8..21407a353a3b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c | |||
@@ -75,8 +75,8 @@ | |||
75 | 75 | ||
76 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 | 76 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 |
77 | 77 | ||
78 | static int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, | 78 | int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, |
79 | struct iwl_beacon_filter_cmd *cmd) | 79 | struct iwl_beacon_filter_cmd *cmd) |
80 | { | 80 | { |
81 | int ret; | 81 | int ret; |
82 | 82 | ||
@@ -85,69 +85,110 @@ static int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, | |||
85 | 85 | ||
86 | if (!ret) { | 86 | if (!ret) { |
87 | IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n", | 87 | IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n", |
88 | cmd->ba_enable_beacon_abort); | 88 | le32_to_cpu(cmd->ba_enable_beacon_abort)); |
89 | IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n", | 89 | IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n", |
90 | cmd->ba_escape_timer); | 90 | le32_to_cpu(cmd->ba_escape_timer)); |
91 | IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n", | 91 | IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n", |
92 | cmd->bf_debug_flag); | 92 | le32_to_cpu(cmd->bf_debug_flag)); |
93 | IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n", | 93 | IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n", |
94 | cmd->bf_enable_beacon_filter); | 94 | le32_to_cpu(cmd->bf_enable_beacon_filter)); |
95 | IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n", | 95 | IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n", |
96 | cmd->bf_energy_delta); | 96 | le32_to_cpu(cmd->bf_energy_delta)); |
97 | IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n", | 97 | IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n", |
98 | cmd->bf_escape_timer); | 98 | le32_to_cpu(cmd->bf_escape_timer)); |
99 | IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n", | 99 | IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n", |
100 | cmd->bf_roaming_energy_delta); | 100 | le32_to_cpu(cmd->bf_roaming_energy_delta)); |
101 | IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n", | 101 | IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n", |
102 | cmd->bf_roaming_state); | 102 | le32_to_cpu(cmd->bf_roaming_state)); |
103 | IWL_DEBUG_POWER(mvm, "bf_temperature_delta is: %d\n", | 103 | IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n", |
104 | cmd->bf_temperature_delta); | 104 | le32_to_cpu(cmd->bf_temp_threshold)); |
105 | IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n", | ||
106 | le32_to_cpu(cmd->bf_temp_fast_filter)); | ||
107 | IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n", | ||
108 | le32_to_cpu(cmd->bf_temp_slow_filter)); | ||
105 | } | 109 | } |
106 | return ret; | 110 | return ret; |
107 | } | 111 | } |
108 | 112 | ||
109 | static int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, | 113 | static |
110 | struct ieee80211_vif *vif, bool enable) | 114 | void iwl_mvm_beacon_filter_set_cqm_params(struct iwl_mvm *mvm, |
115 | struct ieee80211_vif *vif, | ||
116 | struct iwl_beacon_filter_cmd *cmd) | ||
117 | { | ||
118 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
119 | |||
120 | if (vif->bss_conf.cqm_rssi_thold) { | ||
121 | cmd->bf_energy_delta = | ||
122 | cpu_to_le32(vif->bss_conf.cqm_rssi_hyst); | ||
123 | /* fw uses an absolute value for this */ | ||
124 | cmd->bf_roaming_state = | ||
125 | cpu_to_le32(-vif->bss_conf.cqm_rssi_thold); | ||
126 | } | ||
127 | cmd->ba_enable_beacon_abort = cpu_to_le32(mvmvif->bf_data.ba_enabled); | ||
128 | } | ||
129 | |||
130 | int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, | ||
131 | struct ieee80211_vif *vif, bool enable) | ||
111 | { | 132 | { |
112 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 133 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
113 | struct iwl_beacon_filter_cmd cmd = { | 134 | struct iwl_beacon_filter_cmd cmd = { |
114 | IWL_BF_CMD_CONFIG_DEFAULTS, | 135 | IWL_BF_CMD_CONFIG_DEFAULTS, |
115 | .bf_enable_beacon_filter = 1, | 136 | .bf_enable_beacon_filter = cpu_to_le32(1), |
116 | .ba_enable_beacon_abort = enable, | 137 | .ba_enable_beacon_abort = cpu_to_le32(enable), |
117 | }; | 138 | }; |
118 | 139 | ||
119 | if (!mvmvif->bf_enabled) | 140 | if (!mvmvif->bf_data.bf_enabled) |
120 | return 0; | 141 | return 0; |
121 | 142 | ||
143 | if (mvm->cur_ucode == IWL_UCODE_WOWLAN) | ||
144 | cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3); | ||
145 | |||
146 | mvmvif->bf_data.ba_enabled = enable; | ||
147 | iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd); | ||
122 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); | 148 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); |
123 | return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); | 149 | return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); |
124 | } | 150 | } |
125 | 151 | ||
126 | static void iwl_mvm_power_log(struct iwl_mvm *mvm, | 152 | static void iwl_mvm_power_log(struct iwl_mvm *mvm, |
127 | struct iwl_powertable_cmd *cmd) | 153 | struct iwl_mac_power_cmd *cmd) |
128 | { | 154 | { |
129 | IWL_DEBUG_POWER(mvm, | 155 | IWL_DEBUG_POWER(mvm, |
130 | "Sending power table command for power level %d, flags = 0x%X\n", | 156 | "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n", |
131 | iwlmvm_mod_params.power_scheme, | 157 | cmd->id_and_color, iwlmvm_mod_params.power_scheme, |
132 | le16_to_cpu(cmd->flags)); | 158 | le16_to_cpu(cmd->flags)); |
133 | IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", cmd->keep_alive_seconds); | 159 | IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", |
134 | 160 | le16_to_cpu(cmd->keep_alive_seconds)); | |
135 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | 161 | |
136 | IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", | 162 | if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK))) { |
137 | le32_to_cpu(cmd->rx_data_timeout)); | 163 | IWL_DEBUG_POWER(mvm, "Disable power management\n"); |
138 | IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", | 164 | return; |
139 | le32_to_cpu(cmd->tx_data_timeout)); | 165 | } |
140 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) | 166 | |
141 | IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n", | 167 | IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", |
142 | le32_to_cpu(cmd->skip_dtim_periods)); | 168 | le32_to_cpu(cmd->rx_data_timeout)); |
143 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) | 169 | IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", |
144 | IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", | 170 | le32_to_cpu(cmd->tx_data_timeout)); |
145 | le32_to_cpu(cmd->lprx_rssi_threshold)); | 171 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) |
172 | IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n", | ||
173 | cmd->skip_dtim_periods); | ||
174 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) | ||
175 | IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", | ||
176 | cmd->lprx_rssi_threshold); | ||
177 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) { | ||
178 | IWL_DEBUG_POWER(mvm, "uAPSD enabled\n"); | ||
179 | IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n", | ||
180 | le32_to_cpu(cmd->rx_data_timeout_uapsd)); | ||
181 | IWL_DEBUG_POWER(mvm, "Tx timeout (uAPSD) = %u usec\n", | ||
182 | le32_to_cpu(cmd->tx_data_timeout_uapsd)); | ||
183 | IWL_DEBUG_POWER(mvm, "QNDP TID = %d\n", cmd->qndp_tid); | ||
184 | IWL_DEBUG_POWER(mvm, "ACs flags = 0x%x\n", cmd->uapsd_ac_flags); | ||
185 | IWL_DEBUG_POWER(mvm, "Max SP = %d\n", cmd->uapsd_max_sp); | ||
146 | } | 186 | } |
147 | } | 187 | } |
148 | 188 | ||
149 | void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 189 | static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, |
150 | struct iwl_powertable_cmd *cmd) | 190 | struct ieee80211_vif *vif, |
191 | struct iwl_mac_power_cmd *cmd) | ||
151 | { | 192 | { |
152 | struct ieee80211_hw *hw = mvm->hw; | 193 | struct ieee80211_hw *hw = mvm->hw; |
153 | struct ieee80211_chanctx_conf *chanctx_conf; | 194 | struct ieee80211_chanctx_conf *chanctx_conf; |
@@ -157,20 +198,29 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
157 | bool radar_detect = false; | 198 | bool radar_detect = false; |
158 | struct iwl_mvm_vif *mvmvif __maybe_unused = | 199 | struct iwl_mvm_vif *mvmvif __maybe_unused = |
159 | iwl_mvm_vif_from_mac80211(vif); | 200 | iwl_mvm_vif_from_mac80211(vif); |
201 | enum ieee80211_ac_numbers ac; | ||
202 | bool tid_found = false; | ||
203 | |||
204 | cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
205 | mvmvif->color)); | ||
206 | dtimper = hw->conf.ps_dtim_period ?: 1; | ||
160 | 207 | ||
161 | /* | 208 | /* |
162 | * Regardless of power management state the driver must set | 209 | * Regardless of power management state the driver must set |
163 | * keep alive period. FW will use it for sending keep alive NDPs | 210 | * keep alive period. FW will use it for sending keep alive NDPs |
164 | * immediately after association. | 211 | * immediately after association. Check that keep alive period |
212 | * is at least 3 * DTIM | ||
165 | */ | 213 | */ |
166 | cmd->keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC; | 214 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; |
215 | keep_alive = max_t(int, 3 * dtimper_msec, | ||
216 | MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC); | ||
217 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); | ||
218 | cmd->keep_alive_seconds = cpu_to_le16(keep_alive); | ||
167 | 219 | ||
168 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) | 220 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) |
169 | return; | 221 | return; |
170 | 222 | ||
171 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | 223 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); |
172 | if (!vif->bss_conf.assoc) | ||
173 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); | ||
174 | 224 | ||
175 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 225 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
176 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && | 226 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && |
@@ -186,12 +236,9 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
186 | (vif->bss_conf.beacon_rate->bitrate == 10 || | 236 | (vif->bss_conf.beacon_rate->bitrate == 10 || |
187 | vif->bss_conf.beacon_rate->bitrate == 60)) { | 237 | vif->bss_conf.beacon_rate->bitrate == 60)) { |
188 | cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); | 238 | cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); |
189 | cmd->lprx_rssi_threshold = | 239 | cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD; |
190 | cpu_to_le32(POWER_LPRX_RSSI_THRESHOLD); | ||
191 | } | 240 | } |
192 | 241 | ||
193 | dtimper = hw->conf.ps_dtim_period ?: 1; | ||
194 | |||
195 | /* Check if radar detection is required on current channel */ | 242 | /* Check if radar detection is required on current channel */ |
196 | rcu_read_lock(); | 243 | rcu_read_lock(); |
197 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | 244 | chanctx_conf = rcu_dereference(vif->chanctx_conf); |
@@ -207,27 +254,82 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
207 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || | 254 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || |
208 | mvm->cur_ucode == IWL_UCODE_WOWLAN)) { | 255 | mvm->cur_ucode == IWL_UCODE_WOWLAN)) { |
209 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | 256 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); |
210 | cmd->skip_dtim_periods = cpu_to_le32(3); | 257 | cmd->skip_dtim_periods = 3; |
211 | } | 258 | } |
212 | 259 | ||
213 | /* Check that keep alive period is at least 3 * DTIM */ | ||
214 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; | ||
215 | keep_alive = max_t(int, 3 * dtimper_msec, | ||
216 | MSEC_PER_SEC * cmd->keep_alive_seconds); | ||
217 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); | ||
218 | cmd->keep_alive_seconds = keep_alive; | ||
219 | |||
220 | if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { | 260 | if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { |
221 | cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | 261 | cmd->rx_data_timeout = |
222 | cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | 262 | cpu_to_le32(IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT); |
263 | cmd->tx_data_timeout = | ||
264 | cpu_to_le32(IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT); | ||
223 | } else { | 265 | } else { |
224 | cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); | 266 | cmd->rx_data_timeout = |
225 | cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); | 267 | cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT); |
268 | cmd->tx_data_timeout = | ||
269 | cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT); | ||
270 | } | ||
271 | |||
272 | for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) { | ||
273 | if (!mvmvif->queue_params[ac].uapsd) | ||
274 | continue; | ||
275 | |||
276 | cmd->flags |= cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK); | ||
277 | cmd->uapsd_ac_flags |= BIT(ac); | ||
278 | |||
279 | /* QNDP TID - the highest TID with no admission control */ | ||
280 | if (!tid_found && !mvmvif->queue_params[ac].acm) { | ||
281 | tid_found = true; | ||
282 | switch (ac) { | ||
283 | case IEEE80211_AC_VO: | ||
284 | cmd->qndp_tid = 6; | ||
285 | break; | ||
286 | case IEEE80211_AC_VI: | ||
287 | cmd->qndp_tid = 5; | ||
288 | break; | ||
289 | case IEEE80211_AC_BE: | ||
290 | cmd->qndp_tid = 0; | ||
291 | break; | ||
292 | case IEEE80211_AC_BK: | ||
293 | cmd->qndp_tid = 1; | ||
294 | break; | ||
295 | } | ||
296 | } | ||
297 | } | ||
298 | |||
299 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) { | ||
300 | cmd->rx_data_timeout_uapsd = | ||
301 | cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT); | ||
302 | cmd->tx_data_timeout_uapsd = | ||
303 | cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT); | ||
304 | |||
305 | if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) | | ||
306 | BIT(IEEE80211_AC_VI) | | ||
307 | BIT(IEEE80211_AC_BE) | | ||
308 | BIT(IEEE80211_AC_BK))) { | ||
309 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK); | ||
310 | cmd->snooze_interval = | ||
311 | cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL); | ||
312 | cmd->snooze_window = | ||
313 | (mvm->cur_ucode == IWL_UCODE_WOWLAN) ? | ||
314 | cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) : | ||
315 | cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW); | ||
316 | } | ||
317 | |||
318 | cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP; | ||
319 | cmd->heavy_tx_thld_packets = | ||
320 | IWL_MVM_PS_HEAVY_TX_THLD_PACKETS; | ||
321 | cmd->heavy_rx_thld_packets = | ||
322 | IWL_MVM_PS_HEAVY_RX_THLD_PACKETS; | ||
323 | cmd->heavy_tx_thld_percentage = | ||
324 | IWL_MVM_PS_HEAVY_TX_THLD_PERCENT; | ||
325 | cmd->heavy_rx_thld_percentage = | ||
326 | IWL_MVM_PS_HEAVY_RX_THLD_PERCENT; | ||
226 | } | 327 | } |
227 | 328 | ||
228 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 329 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
229 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) | 330 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) |
230 | cmd->keep_alive_seconds = mvmvif->dbgfs_pm.keep_alive_seconds; | 331 | cmd->keep_alive_seconds = |
332 | cpu_to_le16(mvmvif->dbgfs_pm.keep_alive_seconds); | ||
231 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { | 333 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { |
232 | if (mvmvif->dbgfs_pm.skip_over_dtim) | 334 | if (mvmvif->dbgfs_pm.skip_over_dtim) |
233 | cmd->flags |= | 335 | cmd->flags |= |
@@ -243,8 +345,7 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
243 | cmd->tx_data_timeout = | 345 | cmd->tx_data_timeout = |
244 | cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); | 346 | cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); |
245 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) | 347 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) |
246 | cmd->skip_dtim_periods = | 348 | cmd->skip_dtim_periods = mvmvif->dbgfs_pm.skip_dtim_periods; |
247 | cpu_to_le32(mvmvif->dbgfs_pm.skip_dtim_periods); | ||
248 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) { | 349 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) { |
249 | if (mvmvif->dbgfs_pm.lprx_ena) | 350 | if (mvmvif->dbgfs_pm.lprx_ena) |
250 | cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); | 351 | cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); |
@@ -252,16 +353,24 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
252 | cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK); | 353 | cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK); |
253 | } | 354 | } |
254 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD) | 355 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD) |
255 | cmd->lprx_rssi_threshold = | 356 | cmd->lprx_rssi_threshold = mvmvif->dbgfs_pm.lprx_rssi_threshold; |
256 | cpu_to_le32(mvmvif->dbgfs_pm.lprx_rssi_threshold); | 357 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SNOOZE_ENABLE) { |
358 | if (mvmvif->dbgfs_pm.snooze_ena) | ||
359 | cmd->flags |= | ||
360 | cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK); | ||
361 | else | ||
362 | cmd->flags &= | ||
363 | cpu_to_le16(~POWER_FLAGS_SNOOZE_ENA_MSK); | ||
364 | } | ||
257 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | 365 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ |
258 | } | 366 | } |
259 | 367 | ||
260 | int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 368 | static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, |
369 | struct ieee80211_vif *vif) | ||
261 | { | 370 | { |
262 | int ret; | 371 | int ret; |
263 | bool ba_enable; | 372 | bool ba_enable; |
264 | struct iwl_powertable_cmd cmd = {}; | 373 | struct iwl_mac_power_cmd cmd = {}; |
265 | 374 | ||
266 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 375 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
267 | return 0; | 376 | return 0; |
@@ -280,7 +389,7 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
280 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | 389 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); |
281 | iwl_mvm_power_log(mvm, &cmd); | 390 | iwl_mvm_power_log(mvm, &cmd); |
282 | 391 | ||
283 | ret = iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | 392 | ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC, |
284 | sizeof(cmd), &cmd); | 393 | sizeof(cmd), &cmd); |
285 | if (ret) | 394 | if (ret) |
286 | return ret; | 395 | return ret; |
@@ -291,15 +400,19 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
291 | return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); | 400 | return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); |
292 | } | 401 | } |
293 | 402 | ||
294 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 403 | static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm, |
404 | struct ieee80211_vif *vif) | ||
295 | { | 405 | { |
296 | struct iwl_powertable_cmd cmd = {}; | 406 | struct iwl_mac_power_cmd cmd = {}; |
297 | struct iwl_mvm_vif *mvmvif __maybe_unused = | 407 | struct iwl_mvm_vif *mvmvif __maybe_unused = |
298 | iwl_mvm_vif_from_mac80211(vif); | 408 | iwl_mvm_vif_from_mac80211(vif); |
299 | 409 | ||
300 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 410 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
301 | return 0; | 411 | return 0; |
302 | 412 | ||
413 | cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
414 | mvmvif->color)); | ||
415 | |||
303 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) | 416 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) |
304 | cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | 417 | cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); |
305 | 418 | ||
@@ -310,11 +423,98 @@ int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
310 | #endif | 423 | #endif |
311 | iwl_mvm_power_log(mvm, &cmd); | 424 | iwl_mvm_power_log(mvm, &cmd); |
312 | 425 | ||
313 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, | 426 | return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_ASYNC, |
314 | sizeof(cmd), &cmd); | 427 | sizeof(cmd), &cmd); |
315 | } | 428 | } |
316 | 429 | ||
317 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 430 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
431 | static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, | ||
432 | struct ieee80211_vif *vif, char *buf, | ||
433 | int bufsz) | ||
434 | { | ||
435 | struct iwl_mac_power_cmd cmd = {}; | ||
436 | int pos = 0; | ||
437 | |||
438 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | ||
439 | |||
440 | pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", | ||
441 | (cmd.flags & | ||
442 | cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? | ||
443 | 0 : 1); | ||
444 | pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", | ||
445 | iwlmvm_mod_params.power_scheme); | ||
446 | pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", | ||
447 | le16_to_cpu(cmd.flags)); | ||
448 | pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n", | ||
449 | le16_to_cpu(cmd.keep_alive_seconds)); | ||
450 | |||
451 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | ||
452 | pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n", | ||
453 | (cmd.flags & | ||
454 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? | ||
455 | 1 : 0); | ||
456 | pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", | ||
457 | cmd.skip_dtim_periods); | ||
458 | if (!(cmd.flags & | ||
459 | cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) { | ||
460 | pos += scnprintf(buf+pos, bufsz-pos, | ||
461 | "rx_data_timeout = %d\n", | ||
462 | le32_to_cpu(cmd.rx_data_timeout)); | ||
463 | pos += scnprintf(buf+pos, bufsz-pos, | ||
464 | "tx_data_timeout = %d\n", | ||
465 | le32_to_cpu(cmd.tx_data_timeout)); | ||
466 | } | ||
467 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) | ||
468 | pos += scnprintf(buf+pos, bufsz-pos, | ||
469 | "lprx_rssi_threshold = %d\n", | ||
470 | cmd.lprx_rssi_threshold); | ||
471 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) { | ||
472 | pos += | ||
473 | scnprintf(buf+pos, bufsz-pos, | ||
474 | "rx_data_timeout_uapsd = %d\n", | ||
475 | le32_to_cpu(cmd.rx_data_timeout_uapsd)); | ||
476 | pos += | ||
477 | scnprintf(buf+pos, bufsz-pos, | ||
478 | "tx_data_timeout_uapsd = %d\n", | ||
479 | le32_to_cpu(cmd.tx_data_timeout_uapsd)); | ||
480 | pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n", | ||
481 | cmd.qndp_tid); | ||
482 | pos += scnprintf(buf+pos, bufsz-pos, | ||
483 | "uapsd_ac_flags = 0x%x\n", | ||
484 | cmd.uapsd_ac_flags); | ||
485 | pos += scnprintf(buf+pos, bufsz-pos, | ||
486 | "uapsd_max_sp = %d\n", | ||
487 | cmd.uapsd_max_sp); | ||
488 | pos += scnprintf(buf+pos, bufsz-pos, | ||
489 | "heavy_tx_thld_packets = %d\n", | ||
490 | cmd.heavy_tx_thld_packets); | ||
491 | pos += scnprintf(buf+pos, bufsz-pos, | ||
492 | "heavy_rx_thld_packets = %d\n", | ||
493 | cmd.heavy_rx_thld_packets); | ||
494 | pos += scnprintf(buf+pos, bufsz-pos, | ||
495 | "heavy_tx_thld_percentage = %d\n", | ||
496 | cmd.heavy_tx_thld_percentage); | ||
497 | pos += scnprintf(buf+pos, bufsz-pos, | ||
498 | "heavy_rx_thld_percentage = %d\n", | ||
499 | cmd.heavy_rx_thld_percentage); | ||
500 | pos += | ||
501 | scnprintf(buf+pos, bufsz-pos, "snooze_enable = %d\n", | ||
502 | (cmd.flags & | ||
503 | cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) ? | ||
504 | 1 : 0); | ||
505 | } | ||
506 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) { | ||
507 | pos += scnprintf(buf+pos, bufsz-pos, | ||
508 | "snooze_interval = %d\n", | ||
509 | cmd.snooze_interval); | ||
510 | pos += scnprintf(buf+pos, bufsz-pos, | ||
511 | "snooze_window = %d\n", | ||
512 | cmd.snooze_window); | ||
513 | } | ||
514 | } | ||
515 | return pos; | ||
516 | } | ||
517 | |||
318 | void | 518 | void |
319 | iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, | 519 | iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, |
320 | struct iwl_beacon_filter_cmd *cmd) | 520 | struct iwl_beacon_filter_cmd *cmd) |
@@ -323,22 +523,30 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, | |||
323 | struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf; | 523 | struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf; |
324 | 524 | ||
325 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ENERGY_DELTA) | 525 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ENERGY_DELTA) |
326 | cmd->bf_energy_delta = dbgfs_bf->bf_energy_delta; | 526 | cmd->bf_energy_delta = cpu_to_le32(dbgfs_bf->bf_energy_delta); |
327 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA) | 527 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA) |
328 | cmd->bf_roaming_energy_delta = | 528 | cmd->bf_roaming_energy_delta = |
329 | dbgfs_bf->bf_roaming_energy_delta; | 529 | cpu_to_le32(dbgfs_bf->bf_roaming_energy_delta); |
330 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_STATE) | 530 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_STATE) |
331 | cmd->bf_roaming_state = dbgfs_bf->bf_roaming_state; | 531 | cmd->bf_roaming_state = cpu_to_le32(dbgfs_bf->bf_roaming_state); |
332 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMPERATURE_DELTA) | 532 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_THRESHOLD) |
333 | cmd->bf_temperature_delta = dbgfs_bf->bf_temperature_delta; | 533 | cmd->bf_temp_threshold = |
534 | cpu_to_le32(dbgfs_bf->bf_temp_threshold); | ||
535 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_FAST_FILTER) | ||
536 | cmd->bf_temp_fast_filter = | ||
537 | cpu_to_le32(dbgfs_bf->bf_temp_fast_filter); | ||
538 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMP_SLOW_FILTER) | ||
539 | cmd->bf_temp_slow_filter = | ||
540 | cpu_to_le32(dbgfs_bf->bf_temp_slow_filter); | ||
334 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_DEBUG_FLAG) | 541 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_DEBUG_FLAG) |
335 | cmd->bf_debug_flag = dbgfs_bf->bf_debug_flag; | 542 | cmd->bf_debug_flag = cpu_to_le32(dbgfs_bf->bf_debug_flag); |
336 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ESCAPE_TIMER) | 543 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ESCAPE_TIMER) |
337 | cmd->bf_escape_timer = cpu_to_le32(dbgfs_bf->bf_escape_timer); | 544 | cmd->bf_escape_timer = cpu_to_le32(dbgfs_bf->bf_escape_timer); |
338 | if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ESCAPE_TIMER) | 545 | if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ESCAPE_TIMER) |
339 | cmd->ba_escape_timer = cpu_to_le32(dbgfs_bf->ba_escape_timer); | 546 | cmd->ba_escape_timer = cpu_to_le32(dbgfs_bf->ba_escape_timer); |
340 | if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT) | 547 | if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT) |
341 | cmd->ba_enable_beacon_abort = dbgfs_bf->ba_enable_beacon_abort; | 548 | cmd->ba_enable_beacon_abort = |
549 | cpu_to_le32(dbgfs_bf->ba_enable_beacon_abort); | ||
342 | } | 550 | } |
343 | #endif | 551 | #endif |
344 | 552 | ||
@@ -348,7 +556,7 @@ int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, | |||
348 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 556 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
349 | struct iwl_beacon_filter_cmd cmd = { | 557 | struct iwl_beacon_filter_cmd cmd = { |
350 | IWL_BF_CMD_CONFIG_DEFAULTS, | 558 | IWL_BF_CMD_CONFIG_DEFAULTS, |
351 | .bf_enable_beacon_filter = 1, | 559 | .bf_enable_beacon_filter = cpu_to_le32(1), |
352 | }; | 560 | }; |
353 | int ret; | 561 | int ret; |
354 | 562 | ||
@@ -356,11 +564,12 @@ int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, | |||
356 | vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 564 | vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
357 | return 0; | 565 | return 0; |
358 | 566 | ||
567 | iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd); | ||
359 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); | 568 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); |
360 | ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); | 569 | ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); |
361 | 570 | ||
362 | if (!ret) | 571 | if (!ret) |
363 | mvmvif->bf_enabled = true; | 572 | mvmvif->bf_data.bf_enabled = true; |
364 | 573 | ||
365 | return ret; | 574 | return ret; |
366 | } | 575 | } |
@@ -372,13 +581,33 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | |||
372 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 581 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
373 | int ret; | 582 | int ret; |
374 | 583 | ||
375 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 584 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED) || |
585 | vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
376 | return 0; | 586 | return 0; |
377 | 587 | ||
378 | ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); | 588 | ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); |
379 | 589 | ||
380 | if (!ret) | 590 | if (!ret) |
381 | mvmvif->bf_enabled = false; | 591 | mvmvif->bf_data.bf_enabled = false; |
382 | 592 | ||
383 | return ret; | 593 | return ret; |
384 | } | 594 | } |
595 | |||
596 | int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, | ||
597 | struct ieee80211_vif *vif) | ||
598 | { | ||
599 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
600 | |||
601 | if (!mvmvif->bf_data.bf_enabled) | ||
602 | return 0; | ||
603 | |||
604 | return iwl_mvm_enable_beacon_filter(mvm, vif); | ||
605 | } | ||
606 | |||
607 | const struct iwl_mvm_power_ops pm_mac_ops = { | ||
608 | .power_update_mode = iwl_mvm_power_mac_update_mode, | ||
609 | .power_disable = iwl_mvm_power_mac_disable, | ||
610 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
611 | .power_dbgfs_read = iwl_mvm_power_mac_dbgfs_read, | ||
612 | #endif | ||
613 | }; | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/power_legacy.c b/drivers/net/wireless/iwlwifi/mvm/power_legacy.c new file mode 100644 index 000000000000..2ce79bad5845 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/power_legacy.c | |||
@@ -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) 2012 - 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) 2012 - 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 <linux/kernel.h> | ||
65 | #include <linux/module.h> | ||
66 | #include <linux/slab.h> | ||
67 | #include <linux/init.h> | ||
68 | |||
69 | #include <net/mac80211.h> | ||
70 | |||
71 | #include "iwl-debug.h" | ||
72 | #include "mvm.h" | ||
73 | #include "iwl-modparams.h" | ||
74 | #include "fw-api-power.h" | ||
75 | |||
76 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 | ||
77 | |||
78 | static void iwl_mvm_power_log(struct iwl_mvm *mvm, | ||
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 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) | ||
93 | IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n", | ||
94 | le32_to_cpu(cmd->skip_dtim_periods)); | ||
95 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) | ||
96 | IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", | ||
97 | le32_to_cpu(cmd->lprx_rssi_threshold)); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | ||
102 | struct ieee80211_vif *vif, | ||
103 | struct iwl_powertable_cmd *cmd) | ||
104 | { | ||
105 | struct ieee80211_hw *hw = mvm->hw; | ||
106 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
107 | struct ieee80211_channel *chan; | ||
108 | int dtimper, dtimper_msec; | ||
109 | int keep_alive; | ||
110 | bool radar_detect = false; | ||
111 | struct iwl_mvm_vif *mvmvif __maybe_unused = | ||
112 | iwl_mvm_vif_from_mac80211(vif); | ||
113 | |||
114 | /* | ||
115 | * Regardless of power management state the driver must set | ||
116 | * keep alive period. FW will use it for sending keep alive NDPs | ||
117 | * immediately after association. | ||
118 | */ | ||
119 | cmd->keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC; | ||
120 | |||
121 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) | ||
122 | return; | ||
123 | |||
124 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
125 | if (!vif->bss_conf.assoc) | ||
126 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); | ||
127 | |||
128 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
129 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && | ||
130 | mvmvif->dbgfs_pm.disable_power_off) | ||
131 | cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
132 | #endif | ||
133 | if (!vif->bss_conf.ps) | ||
134 | return; | ||
135 | |||
136 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); | ||
137 | |||
138 | if (vif->bss_conf.beacon_rate && | ||
139 | (vif->bss_conf.beacon_rate->bitrate == 10 || | ||
140 | vif->bss_conf.beacon_rate->bitrate == 60)) { | ||
141 | cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); | ||
142 | cmd->lprx_rssi_threshold = | ||
143 | cpu_to_le32(POWER_LPRX_RSSI_THRESHOLD); | ||
144 | } | ||
145 | |||
146 | dtimper = hw->conf.ps_dtim_period ?: 1; | ||
147 | |||
148 | /* Check if radar detection is required on current channel */ | ||
149 | rcu_read_lock(); | ||
150 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
151 | WARN_ON(!chanctx_conf); | ||
152 | if (chanctx_conf) { | ||
153 | chan = chanctx_conf->def.chan; | ||
154 | radar_detect = chan->flags & IEEE80211_CHAN_RADAR; | ||
155 | } | ||
156 | rcu_read_unlock(); | ||
157 | |||
158 | /* Check skip over DTIM conditions */ | ||
159 | if (!radar_detect && (dtimper <= 10) && | ||
160 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || | ||
161 | mvm->cur_ucode == IWL_UCODE_WOWLAN)) { | ||
162 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
163 | cmd->skip_dtim_periods = cpu_to_le32(3); | ||
164 | } | ||
165 | |||
166 | /* Check that keep alive period is at least 3 * DTIM */ | ||
167 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; | ||
168 | keep_alive = max_t(int, 3 * dtimper_msec, | ||
169 | MSEC_PER_SEC * cmd->keep_alive_seconds); | ||
170 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); | ||
171 | cmd->keep_alive_seconds = keep_alive; | ||
172 | |||
173 | if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { | ||
174 | cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | ||
175 | cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | ||
176 | } else { | ||
177 | cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); | ||
178 | cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); | ||
179 | } | ||
180 | |||
181 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
182 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) | ||
183 | cmd->keep_alive_seconds = mvmvif->dbgfs_pm.keep_alive_seconds; | ||
184 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { | ||
185 | if (mvmvif->dbgfs_pm.skip_over_dtim) | ||
186 | cmd->flags |= | ||
187 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
188 | else | ||
189 | cmd->flags &= | ||
190 | cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
191 | } | ||
192 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT) | ||
193 | cmd->rx_data_timeout = | ||
194 | cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout); | ||
195 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT) | ||
196 | cmd->tx_data_timeout = | ||
197 | cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); | ||
198 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) | ||
199 | cmd->skip_dtim_periods = | ||
200 | cpu_to_le32(mvmvif->dbgfs_pm.skip_dtim_periods); | ||
201 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) { | ||
202 | if (mvmvif->dbgfs_pm.lprx_ena) | ||
203 | cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); | ||
204 | else | ||
205 | cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK); | ||
206 | } | ||
207 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD) | ||
208 | cmd->lprx_rssi_threshold = | ||
209 | cpu_to_le32(mvmvif->dbgfs_pm.lprx_rssi_threshold); | ||
210 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | ||
211 | } | ||
212 | |||
213 | static int iwl_mvm_power_legacy_update_mode(struct iwl_mvm *mvm, | ||
214 | struct ieee80211_vif *vif) | ||
215 | { | ||
216 | int ret; | ||
217 | bool ba_enable; | ||
218 | struct iwl_powertable_cmd cmd = {}; | ||
219 | |||
220 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
221 | return 0; | ||
222 | |||
223 | /* | ||
224 | * TODO: The following vif_count verification is temporary condition. | ||
225 | * Avoid power mode update if more than one interface is currently | ||
226 | * active. Remove this condition when FW will support power management | ||
227 | * on multiple MACs. | ||
228 | */ | ||
229 | IWL_DEBUG_POWER(mvm, "Currently %d interfaces active\n", | ||
230 | mvm->vif_count); | ||
231 | if (mvm->vif_count > 1) | ||
232 | return 0; | ||
233 | |||
234 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | ||
235 | iwl_mvm_power_log(mvm, &cmd); | ||
236 | |||
237 | ret = iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | ||
238 | sizeof(cmd), &cmd); | ||
239 | if (ret) | ||
240 | return ret; | ||
241 | |||
242 | ba_enable = !!(cmd.flags & | ||
243 | cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); | ||
244 | |||
245 | return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); | ||
246 | } | ||
247 | |||
248 | static int iwl_mvm_power_legacy_disable(struct iwl_mvm *mvm, | ||
249 | struct ieee80211_vif *vif) | ||
250 | { | ||
251 | struct iwl_powertable_cmd cmd = {}; | ||
252 | struct iwl_mvm_vif *mvmvif __maybe_unused = | ||
253 | iwl_mvm_vif_from_mac80211(vif); | ||
254 | |||
255 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
256 | return 0; | ||
257 | |||
258 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) | ||
259 | cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
260 | |||
261 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
262 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && | ||
263 | mvmvif->dbgfs_pm.disable_power_off) | ||
264 | cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
265 | #endif | ||
266 | iwl_mvm_power_log(mvm, &cmd); | ||
267 | |||
268 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, | ||
269 | sizeof(cmd), &cmd); | ||
270 | } | ||
271 | |||
272 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
273 | static int iwl_mvm_power_legacy_dbgfs_read(struct iwl_mvm *mvm, | ||
274 | struct ieee80211_vif *vif, char *buf, | ||
275 | int bufsz) | ||
276 | { | ||
277 | struct iwl_powertable_cmd cmd = {}; | ||
278 | int pos = 0; | ||
279 | |||
280 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | ||
281 | |||
282 | pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", | ||
283 | (cmd.flags & | ||
284 | cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? | ||
285 | 0 : 1); | ||
286 | pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", | ||
287 | le32_to_cpu(cmd.skip_dtim_periods)); | ||
288 | pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", | ||
289 | iwlmvm_mod_params.power_scheme); | ||
290 | pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", | ||
291 | le16_to_cpu(cmd.flags)); | ||
292 | pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n", | ||
293 | cmd.keep_alive_seconds); | ||
294 | |||
295 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | ||
296 | pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n", | ||
297 | (cmd.flags & | ||
298 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? | ||
299 | 1 : 0); | ||
300 | pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n", | ||
301 | le32_to_cpu(cmd.rx_data_timeout)); | ||
302 | pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n", | ||
303 | le32_to_cpu(cmd.tx_data_timeout)); | ||
304 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) | ||
305 | pos += scnprintf(buf+pos, bufsz-pos, | ||
306 | "lprx_rssi_threshold = %d\n", | ||
307 | le32_to_cpu(cmd.lprx_rssi_threshold)); | ||
308 | } | ||
309 | return pos; | ||
310 | } | ||
311 | #endif | ||
312 | |||
313 | const struct iwl_mvm_power_ops pm_legacy_ops = { | ||
314 | .power_update_mode = iwl_mvm_power_legacy_update_mode, | ||
315 | .power_disable = iwl_mvm_power_legacy_disable, | ||
316 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
317 | .power_dbgfs_read = iwl_mvm_power_legacy_dbgfs_read, | ||
318 | #endif | ||
319 | }; | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 29d49cf0fdb2..5c6ae16ec52b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c | |||
@@ -131,23 +131,22 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, | |||
131 | 131 | ||
132 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | 132 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) |
133 | { | 133 | { |
134 | struct iwl_time_quota_cmd cmd; | 134 | struct iwl_time_quota_cmd cmd = {}; |
135 | int i, idx, ret, num_active_bindings, quota, quota_rem; | 135 | int i, idx, ret, num_active_macs, quota, quota_rem; |
136 | struct iwl_mvm_quota_iterator_data data = { | 136 | struct iwl_mvm_quota_iterator_data data = { |
137 | .n_interfaces = {}, | 137 | .n_interfaces = {}, |
138 | .colors = { -1, -1, -1, -1 }, | 138 | .colors = { -1, -1, -1, -1 }, |
139 | .new_vif = newvif, | 139 | .new_vif = newvif, |
140 | }; | 140 | }; |
141 | 141 | ||
142 | lockdep_assert_held(&mvm->mutex); | ||
143 | |||
142 | /* update all upon completion */ | 144 | /* update all upon completion */ |
143 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | 145 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) |
144 | return 0; | 146 | return 0; |
145 | 147 | ||
146 | BUILD_BUG_ON(data.colors[MAX_BINDINGS - 1] != -1); | 148 | /* iterator data above must match */ |
147 | 149 | BUILD_BUG_ON(MAX_BINDINGS != 4); | |
148 | lockdep_assert_held(&mvm->mutex); | ||
149 | |||
150 | memset(&cmd, 0, sizeof(cmd)); | ||
151 | 150 | ||
152 | ieee80211_iterate_active_interfaces_atomic( | 151 | ieee80211_iterate_active_interfaces_atomic( |
153 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | 152 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, |
@@ -162,18 +161,17 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | |||
162 | * IWL_MVM_MAX_QUOTA fragments. Divide these fragments | 161 | * IWL_MVM_MAX_QUOTA fragments. Divide these fragments |
163 | * equally between all the bindings that require quota | 162 | * equally between all the bindings that require quota |
164 | */ | 163 | */ |
165 | num_active_bindings = 0; | 164 | num_active_macs = 0; |
166 | for (i = 0; i < MAX_BINDINGS; i++) { | 165 | for (i = 0; i < MAX_BINDINGS; i++) { |
167 | cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); | 166 | cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); |
168 | if (data.n_interfaces[i] > 0) | 167 | num_active_macs += data.n_interfaces[i]; |
169 | num_active_bindings++; | ||
170 | } | 168 | } |
171 | 169 | ||
172 | quota = 0; | 170 | quota = 0; |
173 | quota_rem = 0; | 171 | quota_rem = 0; |
174 | if (num_active_bindings) { | 172 | if (num_active_macs) { |
175 | quota = IWL_MVM_MAX_QUOTA / num_active_bindings; | 173 | quota = IWL_MVM_MAX_QUOTA / num_active_macs; |
176 | quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings; | 174 | quota_rem = IWL_MVM_MAX_QUOTA % num_active_macs; |
177 | } | 175 | } |
178 | 176 | ||
179 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { | 177 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { |
@@ -187,7 +185,8 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | |||
187 | cmd.quotas[idx].quota = cpu_to_le32(0); | 185 | cmd.quotas[idx].quota = cpu_to_le32(0); |
188 | cmd.quotas[idx].max_duration = cpu_to_le32(0); | 186 | cmd.quotas[idx].max_duration = cpu_to_le32(0); |
189 | } else { | 187 | } else { |
190 | cmd.quotas[idx].quota = cpu_to_le32(quota); | 188 | cmd.quotas[idx].quota = |
189 | cpu_to_le32(quota * data.n_interfaces[i]); | ||
191 | cmd.quotas[idx].max_duration = | 190 | cmd.quotas[idx].max_duration = |
192 | cpu_to_le32(IWL_MVM_MAX_QUOTA); | 191 | cpu_to_le32(IWL_MVM_MAX_QUOTA); |
193 | } | 192 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index b328a988c130..4ffaa3fa153f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
@@ -56,61 +56,61 @@ | |||
56 | #define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ) | 56 | #define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ) |
57 | 57 | ||
58 | static u8 rs_ht_to_legacy[] = { | 58 | static u8 rs_ht_to_legacy[] = { |
59 | IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, | 59 | [IWL_RATE_1M_INDEX] = IWL_RATE_6M_INDEX, |
60 | IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, | 60 | [IWL_RATE_2M_INDEX] = IWL_RATE_6M_INDEX, |
61 | IWL_RATE_6M_INDEX, | 61 | [IWL_RATE_5M_INDEX] = IWL_RATE_6M_INDEX, |
62 | IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX, | 62 | [IWL_RATE_11M_INDEX] = IWL_RATE_6M_INDEX, |
63 | IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX, | 63 | [IWL_RATE_6M_INDEX] = IWL_RATE_6M_INDEX, |
64 | IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX, | 64 | [IWL_RATE_9M_INDEX] = IWL_RATE_6M_INDEX, |
65 | IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX | 65 | [IWL_RATE_12M_INDEX] = IWL_RATE_9M_INDEX, |
66 | [IWL_RATE_18M_INDEX] = IWL_RATE_12M_INDEX, | ||
67 | [IWL_RATE_24M_INDEX] = IWL_RATE_18M_INDEX, | ||
68 | [IWL_RATE_36M_INDEX] = IWL_RATE_24M_INDEX, | ||
69 | [IWL_RATE_48M_INDEX] = IWL_RATE_36M_INDEX, | ||
70 | [IWL_RATE_54M_INDEX] = IWL_RATE_48M_INDEX, | ||
71 | [IWL_RATE_60M_INDEX] = IWL_RATE_54M_INDEX, | ||
66 | }; | 72 | }; |
67 | 73 | ||
68 | static const u8 ant_toggle_lookup[] = { | 74 | static const u8 ant_toggle_lookup[] = { |
69 | /*ANT_NONE -> */ ANT_NONE, | 75 | [ANT_NONE] = ANT_NONE, |
70 | /*ANT_A -> */ ANT_B, | 76 | [ANT_A] = ANT_B, |
71 | /*ANT_B -> */ ANT_C, | 77 | [ANT_B] = ANT_C, |
72 | /*ANT_AB -> */ ANT_BC, | 78 | [ANT_AB] = ANT_BC, |
73 | /*ANT_C -> */ ANT_A, | 79 | [ANT_C] = ANT_A, |
74 | /*ANT_AC -> */ ANT_AB, | 80 | [ANT_AC] = ANT_AB, |
75 | /*ANT_BC -> */ ANT_AC, | 81 | [ANT_BC] = ANT_AC, |
76 | /*ANT_ABC -> */ ANT_ABC, | 82 | [ANT_ABC] = ANT_ABC, |
77 | }; | 83 | }; |
78 | 84 | ||
79 | #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ | 85 | #define IWL_DECLARE_RATE_INFO(r, s, rp, rn) \ |
80 | [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ | 86 | [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ |
81 | IWL_RATE_SISO_##s##M_PLCP, \ | 87 | IWL_RATE_SISO_##s##M_PLCP, \ |
82 | IWL_RATE_MIMO2_##s##M_PLCP,\ | 88 | IWL_RATE_MIMO2_##s##M_PLCP,\ |
83 | IWL_RATE_MIMO3_##s##M_PLCP,\ | ||
84 | IWL_RATE_##r##M_IEEE, \ | ||
85 | IWL_RATE_##ip##M_INDEX, \ | ||
86 | IWL_RATE_##in##M_INDEX, \ | ||
87 | IWL_RATE_##rp##M_INDEX, \ | 89 | IWL_RATE_##rp##M_INDEX, \ |
88 | IWL_RATE_##rn##M_INDEX, \ | 90 | IWL_RATE_##rn##M_INDEX } |
89 | IWL_RATE_##pp##M_INDEX, \ | ||
90 | IWL_RATE_##np##M_INDEX } | ||
91 | 91 | ||
92 | /* | 92 | /* |
93 | * Parameter order: | 93 | * Parameter order: |
94 | * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate | 94 | * rate, ht rate, prev rate, next rate |
95 | * | 95 | * |
96 | * If there isn't a valid next or previous rate then INV is used which | 96 | * If there isn't a valid next or previous rate then INV is used which |
97 | * maps to IWL_RATE_INVALID | 97 | * maps to IWL_RATE_INVALID |
98 | * | 98 | * |
99 | */ | 99 | */ |
100 | static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = { | 100 | static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = { |
101 | IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ | 101 | IWL_DECLARE_RATE_INFO(1, INV, INV, 2), /* 1mbps */ |
102 | IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ | 102 | IWL_DECLARE_RATE_INFO(2, INV, 1, 5), /* 2mbps */ |
103 | IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ | 103 | IWL_DECLARE_RATE_INFO(5, INV, 2, 11), /*5.5mbps */ |
104 | IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */ | 104 | IWL_DECLARE_RATE_INFO(11, INV, 9, 12), /* 11mbps */ |
105 | IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */ | 105 | IWL_DECLARE_RATE_INFO(6, 6, 5, 11), /* 6mbps */ |
106 | IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */ | 106 | IWL_DECLARE_RATE_INFO(9, 6, 6, 11), /* 9mbps */ |
107 | IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */ | 107 | IWL_DECLARE_RATE_INFO(12, 12, 11, 18), /* 12mbps */ |
108 | IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */ | 108 | IWL_DECLARE_RATE_INFO(18, 18, 12, 24), /* 18mbps */ |
109 | IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */ | 109 | IWL_DECLARE_RATE_INFO(24, 24, 18, 36), /* 24mbps */ |
110 | IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */ | 110 | IWL_DECLARE_RATE_INFO(36, 36, 24, 48), /* 36mbps */ |
111 | IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */ | 111 | IWL_DECLARE_RATE_INFO(48, 48, 36, 54), /* 48mbps */ |
112 | IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */ | 112 | IWL_DECLARE_RATE_INFO(54, 54, 48, INV), /* 54mbps */ |
113 | IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ | 113 | IWL_DECLARE_RATE_INFO(60, 60, 48, INV), /* 60mbps */ |
114 | /* FIXME:RS: ^^ should be INV (legacy) */ | 114 | /* FIXME:RS: ^^ should be INV (legacy) */ |
115 | }; | 115 | }; |
116 | 116 | ||
@@ -128,9 +128,8 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) | |||
128 | if (rate_n_flags & RATE_MCS_HT_MSK) { | 128 | if (rate_n_flags & RATE_MCS_HT_MSK) { |
129 | idx = rs_extract_rate(rate_n_flags); | 129 | idx = rs_extract_rate(rate_n_flags); |
130 | 130 | ||
131 | if (idx >= IWL_RATE_MIMO3_6M_PLCP) | 131 | WARN_ON_ONCE(idx >= IWL_RATE_MIMO3_6M_PLCP); |
132 | idx = idx - IWL_RATE_MIMO3_6M_PLCP; | 132 | if (idx >= IWL_RATE_MIMO2_6M_PLCP) |
133 | else if (idx >= IWL_RATE_MIMO2_6M_PLCP) | ||
134 | idx = idx - IWL_RATE_MIMO2_6M_PLCP; | 133 | idx = idx - IWL_RATE_MIMO2_6M_PLCP; |
135 | 134 | ||
136 | idx += IWL_FIRST_OFDM_RATE; | 135 | idx += IWL_FIRST_OFDM_RATE; |
@@ -162,10 +161,10 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); | |||
162 | 161 | ||
163 | #ifdef CONFIG_MAC80211_DEBUGFS | 162 | #ifdef CONFIG_MAC80211_DEBUGFS |
164 | static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, | 163 | static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, |
165 | u32 *rate_n_flags, int index); | 164 | u32 *rate_n_flags); |
166 | #else | 165 | #else |
167 | static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, | 166 | static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, |
168 | u32 *rate_n_flags, int index) | 167 | u32 *rate_n_flags) |
169 | {} | 168 | {} |
170 | #endif | 169 | #endif |
171 | 170 | ||
@@ -212,20 +211,6 @@ static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { | |||
212 | {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */ | 211 | {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */ |
213 | }; | 212 | }; |
214 | 213 | ||
215 | static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = { | ||
216 | {0, 0, 0, 0, 99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */ | ||
217 | {0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */ | ||
218 | {0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */ | ||
219 | {0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */ | ||
220 | }; | ||
221 | |||
222 | static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = { | ||
223 | {0, 0, 0, 0, 152, 0, 211, 239, 255, 279, 290, 294, 297}, /* Norm */ | ||
224 | {0, 0, 0, 0, 160, 0, 219, 245, 261, 284, 294, 297, 300}, /* SGI */ | ||
225 | {0, 0, 0, 0, 254, 0, 443, 584, 695, 868, 984, 1030, 1070}, /* AGG */ | ||
226 | {0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */ | ||
227 | }; | ||
228 | |||
229 | /* mbps, mcs */ | 214 | /* mbps, mcs */ |
230 | static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { | 215 | static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { |
231 | { "1", "BPSK DSSS"}, | 216 | { "1", "BPSK DSSS"}, |
@@ -260,82 +245,6 @@ static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) | |||
260 | return (ant_type & valid_antenna) == ant_type; | 245 | return (ant_type & valid_antenna) == ant_type; |
261 | } | 246 | } |
262 | 247 | ||
263 | /* | ||
264 | * removes the old data from the statistics. All data that is older than | ||
265 | * TID_MAX_TIME_DIFF, will be deleted. | ||
266 | */ | ||
267 | static void rs_tl_rm_old_stats(struct iwl_traffic_load *tl, u32 curr_time) | ||
268 | { | ||
269 | /* The oldest age we want to keep */ | ||
270 | u32 oldest_time = curr_time - TID_MAX_TIME_DIFF; | ||
271 | |||
272 | while (tl->queue_count && | ||
273 | (tl->time_stamp < oldest_time)) { | ||
274 | tl->total -= tl->packet_count[tl->head]; | ||
275 | tl->packet_count[tl->head] = 0; | ||
276 | tl->time_stamp += TID_QUEUE_CELL_SPACING; | ||
277 | tl->queue_count--; | ||
278 | tl->head++; | ||
279 | if (tl->head >= TID_QUEUE_MAX_SIZE) | ||
280 | tl->head = 0; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * increment traffic load value for tid and also remove | ||
286 | * any old values if passed the certain time period | ||
287 | */ | ||
288 | static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, | ||
289 | struct ieee80211_hdr *hdr) | ||
290 | { | ||
291 | u32 curr_time = jiffies_to_msecs(jiffies); | ||
292 | u32 time_diff; | ||
293 | s32 index; | ||
294 | struct iwl_traffic_load *tl = NULL; | ||
295 | u8 tid; | ||
296 | |||
297 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
298 | u8 *qc = ieee80211_get_qos_ctl(hdr); | ||
299 | tid = qc[0] & 0xf; | ||
300 | } else { | ||
301 | return IWL_MAX_TID_COUNT; | ||
302 | } | ||
303 | |||
304 | if (unlikely(tid >= IWL_MAX_TID_COUNT)) | ||
305 | return IWL_MAX_TID_COUNT; | ||
306 | |||
307 | tl = &lq_data->load[tid]; | ||
308 | |||
309 | curr_time -= curr_time % TID_ROUND_VALUE; | ||
310 | |||
311 | /* Happens only for the first packet. Initialize the data */ | ||
312 | if (!(tl->queue_count)) { | ||
313 | tl->total = 1; | ||
314 | tl->time_stamp = curr_time; | ||
315 | tl->queue_count = 1; | ||
316 | tl->head = 0; | ||
317 | tl->packet_count[0] = 1; | ||
318 | return IWL_MAX_TID_COUNT; | ||
319 | } | ||
320 | |||
321 | time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); | ||
322 | index = time_diff / TID_QUEUE_CELL_SPACING; | ||
323 | |||
324 | /* The history is too long: remove data that is older than */ | ||
325 | /* TID_MAX_TIME_DIFF */ | ||
326 | if (index >= TID_QUEUE_MAX_SIZE) | ||
327 | rs_tl_rm_old_stats(tl, curr_time); | ||
328 | |||
329 | index = (tl->head + index) % TID_QUEUE_MAX_SIZE; | ||
330 | tl->packet_count[index] = tl->packet_count[index] + 1; | ||
331 | tl->total = tl->total + 1; | ||
332 | |||
333 | if ((index + 1) > tl->queue_count) | ||
334 | tl->queue_count = index + 1; | ||
335 | |||
336 | return tid; | ||
337 | } | ||
338 | |||
339 | #ifdef CONFIG_MAC80211_DEBUGFS | 248 | #ifdef CONFIG_MAC80211_DEBUGFS |
340 | /** | 249 | /** |
341 | * Program the device to use fixed rate for frame transmit | 250 | * Program the device to use fixed rate for frame transmit |
@@ -349,7 +258,6 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm, | |||
349 | lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ | 258 | lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ |
350 | lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ | 259 | lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ |
351 | lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ | 260 | lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ |
352 | lq_sta->active_mimo3_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ | ||
353 | 261 | ||
354 | IWL_DEBUG_RATE(mvm, "sta_id %d rate 0x%X\n", | 262 | IWL_DEBUG_RATE(mvm, "sta_id %d rate 0x%X\n", |
355 | lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate); | 263 | lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate); |
@@ -361,45 +269,11 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm, | |||
361 | } | 269 | } |
362 | #endif | 270 | #endif |
363 | 271 | ||
364 | /* | ||
365 | get the traffic load value for tid | ||
366 | */ | ||
367 | static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid) | ||
368 | { | ||
369 | u32 curr_time = jiffies_to_msecs(jiffies); | ||
370 | u32 time_diff; | ||
371 | s32 index; | ||
372 | struct iwl_traffic_load *tl = NULL; | ||
373 | |||
374 | if (tid >= IWL_MAX_TID_COUNT) | ||
375 | return 0; | ||
376 | |||
377 | tl = &(lq_data->load[tid]); | ||
378 | |||
379 | curr_time -= curr_time % TID_ROUND_VALUE; | ||
380 | |||
381 | if (!(tl->queue_count)) | ||
382 | return 0; | ||
383 | |||
384 | time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); | ||
385 | index = time_diff / TID_QUEUE_CELL_SPACING; | ||
386 | |||
387 | /* The history is too long: remove data that is older than */ | ||
388 | /* TID_MAX_TIME_DIFF */ | ||
389 | if (index >= TID_QUEUE_MAX_SIZE) | ||
390 | rs_tl_rm_old_stats(tl, curr_time); | ||
391 | |||
392 | return tl->total; | ||
393 | } | ||
394 | |||
395 | static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm, | 272 | static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm, |
396 | struct iwl_lq_sta *lq_data, u8 tid, | 273 | struct iwl_lq_sta *lq_data, u8 tid, |
397 | struct ieee80211_sta *sta) | 274 | struct ieee80211_sta *sta) |
398 | { | 275 | { |
399 | int ret = -EAGAIN; | 276 | int ret = -EAGAIN; |
400 | u32 load; | ||
401 | |||
402 | load = rs_tl_get_load(lq_data, tid); | ||
403 | 277 | ||
404 | /* | 278 | /* |
405 | * Don't create TX aggregation sessions when in high | 279 | * Don't create TX aggregation sessions when in high |
@@ -563,7 +437,7 @@ static u32 rate_n_flags_from_tbl(struct iwl_mvm *mvm, | |||
563 | else if (is_mimo2(tbl->lq_type)) | 437 | else if (is_mimo2(tbl->lq_type)) |
564 | rate_n_flags |= iwl_rates[index].plcp_mimo2; | 438 | rate_n_flags |= iwl_rates[index].plcp_mimo2; |
565 | else | 439 | else |
566 | rate_n_flags |= iwl_rates[index].plcp_mimo3; | 440 | WARN_ON_ONCE(1); |
567 | } else { | 441 | } else { |
568 | IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type); | 442 | IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type); |
569 | } | 443 | } |
@@ -601,7 +475,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, | |||
601 | u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags); | 475 | u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags); |
602 | u8 mcs; | 476 | u8 mcs; |
603 | 477 | ||
604 | memset(tbl, 0, sizeof(struct iwl_scale_tbl_info)); | 478 | memset(tbl, 0, offsetof(struct iwl_scale_tbl_info, win)); |
605 | *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); | 479 | *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); |
606 | 480 | ||
607 | if (*rate_idx == IWL_RATE_INVALID) { | 481 | if (*rate_idx == IWL_RATE_INVALID) { |
@@ -640,12 +514,8 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, | |||
640 | } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) { | 514 | } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) { |
641 | if (num_of_ant == 2) | 515 | if (num_of_ant == 2) |
642 | tbl->lq_type = LQ_MIMO2; | 516 | tbl->lq_type = LQ_MIMO2; |
643 | /* MIMO3 */ | ||
644 | } else { | 517 | } else { |
645 | if (num_of_ant == 3) { | 518 | WARN_ON_ONCE(num_of_ant == 3); |
646 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | ||
647 | tbl->lq_type = LQ_MIMO3; | ||
648 | } | ||
649 | } | 519 | } |
650 | } | 520 | } |
651 | return 0; | 521 | return 0; |
@@ -711,10 +581,10 @@ static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta, | |||
711 | } else { | 581 | } else { |
712 | if (is_siso(rate_type)) | 582 | if (is_siso(rate_type)) |
713 | return lq_sta->active_siso_rate; | 583 | return lq_sta->active_siso_rate; |
714 | else if (is_mimo2(rate_type)) | 584 | else { |
585 | WARN_ON_ONCE(!is_mimo2(rate_type)); | ||
715 | return lq_sta->active_mimo2_rate; | 586 | return lq_sta->active_mimo2_rate; |
716 | else | 587 | } |
717 | return lq_sta->active_mimo3_rate; | ||
718 | } | 588 | } |
719 | } | 589 | } |
720 | 590 | ||
@@ -1089,7 +959,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | |||
1089 | } | 959 | } |
1090 | 960 | ||
1091 | /* Choose among many HT tables depending on number of streams | 961 | /* Choose among many HT tables depending on number of streams |
1092 | * (SISO/MIMO2/MIMO3), channel width (20/40), SGI, and aggregation | 962 | * (SISO/MIMO2), channel width (20/40), SGI, and aggregation |
1093 | * status */ | 963 | * status */ |
1094 | if (is_siso(tbl->lq_type) && !tbl->is_ht40) | 964 | if (is_siso(tbl->lq_type) && !tbl->is_ht40) |
1095 | ht_tbl_pointer = expected_tpt_siso20MHz; | 965 | ht_tbl_pointer = expected_tpt_siso20MHz; |
@@ -1097,12 +967,10 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | |||
1097 | ht_tbl_pointer = expected_tpt_siso40MHz; | 967 | ht_tbl_pointer = expected_tpt_siso40MHz; |
1098 | else if (is_mimo2(tbl->lq_type) && !tbl->is_ht40) | 968 | else if (is_mimo2(tbl->lq_type) && !tbl->is_ht40) |
1099 | ht_tbl_pointer = expected_tpt_mimo2_20MHz; | 969 | ht_tbl_pointer = expected_tpt_mimo2_20MHz; |
1100 | else if (is_mimo2(tbl->lq_type)) | 970 | else { |
971 | WARN_ON_ONCE(!is_mimo2(tbl->lq_type)); | ||
1101 | ht_tbl_pointer = expected_tpt_mimo2_40MHz; | 972 | ht_tbl_pointer = expected_tpt_mimo2_40MHz; |
1102 | else if (is_mimo3(tbl->lq_type) && !tbl->is_ht40) | 973 | } |
1103 | ht_tbl_pointer = expected_tpt_mimo3_20MHz; | ||
1104 | else /* if (is_mimo3(tbl->lq_type)) <-- must be true */ | ||
1105 | ht_tbl_pointer = expected_tpt_mimo3_40MHz; | ||
1106 | 974 | ||
1107 | if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */ | 975 | if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */ |
1108 | tbl->expected_tpt = ht_tbl_pointer[0]; | 976 | tbl->expected_tpt = ht_tbl_pointer[0]; |
@@ -1274,58 +1142,6 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | |||
1274 | } | 1142 | } |
1275 | 1143 | ||
1276 | /* | 1144 | /* |
1277 | * Set up search table for MIMO3 | ||
1278 | */ | ||
1279 | static int rs_switch_to_mimo3(struct iwl_mvm *mvm, | ||
1280 | struct iwl_lq_sta *lq_sta, | ||
1281 | struct ieee80211_sta *sta, | ||
1282 | struct iwl_scale_tbl_info *tbl, int index) | ||
1283 | { | ||
1284 | u16 rate_mask; | ||
1285 | s32 rate; | ||
1286 | s8 is_green = lq_sta->is_green; | ||
1287 | |||
1288 | if (!sta->ht_cap.ht_supported) | ||
1289 | return -1; | ||
1290 | |||
1291 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) | ||
1292 | return -1; | ||
1293 | |||
1294 | /* Need both Tx chains/antennas to support MIMO */ | ||
1295 | if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 3) | ||
1296 | return -1; | ||
1297 | |||
1298 | IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO3\n"); | ||
1299 | |||
1300 | tbl->lq_type = LQ_MIMO3; | ||
1301 | tbl->action = 0; | ||
1302 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | ||
1303 | rate_mask = lq_sta->active_mimo3_rate; | ||
1304 | |||
1305 | if (iwl_is_ht40_tx_allowed(sta)) | ||
1306 | tbl->is_ht40 = 1; | ||
1307 | else | ||
1308 | tbl->is_ht40 = 0; | ||
1309 | |||
1310 | rs_set_expected_tpt_table(lq_sta, tbl); | ||
1311 | |||
1312 | rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index); | ||
1313 | |||
1314 | IWL_DEBUG_RATE(mvm, "LQ: MIMO3 best rate %d mask %X\n", | ||
1315 | rate, rate_mask); | ||
1316 | if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { | ||
1317 | IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n", | ||
1318 | rate, rate_mask); | ||
1319 | return -1; | ||
1320 | } | ||
1321 | tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green); | ||
1322 | |||
1323 | IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n", | ||
1324 | tbl->current_rate, is_green); | ||
1325 | return 0; | ||
1326 | } | ||
1327 | |||
1328 | /* | ||
1329 | * Set up search table for SISO | 1145 | * Set up search table for SISO |
1330 | */ | 1146 | */ |
1331 | static int rs_switch_to_siso(struct iwl_mvm *mvm, | 1147 | static int rs_switch_to_siso(struct iwl_mvm *mvm, |
@@ -1434,21 +1250,14 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, | |||
1434 | } | 1250 | } |
1435 | 1251 | ||
1436 | break; | 1252 | break; |
1437 | case IWL_LEGACY_SWITCH_MIMO2_AB: | 1253 | case IWL_LEGACY_SWITCH_MIMO2: |
1438 | case IWL_LEGACY_SWITCH_MIMO2_AC: | ||
1439 | case IWL_LEGACY_SWITCH_MIMO2_BC: | ||
1440 | IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO2\n"); | 1254 | IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO2\n"); |
1441 | 1255 | ||
1442 | /* Set up search table to try MIMO */ | 1256 | /* Set up search table to try MIMO */ |
1443 | memcpy(search_tbl, tbl, sz); | 1257 | memcpy(search_tbl, tbl, sz); |
1444 | search_tbl->is_SGI = 0; | 1258 | search_tbl->is_SGI = 0; |
1445 | 1259 | ||
1446 | if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB) | 1260 | search_tbl->ant_type = ANT_AB; |
1447 | search_tbl->ant_type = ANT_AB; | ||
1448 | else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC) | ||
1449 | search_tbl->ant_type = ANT_AC; | ||
1450 | else | ||
1451 | search_tbl->ant_type = ANT_BC; | ||
1452 | 1261 | ||
1453 | if (!rs_is_valid_ant(valid_tx_ant, | 1262 | if (!rs_is_valid_ant(valid_tx_ant, |
1454 | search_tbl->ant_type)) | 1263 | search_tbl->ant_type)) |
@@ -1461,30 +1270,11 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, | |||
1461 | goto out; | 1270 | goto out; |
1462 | } | 1271 | } |
1463 | break; | 1272 | break; |
1464 | 1273 | default: | |
1465 | case IWL_LEGACY_SWITCH_MIMO3_ABC: | 1274 | WARN_ON_ONCE(1); |
1466 | IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO3\n"); | ||
1467 | |||
1468 | /* Set up search table to try MIMO3 */ | ||
1469 | memcpy(search_tbl, tbl, sz); | ||
1470 | search_tbl->is_SGI = 0; | ||
1471 | |||
1472 | search_tbl->ant_type = ANT_ABC; | ||
1473 | |||
1474 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1475 | search_tbl->ant_type)) | ||
1476 | break; | ||
1477 | |||
1478 | ret = rs_switch_to_mimo3(mvm, lq_sta, sta, | ||
1479 | search_tbl, index); | ||
1480 | if (!ret) { | ||
1481 | lq_sta->action_counter = 0; | ||
1482 | goto out; | ||
1483 | } | ||
1484 | break; | ||
1485 | } | 1275 | } |
1486 | tbl->action++; | 1276 | tbl->action++; |
1487 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) | 1277 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) |
1488 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; | 1278 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; |
1489 | 1279 | ||
1490 | if (tbl->action == start_action) | 1280 | if (tbl->action == start_action) |
@@ -1496,7 +1286,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, | |||
1496 | out: | 1286 | out: |
1497 | lq_sta->search_better_tbl = 1; | 1287 | lq_sta->search_better_tbl = 1; |
1498 | tbl->action++; | 1288 | tbl->action++; |
1499 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) | 1289 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) |
1500 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; | 1290 | tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; |
1501 | if (update_search_tbl_counter) | 1291 | if (update_search_tbl_counter) |
1502 | search_tbl->action = tbl->action; | 1292 | search_tbl->action = tbl->action; |
@@ -1531,7 +1321,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, | |||
1531 | case IWL_BT_COEX_TRAFFIC_LOAD_LOW: | 1321 | case IWL_BT_COEX_TRAFFIC_LOAD_LOW: |
1532 | /* avoid antenna B unless MIMO */ | 1322 | /* avoid antenna B unless MIMO */ |
1533 | if (tbl->action == IWL_SISO_SWITCH_ANTENNA2) | 1323 | if (tbl->action == IWL_SISO_SWITCH_ANTENNA2) |
1534 | tbl->action = IWL_SISO_SWITCH_MIMO2_AB; | 1324 | tbl->action = IWL_SISO_SWITCH_MIMO2; |
1535 | break; | 1325 | break; |
1536 | case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: | 1326 | case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: |
1537 | case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: | 1327 | case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: |
@@ -1573,19 +1363,12 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, | |||
1573 | goto out; | 1363 | goto out; |
1574 | } | 1364 | } |
1575 | break; | 1365 | break; |
1576 | case IWL_SISO_SWITCH_MIMO2_AB: | 1366 | case IWL_SISO_SWITCH_MIMO2: |
1577 | case IWL_SISO_SWITCH_MIMO2_AC: | ||
1578 | case IWL_SISO_SWITCH_MIMO2_BC: | ||
1579 | IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n"); | 1367 | IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n"); |
1580 | memcpy(search_tbl, tbl, sz); | 1368 | memcpy(search_tbl, tbl, sz); |
1581 | search_tbl->is_SGI = 0; | 1369 | search_tbl->is_SGI = 0; |
1582 | 1370 | ||
1583 | if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB) | 1371 | search_tbl->ant_type = ANT_AB; |
1584 | search_tbl->ant_type = ANT_AB; | ||
1585 | else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC) | ||
1586 | search_tbl->ant_type = ANT_AC; | ||
1587 | else | ||
1588 | search_tbl->ant_type = ANT_BC; | ||
1589 | 1372 | ||
1590 | if (!rs_is_valid_ant(valid_tx_ant, | 1373 | if (!rs_is_valid_ant(valid_tx_ant, |
1591 | search_tbl->ant_type)) | 1374 | search_tbl->ant_type)) |
@@ -1626,24 +1409,11 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, | |||
1626 | index, is_green); | 1409 | index, is_green); |
1627 | update_search_tbl_counter = 1; | 1410 | update_search_tbl_counter = 1; |
1628 | goto out; | 1411 | goto out; |
1629 | case IWL_SISO_SWITCH_MIMO3_ABC: | 1412 | default: |
1630 | IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO3\n"); | 1413 | WARN_ON_ONCE(1); |
1631 | memcpy(search_tbl, tbl, sz); | ||
1632 | search_tbl->is_SGI = 0; | ||
1633 | search_tbl->ant_type = ANT_ABC; | ||
1634 | |||
1635 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1636 | search_tbl->ant_type)) | ||
1637 | break; | ||
1638 | |||
1639 | ret = rs_switch_to_mimo3(mvm, lq_sta, sta, | ||
1640 | search_tbl, index); | ||
1641 | if (!ret) | ||
1642 | goto out; | ||
1643 | break; | ||
1644 | } | 1414 | } |
1645 | tbl->action++; | 1415 | tbl->action++; |
1646 | if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) | 1416 | if (tbl->action > IWL_SISO_SWITCH_GI) |
1647 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; | 1417 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; |
1648 | 1418 | ||
1649 | if (tbl->action == start_action) | 1419 | if (tbl->action == start_action) |
@@ -1655,7 +1425,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, | |||
1655 | out: | 1425 | out: |
1656 | lq_sta->search_better_tbl = 1; | 1426 | lq_sta->search_better_tbl = 1; |
1657 | tbl->action++; | 1427 | tbl->action++; |
1658 | if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC) | 1428 | if (tbl->action > IWL_SISO_SWITCH_GI) |
1659 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; | 1429 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; |
1660 | if (update_search_tbl_counter) | 1430 | if (update_search_tbl_counter) |
1661 | search_tbl->action = tbl->action; | 1431 | search_tbl->action = tbl->action; |
@@ -1696,8 +1466,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | |||
1696 | break; | 1466 | break; |
1697 | case IWL_BT_COEX_TRAFFIC_LOAD_LOW: | 1467 | case IWL_BT_COEX_TRAFFIC_LOAD_LOW: |
1698 | /* avoid antenna B unless MIMO */ | 1468 | /* avoid antenna B unless MIMO */ |
1699 | if (tbl->action == IWL_MIMO2_SWITCH_SISO_B || | 1469 | if (tbl->action == IWL_MIMO2_SWITCH_SISO_B) |
1700 | tbl->action == IWL_MIMO2_SWITCH_SISO_C) | ||
1701 | tbl->action = IWL_MIMO2_SWITCH_SISO_A; | 1470 | tbl->action = IWL_MIMO2_SWITCH_SISO_A; |
1702 | break; | 1471 | break; |
1703 | default: | 1472 | default: |
@@ -1730,7 +1499,6 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | |||
1730 | break; | 1499 | break; |
1731 | case IWL_MIMO2_SWITCH_SISO_A: | 1500 | case IWL_MIMO2_SWITCH_SISO_A: |
1732 | case IWL_MIMO2_SWITCH_SISO_B: | 1501 | case IWL_MIMO2_SWITCH_SISO_B: |
1733 | case IWL_MIMO2_SWITCH_SISO_C: | ||
1734 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n"); | 1502 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n"); |
1735 | 1503 | ||
1736 | /* Set up new search table for SISO */ | 1504 | /* Set up new search table for SISO */ |
@@ -1738,10 +1506,8 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | |||
1738 | 1506 | ||
1739 | if (tbl->action == IWL_MIMO2_SWITCH_SISO_A) | 1507 | if (tbl->action == IWL_MIMO2_SWITCH_SISO_A) |
1740 | search_tbl->ant_type = ANT_A; | 1508 | search_tbl->ant_type = ANT_A; |
1741 | else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B) | 1509 | else /* tbl->action == IWL_MIMO2_SWITCH_SISO_B */ |
1742 | search_tbl->ant_type = ANT_B; | 1510 | search_tbl->ant_type = ANT_B; |
1743 | else | ||
1744 | search_tbl->ant_type = ANT_C; | ||
1745 | 1511 | ||
1746 | if (!rs_is_valid_ant(valid_tx_ant, | 1512 | if (!rs_is_valid_ant(valid_tx_ant, |
1747 | search_tbl->ant_type)) | 1513 | search_tbl->ant_type)) |
@@ -1784,26 +1550,11 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | |||
1784 | index, is_green); | 1550 | index, is_green); |
1785 | update_search_tbl_counter = 1; | 1551 | update_search_tbl_counter = 1; |
1786 | goto out; | 1552 | goto out; |
1787 | 1553 | default: | |
1788 | case IWL_MIMO2_SWITCH_MIMO3_ABC: | 1554 | WARN_ON_ONCE(1); |
1789 | IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to MIMO3\n"); | ||
1790 | memcpy(search_tbl, tbl, sz); | ||
1791 | search_tbl->is_SGI = 0; | ||
1792 | search_tbl->ant_type = ANT_ABC; | ||
1793 | |||
1794 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1795 | search_tbl->ant_type)) | ||
1796 | break; | ||
1797 | |||
1798 | ret = rs_switch_to_mimo3(mvm, lq_sta, sta, | ||
1799 | search_tbl, index); | ||
1800 | if (!ret) | ||
1801 | goto out; | ||
1802 | |||
1803 | break; | ||
1804 | } | 1555 | } |
1805 | tbl->action++; | 1556 | tbl->action++; |
1806 | if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC) | 1557 | if (tbl->action > IWL_MIMO2_SWITCH_GI) |
1807 | tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; | 1558 | tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; |
1808 | 1559 | ||
1809 | if (tbl->action == start_action) | 1560 | if (tbl->action == start_action) |
@@ -1814,7 +1565,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | |||
1814 | out: | 1565 | out: |
1815 | lq_sta->search_better_tbl = 1; | 1566 | lq_sta->search_better_tbl = 1; |
1816 | tbl->action++; | 1567 | tbl->action++; |
1817 | if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC) | 1568 | if (tbl->action > IWL_MIMO2_SWITCH_GI) |
1818 | tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; | 1569 | tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; |
1819 | if (update_search_tbl_counter) | 1570 | if (update_search_tbl_counter) |
1820 | search_tbl->action = tbl->action; | 1571 | search_tbl->action = tbl->action; |
@@ -1823,171 +1574,6 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | |||
1823 | } | 1574 | } |
1824 | 1575 | ||
1825 | /* | 1576 | /* |
1826 | * Try to switch to new modulation mode from MIMO3 | ||
1827 | */ | ||
1828 | static int rs_move_mimo3_to_other(struct iwl_mvm *mvm, | ||
1829 | struct iwl_lq_sta *lq_sta, | ||
1830 | struct ieee80211_sta *sta, int index) | ||
1831 | { | ||
1832 | s8 is_green = lq_sta->is_green; | ||
1833 | struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); | ||
1834 | struct iwl_scale_tbl_info *search_tbl = | ||
1835 | &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | ||
1836 | struct iwl_rate_scale_data *window = &(tbl->win[index]); | ||
1837 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | ||
1838 | u32 sz = (sizeof(struct iwl_scale_tbl_info) - | ||
1839 | (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); | ||
1840 | u8 start_action; | ||
1841 | u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); | ||
1842 | u8 tx_chains_num = num_of_ant(valid_tx_ant); | ||
1843 | int ret; | ||
1844 | u8 update_search_tbl_counter = 0; | ||
1845 | |||
1846 | switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { | ||
1847 | case IWL_BT_COEX_TRAFFIC_LOAD_NONE: | ||
1848 | /* nothing */ | ||
1849 | break; | ||
1850 | case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: | ||
1851 | case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: | ||
1852 | /* avoid antenna B and MIMO */ | ||
1853 | if (tbl->action != IWL_MIMO3_SWITCH_SISO_A) | ||
1854 | tbl->action = IWL_MIMO3_SWITCH_SISO_A; | ||
1855 | break; | ||
1856 | case IWL_BT_COEX_TRAFFIC_LOAD_LOW: | ||
1857 | /* avoid antenna B unless MIMO */ | ||
1858 | if (tbl->action == IWL_MIMO3_SWITCH_SISO_B || | ||
1859 | tbl->action == IWL_MIMO3_SWITCH_SISO_C) | ||
1860 | tbl->action = IWL_MIMO3_SWITCH_SISO_A; | ||
1861 | break; | ||
1862 | default: | ||
1863 | IWL_ERR(mvm, "Invalid BT load %d", | ||
1864 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)); | ||
1865 | break; | ||
1866 | } | ||
1867 | |||
1868 | start_action = tbl->action; | ||
1869 | while (1) { | ||
1870 | lq_sta->action_counter++; | ||
1871 | switch (tbl->action) { | ||
1872 | case IWL_MIMO3_SWITCH_ANTENNA1: | ||
1873 | case IWL_MIMO3_SWITCH_ANTENNA2: | ||
1874 | IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle Antennas\n"); | ||
1875 | |||
1876 | if (tx_chains_num <= 3) | ||
1877 | break; | ||
1878 | |||
1879 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) | ||
1880 | break; | ||
1881 | |||
1882 | memcpy(search_tbl, tbl, sz); | ||
1883 | if (rs_toggle_antenna(valid_tx_ant, | ||
1884 | &search_tbl->current_rate, | ||
1885 | search_tbl)) | ||
1886 | goto out; | ||
1887 | break; | ||
1888 | case IWL_MIMO3_SWITCH_SISO_A: | ||
1889 | case IWL_MIMO3_SWITCH_SISO_B: | ||
1890 | case IWL_MIMO3_SWITCH_SISO_C: | ||
1891 | IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to SISO\n"); | ||
1892 | |||
1893 | /* Set up new search table for SISO */ | ||
1894 | memcpy(search_tbl, tbl, sz); | ||
1895 | |||
1896 | if (tbl->action == IWL_MIMO3_SWITCH_SISO_A) | ||
1897 | search_tbl->ant_type = ANT_A; | ||
1898 | else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B) | ||
1899 | search_tbl->ant_type = ANT_B; | ||
1900 | else | ||
1901 | search_tbl->ant_type = ANT_C; | ||
1902 | |||
1903 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1904 | search_tbl->ant_type)) | ||
1905 | break; | ||
1906 | |||
1907 | ret = rs_switch_to_siso(mvm, lq_sta, sta, | ||
1908 | search_tbl, index); | ||
1909 | if (!ret) | ||
1910 | goto out; | ||
1911 | |||
1912 | break; | ||
1913 | |||
1914 | case IWL_MIMO3_SWITCH_MIMO2_AB: | ||
1915 | case IWL_MIMO3_SWITCH_MIMO2_AC: | ||
1916 | case IWL_MIMO3_SWITCH_MIMO2_BC: | ||
1917 | IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to MIMO2\n"); | ||
1918 | |||
1919 | memcpy(search_tbl, tbl, sz); | ||
1920 | search_tbl->is_SGI = 0; | ||
1921 | if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB) | ||
1922 | search_tbl->ant_type = ANT_AB; | ||
1923 | else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC) | ||
1924 | search_tbl->ant_type = ANT_AC; | ||
1925 | else | ||
1926 | search_tbl->ant_type = ANT_BC; | ||
1927 | |||
1928 | if (!rs_is_valid_ant(valid_tx_ant, | ||
1929 | search_tbl->ant_type)) | ||
1930 | break; | ||
1931 | |||
1932 | ret = rs_switch_to_mimo2(mvm, lq_sta, sta, | ||
1933 | search_tbl, index); | ||
1934 | if (!ret) | ||
1935 | goto out; | ||
1936 | |||
1937 | break; | ||
1938 | |||
1939 | case IWL_MIMO3_SWITCH_GI: | ||
1940 | if (!tbl->is_ht40 && !(ht_cap->cap & | ||
1941 | IEEE80211_HT_CAP_SGI_20)) | ||
1942 | break; | ||
1943 | if (tbl->is_ht40 && !(ht_cap->cap & | ||
1944 | IEEE80211_HT_CAP_SGI_40)) | ||
1945 | break; | ||
1946 | |||
1947 | IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle SGI/NGI\n"); | ||
1948 | |||
1949 | /* Set up new search table for MIMO */ | ||
1950 | memcpy(search_tbl, tbl, sz); | ||
1951 | search_tbl->is_SGI = !tbl->is_SGI; | ||
1952 | rs_set_expected_tpt_table(lq_sta, search_tbl); | ||
1953 | /* | ||
1954 | * If active table already uses the fastest possible | ||
1955 | * modulation (dual stream with short guard interval), | ||
1956 | * and it's working well, there's no need to look | ||
1957 | * for a better type of modulation! | ||
1958 | */ | ||
1959 | if (tbl->is_SGI) { | ||
1960 | s32 tpt = lq_sta->last_tpt / 100; | ||
1961 | if (tpt >= search_tbl->expected_tpt[index]) | ||
1962 | break; | ||
1963 | } | ||
1964 | search_tbl->current_rate = | ||
1965 | rate_n_flags_from_tbl(mvm, search_tbl, | ||
1966 | index, is_green); | ||
1967 | update_search_tbl_counter = 1; | ||
1968 | goto out; | ||
1969 | } | ||
1970 | tbl->action++; | ||
1971 | if (tbl->action > IWL_MIMO3_SWITCH_GI) | ||
1972 | tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; | ||
1973 | |||
1974 | if (tbl->action == start_action) | ||
1975 | break; | ||
1976 | } | ||
1977 | search_tbl->lq_type = LQ_NONE; | ||
1978 | return 0; | ||
1979 | out: | ||
1980 | lq_sta->search_better_tbl = 1; | ||
1981 | tbl->action++; | ||
1982 | if (tbl->action > IWL_MIMO3_SWITCH_GI) | ||
1983 | tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; | ||
1984 | if (update_search_tbl_counter) | ||
1985 | search_tbl->action = tbl->action; | ||
1986 | |||
1987 | return 0; | ||
1988 | } | ||
1989 | |||
1990 | /* | ||
1991 | * Check whether we should continue using same modulation mode, or | 1577 | * Check whether we should continue using same modulation mode, or |
1992 | * begin search for a new mode, based on: | 1578 | * begin search for a new mode, based on: |
1993 | * 1) # tx successes or failures while using this mode | 1579 | * 1) # tx successes or failures while using this mode |
@@ -2086,6 +1672,22 @@ static void rs_update_rate_tbl(struct iwl_mvm *mvm, | |||
2086 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); | 1672 | iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false); |
2087 | } | 1673 | } |
2088 | 1674 | ||
1675 | static u8 rs_get_tid(struct iwl_lq_sta *lq_data, | ||
1676 | struct ieee80211_hdr *hdr) | ||
1677 | { | ||
1678 | u8 tid = IWL_MAX_TID_COUNT; | ||
1679 | |||
1680 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
1681 | u8 *qc = ieee80211_get_qos_ctl(hdr); | ||
1682 | tid = qc[0] & 0xf; | ||
1683 | } | ||
1684 | |||
1685 | if (unlikely(tid > IWL_MAX_TID_COUNT)) | ||
1686 | tid = IWL_MAX_TID_COUNT; | ||
1687 | |||
1688 | return tid; | ||
1689 | } | ||
1690 | |||
2089 | /* | 1691 | /* |
2090 | * Do rate scaling and search for new modulation mode. | 1692 | * Do rate scaling and search for new modulation mode. |
2091 | */ | 1693 | */ |
@@ -2129,7 +1731,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
2129 | 1731 | ||
2130 | lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; | 1732 | lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; |
2131 | 1733 | ||
2132 | tid = rs_tl_add_packet(lq_sta, hdr); | 1734 | tid = rs_get_tid(lq_sta, hdr); |
2133 | if ((tid != IWL_MAX_TID_COUNT) && | 1735 | if ((tid != IWL_MAX_TID_COUNT) && |
2134 | (lq_sta->tx_agg_tid_en & (1 << tid))) { | 1736 | (lq_sta->tx_agg_tid_en & (1 << tid))) { |
2135 | tid_data = &sta_priv->tid_data[tid]; | 1737 | tid_data = &sta_priv->tid_data[tid]; |
@@ -2377,8 +1979,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
2377 | scale_action = 0; | 1979 | scale_action = 0; |
2378 | 1980 | ||
2379 | if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= | 1981 | if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= |
2380 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && | 1982 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && (is_mimo(tbl->lq_type))) { |
2381 | (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) { | ||
2382 | if (lq_sta->last_bt_traffic > | 1983 | if (lq_sta->last_bt_traffic > |
2383 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { | 1984 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { |
2384 | /* | 1985 | /* |
@@ -2395,8 +1996,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
2395 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD); | 1996 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD); |
2396 | 1997 | ||
2397 | if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= | 1998 | if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= |
2398 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && | 1999 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && is_mimo(tbl->lq_type)) { |
2399 | (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) { | ||
2400 | /* search for a new modulation */ | 2000 | /* search for a new modulation */ |
2401 | rs_stay_in_table(lq_sta, true); | 2001 | rs_stay_in_table(lq_sta, true); |
2402 | goto lq_update; | 2002 | goto lq_update; |
@@ -2456,7 +2056,7 @@ lq_update: | |||
2456 | else if (is_mimo2(tbl->lq_type)) | 2056 | else if (is_mimo2(tbl->lq_type)) |
2457 | rs_move_mimo2_to_other(mvm, lq_sta, sta, index); | 2057 | rs_move_mimo2_to_other(mvm, lq_sta, sta, index); |
2458 | else | 2058 | else |
2459 | rs_move_mimo3_to_other(mvm, lq_sta, sta, index); | 2059 | WARN_ON_ONCE(1); |
2460 | 2060 | ||
2461 | /* If new "search" mode was selected, set up in uCode table */ | 2061 | /* If new "search" mode was selected, set up in uCode table */ |
2462 | if (lq_sta->search_better_tbl) { | 2062 | if (lq_sta->search_better_tbl) { |
@@ -2621,11 +2221,10 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, | |||
2621 | rate_idx -= IWL_FIRST_OFDM_RATE; | 2221 | rate_idx -= IWL_FIRST_OFDM_RATE; |
2622 | /* 6M and 9M shared same MCS index */ | 2222 | /* 6M and 9M shared same MCS index */ |
2623 | rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0; | 2223 | rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0; |
2224 | WARN_ON_ONCE(rs_extract_rate(lq_sta->last_rate_n_flags) >= | ||
2225 | IWL_RATE_MIMO3_6M_PLCP); | ||
2624 | if (rs_extract_rate(lq_sta->last_rate_n_flags) >= | 2226 | if (rs_extract_rate(lq_sta->last_rate_n_flags) >= |
2625 | IWL_RATE_MIMO3_6M_PLCP) | 2227 | IWL_RATE_MIMO2_6M_PLCP) |
2626 | rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM); | ||
2627 | else if (rs_extract_rate(lq_sta->last_rate_n_flags) >= | ||
2628 | IWL_RATE_MIMO2_6M_PLCP) | ||
2629 | rate_idx = rate_idx + MCS_INDEX_PER_STREAM; | 2228 | rate_idx = rate_idx + MCS_INDEX_PER_STREAM; |
2630 | info->control.rates[0].flags = IEEE80211_TX_RC_MCS; | 2229 | info->control.rates[0].flags = IEEE80211_TX_RC_MCS; |
2631 | if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK) | 2230 | if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK) |
@@ -2688,9 +2287,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2688 | 2287 | ||
2689 | lq_sta->flush_timer = 0; | 2288 | lq_sta->flush_timer = 0; |
2690 | lq_sta->supp_rates = sta->supp_rates[sband->band]; | 2289 | lq_sta->supp_rates = sta->supp_rates[sband->band]; |
2691 | for (j = 0; j < LQ_SIZE; j++) | ||
2692 | for (i = 0; i < IWL_RATE_COUNT; i++) | ||
2693 | rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); | ||
2694 | 2290 | ||
2695 | IWL_DEBUG_RATE(mvm, | 2291 | IWL_DEBUG_RATE(mvm, |
2696 | "LQ: *** rate scale station global init for station %d ***\n", | 2292 | "LQ: *** rate scale station global init for station %d ***\n", |
@@ -2727,16 +2323,10 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2727 | lq_sta->active_mimo2_rate &= ~((u16)0x2); | 2323 | lq_sta->active_mimo2_rate &= ~((u16)0x2); |
2728 | lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; | 2324 | lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; |
2729 | 2325 | ||
2730 | lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1; | ||
2731 | lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1; | ||
2732 | lq_sta->active_mimo3_rate &= ~((u16)0x2); | ||
2733 | lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; | ||
2734 | |||
2735 | IWL_DEBUG_RATE(mvm, | 2326 | IWL_DEBUG_RATE(mvm, |
2736 | "SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n", | 2327 | "SISO-RATE=%X MIMO2-RATE=%X\n", |
2737 | lq_sta->active_siso_rate, | 2328 | lq_sta->active_siso_rate, |
2738 | lq_sta->active_mimo2_rate, | 2329 | lq_sta->active_mimo2_rate); |
2739 | lq_sta->active_mimo3_rate); | ||
2740 | 2330 | ||
2741 | /* These values will be overridden later */ | 2331 | /* These values will be overridden later */ |
2742 | lq_sta->lq.single_stream_ant_msk = | 2332 | lq_sta->lq.single_stream_ant_msk = |
@@ -2780,7 +2370,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, | |||
2780 | struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; | 2370 | struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; |
2781 | 2371 | ||
2782 | /* Override starting rate (index 0) if needed for debug purposes */ | 2372 | /* Override starting rate (index 0) if needed for debug purposes */ |
2783 | rs_dbgfs_set_mcs(lq_sta, &new_rate, index); | 2373 | rs_dbgfs_set_mcs(lq_sta, &new_rate); |
2784 | 2374 | ||
2785 | /* Interpret new_rate (rate_n_flags) */ | 2375 | /* Interpret new_rate (rate_n_flags) */ |
2786 | rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, | 2376 | rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, |
@@ -2827,7 +2417,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, | |||
2827 | } | 2417 | } |
2828 | 2418 | ||
2829 | /* Override next rate if needed for debug purposes */ | 2419 | /* Override next rate if needed for debug purposes */ |
2830 | rs_dbgfs_set_mcs(lq_sta, &new_rate, index); | 2420 | rs_dbgfs_set_mcs(lq_sta, &new_rate); |
2831 | 2421 | ||
2832 | /* Fill next table entry */ | 2422 | /* Fill next table entry */ |
2833 | lq_cmd->rs_table[index] = | 2423 | lq_cmd->rs_table[index] = |
@@ -2869,7 +2459,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, | |||
2869 | use_ht_possible = 0; | 2459 | use_ht_possible = 0; |
2870 | 2460 | ||
2871 | /* Override next rate if needed for debug purposes */ | 2461 | /* Override next rate if needed for debug purposes */ |
2872 | rs_dbgfs_set_mcs(lq_sta, &new_rate, index); | 2462 | rs_dbgfs_set_mcs(lq_sta, &new_rate); |
2873 | 2463 | ||
2874 | /* Fill next table entry */ | 2464 | /* Fill next table entry */ |
2875 | lq_cmd->rs_table[index] = cpu_to_le32(new_rate); | 2465 | lq_cmd->rs_table[index] = cpu_to_le32(new_rate); |
@@ -2914,7 +2504,7 @@ static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta, | |||
2914 | 2504 | ||
2915 | #ifdef CONFIG_MAC80211_DEBUGFS | 2505 | #ifdef CONFIG_MAC80211_DEBUGFS |
2916 | static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, | 2506 | static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, |
2917 | u32 *rate_n_flags, int index) | 2507 | u32 *rate_n_flags) |
2918 | { | 2508 | { |
2919 | struct iwl_mvm *mvm; | 2509 | struct iwl_mvm *mvm; |
2920 | u8 valid_tx_ant; | 2510 | u8 valid_tx_ant; |
@@ -2999,8 +2589,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | |||
2999 | (is_legacy(tbl->lq_type)) ? "legacy" : "HT"); | 2589 | (is_legacy(tbl->lq_type)) ? "legacy" : "HT"); |
3000 | if (is_Ht(tbl->lq_type)) { | 2590 | if (is_Ht(tbl->lq_type)) { |
3001 | desc += sprintf(buff+desc, " %s", | 2591 | desc += sprintf(buff+desc, " %s", |
3002 | (is_siso(tbl->lq_type)) ? "SISO" : | 2592 | (is_siso(tbl->lq_type)) ? "SISO" : "MIMO2"); |
3003 | ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); | ||
3004 | desc += sprintf(buff+desc, " %s", | 2593 | desc += sprintf(buff+desc, " %s", |
3005 | (tbl->is_ht40) ? "40MHz" : "20MHz"); | 2594 | (tbl->is_ht40) ? "40MHz" : "20MHz"); |
3006 | desc += sprintf(buff+desc, " %s %s %s\n", | 2595 | desc += sprintf(buff+desc, " %s %s %s\n", |
@@ -3100,32 +2689,6 @@ static const struct file_operations rs_sta_dbgfs_stats_table_ops = { | |||
3100 | .llseek = default_llseek, | 2689 | .llseek = default_llseek, |
3101 | }; | 2690 | }; |
3102 | 2691 | ||
3103 | static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, | ||
3104 | char __user *user_buf, size_t count, loff_t *ppos) | ||
3105 | { | ||
3106 | struct iwl_lq_sta *lq_sta = file->private_data; | ||
3107 | struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl]; | ||
3108 | char buff[120]; | ||
3109 | int desc = 0; | ||
3110 | |||
3111 | if (is_Ht(tbl->lq_type)) | ||
3112 | desc += sprintf(buff+desc, | ||
3113 | "Bit Rate= %d Mb/s\n", | ||
3114 | tbl->expected_tpt[lq_sta->last_txrate_idx]); | ||
3115 | else | ||
3116 | desc += sprintf(buff+desc, | ||
3117 | "Bit Rate= %d Mb/s\n", | ||
3118 | iwl_rates[lq_sta->last_txrate_idx].ieee >> 1); | ||
3119 | |||
3120 | return simple_read_from_buffer(user_buf, count, ppos, buff, desc); | ||
3121 | } | ||
3122 | |||
3123 | static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { | ||
3124 | .read = rs_sta_dbgfs_rate_scale_data_read, | ||
3125 | .open = simple_open, | ||
3126 | .llseek = default_llseek, | ||
3127 | }; | ||
3128 | |||
3129 | static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) | 2692 | static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) |
3130 | { | 2693 | { |
3131 | struct iwl_lq_sta *lq_sta = mvm_sta; | 2694 | struct iwl_lq_sta *lq_sta = mvm_sta; |
@@ -3135,9 +2698,6 @@ static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) | |||
3135 | lq_sta->rs_sta_dbgfs_stats_table_file = | 2698 | lq_sta->rs_sta_dbgfs_stats_table_file = |
3136 | debugfs_create_file("rate_stats_table", S_IRUSR, dir, | 2699 | debugfs_create_file("rate_stats_table", S_IRUSR, dir, |
3137 | lq_sta, &rs_sta_dbgfs_stats_table_ops); | 2700 | lq_sta, &rs_sta_dbgfs_stats_table_ops); |
3138 | lq_sta->rs_sta_dbgfs_rate_scale_data_file = | ||
3139 | debugfs_create_file("rate_scale_data", S_IRUSR, dir, | ||
3140 | lq_sta, &rs_sta_dbgfs_rate_scale_data_ops); | ||
3141 | lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = | 2701 | lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = |
3142 | debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, | 2702 | debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, |
3143 | &lq_sta->tx_agg_tid_en); | 2703 | &lq_sta->tx_agg_tid_en); |
@@ -3148,7 +2708,6 @@ static void rs_remove_debugfs(void *mvm, void *mvm_sta) | |||
3148 | struct iwl_lq_sta *lq_sta = mvm_sta; | 2708 | struct iwl_lq_sta *lq_sta = mvm_sta; |
3149 | debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file); | 2709 | debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file); |
3150 | debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); | 2710 | debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); |
3151 | debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file); | ||
3152 | debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file); | 2711 | debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file); |
3153 | } | 2712 | } |
3154 | #endif | 2713 | #endif |
@@ -3159,8 +2718,9 @@ static void rs_remove_debugfs(void *mvm, void *mvm_sta) | |||
3159 | * station is added we ignore it. | 2718 | * station is added we ignore it. |
3160 | */ | 2719 | */ |
3161 | static void rs_rate_init_stub(void *mvm_r, | 2720 | static void rs_rate_init_stub(void *mvm_r, |
3162 | struct ieee80211_supported_band *sband, | 2721 | struct ieee80211_supported_band *sband, |
3163 | struct ieee80211_sta *sta, void *mvm_sta) | 2722 | struct cfg80211_chan_def *chandef, |
2723 | struct ieee80211_sta *sta, void *mvm_sta) | ||
3164 | { | 2724 | { |
3165 | } | 2725 | } |
3166 | static struct rate_control_ops rs_mvm_ops = { | 2726 | static struct rate_control_ops rs_mvm_ops = { |
@@ -3193,13 +2753,14 @@ void iwl_mvm_rate_control_unregister(void) | |||
3193 | * iwl_mvm_tx_protection - Gets LQ command, change it to enable/disable | 2753 | * iwl_mvm_tx_protection - Gets LQ command, change it to enable/disable |
3194 | * Tx protection, according to this rquest and previous requests, | 2754 | * Tx protection, according to this rquest and previous requests, |
3195 | * and send the LQ command. | 2755 | * and send the LQ command. |
3196 | * @lq: The LQ command | ||
3197 | * @mvmsta: The station | 2756 | * @mvmsta: The station |
3198 | * @enable: Enable Tx protection? | 2757 | * @enable: Enable Tx protection? |
3199 | */ | 2758 | */ |
3200 | int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | 2759 | int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, |
3201 | struct iwl_mvm_sta *mvmsta, bool enable) | 2760 | bool enable) |
3202 | { | 2761 | { |
2762 | struct iwl_lq_cmd *lq = &mvmsta->lq_sta.lq; | ||
2763 | |||
3203 | lockdep_assert_held(&mvm->mutex); | 2764 | lockdep_assert_held(&mvm->mutex); |
3204 | 2765 | ||
3205 | if (enable) { | 2766 | if (enable) { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index cff4f6da7733..335cf1682902 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h | |||
@@ -38,14 +38,8 @@ struct iwl_rs_rate_info { | |||
38 | u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ | 38 | u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ |
39 | u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ | 39 | u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ |
40 | u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ | 40 | u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ |
41 | u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_6M_PLCP, etc. */ | ||
42 | u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ | ||
43 | u8 prev_ieee; /* previous rate in IEEE speeds */ | ||
44 | u8 next_ieee; /* next rate in IEEE speeds */ | ||
45 | u8 prev_rs; /* previous rate used in rs algo */ | 41 | u8 prev_rs; /* previous rate used in rs algo */ |
46 | u8 next_rs; /* next rate used in rs algo */ | 42 | u8 next_rs; /* next rate used in rs algo */ |
47 | u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ | ||
48 | u8 next_rs_tgg; /* next rate used in TGG rs algo */ | ||
49 | }; | 43 | }; |
50 | 44 | ||
51 | #define IWL_RATE_60M_PLCP 3 | 45 | #define IWL_RATE_60M_PLCP 3 |
@@ -120,23 +114,6 @@ enum { | |||
120 | IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, | 114 | IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, |
121 | }; | 115 | }; |
122 | 116 | ||
123 | /* MAC header values for bit rates */ | ||
124 | enum { | ||
125 | IWL_RATE_6M_IEEE = 12, | ||
126 | IWL_RATE_9M_IEEE = 18, | ||
127 | IWL_RATE_12M_IEEE = 24, | ||
128 | IWL_RATE_18M_IEEE = 36, | ||
129 | IWL_RATE_24M_IEEE = 48, | ||
130 | IWL_RATE_36M_IEEE = 72, | ||
131 | IWL_RATE_48M_IEEE = 96, | ||
132 | IWL_RATE_54M_IEEE = 108, | ||
133 | IWL_RATE_60M_IEEE = 120, | ||
134 | IWL_RATE_1M_IEEE = 2, | ||
135 | IWL_RATE_2M_IEEE = 4, | ||
136 | IWL_RATE_5M_IEEE = 11, | ||
137 | IWL_RATE_11M_IEEE = 22, | ||
138 | }; | ||
139 | |||
140 | #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) | 117 | #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) |
141 | 118 | ||
142 | #define IWL_INVALID_VALUE -1 | 119 | #define IWL_INVALID_VALUE -1 |
@@ -165,47 +142,22 @@ enum { | |||
165 | #define IWL_LEGACY_SWITCH_ANTENNA1 0 | 142 | #define IWL_LEGACY_SWITCH_ANTENNA1 0 |
166 | #define IWL_LEGACY_SWITCH_ANTENNA2 1 | 143 | #define IWL_LEGACY_SWITCH_ANTENNA2 1 |
167 | #define IWL_LEGACY_SWITCH_SISO 2 | 144 | #define IWL_LEGACY_SWITCH_SISO 2 |
168 | #define IWL_LEGACY_SWITCH_MIMO2_AB 3 | 145 | #define IWL_LEGACY_SWITCH_MIMO2 3 |
169 | #define IWL_LEGACY_SWITCH_MIMO2_AC 4 | ||
170 | #define IWL_LEGACY_SWITCH_MIMO2_BC 5 | ||
171 | #define IWL_LEGACY_SWITCH_MIMO3_ABC 6 | ||
172 | 146 | ||
173 | /* possible actions when in siso mode */ | 147 | /* possible actions when in siso mode */ |
174 | #define IWL_SISO_SWITCH_ANTENNA1 0 | 148 | #define IWL_SISO_SWITCH_ANTENNA1 0 |
175 | #define IWL_SISO_SWITCH_ANTENNA2 1 | 149 | #define IWL_SISO_SWITCH_ANTENNA2 1 |
176 | #define IWL_SISO_SWITCH_MIMO2_AB 2 | 150 | #define IWL_SISO_SWITCH_MIMO2 2 |
177 | #define IWL_SISO_SWITCH_MIMO2_AC 3 | 151 | #define IWL_SISO_SWITCH_GI 3 |
178 | #define IWL_SISO_SWITCH_MIMO2_BC 4 | ||
179 | #define IWL_SISO_SWITCH_GI 5 | ||
180 | #define IWL_SISO_SWITCH_MIMO3_ABC 6 | ||
181 | |||
182 | 152 | ||
183 | /* possible actions when in mimo mode */ | 153 | /* possible actions when in mimo mode */ |
184 | #define IWL_MIMO2_SWITCH_ANTENNA1 0 | 154 | #define IWL_MIMO2_SWITCH_ANTENNA1 0 |
185 | #define IWL_MIMO2_SWITCH_ANTENNA2 1 | 155 | #define IWL_MIMO2_SWITCH_ANTENNA2 1 |
186 | #define IWL_MIMO2_SWITCH_SISO_A 2 | 156 | #define IWL_MIMO2_SWITCH_SISO_A 2 |
187 | #define IWL_MIMO2_SWITCH_SISO_B 3 | 157 | #define IWL_MIMO2_SWITCH_SISO_B 3 |
188 | #define IWL_MIMO2_SWITCH_SISO_C 4 | 158 | #define IWL_MIMO2_SWITCH_GI 4 |
189 | #define IWL_MIMO2_SWITCH_GI 5 | ||
190 | #define IWL_MIMO2_SWITCH_MIMO3_ABC 6 | ||
191 | |||
192 | 159 | ||
193 | /* possible actions when in mimo3 mode */ | 160 | #define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_GI |
194 | #define IWL_MIMO3_SWITCH_ANTENNA1 0 | ||
195 | #define IWL_MIMO3_SWITCH_ANTENNA2 1 | ||
196 | #define IWL_MIMO3_SWITCH_SISO_A 2 | ||
197 | #define IWL_MIMO3_SWITCH_SISO_B 3 | ||
198 | #define IWL_MIMO3_SWITCH_SISO_C 4 | ||
199 | #define IWL_MIMO3_SWITCH_MIMO2_AB 5 | ||
200 | #define IWL_MIMO3_SWITCH_MIMO2_AC 6 | ||
201 | #define IWL_MIMO3_SWITCH_MIMO2_BC 7 | ||
202 | #define IWL_MIMO3_SWITCH_GI 8 | ||
203 | |||
204 | |||
205 | #define IWL_MAX_11N_MIMO3_SEARCH IWL_MIMO3_SWITCH_GI | ||
206 | #define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_MIMO3_ABC | ||
207 | |||
208 | /*FIXME:RS:add possible actions for MIMO3*/ | ||
209 | 161 | ||
210 | #define IWL_ACTION_LIMIT 3 /* # possible actions */ | 162 | #define IWL_ACTION_LIMIT 3 /* # possible actions */ |
211 | 163 | ||
@@ -240,15 +192,13 @@ enum iwl_table_type { | |||
240 | LQ_A, | 192 | LQ_A, |
241 | LQ_SISO, /* high-throughput types */ | 193 | LQ_SISO, /* high-throughput types */ |
242 | LQ_MIMO2, | 194 | LQ_MIMO2, |
243 | LQ_MIMO3, | ||
244 | LQ_MAX, | 195 | LQ_MAX, |
245 | }; | 196 | }; |
246 | 197 | ||
247 | #define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) | 198 | #define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) |
248 | #define is_siso(tbl) ((tbl) == LQ_SISO) | 199 | #define is_siso(tbl) ((tbl) == LQ_SISO) |
249 | #define is_mimo2(tbl) ((tbl) == LQ_MIMO2) | 200 | #define is_mimo2(tbl) ((tbl) == LQ_MIMO2) |
250 | #define is_mimo3(tbl) ((tbl) == LQ_MIMO3) | 201 | #define is_mimo(tbl) is_mimo2(tbl) |
251 | #define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl)) | ||
252 | #define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl)) | 202 | #define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl)) |
253 | #define is_a_band(tbl) ((tbl) == LQ_A) | 203 | #define is_a_band(tbl) ((tbl) == LQ_A) |
254 | #define is_g_and(tbl) ((tbl) == LQ_G) | 204 | #define is_g_and(tbl) ((tbl) == LQ_G) |
@@ -290,17 +240,6 @@ struct iwl_scale_tbl_info { | |||
290 | struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ | 240 | struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ |
291 | }; | 241 | }; |
292 | 242 | ||
293 | struct iwl_traffic_load { | ||
294 | unsigned long time_stamp; /* age of the oldest statistics */ | ||
295 | u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time | ||
296 | * slice */ | ||
297 | u32 total; /* total num of packets during the | ||
298 | * last TID_MAX_TIME_DIFF */ | ||
299 | u8 queue_count; /* number of queues that has | ||
300 | * been used since the last cleanup */ | ||
301 | u8 head; /* start of the circular buffer */ | ||
302 | }; | ||
303 | |||
304 | /** | 243 | /** |
305 | * struct iwl_lq_sta -- driver's rate scaling private structure | 244 | * struct iwl_lq_sta -- driver's rate scaling private structure |
306 | * | 245 | * |
@@ -331,18 +270,15 @@ struct iwl_lq_sta { | |||
331 | u16 active_legacy_rate; | 270 | u16 active_legacy_rate; |
332 | u16 active_siso_rate; | 271 | u16 active_siso_rate; |
333 | u16 active_mimo2_rate; | 272 | u16 active_mimo2_rate; |
334 | u16 active_mimo3_rate; | ||
335 | s8 max_rate_idx; /* Max rate set by user */ | 273 | s8 max_rate_idx; /* Max rate set by user */ |
336 | u8 missed_rate_counter; | 274 | u8 missed_rate_counter; |
337 | 275 | ||
338 | struct iwl_lq_cmd lq; | 276 | struct iwl_lq_cmd lq; |
339 | struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ | 277 | struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ |
340 | struct iwl_traffic_load load[IWL_MAX_TID_COUNT]; | ||
341 | u8 tx_agg_tid_en; | 278 | u8 tx_agg_tid_en; |
342 | #ifdef CONFIG_MAC80211_DEBUGFS | 279 | #ifdef CONFIG_MAC80211_DEBUGFS |
343 | struct dentry *rs_sta_dbgfs_scale_table_file; | 280 | struct dentry *rs_sta_dbgfs_scale_table_file; |
344 | struct dentry *rs_sta_dbgfs_stats_table_file; | 281 | struct dentry *rs_sta_dbgfs_stats_table_file; |
345 | struct dentry *rs_sta_dbgfs_rate_scale_data_file; | ||
346 | struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; | 282 | struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; |
347 | u32 dbg_fixed_rate; | 283 | u32 dbg_fixed_rate; |
348 | #endif | 284 | #endif |
@@ -404,7 +340,7 @@ extern void iwl_mvm_rate_control_unregister(void); | |||
404 | 340 | ||
405 | struct iwl_mvm_sta; | 341 | struct iwl_mvm_sta; |
406 | 342 | ||
407 | int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | 343 | int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, |
408 | struct iwl_mvm_sta *mvmsta, bool enable); | 344 | bool enable); |
409 | 345 | ||
410 | #endif /* __rs__ */ | 346 | #endif /* __rs__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index e4930d5027d2..2a8cb5a60535 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c | |||
@@ -124,24 +124,15 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, | |||
124 | ieee80211_rx_ni(mvm->hw, skb); | 124 | ieee80211_rx_ni(mvm->hw, skb); |
125 | } | 125 | } |
126 | 126 | ||
127 | /* | 127 | static void iwl_mvm_calc_rssi(struct iwl_mvm *mvm, |
128 | * iwl_mvm_calc_rssi - calculate the rssi in dBm | 128 | struct iwl_rx_phy_info *phy_info, |
129 | * @phy_info: the phy information for the coming packet | 129 | struct ieee80211_rx_status *rx_status) |
130 | */ | ||
131 | static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm, | ||
132 | struct iwl_rx_phy_info *phy_info) | ||
133 | { | 130 | { |
134 | int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; | 131 | int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; |
135 | int rssi_all_band_a, rssi_all_band_b; | 132 | int rssi_all_band_a, rssi_all_band_b; |
136 | u32 agc_a, agc_b, max_agc; | 133 | u32 agc_a, agc_b, max_agc; |
137 | u32 val; | 134 | u32 val; |
138 | 135 | ||
139 | /* Find max rssi among 2 possible receivers. | ||
140 | * These values are measured by the Digital Signal Processor (DSP). | ||
141 | * They should stay fairly constant even as the signal strength varies, | ||
142 | * if the radio's Automatic Gain Control (AGC) is working right. | ||
143 | * AGC value (see below) will provide the "interesting" info. | ||
144 | */ | ||
145 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); | 136 | 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; | 137 | 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; | 138 | agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS; |
@@ -166,7 +157,51 @@ static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm, | |||
166 | IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d Max %d AGCA %d AGCB %d\n", | 157 | IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d Max %d AGCA %d AGCB %d\n", |
167 | rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b); | 158 | rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b); |
168 | 159 | ||
169 | return max_rssi_dbm; | 160 | rx_status->signal = max_rssi_dbm; |
161 | rx_status->chains = (le16_to_cpu(phy_info->phy_flags) & | ||
162 | RX_RES_PHY_FLAGS_ANTENNA) | ||
163 | >> RX_RES_PHY_FLAGS_ANTENNA_POS; | ||
164 | rx_status->chain_signal[0] = rssi_a_dbm; | ||
165 | rx_status->chain_signal[1] = rssi_b_dbm; | ||
166 | } | ||
167 | |||
168 | /* | ||
169 | * iwl_mvm_get_signal_strength - use new rx PHY INFO API | ||
170 | * values are reported by the fw as positive values - need to negate | ||
171 | * to obtain their dBM. Account for missing antennas by replacing 0 | ||
172 | * values by -256dBm: practically 0 power and a non-feasible 8 bit value. | ||
173 | */ | ||
174 | static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, | ||
175 | struct iwl_rx_phy_info *phy_info, | ||
176 | struct ieee80211_rx_status *rx_status) | ||
177 | { | ||
178 | int energy_a, energy_b, energy_c, max_energy; | ||
179 | u32 val; | ||
180 | |||
181 | val = | ||
182 | le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_ENERGY_ANT_ABC_IDX]); | ||
183 | energy_a = (val & IWL_RX_INFO_ENERGY_ANT_A_MSK) >> | ||
184 | IWL_RX_INFO_ENERGY_ANT_A_POS; | ||
185 | energy_a = energy_a ? -energy_a : -256; | ||
186 | energy_b = (val & IWL_RX_INFO_ENERGY_ANT_B_MSK) >> | ||
187 | IWL_RX_INFO_ENERGY_ANT_B_POS; | ||
188 | energy_b = energy_b ? -energy_b : -256; | ||
189 | energy_c = (val & IWL_RX_INFO_ENERGY_ANT_C_MSK) >> | ||
190 | IWL_RX_INFO_ENERGY_ANT_C_POS; | ||
191 | energy_c = energy_c ? -energy_c : -256; | ||
192 | max_energy = max(energy_a, energy_b); | ||
193 | max_energy = max(max_energy, energy_c); | ||
194 | |||
195 | IWL_DEBUG_STATS(mvm, "energy In A %d B %d C %d , and max %d\n", | ||
196 | energy_a, energy_b, energy_c, max_energy); | ||
197 | |||
198 | rx_status->signal = max_energy; | ||
199 | rx_status->chains = (le16_to_cpu(phy_info->phy_flags) & | ||
200 | RX_RES_PHY_FLAGS_ANTENNA) | ||
201 | >> RX_RES_PHY_FLAGS_ANTENNA_POS; | ||
202 | rx_status->chain_signal[0] = energy_a; | ||
203 | rx_status->chain_signal[1] = energy_b; | ||
204 | rx_status->chain_signal[2] = energy_c; | ||
170 | } | 205 | } |
171 | 206 | ||
172 | /* | 207 | /* |
@@ -289,29 +324,14 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
289 | */ | 324 | */ |
290 | /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/ | 325 | /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/ |
291 | 326 | ||
292 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ | 327 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_RX_ENERGY_API) |
293 | rx_status.signal = iwl_mvm_calc_rssi(mvm, phy_info); | 328 | iwl_mvm_get_signal_strength(mvm, phy_info, &rx_status); |
329 | else | ||
330 | iwl_mvm_calc_rssi(mvm, phy_info, &rx_status); | ||
294 | 331 | ||
295 | IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal, | 332 | IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal, |
296 | (unsigned long long)rx_status.mactime); | 333 | (unsigned long long)rx_status.mactime); |
297 | 334 | ||
298 | /* | ||
299 | * "antenna number" | ||
300 | * | ||
301 | * It seems that the antenna field in the phy flags value | ||
302 | * is actually a bit field. This is undefined by radiotap, | ||
303 | * it wants an actual antenna number but I always get "7" | ||
304 | * for most legacy frames I receive indicating that the | ||
305 | * same frame was received on all three RX chains. | ||
306 | * | ||
307 | * I think this field should be removed in favor of a | ||
308 | * new 802.11n radiotap field "RX chains" that is defined | ||
309 | * as a bitmask. | ||
310 | */ | ||
311 | rx_status.antenna = (le16_to_cpu(phy_info->phy_flags) & | ||
312 | RX_RES_PHY_FLAGS_ANTENNA) | ||
313 | >> RX_RES_PHY_FLAGS_ANTENNA_POS; | ||
314 | |||
315 | /* set the preamble flag if appropriate */ | 335 | /* set the preamble flag if appropriate */ |
316 | if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE)) | 336 | if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE)) |
317 | rx_status.flag |= RX_FLAG_SHORTPRE; | 337 | rx_status.flag |= RX_FLAG_SHORTPRE; |
@@ -364,11 +384,74 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
364 | return 0; | 384 | return 0; |
365 | } | 385 | } |
366 | 386 | ||
387 | static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm, | ||
388 | struct iwl_notif_statistics *stats) | ||
389 | { | ||
390 | /* | ||
391 | * NOTE FW aggregates the statistics - BUT the statistics are cleared | ||
392 | * when the driver issues REPLY_STATISTICS_CMD 0x9c with CLEAR_STATS | ||
393 | * bit set. | ||
394 | */ | ||
395 | lockdep_assert_held(&mvm->mutex); | ||
396 | memcpy(&mvm->rx_stats, &stats->rx, sizeof(struct mvm_statistics_rx)); | ||
397 | } | ||
398 | |||
399 | struct iwl_mvm_stat_data { | ||
400 | struct iwl_notif_statistics *stats; | ||
401 | struct iwl_mvm *mvm; | ||
402 | }; | ||
403 | |||
404 | static void iwl_mvm_stat_iterator(void *_data, u8 *mac, | ||
405 | struct ieee80211_vif *vif) | ||
406 | { | ||
407 | struct iwl_mvm_stat_data *data = _data; | ||
408 | struct iwl_notif_statistics *stats = data->stats; | ||
409 | struct iwl_mvm *mvm = data->mvm; | ||
410 | int sig = -stats->general.beacon_filter_average_energy; | ||
411 | int last_event; | ||
412 | int thold = vif->bss_conf.cqm_rssi_thold; | ||
413 | int hyst = vif->bss_conf.cqm_rssi_hyst; | ||
414 | u16 id = le32_to_cpu(stats->rx.general.mac_id); | ||
415 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
416 | |||
417 | if (mvmvif->id != id) | ||
418 | return; | ||
419 | |||
420 | if (vif->type != NL80211_IFTYPE_STATION) | ||
421 | return; | ||
422 | |||
423 | mvmvif->bf_data.ave_beacon_signal = sig; | ||
424 | |||
425 | if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) | ||
426 | return; | ||
427 | |||
428 | /* CQM Notification */ | ||
429 | last_event = mvmvif->bf_data.last_cqm_event; | ||
430 | if (thold && sig < thold && (last_event == 0 || | ||
431 | sig < last_event - hyst)) { | ||
432 | mvmvif->bf_data.last_cqm_event = sig; | ||
433 | IWL_DEBUG_RX(mvm, "cqm_iterator cqm low %d\n", | ||
434 | sig); | ||
435 | ieee80211_cqm_rssi_notify( | ||
436 | vif, | ||
437 | NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, | ||
438 | GFP_KERNEL); | ||
439 | } else if (sig > thold && | ||
440 | (last_event == 0 || sig > last_event + hyst)) { | ||
441 | mvmvif->bf_data.last_cqm_event = sig; | ||
442 | IWL_DEBUG_RX(mvm, "cqm_iterator cqm high %d\n", | ||
443 | sig); | ||
444 | ieee80211_cqm_rssi_notify( | ||
445 | vif, | ||
446 | NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, | ||
447 | GFP_KERNEL); | ||
448 | } | ||
449 | } | ||
450 | |||
367 | /* | 451 | /* |
368 | * iwl_mvm_rx_statistics - STATISTICS_NOTIFICATION handler | 452 | * iwl_mvm_rx_statistics - STATISTICS_NOTIFICATION handler |
369 | * | 453 | * |
370 | * TODO: This handler is implemented partially. | 454 | * TODO: This handler is implemented partially. |
371 | * It only gets the NIC's temperature. | ||
372 | */ | 455 | */ |
373 | int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, | 456 | int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, |
374 | struct iwl_rx_cmd_buffer *rxb, | 457 | struct iwl_rx_cmd_buffer *rxb, |
@@ -377,11 +460,20 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, | |||
377 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 460 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
378 | struct iwl_notif_statistics *stats = (void *)&pkt->data; | 461 | struct iwl_notif_statistics *stats = (void *)&pkt->data; |
379 | struct mvm_statistics_general_common *common = &stats->general.common; | 462 | struct mvm_statistics_general_common *common = &stats->general.common; |
463 | struct iwl_mvm_stat_data data = { | ||
464 | .stats = stats, | ||
465 | .mvm = mvm, | ||
466 | }; | ||
380 | 467 | ||
381 | if (mvm->temperature != le32_to_cpu(common->temperature)) { | 468 | if (mvm->temperature != le32_to_cpu(common->temperature)) { |
382 | mvm->temperature = le32_to_cpu(common->temperature); | 469 | mvm->temperature = le32_to_cpu(common->temperature); |
383 | iwl_mvm_tt_handler(mvm); | 470 | iwl_mvm_tt_handler(mvm); |
384 | } | 471 | } |
472 | iwl_mvm_update_rx_statistics(mvm, stats); | ||
385 | 473 | ||
474 | ieee80211_iterate_active_interfaces(mvm->hw, | ||
475 | IEEE80211_IFACE_ITER_NORMAL, | ||
476 | iwl_mvm_stat_iterator, | ||
477 | &data); | ||
386 | return 0; | 478 | return 0; |
387 | } | 479 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index acdff6b67e04..9a7ab8495300 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
@@ -301,10 +301,12 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, | |||
301 | */ | 301 | */ |
302 | if (req->n_ssids > 0) { | 302 | if (req->n_ssids > 0) { |
303 | cmd->passive2active = cpu_to_le16(1); | 303 | cmd->passive2active = cpu_to_le16(1); |
304 | cmd->scan_flags |= SCAN_FLAGS_PASSIVE2ACTIVE; | ||
304 | ssid = req->ssids[0].ssid; | 305 | ssid = req->ssids[0].ssid; |
305 | ssid_len = req->ssids[0].ssid_len; | 306 | ssid_len = req->ssids[0].ssid_len; |
306 | } else { | 307 | } else { |
307 | cmd->passive2active = 0; | 308 | cmd->passive2active = 0; |
309 | cmd->scan_flags &= ~SCAN_FLAGS_PASSIVE2ACTIVE; | ||
308 | } | 310 | } |
309 | 311 | ||
310 | iwl_mvm_scan_fill_ssids(cmd, req); | 312 | iwl_mvm_scan_fill_ssids(cmd, req); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 563f559b902d..44add291531b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -826,8 +826,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
826 | * method for HT traffic | 826 | * method for HT traffic |
827 | * this function also sends the LQ command | 827 | * this function also sends the LQ command |
828 | */ | 828 | */ |
829 | return iwl_mvm_tx_protection(mvm, &mvmsta->lq_sta.lq, | 829 | return iwl_mvm_tx_protection(mvm, mvmsta, true); |
830 | mvmsta, true); | ||
831 | /* | 830 | /* |
832 | * TODO: remove the TLC_RTS flag when we tear down the last | 831 | * TODO: remove the TLC_RTS flag when we tear down the last |
833 | * AGG session (agg_tids_count in DVM) | 832 | * AGG session (agg_tids_count in DVM) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 7fd6fbfbc1b3..c17b74c31398 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
@@ -73,7 +73,6 @@ | |||
73 | #include "iwl-prph.h" | 73 | #include "iwl-prph.h" |
74 | 74 | ||
75 | /* A TimeUnit is 1024 microsecond */ | 75 | /* A TimeUnit is 1024 microsecond */ |
76 | #define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024)) | ||
77 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) | 76 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) |
78 | 77 | ||
79 | /* | 78 | /* |
@@ -185,7 +184,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
185 | } | 184 | } |
186 | } | 185 | } |
187 | 186 | ||
188 | if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_END) { | 187 | if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_END) { |
189 | IWL_DEBUG_TE(mvm, | 188 | IWL_DEBUG_TE(mvm, |
190 | "TE ended - current time %lu, estimated end %lu\n", | 189 | "TE ended - current time %lu, estimated end %lu\n", |
191 | jiffies, te_data->end_jiffies); | 190 | jiffies, te_data->end_jiffies); |
@@ -202,10 +201,9 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
202 | iwl_mvm_te_check_disconnect(mvm, te_data->vif, | 201 | iwl_mvm_te_check_disconnect(mvm, te_data->vif, |
203 | "No assocation and the time event is over already..."); | 202 | "No assocation and the time event is over already..."); |
204 | iwl_mvm_te_clear_data(mvm, te_data); | 203 | iwl_mvm_te_clear_data(mvm, te_data); |
205 | } else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) { | 204 | } else if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_START) { |
206 | te_data->running = true; | 205 | te_data->running = true; |
207 | te_data->end_jiffies = jiffies + | 206 | te_data->end_jiffies = TU_TO_EXP_TIME(te_data->duration); |
208 | TU_TO_JIFFIES(te_data->duration); | ||
209 | 207 | ||
210 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { | 208 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { |
211 | set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); | 209 | set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); |
@@ -270,10 +268,67 @@ static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait, | |||
270 | return true; | 268 | return true; |
271 | } | 269 | } |
272 | 270 | ||
271 | /* used to convert from time event API v2 to v1 */ | ||
272 | #define TE_V2_DEP_POLICY_MSK (TE_V2_DEP_OTHER | TE_V2_DEP_TSF |\ | ||
273 | TE_V2_EVENT_SOCIOPATHIC) | ||
274 | static inline u16 te_v2_get_notify(__le16 policy) | ||
275 | { | ||
276 | return le16_to_cpu(policy) & TE_V2_NOTIF_MSK; | ||
277 | } | ||
278 | |||
279 | static inline u16 te_v2_get_dep_policy(__le16 policy) | ||
280 | { | ||
281 | return (le16_to_cpu(policy) & TE_V2_DEP_POLICY_MSK) >> | ||
282 | TE_V2_PLACEMENT_POS; | ||
283 | } | ||
284 | |||
285 | static inline u16 te_v2_get_absence(__le16 policy) | ||
286 | { | ||
287 | return (le16_to_cpu(policy) & TE_V2_ABSENCE) >> TE_V2_ABSENCE_POS; | ||
288 | } | ||
289 | |||
290 | static void iwl_mvm_te_v2_to_v1(const struct iwl_time_event_cmd_v2 *cmd_v2, | ||
291 | struct iwl_time_event_cmd_v1 *cmd_v1) | ||
292 | { | ||
293 | cmd_v1->id_and_color = cmd_v2->id_and_color; | ||
294 | cmd_v1->action = cmd_v2->action; | ||
295 | cmd_v1->id = cmd_v2->id; | ||
296 | cmd_v1->apply_time = cmd_v2->apply_time; | ||
297 | cmd_v1->max_delay = cmd_v2->max_delay; | ||
298 | cmd_v1->depends_on = cmd_v2->depends_on; | ||
299 | cmd_v1->interval = cmd_v2->interval; | ||
300 | cmd_v1->duration = cmd_v2->duration; | ||
301 | if (cmd_v2->repeat == TE_V2_REPEAT_ENDLESS) | ||
302 | cmd_v1->repeat = cpu_to_le32(TE_V1_REPEAT_ENDLESS); | ||
303 | else | ||
304 | cmd_v1->repeat = cpu_to_le32(cmd_v2->repeat); | ||
305 | cmd_v1->max_frags = cpu_to_le32(cmd_v2->max_frags); | ||
306 | cmd_v1->interval_reciprocal = 0; /* unused */ | ||
307 | |||
308 | cmd_v1->dep_policy = cpu_to_le32(te_v2_get_dep_policy(cmd_v2->policy)); | ||
309 | cmd_v1->is_present = cpu_to_le32(!te_v2_get_absence(cmd_v2->policy)); | ||
310 | cmd_v1->notify = cpu_to_le32(te_v2_get_notify(cmd_v2->policy)); | ||
311 | } | ||
312 | |||
313 | static int iwl_mvm_send_time_event_cmd(struct iwl_mvm *mvm, | ||
314 | const struct iwl_time_event_cmd_v2 *cmd) | ||
315 | { | ||
316 | struct iwl_time_event_cmd_v1 cmd_v1; | ||
317 | |||
318 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2) | ||
319 | return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | ||
320 | sizeof(*cmd), cmd); | ||
321 | |||
322 | iwl_mvm_te_v2_to_v1(cmd, &cmd_v1); | ||
323 | return iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | ||
324 | sizeof(cmd_v1), &cmd_v1); | ||
325 | } | ||
326 | |||
327 | |||
273 | static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, | 328 | static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, |
274 | struct ieee80211_vif *vif, | 329 | struct ieee80211_vif *vif, |
275 | struct iwl_mvm_time_event_data *te_data, | 330 | struct iwl_mvm_time_event_data *te_data, |
276 | struct iwl_time_event_cmd *te_cmd) | 331 | struct iwl_time_event_cmd_v2 *te_cmd) |
277 | { | 332 | { |
278 | static const u8 time_event_response[] = { TIME_EVENT_CMD }; | 333 | static const u8 time_event_response[] = { TIME_EVENT_CMD }; |
279 | struct iwl_notification_wait wait_time_event; | 334 | struct iwl_notification_wait wait_time_event; |
@@ -309,8 +364,7 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, | |||
309 | ARRAY_SIZE(time_event_response), | 364 | ARRAY_SIZE(time_event_response), |
310 | iwl_mvm_time_event_response, te_data); | 365 | iwl_mvm_time_event_response, te_data); |
311 | 366 | ||
312 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | 367 | ret = iwl_mvm_send_time_event_cmd(mvm, te_cmd); |
313 | sizeof(*te_cmd), te_cmd); | ||
314 | if (ret) { | 368 | if (ret) { |
315 | IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); | 369 | IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); |
316 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | 370 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); |
@@ -337,13 +391,12 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
337 | { | 391 | { |
338 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 392 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
339 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 393 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; |
340 | struct iwl_time_event_cmd time_cmd = {}; | 394 | struct iwl_time_event_cmd_v2 time_cmd = {}; |
341 | 395 | ||
342 | lockdep_assert_held(&mvm->mutex); | 396 | lockdep_assert_held(&mvm->mutex); |
343 | 397 | ||
344 | if (te_data->running && | 398 | if (te_data->running && |
345 | time_after(te_data->end_jiffies, | 399 | time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) { |
346 | jiffies + TU_TO_JIFFIES(min_duration))) { | ||
347 | IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n", | 400 | IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n", |
348 | jiffies_to_msecs(te_data->end_jiffies - jiffies)); | 401 | jiffies_to_msecs(te_data->end_jiffies - jiffies)); |
349 | return; | 402 | return; |
@@ -372,17 +425,14 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
372 | time_cmd.apply_time = | 425 | time_cmd.apply_time = |
373 | cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); | 426 | cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); |
374 | 427 | ||
375 | time_cmd.dep_policy = TE_INDEPENDENT; | 428 | time_cmd.max_frags = TE_V2_FRAG_NONE; |
376 | time_cmd.is_present = cpu_to_le32(1); | ||
377 | time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE); | ||
378 | time_cmd.max_delay = cpu_to_le32(500); | 429 | time_cmd.max_delay = cpu_to_le32(500); |
379 | /* TODO: why do we need to interval = bi if it is not periodic? */ | 430 | /* TODO: why do we need to interval = bi if it is not periodic? */ |
380 | time_cmd.interval = cpu_to_le32(1); | 431 | time_cmd.interval = cpu_to_le32(1); |
381 | time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1)); | ||
382 | time_cmd.duration = cpu_to_le32(duration); | 432 | time_cmd.duration = cpu_to_le32(duration); |
383 | time_cmd.repeat = cpu_to_le32(1); | 433 | time_cmd.repeat = 1; |
384 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START | | 434 | time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | |
385 | TE_NOTIF_HOST_EVENT_END); | 435 | TE_V2_NOTIF_HOST_EVENT_END); |
386 | 436 | ||
387 | iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | 437 | iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
388 | } | 438 | } |
@@ -396,7 +446,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | |||
396 | struct iwl_mvm_vif *mvmvif, | 446 | struct iwl_mvm_vif *mvmvif, |
397 | struct iwl_mvm_time_event_data *te_data) | 447 | struct iwl_mvm_time_event_data *te_data) |
398 | { | 448 | { |
399 | struct iwl_time_event_cmd time_cmd = {}; | 449 | struct iwl_time_event_cmd_v2 time_cmd = {}; |
400 | u32 id, uid; | 450 | u32 id, uid; |
401 | int ret; | 451 | int ret; |
402 | 452 | ||
@@ -433,8 +483,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, | |||
433 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | 483 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); |
434 | 484 | ||
435 | IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id)); | 485 | IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id)); |
436 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | 486 | ret = iwl_mvm_send_time_event_cmd(mvm, &time_cmd); |
437 | sizeof(time_cmd), &time_cmd); | ||
438 | if (WARN_ON(ret)) | 487 | if (WARN_ON(ret)) |
439 | return; | 488 | return; |
440 | } | 489 | } |
@@ -454,7 +503,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
454 | { | 503 | { |
455 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 504 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
456 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 505 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; |
457 | struct iwl_time_event_cmd time_cmd = {}; | 506 | struct iwl_time_event_cmd_v2 time_cmd = {}; |
458 | 507 | ||
459 | lockdep_assert_held(&mvm->mutex); | 508 | lockdep_assert_held(&mvm->mutex); |
460 | if (te_data->running) { | 509 | if (te_data->running) { |
@@ -485,8 +534,6 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
485 | } | 534 | } |
486 | 535 | ||
487 | time_cmd.apply_time = cpu_to_le32(0); | 536 | time_cmd.apply_time = cpu_to_le32(0); |
488 | time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT); | ||
489 | time_cmd.is_present = cpu_to_le32(1); | ||
490 | time_cmd.interval = cpu_to_le32(1); | 537 | time_cmd.interval = cpu_to_le32(1); |
491 | 538 | ||
492 | /* | 539 | /* |
@@ -495,12 +542,12 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
495 | * scheduled. To improve the chances of it being scheduled, allow them | 542 | * scheduled. To improve the chances of it being scheduled, allow them |
496 | * to be fragmented, and in addition allow them to be delayed. | 543 | * to be fragmented, and in addition allow them to be delayed. |
497 | */ | 544 | */ |
498 | time_cmd.max_frags = cpu_to_le32(MSEC_TO_TU(duration)/20); | 545 | time_cmd.max_frags = min(MSEC_TO_TU(duration)/50, TE_V2_FRAG_ENDLESS); |
499 | time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2)); | 546 | time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2)); |
500 | time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); | 547 | time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); |
501 | time_cmd.repeat = cpu_to_le32(1); | 548 | time_cmd.repeat = 1; |
502 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START | | 549 | time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | |
503 | TE_NOTIF_HOST_EVENT_END); | 550 | TE_V2_NOTIF_HOST_EVENT_END); |
504 | 551 | ||
505 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | 552 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
506 | } | 553 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index d6ae7f16ac11..1f3282dff513 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c | |||
@@ -391,8 +391,7 @@ static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable) | |||
391 | mvmsta = (void *)sta->drv_priv; | 391 | mvmsta = (void *)sta->drv_priv; |
392 | if (enable == mvmsta->tt_tx_protection) | 392 | if (enable == mvmsta->tt_tx_protection) |
393 | continue; | 393 | continue; |
394 | err = iwl_mvm_tx_protection(mvm, &mvmsta->lq_sta.lq, | 394 | err = iwl_mvm_tx_protection(mvm, mvmsta, enable); |
395 | mvmsta, enable); | ||
396 | if (err) { | 395 | if (err) { |
397 | IWL_ERR(mvm, "Failed to %s Tx protection\n", | 396 | IWL_ERR(mvm, "Failed to %s Tx protection\n", |
398 | enable ? "enable" : "disable"); | 397 | enable ? "enable" : "disable"); |
@@ -513,12 +512,39 @@ static const struct iwl_tt_params iwl7000_tt_params = { | |||
513 | .support_tx_backoff = true, | 512 | .support_tx_backoff = true, |
514 | }; | 513 | }; |
515 | 514 | ||
515 | static const struct iwl_tt_params iwl7000_high_temp_tt_params = { | ||
516 | .ct_kill_entry = 118, | ||
517 | .ct_kill_exit = 96, | ||
518 | .ct_kill_duration = 5, | ||
519 | .dynamic_smps_entry = 114, | ||
520 | .dynamic_smps_exit = 110, | ||
521 | .tx_protection_entry = 114, | ||
522 | .tx_protection_exit = 108, | ||
523 | .tx_backoff = { | ||
524 | {.temperature = 112, .backoff = 300}, | ||
525 | {.temperature = 113, .backoff = 800}, | ||
526 | {.temperature = 114, .backoff = 1500}, | ||
527 | {.temperature = 115, .backoff = 3000}, | ||
528 | {.temperature = 116, .backoff = 5000}, | ||
529 | {.temperature = 117, .backoff = 10000}, | ||
530 | }, | ||
531 | .support_ct_kill = true, | ||
532 | .support_dynamic_smps = true, | ||
533 | .support_tx_protection = true, | ||
534 | .support_tx_backoff = true, | ||
535 | }; | ||
536 | |||
516 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm) | 537 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm) |
517 | { | 538 | { |
518 | struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; | 539 | struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; |
519 | 540 | ||
520 | IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n"); | 541 | IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n"); |
521 | tt->params = &iwl7000_tt_params; | 542 | |
543 | if (mvm->cfg->high_temp) | ||
544 | tt->params = &iwl7000_high_temp_tt_params; | ||
545 | else | ||
546 | tt->params = &iwl7000_tt_params; | ||
547 | |||
522 | tt->throttle = false; | 548 | tt->throttle = false; |
523 | INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); | 549 | INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); |
524 | } | 550 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index f0e96a927407..e05440d90319 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -91,11 +91,10 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
91 | tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; | 91 | tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; |
92 | 92 | ||
93 | /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */ | 93 | /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */ |
94 | if (info->band == IEEE80211_BAND_2GHZ && | 94 | if (info->band == IEEE80211_BAND_2GHZ && |
95 | (skb->protocol == cpu_to_be16(ETH_P_PAE) || | 95 | (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO || |
96 | is_multicast_ether_addr(hdr->addr1) || | 96 | is_multicast_ether_addr(hdr->addr1) || |
97 | ieee80211_is_back_req(fc) || | 97 | ieee80211_is_back_req(fc) || ieee80211_is_mgmt(fc))) |
98 | ieee80211_is_mgmt(fc))) | ||
99 | tx_flags |= TX_CMD_FLG_BT_DIS; | 98 | tx_flags |= TX_CMD_FLG_BT_DIS; |
100 | 99 | ||
101 | if (ieee80211_has_morefrags(fc)) | 100 | if (ieee80211_has_morefrags(fc)) |
@@ -123,6 +122,8 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
123 | * it | 122 | * it |
124 | */ | 123 | */ |
125 | WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU); | 124 | WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU); |
125 | } else if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { | ||
126 | tx_cmd->pm_frame_timeout = cpu_to_le16(2); | ||
126 | } else { | 127 | } else { |
127 | tx_cmd->pm_frame_timeout = 0; | 128 | tx_cmd->pm_frame_timeout = 0; |
128 | } | 129 | } |
@@ -171,7 +172,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, | |||
171 | } | 172 | } |
172 | 173 | ||
173 | /* | 174 | /* |
174 | * for data packets, rate info comes from the table inside he fw. This | 175 | * for data packets, rate info comes from the table inside the fw. This |
175 | * table is controlled by LINK_QUALITY commands | 176 | * table is controlled by LINK_QUALITY commands |
176 | */ | 177 | */ |
177 | 178 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 1e1332839e4a..a9c357491434 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c | |||
@@ -453,6 +453,29 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) | |||
453 | IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); | 453 | IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); |
454 | } | 454 | } |
455 | 455 | ||
456 | void iwl_mvm_dump_sram(struct iwl_mvm *mvm) | ||
457 | { | ||
458 | const struct fw_img *img; | ||
459 | int ofs, len = 0; | ||
460 | u8 *buf; | ||
461 | |||
462 | if (!mvm->ucode_loaded) | ||
463 | return; | ||
464 | |||
465 | img = &mvm->fw->img[mvm->cur_ucode]; | ||
466 | ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; | ||
467 | len = img->sec[IWL_UCODE_SECTION_DATA].len; | ||
468 | |||
469 | buf = kzalloc(len, GFP_KERNEL); | ||
470 | if (!buf) | ||
471 | return; | ||
472 | |||
473 | iwl_trans_read_mem_bytes(mvm->trans, ofs, buf, len); | ||
474 | iwl_print_hex_error(mvm->trans, buf, len); | ||
475 | |||
476 | kfree(buf); | ||
477 | } | ||
478 | |||
456 | /** | 479 | /** |
457 | * iwl_mvm_send_lq_cmd() - Send link quality command | 480 | * iwl_mvm_send_lq_cmd() - Send link quality command |
458 | * @init: This command is sent as part of station initialization right | 481 | * @init: This command is sent as part of station initialization right |