diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-02 23:53:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-02 23:53:45 -0400 |
commit | cd6362befe4cc7bf589a5236d2a780af2d47bcc9 (patch) | |
tree | 3bd4e13ec3f92a00dc4f6c3d65e820b54dbfe46e /drivers/net/wireless/iwlwifi | |
parent | 0f1b1e6d73cb989ce2c071edc57deade3b084dfe (diff) | |
parent | b1586f099ba897542ece36e8a23c1a62907261ef (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller:
"Here is my initial pull request for the networking subsystem during
this merge window:
1) Support for ESN in AH (RFC 4302) from Fan Du.
2) Add full kernel doc for ethtool command structures, from Ben
Hutchings.
3) Add BCM7xxx PHY driver, from Florian Fainelli.
4) Export computed TCP rate information in netlink socket dumps, from
Eric Dumazet.
5) Allow IPSEC SA to be dumped partially using a filter, from Nicolas
Dichtel.
6) Convert many drivers to pci_enable_msix_range(), from Alexander
Gordeev.
7) Record SKB timestamps more efficiently, from Eric Dumazet.
8) Switch to microsecond resolution for TCP round trip times, also
from Eric Dumazet.
9) Clean up and fix 6lowpan fragmentation handling by making use of
the existing inet_frag api for it's implementation.
10) Add TX grant mapping to xen-netback driver, from Zoltan Kiss.
11) Auto size SKB lengths when composing netlink messages based upon
past message sizes used, from Eric Dumazet.
12) qdisc dumps can take a long time, add a cond_resched(), From Eric
Dumazet.
13) Sanitize netpoll core and drivers wrt. SKB handling semantics.
Get rid of never-used-in-tree netpoll RX handling. From Eric W
Biederman.
14) Support inter-address-family and namespace changing in VTI tunnel
driver(s). From Steffen Klassert.
15) Add Altera TSE driver, from Vince Bridgers.
16) Optimizing csum_replace2() so that it doesn't adjust the checksum
by checksumming the entire header, from Eric Dumazet.
17) Expand BPF internal implementation for faster interpreting, more
direct translations into JIT'd code, and much cleaner uses of BPF
filtering in non-socket ocntexts. From Daniel Borkmann and Alexei
Starovoitov"
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1976 commits)
netpoll: Use skb_irq_freeable to make zap_completion_queue safe.
net: Add a test to see if a skb is freeable in irq context
qlcnic: Fix build failure due to undefined reference to `vxlan_get_rx_port'
net: ptp: move PTP classifier in its own file
net: sxgbe: make "core_ops" static
net: sxgbe: fix logical vs bitwise operation
net: sxgbe: sxgbe_mdio_register() frees the bus
Call efx_set_channels() before efx->type->dimension_resources()
xen-netback: disable rogue vif in kthread context
net/mlx4: Set proper build dependancy with vxlan
be2net: fix build dependency on VxLAN
mac802154: make csma/cca parameters per-wpan
mac802154: allow only one WPAN to be up at any given time
net: filter: minor: fix kdoc in __sk_run_filter
netlink: don't compare the nul-termination in nla_strcmp
can: c_can: Avoid led toggling for every packet.
can: c_can: Simplify TX interrupt cleanup
can: c_can: Store dlc private
can: c_can: Reduce register access
can: c_can: Make the code readable
...
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
69 files changed, 5129 insertions, 1670 deletions
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 3eb2102ce236..74b3b4de7bb7 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig | |||
@@ -68,6 +68,19 @@ config IWLWIFI_OPMODE_MODULAR | |||
68 | comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM" | 68 | comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM" |
69 | depends on IWLWIFI && IWLDVM=n && IWLMVM=n | 69 | depends on IWLWIFI && IWLDVM=n && IWLMVM=n |
70 | 70 | ||
71 | config IWLWIFI_BCAST_FILTERING | ||
72 | bool "Enable broadcast filtering" | ||
73 | depends on IWLMVM | ||
74 | help | ||
75 | Say Y here to enable default bcast filtering configuration. | ||
76 | |||
77 | Enabling broadcast filtering will drop any incoming wireless | ||
78 | broadcast frames, except some very specific predefined | ||
79 | patterns (e.g. incoming arp requests). | ||
80 | |||
81 | If unsure, don't enable this option, as some programs might | ||
82 | expect incoming broadcasts for their normal operations. | ||
83 | |||
71 | menu "Debugging Options" | 84 | menu "Debugging Options" |
72 | depends on IWLWIFI | 85 | depends on IWLWIFI |
73 | 86 | ||
@@ -111,6 +124,7 @@ config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE | |||
111 | Enable use of experimental ucode for testing and debugging. | 124 | Enable use of experimental ucode for testing and debugging. |
112 | 125 | ||
113 | config IWLWIFI_DEVICE_TRACING | 126 | config IWLWIFI_DEVICE_TRACING |
127 | |||
114 | bool "iwlwifi device access tracing" | 128 | bool "iwlwifi device access tracing" |
115 | depends on IWLWIFI | 129 | depends on IWLWIFI |
116 | depends on EVENT_TRACING | 130 | depends on EVENT_TRACING |
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 1fa64429bcc2..3d32f4120174 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile | |||
@@ -8,7 +8,7 @@ iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o | |||
8 | iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o | 8 | iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o |
9 | iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o | 9 | iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o |
10 | iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o | 10 | iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o |
11 | iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o | 11 | iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o |
12 | 12 | ||
13 | iwlwifi-objs += $(iwlwifi-m) | 13 | iwlwifi-objs += $(iwlwifi-m) |
14 | 14 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index 562772d85102..c160dad03037 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h | |||
@@ -109,7 +109,7 @@ extern const struct iwl_dvm_cfg iwl_dvm_6030_cfg; | |||
109 | 109 | ||
110 | struct iwl_ucode_capabilities; | 110 | struct iwl_ucode_capabilities; |
111 | 111 | ||
112 | extern struct ieee80211_ops iwlagn_hw_ops; | 112 | extern const struct ieee80211_ops iwlagn_hw_ops; |
113 | 113 | ||
114 | static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) | 114 | static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) |
115 | { | 115 | { |
@@ -480,7 +480,7 @@ do { \ | |||
480 | } while (0) | 480 | } while (0) |
481 | #endif /* CONFIG_IWLWIFI_DEBUG */ | 481 | #endif /* CONFIG_IWLWIFI_DEBUG */ |
482 | 482 | ||
483 | extern const char *iwl_dvm_cmd_strings[REPLY_MAX]; | 483 | extern const char *const iwl_dvm_cmd_strings[REPLY_MAX]; |
484 | 484 | ||
485 | static inline const char *iwl_dvm_get_cmd_string(u8 cmd) | 485 | static inline const char *iwl_dvm_get_cmd_string(u8 cmd) |
486 | { | 486 | { |
diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c index 7b140e487deb..758c54eeb206 100644 --- a/drivers/net/wireless/iwlwifi/dvm/devices.c +++ b/drivers/net/wireless/iwlwifi/dvm/devices.c | |||
@@ -317,7 +317,7 @@ static const struct iwl_sensitivity_ranges iwl5000_sensitivity = { | |||
317 | .nrg_th_cca = 62, | 317 | .nrg_th_cca = 62, |
318 | }; | 318 | }; |
319 | 319 | ||
320 | static struct iwl_sensitivity_ranges iwl5150_sensitivity = { | 320 | static const struct iwl_sensitivity_ranges iwl5150_sensitivity = { |
321 | .min_nrg_cck = 95, | 321 | .min_nrg_cck = 95, |
322 | .auto_corr_min_ofdm = 90, | 322 | .auto_corr_min_ofdm = 90, |
323 | .auto_corr_min_ofdm_mrc = 170, | 323 | .auto_corr_min_ofdm_mrc = 170, |
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 73086c1629ca..dd55c9cf7ba8 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
@@ -1582,7 +1582,7 @@ static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, | |||
1582 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 1582 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
1583 | } | 1583 | } |
1584 | 1584 | ||
1585 | struct ieee80211_ops iwlagn_hw_ops = { | 1585 | const struct ieee80211_ops iwlagn_hw_ops = { |
1586 | .tx = iwlagn_mac_tx, | 1586 | .tx = iwlagn_mac_tx, |
1587 | .start = iwlagn_mac_start, | 1587 | .start = iwlagn_mac_start, |
1588 | .stop = iwlagn_mac_stop, | 1588 | .stop = iwlagn_mac_stop, |
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index ba1b1ea54252..6a6df71af1d7 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c | |||
@@ -252,13 +252,17 @@ static void iwl_bg_bt_runtime_config(struct work_struct *work) | |||
252 | struct iwl_priv *priv = | 252 | struct iwl_priv *priv = |
253 | container_of(work, struct iwl_priv, bt_runtime_config); | 253 | container_of(work, struct iwl_priv, bt_runtime_config); |
254 | 254 | ||
255 | mutex_lock(&priv->mutex); | ||
255 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 256 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
256 | return; | 257 | goto out; |
257 | 258 | ||
258 | /* dont send host command if rf-kill is on */ | 259 | /* dont send host command if rf-kill is on */ |
259 | if (!iwl_is_ready_rf(priv)) | 260 | if (!iwl_is_ready_rf(priv)) |
260 | return; | 261 | goto out; |
262 | |||
261 | iwlagn_send_advance_bt_config(priv); | 263 | iwlagn_send_advance_bt_config(priv); |
264 | out: | ||
265 | mutex_unlock(&priv->mutex); | ||
262 | } | 266 | } |
263 | 267 | ||
264 | static void iwl_bg_bt_full_concurrency(struct work_struct *work) | 268 | static void iwl_bg_bt_full_concurrency(struct work_struct *work) |
@@ -2035,7 +2039,7 @@ static void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) | |||
2035 | ieee80211_free_txskb(priv->hw, skb); | 2039 | ieee80211_free_txskb(priv->hw, skb); |
2036 | } | 2040 | } |
2037 | 2041 | ||
2038 | static void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) | 2042 | static bool iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) |
2039 | { | 2043 | { |
2040 | struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); | 2044 | struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); |
2041 | 2045 | ||
@@ -2045,6 +2049,8 @@ static void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) | |||
2045 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | 2049 | clear_bit(STATUS_RF_KILL_HW, &priv->status); |
2046 | 2050 | ||
2047 | wiphy_rfkill_set_hw_state(priv->hw->wiphy, state); | 2051 | wiphy_rfkill_set_hw_state(priv->hw->wiphy, state); |
2052 | |||
2053 | return false; | ||
2048 | } | 2054 | } |
2049 | 2055 | ||
2050 | static const struct iwl_op_mode_ops iwl_dvm_ops = { | 2056 | static const struct iwl_op_mode_ops iwl_dvm_ops = { |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index 0977d93b529d..aa773a2da4ab 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c | |||
@@ -176,46 +176,46 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, | |||
176 | * (2.4 GHz) band. | 176 | * (2.4 GHz) band. |
177 | */ | 177 | */ |
178 | 178 | ||
179 | static s32 expected_tpt_legacy[IWL_RATE_COUNT] = { | 179 | static const u16 expected_tpt_legacy[IWL_RATE_COUNT] = { |
180 | 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0 | 180 | 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0 |
181 | }; | 181 | }; |
182 | 182 | ||
183 | static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = { | 183 | static const u16 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = { |
184 | {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202}, /* Norm */ | 184 | {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202}, /* Norm */ |
185 | {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210}, /* SGI */ | 185 | {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210}, /* SGI */ |
186 | {0, 0, 0, 0, 47, 0, 91, 133, 171, 242, 305, 334, 362}, /* AGG */ | 186 | {0, 0, 0, 0, 47, 0, 91, 133, 171, 242, 305, 334, 362}, /* AGG */ |
187 | {0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */ | 187 | {0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */ |
188 | }; | 188 | }; |
189 | 189 | ||
190 | static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = { | 190 | static const u16 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = { |
191 | {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */ | 191 | {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */ |
192 | {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */ | 192 | {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */ |
193 | {0, 0, 0, 0, 94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */ | 193 | {0, 0, 0, 0, 94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */ |
194 | {0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */ | 194 | {0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */ |
195 | }; | 195 | }; |
196 | 196 | ||
197 | static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { | 197 | static const u16 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { |
198 | {0, 0, 0, 0, 74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */ | 198 | {0, 0, 0, 0, 74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */ |
199 | {0, 0, 0, 0, 81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */ | 199 | {0, 0, 0, 0, 81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */ |
200 | {0, 0, 0, 0, 89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */ | 200 | {0, 0, 0, 0, 89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */ |
201 | {0, 0, 0, 0, 97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/ | 201 | {0, 0, 0, 0, 97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/ |
202 | }; | 202 | }; |
203 | 203 | ||
204 | static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { | 204 | static const u16 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { |
205 | {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */ | 205 | {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */ |
206 | {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */ | 206 | {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */ |
207 | {0, 0, 0, 0, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */ | 207 | {0, 0, 0, 0, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */ |
208 | {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */ | 208 | {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */ |
209 | }; | 209 | }; |
210 | 210 | ||
211 | static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = { | 211 | static const u16 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = { |
212 | {0, 0, 0, 0, 99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */ | 212 | {0, 0, 0, 0, 99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */ |
213 | {0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */ | 213 | {0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */ |
214 | {0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */ | 214 | {0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */ |
215 | {0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */ | 215 | {0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */ |
216 | }; | 216 | }; |
217 | 217 | ||
218 | static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = { | 218 | static const u16 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = { |
219 | {0, 0, 0, 0, 152, 0, 211, 239, 255, 279, 290, 294, 297}, /* Norm */ | 219 | {0, 0, 0, 0, 152, 0, 211, 239, 255, 279, 290, 294, 297}, /* Norm */ |
220 | {0, 0, 0, 0, 160, 0, 219, 245, 261, 284, 294, 297, 300}, /* SGI */ | 220 | {0, 0, 0, 0, 160, 0, 219, 245, 261, 284, 294, 297, 300}, /* SGI */ |
221 | {0, 0, 0, 0, 254, 0, 443, 584, 695, 868, 984, 1030, 1070}, /* AGG */ | 221 | {0, 0, 0, 0, 254, 0, 443, 584, 695, 868, 984, 1030, 1070}, /* AGG */ |
@@ -1111,7 +1111,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, | |||
1111 | struct iwl_scale_tbl_info *tbl) | 1111 | struct iwl_scale_tbl_info *tbl) |
1112 | { | 1112 | { |
1113 | /* Used to choose among HT tables */ | 1113 | /* Used to choose among HT tables */ |
1114 | s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; | 1114 | const u16 (*ht_tbl_pointer)[IWL_RATE_COUNT]; |
1115 | 1115 | ||
1116 | /* Check for invalid LQ type */ | 1116 | /* Check for invalid LQ type */ |
1117 | if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) { | 1117 | if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) { |
@@ -1173,9 +1173,8 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, | |||
1173 | &(lq_sta->lq_info[lq_sta->active_tbl]); | 1173 | &(lq_sta->lq_info[lq_sta->active_tbl]); |
1174 | s32 active_sr = active_tbl->win[index].success_ratio; | 1174 | s32 active_sr = active_tbl->win[index].success_ratio; |
1175 | s32 active_tpt = active_tbl->expected_tpt[index]; | 1175 | s32 active_tpt = active_tbl->expected_tpt[index]; |
1176 | |||
1177 | /* expected "search" throughput */ | 1176 | /* expected "search" throughput */ |
1178 | s32 *tpt_tbl = tbl->expected_tpt; | 1177 | const u16 *tpt_tbl = tbl->expected_tpt; |
1179 | 1178 | ||
1180 | s32 new_rate, high, low, start_hi; | 1179 | s32 new_rate, high, low, start_hi; |
1181 | u16 high_low; | 1180 | u16 high_low; |
@@ -3319,8 +3318,8 @@ static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sba | |||
3319 | struct ieee80211_sta *sta, void *priv_sta) | 3318 | struct ieee80211_sta *sta, void *priv_sta) |
3320 | { | 3319 | { |
3321 | } | 3320 | } |
3322 | static struct rate_control_ops rs_ops = { | 3321 | |
3323 | .module = NULL, | 3322 | static const struct rate_control_ops rs_ops = { |
3324 | .name = RS_NAME, | 3323 | .name = RS_NAME, |
3325 | .tx_status = rs_tx_status, | 3324 | .tx_status = rs_tx_status, |
3326 | .get_rate = rs_get_rate, | 3325 | .get_rate = rs_get_rate, |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.h b/drivers/net/wireless/iwlwifi/dvm/rs.h index bdd5644a400b..f6bd25cad203 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.h +++ b/drivers/net/wireless/iwlwifi/dvm/rs.h | |||
@@ -315,7 +315,7 @@ struct iwl_scale_tbl_info { | |||
315 | u8 is_dup; /* 1 = duplicated data streams */ | 315 | u8 is_dup; /* 1 = duplicated data streams */ |
316 | u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ | 316 | u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ |
317 | u8 max_search; /* maximun number of tables we can search */ | 317 | u8 max_search; /* maximun number of tables we can search */ |
318 | s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ | 318 | const u16 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ |
319 | u32 current_rate; /* rate_n_flags, uCode API format */ | 319 | u32 current_rate; /* rate_n_flags, uCode API format */ |
320 | struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ | 320 | struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ |
321 | }; | 321 | }; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index 7a1bc1c547e1..cd8377346aff 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c | |||
@@ -39,7 +39,7 @@ | |||
39 | 39 | ||
40 | #define IWL_CMD_ENTRY(x) [x] = #x | 40 | #define IWL_CMD_ENTRY(x) [x] = #x |
41 | 41 | ||
42 | const char *iwl_dvm_cmd_strings[REPLY_MAX] = { | 42 | const char *const iwl_dvm_cmd_strings[REPLY_MAX] = { |
43 | IWL_CMD_ENTRY(REPLY_ALIVE), | 43 | IWL_CMD_ENTRY(REPLY_ALIVE), |
44 | IWL_CMD_ENTRY(REPLY_ERROR), | 44 | IWL_CMD_ENTRY(REPLY_ERROR), |
45 | IWL_CMD_ENTRY(REPLY_ECHO), | 45 | IWL_CMD_ENTRY(REPLY_ECHO), |
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 2a59da2ff87a..003a546571d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c | |||
@@ -71,8 +71,8 @@ | |||
71 | #define IWL3160_UCODE_API_MAX 8 | 71 | #define IWL3160_UCODE_API_MAX 8 |
72 | 72 | ||
73 | /* Oldest version we won't warn about */ | 73 | /* Oldest version we won't warn about */ |
74 | #define IWL7260_UCODE_API_OK 7 | 74 | #define IWL7260_UCODE_API_OK 8 |
75 | #define IWL3160_UCODE_API_OK 7 | 75 | #define IWL3160_UCODE_API_OK 8 |
76 | 76 | ||
77 | /* Lowest firmware API version supported */ | 77 | /* Lowest firmware API version supported */ |
78 | #define IWL7260_UCODE_API_MIN 7 | 78 | #define IWL7260_UCODE_API_MIN 7 |
@@ -95,6 +95,8 @@ | |||
95 | #define IWL7265_FW_PRE "iwlwifi-7265-" | 95 | #define IWL7265_FW_PRE "iwlwifi-7265-" |
96 | #define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" | 96 | #define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" |
97 | 97 | ||
98 | #define NVM_HW_SECTION_NUM_FAMILY_7000 0 | ||
99 | |||
98 | static const struct iwl_base_params iwl7000_base_params = { | 100 | static const struct iwl_base_params iwl7000_base_params = { |
99 | .eeprom_size = OTP_LOW_IMAGE_SIZE, | 101 | .eeprom_size = OTP_LOW_IMAGE_SIZE, |
100 | .num_of_queues = IWLAGN_NUM_QUEUES, | 102 | .num_of_queues = IWLAGN_NUM_QUEUES, |
@@ -120,7 +122,8 @@ static const struct iwl_ht_params iwl7000_ht_params = { | |||
120 | .max_inst_size = IWL60_RTC_INST_SIZE, \ | 122 | .max_inst_size = IWL60_RTC_INST_SIZE, \ |
121 | .max_data_size = IWL60_RTC_DATA_SIZE, \ | 123 | .max_data_size = IWL60_RTC_DATA_SIZE, \ |
122 | .base_params = &iwl7000_base_params, \ | 124 | .base_params = &iwl7000_base_params, \ |
123 | .led_mode = IWL_LED_RF_STATE | 125 | .led_mode = IWL_LED_RF_STATE, \ |
126 | .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000 | ||
124 | 127 | ||
125 | 128 | ||
126 | const struct iwl_cfg iwl7260_2ac_cfg = { | 129 | const struct iwl_cfg iwl7260_2ac_cfg = { |
@@ -131,6 +134,7 @@ const struct iwl_cfg iwl7260_2ac_cfg = { | |||
131 | .nvm_ver = IWL7260_NVM_VERSION, | 134 | .nvm_ver = IWL7260_NVM_VERSION, |
132 | .nvm_calib_ver = IWL7260_TX_POWER_VERSION, | 135 | .nvm_calib_ver = IWL7260_TX_POWER_VERSION, |
133 | .host_interrupt_operation_mode = true, | 136 | .host_interrupt_operation_mode = true, |
137 | .lp_xtal_workaround = true, | ||
134 | }; | 138 | }; |
135 | 139 | ||
136 | const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { | 140 | const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { |
@@ -142,6 +146,7 @@ const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { | |||
142 | .nvm_calib_ver = IWL7260_TX_POWER_VERSION, | 146 | .nvm_calib_ver = IWL7260_TX_POWER_VERSION, |
143 | .high_temp = true, | 147 | .high_temp = true, |
144 | .host_interrupt_operation_mode = true, | 148 | .host_interrupt_operation_mode = true, |
149 | .lp_xtal_workaround = true, | ||
145 | }; | 150 | }; |
146 | 151 | ||
147 | const struct iwl_cfg iwl7260_2n_cfg = { | 152 | const struct iwl_cfg iwl7260_2n_cfg = { |
@@ -152,6 +157,7 @@ const struct iwl_cfg iwl7260_2n_cfg = { | |||
152 | .nvm_ver = IWL7260_NVM_VERSION, | 157 | .nvm_ver = IWL7260_NVM_VERSION, |
153 | .nvm_calib_ver = IWL7260_TX_POWER_VERSION, | 158 | .nvm_calib_ver = IWL7260_TX_POWER_VERSION, |
154 | .host_interrupt_operation_mode = true, | 159 | .host_interrupt_operation_mode = true, |
160 | .lp_xtal_workaround = true, | ||
155 | }; | 161 | }; |
156 | 162 | ||
157 | const struct iwl_cfg iwl7260_n_cfg = { | 163 | const struct iwl_cfg iwl7260_n_cfg = { |
@@ -162,6 +168,7 @@ const struct iwl_cfg iwl7260_n_cfg = { | |||
162 | .nvm_ver = IWL7260_NVM_VERSION, | 168 | .nvm_ver = IWL7260_NVM_VERSION, |
163 | .nvm_calib_ver = IWL7260_TX_POWER_VERSION, | 169 | .nvm_calib_ver = IWL7260_TX_POWER_VERSION, |
164 | .host_interrupt_operation_mode = true, | 170 | .host_interrupt_operation_mode = true, |
171 | .lp_xtal_workaround = true, | ||
165 | }; | 172 | }; |
166 | 173 | ||
167 | const struct iwl_cfg iwl3160_2ac_cfg = { | 174 | const struct iwl_cfg iwl3160_2ac_cfg = { |
@@ -194,6 +201,17 @@ const struct iwl_cfg iwl3160_n_cfg = { | |||
194 | .host_interrupt_operation_mode = true, | 201 | .host_interrupt_operation_mode = true, |
195 | }; | 202 | }; |
196 | 203 | ||
204 | static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = { | ||
205 | {.pwr = 1600, .backoff = 0}, | ||
206 | {.pwr = 1300, .backoff = 467}, | ||
207 | {.pwr = 900, .backoff = 1900}, | ||
208 | {.pwr = 800, .backoff = 2630}, | ||
209 | {.pwr = 700, .backoff = 3720}, | ||
210 | {.pwr = 600, .backoff = 5550}, | ||
211 | {.pwr = 500, .backoff = 9350}, | ||
212 | {0}, | ||
213 | }; | ||
214 | |||
197 | const struct iwl_cfg iwl7265_2ac_cfg = { | 215 | const struct iwl_cfg iwl7265_2ac_cfg = { |
198 | .name = "Intel(R) Dual Band Wireless AC 7265", | 216 | .name = "Intel(R) Dual Band Wireless AC 7265", |
199 | .fw_name_pre = IWL7265_FW_PRE, | 217 | .fw_name_pre = IWL7265_FW_PRE, |
@@ -201,6 +219,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = { | |||
201 | .ht_params = &iwl7000_ht_params, | 219 | .ht_params = &iwl7000_ht_params, |
202 | .nvm_ver = IWL7265_NVM_VERSION, | 220 | .nvm_ver = IWL7265_NVM_VERSION, |
203 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, | 221 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, |
222 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, | ||
204 | }; | 223 | }; |
205 | 224 | ||
206 | const struct iwl_cfg iwl7265_2n_cfg = { | 225 | const struct iwl_cfg iwl7265_2n_cfg = { |
@@ -210,6 +229,7 @@ const struct iwl_cfg iwl7265_2n_cfg = { | |||
210 | .ht_params = &iwl7000_ht_params, | 229 | .ht_params = &iwl7000_ht_params, |
211 | .nvm_ver = IWL7265_NVM_VERSION, | 230 | .nvm_ver = IWL7265_NVM_VERSION, |
212 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, | 231 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, |
232 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, | ||
213 | }; | 233 | }; |
214 | 234 | ||
215 | const struct iwl_cfg iwl7265_n_cfg = { | 235 | const struct iwl_cfg iwl7265_n_cfg = { |
@@ -219,6 +239,7 @@ const struct iwl_cfg iwl7265_n_cfg = { | |||
219 | .ht_params = &iwl7000_ht_params, | 239 | .ht_params = &iwl7000_ht_params, |
220 | .nvm_ver = IWL7265_NVM_VERSION, | 240 | .nvm_ver = IWL7265_NVM_VERSION, |
221 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, | 241 | .nvm_calib_ver = IWL7265_TX_POWER_VERSION, |
242 | .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, | ||
222 | }; | 243 | }; |
223 | 244 | ||
224 | MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); | 245 | MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c new file mode 100644 index 000000000000..f5bd82b88592 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c | |||
@@ -0,0 +1,132 @@ | |||
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) 2014 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) 2014 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/module.h> | ||
65 | #include <linux/stringify.h> | ||
66 | #include "iwl-config.h" | ||
67 | #include "iwl-agn-hw.h" | ||
68 | |||
69 | /* Highest firmware API version supported */ | ||
70 | #define IWL8000_UCODE_API_MAX 8 | ||
71 | |||
72 | /* Oldest version we won't warn about */ | ||
73 | #define IWL8000_UCODE_API_OK 8 | ||
74 | |||
75 | /* Lowest firmware API version supported */ | ||
76 | #define IWL8000_UCODE_API_MIN 8 | ||
77 | |||
78 | /* NVM versions */ | ||
79 | #define IWL8000_NVM_VERSION 0x0a1d | ||
80 | #define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */ | ||
81 | |||
82 | #define IWL8000_FW_PRE "iwlwifi-8000-" | ||
83 | #define IWL8000_MODULE_FIRMWARE(api) IWL8000_FW_PRE __stringify(api) ".ucode" | ||
84 | |||
85 | #define NVM_HW_SECTION_NUM_FAMILY_8000 10 | ||
86 | |||
87 | static const struct iwl_base_params iwl8000_base_params = { | ||
88 | .eeprom_size = OTP_LOW_IMAGE_SIZE, | ||
89 | .num_of_queues = IWLAGN_NUM_QUEUES, | ||
90 | .pll_cfg_val = 0, | ||
91 | .shadow_ram_support = true, | ||
92 | .led_compensation = 57, | ||
93 | .wd_timeout = IWL_LONG_WD_TIMEOUT, | ||
94 | .max_event_log_size = 512, | ||
95 | .shadow_reg_enable = true, | ||
96 | .pcie_l1_allowed = true, | ||
97 | }; | ||
98 | |||
99 | static const struct iwl_ht_params iwl8000_ht_params = { | ||
100 | .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), | ||
101 | }; | ||
102 | |||
103 | #define IWL_DEVICE_8000 \ | ||
104 | .ucode_api_max = IWL8000_UCODE_API_MAX, \ | ||
105 | .ucode_api_ok = IWL8000_UCODE_API_OK, \ | ||
106 | .ucode_api_min = IWL8000_UCODE_API_MIN, \ | ||
107 | .device_family = IWL_DEVICE_FAMILY_8000, \ | ||
108 | .max_inst_size = IWL60_RTC_INST_SIZE, \ | ||
109 | .max_data_size = IWL60_RTC_DATA_SIZE, \ | ||
110 | .base_params = &iwl8000_base_params, \ | ||
111 | .led_mode = IWL_LED_RF_STATE, \ | ||
112 | .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000 | ||
113 | |||
114 | const struct iwl_cfg iwl8260_2ac_cfg = { | ||
115 | .name = "Intel(R) Dual Band Wireless AC 8260", | ||
116 | .fw_name_pre = IWL8000_FW_PRE, | ||
117 | IWL_DEVICE_8000, | ||
118 | .ht_params = &iwl8000_ht_params, | ||
119 | .nvm_ver = IWL8000_NVM_VERSION, | ||
120 | .nvm_calib_ver = IWL8000_TX_POWER_VERSION, | ||
121 | }; | ||
122 | |||
123 | const struct iwl_cfg iwl8260_n_cfg = { | ||
124 | .name = "Intel(R) Dual Band Wireless-AC 8260", | ||
125 | .fw_name_pre = IWL8000_FW_PRE, | ||
126 | IWL_DEVICE_8000, | ||
127 | .ht_params = &iwl8000_ht_params, | ||
128 | .nvm_ver = IWL8000_NVM_VERSION, | ||
129 | .nvm_calib_ver = IWL8000_TX_POWER_VERSION, | ||
130 | }; | ||
131 | |||
132 | MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 1ced525157dc..3f17dc3f2c8a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h | |||
@@ -84,6 +84,7 @@ enum iwl_device_family { | |||
84 | IWL_DEVICE_FAMILY_6050, | 84 | IWL_DEVICE_FAMILY_6050, |
85 | IWL_DEVICE_FAMILY_6150, | 85 | IWL_DEVICE_FAMILY_6150, |
86 | IWL_DEVICE_FAMILY_7000, | 86 | IWL_DEVICE_FAMILY_7000, |
87 | IWL_DEVICE_FAMILY_8000, | ||
87 | }; | 88 | }; |
88 | 89 | ||
89 | /* | 90 | /* |
@@ -192,6 +193,15 @@ struct iwl_eeprom_params { | |||
192 | bool enhanced_txpower; | 193 | bool enhanced_txpower; |
193 | }; | 194 | }; |
194 | 195 | ||
196 | /* Tx-backoff power threshold | ||
197 | * @pwr: The power limit in mw | ||
198 | * @backoff: The tx-backoff in uSec | ||
199 | */ | ||
200 | struct iwl_pwr_tx_backoff { | ||
201 | u32 pwr; | ||
202 | u32 backoff; | ||
203 | }; | ||
204 | |||
195 | /** | 205 | /** |
196 | * struct iwl_cfg | 206 | * struct iwl_cfg |
197 | * @name: Offical name of the device | 207 | * @name: Offical name of the device |
@@ -217,6 +227,9 @@ struct iwl_eeprom_params { | |||
217 | * @high_temp: Is this NIC is designated to be in high temperature. | 227 | * @high_temp: Is this NIC is designated to be in high temperature. |
218 | * @host_interrupt_operation_mode: device needs host interrupt operation | 228 | * @host_interrupt_operation_mode: device needs host interrupt operation |
219 | * mode set | 229 | * mode set |
230 | * @d0i3: device uses d0i3 instead of d3 | ||
231 | * @nvm_hw_section_num: the ID of the HW NVM section | ||
232 | * @pwr_tx_backoffs: translation table between power limits and backoffs | ||
220 | * | 233 | * |
221 | * We enable the driver to be backward compatible wrt. hardware features. | 234 | * We enable the driver to be backward compatible wrt. hardware features. |
222 | * API differences in uCode shouldn't be handled here but through TLVs | 235 | * API differences in uCode shouldn't be handled here but through TLVs |
@@ -247,6 +260,10 @@ struct iwl_cfg { | |||
247 | const bool internal_wimax_coex; | 260 | const bool internal_wimax_coex; |
248 | const bool host_interrupt_operation_mode; | 261 | const bool host_interrupt_operation_mode; |
249 | bool high_temp; | 262 | bool high_temp; |
263 | bool d0i3; | ||
264 | u8 nvm_hw_section_num; | ||
265 | bool lp_xtal_workaround; | ||
266 | const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; | ||
250 | }; | 267 | }; |
251 | 268 | ||
252 | /* | 269 | /* |
@@ -307,6 +324,8 @@ extern const struct iwl_cfg iwl3160_n_cfg; | |||
307 | extern const struct iwl_cfg iwl7265_2ac_cfg; | 324 | extern const struct iwl_cfg iwl7265_2ac_cfg; |
308 | extern const struct iwl_cfg iwl7265_2n_cfg; | 325 | extern const struct iwl_cfg iwl7265_2n_cfg; |
309 | extern const struct iwl_cfg iwl7265_n_cfg; | 326 | extern const struct iwl_cfg iwl7265_n_cfg; |
327 | extern const struct iwl_cfg iwl8260_2ac_cfg; | ||
328 | extern const struct iwl_cfg iwl8260_n_cfg; | ||
310 | #endif /* CONFIG_IWLMVM */ | 329 | #endif /* CONFIG_IWLMVM */ |
311 | 330 | ||
312 | #endif /* __IWL_CONFIG_H__ */ | 331 | #endif /* __IWL_CONFIG_H__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 9d325516c42d..fe129c94ae3e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h | |||
@@ -139,6 +139,13 @@ | |||
139 | #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) | 139 | #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) |
140 | 140 | ||
141 | /* | 141 | /* |
142 | * CSR HW resources monitor registers | ||
143 | */ | ||
144 | #define CSR_MONITOR_CFG_REG (CSR_BASE+0x214) | ||
145 | #define CSR_MONITOR_STATUS_REG (CSR_BASE+0x228) | ||
146 | #define CSR_MONITOR_XTAL_RESOURCES (0x00000010) | ||
147 | |||
148 | /* | ||
142 | * CSR Hardware Revision Workaround Register. Indicates hardware rev; | 149 | * CSR Hardware Revision Workaround Register. Indicates hardware rev; |
143 | * "step" determines CCK backoff for txpower calculation. Used for 4965 only. | 150 | * "step" determines CCK backoff for txpower calculation. Used for 4965 only. |
144 | * See also CSR_HW_REV register. | 151 | * See also CSR_HW_REV register. |
@@ -173,6 +180,7 @@ | |||
173 | #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ | 180 | #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ |
174 | #define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */ | 181 | #define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */ |
175 | #define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ | 182 | #define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ |
183 | #define CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */ | ||
176 | 184 | ||
177 | #define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ | 185 | #define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ |
178 | #define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ | 186 | #define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ |
@@ -240,6 +248,7 @@ | |||
240 | * 001 -- MAC power-down | 248 | * 001 -- MAC power-down |
241 | * 010 -- PHY (radio) power-down | 249 | * 010 -- PHY (radio) power-down |
242 | * 011 -- Error | 250 | * 011 -- Error |
251 | * 10: XTAL ON request | ||
243 | * 9-6: SYS_CONFIG | 252 | * 9-6: SYS_CONFIG |
244 | * Indicates current system configuration, reflecting pins on chip | 253 | * Indicates current system configuration, reflecting pins on chip |
245 | * as forced high/low by device circuit board. | 254 | * as forced high/low by device circuit board. |
@@ -271,6 +280,7 @@ | |||
271 | #define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) | 280 | #define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) |
272 | #define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) | 281 | #define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) |
273 | #define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) | 282 | #define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) |
283 | #define CSR_GP_CNTRL_REG_FLAG_XTAL_ON (0x00000400) | ||
274 | 284 | ||
275 | #define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) | 285 | #define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) |
276 | 286 | ||
@@ -395,37 +405,33 @@ | |||
395 | #define CSR_DRAM_INT_TBL_ENABLE (1 << 31) | 405 | #define CSR_DRAM_INT_TBL_ENABLE (1 << 31) |
396 | #define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) | 406 | #define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) |
397 | 407 | ||
398 | /* SECURE boot registers */ | 408 | /* |
399 | #define CSR_SECURE_BOOT_CONFIG_ADDR (0x100) | 409 | * SHR target access (Shared block memory space) |
400 | enum secure_boot_config_reg { | 410 | * |
401 | CSR_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP = 0x00000001, | 411 | * Shared internal registers can be accessed directly from PCI bus through SHR |
402 | CSR_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002, | 412 | * arbiter without need for the MAC HW to be powered up. This is possible due to |
403 | }; | 413 | * indirect read/write via HEEP_CTRL_WRD_PCIEX_CTRL (0xEC) and |
404 | 414 | * HEEP_CTRL_WRD_PCIEX_DATA (0xF4) registers. | |
405 | #define CSR_SECURE_BOOT_CPU1_STATUS_ADDR (0x100) | 415 | * |
406 | #define CSR_SECURE_BOOT_CPU2_STATUS_ADDR (0x100) | 416 | * Use iwl_write32()/iwl_read32() family to access these registers. The MAC HW |
407 | enum secure_boot_status_reg { | 417 | * need not be powered up so no "grab inc access" is required. |
408 | CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS = 0x00000003, | 418 | */ |
409 | CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED = 0x00000002, | ||
410 | CSR_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS = 0x00000004, | ||
411 | CSR_SECURE_BOOT_CPU_STATUS_VERF_FAIL = 0x00000008, | ||
412 | CSR_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL = 0x00000010, | ||
413 | }; | ||
414 | |||
415 | #define CSR_UCODE_LOAD_STATUS_ADDR (0x100) | ||
416 | enum secure_load_status_reg { | ||
417 | CSR_CPU_STATUS_LOADING_STARTED = 0x00000001, | ||
418 | CSR_CPU_STATUS_LOADING_COMPLETED = 0x00000002, | ||
419 | CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8, | ||
420 | CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00, | ||
421 | }; | ||
422 | |||
423 | #define CSR_SECURE_INSPECTOR_CODE_ADDR (0x100) | ||
424 | #define CSR_SECURE_INSPECTOR_DATA_ADDR (0x100) | ||
425 | |||
426 | #define CSR_SECURE_TIME_OUT (100) | ||
427 | 419 | ||
428 | #define FH_TCSR_0_REG0 (0x1D00) | 420 | /* |
421 | * Registers for accessing shared registers (e.g. SHR_APMG_GP1, | ||
422 | * SHR_APMG_XTAL_CFG). For example, to read from SHR_APMG_GP1 register (0x1DC), | ||
423 | * first, write to the control register: | ||
424 | * HEEP_CTRL_WRD_PCIEX_CTRL[15:0] = 0x1DC (offset of the SHR_APMG_GP1 register) | ||
425 | * HEEP_CTRL_WRD_PCIEX_CTRL[29:28] = 2 (read access) | ||
426 | * second, read from the data register HEEP_CTRL_WRD_PCIEX_DATA[31:0]. | ||
427 | * | ||
428 | * To write the register, first, write to the data register | ||
429 | * HEEP_CTRL_WRD_PCIEX_DATA[31:0] and then: | ||
430 | * HEEP_CTRL_WRD_PCIEX_CTRL[15:0] = 0x1DC (offset of the SHR_APMG_GP1 register) | ||
431 | * HEEP_CTRL_WRD_PCIEX_CTRL[29:28] = 3 (write access) | ||
432 | */ | ||
433 | #define HEEP_CTRL_WRD_PCIEX_CTRL_REG (CSR_BASE+0x0ec) | ||
434 | #define HEEP_CTRL_WRD_PCIEX_DATA_REG (CSR_BASE+0x0f4) | ||
429 | 435 | ||
430 | /* | 436 | /* |
431 | * HBUS (Host-side Bus) | 437 | * HBUS (Host-side Bus) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index a75aac986a23..c8cbdbe15924 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h | |||
@@ -126,6 +126,7 @@ do { \ | |||
126 | /* 0x00000F00 - 0x00000100 */ | 126 | /* 0x00000F00 - 0x00000100 */ |
127 | #define IWL_DL_POWER 0x00000100 | 127 | #define IWL_DL_POWER 0x00000100 |
128 | #define IWL_DL_TEMP 0x00000200 | 128 | #define IWL_DL_TEMP 0x00000200 |
129 | #define IWL_DL_RPM 0x00000400 | ||
129 | #define IWL_DL_SCAN 0x00000800 | 130 | #define IWL_DL_SCAN 0x00000800 |
130 | /* 0x0000F000 - 0x00001000 */ | 131 | /* 0x0000F000 - 0x00001000 */ |
131 | #define IWL_DL_ASSOC 0x00001000 | 132 | #define IWL_DL_ASSOC 0x00001000 |
@@ -189,5 +190,6 @@ do { \ | |||
189 | #define IWL_DEBUG_RADIO(p, f, a...) IWL_DEBUG(p, IWL_DL_RADIO, f, ## a) | 190 | #define IWL_DEBUG_RADIO(p, f, a...) IWL_DEBUG(p, IWL_DL_RADIO, f, ## a) |
190 | #define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a) | 191 | #define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a) |
191 | #define IWL_DEBUG_11H(p, f, a...) IWL_DEBUG(p, IWL_DL_11H, f, ## a) | 192 | #define IWL_DEBUG_11H(p, f, a...) IWL_DEBUG(p, IWL_DL_11H, f, ## a) |
193 | #define IWL_DEBUG_RPM(p, f, a...) IWL_DEBUG(p, IWL_DL_RPM, f, ## a) | ||
192 | 194 | ||
193 | #endif | 195 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 75103554cd63..0a3e841b44a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -128,7 +128,7 @@ struct iwl_drv { | |||
128 | const struct iwl_cfg *cfg; | 128 | const struct iwl_cfg *cfg; |
129 | 129 | ||
130 | int fw_index; /* firmware we're trying to load */ | 130 | int fw_index; /* firmware we're trying to load */ |
131 | char firmware_name[25]; /* name of firmware file to load */ | 131 | char firmware_name[32]; /* name of firmware file to load */ |
132 | 132 | ||
133 | struct completion request_firmware_complete; | 133 | struct completion request_firmware_complete; |
134 | 134 | ||
@@ -237,7 +237,8 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) | |||
237 | return -ENOENT; | 237 | return -ENOENT; |
238 | } | 238 | } |
239 | 239 | ||
240 | sprintf(drv->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); | 240 | snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s.ucode", |
241 | name_pre, tag); | ||
241 | 242 | ||
242 | IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n", | 243 | IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n", |
243 | (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) | 244 | (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) |
@@ -403,6 +404,38 @@ static int iwl_set_default_calib(struct iwl_drv *drv, const u8 *data) | |||
403 | return 0; | 404 | return 0; |
404 | } | 405 | } |
405 | 406 | ||
407 | static int iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data, | ||
408 | struct iwl_ucode_capabilities *capa) | ||
409 | { | ||
410 | const struct iwl_ucode_api *ucode_api = (void *)data; | ||
411 | u32 api_index = le32_to_cpu(ucode_api->api_index); | ||
412 | |||
413 | if (api_index >= IWL_API_ARRAY_SIZE) { | ||
414 | IWL_ERR(drv, "api_index larger than supported by driver\n"); | ||
415 | return -EINVAL; | ||
416 | } | ||
417 | |||
418 | capa->api[api_index] = le32_to_cpu(ucode_api->api_flags); | ||
419 | |||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static int iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data, | ||
424 | struct iwl_ucode_capabilities *capa) | ||
425 | { | ||
426 | const struct iwl_ucode_capa *ucode_capa = (void *)data; | ||
427 | u32 api_index = le32_to_cpu(ucode_capa->api_index); | ||
428 | |||
429 | if (api_index >= IWL_CAPABILITIES_ARRAY_SIZE) { | ||
430 | IWL_ERR(drv, "api_index larger than supported by driver\n"); | ||
431 | return -EINVAL; | ||
432 | } | ||
433 | |||
434 | capa->capa[api_index] = le32_to_cpu(ucode_capa->api_capa); | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
406 | static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, | 439 | static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, |
407 | const struct firmware *ucode_raw, | 440 | const struct firmware *ucode_raw, |
408 | struct iwl_firmware_pieces *pieces) | 441 | struct iwl_firmware_pieces *pieces) |
@@ -637,6 +670,18 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, | |||
637 | */ | 670 | */ |
638 | capa->flags = le32_to_cpup((__le32 *)tlv_data); | 671 | capa->flags = le32_to_cpup((__le32 *)tlv_data); |
639 | break; | 672 | break; |
673 | case IWL_UCODE_TLV_API_CHANGES_SET: | ||
674 | if (tlv_len != sizeof(struct iwl_ucode_api)) | ||
675 | goto invalid_tlv_len; | ||
676 | if (iwl_set_ucode_api_flags(drv, tlv_data, capa)) | ||
677 | goto tlv_error; | ||
678 | break; | ||
679 | case IWL_UCODE_TLV_ENABLED_CAPABILITIES: | ||
680 | if (tlv_len != sizeof(struct iwl_ucode_capa)) | ||
681 | goto invalid_tlv_len; | ||
682 | if (iwl_set_ucode_capabilities(drv, tlv_data, capa)) | ||
683 | goto tlv_error; | ||
684 | break; | ||
640 | case IWL_UCODE_TLV_INIT_EVTLOG_PTR: | 685 | case IWL_UCODE_TLV_INIT_EVTLOG_PTR: |
641 | if (tlv_len != sizeof(u32)) | 686 | if (tlv_len != sizeof(u32)) |
642 | goto invalid_tlv_len; | 687 | goto invalid_tlv_len; |
@@ -727,6 +772,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, | |||
727 | if (tlv_len != sizeof(u32)) | 772 | if (tlv_len != sizeof(u32)) |
728 | goto invalid_tlv_len; | 773 | goto invalid_tlv_len; |
729 | drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data); | 774 | drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data); |
775 | drv->fw.valid_tx_ant = (drv->fw.phy_config & | ||
776 | FW_PHY_CFG_TX_CHAIN) >> | ||
777 | FW_PHY_CFG_TX_CHAIN_POS; | ||
778 | drv->fw.valid_rx_ant = (drv->fw.phy_config & | ||
779 | FW_PHY_CFG_RX_CHAIN) >> | ||
780 | FW_PHY_CFG_RX_CHAIN_POS; | ||
730 | break; | 781 | break; |
731 | case IWL_UCODE_TLV_SECURE_SEC_RT: | 782 | case IWL_UCODE_TLV_SECURE_SEC_RT: |
732 | iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR, | 783 | iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR, |
@@ -1300,8 +1351,7 @@ MODULE_PARM_DESC(antenna_coupling, | |||
1300 | 1351 | ||
1301 | module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); | 1352 | module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); |
1302 | MODULE_PARM_DESC(wd_disable, | 1353 | MODULE_PARM_DESC(wd_disable, |
1303 | "Disable stuck queue watchdog timer 0=system default, " | 1354 | "Disable stuck queue watchdog timer 0=system default, 1=disable (default: 1)"); |
1304 | "1=disable, 2=enable (default: 0)"); | ||
1305 | 1355 | ||
1306 | module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO); | 1356 | module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO); |
1307 | MODULE_PARM_DESC(nvm_file, "NVM file name"); | 1357 | MODULE_PARM_DESC(nvm_file, "NVM file name"); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h index 592c01e11013..3c72cb710b0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h | |||
@@ -70,6 +70,20 @@ | |||
70 | #define DRV_COPYRIGHT "Copyright(c) 2003- 2014 Intel Corporation" | 70 | #define DRV_COPYRIGHT "Copyright(c) 2003- 2014 Intel Corporation" |
71 | #define DRV_AUTHOR "<ilw@linux.intel.com>" | 71 | #define DRV_AUTHOR "<ilw@linux.intel.com>" |
72 | 72 | ||
73 | /* radio config bits (actual values from NVM definition) */ | ||
74 | #define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */ | ||
75 | #define NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */ | ||
76 | #define NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */ | ||
77 | #define NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */ | ||
78 | #define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ | ||
79 | #define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ | ||
80 | |||
81 | #define NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(x) (x & 0xF) | ||
82 | #define NVM_RF_CFG_DASH_MSK_FAMILY_8000(x) ((x >> 4) & 0xF) | ||
83 | #define NVM_RF_CFG_STEP_MSK_FAMILY_8000(x) ((x >> 8) & 0xF) | ||
84 | #define NVM_RF_CFG_TYPE_MSK_FAMILY_8000(x) ((x >> 12) & 0xFFF) | ||
85 | #define NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(x) ((x >> 24) & 0xF) | ||
86 | #define NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(x) ((x >> 28) & 0xF) | ||
73 | 87 | ||
74 | /** | 88 | /** |
75 | * DOC: Driver system flows - drv component | 89 | * DOC: Driver system flows - drv component |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h index e3c7deafabe6..f0548b8a64b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h | |||
@@ -81,16 +81,17 @@ struct iwl_nvm_data { | |||
81 | bool sku_cap_band_24GHz_enable; | 81 | bool sku_cap_band_24GHz_enable; |
82 | bool sku_cap_band_52GHz_enable; | 82 | bool sku_cap_band_52GHz_enable; |
83 | bool sku_cap_11n_enable; | 83 | bool sku_cap_11n_enable; |
84 | bool sku_cap_11ac_enable; | ||
84 | bool sku_cap_amt_enable; | 85 | bool sku_cap_amt_enable; |
85 | bool sku_cap_ipan_enable; | 86 | bool sku_cap_ipan_enable; |
86 | 87 | ||
87 | u8 radio_cfg_type; | 88 | u16 radio_cfg_type; |
88 | u8 radio_cfg_step; | 89 | u8 radio_cfg_step; |
89 | u8 radio_cfg_dash; | 90 | u8 radio_cfg_dash; |
90 | u8 radio_cfg_pnum; | 91 | u8 radio_cfg_pnum; |
91 | u8 valid_tx_ant, valid_rx_ant; | 92 | u8 valid_tx_ant, valid_rx_ant; |
92 | 93 | ||
93 | u16 nvm_version; | 94 | u32 nvm_version; |
94 | s8 max_tx_pwr_half_dbm; | 95 | s8 max_tx_pwr_half_dbm; |
95 | 96 | ||
96 | struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; | 97 | struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 88e2d6eb569f..b45e576a4b57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h | |||
@@ -126,6 +126,8 @@ enum iwl_ucode_tlv_type { | |||
126 | IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26, | 126 | IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26, |
127 | IWL_UCODE_TLV_NUM_OF_CPU = 27, | 127 | IWL_UCODE_TLV_NUM_OF_CPU = 27, |
128 | IWL_UCODE_TLV_CSCHEME = 28, | 128 | IWL_UCODE_TLV_CSCHEME = 28, |
129 | IWL_UCODE_TLV_API_CHANGES_SET = 29, | ||
130 | IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, | ||
129 | }; | 131 | }; |
130 | 132 | ||
131 | struct iwl_ucode_tlv { | 133 | struct iwl_ucode_tlv { |
@@ -158,4 +160,19 @@ struct iwl_tlv_ucode_header { | |||
158 | u8 data[0]; | 160 | u8 data[0]; |
159 | }; | 161 | }; |
160 | 162 | ||
163 | /* | ||
164 | * ucode TLVs | ||
165 | * | ||
166 | * ability to get extension for: flags & capabilities from ucode binaries files | ||
167 | */ | ||
168 | struct iwl_ucode_api { | ||
169 | __le32 api_index; | ||
170 | __le32 api_flags; | ||
171 | } __packed; | ||
172 | |||
173 | struct iwl_ucode_capa { | ||
174 | __le32 api_index; | ||
175 | __le32 api_capa; | ||
176 | } __packed; | ||
177 | |||
161 | #endif /* __iwl_fw_file_h__ */ | 178 | #endif /* __iwl_fw_file_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 5f1493c44097..d14f19339d61 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h | |||
@@ -92,9 +92,11 @@ | |||
92 | * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API | 92 | * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API |
93 | * @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command | 93 | * @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command |
94 | * containing CAM (Continuous Active Mode) indication. | 94 | * containing CAM (Continuous Active Mode) indication. |
95 | * @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a | 95 | * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and |
96 | * single bound interface). | 96 | * P2P client interfaces simultaneously if they are in different bindings. |
97 | * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save | 97 | * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save |
98 | * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. | ||
99 | * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients | ||
98 | */ | 100 | */ |
99 | enum iwl_ucode_tlv_flag { | 101 | enum iwl_ucode_tlv_flag { |
100 | IWL_UCODE_TLV_FLAGS_PAN = BIT(0), | 102 | IWL_UCODE_TLV_FLAGS_PAN = BIT(0), |
@@ -116,9 +118,27 @@ enum iwl_ucode_tlv_flag { | |||
116 | IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17), | 118 | IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17), |
117 | IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19), | 119 | IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19), |
118 | IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD = BIT(20), | 120 | IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD = BIT(20), |
119 | IWL_UCODE_TLV_FLAGS_P2P_PS = BIT(21), | 121 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM = BIT(22), |
120 | IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), | 122 | IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), |
121 | IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), | 123 | IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), |
124 | IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29), | ||
125 | IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30), | ||
126 | }; | ||
127 | |||
128 | /** | ||
129 | * enum iwl_ucode_tlv_api - ucode api | ||
130 | * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. | ||
131 | */ | ||
132 | enum iwl_ucode_tlv_api { | ||
133 | IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), | ||
134 | }; | ||
135 | |||
136 | /** | ||
137 | * enum iwl_ucode_tlv_capa - ucode capabilities | ||
138 | * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 | ||
139 | */ | ||
140 | enum iwl_ucode_tlv_capa { | ||
141 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), | ||
122 | }; | 142 | }; |
123 | 143 | ||
124 | /* The default calibrate table size if not specified by firmware file */ | 144 | /* The default calibrate table size if not specified by firmware file */ |
@@ -160,13 +180,16 @@ enum iwl_ucode_sec { | |||
160 | * For 16.0 uCode and above, there is no differentiation between sections, | 180 | * For 16.0 uCode and above, there is no differentiation between sections, |
161 | * just an offset to the HW address. | 181 | * just an offset to the HW address. |
162 | */ | 182 | */ |
163 | #define IWL_UCODE_SECTION_MAX 6 | 183 | #define IWL_UCODE_SECTION_MAX 12 |
164 | #define IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU (IWL_UCODE_SECTION_MAX/2) | 184 | #define IWL_API_ARRAY_SIZE 1 |
185 | #define IWL_CAPABILITIES_ARRAY_SIZE 1 | ||
165 | 186 | ||
166 | struct iwl_ucode_capabilities { | 187 | struct iwl_ucode_capabilities { |
167 | u32 max_probe_length; | 188 | u32 max_probe_length; |
168 | u32 standard_phy_calibration_size; | 189 | u32 standard_phy_calibration_size; |
169 | u32 flags; | 190 | u32 flags; |
191 | u32 api[IWL_API_ARRAY_SIZE]; | ||
192 | u32 capa[IWL_CAPABILITIES_ARRAY_SIZE]; | ||
170 | }; | 193 | }; |
171 | 194 | ||
172 | /* one for each uCode image (inst/data, init/runtime/wowlan) */ | 195 | /* one for each uCode image (inst/data, init/runtime/wowlan) */ |
@@ -285,22 +308,12 @@ struct iwl_fw { | |||
285 | 308 | ||
286 | struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX]; | 309 | struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX]; |
287 | u32 phy_config; | 310 | u32 phy_config; |
311 | u8 valid_tx_ant; | ||
312 | u8 valid_rx_ant; | ||
288 | 313 | ||
289 | bool mvm_fw; | 314 | bool mvm_fw; |
290 | 315 | ||
291 | struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; | 316 | struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; |
292 | }; | 317 | }; |
293 | 318 | ||
294 | static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw) | ||
295 | { | ||
296 | return (fw->phy_config & FW_PHY_CFG_TX_CHAIN) >> | ||
297 | FW_PHY_CFG_TX_CHAIN_POS; | ||
298 | } | ||
299 | |||
300 | static inline u8 iwl_fw_valid_rx_ant(const struct iwl_fw *fw) | ||
301 | { | ||
302 | return (fw->phy_config & FW_PHY_CFG_RX_CHAIN) >> | ||
303 | FW_PHY_CFG_RX_CHAIN_POS; | ||
304 | } | ||
305 | |||
306 | #endif /* __iwl_fw_h__ */ | 319 | #endif /* __iwl_fw_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index f98175a0d35b..44cc3cf45762 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c | |||
@@ -93,14 +93,14 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, | |||
93 | } | 93 | } |
94 | IWL_EXPORT_SYMBOL(iwl_poll_direct_bit); | 94 | IWL_EXPORT_SYMBOL(iwl_poll_direct_bit); |
95 | 95 | ||
96 | static inline u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs) | 96 | u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs) |
97 | { | 97 | { |
98 | u32 val = iwl_trans_read_prph(trans, ofs); | 98 | u32 val = iwl_trans_read_prph(trans, ofs); |
99 | trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val); | 99 | trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val); |
100 | return val; | 100 | return val; |
101 | } | 101 | } |
102 | 102 | ||
103 | static inline void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) | 103 | void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) |
104 | { | 104 | { |
105 | trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val); | 105 | trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val); |
106 | iwl_trans_write_prph(trans, ofs, val); | 106 | iwl_trans_write_prph(trans, ofs, val); |
@@ -130,6 +130,21 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) | |||
130 | } | 130 | } |
131 | IWL_EXPORT_SYMBOL(iwl_write_prph); | 131 | IWL_EXPORT_SYMBOL(iwl_write_prph); |
132 | 132 | ||
133 | int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, | ||
134 | u32 bits, u32 mask, int timeout) | ||
135 | { | ||
136 | int t = 0; | ||
137 | |||
138 | do { | ||
139 | if ((iwl_read_prph(trans, addr) & mask) == (bits & mask)) | ||
140 | return t; | ||
141 | udelay(IWL_POLL_INTERVAL); | ||
142 | t += IWL_POLL_INTERVAL; | ||
143 | } while (t < timeout); | ||
144 | |||
145 | return -ETIMEDOUT; | ||
146 | } | ||
147 | |||
133 | void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) | 148 | void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) |
134 | { | 149 | { |
135 | unsigned long flags; | 150 | unsigned long flags; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index c339c1bed080..665ddd9dbbc4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h | |||
@@ -70,8 +70,12 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg); | |||
70 | void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value); | 70 | void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value); |
71 | 71 | ||
72 | 72 | ||
73 | u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs); | ||
73 | u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs); | 74 | u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs); |
75 | void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val); | ||
74 | void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val); | 76 | void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val); |
77 | int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, | ||
78 | u32 bits, u32 mask, int timeout); | ||
75 | void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); | 79 | void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); |
76 | void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, | 80 | void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, |
77 | u32 bits, u32 mask); | 81 | u32 bits, u32 mask); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index b29075c3da8e..d994317db85b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h | |||
@@ -96,7 +96,7 @@ enum iwl_disable_11n { | |||
96 | * use IWL_[DIS,EN]ABLE_HT_* constants | 96 | * use IWL_[DIS,EN]ABLE_HT_* constants |
97 | * @amsdu_size_8K: enable 8K amsdu size, default = 0 | 97 | * @amsdu_size_8K: enable 8K amsdu size, default = 0 |
98 | * @restart_fw: restart firmware, default = 1 | 98 | * @restart_fw: restart firmware, default = 1 |
99 | * @wd_disable: enable stuck queue check, default = 0 | 99 | * @wd_disable: disable stuck queue check, default = 1 |
100 | * @bt_coex_active: enable bt coex, default = true | 100 | * @bt_coex_active: enable bt coex, default = true |
101 | * @led_mode: system default, default = 0 | 101 | * @led_mode: system default, default = 0 |
102 | * @power_save: disable power save, default = false | 102 | * @power_save: disable power save, default = false |
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 725e954d8475..6be30c698506 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | |||
@@ -71,7 +71,7 @@ enum wkp_nvm_offsets { | |||
71 | /* NVM HW-Section offset (in words) definitions */ | 71 | /* NVM HW-Section offset (in words) definitions */ |
72 | HW_ADDR = 0x15, | 72 | HW_ADDR = 0x15, |
73 | 73 | ||
74 | /* NVM SW-Section offset (in words) definitions */ | 74 | /* NVM SW-Section offset (in words) definitions */ |
75 | NVM_SW_SECTION = 0x1C0, | 75 | NVM_SW_SECTION = 0x1C0, |
76 | NVM_VERSION = 0, | 76 | NVM_VERSION = 0, |
77 | RADIO_CFG = 1, | 77 | RADIO_CFG = 1, |
@@ -79,11 +79,32 @@ enum wkp_nvm_offsets { | |||
79 | N_HW_ADDRS = 3, | 79 | N_HW_ADDRS = 3, |
80 | NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION, | 80 | NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION, |
81 | 81 | ||
82 | /* NVM calibration section offset (in words) definitions */ | 82 | /* NVM calibration section offset (in words) definitions */ |
83 | NVM_CALIB_SECTION = 0x2B8, | 83 | NVM_CALIB_SECTION = 0x2B8, |
84 | XTAL_CALIB = 0x316 - NVM_CALIB_SECTION | 84 | XTAL_CALIB = 0x316 - NVM_CALIB_SECTION |
85 | }; | 85 | }; |
86 | 86 | ||
87 | enum family_8000_nvm_offsets { | ||
88 | /* NVM HW-Section offset (in words) definitions */ | ||
89 | HW_ADDR0_FAMILY_8000 = 0x12, | ||
90 | HW_ADDR1_FAMILY_8000 = 0x16, | ||
91 | MAC_ADDRESS_OVERRIDE_FAMILY_8000 = 1, | ||
92 | |||
93 | /* NVM SW-Section offset (in words) definitions */ | ||
94 | NVM_SW_SECTION_FAMILY_8000 = 0x1C0, | ||
95 | NVM_VERSION_FAMILY_8000 = 0, | ||
96 | RADIO_CFG_FAMILY_8000 = 2, | ||
97 | SKU_FAMILY_8000 = 4, | ||
98 | N_HW_ADDRS_FAMILY_8000 = 5, | ||
99 | |||
100 | /* NVM REGULATORY -Section offset (in words) definitions */ | ||
101 | NVM_CHANNELS_FAMILY_8000 = 0, | ||
102 | |||
103 | /* NVM calibration section offset (in words) definitions */ | ||
104 | NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8, | ||
105 | XTAL_CALIB_FAMILY_8000 = 0x316 - NVM_CALIB_SECTION_FAMILY_8000 | ||
106 | }; | ||
107 | |||
87 | /* SKU Capabilities (actual values from NVM definition) */ | 108 | /* SKU Capabilities (actual values from NVM definition) */ |
88 | enum nvm_sku_bits { | 109 | enum nvm_sku_bits { |
89 | NVM_SKU_CAP_BAND_24GHZ = BIT(0), | 110 | NVM_SKU_CAP_BAND_24GHZ = BIT(0), |
@@ -92,14 +113,6 @@ enum nvm_sku_bits { | |||
92 | NVM_SKU_CAP_11AC_ENABLE = BIT(3), | 113 | NVM_SKU_CAP_11AC_ENABLE = BIT(3), |
93 | }; | 114 | }; |
94 | 115 | ||
95 | /* radio config bits (actual values from NVM definition) */ | ||
96 | #define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */ | ||
97 | #define NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */ | ||
98 | #define NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */ | ||
99 | #define NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */ | ||
100 | #define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ | ||
101 | #define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ | ||
102 | |||
103 | /* | 116 | /* |
104 | * These are the channel numbers in the order that they are stored in the NVM | 117 | * These are the channel numbers in the order that they are stored in the NVM |
105 | */ | 118 | */ |
@@ -112,7 +125,17 @@ static const u8 iwl_nvm_channels[] = { | |||
112 | 149, 153, 157, 161, 165 | 125 | 149, 153, 157, 161, 165 |
113 | }; | 126 | }; |
114 | 127 | ||
128 | static const u8 iwl_nvm_channels_family_8000[] = { | ||
129 | /* 2.4 GHz */ | ||
130 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, | ||
131 | /* 5 GHz */ | ||
132 | 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, | ||
133 | 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, | ||
134 | 149, 153, 157, 161, 165, 169, 173, 177, 181 | ||
135 | }; | ||
136 | |||
115 | #define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) | 137 | #define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) |
138 | #define IWL_NUM_CHANNELS_FAMILY_8000 ARRAY_SIZE(iwl_nvm_channels_family_8000) | ||
116 | #define NUM_2GHZ_CHANNELS 14 | 139 | #define NUM_2GHZ_CHANNELS 14 |
117 | #define FIRST_2GHZ_HT_MINUS 5 | 140 | #define FIRST_2GHZ_HT_MINUS 5 |
118 | #define LAST_2GHZ_HT_PLUS 9 | 141 | #define LAST_2GHZ_HT_PLUS 9 |
@@ -179,8 +202,18 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, | |||
179 | struct ieee80211_channel *channel; | 202 | struct ieee80211_channel *channel; |
180 | u16 ch_flags; | 203 | u16 ch_flags; |
181 | bool is_5ghz; | 204 | bool is_5ghz; |
205 | int num_of_ch; | ||
206 | const u8 *nvm_chan; | ||
207 | |||
208 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { | ||
209 | num_of_ch = IWL_NUM_CHANNELS; | ||
210 | nvm_chan = &iwl_nvm_channels[0]; | ||
211 | } else { | ||
212 | num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000; | ||
213 | nvm_chan = &iwl_nvm_channels_family_8000[0]; | ||
214 | } | ||
182 | 215 | ||
183 | for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) { | 216 | for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { |
184 | ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); | 217 | ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); |
185 | 218 | ||
186 | if (ch_idx >= NUM_2GHZ_CHANNELS && | 219 | if (ch_idx >= NUM_2GHZ_CHANNELS && |
@@ -190,7 +223,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, | |||
190 | if (!(ch_flags & NVM_CHANNEL_VALID)) { | 223 | if (!(ch_flags & NVM_CHANNEL_VALID)) { |
191 | IWL_DEBUG_EEPROM(dev, | 224 | IWL_DEBUG_EEPROM(dev, |
192 | "Ch. %d Flags %x [%sGHz] - No traffic\n", | 225 | "Ch. %d Flags %x [%sGHz] - No traffic\n", |
193 | iwl_nvm_channels[ch_idx], | 226 | nvm_chan[ch_idx], |
194 | ch_flags, | 227 | ch_flags, |
195 | (ch_idx >= NUM_2GHZ_CHANNELS) ? | 228 | (ch_idx >= NUM_2GHZ_CHANNELS) ? |
196 | "5.2" : "2.4"); | 229 | "5.2" : "2.4"); |
@@ -200,7 +233,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, | |||
200 | channel = &data->channels[n_channels]; | 233 | channel = &data->channels[n_channels]; |
201 | n_channels++; | 234 | n_channels++; |
202 | 235 | ||
203 | channel->hw_value = iwl_nvm_channels[ch_idx]; | 236 | channel->hw_value = nvm_chan[ch_idx]; |
204 | channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ? | 237 | channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ? |
205 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | 238 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; |
206 | channel->center_freq = | 239 | channel->center_freq = |
@@ -211,11 +244,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, | |||
211 | channel->flags = IEEE80211_CHAN_NO_HT40; | 244 | channel->flags = IEEE80211_CHAN_NO_HT40; |
212 | if (ch_idx < NUM_2GHZ_CHANNELS && | 245 | if (ch_idx < NUM_2GHZ_CHANNELS && |
213 | (ch_flags & NVM_CHANNEL_40MHZ)) { | 246 | (ch_flags & NVM_CHANNEL_40MHZ)) { |
214 | if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS) | 247 | if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS) |
215 | channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; | 248 | channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; |
216 | if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS) | 249 | if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS) |
217 | channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; | 250 | channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; |
218 | } else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT && | 251 | } else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT && |
219 | (ch_flags & NVM_CHANNEL_40MHZ)) { | 252 | (ch_flags & NVM_CHANNEL_40MHZ)) { |
220 | if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) | 253 | if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) |
221 | channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; | 254 | channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; |
@@ -266,9 +299,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, | |||
266 | 299 | ||
267 | static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, | 300 | static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, |
268 | struct iwl_nvm_data *data, | 301 | struct iwl_nvm_data *data, |
269 | struct ieee80211_sta_vht_cap *vht_cap) | 302 | struct ieee80211_sta_vht_cap *vht_cap, |
303 | u8 tx_chains, u8 rx_chains) | ||
270 | { | 304 | { |
271 | int num_ants = num_of_ant(data->valid_rx_ant); | 305 | int num_rx_ants = num_of_ant(rx_chains); |
306 | int num_tx_ants = num_of_ant(tx_chains); | ||
272 | 307 | ||
273 | vht_cap->vht_supported = true; | 308 | vht_cap->vht_supported = true; |
274 | 309 | ||
@@ -278,8 +313,10 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, | |||
278 | 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | | 313 | 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | |
279 | 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | 314 | 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; |
280 | 315 | ||
281 | if (num_ants > 1) | 316 | if (num_tx_ants > 1) |
282 | vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; | 317 | vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; |
318 | else | ||
319 | vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; | ||
283 | 320 | ||
284 | if (iwlwifi_mod_params.amsdu_size_8K) | 321 | if (iwlwifi_mod_params.amsdu_size_8K) |
285 | vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; | 322 | vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; |
@@ -294,10 +331,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, | |||
294 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | | 331 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | |
295 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 14); | 332 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 14); |
296 | 333 | ||
297 | if (num_ants == 1 || | 334 | if (num_rx_ants == 1 || cfg->rx_with_siso_diversity) { |
298 | cfg->rx_with_siso_diversity) { | 335 | vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; |
299 | vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | | ||
300 | IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; | ||
301 | /* this works because NOT_SUPPORTED == 3 */ | 336 | /* this works because NOT_SUPPORTED == 3 */ |
302 | vht_cap->vht_mcs.rx_mcs_map |= | 337 | vht_cap->vht_mcs.rx_mcs_map |= |
303 | cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2); | 338 | cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2); |
@@ -307,14 +342,23 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, | |||
307 | } | 342 | } |
308 | 343 | ||
309 | static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | 344 | static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, |
310 | struct iwl_nvm_data *data, const __le16 *nvm_sw, | 345 | struct iwl_nvm_data *data, |
311 | bool enable_vht, u8 tx_chains, u8 rx_chains) | 346 | const __le16 *ch_section, bool enable_vht, |
347 | u8 tx_chains, u8 rx_chains) | ||
312 | { | 348 | { |
313 | int n_channels = iwl_init_channel_map(dev, cfg, data, | 349 | int n_channels; |
314 | &nvm_sw[NVM_CHANNELS]); | ||
315 | int n_used = 0; | 350 | int n_used = 0; |
316 | struct ieee80211_supported_band *sband; | 351 | struct ieee80211_supported_band *sband; |
317 | 352 | ||
353 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) | ||
354 | n_channels = iwl_init_channel_map( | ||
355 | dev, cfg, data, | ||
356 | &ch_section[NVM_CHANNELS]); | ||
357 | else | ||
358 | n_channels = iwl_init_channel_map( | ||
359 | dev, cfg, data, | ||
360 | &ch_section[NVM_CHANNELS_FAMILY_8000]); | ||
361 | |||
318 | sband = &data->bands[IEEE80211_BAND_2GHZ]; | 362 | sband = &data->bands[IEEE80211_BAND_2GHZ]; |
319 | sband->band = IEEE80211_BAND_2GHZ; | 363 | sband->band = IEEE80211_BAND_2GHZ; |
320 | sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS]; | 364 | sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS]; |
@@ -333,80 +377,160 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | |||
333 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ, | 377 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ, |
334 | tx_chains, rx_chains); | 378 | tx_chains, rx_chains); |
335 | if (enable_vht) | 379 | if (enable_vht) |
336 | iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap); | 380 | iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap, |
381 | tx_chains, rx_chains); | ||
337 | 382 | ||
338 | if (n_channels != n_used) | 383 | if (n_channels != n_used) |
339 | IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n", | 384 | IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n", |
340 | n_used, n_channels); | 385 | n_used, n_channels); |
341 | } | 386 | } |
342 | 387 | ||
388 | static int iwl_get_sku(const struct iwl_cfg *cfg, | ||
389 | const __le16 *nvm_sw) | ||
390 | { | ||
391 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) | ||
392 | return le16_to_cpup(nvm_sw + SKU); | ||
393 | else | ||
394 | return le32_to_cpup((__le32 *)(nvm_sw + SKU_FAMILY_8000)); | ||
395 | } | ||
396 | |||
397 | static int iwl_get_nvm_version(const struct iwl_cfg *cfg, | ||
398 | const __le16 *nvm_sw) | ||
399 | { | ||
400 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) | ||
401 | return le16_to_cpup(nvm_sw + NVM_VERSION); | ||
402 | else | ||
403 | return le32_to_cpup((__le32 *)(nvm_sw + | ||
404 | NVM_VERSION_FAMILY_8000)); | ||
405 | } | ||
406 | |||
407 | static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, | ||
408 | const __le16 *nvm_sw) | ||
409 | { | ||
410 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) | ||
411 | return le16_to_cpup(nvm_sw + RADIO_CFG); | ||
412 | else | ||
413 | return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000)); | ||
414 | } | ||
415 | |||
416 | #define N_HW_ADDRS_MASK_FAMILY_8000 0xF | ||
417 | static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, | ||
418 | const __le16 *nvm_sw) | ||
419 | { | ||
420 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) | ||
421 | return le16_to_cpup(nvm_sw + N_HW_ADDRS); | ||
422 | else | ||
423 | return le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000)) | ||
424 | & N_HW_ADDRS_MASK_FAMILY_8000; | ||
425 | } | ||
426 | |||
427 | static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, | ||
428 | struct iwl_nvm_data *data, | ||
429 | u32 radio_cfg) | ||
430 | { | ||
431 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { | ||
432 | data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg); | ||
433 | data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg); | ||
434 | data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg); | ||
435 | data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg); | ||
436 | return; | ||
437 | } | ||
438 | |||
439 | /* set the radio configuration for family 8000 */ | ||
440 | data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK_FAMILY_8000(radio_cfg); | ||
441 | data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg); | ||
442 | data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg); | ||
443 | data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg); | ||
444 | } | ||
445 | |||
446 | static void iwl_set_hw_address(const struct iwl_cfg *cfg, | ||
447 | struct iwl_nvm_data *data, | ||
448 | const __le16 *nvm_sec) | ||
449 | { | ||
450 | u8 hw_addr[ETH_ALEN]; | ||
451 | |||
452 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) | ||
453 | memcpy(hw_addr, nvm_sec + HW_ADDR, ETH_ALEN); | ||
454 | else | ||
455 | memcpy(hw_addr, nvm_sec + MAC_ADDRESS_OVERRIDE_FAMILY_8000, | ||
456 | ETH_ALEN); | ||
457 | |||
458 | /* The byte order is little endian 16 bit, meaning 214365 */ | ||
459 | data->hw_addr[0] = hw_addr[1]; | ||
460 | data->hw_addr[1] = hw_addr[0]; | ||
461 | data->hw_addr[2] = hw_addr[3]; | ||
462 | data->hw_addr[3] = hw_addr[2]; | ||
463 | data->hw_addr[4] = hw_addr[5]; | ||
464 | data->hw_addr[5] = hw_addr[4]; | ||
465 | } | ||
466 | |||
343 | struct iwl_nvm_data * | 467 | struct iwl_nvm_data * |
344 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, | 468 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, |
345 | const __le16 *nvm_hw, const __le16 *nvm_sw, | 469 | const __le16 *nvm_hw, const __le16 *nvm_sw, |
346 | const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains) | 470 | const __le16 *nvm_calib, const __le16 *regulatory, |
471 | const __le16 *mac_override, u8 tx_chains, u8 rx_chains) | ||
347 | { | 472 | { |
348 | struct iwl_nvm_data *data; | 473 | struct iwl_nvm_data *data; |
349 | u8 hw_addr[ETH_ALEN]; | 474 | u32 sku; |
350 | u16 radio_cfg, sku; | 475 | u32 radio_cfg; |
351 | 476 | ||
352 | data = kzalloc(sizeof(*data) + | 477 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) |
353 | sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS, | 478 | data = kzalloc(sizeof(*data) + |
354 | GFP_KERNEL); | 479 | sizeof(struct ieee80211_channel) * |
480 | IWL_NUM_CHANNELS, | ||
481 | GFP_KERNEL); | ||
482 | else | ||
483 | data = kzalloc(sizeof(*data) + | ||
484 | sizeof(struct ieee80211_channel) * | ||
485 | IWL_NUM_CHANNELS_FAMILY_8000, | ||
486 | GFP_KERNEL); | ||
355 | if (!data) | 487 | if (!data) |
356 | return NULL; | 488 | return NULL; |
357 | 489 | ||
358 | data->nvm_version = le16_to_cpup(nvm_sw + NVM_VERSION); | 490 | data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw); |
359 | 491 | ||
360 | radio_cfg = le16_to_cpup(nvm_sw + RADIO_CFG); | 492 | radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw); |
361 | data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg); | 493 | iwl_set_radio_cfg(cfg, data, radio_cfg); |
362 | data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg); | ||
363 | data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg); | ||
364 | data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg); | ||
365 | data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg); | ||
366 | data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg); | ||
367 | 494 | ||
368 | sku = le16_to_cpup(nvm_sw + SKU); | 495 | sku = iwl_get_sku(cfg, nvm_sw); |
369 | data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; | 496 | data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; |
370 | data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; | 497 | data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; |
371 | data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE; | 498 | data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE; |
499 | data->sku_cap_11ac_enable = sku & NVM_SKU_CAP_11AC_ENABLE; | ||
372 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) | 500 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) |
373 | data->sku_cap_11n_enable = false; | 501 | data->sku_cap_11n_enable = false; |
374 | 502 | ||
375 | /* check overrides (some devices have wrong NVM) */ | 503 | data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw); |
376 | if (cfg->valid_tx_ant) | ||
377 | data->valid_tx_ant = cfg->valid_tx_ant; | ||
378 | if (cfg->valid_rx_ant) | ||
379 | data->valid_rx_ant = cfg->valid_rx_ant; | ||
380 | 504 | ||
381 | if (!data->valid_tx_ant || !data->valid_rx_ant) { | 505 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { |
382 | IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n", | 506 | /* Checking for required sections */ |
383 | data->valid_tx_ant, data->valid_rx_ant); | 507 | if (!nvm_calib) { |
384 | kfree(data); | 508 | IWL_ERR_DEV(dev, |
385 | return NULL; | 509 | "Can't parse empty Calib NVM sections\n"); |
510 | kfree(data); | ||
511 | return NULL; | ||
512 | } | ||
513 | /* in family 8000 Xtal calibration values moved to OTP */ | ||
514 | data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB); | ||
515 | data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1); | ||
386 | } | 516 | } |
387 | 517 | ||
388 | data->n_hw_addrs = le16_to_cpup(nvm_sw + N_HW_ADDRS); | 518 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { |
519 | iwl_set_hw_address(cfg, data, nvm_hw); | ||
389 | 520 | ||
390 | data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB); | 521 | iwl_init_sbands(dev, cfg, data, nvm_sw, |
391 | data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1); | 522 | sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, |
523 | rx_chains); | ||
524 | } else { | ||
525 | /* MAC address in family 8000 */ | ||
526 | iwl_set_hw_address(cfg, data, mac_override); | ||
392 | 527 | ||
393 | /* The byte order is little endian 16 bit, meaning 214365 */ | 528 | iwl_init_sbands(dev, cfg, data, regulatory, |
394 | memcpy(hw_addr, nvm_hw + HW_ADDR, ETH_ALEN); | 529 | sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, |
395 | data->hw_addr[0] = hw_addr[1]; | 530 | rx_chains); |
396 | data->hw_addr[1] = hw_addr[0]; | 531 | } |
397 | data->hw_addr[2] = hw_addr[3]; | ||
398 | data->hw_addr[3] = hw_addr[2]; | ||
399 | data->hw_addr[4] = hw_addr[5]; | ||
400 | data->hw_addr[5] = hw_addr[4]; | ||
401 | |||
402 | iwl_init_sbands(dev, cfg, data, nvm_sw, sku & NVM_SKU_CAP_11AC_ENABLE, | ||
403 | tx_chains, rx_chains); | ||
404 | 532 | ||
405 | data->calib_version = 255; /* TODO: | 533 | data->calib_version = 255; |
406 | this value will prevent some checks from | ||
407 | failing, we need to check if this | ||
408 | field is still needed, and if it does, | ||
409 | where is it in the NVM*/ | ||
410 | 534 | ||
411 | return data; | 535 | return data; |
412 | } | 536 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h index 0c4399aba8c6..c9c45a39d212 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h | |||
@@ -75,6 +75,7 @@ | |||
75 | struct iwl_nvm_data * | 75 | struct iwl_nvm_data * |
76 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, | 76 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, |
77 | const __le16 *nvm_hw, const __le16 *nvm_sw, | 77 | const __le16 *nvm_hw, const __le16 *nvm_sw, |
78 | const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains); | 78 | const __le16 *nvm_calib, const __le16 *regulatory, |
79 | const __le16 *mac_override, u8 tx_chains, u8 rx_chains); | ||
79 | 80 | ||
80 | #endif /* __iwl_nvm_parse_h__ */ | 81 | #endif /* __iwl_nvm_parse_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index b5be51f3cd3d..ea29504ac617 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h | |||
@@ -119,7 +119,8 @@ struct iwl_cfg; | |||
119 | * @queue_not_full: notifies that a HW queue is not full any more. | 119 | * @queue_not_full: notifies that a HW queue is not full any more. |
120 | * Must be atomic and called with BH disabled. | 120 | * Must be atomic and called with BH disabled. |
121 | * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that | 121 | * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that |
122 | * the radio is killed. May sleep. | 122 | * the radio is killed. Return %true if the device should be stopped by |
123 | * the transport immediately after the call. May sleep. | ||
123 | * @free_skb: allows the transport layer to free skbs that haven't been | 124 | * @free_skb: allows the transport layer to free skbs that haven't been |
124 | * reclaimed by the op_mode. This can happen when the driver is freed and | 125 | * reclaimed by the op_mode. This can happen when the driver is freed and |
125 | * there are Tx packets pending in the transport layer. | 126 | * there are Tx packets pending in the transport layer. |
@@ -131,6 +132,8 @@ struct iwl_cfg; | |||
131 | * @nic_config: configure NIC, called before firmware is started. | 132 | * @nic_config: configure NIC, called before firmware is started. |
132 | * May sleep | 133 | * May sleep |
133 | * @wimax_active: invoked when WiMax becomes active. May sleep | 134 | * @wimax_active: invoked when WiMax becomes active. May sleep |
135 | * @enter_d0i3: configure the fw to enter d0i3. May sleep. | ||
136 | * @exit_d0i3: configure the fw to exit d0i3. May sleep. | ||
134 | */ | 137 | */ |
135 | struct iwl_op_mode_ops { | 138 | struct iwl_op_mode_ops { |
136 | struct iwl_op_mode *(*start)(struct iwl_trans *trans, | 139 | struct iwl_op_mode *(*start)(struct iwl_trans *trans, |
@@ -142,12 +145,14 @@ struct iwl_op_mode_ops { | |||
142 | struct iwl_device_cmd *cmd); | 145 | struct iwl_device_cmd *cmd); |
143 | void (*queue_full)(struct iwl_op_mode *op_mode, int queue); | 146 | void (*queue_full)(struct iwl_op_mode *op_mode, int queue); |
144 | void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue); | 147 | void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue); |
145 | void (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); | 148 | bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); |
146 | void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb); | 149 | void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb); |
147 | void (*nic_error)(struct iwl_op_mode *op_mode); | 150 | void (*nic_error)(struct iwl_op_mode *op_mode); |
148 | void (*cmd_queue_full)(struct iwl_op_mode *op_mode); | 151 | void (*cmd_queue_full)(struct iwl_op_mode *op_mode); |
149 | void (*nic_config)(struct iwl_op_mode *op_mode); | 152 | void (*nic_config)(struct iwl_op_mode *op_mode); |
150 | void (*wimax_active)(struct iwl_op_mode *op_mode); | 153 | void (*wimax_active)(struct iwl_op_mode *op_mode); |
154 | int (*enter_d0i3)(struct iwl_op_mode *op_mode); | ||
155 | int (*exit_d0i3)(struct iwl_op_mode *op_mode); | ||
151 | }; | 156 | }; |
152 | 157 | ||
153 | int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops); | 158 | int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops); |
@@ -155,7 +160,7 @@ void iwl_opmode_deregister(const char *name); | |||
155 | 160 | ||
156 | /** | 161 | /** |
157 | * struct iwl_op_mode - operational mode | 162 | * struct iwl_op_mode - operational mode |
158 | * @ops - pointer to its own ops | 163 | * @ops: pointer to its own ops |
159 | * | 164 | * |
160 | * This holds an implementation of the mac80211 / fw API. | 165 | * This holds an implementation of the mac80211 / fw API. |
161 | */ | 166 | */ |
@@ -191,11 +196,11 @@ static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode, | |||
191 | op_mode->ops->queue_not_full(op_mode, queue); | 196 | op_mode->ops->queue_not_full(op_mode, queue); |
192 | } | 197 | } |
193 | 198 | ||
194 | static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, | 199 | static inline bool __must_check |
195 | bool state) | 200 | iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, bool state) |
196 | { | 201 | { |
197 | might_sleep(); | 202 | might_sleep(); |
198 | op_mode->ops->hw_rf_kill(op_mode, state); | 203 | return op_mode->ops->hw_rf_kill(op_mode, state); |
199 | } | 204 | } |
200 | 205 | ||
201 | static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode, | 206 | static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode, |
@@ -226,4 +231,22 @@ static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) | |||
226 | op_mode->ops->wimax_active(op_mode); | 231 | op_mode->ops->wimax_active(op_mode); |
227 | } | 232 | } |
228 | 233 | ||
234 | static inline int iwl_op_mode_enter_d0i3(struct iwl_op_mode *op_mode) | ||
235 | { | ||
236 | might_sleep(); | ||
237 | |||
238 | if (!op_mode->ops->enter_d0i3) | ||
239 | return 0; | ||
240 | return op_mode->ops->enter_d0i3(op_mode); | ||
241 | } | ||
242 | |||
243 | static inline int iwl_op_mode_exit_d0i3(struct iwl_op_mode *op_mode) | ||
244 | { | ||
245 | might_sleep(); | ||
246 | |||
247 | if (!op_mode->ops->exit_d0i3) | ||
248 | return 0; | ||
249 | return op_mode->ops->exit_d0i3(op_mode); | ||
250 | } | ||
251 | |||
229 | #endif /* __iwl_op_mode_h__ */ | 252 | #endif /* __iwl_op_mode_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c index fa77d63a277a..b761ac4822a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-phy-db.c +++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c | |||
@@ -72,7 +72,7 @@ | |||
72 | #include "iwl-trans.h" | 72 | #include "iwl-trans.h" |
73 | 73 | ||
74 | #define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */ | 74 | #define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */ |
75 | #define IWL_NUM_PAPD_CH_GROUPS 4 | 75 | #define IWL_NUM_PAPD_CH_GROUPS 7 |
76 | #define IWL_NUM_TXP_CH_GROUPS 9 | 76 | #define IWL_NUM_TXP_CH_GROUPS 9 |
77 | 77 | ||
78 | struct iwl_phy_db_entry { | 78 | struct iwl_phy_db_entry { |
@@ -383,7 +383,7 @@ static int iwl_phy_db_send_all_channel_groups( | |||
383 | if (!entry) | 383 | if (!entry) |
384 | return -EINVAL; | 384 | return -EINVAL; |
385 | 385 | ||
386 | if (WARN_ON_ONCE(!entry->size)) | 386 | if (!entry->size) |
387 | continue; | 387 | continue; |
388 | 388 | ||
389 | /* Send the requested PHY DB section */ | 389 | /* Send the requested PHY DB section */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 100bd0d79681..5f657c501406 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h | |||
@@ -95,7 +95,8 @@ | |||
95 | #define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ | 95 | #define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ |
96 | #define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) | 96 | #define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) |
97 | 97 | ||
98 | #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) | 98 | #define APMG_PCIDEV_STT_VAL_PERSIST_DIS (0x00000200) |
99 | #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) | ||
99 | 100 | ||
100 | #define APMG_RTC_INT_STT_RFKILL (0x10000000) | 101 | #define APMG_RTC_INT_STT_RFKILL (0x10000000) |
101 | 102 | ||
@@ -105,6 +106,33 @@ | |||
105 | /* Device NMI register */ | 106 | /* Device NMI register */ |
106 | #define DEVICE_SET_NMI_REG 0x00a01c30 | 107 | #define DEVICE_SET_NMI_REG 0x00a01c30 |
107 | 108 | ||
109 | /* Shared registers (0x0..0x3ff, via target indirect or periphery */ | ||
110 | #define SHR_BASE 0x00a10000 | ||
111 | |||
112 | /* Shared GP1 register */ | ||
113 | #define SHR_APMG_GP1_REG 0x01dc | ||
114 | #define SHR_APMG_GP1_REG_PRPH (SHR_BASE + SHR_APMG_GP1_REG) | ||
115 | #define SHR_APMG_GP1_WF_XTAL_LP_EN 0x00000004 | ||
116 | #define SHR_APMG_GP1_CHICKEN_BIT_SELECT 0x80000000 | ||
117 | |||
118 | /* Shared DL_CFG register */ | ||
119 | #define SHR_APMG_DL_CFG_REG 0x01c4 | ||
120 | #define SHR_APMG_DL_CFG_REG_PRPH (SHR_BASE + SHR_APMG_DL_CFG_REG) | ||
121 | #define SHR_APMG_DL_CFG_RTCS_CLK_SELECTOR_MSK 0x000000c0 | ||
122 | #define SHR_APMG_DL_CFG_RTCS_CLK_INTERNAL_XTAL 0x00000080 | ||
123 | #define SHR_APMG_DL_CFG_DL_CLOCK_POWER_UP 0x00000100 | ||
124 | |||
125 | /* Shared APMG_XTAL_CFG register */ | ||
126 | #define SHR_APMG_XTAL_CFG_REG 0x1c0 | ||
127 | #define SHR_APMG_XTAL_CFG_XTAL_ON_REQ 0x80000000 | ||
128 | |||
129 | /* | ||
130 | * Device reset for family 8000 | ||
131 | * write to bit 24 in order to reset the CPU | ||
132 | */ | ||
133 | #define RELEASE_CPU_RESET (0x300C) | ||
134 | #define RELEASE_CPU_RESET_BIT BIT(24) | ||
135 | |||
108 | /***************************************************************************** | 136 | /***************************************************************************** |
109 | * 7000/3000 series SHR DTS addresses * | 137 | * 7000/3000 series SHR DTS addresses * |
110 | *****************************************************************************/ | 138 | *****************************************************************************/ |
@@ -281,4 +309,43 @@ static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl) | |||
281 | #define OSC_CLK (0xa04068) | 309 | #define OSC_CLK (0xa04068) |
282 | #define OSC_CLK_FORCE_CONTROL (0x8) | 310 | #define OSC_CLK_FORCE_CONTROL (0x8) |
283 | 311 | ||
312 | /* SECURE boot registers */ | ||
313 | #define LMPM_SECURE_BOOT_CONFIG_ADDR (0x100) | ||
314 | enum secure_boot_config_reg { | ||
315 | LMPM_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP = 0x00000001, | ||
316 | LMPM_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002, | ||
317 | }; | ||
318 | |||
319 | #define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR (0x1E30) | ||
320 | #define LMPM_SECURE_BOOT_CPU2_STATUS_ADDR (0x1E34) | ||
321 | enum secure_boot_status_reg { | ||
322 | LMPM_SECURE_BOOT_CPU_STATUS_VERF_STATUS = 0x00000001, | ||
323 | LMPM_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED = 0x00000002, | ||
324 | LMPM_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS = 0x00000004, | ||
325 | LMPM_SECURE_BOOT_CPU_STATUS_VERF_FAIL = 0x00000008, | ||
326 | LMPM_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL = 0x00000010, | ||
327 | LMPM_SECURE_BOOT_STATUS_SUCCESS = 0x00000003, | ||
328 | }; | ||
329 | |||
330 | #define CSR_UCODE_LOAD_STATUS_ADDR (0x1E70) | ||
331 | enum secure_load_status_reg { | ||
332 | LMPM_CPU_UCODE_LOADING_STARTED = 0x00000001, | ||
333 | LMPM_CPU_HDRS_LOADING_COMPLETED = 0x00000003, | ||
334 | LMPM_CPU_UCODE_LOADING_COMPLETED = 0x00000007, | ||
335 | LMPM_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8, | ||
336 | LMPM_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00, | ||
337 | }; | ||
338 | |||
339 | #define LMPM_SECURE_INSPECTOR_CODE_ADDR (0x1E38) | ||
340 | #define LMPM_SECURE_INSPECTOR_DATA_ADDR (0x1E3C) | ||
341 | #define LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR (0x1E78) | ||
342 | #define LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR (0x1E7C) | ||
343 | |||
344 | #define LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE (0x400000) | ||
345 | #define LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE (0x402000) | ||
346 | #define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x420000) | ||
347 | #define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x420400) | ||
348 | |||
349 | #define LMPM_SECURE_TIME_OUT (100) | ||
350 | |||
284 | #endif /* __iwl_prph_h__ */ | 351 | #endif /* __iwl_prph_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 1f065cf4a4ba..8cdb0dd618a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -193,12 +193,23 @@ static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt) | |||
193 | * @CMD_ASYNC: Return right away and don't wait for the response | 193 | * @CMD_ASYNC: Return right away and don't wait for the response |
194 | * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the | 194 | * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the |
195 | * response. The caller needs to call iwl_free_resp when done. | 195 | * response. The caller needs to call iwl_free_resp when done. |
196 | * @CMD_HIGH_PRIO: The command is high priority - it goes to the front of the | ||
197 | * command queue, but after other high priority commands. valid only | ||
198 | * with CMD_ASYNC. | ||
199 | * @CMD_SEND_IN_IDLE: The command should be sent even when the trans is idle. | ||
200 | * @CMD_MAKE_TRANS_IDLE: The command response should mark the trans as idle. | ||
201 | * @CMD_WAKE_UP_TRANS: The command response should wake up the trans | ||
202 | * (i.e. mark it as non-idle). | ||
196 | */ | 203 | */ |
197 | enum CMD_MODE { | 204 | enum CMD_MODE { |
198 | CMD_SYNC = 0, | 205 | CMD_SYNC = 0, |
199 | CMD_ASYNC = BIT(0), | 206 | CMD_ASYNC = BIT(0), |
200 | CMD_WANT_SKB = BIT(1), | 207 | CMD_WANT_SKB = BIT(1), |
201 | CMD_SEND_IN_RFKILL = BIT(2), | 208 | CMD_SEND_IN_RFKILL = BIT(2), |
209 | CMD_HIGH_PRIO = BIT(3), | ||
210 | CMD_SEND_IN_IDLE = BIT(4), | ||
211 | CMD_MAKE_TRANS_IDLE = BIT(5), | ||
212 | CMD_WAKE_UP_TRANS = BIT(6), | ||
202 | }; | 213 | }; |
203 | 214 | ||
204 | #define DEF_CMD_PAYLOAD_SIZE 320 | 215 | #define DEF_CMD_PAYLOAD_SIZE 320 |
@@ -335,6 +346,9 @@ enum iwl_d3_status { | |||
335 | * @STATUS_INT_ENABLED: interrupts are enabled | 346 | * @STATUS_INT_ENABLED: interrupts are enabled |
336 | * @STATUS_RFKILL: the HW RFkill switch is in KILL position | 347 | * @STATUS_RFKILL: the HW RFkill switch is in KILL position |
337 | * @STATUS_FW_ERROR: the fw is in error state | 348 | * @STATUS_FW_ERROR: the fw is in error state |
349 | * @STATUS_TRANS_GOING_IDLE: shutting down the trans, only special commands | ||
350 | * are sent | ||
351 | * @STATUS_TRANS_IDLE: the trans is idle - general commands are not to be sent | ||
338 | */ | 352 | */ |
339 | enum iwl_trans_status { | 353 | enum iwl_trans_status { |
340 | STATUS_SYNC_HCMD_ACTIVE, | 354 | STATUS_SYNC_HCMD_ACTIVE, |
@@ -343,6 +357,8 @@ enum iwl_trans_status { | |||
343 | STATUS_INT_ENABLED, | 357 | STATUS_INT_ENABLED, |
344 | STATUS_RFKILL, | 358 | STATUS_RFKILL, |
345 | STATUS_FW_ERROR, | 359 | STATUS_FW_ERROR, |
360 | STATUS_TRANS_GOING_IDLE, | ||
361 | STATUS_TRANS_IDLE, | ||
346 | }; | 362 | }; |
347 | 363 | ||
348 | /** | 364 | /** |
@@ -377,7 +393,7 @@ struct iwl_trans_config { | |||
377 | bool rx_buf_size_8k; | 393 | bool rx_buf_size_8k; |
378 | bool bc_table_dword; | 394 | bool bc_table_dword; |
379 | unsigned int queue_watchdog_timeout; | 395 | unsigned int queue_watchdog_timeout; |
380 | const char **command_names; | 396 | const char *const *command_names; |
381 | }; | 397 | }; |
382 | 398 | ||
383 | struct iwl_trans; | 399 | struct iwl_trans; |
@@ -443,6 +459,11 @@ struct iwl_trans; | |||
443 | * @release_nic_access: let the NIC go to sleep. The "flags" parameter | 459 | * @release_nic_access: let the NIC go to sleep. The "flags" parameter |
444 | * must be the same one that was sent before to the grab_nic_access. | 460 | * must be the same one that was sent before to the grab_nic_access. |
445 | * @set_bits_mask - set SRAM register according to value and mask. | 461 | * @set_bits_mask - set SRAM register according to value and mask. |
462 | * @ref: grab a reference to the transport/FW layers, disallowing | ||
463 | * certain low power states | ||
464 | * @unref: release a reference previously taken with @ref. Note that | ||
465 | * initially the reference count is 1, making an initial @unref | ||
466 | * necessary to allow low power states. | ||
446 | */ | 467 | */ |
447 | struct iwl_trans_ops { | 468 | struct iwl_trans_ops { |
448 | 469 | ||
@@ -489,6 +510,8 @@ struct iwl_trans_ops { | |||
489 | unsigned long *flags); | 510 | unsigned long *flags); |
490 | void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask, | 511 | void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask, |
491 | u32 value); | 512 | u32 value); |
513 | void (*ref)(struct iwl_trans *trans); | ||
514 | void (*unref)(struct iwl_trans *trans); | ||
492 | }; | 515 | }; |
493 | 516 | ||
494 | /** | 517 | /** |
@@ -523,6 +546,7 @@ enum iwl_trans_state { | |||
523 | * starting the firmware, used for tracing | 546 | * starting the firmware, used for tracing |
524 | * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the | 547 | * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the |
525 | * start of the 802.11 header in the @rx_mpdu_cmd | 548 | * start of the 802.11 header in the @rx_mpdu_cmd |
549 | * @dflt_pwr_limit: default power limit fetched from the platform (ACPI) | ||
526 | */ | 550 | */ |
527 | struct iwl_trans { | 551 | struct iwl_trans { |
528 | const struct iwl_trans_ops *ops; | 552 | const struct iwl_trans_ops *ops; |
@@ -551,6 +575,8 @@ struct iwl_trans { | |||
551 | struct lockdep_map sync_cmd_lockdep_map; | 575 | struct lockdep_map sync_cmd_lockdep_map; |
552 | #endif | 576 | #endif |
553 | 577 | ||
578 | u64 dflt_pwr_limit; | ||
579 | |||
554 | /* pointer to trans specific struct */ | 580 | /* pointer to trans specific struct */ |
555 | /*Ensure that this pointer will always be aligned to sizeof pointer */ | 581 | /*Ensure that this pointer will always be aligned to sizeof pointer */ |
556 | char trans_specific[0] __aligned(sizeof(void *)); | 582 | char trans_specific[0] __aligned(sizeof(void *)); |
@@ -627,6 +653,18 @@ static inline int iwl_trans_d3_resume(struct iwl_trans *trans, | |||
627 | return trans->ops->d3_resume(trans, status, test); | 653 | return trans->ops->d3_resume(trans, status, test); |
628 | } | 654 | } |
629 | 655 | ||
656 | static inline void iwl_trans_ref(struct iwl_trans *trans) | ||
657 | { | ||
658 | if (trans->ops->ref) | ||
659 | trans->ops->ref(trans); | ||
660 | } | ||
661 | |||
662 | static inline void iwl_trans_unref(struct iwl_trans *trans) | ||
663 | { | ||
664 | if (trans->ops->unref) | ||
665 | trans->ops->unref(trans); | ||
666 | } | ||
667 | |||
630 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, | 668 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, |
631 | struct iwl_host_cmd *cmd) | 669 | struct iwl_host_cmd *cmd) |
632 | { | 670 | { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index f98ec2b23898..ccdd3b7c4cce 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile | |||
@@ -2,8 +2,8 @@ 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 sf.o | 3 | iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.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 power_legacy.o bt-coex.o | 5 | iwlmvm-y += power.o coex.o |
6 | iwlmvm-y += led.o tt.o | 6 | iwlmvm-y += led.o tt.o offloading.o |
7 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o | 7 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o |
8 | iwlmvm-$(CONFIG_PM_SLEEP) += d3.o | 8 | iwlmvm-$(CONFIG_PM_SLEEP) += d3.o |
9 | 9 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 18a895a949d4..685f7e8e6943 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c | |||
@@ -61,9 +61,11 @@ | |||
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | 63 | ||
64 | #include <linux/ieee80211.h> | ||
65 | #include <linux/etherdevice.h> | ||
64 | #include <net/mac80211.h> | 66 | #include <net/mac80211.h> |
65 | 67 | ||
66 | #include "fw-api-bt-coex.h" | 68 | #include "fw-api-coex.h" |
67 | #include "iwl-modparams.h" | 69 | #include "iwl-modparams.h" |
68 | #include "mvm.h" | 70 | #include "mvm.h" |
69 | #include "iwl-debug.h" | 71 | #include "iwl-debug.h" |
@@ -305,6 +307,215 @@ static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = { | |||
305 | cpu_to_le32(0x33113311), | 307 | cpu_to_le32(0x33113311), |
306 | }; | 308 | }; |
307 | 309 | ||
310 | struct corunning_block_luts { | ||
311 | u8 range; | ||
312 | __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; | ||
313 | }; | ||
314 | |||
315 | /* | ||
316 | * Ranges for the antenna coupling calibration / co-running block LUT: | ||
317 | * LUT0: [ 0, 12[ | ||
318 | * LUT1: [12, 20[ | ||
319 | * LUT2: [20, 21[ | ||
320 | * LUT3: [21, 23[ | ||
321 | * LUT4: [23, 27[ | ||
322 | * LUT5: [27, 30[ | ||
323 | * LUT6: [30, 32[ | ||
324 | * LUT7: [32, 33[ | ||
325 | * LUT8: [33, - [ | ||
326 | */ | ||
327 | static const struct corunning_block_luts antenna_coupling_ranges[] = { | ||
328 | { | ||
329 | .range = 0, | ||
330 | .lut20 = { | ||
331 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
332 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
333 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
334 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
335 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
336 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
337 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
338 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
339 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
340 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
341 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
342 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
343 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
344 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
345 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
346 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
347 | }, | ||
348 | }, | ||
349 | { | ||
350 | .range = 12, | ||
351 | .lut20 = { | ||
352 | cpu_to_le32(0x00000001), cpu_to_le32(0x00000000), | ||
353 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
354 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
355 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
356 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
357 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
358 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
359 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
360 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
361 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
362 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
363 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
364 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
365 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
366 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
367 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
368 | }, | ||
369 | }, | ||
370 | { | ||
371 | .range = 20, | ||
372 | .lut20 = { | ||
373 | cpu_to_le32(0x00000002), cpu_to_le32(0x00000000), | ||
374 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
375 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
376 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
377 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
378 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
379 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
380 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
381 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
382 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
383 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
384 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
385 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
386 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
387 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
388 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
389 | }, | ||
390 | }, | ||
391 | { | ||
392 | .range = 21, | ||
393 | .lut20 = { | ||
394 | cpu_to_le32(0x00000003), cpu_to_le32(0x00000000), | ||
395 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
396 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
397 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
398 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
399 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
400 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
401 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
402 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
403 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
404 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
405 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
406 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
407 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
408 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
409 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
410 | }, | ||
411 | }, | ||
412 | { | ||
413 | .range = 23, | ||
414 | .lut20 = { | ||
415 | cpu_to_le32(0x00000004), cpu_to_le32(0x00000000), | ||
416 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
417 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
418 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
419 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
420 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
421 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
422 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
423 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
424 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
425 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
426 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
427 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
428 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
429 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
430 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
431 | }, | ||
432 | }, | ||
433 | { | ||
434 | .range = 27, | ||
435 | .lut20 = { | ||
436 | cpu_to_le32(0x00000005), cpu_to_le32(0x00000000), | ||
437 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
438 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
439 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
440 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
441 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
442 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
443 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
444 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
445 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
446 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
447 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
448 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
449 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
450 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
451 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
452 | }, | ||
453 | }, | ||
454 | { | ||
455 | .range = 30, | ||
456 | .lut20 = { | ||
457 | cpu_to_le32(0x00000006), cpu_to_le32(0x00000000), | ||
458 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
459 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
460 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
461 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
462 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
463 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
464 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
465 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
466 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
467 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
468 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
469 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
470 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
471 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
472 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
473 | }, | ||
474 | }, | ||
475 | { | ||
476 | .range = 32, | ||
477 | .lut20 = { | ||
478 | cpu_to_le32(0x00000007), cpu_to_le32(0x00000000), | ||
479 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
480 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
481 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
482 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
483 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
484 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
485 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
486 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
487 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
488 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
489 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
490 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
491 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
492 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
493 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
494 | }, | ||
495 | }, | ||
496 | { | ||
497 | .range = 33, | ||
498 | .lut20 = { | ||
499 | cpu_to_le32(0x00000008), cpu_to_le32(0x00000000), | ||
500 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
501 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
502 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
503 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
504 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
505 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
506 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
507 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
508 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
509 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
510 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
511 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
512 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
513 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
514 | cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), | ||
515 | }, | ||
516 | }, | ||
517 | }; | ||
518 | |||
308 | static enum iwl_bt_coex_lut_type | 519 | static enum iwl_bt_coex_lut_type |
309 | iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) | 520 | iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) |
310 | { | 521 | { |
@@ -378,7 +589,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | |||
378 | 589 | ||
379 | flags = iwlwifi_mod_params.bt_coex_active ? | 590 | flags = iwlwifi_mod_params.bt_coex_active ? |
380 | BT_COEX_NW : BT_COEX_DISABLE; | 591 | BT_COEX_NW : BT_COEX_DISABLE; |
381 | flags |= BT_CH_PRIMARY_EN | BT_CH_SECONDARY_EN | BT_SYNC_2_BT_DISABLE; | ||
382 | bt_cmd->flags = cpu_to_le32(flags); | 592 | bt_cmd->flags = cpu_to_le32(flags); |
383 | 593 | ||
384 | bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE | | 594 | bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE | |
@@ -391,14 +601,26 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | |||
391 | BT_VALID_LUT | | 601 | BT_VALID_LUT | |
392 | BT_VALID_WIFI_RX_SW_PRIO_BOOST | | 602 | BT_VALID_WIFI_RX_SW_PRIO_BOOST | |
393 | BT_VALID_WIFI_TX_SW_PRIO_BOOST | | 603 | BT_VALID_WIFI_TX_SW_PRIO_BOOST | |
394 | BT_VALID_CORUN_LUT_20 | | ||
395 | BT_VALID_CORUN_LUT_40 | | ||
396 | BT_VALID_ANT_ISOLATION | | 604 | BT_VALID_ANT_ISOLATION | |
397 | BT_VALID_ANT_ISOLATION_THRS | | 605 | BT_VALID_ANT_ISOLATION_THRS | |
398 | BT_VALID_TXTX_DELTA_FREQ_THRS | | 606 | BT_VALID_TXTX_DELTA_FREQ_THRS | |
399 | BT_VALID_TXRX_MAX_FREQ_0 | | 607 | BT_VALID_TXRX_MAX_FREQ_0 | |
400 | BT_VALID_SYNC_TO_SCO); | 608 | BT_VALID_SYNC_TO_SCO); |
401 | 609 | ||
610 | if (IWL_MVM_BT_COEX_SYNC2SCO) | ||
611 | bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); | ||
612 | |||
613 | if (IWL_MVM_BT_COEX_CORUNNING) { | ||
614 | bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_CORUN_LUT_20 | | ||
615 | BT_VALID_CORUN_LUT_40); | ||
616 | bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING); | ||
617 | } | ||
618 | |||
619 | if (IWL_MVM_BT_COEX_MPLUT) { | ||
620 | bt_cmd->flags |= cpu_to_le32(BT_COEX_MPLUT); | ||
621 | bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); | ||
622 | } | ||
623 | |||
402 | if (mvm->cfg->bt_shared_single_ant) | 624 | if (mvm->cfg->bt_shared_single_ant) |
403 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, | 625 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, |
404 | sizeof(iwl_single_shared_ant)); | 626 | sizeof(iwl_single_shared_ant)); |
@@ -406,6 +628,12 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | |||
406 | memcpy(&bt_cmd->decision_lut, iwl_combined_lookup, | 628 | memcpy(&bt_cmd->decision_lut, iwl_combined_lookup, |
407 | sizeof(iwl_combined_lookup)); | 629 | sizeof(iwl_combined_lookup)); |
408 | 630 | ||
631 | /* Take first Co-running block LUT to get started */ | ||
632 | memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[0].lut20, | ||
633 | sizeof(bt_cmd->bt4_corun_lut20)); | ||
634 | memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[0].lut20, | ||
635 | sizeof(bt_cmd->bt4_corun_lut40)); | ||
636 | |||
409 | memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost, | 637 | memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost, |
410 | sizeof(iwl_bt_prio_boost)); | 638 | sizeof(iwl_bt_prio_boost)); |
411 | memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, | 639 | memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, |
@@ -489,36 +717,26 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, | |||
489 | return ret; | 717 | return ret; |
490 | } | 718 | } |
491 | 719 | ||
492 | static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, | 720 | int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable) |
493 | bool enable) | ||
494 | { | 721 | { |
495 | struct iwl_bt_coex_cmd *bt_cmd; | 722 | struct iwl_bt_coex_cmd *bt_cmd; |
496 | /* Send ASYNC since this can be sent from an atomic context */ | 723 | /* Send ASYNC since this can be sent from an atomic context */ |
497 | struct iwl_host_cmd cmd = { | 724 | struct iwl_host_cmd cmd = { |
498 | .id = BT_CONFIG, | 725 | .id = BT_CONFIG, |
499 | .len = { sizeof(*bt_cmd), }, | 726 | .len = { sizeof(*bt_cmd), }, |
500 | .dataflags = { IWL_HCMD_DFL_DUP, }, | 727 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, |
501 | .flags = CMD_ASYNC, | 728 | .flags = CMD_ASYNC, |
502 | }; | 729 | }; |
503 | |||
504 | struct ieee80211_sta *sta; | ||
505 | struct iwl_mvm_sta *mvmsta; | 730 | struct iwl_mvm_sta *mvmsta; |
506 | int ret; | 731 | int ret; |
507 | 732 | ||
508 | if (sta_id == IWL_MVM_STATION_COUNT) | 733 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); |
734 | if (!mvmsta) | ||
509 | return 0; | 735 | return 0; |
510 | 736 | ||
511 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
512 | lockdep_is_held(&mvm->mutex)); | ||
513 | |||
514 | /* This can happen if the station has been removed right now */ | ||
515 | if (IS_ERR_OR_NULL(sta)) | ||
516 | return 0; | ||
517 | |||
518 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
519 | |||
520 | /* nothing to do */ | 737 | /* nothing to do */ |
521 | if (mvmsta->bt_reduced_txpower == enable) | 738 | if (mvmsta->bt_reduced_txpower_dbg || |
739 | mvmsta->bt_reduced_txpower == enable) | ||
522 | return 0; | 740 | return 0; |
523 | 741 | ||
524 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_ATOMIC); | 742 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_ATOMIC); |
@@ -552,6 +770,7 @@ struct iwl_bt_iterator_data { | |||
552 | bool reduced_tx_power; | 770 | bool reduced_tx_power; |
553 | struct ieee80211_chanctx_conf *primary; | 771 | struct ieee80211_chanctx_conf *primary; |
554 | struct ieee80211_chanctx_conf *secondary; | 772 | struct ieee80211_chanctx_conf *secondary; |
773 | bool primary_ll; | ||
555 | }; | 774 | }; |
556 | 775 | ||
557 | static inline | 776 | static inline |
@@ -577,72 +796,113 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
577 | struct iwl_mvm *mvm = data->mvm; | 796 | struct iwl_mvm *mvm = data->mvm; |
578 | struct ieee80211_chanctx_conf *chanctx_conf; | 797 | struct ieee80211_chanctx_conf *chanctx_conf; |
579 | enum ieee80211_smps_mode smps_mode; | 798 | enum ieee80211_smps_mode smps_mode; |
799 | u32 bt_activity_grading; | ||
580 | int ave_rssi; | 800 | int ave_rssi; |
581 | 801 | ||
582 | lockdep_assert_held(&mvm->mutex); | 802 | lockdep_assert_held(&mvm->mutex); |
583 | 803 | ||
584 | if (vif->type != NL80211_IFTYPE_STATION && | 804 | switch (vif->type) { |
585 | vif->type != NL80211_IFTYPE_AP) | 805 | case NL80211_IFTYPE_STATION: |
586 | return; | 806 | /* default smps_mode for BSS / P2P client is AUTOMATIC */ |
807 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | ||
808 | data->num_bss_ifaces++; | ||
587 | 809 | ||
588 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 810 | /* |
811 | * Count unassoc BSSes, relax SMSP constraints | ||
812 | * and disable reduced Tx Power | ||
813 | */ | ||
814 | if (!vif->bss_conf.assoc) { | ||
815 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
816 | smps_mode); | ||
817 | if (iwl_mvm_bt_coex_reduced_txp(mvm, | ||
818 | mvmvif->ap_sta_id, | ||
819 | false)) | ||
820 | IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); | ||
821 | return; | ||
822 | } | ||
823 | break; | ||
824 | case NL80211_IFTYPE_AP: | ||
825 | /* default smps_mode for AP / GO is OFF */ | ||
826 | smps_mode = IEEE80211_SMPS_OFF; | ||
827 | if (!mvmvif->ap_ibss_active) { | ||
828 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | ||
829 | smps_mode); | ||
830 | return; | ||
831 | } | ||
832 | |||
833 | /* the Ack / Cts kill mask must be default if AP / GO */ | ||
834 | data->reduced_tx_power = false; | ||
835 | break; | ||
836 | default: | ||
837 | return; | ||
838 | } | ||
589 | 839 | ||
590 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | 840 | chanctx_conf = rcu_dereference(vif->chanctx_conf); |
591 | 841 | ||
592 | /* If channel context is invalid or not on 2.4GHz .. */ | 842 | /* If channel context is invalid or not on 2.4GHz .. */ |
593 | if ((!chanctx_conf || | 843 | if ((!chanctx_conf || |
594 | chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { | 844 | chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { |
595 | /* ... and it is an associated STATION, relax constraints */ | 845 | /* ... relax constraints and disable rssi events */ |
596 | if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc) | 846 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, |
597 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | 847 | smps_mode); |
598 | smps_mode); | 848 | if (vif->type == NL80211_IFTYPE_STATION) |
599 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); | 849 | iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); |
600 | return; | 850 | return; |
601 | } | 851 | } |
602 | 852 | ||
603 | /* SoftAP / GO will always be primary */ | 853 | bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading); |
604 | if (vif->type == NL80211_IFTYPE_AP) { | 854 | if (bt_activity_grading >= BT_HIGH_TRAFFIC) |
605 | if (!mvmvif->ap_ibss_active) | 855 | smps_mode = IEEE80211_SMPS_STATIC; |
606 | return; | 856 | else if (bt_activity_grading >= BT_LOW_TRAFFIC) |
857 | smps_mode = vif->type == NL80211_IFTYPE_AP ? | ||
858 | IEEE80211_SMPS_OFF : | ||
859 | IEEE80211_SMPS_DYNAMIC; | ||
860 | IWL_DEBUG_COEX(data->mvm, | ||
861 | "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", | ||
862 | mvmvif->id, data->notif->bt_status, bt_activity_grading, | ||
863 | smps_mode); | ||
607 | 864 | ||
608 | /* the Ack / Cts kill mask must be default if AP / GO */ | 865 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); |
609 | data->reduced_tx_power = false; | ||
610 | 866 | ||
611 | if (chanctx_conf == data->primary) | 867 | /* low latency is always primary */ |
612 | return; | 868 | if (iwl_mvm_vif_low_latency(mvmvif)) { |
869 | data->primary_ll = true; | ||
613 | 870 | ||
614 | /* downgrade the current primary no matter what its type is */ | ||
615 | data->secondary = data->primary; | 871 | data->secondary = data->primary; |
616 | data->primary = chanctx_conf; | 872 | data->primary = chanctx_conf; |
617 | return; | ||
618 | } | 873 | } |
619 | 874 | ||
620 | data->num_bss_ifaces++; | 875 | if (vif->type == NL80211_IFTYPE_AP) { |
876 | if (!mvmvif->ap_ibss_active) | ||
877 | return; | ||
621 | 878 | ||
622 | /* we are now a STA / P2P Client, and take associated ones only */ | 879 | if (chanctx_conf == data->primary) |
623 | if (!vif->bss_conf.assoc) | 880 | return; |
881 | |||
882 | if (!data->primary_ll) { | ||
883 | /* | ||
884 | * downgrade the current primary no matter what its | ||
885 | * type is. | ||
886 | */ | ||
887 | data->secondary = data->primary; | ||
888 | data->primary = chanctx_conf; | ||
889 | } else { | ||
890 | /* there is low latency vif - we will be secondary */ | ||
891 | data->secondary = chanctx_conf; | ||
892 | } | ||
624 | return; | 893 | return; |
894 | } | ||
625 | 895 | ||
626 | /* STA / P2P Client, try to be primary if first vif */ | 896 | /* |
897 | * STA / P2P Client, try to be primary if first vif. If we are in low | ||
898 | * latency mode, we are already in primary and just don't do much | ||
899 | */ | ||
627 | if (!data->primary || data->primary == chanctx_conf) | 900 | if (!data->primary || data->primary == chanctx_conf) |
628 | data->primary = chanctx_conf; | 901 | data->primary = chanctx_conf; |
629 | else if (!data->secondary) | 902 | else if (!data->secondary) |
630 | /* if secondary is not NULL, it might be a GO */ | 903 | /* if secondary is not NULL, it might be a GO */ |
631 | data->secondary = chanctx_conf; | 904 | data->secondary = chanctx_conf; |
632 | 905 | ||
633 | if (le32_to_cpu(data->notif->bt_activity_grading) >= BT_HIGH_TRAFFIC) | ||
634 | smps_mode = IEEE80211_SMPS_STATIC; | ||
635 | else if (le32_to_cpu(data->notif->bt_activity_grading) >= | ||
636 | BT_LOW_TRAFFIC) | ||
637 | smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
638 | |||
639 | IWL_DEBUG_COEX(data->mvm, | ||
640 | "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", | ||
641 | mvmvif->id, data->notif->bt_status, | ||
642 | data->notif->bt_activity_grading, smps_mode); | ||
643 | |||
644 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); | ||
645 | |||
646 | /* don't reduce the Tx power if in loose scheme */ | 906 | /* don't reduce the Tx power if in loose scheme */ |
647 | if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || | 907 | if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || |
648 | mvm->cfg->bt_shared_single_ant) { | 908 | mvm->cfg->bt_shared_single_ant) { |
@@ -918,8 +1178,8 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
918 | #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) | 1178 | #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) |
919 | #define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200) | 1179 | #define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200) |
920 | 1180 | ||
921 | u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm, | 1181 | u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, |
922 | struct ieee80211_sta *sta) | 1182 | struct ieee80211_sta *sta) |
923 | { | 1183 | { |
924 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | 1184 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
925 | enum iwl_bt_coex_lut_type lut_type; | 1185 | enum iwl_bt_coex_lut_type lut_type; |
@@ -955,6 +1215,38 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, | |||
955 | return iwl_get_coex_type(mvm, mvmsta->vif) == BT_COEX_TIGHT_LUT; | 1215 | return iwl_get_coex_type(mvm, mvmsta->vif) == BT_COEX_TIGHT_LUT; |
956 | } | 1216 | } |
957 | 1217 | ||
1218 | u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, | ||
1219 | struct ieee80211_tx_info *info, u8 ac) | ||
1220 | { | ||
1221 | __le16 fc = hdr->frame_control; | ||
1222 | |||
1223 | if (info->band != IEEE80211_BAND_2GHZ) | ||
1224 | return 0; | ||
1225 | |||
1226 | if (unlikely(mvm->bt_tx_prio)) | ||
1227 | return mvm->bt_tx_prio - 1; | ||
1228 | |||
1229 | /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */ | ||
1230 | if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO || | ||
1231 | is_multicast_ether_addr(hdr->addr1) || | ||
1232 | ieee80211_is_ctl(fc) || ieee80211_is_mgmt(fc) || | ||
1233 | ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) | ||
1234 | return 3; | ||
1235 | |||
1236 | switch (ac) { | ||
1237 | case IEEE80211_AC_BE: | ||
1238 | return 1; | ||
1239 | case IEEE80211_AC_VO: | ||
1240 | return 3; | ||
1241 | case IEEE80211_AC_VI: | ||
1242 | return 2; | ||
1243 | default: | ||
1244 | break; | ||
1245 | } | ||
1246 | |||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
958 | void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) | 1250 | void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) |
959 | { | 1251 | { |
960 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX)) | 1252 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX)) |
@@ -962,3 +1254,69 @@ void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) | |||
962 | 1254 | ||
963 | iwl_mvm_bt_coex_notif_handle(mvm); | 1255 | iwl_mvm_bt_coex_notif_handle(mvm); |
964 | } | 1256 | } |
1257 | |||
1258 | int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, | ||
1259 | struct iwl_rx_cmd_buffer *rxb, | ||
1260 | struct iwl_device_cmd *dev_cmd) | ||
1261 | { | ||
1262 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1263 | u32 ant_isolation = le32_to_cpup((void *)pkt->data); | ||
1264 | u8 __maybe_unused lower_bound, upper_bound; | ||
1265 | u8 lut; | ||
1266 | |||
1267 | struct iwl_bt_coex_cmd *bt_cmd; | ||
1268 | struct iwl_host_cmd cmd = { | ||
1269 | .id = BT_CONFIG, | ||
1270 | .len = { sizeof(*bt_cmd), }, | ||
1271 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
1272 | .flags = CMD_SYNC, | ||
1273 | }; | ||
1274 | |||
1275 | if (!IWL_MVM_BT_COEX_CORUNNING) | ||
1276 | return 0; | ||
1277 | |||
1278 | lockdep_assert_held(&mvm->mutex); | ||
1279 | |||
1280 | if (ant_isolation == mvm->last_ant_isol) | ||
1281 | return 0; | ||
1282 | |||
1283 | for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++) | ||
1284 | if (ant_isolation < antenna_coupling_ranges[lut + 1].range) | ||
1285 | break; | ||
1286 | |||
1287 | lower_bound = antenna_coupling_ranges[lut].range; | ||
1288 | |||
1289 | if (lut < ARRAY_SIZE(antenna_coupling_ranges) - 1) | ||
1290 | upper_bound = antenna_coupling_ranges[lut + 1].range; | ||
1291 | else | ||
1292 | upper_bound = antenna_coupling_ranges[lut].range; | ||
1293 | |||
1294 | IWL_DEBUG_COEX(mvm, "Antenna isolation=%d in range [%d,%d[, lut=%d\n", | ||
1295 | ant_isolation, lower_bound, upper_bound, lut); | ||
1296 | |||
1297 | mvm->last_ant_isol = ant_isolation; | ||
1298 | |||
1299 | if (mvm->last_corun_lut == lut) | ||
1300 | return 0; | ||
1301 | |||
1302 | mvm->last_corun_lut = lut; | ||
1303 | |||
1304 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); | ||
1305 | if (!bt_cmd) | ||
1306 | return 0; | ||
1307 | cmd.data[0] = bt_cmd; | ||
1308 | |||
1309 | bt_cmd->flags = cpu_to_le32(BT_COEX_NW); | ||
1310 | bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | | ||
1311 | BT_VALID_CORUN_LUT_20 | | ||
1312 | BT_VALID_CORUN_LUT_40); | ||
1313 | |||
1314 | /* For the moment, use the same LUT for 20GHz and 40GHz */ | ||
1315 | memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[lut].lut20, | ||
1316 | sizeof(bt_cmd->bt4_corun_lut20)); | ||
1317 | |||
1318 | memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20, | ||
1319 | sizeof(bt_cmd->bt4_corun_lut40)); | ||
1320 | |||
1321 | return 0; | ||
1322 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 036857698565..51685693af2e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h | |||
@@ -78,5 +78,9 @@ | |||
78 | #define IWL_MVM_PS_SNOOZE_INTERVAL 25 | 78 | #define IWL_MVM_PS_SNOOZE_INTERVAL 25 |
79 | #define IWL_MVM_PS_SNOOZE_WINDOW 50 | 79 | #define IWL_MVM_PS_SNOOZE_WINDOW 50 |
80 | #define IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW 25 | 80 | #define IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW 25 |
81 | #define IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT 64 | ||
82 | #define IWL_MVM_BT_COEX_SYNC2SCO 1 | ||
83 | #define IWL_MVM_BT_COEX_CORUNNING 1 | ||
84 | #define IWL_MVM_BT_COEX_MPLUT 1 | ||
81 | 85 | ||
82 | #endif /* __MVM_CONSTANTS_H */ | 86 | #endif /* __MVM_CONSTANTS_H */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index f36a7ee0267f..e56f5a0edf85 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -376,139 +376,6 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, | |||
376 | return err; | 376 | return err; |
377 | } | 377 | } |
378 | 378 | ||
379 | static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | ||
380 | struct ieee80211_vif *vif) | ||
381 | { | ||
382 | union { | ||
383 | struct iwl_proto_offload_cmd_v1 v1; | ||
384 | struct iwl_proto_offload_cmd_v2 v2; | ||
385 | struct iwl_proto_offload_cmd_v3_small v3s; | ||
386 | struct iwl_proto_offload_cmd_v3_large v3l; | ||
387 | } cmd = {}; | ||
388 | struct iwl_host_cmd hcmd = { | ||
389 | .id = PROT_OFFLOAD_CONFIG_CMD, | ||
390 | .flags = CMD_SYNC, | ||
391 | .data[0] = &cmd, | ||
392 | .dataflags[0] = IWL_HCMD_DFL_DUP, | ||
393 | }; | ||
394 | struct iwl_proto_offload_cmd_common *common; | ||
395 | u32 enabled = 0, size; | ||
396 | u32 capa_flags = mvm->fw->ucode_capa.flags; | ||
397 | #if IS_ENABLED(CONFIG_IPV6) | ||
398 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
399 | int i; | ||
400 | |||
401 | if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL || | ||
402 | capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { | ||
403 | struct iwl_ns_config *nsc; | ||
404 | struct iwl_targ_addr *addrs; | ||
405 | int n_nsc, n_addrs; | ||
406 | int c; | ||
407 | |||
408 | if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { | ||
409 | nsc = cmd.v3s.ns_config; | ||
410 | n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S; | ||
411 | addrs = cmd.v3s.targ_addrs; | ||
412 | n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S; | ||
413 | } else { | ||
414 | nsc = cmd.v3l.ns_config; | ||
415 | n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L; | ||
416 | addrs = cmd.v3l.targ_addrs; | ||
417 | n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L; | ||
418 | } | ||
419 | |||
420 | if (mvmvif->num_target_ipv6_addrs) | ||
421 | enabled |= IWL_D3_PROTO_OFFLOAD_NS; | ||
422 | |||
423 | /* | ||
424 | * For each address we have (and that will fit) fill a target | ||
425 | * address struct and combine for NS offload structs with the | ||
426 | * solicited node addresses. | ||
427 | */ | ||
428 | for (i = 0, c = 0; | ||
429 | i < mvmvif->num_target_ipv6_addrs && | ||
430 | i < n_addrs && c < n_nsc; i++) { | ||
431 | struct in6_addr solicited_addr; | ||
432 | int j; | ||
433 | |||
434 | addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i], | ||
435 | &solicited_addr); | ||
436 | for (j = 0; j < c; j++) | ||
437 | if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr, | ||
438 | &solicited_addr) == 0) | ||
439 | break; | ||
440 | if (j == c) | ||
441 | c++; | ||
442 | addrs[i].addr = mvmvif->target_ipv6_addrs[i]; | ||
443 | addrs[i].config_num = cpu_to_le32(j); | ||
444 | nsc[j].dest_ipv6_addr = solicited_addr; | ||
445 | memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN); | ||
446 | } | ||
447 | |||
448 | if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) | ||
449 | cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i); | ||
450 | else | ||
451 | cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i); | ||
452 | } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { | ||
453 | if (mvmvif->num_target_ipv6_addrs) { | ||
454 | enabled |= IWL_D3_PROTO_OFFLOAD_NS; | ||
455 | memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); | ||
456 | } | ||
457 | |||
458 | BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) != | ||
459 | sizeof(mvmvif->target_ipv6_addrs[0])); | ||
460 | |||
461 | for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, | ||
462 | IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++) | ||
463 | memcpy(cmd.v2.target_ipv6_addr[i], | ||
464 | &mvmvif->target_ipv6_addrs[i], | ||
465 | sizeof(cmd.v2.target_ipv6_addr[i])); | ||
466 | } else { | ||
467 | if (mvmvif->num_target_ipv6_addrs) { | ||
468 | enabled |= IWL_D3_PROTO_OFFLOAD_NS; | ||
469 | memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN); | ||
470 | } | ||
471 | |||
472 | BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) != | ||
473 | sizeof(mvmvif->target_ipv6_addrs[0])); | ||
474 | |||
475 | for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, | ||
476 | IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++) | ||
477 | memcpy(cmd.v1.target_ipv6_addr[i], | ||
478 | &mvmvif->target_ipv6_addrs[i], | ||
479 | sizeof(cmd.v1.target_ipv6_addr[i])); | ||
480 | } | ||
481 | #endif | ||
482 | |||
483 | if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { | ||
484 | common = &cmd.v3s.common; | ||
485 | size = sizeof(cmd.v3s); | ||
486 | } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { | ||
487 | common = &cmd.v3l.common; | ||
488 | size = sizeof(cmd.v3l); | ||
489 | } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { | ||
490 | common = &cmd.v2.common; | ||
491 | size = sizeof(cmd.v2); | ||
492 | } else { | ||
493 | common = &cmd.v1.common; | ||
494 | size = sizeof(cmd.v1); | ||
495 | } | ||
496 | |||
497 | if (vif->bss_conf.arp_addr_cnt) { | ||
498 | enabled |= IWL_D3_PROTO_OFFLOAD_ARP; | ||
499 | common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; | ||
500 | memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); | ||
501 | } | ||
502 | |||
503 | if (!enabled) | ||
504 | return 0; | ||
505 | |||
506 | common->enabled = cpu_to_le32(enabled); | ||
507 | |||
508 | hcmd.len[0] = size; | ||
509 | return iwl_mvm_send_cmd(mvm, &hcmd); | ||
510 | } | ||
511 | |||
512 | enum iwl_mvm_tcp_packet_type { | 379 | enum iwl_mvm_tcp_packet_type { |
513 | MVM_TCP_TX_SYN, | 380 | MVM_TCP_TX_SYN, |
514 | MVM_TCP_RX_SYNACK, | 381 | MVM_TCP_RX_SYNACK, |
@@ -846,8 +713,8 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
846 | quota_cmd.quotas[0].id_and_color = | 713 | quota_cmd.quotas[0].id_and_color = |
847 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id, | 714 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id, |
848 | mvmvif->phy_ctxt->color)); | 715 | mvmvif->phy_ctxt->color)); |
849 | quota_cmd.quotas[0].quota = cpu_to_le32(100); | 716 | quota_cmd.quotas[0].quota = cpu_to_le32(IWL_MVM_MAX_QUOTA); |
850 | quota_cmd.quotas[0].max_duration = cpu_to_le32(1000); | 717 | quota_cmd.quotas[0].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA); |
851 | 718 | ||
852 | for (i = 1; i < MAX_BINDINGS; i++) | 719 | for (i = 1; i < MAX_BINDINGS; i++) |
853 | quota_cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); | 720 | quota_cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); |
@@ -927,6 +794,20 @@ void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
927 | IWL_ERR(mvm, "failed to set non-QoS seqno\n"); | 794 | IWL_ERR(mvm, "failed to set non-QoS seqno\n"); |
928 | } | 795 | } |
929 | 796 | ||
797 | static int | ||
798 | iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm, | ||
799 | const struct iwl_wowlan_config_cmd_v3 *cmd) | ||
800 | { | ||
801 | /* start only with the v2 part of the command */ | ||
802 | u16 cmd_len = sizeof(cmd->common); | ||
803 | |||
804 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID) | ||
805 | cmd_len = sizeof(*cmd); | ||
806 | |||
807 | return iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, CMD_SYNC, | ||
808 | cmd_len, cmd); | ||
809 | } | ||
810 | |||
930 | static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | 811 | static int __iwl_mvm_suspend(struct ieee80211_hw *hw, |
931 | struct cfg80211_wowlan *wowlan, | 812 | struct cfg80211_wowlan *wowlan, |
932 | bool test) | 813 | bool test) |
@@ -939,7 +820,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
939 | struct iwl_mvm_vif *mvmvif; | 820 | struct iwl_mvm_vif *mvmvif; |
940 | struct ieee80211_sta *ap_sta; | 821 | struct ieee80211_sta *ap_sta; |
941 | struct iwl_mvm_sta *mvm_ap_sta; | 822 | struct iwl_mvm_sta *mvm_ap_sta; |
942 | struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; | 823 | struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {}; |
943 | struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; | 824 | struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; |
944 | struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; | 825 | struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; |
945 | struct iwl_d3_manager_config d3_cfg_cmd_data = { | 826 | struct iwl_d3_manager_config d3_cfg_cmd_data = { |
@@ -961,9 +842,8 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
961 | .tkip = &tkip_cmd, | 842 | .tkip = &tkip_cmd, |
962 | .use_tkip = false, | 843 | .use_tkip = false, |
963 | }; | 844 | }; |
964 | int ret, i; | 845 | int ret; |
965 | int len __maybe_unused; | 846 | int len __maybe_unused; |
966 | u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT; | ||
967 | 847 | ||
968 | if (!wowlan) { | 848 | if (!wowlan) { |
969 | /* | 849 | /* |
@@ -980,8 +860,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
980 | 860 | ||
981 | mutex_lock(&mvm->mutex); | 861 | mutex_lock(&mvm->mutex); |
982 | 862 | ||
983 | old_aux_sta_id = mvm->aux_sta.sta_id; | ||
984 | |||
985 | /* see if there's only a single BSS vif and it's associated */ | 863 | /* see if there's only a single BSS vif and it's associated */ |
986 | ieee80211_iterate_active_interfaces_atomic( | 864 | ieee80211_iterate_active_interfaces_atomic( |
987 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | 865 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, |
@@ -1005,49 +883,41 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1005 | 883 | ||
1006 | mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; | 884 | mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; |
1007 | 885 | ||
1008 | /* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */ | 886 | /* TODO: wowlan_config_cmd.common.wowlan_ba_teardown_tids */ |
1009 | 887 | ||
1010 | wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported; | 888 | wowlan_config_cmd.common.is_11n_connection = |
889 | ap_sta->ht_cap.ht_supported; | ||
1011 | 890 | ||
1012 | /* Query the last used seqno and set it */ | 891 | /* Query the last used seqno and set it */ |
1013 | ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); | 892 | ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); |
1014 | if (ret < 0) | 893 | if (ret < 0) |
1015 | goto out_noreset; | 894 | goto out_noreset; |
1016 | wowlan_config_cmd.non_qos_seq = cpu_to_le16(ret); | 895 | wowlan_config_cmd.common.non_qos_seq = cpu_to_le16(ret); |
1017 | 896 | ||
1018 | /* | 897 | iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd.common); |
1019 | * For QoS counters, we store the one to use next, so subtract 0x10 | ||
1020 | * since the uCode will add 0x10 *before* using the value while we | ||
1021 | * increment after using the value (i.e. store the next value to use). | ||
1022 | */ | ||
1023 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { | ||
1024 | u16 seq = mvm_ap_sta->tid_data[i].seq_number; | ||
1025 | seq -= 0x10; | ||
1026 | wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq); | ||
1027 | } | ||
1028 | 898 | ||
1029 | if (wowlan->disconnect) | 899 | if (wowlan->disconnect) |
1030 | wowlan_config_cmd.wakeup_filter |= | 900 | wowlan_config_cmd.common.wakeup_filter |= |
1031 | cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | | 901 | cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | |
1032 | IWL_WOWLAN_WAKEUP_LINK_CHANGE); | 902 | IWL_WOWLAN_WAKEUP_LINK_CHANGE); |
1033 | if (wowlan->magic_pkt) | 903 | if (wowlan->magic_pkt) |
1034 | wowlan_config_cmd.wakeup_filter |= | 904 | wowlan_config_cmd.common.wakeup_filter |= |
1035 | cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET); | 905 | cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET); |
1036 | if (wowlan->gtk_rekey_failure) | 906 | if (wowlan->gtk_rekey_failure) |
1037 | wowlan_config_cmd.wakeup_filter |= | 907 | wowlan_config_cmd.common.wakeup_filter |= |
1038 | cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL); | 908 | cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL); |
1039 | if (wowlan->eap_identity_req) | 909 | if (wowlan->eap_identity_req) |
1040 | wowlan_config_cmd.wakeup_filter |= | 910 | wowlan_config_cmd.common.wakeup_filter |= |
1041 | cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ); | 911 | cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ); |
1042 | if (wowlan->four_way_handshake) | 912 | if (wowlan->four_way_handshake) |
1043 | wowlan_config_cmd.wakeup_filter |= | 913 | wowlan_config_cmd.common.wakeup_filter |= |
1044 | cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE); | 914 | cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE); |
1045 | if (wowlan->n_patterns) | 915 | if (wowlan->n_patterns) |
1046 | wowlan_config_cmd.wakeup_filter |= | 916 | wowlan_config_cmd.common.wakeup_filter |= |
1047 | cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH); | 917 | cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH); |
1048 | 918 | ||
1049 | if (wowlan->rfkill_release) | 919 | if (wowlan->rfkill_release) |
1050 | wowlan_config_cmd.wakeup_filter |= | 920 | wowlan_config_cmd.common.wakeup_filter |= |
1051 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); | 921 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); |
1052 | 922 | ||
1053 | if (wowlan->tcp) { | 923 | if (wowlan->tcp) { |
@@ -1055,7 +925,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1055 | * Set the "link change" (really "link lost") flag as well | 925 | * Set the "link change" (really "link lost") flag as well |
1056 | * since that implies losing the TCP connection. | 926 | * since that implies losing the TCP connection. |
1057 | */ | 927 | */ |
1058 | wowlan_config_cmd.wakeup_filter |= | 928 | wowlan_config_cmd.common.wakeup_filter |= |
1059 | cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS | | 929 | cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS | |
1060 | IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE | | 930 | IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE | |
1061 | IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET | | 931 | IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET | |
@@ -1067,16 +937,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1067 | iwl_trans_stop_device(mvm->trans); | 937 | iwl_trans_stop_device(mvm->trans); |
1068 | 938 | ||
1069 | /* | 939 | /* |
1070 | * The D3 firmware still hardcodes the AP station ID for the | ||
1071 | * BSS we're associated with as 0. Store the real STA ID here | ||
1072 | * and assign 0. When we leave this function, we'll restore | ||
1073 | * the original value for the resume code. | ||
1074 | */ | ||
1075 | old_ap_sta_id = mvm_ap_sta->sta_id; | ||
1076 | mvm_ap_sta->sta_id = 0; | ||
1077 | mvmvif->ap_sta_id = 0; | ||
1078 | |||
1079 | /* | ||
1080 | * Set the HW restart bit -- this is mostly true as we're | 940 | * Set the HW restart bit -- this is mostly true as we're |
1081 | * going to load new firmware and reprogram that, though | 941 | * going to load new firmware and reprogram that, though |
1082 | * the reprogramming is going to be manual to avoid adding | 942 | * the reprogramming is going to be manual to avoid adding |
@@ -1096,16 +956,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1096 | mvm->ptk_ivlen = 0; | 956 | mvm->ptk_ivlen = 0; |
1097 | mvm->ptk_icvlen = 0; | 957 | mvm->ptk_icvlen = 0; |
1098 | 958 | ||
1099 | /* | ||
1100 | * The D3 firmware still hardcodes the AP station ID for the | ||
1101 | * BSS we're associated with as 0. As a result, we have to move | ||
1102 | * the auxiliary station to ID 1 so the ID 0 remains free for | ||
1103 | * the AP station for later. | ||
1104 | * We set the sta_id to 1 here, and reset it to its previous | ||
1105 | * value (that we stored above) later. | ||
1106 | */ | ||
1107 | mvm->aux_sta.sta_id = 1; | ||
1108 | |||
1109 | ret = iwl_mvm_load_d3_fw(mvm); | 959 | ret = iwl_mvm_load_d3_fw(mvm); |
1110 | if (ret) | 960 | if (ret) |
1111 | goto out; | 961 | goto out; |
@@ -1173,9 +1023,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1173 | } | 1023 | } |
1174 | } | 1024 | } |
1175 | 1025 | ||
1176 | ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, | 1026 | ret = iwl_mvm_send_wowlan_config_cmd(mvm, &wowlan_config_cmd); |
1177 | CMD_SYNC, sizeof(wowlan_config_cmd), | ||
1178 | &wowlan_config_cmd); | ||
1179 | if (ret) | 1027 | if (ret) |
1180 | goto out; | 1028 | goto out; |
1181 | 1029 | ||
@@ -1183,7 +1031,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1183 | if (ret) | 1031 | if (ret) |
1184 | goto out; | 1032 | goto out; |
1185 | 1033 | ||
1186 | ret = iwl_mvm_send_proto_offload(mvm, vif); | 1034 | ret = iwl_mvm_send_proto_offload(mvm, vif, false, CMD_SYNC); |
1187 | if (ret) | 1035 | if (ret) |
1188 | goto out; | 1036 | goto out; |
1189 | 1037 | ||
@@ -1191,11 +1039,11 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1191 | if (ret) | 1039 | if (ret) |
1192 | goto out; | 1040 | goto out; |
1193 | 1041 | ||
1194 | ret = iwl_mvm_power_update_device_mode(mvm); | 1042 | ret = iwl_mvm_power_update_device(mvm); |
1195 | if (ret) | 1043 | if (ret) |
1196 | goto out; | 1044 | goto out; |
1197 | 1045 | ||
1198 | ret = iwl_mvm_power_update_mode(mvm, vif); | 1046 | ret = iwl_mvm_power_update_mac(mvm, vif); |
1199 | if (ret) | 1047 | if (ret) |
1200 | goto out; | 1048 | goto out; |
1201 | 1049 | ||
@@ -1222,10 +1070,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1222 | 1070 | ||
1223 | iwl_trans_d3_suspend(mvm->trans, test); | 1071 | iwl_trans_d3_suspend(mvm->trans, test); |
1224 | out: | 1072 | out: |
1225 | mvm->aux_sta.sta_id = old_aux_sta_id; | ||
1226 | mvm_ap_sta->sta_id = old_ap_sta_id; | ||
1227 | mvmvif->ap_sta_id = old_ap_sta_id; | ||
1228 | |||
1229 | if (ret < 0) | 1073 | if (ret < 0) |
1230 | ieee80211_restart_hw(mvm->hw); | 1074 | ieee80211_restart_hw(mvm->hw); |
1231 | out_noreset: | 1075 | out_noreset: |
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 0e29cd83a06a..9b59e1d7ae71 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | |||
@@ -185,7 +185,7 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf, | |||
185 | 185 | ||
186 | mutex_lock(&mvm->mutex); | 186 | mutex_lock(&mvm->mutex); |
187 | iwl_dbgfs_update_pm(mvm, vif, param, val); | 187 | iwl_dbgfs_update_pm(mvm, vif, param, val); |
188 | ret = iwl_mvm_power_update_mode(mvm, vif); | 188 | ret = iwl_mvm_power_update_mac(mvm, vif); |
189 | mutex_unlock(&mvm->mutex); | 189 | mutex_unlock(&mvm->mutex); |
190 | 190 | ||
191 | return ret ?: count; | 191 | return ret ?: count; |
@@ -202,7 +202,7 @@ static ssize_t iwl_dbgfs_pm_params_read(struct file *file, | |||
202 | int bufsz = sizeof(buf); | 202 | int bufsz = sizeof(buf); |
203 | int pos; | 203 | int pos; |
204 | 204 | ||
205 | pos = iwl_mvm_power_dbgfs_read(mvm, vif, buf, bufsz); | 205 | pos = iwl_mvm_power_mac_dbgfs_read(mvm, vif, buf, bufsz); |
206 | 206 | ||
207 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 207 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
208 | } | 208 | } |
@@ -225,6 +225,29 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, | |||
225 | 225 | ||
226 | ap_sta_id = mvmvif->ap_sta_id; | 226 | ap_sta_id = mvmvif->ap_sta_id; |
227 | 227 | ||
228 | switch (ieee80211_vif_type_p2p(vif)) { | ||
229 | case NL80211_IFTYPE_ADHOC: | ||
230 | pos += scnprintf(buf+pos, bufsz-pos, "type: ibss\n"); | ||
231 | break; | ||
232 | case NL80211_IFTYPE_STATION: | ||
233 | pos += scnprintf(buf+pos, bufsz-pos, "type: bss\n"); | ||
234 | break; | ||
235 | case NL80211_IFTYPE_AP: | ||
236 | pos += scnprintf(buf+pos, bufsz-pos, "type: ap\n"); | ||
237 | break; | ||
238 | case NL80211_IFTYPE_P2P_CLIENT: | ||
239 | pos += scnprintf(buf+pos, bufsz-pos, "type: p2p client\n"); | ||
240 | break; | ||
241 | case NL80211_IFTYPE_P2P_GO: | ||
242 | pos += scnprintf(buf+pos, bufsz-pos, "type: p2p go\n"); | ||
243 | break; | ||
244 | case NL80211_IFTYPE_P2P_DEVICE: | ||
245 | pos += scnprintf(buf+pos, bufsz-pos, "type: p2p dev\n"); | ||
246 | break; | ||
247 | default: | ||
248 | break; | ||
249 | } | ||
250 | |||
228 | pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n", | 251 | pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n", |
229 | mvmvif->id, mvmvif->color); | 252 | mvmvif->id, mvmvif->color); |
230 | pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n", | 253 | pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n", |
@@ -249,9 +272,10 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, | |||
249 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 272 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
250 | 273 | ||
251 | pos += scnprintf(buf+pos, bufsz-pos, | 274 | pos += scnprintf(buf+pos, bufsz-pos, |
252 | "ap_sta_id %d - reduced Tx power %d\n", | 275 | "ap_sta_id %d - reduced Tx power %d force %d\n", |
253 | ap_sta_id, | 276 | ap_sta_id, |
254 | mvm_sta->bt_reduced_txpower); | 277 | mvm_sta->bt_reduced_txpower, |
278 | mvm_sta->bt_reduced_txpower_dbg); | ||
255 | } | 279 | } |
256 | } | 280 | } |
257 | 281 | ||
@@ -269,6 +293,41 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, | |||
269 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 293 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
270 | } | 294 | } |
271 | 295 | ||
296 | static ssize_t iwl_dbgfs_reduced_txp_write(struct ieee80211_vif *vif, | ||
297 | char *buf, size_t count, | ||
298 | loff_t *ppos) | ||
299 | { | ||
300 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
301 | struct iwl_mvm *mvm = mvmvif->mvm; | ||
302 | struct iwl_mvm_sta *mvmsta; | ||
303 | bool reduced_tx_power; | ||
304 | int ret; | ||
305 | |||
306 | if (mvmvif->ap_sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id)) | ||
307 | return -ENOTCONN; | ||
308 | |||
309 | if (strtobool(buf, &reduced_tx_power) != 0) | ||
310 | return -EINVAL; | ||
311 | |||
312 | mutex_lock(&mvm->mutex); | ||
313 | |||
314 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id); | ||
315 | if (IS_ERR_OR_NULL(mvmsta)) { | ||
316 | mutex_unlock(&mvm->mutex); | ||
317 | return -ENOTCONN; | ||
318 | } | ||
319 | |||
320 | mvmsta->bt_reduced_txpower_dbg = false; | ||
321 | ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, | ||
322 | reduced_tx_power); | ||
323 | if (!ret) | ||
324 | mvmsta->bt_reduced_txpower_dbg = true; | ||
325 | |||
326 | mutex_unlock(&mvm->mutex); | ||
327 | |||
328 | return ret ? : count; | ||
329 | } | ||
330 | |||
272 | static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif, | 331 | static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif, |
273 | enum iwl_dbgfs_bf_mask param, int value) | 332 | enum iwl_dbgfs_bf_mask param, int value) |
274 | { | 333 | { |
@@ -403,9 +462,9 @@ static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf, | |||
403 | mutex_lock(&mvm->mutex); | 462 | mutex_lock(&mvm->mutex); |
404 | iwl_dbgfs_update_bf(vif, param, value); | 463 | iwl_dbgfs_update_bf(vif, param, value); |
405 | if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) | 464 | if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) |
406 | ret = iwl_mvm_disable_beacon_filter(mvm, vif); | 465 | ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC); |
407 | else | 466 | else |
408 | ret = iwl_mvm_enable_beacon_filter(mvm, vif); | 467 | ret = iwl_mvm_enable_beacon_filter(mvm, vif, CMD_SYNC); |
409 | mutex_unlock(&mvm->mutex); | 468 | mutex_unlock(&mvm->mutex); |
410 | 469 | ||
411 | return ret ?: count; | 470 | return ret ?: count; |
@@ -460,6 +519,41 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file, | |||
460 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 519 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
461 | } | 520 | } |
462 | 521 | ||
522 | static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, | ||
523 | size_t count, loff_t *ppos) | ||
524 | { | ||
525 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
526 | struct iwl_mvm *mvm = mvmvif->mvm; | ||
527 | u8 value; | ||
528 | int ret; | ||
529 | |||
530 | ret = kstrtou8(buf, 0, &value); | ||
531 | if (ret) | ||
532 | return ret; | ||
533 | if (value > 1) | ||
534 | return -EINVAL; | ||
535 | |||
536 | mutex_lock(&mvm->mutex); | ||
537 | iwl_mvm_update_low_latency(mvm, vif, value); | ||
538 | mutex_unlock(&mvm->mutex); | ||
539 | |||
540 | return count; | ||
541 | } | ||
542 | |||
543 | static ssize_t iwl_dbgfs_low_latency_read(struct file *file, | ||
544 | char __user *user_buf, | ||
545 | size_t count, loff_t *ppos) | ||
546 | { | ||
547 | struct ieee80211_vif *vif = file->private_data; | ||
548 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
549 | char buf[3]; | ||
550 | |||
551 | buf[0] = mvmvif->low_latency ? '1' : '0'; | ||
552 | buf[1] = '\n'; | ||
553 | buf[2] = '\0'; | ||
554 | return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf)); | ||
555 | } | ||
556 | |||
463 | #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ | 557 | #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ |
464 | _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) | 558 | _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) |
465 | #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ | 559 | #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ |
@@ -473,6 +567,8 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file, | |||
473 | MVM_DEBUGFS_READ_FILE_OPS(mac_params); | 567 | MVM_DEBUGFS_READ_FILE_OPS(mac_params); |
474 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32); | 568 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32); |
475 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); | 569 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); |
570 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); | ||
571 | MVM_DEBUGFS_WRITE_FILE_OPS(reduced_txp, 10); | ||
476 | 572 | ||
477 | void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 573 | void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
478 | { | 574 | { |
@@ -496,15 +592,18 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
496 | return; | 592 | return; |
497 | } | 593 | } |
498 | 594 | ||
499 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && | 595 | if ((mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT) && |
596 | iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && | ||
500 | ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) || | 597 | ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) || |
501 | (vif->type == NL80211_IFTYPE_STATION && vif->p2p && | 598 | (vif->type == NL80211_IFTYPE_STATION && vif->p2p && |
502 | mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS))) | 599 | mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM))) |
503 | MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR | | 600 | MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR | |
504 | S_IRUSR); | 601 | S_IRUSR); |
505 | 602 | ||
506 | MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, | 603 | MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR); |
507 | S_IRUSR); | 604 | MVM_DEBUGFS_ADD_FILE_VIF(reduced_txp, mvmvif->dbgfs_dir, S_IWUSR); |
605 | MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, | ||
606 | S_IRUSR | S_IWUSR); | ||
508 | 607 | ||
509 | if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && | 608 | if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && |
510 | mvmvif == mvm->bf_allowed_vif) | 609 | mvmvif == mvm->bf_allowed_vif) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 369d4c90e669..1b52deea6081 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
@@ -60,11 +60,14 @@ | |||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | #include <linux/vmalloc.h> | ||
64 | |||
63 | #include "mvm.h" | 65 | #include "mvm.h" |
64 | #include "sta.h" | 66 | #include "sta.h" |
65 | #include "iwl-io.h" | 67 | #include "iwl-io.h" |
66 | #include "iwl-prph.h" | 68 | #include "iwl-prph.h" |
67 | #include "debugfs.h" | 69 | #include "debugfs.h" |
70 | #include "fw-error-dump.h" | ||
68 | 71 | ||
69 | static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, | 72 | static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, |
70 | size_t count, loff_t *ppos) | 73 | size_t count, loff_t *ppos) |
@@ -90,7 +93,7 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, | |||
90 | static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, | 93 | static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, |
91 | size_t count, loff_t *ppos) | 94 | size_t count, loff_t *ppos) |
92 | { | 95 | { |
93 | struct ieee80211_sta *sta; | 96 | struct iwl_mvm_sta *mvmsta; |
94 | int sta_id, drain, ret; | 97 | int sta_id, drain, ret; |
95 | 98 | ||
96 | if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) | 99 | if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) |
@@ -105,19 +108,63 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, | |||
105 | 108 | ||
106 | mutex_lock(&mvm->mutex); | 109 | mutex_lock(&mvm->mutex); |
107 | 110 | ||
108 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | 111 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); |
109 | lockdep_is_held(&mvm->mutex)); | 112 | |
110 | if (IS_ERR_OR_NULL(sta)) | 113 | if (!mvmsta) |
111 | ret = -ENOENT; | 114 | ret = -ENOENT; |
112 | else | 115 | else |
113 | ret = iwl_mvm_drain_sta(mvm, (void *)sta->drv_priv, drain) ? : | 116 | ret = iwl_mvm_drain_sta(mvm, mvmsta, drain) ? : count; |
114 | count; | ||
115 | 117 | ||
116 | mutex_unlock(&mvm->mutex); | 118 | mutex_unlock(&mvm->mutex); |
117 | 119 | ||
118 | return ret; | 120 | return ret; |
119 | } | 121 | } |
120 | 122 | ||
123 | static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file) | ||
124 | { | ||
125 | struct iwl_mvm *mvm = inode->i_private; | ||
126 | int ret; | ||
127 | |||
128 | if (!mvm) | ||
129 | return -EINVAL; | ||
130 | |||
131 | mutex_lock(&mvm->mutex); | ||
132 | if (!mvm->fw_error_dump) { | ||
133 | ret = -ENODATA; | ||
134 | goto out; | ||
135 | } | ||
136 | |||
137 | file->private_data = mvm->fw_error_dump; | ||
138 | mvm->fw_error_dump = NULL; | ||
139 | kfree(mvm->fw_error_sram); | ||
140 | mvm->fw_error_sram = NULL; | ||
141 | mvm->fw_error_sram_len = 0; | ||
142 | ret = 0; | ||
143 | |||
144 | out: | ||
145 | mutex_unlock(&mvm->mutex); | ||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file, | ||
150 | char __user *user_buf, | ||
151 | size_t count, loff_t *ppos) | ||
152 | { | ||
153 | struct iwl_fw_error_dump_file *dump_file = file->private_data; | ||
154 | |||
155 | return simple_read_from_buffer(user_buf, count, ppos, | ||
156 | dump_file, | ||
157 | le32_to_cpu(dump_file->file_len)); | ||
158 | } | ||
159 | |||
160 | static int iwl_dbgfs_fw_error_dump_release(struct inode *inode, | ||
161 | struct file *file) | ||
162 | { | ||
163 | vfree(file->private_data); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
121 | static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, | 168 | static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, |
122 | size_t count, loff_t *ppos) | 169 | size_t count, loff_t *ppos) |
123 | { | 170 | { |
@@ -251,7 +298,7 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf, | |||
251 | } | 298 | } |
252 | 299 | ||
253 | mutex_lock(&mvm->mutex); | 300 | mutex_lock(&mvm->mutex); |
254 | ret = iwl_mvm_power_update_device_mode(mvm); | 301 | ret = iwl_mvm_power_update_device(mvm); |
255 | mutex_unlock(&mvm->mutex); | 302 | mutex_unlock(&mvm->mutex); |
256 | 303 | ||
257 | return ret ?: count; | 304 | return ret ?: count; |
@@ -351,6 +398,9 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, | |||
351 | le32_to_cpu(notif->secondary_ch_lut)); | 398 | le32_to_cpu(notif->secondary_ch_lut)); |
352 | pos += scnprintf(buf+pos, bufsz-pos, "bt_activity_grading = %d\n", | 399 | pos += scnprintf(buf+pos, bufsz-pos, "bt_activity_grading = %d\n", |
353 | le32_to_cpu(notif->bt_activity_grading)); | 400 | le32_to_cpu(notif->bt_activity_grading)); |
401 | pos += scnprintf(buf+pos, bufsz-pos, | ||
402 | "antenna isolation = %d CORUN LUT index = %d\n", | ||
403 | mvm->last_ant_isol, mvm->last_corun_lut); | ||
354 | 404 | ||
355 | mutex_unlock(&mvm->mutex); | 405 | mutex_unlock(&mvm->mutex); |
356 | 406 | ||
@@ -393,6 +443,22 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, | |||
393 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 443 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
394 | } | 444 | } |
395 | 445 | ||
446 | static ssize_t | ||
447 | iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf, | ||
448 | size_t count, loff_t *ppos) | ||
449 | { | ||
450 | u32 bt_tx_prio; | ||
451 | |||
452 | if (sscanf(buf, "%u", &bt_tx_prio) != 1) | ||
453 | return -EINVAL; | ||
454 | if (bt_tx_prio > 4) | ||
455 | return -EINVAL; | ||
456 | |||
457 | mvm->bt_tx_prio = bt_tx_prio; | ||
458 | |||
459 | return count; | ||
460 | } | ||
461 | |||
396 | #define PRINT_STATS_LE32(_str, _val) \ | 462 | #define PRINT_STATS_LE32(_str, _val) \ |
397 | pos += scnprintf(buf + pos, bufsz - pos, \ | 463 | pos += scnprintf(buf + pos, bufsz - pos, \ |
398 | fmt_table, _str, \ | 464 | fmt_table, _str, \ |
@@ -532,6 +598,80 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, | |||
532 | } | 598 | } |
533 | #undef PRINT_STAT_LE32 | 599 | #undef PRINT_STAT_LE32 |
534 | 600 | ||
601 | static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm, | ||
602 | char __user *user_buf, size_t count, | ||
603 | loff_t *ppos, | ||
604 | struct iwl_mvm_frame_stats *stats) | ||
605 | { | ||
606 | char *buff, *pos, *endpos; | ||
607 | int idx, i; | ||
608 | int ret; | ||
609 | static const size_t bufsz = 1024; | ||
610 | |||
611 | buff = kmalloc(bufsz, GFP_KERNEL); | ||
612 | if (!buff) | ||
613 | return -ENOMEM; | ||
614 | |||
615 | spin_lock_bh(&mvm->drv_stats_lock); | ||
616 | |||
617 | pos = buff; | ||
618 | endpos = pos + bufsz; | ||
619 | |||
620 | pos += scnprintf(pos, endpos - pos, | ||
621 | "Legacy/HT/VHT\t:\t%d/%d/%d\n", | ||
622 | stats->legacy_frames, | ||
623 | stats->ht_frames, | ||
624 | stats->vht_frames); | ||
625 | pos += scnprintf(pos, endpos - pos, "20/40/80\t:\t%d/%d/%d\n", | ||
626 | stats->bw_20_frames, | ||
627 | stats->bw_40_frames, | ||
628 | stats->bw_80_frames); | ||
629 | pos += scnprintf(pos, endpos - pos, "NGI/SGI\t\t:\t%d/%d\n", | ||
630 | stats->ngi_frames, | ||
631 | stats->sgi_frames); | ||
632 | pos += scnprintf(pos, endpos - pos, "SISO/MIMO2\t:\t%d/%d\n", | ||
633 | stats->siso_frames, | ||
634 | stats->mimo2_frames); | ||
635 | pos += scnprintf(pos, endpos - pos, "FAIL/SCSS\t:\t%d/%d\n", | ||
636 | stats->fail_frames, | ||
637 | stats->success_frames); | ||
638 | pos += scnprintf(pos, endpos - pos, "MPDUs agg\t:\t%d\n", | ||
639 | stats->agg_frames); | ||
640 | pos += scnprintf(pos, endpos - pos, "A-MPDUs\t\t:\t%d\n", | ||
641 | stats->ampdu_count); | ||
642 | pos += scnprintf(pos, endpos - pos, "Avg MPDUs/A-MPDU:\t%d\n", | ||
643 | stats->ampdu_count > 0 ? | ||
644 | (stats->agg_frames / stats->ampdu_count) : 0); | ||
645 | |||
646 | pos += scnprintf(pos, endpos - pos, "Last Rates\n"); | ||
647 | |||
648 | idx = stats->last_frame_idx - 1; | ||
649 | for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) { | ||
650 | idx = (idx + 1) % ARRAY_SIZE(stats->last_rates); | ||
651 | if (stats->last_rates[idx] == 0) | ||
652 | continue; | ||
653 | pos += scnprintf(pos, endpos - pos, "Rate[%d]: ", | ||
654 | (int)(ARRAY_SIZE(stats->last_rates) - i)); | ||
655 | pos += rs_pretty_print_rate(pos, stats->last_rates[idx]); | ||
656 | } | ||
657 | spin_unlock_bh(&mvm->drv_stats_lock); | ||
658 | |||
659 | ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff); | ||
660 | kfree(buff); | ||
661 | |||
662 | return ret; | ||
663 | } | ||
664 | |||
665 | static ssize_t iwl_dbgfs_drv_rx_stats_read(struct file *file, | ||
666 | char __user *user_buf, size_t count, | ||
667 | loff_t *ppos) | ||
668 | { | ||
669 | struct iwl_mvm *mvm = file->private_data; | ||
670 | |||
671 | return iwl_dbgfs_frame_stats_read(mvm, user_buf, count, ppos, | ||
672 | &mvm->drv_rx_stats); | ||
673 | } | ||
674 | |||
535 | static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, | 675 | static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, |
536 | size_t count, loff_t *ppos) | 676 | size_t count, loff_t *ppos) |
537 | { | 677 | { |
@@ -592,7 +732,7 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, | |||
592 | return -EINVAL; | 732 | return -EINVAL; |
593 | if (scan_rx_ant > ANT_ABC) | 733 | if (scan_rx_ant > ANT_ABC) |
594 | return -EINVAL; | 734 | return -EINVAL; |
595 | if (scan_rx_ant & ~iwl_fw_valid_rx_ant(mvm->fw)) | 735 | if (scan_rx_ant & ~mvm->fw->valid_rx_ant) |
596 | return -EINVAL; | 736 | return -EINVAL; |
597 | 737 | ||
598 | mvm->scan_rx_ant = scan_rx_ant; | 738 | mvm->scan_rx_ant = scan_rx_ant; |
@@ -600,6 +740,187 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, | |||
600 | return count; | 740 | return count; |
601 | } | 741 | } |
602 | 742 | ||
743 | #define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__) | ||
744 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | ||
745 | static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file, | ||
746 | char __user *user_buf, | ||
747 | size_t count, loff_t *ppos) | ||
748 | { | ||
749 | struct iwl_mvm *mvm = file->private_data; | ||
750 | struct iwl_bcast_filter_cmd cmd; | ||
751 | const struct iwl_fw_bcast_filter *filter; | ||
752 | char *buf; | ||
753 | int bufsz = 1024; | ||
754 | int i, j, pos = 0; | ||
755 | ssize_t ret; | ||
756 | |||
757 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
758 | if (!buf) | ||
759 | return -ENOMEM; | ||
760 | |||
761 | mutex_lock(&mvm->mutex); | ||
762 | if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) { | ||
763 | ADD_TEXT("None\n"); | ||
764 | mutex_unlock(&mvm->mutex); | ||
765 | goto out; | ||
766 | } | ||
767 | mutex_unlock(&mvm->mutex); | ||
768 | |||
769 | for (i = 0; cmd.filters[i].attrs[0].mask; i++) { | ||
770 | filter = &cmd.filters[i]; | ||
771 | |||
772 | ADD_TEXT("Filter [%d]:\n", i); | ||
773 | ADD_TEXT("\tDiscard=%d\n", filter->discard); | ||
774 | ADD_TEXT("\tFrame Type: %s\n", | ||
775 | filter->frame_type ? "IPv4" : "Generic"); | ||
776 | |||
777 | for (j = 0; j < ARRAY_SIZE(filter->attrs); j++) { | ||
778 | const struct iwl_fw_bcast_filter_attr *attr; | ||
779 | |||
780 | attr = &filter->attrs[j]; | ||
781 | if (!attr->mask) | ||
782 | break; | ||
783 | |||
784 | ADD_TEXT("\tAttr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x\n", | ||
785 | j, attr->offset, | ||
786 | attr->offset_type ? "IP End" : | ||
787 | "Payload Start", | ||
788 | be32_to_cpu(attr->mask), | ||
789 | be32_to_cpu(attr->val), | ||
790 | le16_to_cpu(attr->reserved1)); | ||
791 | } | ||
792 | } | ||
793 | out: | ||
794 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
795 | kfree(buf); | ||
796 | return ret; | ||
797 | } | ||
798 | |||
799 | static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf, | ||
800 | size_t count, loff_t *ppos) | ||
801 | { | ||
802 | int pos, next_pos; | ||
803 | struct iwl_fw_bcast_filter filter = {}; | ||
804 | struct iwl_bcast_filter_cmd cmd; | ||
805 | u32 filter_id, attr_id, mask, value; | ||
806 | int err = 0; | ||
807 | |||
808 | if (sscanf(buf, "%d %hhi %hhi %n", &filter_id, &filter.discard, | ||
809 | &filter.frame_type, &pos) != 3) | ||
810 | return -EINVAL; | ||
811 | |||
812 | if (filter_id >= ARRAY_SIZE(mvm->dbgfs_bcast_filtering.cmd.filters) || | ||
813 | filter.frame_type > BCAST_FILTER_FRAME_TYPE_IPV4) | ||
814 | return -EINVAL; | ||
815 | |||
816 | for (attr_id = 0; attr_id < ARRAY_SIZE(filter.attrs); | ||
817 | attr_id++) { | ||
818 | struct iwl_fw_bcast_filter_attr *attr = | ||
819 | &filter.attrs[attr_id]; | ||
820 | |||
821 | if (pos >= count) | ||
822 | break; | ||
823 | |||
824 | if (sscanf(&buf[pos], "%hhi %hhi %i %i %n", | ||
825 | &attr->offset, &attr->offset_type, | ||
826 | &mask, &value, &next_pos) != 4) | ||
827 | return -EINVAL; | ||
828 | |||
829 | attr->mask = cpu_to_be32(mask); | ||
830 | attr->val = cpu_to_be32(value); | ||
831 | if (mask) | ||
832 | filter.num_attrs++; | ||
833 | |||
834 | pos += next_pos; | ||
835 | } | ||
836 | |||
837 | mutex_lock(&mvm->mutex); | ||
838 | memcpy(&mvm->dbgfs_bcast_filtering.cmd.filters[filter_id], | ||
839 | &filter, sizeof(filter)); | ||
840 | |||
841 | /* send updated bcast filtering configuration */ | ||
842 | if (mvm->dbgfs_bcast_filtering.override && | ||
843 | iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) | ||
844 | err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC, | ||
845 | sizeof(cmd), &cmd); | ||
846 | mutex_unlock(&mvm->mutex); | ||
847 | |||
848 | return err ?: count; | ||
849 | } | ||
850 | |||
851 | static ssize_t iwl_dbgfs_bcast_filters_macs_read(struct file *file, | ||
852 | char __user *user_buf, | ||
853 | size_t count, loff_t *ppos) | ||
854 | { | ||
855 | struct iwl_mvm *mvm = file->private_data; | ||
856 | struct iwl_bcast_filter_cmd cmd; | ||
857 | char *buf; | ||
858 | int bufsz = 1024; | ||
859 | int i, pos = 0; | ||
860 | ssize_t ret; | ||
861 | |||
862 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
863 | if (!buf) | ||
864 | return -ENOMEM; | ||
865 | |||
866 | mutex_lock(&mvm->mutex); | ||
867 | if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) { | ||
868 | ADD_TEXT("None\n"); | ||
869 | mutex_unlock(&mvm->mutex); | ||
870 | goto out; | ||
871 | } | ||
872 | mutex_unlock(&mvm->mutex); | ||
873 | |||
874 | for (i = 0; i < ARRAY_SIZE(cmd.macs); i++) { | ||
875 | const struct iwl_fw_bcast_mac *mac = &cmd.macs[i]; | ||
876 | |||
877 | ADD_TEXT("Mac [%d]: discard=%d attached_filters=0x%x\n", | ||
878 | i, mac->default_discard, mac->attached_filters); | ||
879 | } | ||
880 | out: | ||
881 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
882 | kfree(buf); | ||
883 | return ret; | ||
884 | } | ||
885 | |||
886 | static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm, | ||
887 | char *buf, size_t count, | ||
888 | loff_t *ppos) | ||
889 | { | ||
890 | struct iwl_bcast_filter_cmd cmd; | ||
891 | struct iwl_fw_bcast_mac mac = {}; | ||
892 | u32 mac_id, attached_filters; | ||
893 | int err = 0; | ||
894 | |||
895 | if (!mvm->bcast_filters) | ||
896 | return -ENOENT; | ||
897 | |||
898 | if (sscanf(buf, "%d %hhi %i", &mac_id, &mac.default_discard, | ||
899 | &attached_filters) != 3) | ||
900 | return -EINVAL; | ||
901 | |||
902 | if (mac_id >= ARRAY_SIZE(cmd.macs) || | ||
903 | mac.default_discard > 1 || | ||
904 | attached_filters >= BIT(ARRAY_SIZE(cmd.filters))) | ||
905 | return -EINVAL; | ||
906 | |||
907 | mac.attached_filters = cpu_to_le16(attached_filters); | ||
908 | |||
909 | mutex_lock(&mvm->mutex); | ||
910 | memcpy(&mvm->dbgfs_bcast_filtering.cmd.macs[mac_id], | ||
911 | &mac, sizeof(mac)); | ||
912 | |||
913 | /* send updated bcast filtering configuration */ | ||
914 | if (mvm->dbgfs_bcast_filtering.override && | ||
915 | iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) | ||
916 | err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC, | ||
917 | sizeof(cmd), &cmd); | ||
918 | mutex_unlock(&mvm->mutex); | ||
919 | |||
920 | return err ?: count; | ||
921 | } | ||
922 | #endif | ||
923 | |||
603 | #ifdef CONFIG_PM_SLEEP | 924 | #ifdef CONFIG_PM_SLEEP |
604 | static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf, | 925 | static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf, |
605 | size_t count, loff_t *ppos) | 926 | size_t count, loff_t *ppos) |
@@ -658,15 +979,117 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, | |||
658 | } | 979 | } |
659 | #endif | 980 | #endif |
660 | 981 | ||
982 | #define PRINT_MVM_REF(ref) do { \ | ||
983 | if (test_bit(ref, mvm->ref_bitmap)) \ | ||
984 | pos += scnprintf(buf + pos, bufsz - pos, \ | ||
985 | "\t(0x%lx) %s\n", \ | ||
986 | BIT(ref), #ref); \ | ||
987 | } while (0) | ||
988 | |||
989 | static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, | ||
990 | char __user *user_buf, | ||
991 | size_t count, loff_t *ppos) | ||
992 | { | ||
993 | struct iwl_mvm *mvm = file->private_data; | ||
994 | int pos = 0; | ||
995 | char buf[256]; | ||
996 | const size_t bufsz = sizeof(buf); | ||
997 | |||
998 | pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%lx\n", | ||
999 | mvm->ref_bitmap[0]); | ||
1000 | |||
1001 | PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN); | ||
1002 | PRINT_MVM_REF(IWL_MVM_REF_SCAN); | ||
1003 | PRINT_MVM_REF(IWL_MVM_REF_ROC); | ||
1004 | PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT); | ||
1005 | PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); | ||
1006 | PRINT_MVM_REF(IWL_MVM_REF_USER); | ||
1007 | |||
1008 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
1009 | } | ||
1010 | |||
1011 | static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf, | ||
1012 | size_t count, loff_t *ppos) | ||
1013 | { | ||
1014 | unsigned long value; | ||
1015 | int ret; | ||
1016 | bool taken; | ||
1017 | |||
1018 | ret = kstrtoul(buf, 10, &value); | ||
1019 | if (ret < 0) | ||
1020 | return ret; | ||
1021 | |||
1022 | mutex_lock(&mvm->mutex); | ||
1023 | |||
1024 | taken = test_bit(IWL_MVM_REF_USER, mvm->ref_bitmap); | ||
1025 | if (value == 1 && !taken) | ||
1026 | iwl_mvm_ref(mvm, IWL_MVM_REF_USER); | ||
1027 | else if (value == 0 && taken) | ||
1028 | iwl_mvm_unref(mvm, IWL_MVM_REF_USER); | ||
1029 | else | ||
1030 | ret = -EINVAL; | ||
1031 | |||
1032 | mutex_unlock(&mvm->mutex); | ||
1033 | |||
1034 | if (ret < 0) | ||
1035 | return ret; | ||
1036 | return count; | ||
1037 | } | ||
1038 | |||
661 | #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ | 1039 | #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ |
662 | _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) | 1040 | _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) |
663 | #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ | 1041 | #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ |
664 | _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) | 1042 | _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) |
665 | #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \ | 1043 | #define MVM_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do { \ |
666 | if (!debugfs_create_file(#name, mode, parent, mvm, \ | 1044 | if (!debugfs_create_file(alias, mode, parent, mvm, \ |
667 | &iwl_dbgfs_##name##_ops)) \ | 1045 | &iwl_dbgfs_##name##_ops)) \ |
668 | goto err; \ | 1046 | goto err; \ |
669 | } while (0) | 1047 | } while (0) |
1048 | #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \ | ||
1049 | MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) | ||
1050 | |||
1051 | static ssize_t | ||
1052 | iwl_dbgfs_prph_reg_read(struct file *file, | ||
1053 | char __user *user_buf, | ||
1054 | size_t count, loff_t *ppos) | ||
1055 | { | ||
1056 | struct iwl_mvm *mvm = file->private_data; | ||
1057 | int pos = 0; | ||
1058 | char buf[32]; | ||
1059 | const size_t bufsz = sizeof(buf); | ||
1060 | |||
1061 | if (!mvm->dbgfs_prph_reg_addr) | ||
1062 | return -EINVAL; | ||
1063 | |||
1064 | pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n", | ||
1065 | mvm->dbgfs_prph_reg_addr, | ||
1066 | iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr)); | ||
1067 | |||
1068 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
1069 | } | ||
1070 | |||
1071 | static ssize_t | ||
1072 | iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf, | ||
1073 | size_t count, loff_t *ppos) | ||
1074 | { | ||
1075 | u8 args; | ||
1076 | u32 value; | ||
1077 | |||
1078 | args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value); | ||
1079 | /* if we only want to set the reg address - nothing more to do */ | ||
1080 | if (args == 1) | ||
1081 | goto out; | ||
1082 | |||
1083 | /* otherwise, make sure we have both address and value */ | ||
1084 | if (args != 2) | ||
1085 | return -EINVAL; | ||
1086 | |||
1087 | iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value); | ||
1088 | out: | ||
1089 | return count; | ||
1090 | } | ||
1091 | |||
1092 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); | ||
670 | 1093 | ||
671 | /* Device wide debugfs entries */ | 1094 | /* Device wide debugfs entries */ |
672 | MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); | 1095 | MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); |
@@ -677,9 +1100,23 @@ MVM_DEBUGFS_READ_FILE_OPS(bt_notif); | |||
677 | MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); | 1100 | MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); |
678 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64); | 1101 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64); |
679 | MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); | 1102 | MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); |
1103 | MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats); | ||
680 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); | 1104 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); |
681 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); | 1105 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); |
1106 | MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10); | ||
682 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); | 1107 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); |
1108 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); | ||
1109 | |||
1110 | static const struct file_operations iwl_dbgfs_fw_error_dump_ops = { | ||
1111 | .open = iwl_dbgfs_fw_error_dump_open, | ||
1112 | .read = iwl_dbgfs_fw_error_dump_read, | ||
1113 | .release = iwl_dbgfs_fw_error_dump_release, | ||
1114 | }; | ||
1115 | |||
1116 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | ||
1117 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); | ||
1118 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); | ||
1119 | #endif | ||
683 | 1120 | ||
684 | #ifdef CONFIG_PM_SLEEP | 1121 | #ifdef CONFIG_PM_SLEEP |
685 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); | 1122 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); |
@@ -687,24 +1124,52 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); | |||
687 | 1124 | ||
688 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | 1125 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) |
689 | { | 1126 | { |
1127 | struct dentry *bcast_dir __maybe_unused; | ||
690 | char buf[100]; | 1128 | char buf[100]; |
691 | 1129 | ||
1130 | spin_lock_init(&mvm->drv_stats_lock); | ||
1131 | |||
692 | mvm->debugfs_dir = dbgfs_dir; | 1132 | mvm->debugfs_dir = dbgfs_dir; |
693 | 1133 | ||
694 | MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR); | 1134 | MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR); |
695 | MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); | 1135 | MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); |
696 | MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); | 1136 | MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); |
697 | MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); | 1137 | MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); |
1138 | MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR); | ||
698 | MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); | 1139 | MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); |
699 | MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); | 1140 | MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); |
700 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD) | 1141 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD) |
701 | MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, | 1142 | MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, |
702 | S_IRUSR | S_IWUSR); | 1143 | S_IRUSR | S_IWUSR); |
703 | MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); | 1144 | MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); |
1145 | MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR); | ||
704 | MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); | 1146 | MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); |
705 | MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); | 1147 | MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); |
1148 | MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR); | ||
706 | MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, | 1149 | MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, |
707 | S_IWUSR | S_IRUSR); | 1150 | S_IWUSR | S_IRUSR); |
1151 | MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR); | ||
1152 | MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR); | ||
1153 | |||
1154 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | ||
1155 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) { | ||
1156 | bcast_dir = debugfs_create_dir("bcast_filtering", | ||
1157 | mvm->debugfs_dir); | ||
1158 | if (!bcast_dir) | ||
1159 | goto err; | ||
1160 | |||
1161 | if (!debugfs_create_bool("override", S_IRUSR | S_IWUSR, | ||
1162 | bcast_dir, | ||
1163 | &mvm->dbgfs_bcast_filtering.override)) | ||
1164 | goto err; | ||
1165 | |||
1166 | MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters, | ||
1167 | bcast_dir, S_IWUSR | S_IRUSR); | ||
1168 | MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs, | ||
1169 | bcast_dir, S_IWUSR | S_IRUSR); | ||
1170 | } | ||
1171 | #endif | ||
1172 | |||
708 | #ifdef CONFIG_PM_SLEEP | 1173 | #ifdef CONFIG_PM_SLEEP |
709 | MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); | 1174 | MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); |
710 | MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR); | 1175 | MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index 1b4e54d416b0..21877e5966a8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | |||
@@ -70,37 +70,28 @@ | |||
70 | 70 | ||
71 | /** | 71 | /** |
72 | * enum iwl_bt_coex_flags - flags for BT_COEX command | 72 | * enum iwl_bt_coex_flags - flags for BT_COEX command |
73 | * @BT_CH_PRIMARY_EN: | ||
74 | * @BT_CH_SECONDARY_EN: | ||
75 | * @BT_NOTIF_COEX_OFF: | ||
76 | * @BT_COEX_MODE_POS: | 73 | * @BT_COEX_MODE_POS: |
77 | * @BT_COEX_MODE_MSK: | 74 | * @BT_COEX_MODE_MSK: |
78 | * @BT_COEX_DISABLE: | 75 | * @BT_COEX_DISABLE: |
79 | * @BT_COEX_2W: | 76 | * @BT_COEX_2W: |
80 | * @BT_COEX_3W: | 77 | * @BT_COEX_3W: |
81 | * @BT_COEX_NW: | 78 | * @BT_COEX_NW: |
82 | * @BT_USE_DEFAULTS: | 79 | * @BT_COEX_SYNC2SCO: |
83 | * @BT_SYNC_2_BT_DISABLE: | 80 | * @BT_COEX_CORUNNING: |
84 | * @BT_COEX_CORUNNING_TBL_EN: | 81 | * @BT_COEX_MPLUT: |
85 | * | 82 | * |
86 | * The COEX_MODE must be set for each command. Even if it is not changed. | 83 | * The COEX_MODE must be set for each command. Even if it is not changed. |
87 | */ | 84 | */ |
88 | enum iwl_bt_coex_flags { | 85 | enum iwl_bt_coex_flags { |
89 | BT_CH_PRIMARY_EN = BIT(0), | ||
90 | BT_CH_SECONDARY_EN = BIT(1), | ||
91 | BT_NOTIF_COEX_OFF = BIT(2), | ||
92 | BT_COEX_MODE_POS = 3, | 86 | BT_COEX_MODE_POS = 3, |
93 | BT_COEX_MODE_MSK = BITS(3) << BT_COEX_MODE_POS, | 87 | BT_COEX_MODE_MSK = BITS(3) << BT_COEX_MODE_POS, |
94 | BT_COEX_DISABLE = 0x0 << BT_COEX_MODE_POS, | 88 | BT_COEX_DISABLE = 0x0 << BT_COEX_MODE_POS, |
95 | BT_COEX_2W = 0x1 << BT_COEX_MODE_POS, | 89 | BT_COEX_2W = 0x1 << BT_COEX_MODE_POS, |
96 | BT_COEX_3W = 0x2 << BT_COEX_MODE_POS, | 90 | BT_COEX_3W = 0x2 << BT_COEX_MODE_POS, |
97 | BT_COEX_NW = 0x3 << BT_COEX_MODE_POS, | 91 | BT_COEX_NW = 0x3 << BT_COEX_MODE_POS, |
98 | BT_USE_DEFAULTS = BIT(6), | 92 | BT_COEX_SYNC2SCO = BIT(7), |
99 | BT_SYNC_2_BT_DISABLE = BIT(7), | 93 | BT_COEX_CORUNNING = BIT(8), |
100 | BT_COEX_CORUNNING_TBL_EN = BIT(8), | 94 | BT_COEX_MPLUT = BIT(9), |
101 | BT_COEX_MPLUT_TBL_EN = BIT(9), | ||
102 | /* Bit 10 is reserved */ | ||
103 | BT_COEX_WF_PRIO_BOOST_CHECK_EN = BIT(11), | ||
104 | }; | 95 | }; |
105 | 96 | ||
106 | /* | 97 | /* |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index 8415ff312d0e..10fcc1a79ebd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | |||
@@ -231,11 +231,15 @@ enum iwl_wowlan_wakeup_filters { | |||
231 | IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT = BIT(8), | 231 | IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT = BIT(8), |
232 | IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS = BIT(9), | 232 | IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS = BIT(9), |
233 | IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE = BIT(10), | 233 | IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE = BIT(10), |
234 | /* BIT(11) reserved */ | 234 | IWL_WOWLAN_WAKEUP_REMOTE_TCP_EXTERNAL = BIT(11), |
235 | IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET = BIT(12), | 235 | IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET = BIT(12), |
236 | IWL_WOWLAN_WAKEUP_IOAC_MAGIC_PACKET = BIT(13), | ||
237 | IWL_WOWLAN_WAKEUP_HOST_TIMER = BIT(14), | ||
238 | IWL_WOWLAN_WAKEUP_RX_FRAME = BIT(15), | ||
239 | IWL_WOWLAN_WAKEUP_BCN_FILTERING = BIT(16), | ||
236 | }; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */ | 240 | }; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */ |
237 | 241 | ||
238 | struct iwl_wowlan_config_cmd { | 242 | struct iwl_wowlan_config_cmd_v2 { |
239 | __le32 wakeup_filter; | 243 | __le32 wakeup_filter; |
240 | __le16 non_qos_seq; | 244 | __le16 non_qos_seq; |
241 | __le16 qos_seq[8]; | 245 | __le16 qos_seq[8]; |
@@ -243,6 +247,12 @@ struct iwl_wowlan_config_cmd { | |||
243 | u8 is_11n_connection; | 247 | u8 is_11n_connection; |
244 | } __packed; /* WOWLAN_CONFIG_API_S_VER_2 */ | 248 | } __packed; /* WOWLAN_CONFIG_API_S_VER_2 */ |
245 | 249 | ||
250 | struct iwl_wowlan_config_cmd_v3 { | ||
251 | struct iwl_wowlan_config_cmd_v2 common; | ||
252 | u8 offloading_tid; | ||
253 | u8 reserved[3]; | ||
254 | } __packed; /* WOWLAN_CONFIG_API_S_VER_3 */ | ||
255 | |||
246 | /* | 256 | /* |
247 | * WOWLAN_TSC_RSC_PARAMS | 257 | * WOWLAN_TSC_RSC_PARAMS |
248 | */ | 258 | */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 884c08725308..cbbcd8e284e4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | |||
@@ -301,54 +301,65 @@ struct iwl_beacon_filter_cmd { | |||
301 | 301 | ||
302 | /* Beacon filtering and beacon abort */ | 302 | /* Beacon filtering and beacon abort */ |
303 | #define IWL_BF_ENERGY_DELTA_DEFAULT 5 | 303 | #define IWL_BF_ENERGY_DELTA_DEFAULT 5 |
304 | #define IWL_BF_ENERGY_DELTA_D0I3 20 | ||
304 | #define IWL_BF_ENERGY_DELTA_MAX 255 | 305 | #define IWL_BF_ENERGY_DELTA_MAX 255 |
305 | #define IWL_BF_ENERGY_DELTA_MIN 0 | 306 | #define IWL_BF_ENERGY_DELTA_MIN 0 |
306 | 307 | ||
307 | #define IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT 1 | 308 | #define IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT 1 |
309 | #define IWL_BF_ROAMING_ENERGY_DELTA_D0I3 20 | ||
308 | #define IWL_BF_ROAMING_ENERGY_DELTA_MAX 255 | 310 | #define IWL_BF_ROAMING_ENERGY_DELTA_MAX 255 |
309 | #define IWL_BF_ROAMING_ENERGY_DELTA_MIN 0 | 311 | #define IWL_BF_ROAMING_ENERGY_DELTA_MIN 0 |
310 | 312 | ||
311 | #define IWL_BF_ROAMING_STATE_DEFAULT 72 | 313 | #define IWL_BF_ROAMING_STATE_DEFAULT 72 |
314 | #define IWL_BF_ROAMING_STATE_D0I3 72 | ||
312 | #define IWL_BF_ROAMING_STATE_MAX 255 | 315 | #define IWL_BF_ROAMING_STATE_MAX 255 |
313 | #define IWL_BF_ROAMING_STATE_MIN 0 | 316 | #define IWL_BF_ROAMING_STATE_MIN 0 |
314 | 317 | ||
315 | #define IWL_BF_TEMP_THRESHOLD_DEFAULT 112 | 318 | #define IWL_BF_TEMP_THRESHOLD_DEFAULT 112 |
319 | #define IWL_BF_TEMP_THRESHOLD_D0I3 112 | ||
316 | #define IWL_BF_TEMP_THRESHOLD_MAX 255 | 320 | #define IWL_BF_TEMP_THRESHOLD_MAX 255 |
317 | #define IWL_BF_TEMP_THRESHOLD_MIN 0 | 321 | #define IWL_BF_TEMP_THRESHOLD_MIN 0 |
318 | 322 | ||
319 | #define IWL_BF_TEMP_FAST_FILTER_DEFAULT 1 | 323 | #define IWL_BF_TEMP_FAST_FILTER_DEFAULT 1 |
324 | #define IWL_BF_TEMP_FAST_FILTER_D0I3 1 | ||
320 | #define IWL_BF_TEMP_FAST_FILTER_MAX 255 | 325 | #define IWL_BF_TEMP_FAST_FILTER_MAX 255 |
321 | #define IWL_BF_TEMP_FAST_FILTER_MIN 0 | 326 | #define IWL_BF_TEMP_FAST_FILTER_MIN 0 |
322 | 327 | ||
323 | #define IWL_BF_TEMP_SLOW_FILTER_DEFAULT 5 | 328 | #define IWL_BF_TEMP_SLOW_FILTER_DEFAULT 5 |
329 | #define IWL_BF_TEMP_SLOW_FILTER_D0I3 5 | ||
324 | #define IWL_BF_TEMP_SLOW_FILTER_MAX 255 | 330 | #define IWL_BF_TEMP_SLOW_FILTER_MAX 255 |
325 | #define IWL_BF_TEMP_SLOW_FILTER_MIN 0 | 331 | #define IWL_BF_TEMP_SLOW_FILTER_MIN 0 |
326 | 332 | ||
327 | #define IWL_BF_ENABLE_BEACON_FILTER_DEFAULT 1 | 333 | #define IWL_BF_ENABLE_BEACON_FILTER_DEFAULT 1 |
328 | 334 | ||
329 | #define IWL_BF_DEBUG_FLAG_DEFAULT 0 | 335 | #define IWL_BF_DEBUG_FLAG_DEFAULT 0 |
336 | #define IWL_BF_DEBUG_FLAG_D0I3 0 | ||
330 | 337 | ||
331 | #define IWL_BF_ESCAPE_TIMER_DEFAULT 50 | 338 | #define IWL_BF_ESCAPE_TIMER_DEFAULT 50 |
339 | #define IWL_BF_ESCAPE_TIMER_D0I3 1024 | ||
332 | #define IWL_BF_ESCAPE_TIMER_MAX 1024 | 340 | #define IWL_BF_ESCAPE_TIMER_MAX 1024 |
333 | #define IWL_BF_ESCAPE_TIMER_MIN 0 | 341 | #define IWL_BF_ESCAPE_TIMER_MIN 0 |
334 | 342 | ||
335 | #define IWL_BA_ESCAPE_TIMER_DEFAULT 6 | 343 | #define IWL_BA_ESCAPE_TIMER_DEFAULT 6 |
344 | #define IWL_BA_ESCAPE_TIMER_D0I3 6 | ||
336 | #define IWL_BA_ESCAPE_TIMER_D3 9 | 345 | #define IWL_BA_ESCAPE_TIMER_D3 9 |
337 | #define IWL_BA_ESCAPE_TIMER_MAX 1024 | 346 | #define IWL_BA_ESCAPE_TIMER_MAX 1024 |
338 | #define IWL_BA_ESCAPE_TIMER_MIN 0 | 347 | #define IWL_BA_ESCAPE_TIMER_MIN 0 |
339 | 348 | ||
340 | #define IWL_BA_ENABLE_BEACON_ABORT_DEFAULT 1 | 349 | #define IWL_BA_ENABLE_BEACON_ABORT_DEFAULT 1 |
341 | 350 | ||
342 | #define IWL_BF_CMD_CONFIG_DEFAULTS \ | 351 | #define IWL_BF_CMD_CONFIG(mode) \ |
343 | .bf_energy_delta = cpu_to_le32(IWL_BF_ENERGY_DELTA_DEFAULT), \ | 352 | .bf_energy_delta = cpu_to_le32(IWL_BF_ENERGY_DELTA ## mode), \ |
344 | .bf_roaming_energy_delta = \ | 353 | .bf_roaming_energy_delta = \ |
345 | cpu_to_le32(IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT), \ | 354 | cpu_to_le32(IWL_BF_ROAMING_ENERGY_DELTA ## mode), \ |
346 | .bf_roaming_state = cpu_to_le32(IWL_BF_ROAMING_STATE_DEFAULT), \ | 355 | .bf_roaming_state = cpu_to_le32(IWL_BF_ROAMING_STATE ## mode), \ |
347 | .bf_temp_threshold = cpu_to_le32(IWL_BF_TEMP_THRESHOLD_DEFAULT), \ | 356 | .bf_temp_threshold = cpu_to_le32(IWL_BF_TEMP_THRESHOLD ## mode), \ |
348 | .bf_temp_fast_filter = cpu_to_le32(IWL_BF_TEMP_FAST_FILTER_DEFAULT), \ | 357 | .bf_temp_fast_filter = cpu_to_le32(IWL_BF_TEMP_FAST_FILTER ## mode), \ |
349 | .bf_temp_slow_filter = cpu_to_le32(IWL_BF_TEMP_SLOW_FILTER_DEFAULT), \ | 358 | .bf_temp_slow_filter = cpu_to_le32(IWL_BF_TEMP_SLOW_FILTER ## mode), \ |
350 | .bf_debug_flag = cpu_to_le32(IWL_BF_DEBUG_FLAG_DEFAULT), \ | 359 | .bf_debug_flag = cpu_to_le32(IWL_BF_DEBUG_FLAG ## mode), \ |
351 | .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT), \ | 360 | .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER ## mode), \ |
352 | .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT) | 361 | .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER ## mode) |
353 | 362 | ||
363 | #define IWL_BF_CMD_CONFIG_DEFAULTS IWL_BF_CMD_CONFIG(_DEFAULT) | ||
364 | #define IWL_BF_CMD_CONFIG_D0I3 IWL_BF_CMD_CONFIG(_D0I3) | ||
354 | #endif | 365 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h index 85057219cc43..39148b5bb332 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h | |||
@@ -257,7 +257,8 @@ enum { | |||
257 | 257 | ||
258 | /* Bit 17-18: (0) SS, (1) SS*2 */ | 258 | /* Bit 17-18: (0) SS, (1) SS*2 */ |
259 | #define RATE_MCS_STBC_POS 17 | 259 | #define RATE_MCS_STBC_POS 17 |
260 | #define RATE_MCS_STBC_MSK (1 << RATE_MCS_STBC_POS) | 260 | #define RATE_MCS_HT_STBC_MSK (3 << RATE_MCS_STBC_POS) |
261 | #define RATE_MCS_VHT_STBC_MSK (1 << RATE_MCS_STBC_POS) | ||
261 | 262 | ||
262 | /* Bit 19: (0) Beamforming is off, (1) Beamforming is on */ | 263 | /* Bit 19: (0) Beamforming is off, (1) Beamforming is on */ |
263 | #define RATE_MCS_BF_POS 19 | 264 | #define RATE_MCS_BF_POS 19 |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h index 1b60fdff6a56..d63647867262 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h | |||
@@ -199,11 +199,14 @@ enum iwl_sta_modify_flag { | |||
199 | * @STA_SLEEP_STATE_AWAKE: | 199 | * @STA_SLEEP_STATE_AWAKE: |
200 | * @STA_SLEEP_STATE_PS_POLL: | 200 | * @STA_SLEEP_STATE_PS_POLL: |
201 | * @STA_SLEEP_STATE_UAPSD: | 201 | * @STA_SLEEP_STATE_UAPSD: |
202 | * @STA_SLEEP_STATE_MOREDATA: set more-data bit on | ||
203 | * (last) released frame | ||
202 | */ | 204 | */ |
203 | enum iwl_sta_sleep_flag { | 205 | enum iwl_sta_sleep_flag { |
204 | STA_SLEEP_STATE_AWAKE = 0, | 206 | STA_SLEEP_STATE_AWAKE = 0, |
205 | STA_SLEEP_STATE_PS_POLL = BIT(0), | 207 | STA_SLEEP_STATE_PS_POLL = BIT(0), |
206 | STA_SLEEP_STATE_UAPSD = BIT(1), | 208 | STA_SLEEP_STATE_UAPSD = BIT(1), |
209 | STA_SLEEP_STATE_MOREDATA = BIT(2), | ||
207 | }; | 210 | }; |
208 | 211 | ||
209 | /* STA ID and color bits definitions */ | 212 | /* STA ID and color bits definitions */ |
@@ -318,13 +321,15 @@ struct iwl_mvm_add_sta_cmd_v5 { | |||
318 | } __packed; /* ADD_STA_CMD_API_S_VER_5 */ | 321 | } __packed; /* ADD_STA_CMD_API_S_VER_5 */ |
319 | 322 | ||
320 | /** | 323 | /** |
321 | * struct iwl_mvm_add_sta_cmd_v6 - Add / modify a station | 324 | * struct iwl_mvm_add_sta_cmd_v7 - Add / modify a station |
322 | * VER_6 of this command is quite similar to VER_5 except | 325 | * VER_7 of this command is quite similar to VER_5 except |
323 | * exclusion of all fields related to the security key installation. | 326 | * exclusion of all fields related to the security key installation. |
327 | * It only differs from VER_6 by the "awake_acs" field that is | ||
328 | * reserved and ignored in VER_6. | ||
324 | */ | 329 | */ |
325 | struct iwl_mvm_add_sta_cmd_v6 { | 330 | struct iwl_mvm_add_sta_cmd_v7 { |
326 | u8 add_modify; | 331 | u8 add_modify; |
327 | u8 reserved1; | 332 | u8 awake_acs; |
328 | __le16 tid_disable_tx; | 333 | __le16 tid_disable_tx; |
329 | __le32 mac_id_n_color; | 334 | __le32 mac_id_n_color; |
330 | u8 addr[ETH_ALEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */ | 335 | u8 addr[ETH_ALEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */ |
@@ -342,7 +347,7 @@ struct iwl_mvm_add_sta_cmd_v6 { | |||
342 | __le16 assoc_id; | 347 | __le16 assoc_id; |
343 | __le16 beamform_flags; | 348 | __le16 beamform_flags; |
344 | __le32 tfd_queue_msk; | 349 | __le32 tfd_queue_msk; |
345 | } __packed; /* ADD_STA_CMD_API_S_VER_6 */ | 350 | } __packed; /* ADD_STA_CMD_API_S_VER_7 */ |
346 | 351 | ||
347 | /** | 352 | /** |
348 | * struct iwl_mvm_add_sta_key_cmd - add/modify sta key | 353 | * struct iwl_mvm_add_sta_key_cmd - add/modify sta key |
@@ -432,5 +437,15 @@ struct iwl_mvm_wep_key_cmd { | |||
432 | struct iwl_mvm_wep_key wep_key[0]; | 437 | struct iwl_mvm_wep_key wep_key[0]; |
433 | } __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */ | 438 | } __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */ |
434 | 439 | ||
440 | /** | ||
441 | * struct iwl_mvm_eosp_notification - EOSP notification from firmware | ||
442 | * @remain_frame_count: # of frames remaining, non-zero if SP was cut | ||
443 | * short by GO absence | ||
444 | * @sta_id: station ID | ||
445 | */ | ||
446 | struct iwl_mvm_eosp_notification { | ||
447 | __le32 remain_frame_count; | ||
448 | __le32 sta_id; | ||
449 | } __packed; /* UAPSD_EOSP_NTFY_API_S_VER_1 */ | ||
435 | 450 | ||
436 | #endif /* __fw_api_sta_h__ */ | 451 | #endif /* __fw_api_sta_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index b674c2a2b51c..8e122f3a7a74 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | |||
@@ -76,6 +76,8 @@ | |||
76 | * @TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence | 76 | * @TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence |
77 | * @TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence | 77 | * @TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence |
78 | * @TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC) | 78 | * @TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC) |
79 | * @TX_CMD_FLG_BT_PRIO_POS: the position of the BT priority (bit 11 is ignored | ||
80 | * on old firmwares). | ||
79 | * @TX_CMD_FLG_BT_DIS: disable BT priority for this frame | 81 | * @TX_CMD_FLG_BT_DIS: disable BT priority for this frame |
80 | * @TX_CMD_FLG_SEQ_CTL: set if FW should override the sequence control. | 82 | * @TX_CMD_FLG_SEQ_CTL: set if FW should override the sequence control. |
81 | * Should be set for mgmt, non-QOS data, mcast, bcast and in scan command | 83 | * Should be set for mgmt, non-QOS data, mcast, bcast and in scan command |
@@ -107,6 +109,7 @@ enum iwl_tx_flags { | |||
107 | TX_CMD_FLG_VHT_NDPA = BIT(8), | 109 | TX_CMD_FLG_VHT_NDPA = BIT(8), |
108 | TX_CMD_FLG_HT_NDPA = BIT(9), | 110 | TX_CMD_FLG_HT_NDPA = BIT(9), |
109 | TX_CMD_FLG_CSI_FDBK2HOST = BIT(10), | 111 | TX_CMD_FLG_CSI_FDBK2HOST = BIT(10), |
112 | TX_CMD_FLG_BT_PRIO_POS = 11, | ||
110 | TX_CMD_FLG_BT_DIS = BIT(12), | 113 | TX_CMD_FLG_BT_DIS = BIT(12), |
111 | TX_CMD_FLG_SEQ_CTL = BIT(13), | 114 | TX_CMD_FLG_SEQ_CTL = BIT(13), |
112 | TX_CMD_FLG_MORE_FRAG = BIT(14), | 115 | TX_CMD_FLG_MORE_FRAG = BIT(14), |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 989d7dbdca6c..6e75b52588de 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -70,7 +70,7 @@ | |||
70 | #include "fw-api-mac.h" | 70 | #include "fw-api-mac.h" |
71 | #include "fw-api-power.h" | 71 | #include "fw-api-power.h" |
72 | #include "fw-api-d3.h" | 72 | #include "fw-api-d3.h" |
73 | #include "fw-api-bt-coex.h" | 73 | #include "fw-api-coex.h" |
74 | 74 | ||
75 | /* maximal number of Tx queues in any platform */ | 75 | /* maximal number of Tx queues in any platform */ |
76 | #define IWL_MVM_MAX_QUEUES 20 | 76 | #define IWL_MVM_MAX_QUEUES 20 |
@@ -95,6 +95,7 @@ enum { | |||
95 | /* PHY context commands */ | 95 | /* PHY context commands */ |
96 | PHY_CONTEXT_CMD = 0x8, | 96 | PHY_CONTEXT_CMD = 0x8, |
97 | DBG_CFG = 0x9, | 97 | DBG_CFG = 0x9, |
98 | ANTENNA_COUPLING_NOTIFICATION = 0xa, | ||
98 | 99 | ||
99 | /* station table */ | 100 | /* station table */ |
100 | ADD_STA_KEY = 0x17, | 101 | ADD_STA_KEY = 0x17, |
@@ -163,6 +164,7 @@ enum { | |||
163 | TX_ANT_CONFIGURATION_CMD = 0x98, | 164 | TX_ANT_CONFIGURATION_CMD = 0x98, |
164 | BT_CONFIG = 0x9b, | 165 | BT_CONFIG = 0x9b, |
165 | STATISTICS_NOTIFICATION = 0x9d, | 166 | STATISTICS_NOTIFICATION = 0x9d, |
167 | EOSP_NOTIFICATION = 0x9e, | ||
166 | REDUCE_TX_POWER_CMD = 0x9f, | 168 | REDUCE_TX_POWER_CMD = 0x9f, |
167 | 169 | ||
168 | /* RF-KILL commands and notifications */ | 170 | /* RF-KILL commands and notifications */ |
@@ -190,6 +192,7 @@ enum { | |||
190 | REPLY_DEBUG_CMD = 0xf0, | 192 | REPLY_DEBUG_CMD = 0xf0, |
191 | DEBUG_LOG_MSG = 0xf7, | 193 | DEBUG_LOG_MSG = 0xf7, |
192 | 194 | ||
195 | BCAST_FILTER_CMD = 0xcf, | ||
193 | MCAST_FILTER_CMD = 0xd0, | 196 | MCAST_FILTER_CMD = 0xd0, |
194 | 197 | ||
195 | /* D3 commands/notifications */ | 198 | /* D3 commands/notifications */ |
@@ -197,6 +200,7 @@ enum { | |||
197 | PROT_OFFLOAD_CONFIG_CMD = 0xd4, | 200 | PROT_OFFLOAD_CONFIG_CMD = 0xd4, |
198 | OFFLOADS_QUERY_CMD = 0xd5, | 201 | OFFLOADS_QUERY_CMD = 0xd5, |
199 | REMOTE_WAKE_CONFIG_CMD = 0xd6, | 202 | REMOTE_WAKE_CONFIG_CMD = 0xd6, |
203 | D0I3_END_CMD = 0xed, | ||
200 | 204 | ||
201 | /* for WoWLAN in particular */ | 205 | /* for WoWLAN in particular */ |
202 | WOWLAN_PATTERNS = 0xe0, | 206 | WOWLAN_PATTERNS = 0xe0, |
@@ -313,14 +317,12 @@ enum { | |||
313 | 317 | ||
314 | /* Section types for NVM_ACCESS_CMD */ | 318 | /* Section types for NVM_ACCESS_CMD */ |
315 | enum { | 319 | enum { |
316 | NVM_SECTION_TYPE_HW = 0, | 320 | NVM_SECTION_TYPE_SW = 1, |
317 | NVM_SECTION_TYPE_SW, | 321 | NVM_SECTION_TYPE_REGULATORY = 3, |
318 | NVM_SECTION_TYPE_PAPD, | 322 | NVM_SECTION_TYPE_CALIBRATION = 4, |
319 | NVM_SECTION_TYPE_BT, | 323 | NVM_SECTION_TYPE_PRODUCTION = 5, |
320 | NVM_SECTION_TYPE_CALIBRATION, | 324 | NVM_SECTION_TYPE_MAC_OVERRIDE = 11, |
321 | NVM_SECTION_TYPE_PRODUCTION, | 325 | NVM_MAX_NUM_SECTIONS = 12, |
322 | NVM_SECTION_TYPE_POST_FCS_CALIB, | ||
323 | NVM_NUM_OF_SECTIONS, | ||
324 | }; | 326 | }; |
325 | 327 | ||
326 | /** | 328 | /** |
@@ -412,6 +414,35 @@ struct mvm_alive_resp { | |||
412 | __le32 scd_base_ptr; /* SRAM address for SCD */ | 414 | __le32 scd_base_ptr; /* SRAM address for SCD */ |
413 | } __packed; /* ALIVE_RES_API_S_VER_1 */ | 415 | } __packed; /* ALIVE_RES_API_S_VER_1 */ |
414 | 416 | ||
417 | struct mvm_alive_resp_ver2 { | ||
418 | __le16 status; | ||
419 | __le16 flags; | ||
420 | u8 ucode_minor; | ||
421 | u8 ucode_major; | ||
422 | __le16 id; | ||
423 | u8 api_minor; | ||
424 | u8 api_major; | ||
425 | u8 ver_subtype; | ||
426 | u8 ver_type; | ||
427 | u8 mac; | ||
428 | u8 opt; | ||
429 | __le16 reserved2; | ||
430 | __le32 timestamp; | ||
431 | __le32 error_event_table_ptr; /* SRAM address for error log */ | ||
432 | __le32 log_event_table_ptr; /* SRAM address for LMAC event log */ | ||
433 | __le32 cpu_register_ptr; | ||
434 | __le32 dbgm_config_ptr; | ||
435 | __le32 alive_counter_ptr; | ||
436 | __le32 scd_base_ptr; /* SRAM address for SCD */ | ||
437 | __le32 st_fwrd_addr; /* pointer to Store and forward */ | ||
438 | __le32 st_fwrd_size; | ||
439 | u8 umac_minor; /* UMAC version: minor */ | ||
440 | u8 umac_major; /* UMAC version: major */ | ||
441 | __le16 umac_id; /* UMAC version: id */ | ||
442 | __le32 error_info_addr; /* SRAM address for UMAC error log */ | ||
443 | __le32 dbg_print_buff_addr; | ||
444 | } __packed; /* ALIVE_RES_API_S_VER_2 */ | ||
445 | |||
415 | /* Error response/notification */ | 446 | /* Error response/notification */ |
416 | enum { | 447 | enum { |
417 | FW_ERR_UNKNOWN_CMD = 0x0, | 448 | FW_ERR_UNKNOWN_CMD = 0x0, |
@@ -682,6 +713,7 @@ enum { | |||
682 | TE_V2_NOTIF_HOST_FRAG_END = BIT(5), | 713 | TE_V2_NOTIF_HOST_FRAG_END = BIT(5), |
683 | TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6), | 714 | TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6), |
684 | TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7), | 715 | TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7), |
716 | T2_V2_START_IMMEDIATELY = BIT(11), | ||
685 | 717 | ||
686 | TE_V2_NOTIF_MSK = 0xff, | 718 | TE_V2_NOTIF_MSK = 0xff, |
687 | 719 | ||
@@ -1159,6 +1191,90 @@ struct iwl_mcast_filter_cmd { | |||
1159 | u8 addr_list[0]; | 1191 | u8 addr_list[0]; |
1160 | } __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */ | 1192 | } __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */ |
1161 | 1193 | ||
1194 | #define MAX_BCAST_FILTERS 8 | ||
1195 | #define MAX_BCAST_FILTER_ATTRS 2 | ||
1196 | |||
1197 | /** | ||
1198 | * enum iwl_mvm_bcast_filter_attr_offset - written by fw for each Rx packet | ||
1199 | * @BCAST_FILTER_OFFSET_PAYLOAD_START: offset is from payload start. | ||
1200 | * @BCAST_FILTER_OFFSET_IP_END: offset is from ip header end (i.e. | ||
1201 | * start of ip payload). | ||
1202 | */ | ||
1203 | enum iwl_mvm_bcast_filter_attr_offset { | ||
1204 | BCAST_FILTER_OFFSET_PAYLOAD_START = 0, | ||
1205 | BCAST_FILTER_OFFSET_IP_END = 1, | ||
1206 | }; | ||
1207 | |||
1208 | /** | ||
1209 | * struct iwl_fw_bcast_filter_attr - broadcast filter attribute | ||
1210 | * @offset_type: &enum iwl_mvm_bcast_filter_attr_offset. | ||
1211 | * @offset: starting offset of this pattern. | ||
1212 | * @val: value to match - big endian (MSB is the first | ||
1213 | * byte to match from offset pos). | ||
1214 | * @mask: mask to match (big endian). | ||
1215 | */ | ||
1216 | struct iwl_fw_bcast_filter_attr { | ||
1217 | u8 offset_type; | ||
1218 | u8 offset; | ||
1219 | __le16 reserved1; | ||
1220 | __be32 val; | ||
1221 | __be32 mask; | ||
1222 | } __packed; /* BCAST_FILTER_ATT_S_VER_1 */ | ||
1223 | |||
1224 | /** | ||
1225 | * enum iwl_mvm_bcast_filter_frame_type - filter frame type | ||
1226 | * @BCAST_FILTER_FRAME_TYPE_ALL: consider all frames. | ||
1227 | * @BCAST_FILTER_FRAME_TYPE_IPV4: consider only ipv4 frames | ||
1228 | */ | ||
1229 | enum iwl_mvm_bcast_filter_frame_type { | ||
1230 | BCAST_FILTER_FRAME_TYPE_ALL = 0, | ||
1231 | BCAST_FILTER_FRAME_TYPE_IPV4 = 1, | ||
1232 | }; | ||
1233 | |||
1234 | /** | ||
1235 | * struct iwl_fw_bcast_filter - broadcast filter | ||
1236 | * @discard: discard frame (1) or let it pass (0). | ||
1237 | * @frame_type: &enum iwl_mvm_bcast_filter_frame_type. | ||
1238 | * @num_attrs: number of valid attributes in this filter. | ||
1239 | * @attrs: attributes of this filter. a filter is considered matched | ||
1240 | * only when all its attributes are matched (i.e. AND relationship) | ||
1241 | */ | ||
1242 | struct iwl_fw_bcast_filter { | ||
1243 | u8 discard; | ||
1244 | u8 frame_type; | ||
1245 | u8 num_attrs; | ||
1246 | u8 reserved1; | ||
1247 | struct iwl_fw_bcast_filter_attr attrs[MAX_BCAST_FILTER_ATTRS]; | ||
1248 | } __packed; /* BCAST_FILTER_S_VER_1 */ | ||
1249 | |||
1250 | /** | ||
1251 | * struct iwl_fw_bcast_mac - per-mac broadcast filtering configuration. | ||
1252 | * @default_discard: default action for this mac (discard (1) / pass (0)). | ||
1253 | * @attached_filters: bitmap of relevant filters for this mac. | ||
1254 | */ | ||
1255 | struct iwl_fw_bcast_mac { | ||
1256 | u8 default_discard; | ||
1257 | u8 reserved1; | ||
1258 | __le16 attached_filters; | ||
1259 | } __packed; /* BCAST_MAC_CONTEXT_S_VER_1 */ | ||
1260 | |||
1261 | /** | ||
1262 | * struct iwl_bcast_filter_cmd - broadcast filtering configuration | ||
1263 | * @disable: enable (0) / disable (1) | ||
1264 | * @max_bcast_filters: max number of filters (MAX_BCAST_FILTERS) | ||
1265 | * @max_macs: max number of macs (NUM_MAC_INDEX_DRIVER) | ||
1266 | * @filters: broadcast filters | ||
1267 | * @macs: broadcast filtering configuration per-mac | ||
1268 | */ | ||
1269 | struct iwl_bcast_filter_cmd { | ||
1270 | u8 disable; | ||
1271 | u8 max_bcast_filters; | ||
1272 | u8 max_macs; | ||
1273 | u8 reserved1; | ||
1274 | struct iwl_fw_bcast_filter filters[MAX_BCAST_FILTERS]; | ||
1275 | struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER]; | ||
1276 | } __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */ | ||
1277 | |||
1162 | struct mvm_statistics_dbg { | 1278 | struct mvm_statistics_dbg { |
1163 | __le32 burst_check; | 1279 | __le32 burst_check; |
1164 | __le32 burst_count; | 1280 | __le32 burst_count; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h b/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h new file mode 100644 index 000000000000..58c8941c0d95 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-error-dump.h | |||
@@ -0,0 +1,106 @@ | |||
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) 2014 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) 2014 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | *****************************************************************************/ | ||
62 | |||
63 | #ifndef __fw_error_dump_h__ | ||
64 | #define __fw_error_dump_h__ | ||
65 | |||
66 | #include <linux/types.h> | ||
67 | |||
68 | #define IWL_FW_ERROR_DUMP_BARKER 0x14789632 | ||
69 | |||
70 | /** | ||
71 | * enum iwl_fw_error_dump_type - types of data in the dump file | ||
72 | * @IWL_FW_ERROR_DUMP_SRAM: | ||
73 | * @IWL_FW_ERROR_DUMP_REG: | ||
74 | */ | ||
75 | enum iwl_fw_error_dump_type { | ||
76 | IWL_FW_ERROR_DUMP_SRAM = 0, | ||
77 | IWL_FW_ERROR_DUMP_REG = 1, | ||
78 | |||
79 | IWL_FW_ERROR_DUMP_MAX, | ||
80 | }; | ||
81 | |||
82 | /** | ||
83 | * struct iwl_fw_error_dump_data - data for one type | ||
84 | * @type: %enum iwl_fw_error_dump_type | ||
85 | * @len: the length starting from %data - must be a multiplier of 4. | ||
86 | * @data: the data itself padded to be a multiplier of 4. | ||
87 | */ | ||
88 | struct iwl_fw_error_dump_data { | ||
89 | __le32 type; | ||
90 | __le32 len; | ||
91 | __u8 data[]; | ||
92 | } __packed __aligned(4); | ||
93 | |||
94 | /** | ||
95 | * struct iwl_fw_error_dump_file - the layout of the header of the file | ||
96 | * @barker: must be %IWL_FW_ERROR_DUMP_BARKER | ||
97 | * @file_len: the length of all the file starting from %barker | ||
98 | * @data: array of %struct iwl_fw_error_dump_data | ||
99 | */ | ||
100 | struct iwl_fw_error_dump_file { | ||
101 | __le32 barker; | ||
102 | __le32 file_len; | ||
103 | u8 data[0]; | ||
104 | } __packed __aligned(4); | ||
105 | |||
106 | #endif /* __fw_error_dump_h__ */ | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index c03d39541f9e..7ce20062f32d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -110,18 +110,48 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, | |||
110 | container_of(notif_wait, struct iwl_mvm, notif_wait); | 110 | container_of(notif_wait, struct iwl_mvm, notif_wait); |
111 | struct iwl_mvm_alive_data *alive_data = data; | 111 | struct iwl_mvm_alive_data *alive_data = data; |
112 | struct mvm_alive_resp *palive; | 112 | struct mvm_alive_resp *palive; |
113 | 113 | struct mvm_alive_resp_ver2 *palive2; | |
114 | palive = (void *)pkt->data; | 114 | |
115 | 115 | if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive)) { | |
116 | mvm->error_event_table = le32_to_cpu(palive->error_event_table_ptr); | 116 | palive = (void *)pkt->data; |
117 | mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr); | 117 | |
118 | alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr); | 118 | mvm->support_umac_log = false; |
119 | 119 | mvm->error_event_table = | |
120 | alive_data->valid = le16_to_cpu(palive->status) == IWL_ALIVE_STATUS_OK; | 120 | le32_to_cpu(palive->error_event_table_ptr); |
121 | IWL_DEBUG_FW(mvm, | 121 | mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr); |
122 | "Alive ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n", | 122 | alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr); |
123 | le16_to_cpu(palive->status), palive->ver_type, | 123 | |
124 | palive->ver_subtype, palive->flags); | 124 | alive_data->valid = le16_to_cpu(palive->status) == |
125 | IWL_ALIVE_STATUS_OK; | ||
126 | IWL_DEBUG_FW(mvm, | ||
127 | "Alive VER1 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n", | ||
128 | le16_to_cpu(palive->status), palive->ver_type, | ||
129 | palive->ver_subtype, palive->flags); | ||
130 | } else { | ||
131 | palive2 = (void *)pkt->data; | ||
132 | |||
133 | mvm->error_event_table = | ||
134 | le32_to_cpu(palive2->error_event_table_ptr); | ||
135 | mvm->log_event_table = | ||
136 | le32_to_cpu(palive2->log_event_table_ptr); | ||
137 | alive_data->scd_base_addr = le32_to_cpu(palive2->scd_base_ptr); | ||
138 | mvm->umac_error_event_table = | ||
139 | le32_to_cpu(palive2->error_info_addr); | ||
140 | |||
141 | alive_data->valid = le16_to_cpu(palive2->status) == | ||
142 | IWL_ALIVE_STATUS_OK; | ||
143 | if (mvm->umac_error_event_table) | ||
144 | mvm->support_umac_log = true; | ||
145 | |||
146 | IWL_DEBUG_FW(mvm, | ||
147 | "Alive VER2 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n", | ||
148 | le16_to_cpu(palive2->status), palive2->ver_type, | ||
149 | palive2->ver_subtype, palive2->flags); | ||
150 | |||
151 | IWL_DEBUG_FW(mvm, | ||
152 | "UMAC version: Major - 0x%x, Minor - 0x%x\n", | ||
153 | palive2->umac_major, palive2->umac_minor); | ||
154 | } | ||
125 | 155 | ||
126 | return true; | 156 | return true; |
127 | } | 157 | } |
@@ -292,7 +322,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
292 | } | 322 | } |
293 | 323 | ||
294 | /* Send TX valid antennas before triggering calibrations */ | 324 | /* Send TX valid antennas before triggering calibrations */ |
295 | ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); | 325 | ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); |
296 | if (ret) | 326 | if (ret) |
297 | goto error; | 327 | goto error; |
298 | 328 | ||
@@ -328,8 +358,6 @@ out: | |||
328 | GFP_KERNEL); | 358 | GFP_KERNEL); |
329 | if (!mvm->nvm_data) | 359 | if (!mvm->nvm_data) |
330 | return -ENOMEM; | 360 | return -ENOMEM; |
331 | mvm->nvm_data->valid_rx_ant = 1; | ||
332 | mvm->nvm_data->valid_tx_ant = 1; | ||
333 | mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels; | 361 | mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels; |
334 | mvm->nvm_data->bands[0].n_channels = 1; | 362 | mvm->nvm_data->bands[0].n_channels = 1; |
335 | mvm->nvm_data->bands[0].n_bitrates = 1; | 363 | mvm->nvm_data->bands[0].n_bitrates = 1; |
@@ -341,8 +369,6 @@ out: | |||
341 | return ret; | 369 | return ret; |
342 | } | 370 | } |
343 | 371 | ||
344 | #define UCODE_CALIB_TIMEOUT (2*HZ) | ||
345 | |||
346 | int iwl_mvm_up(struct iwl_mvm *mvm) | 372 | int iwl_mvm_up(struct iwl_mvm *mvm) |
347 | { | 373 | { |
348 | int ret, i; | 374 | int ret, i; |
@@ -394,7 +420,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
394 | if (ret) | 420 | if (ret) |
395 | IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); | 421 | IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); |
396 | 422 | ||
397 | ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); | 423 | ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); |
398 | if (ret) | 424 | if (ret) |
399 | goto error; | 425 | goto error; |
400 | 426 | ||
@@ -439,10 +465,23 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
439 | goto error; | 465 | goto error; |
440 | } | 466 | } |
441 | 467 | ||
442 | ret = iwl_mvm_power_update_device_mode(mvm); | 468 | /* Initialize tx backoffs to the minimal possible */ |
469 | iwl_mvm_tt_tx_backoff(mvm, 0); | ||
470 | |||
471 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) { | ||
472 | ret = iwl_power_legacy_set_cam_mode(mvm); | ||
473 | if (ret) | ||
474 | goto error; | ||
475 | } | ||
476 | |||
477 | ret = iwl_mvm_power_update_device(mvm); | ||
443 | if (ret) | 478 | if (ret) |
444 | goto error; | 479 | goto error; |
445 | 480 | ||
481 | /* allow FW/transport low power modes if not during restart */ | ||
482 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | ||
483 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); | ||
484 | |||
446 | IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); | 485 | IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); |
447 | return 0; | 486 | return 0; |
448 | error: | 487 | error: |
@@ -466,7 +505,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) | |||
466 | goto error; | 505 | goto error; |
467 | } | 506 | } |
468 | 507 | ||
469 | ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); | 508 | ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); |
470 | if (ret) | 509 | if (ret) |
471 | goto error; | 510 | goto error; |
472 | 511 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/led.c b/drivers/net/wireless/iwlwifi/mvm/led.c index 6b4ea6bf8ffe..e3b3cf4dbd77 100644 --- a/drivers/net/wireless/iwlwifi/mvm/led.c +++ b/drivers/net/wireless/iwlwifi/mvm/led.c | |||
@@ -94,6 +94,8 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm) | |||
94 | int ret; | 94 | int ret; |
95 | 95 | ||
96 | switch (mode) { | 96 | switch (mode) { |
97 | case IWL_LED_BLINK: | ||
98 | IWL_ERR(mvm, "Blink led mode not supported, used default\n"); | ||
97 | case IWL_LED_DEFAULT: | 99 | case IWL_LED_DEFAULT: |
98 | case IWL_LED_RF_STATE: | 100 | case IWL_LED_RF_STATE: |
99 | mode = IWL_LED_RF_STATE; | 101 | mode = IWL_LED_RF_STATE; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index ba723d50939a..9ccec10bba16 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -90,6 +90,7 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, | |||
90 | { | 90 | { |
91 | struct iwl_mvm_mac_iface_iterator_data *data = _data; | 91 | struct iwl_mvm_mac_iface_iterator_data *data = _data; |
92 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 92 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
93 | u16 min_bi; | ||
93 | 94 | ||
94 | /* Skip the interface for which we are trying to assign a tsf_id */ | 95 | /* Skip the interface for which we are trying to assign a tsf_id */ |
95 | if (vif == data->vif) | 96 | if (vif == data->vif) |
@@ -114,42 +115,57 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, | |||
114 | switch (data->vif->type) { | 115 | switch (data->vif->type) { |
115 | case NL80211_IFTYPE_STATION: | 116 | case NL80211_IFTYPE_STATION: |
116 | /* | 117 | /* |
117 | * The new interface is client, so if the existing one | 118 | * The new interface is a client, so if the one we're iterating |
118 | * we're iterating is an AP, and both interfaces have the | 119 | * is an AP, and the beacon interval of the AP is a multiple or |
119 | * same beacon interval, the same TSF should be used to | 120 | * divisor of the beacon interval of the client, the same TSF |
120 | * avoid drift between the new client and existing AP, | 121 | * should be used to avoid drift between the new client and |
121 | * the existing AP will get drift updates from the new | 122 | * existing AP. The existing AP will get drift updates from the |
122 | * client context in this case | 123 | * new client context in this case. |
123 | */ | 124 | */ |
124 | if (vif->type == NL80211_IFTYPE_AP) { | 125 | if (vif->type != NL80211_IFTYPE_AP || |
125 | if (data->preferred_tsf == NUM_TSF_IDS && | 126 | data->preferred_tsf != NUM_TSF_IDS || |
126 | test_bit(mvmvif->tsf_id, data->available_tsf_ids) && | 127 | !test_bit(mvmvif->tsf_id, data->available_tsf_ids)) |
127 | (vif->bss_conf.beacon_int == | 128 | break; |
128 | data->vif->bss_conf.beacon_int)) { | 129 | |
129 | data->preferred_tsf = mvmvif->tsf_id; | 130 | min_bi = min(data->vif->bss_conf.beacon_int, |
130 | return; | 131 | vif->bss_conf.beacon_int); |
131 | } | 132 | |
133 | if (!min_bi) | ||
134 | break; | ||
135 | |||
136 | if ((data->vif->bss_conf.beacon_int - | ||
137 | vif->bss_conf.beacon_int) % min_bi == 0) { | ||
138 | data->preferred_tsf = mvmvif->tsf_id; | ||
139 | return; | ||
132 | } | 140 | } |
133 | break; | 141 | break; |
142 | |||
134 | case NL80211_IFTYPE_AP: | 143 | case NL80211_IFTYPE_AP: |
135 | /* | 144 | /* |
136 | * The new interface is AP/GO, so in case both interfaces | 145 | * The new interface is AP/GO, so if its beacon interval is a |
137 | * have the same beacon interval, it should get drift | 146 | * multiple or a divisor of the beacon interval of an existing |
138 | * updates from an existing client or use the same | 147 | * interface, it should get drift updates from an existing |
139 | * TSF as an existing GO. There's no drift between | 148 | * client or use the same TSF as an existing GO. There's no |
140 | * TSFs internally but if they used different TSFs | 149 | * drift between TSFs internally but if they used different |
141 | * then a new client MAC could update one of them | 150 | * TSFs then a new client MAC could update one of them and |
142 | * and cause drift that way. | 151 | * cause drift that way. |
143 | */ | 152 | */ |
144 | if (vif->type == NL80211_IFTYPE_STATION || | 153 | if ((vif->type != NL80211_IFTYPE_AP && |
145 | vif->type == NL80211_IFTYPE_AP) { | 154 | vif->type != NL80211_IFTYPE_STATION) || |
146 | if (data->preferred_tsf == NUM_TSF_IDS && | 155 | data->preferred_tsf != NUM_TSF_IDS || |
147 | test_bit(mvmvif->tsf_id, data->available_tsf_ids) && | 156 | !test_bit(mvmvif->tsf_id, data->available_tsf_ids)) |
148 | (vif->bss_conf.beacon_int == | 157 | break; |
149 | data->vif->bss_conf.beacon_int)) { | 158 | |
150 | data->preferred_tsf = mvmvif->tsf_id; | 159 | min_bi = min(data->vif->bss_conf.beacon_int, |
151 | return; | 160 | vif->bss_conf.beacon_int); |
152 | } | 161 | |
162 | if (!min_bi) | ||
163 | break; | ||
164 | |||
165 | if ((data->vif->bss_conf.beacon_int - | ||
166 | vif->bss_conf.beacon_int) % min_bi == 0) { | ||
167 | data->preferred_tsf = mvmvif->tsf_id; | ||
168 | return; | ||
153 | } | 169 | } |
154 | break; | 170 | break; |
155 | default: | 171 | default: |
@@ -936,7 +952,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, | |||
936 | TX_CMD_FLG_TSF); | 952 | TX_CMD_FLG_TSF); |
937 | 953 | ||
938 | mvm->mgmt_last_antenna_idx = | 954 | mvm->mgmt_last_antenna_idx = |
939 | iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw), | 955 | iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, |
940 | mvm->mgmt_last_antenna_idx); | 956 | mvm->mgmt_last_antenna_idx); |
941 | 957 | ||
942 | beacon_cmd.tx.rate_n_flags = | 958 | beacon_cmd.tx.rate_n_flags = |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index c35b8661b395..4dd9ff43b8b6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -66,7 +66,9 @@ | |||
66 | #include <linux/netdevice.h> | 66 | #include <linux/netdevice.h> |
67 | #include <linux/etherdevice.h> | 67 | #include <linux/etherdevice.h> |
68 | #include <linux/ip.h> | 68 | #include <linux/ip.h> |
69 | #include <linux/if_arp.h> | ||
69 | #include <net/mac80211.h> | 70 | #include <net/mac80211.h> |
71 | #include <net/ieee80211_radiotap.h> | ||
70 | #include <net/tcp.h> | 72 | #include <net/tcp.h> |
71 | 73 | ||
72 | #include "iwl-op-mode.h" | 74 | #include "iwl-op-mode.h" |
@@ -128,6 +130,117 @@ static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = { | |||
128 | }; | 130 | }; |
129 | #endif | 131 | #endif |
130 | 132 | ||
133 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | ||
134 | /* | ||
135 | * Use the reserved field to indicate magic values. | ||
136 | * these values will only be used internally by the driver, | ||
137 | * and won't make it to the fw (reserved will be 0). | ||
138 | * BC_FILTER_MAGIC_IP - configure the val of this attribute to | ||
139 | * be the vif's ip address. in case there is not a single | ||
140 | * ip address (0, or more than 1), this attribute will | ||
141 | * be skipped. | ||
142 | * BC_FILTER_MAGIC_MAC - set the val of this attribute to | ||
143 | * the LSB bytes of the vif's mac address | ||
144 | */ | ||
145 | enum { | ||
146 | BC_FILTER_MAGIC_NONE = 0, | ||
147 | BC_FILTER_MAGIC_IP, | ||
148 | BC_FILTER_MAGIC_MAC, | ||
149 | }; | ||
150 | |||
151 | static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = { | ||
152 | { | ||
153 | /* arp */ | ||
154 | .discard = 0, | ||
155 | .frame_type = BCAST_FILTER_FRAME_TYPE_ALL, | ||
156 | .attrs = { | ||
157 | { | ||
158 | /* frame type - arp, hw type - ethernet */ | ||
159 | .offset_type = | ||
160 | BCAST_FILTER_OFFSET_PAYLOAD_START, | ||
161 | .offset = sizeof(rfc1042_header), | ||
162 | .val = cpu_to_be32(0x08060001), | ||
163 | .mask = cpu_to_be32(0xffffffff), | ||
164 | }, | ||
165 | { | ||
166 | /* arp dest ip */ | ||
167 | .offset_type = | ||
168 | BCAST_FILTER_OFFSET_PAYLOAD_START, | ||
169 | .offset = sizeof(rfc1042_header) + 2 + | ||
170 | sizeof(struct arphdr) + | ||
171 | ETH_ALEN + sizeof(__be32) + | ||
172 | ETH_ALEN, | ||
173 | .mask = cpu_to_be32(0xffffffff), | ||
174 | /* mark it as special field */ | ||
175 | .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_IP), | ||
176 | }, | ||
177 | }, | ||
178 | }, | ||
179 | { | ||
180 | /* dhcp offer bcast */ | ||
181 | .discard = 0, | ||
182 | .frame_type = BCAST_FILTER_FRAME_TYPE_IPV4, | ||
183 | .attrs = { | ||
184 | { | ||
185 | /* udp dest port - 68 (bootp client)*/ | ||
186 | .offset_type = BCAST_FILTER_OFFSET_IP_END, | ||
187 | .offset = offsetof(struct udphdr, dest), | ||
188 | .val = cpu_to_be32(0x00440000), | ||
189 | .mask = cpu_to_be32(0xffff0000), | ||
190 | }, | ||
191 | { | ||
192 | /* dhcp - lsb bytes of client hw address */ | ||
193 | .offset_type = BCAST_FILTER_OFFSET_IP_END, | ||
194 | .offset = 38, | ||
195 | .mask = cpu_to_be32(0xffffffff), | ||
196 | /* mark it as special field */ | ||
197 | .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_MAC), | ||
198 | }, | ||
199 | }, | ||
200 | }, | ||
201 | /* last filter must be empty */ | ||
202 | {}, | ||
203 | }; | ||
204 | #endif | ||
205 | |||
206 | void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) | ||
207 | { | ||
208 | if (!iwl_mvm_is_d0i3_supported(mvm)) | ||
209 | return; | ||
210 | |||
211 | IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type); | ||
212 | WARN_ON(test_and_set_bit(ref_type, mvm->ref_bitmap)); | ||
213 | iwl_trans_ref(mvm->trans); | ||
214 | } | ||
215 | |||
216 | void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) | ||
217 | { | ||
218 | if (!iwl_mvm_is_d0i3_supported(mvm)) | ||
219 | return; | ||
220 | |||
221 | IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type); | ||
222 | WARN_ON(!test_and_clear_bit(ref_type, mvm->ref_bitmap)); | ||
223 | iwl_trans_unref(mvm->trans); | ||
224 | } | ||
225 | |||
226 | static void | ||
227 | iwl_mvm_unref_all_except(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref) | ||
228 | { | ||
229 | int i; | ||
230 | |||
231 | if (!iwl_mvm_is_d0i3_supported(mvm)) | ||
232 | return; | ||
233 | |||
234 | for_each_set_bit(i, mvm->ref_bitmap, IWL_MVM_REF_COUNT) { | ||
235 | if (ref == i) | ||
236 | continue; | ||
237 | |||
238 | IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d\n", i); | ||
239 | clear_bit(i, mvm->ref_bitmap); | ||
240 | iwl_trans_unref(mvm->trans); | ||
241 | } | ||
242 | } | ||
243 | |||
131 | static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) | 244 | static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) |
132 | { | 245 | { |
133 | int i; | 246 | int i; |
@@ -168,6 +281,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
168 | 281 | ||
169 | hw->queues = mvm->first_agg_queue; | 282 | hw->queues = mvm->first_agg_queue; |
170 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; | 283 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; |
284 | hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | | ||
285 | IEEE80211_RADIOTAP_MCS_HAVE_STBC; | ||
286 | hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC; | ||
171 | hw->rate_control_algorithm = "iwl-mvm-rs"; | 287 | hw->rate_control_algorithm = "iwl-mvm-rs"; |
172 | 288 | ||
173 | /* | 289 | /* |
@@ -179,7 +295,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
179 | !iwlwifi_mod_params.sw_crypto) | 295 | !iwlwifi_mod_params.sw_crypto) |
180 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; | 296 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; |
181 | 297 | ||
182 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT) { | 298 | if (0 && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT) { |
183 | hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; | 299 | hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; |
184 | hw->uapsd_queues = IWL_UAPSD_AC_INFO; | 300 | hw->uapsd_queues = IWL_UAPSD_AC_INFO; |
185 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; | 301 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; |
@@ -203,6 +319,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
203 | hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | | 319 | hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | |
204 | REGULATORY_DISABLE_BEACON_HINTS; | 320 | REGULATORY_DISABLE_BEACON_HINTS; |
205 | 321 | ||
322 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) | ||
323 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; | ||
324 | |||
206 | hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; | 325 | hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; |
207 | hw->wiphy->n_iface_combinations = | 326 | hw->wiphy->n_iface_combinations = |
208 | ARRAY_SIZE(iwl_mvm_iface_combinations); | 327 | ARRAY_SIZE(iwl_mvm_iface_combinations); |
@@ -246,7 +365,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
246 | else | 365 | else |
247 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | 366 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; |
248 | 367 | ||
249 | if (0 && mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) { | 368 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) { |
250 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | 369 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; |
251 | hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; | 370 | hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX; |
252 | hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; | 371 | hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES; |
@@ -256,8 +375,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
256 | } | 375 | } |
257 | 376 | ||
258 | hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | | 377 | hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | |
259 | NL80211_FEATURE_P2P_GO_OPPPS | | 378 | NL80211_FEATURE_P2P_GO_OPPPS; |
260 | NL80211_FEATURE_LOW_PRIORITY_SCAN; | ||
261 | 379 | ||
262 | mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | 380 | mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; |
263 | 381 | ||
@@ -289,6 +407,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
289 | } | 407 | } |
290 | #endif | 408 | #endif |
291 | 409 | ||
410 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | ||
411 | /* assign default bcast filtering configuration */ | ||
412 | mvm->bcast_filters = iwl_mvm_default_bcast_filters; | ||
413 | #endif | ||
414 | |||
292 | ret = iwl_mvm_leds_init(mvm); | 415 | ret = iwl_mvm_leds_init(mvm); |
293 | if (ret) | 416 | if (ret) |
294 | return ret; | 417 | return ret; |
@@ -300,11 +423,55 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
300 | return ret; | 423 | return ret; |
301 | } | 424 | } |
302 | 425 | ||
426 | static bool iwl_mvm_defer_tx(struct iwl_mvm *mvm, | ||
427 | struct ieee80211_sta *sta, | ||
428 | struct sk_buff *skb) | ||
429 | { | ||
430 | struct iwl_mvm_sta *mvmsta; | ||
431 | bool defer = false; | ||
432 | |||
433 | /* | ||
434 | * double check the IN_D0I3 flag both before and after | ||
435 | * taking the spinlock, in order to prevent taking | ||
436 | * the spinlock when not needed. | ||
437 | */ | ||
438 | if (likely(!test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status))) | ||
439 | return false; | ||
440 | |||
441 | spin_lock(&mvm->d0i3_tx_lock); | ||
442 | /* | ||
443 | * testing the flag again ensures the skb dequeue | ||
444 | * loop (on d0i3 exit) hasn't run yet. | ||
445 | */ | ||
446 | if (!test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status)) | ||
447 | goto out; | ||
448 | |||
449 | mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
450 | if (mvmsta->sta_id == IWL_MVM_STATION_COUNT || | ||
451 | mvmsta->sta_id != mvm->d0i3_ap_sta_id) | ||
452 | goto out; | ||
453 | |||
454 | __skb_queue_tail(&mvm->d0i3_tx, skb); | ||
455 | ieee80211_stop_queues(mvm->hw); | ||
456 | |||
457 | /* trigger wakeup */ | ||
458 | iwl_mvm_ref(mvm, IWL_MVM_REF_TX); | ||
459 | iwl_mvm_unref(mvm, IWL_MVM_REF_TX); | ||
460 | |||
461 | defer = true; | ||
462 | out: | ||
463 | spin_unlock(&mvm->d0i3_tx_lock); | ||
464 | return defer; | ||
465 | } | ||
466 | |||
303 | static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, | 467 | static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, |
304 | struct ieee80211_tx_control *control, | 468 | struct ieee80211_tx_control *control, |
305 | struct sk_buff *skb) | 469 | struct sk_buff *skb) |
306 | { | 470 | { |
307 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 471 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
472 | struct ieee80211_sta *sta = control->sta; | ||
473 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
474 | struct ieee80211_hdr *hdr = (void *)skb->data; | ||
308 | 475 | ||
309 | if (iwl_mvm_is_radio_killed(mvm)) { | 476 | if (iwl_mvm_is_radio_killed(mvm)) { |
310 | IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n"); | 477 | IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n"); |
@@ -315,8 +482,18 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, | |||
315 | !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) | 482 | !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) |
316 | goto drop; | 483 | goto drop; |
317 | 484 | ||
318 | if (control->sta) { | 485 | /* treat non-bufferable MMPDUs as broadcast if sta is sleeping */ |
319 | if (iwl_mvm_tx_skb(mvm, skb, control->sta)) | 486 | if (unlikely(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER && |
487 | ieee80211_is_mgmt(hdr->frame_control) && | ||
488 | !ieee80211_is_deauth(hdr->frame_control) && | ||
489 | !ieee80211_is_disassoc(hdr->frame_control) && | ||
490 | !ieee80211_is_action(hdr->frame_control))) | ||
491 | sta = NULL; | ||
492 | |||
493 | if (sta) { | ||
494 | if (iwl_mvm_defer_tx(mvm, sta, skb)) | ||
495 | return; | ||
496 | if (iwl_mvm_tx_skb(mvm, skb, sta)) | ||
320 | goto drop; | 497 | goto drop; |
321 | return; | 498 | return; |
322 | } | 499 | } |
@@ -354,6 +531,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, | |||
354 | { | 531 | { |
355 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 532 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
356 | int ret; | 533 | int ret; |
534 | bool tx_agg_ref = false; | ||
357 | 535 | ||
358 | IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n", | 536 | IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n", |
359 | sta->addr, tid, action); | 537 | sta->addr, tid, action); |
@@ -361,6 +539,23 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, | |||
361 | if (!(mvm->nvm_data->sku_cap_11n_enable)) | 539 | if (!(mvm->nvm_data->sku_cap_11n_enable)) |
362 | return -EACCES; | 540 | return -EACCES; |
363 | 541 | ||
542 | /* return from D0i3 before starting a new Tx aggregation */ | ||
543 | if (action == IEEE80211_AMPDU_TX_START) { | ||
544 | iwl_mvm_ref(mvm, IWL_MVM_REF_TX_AGG); | ||
545 | tx_agg_ref = true; | ||
546 | |||
547 | /* | ||
548 | * wait synchronously until D0i3 exit to get the correct | ||
549 | * sequence number for the tid | ||
550 | */ | ||
551 | if (!wait_event_timeout(mvm->d0i3_exit_waitq, | ||
552 | !test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status), HZ)) { | ||
553 | WARN_ON_ONCE(1); | ||
554 | iwl_mvm_unref(mvm, IWL_MVM_REF_TX_AGG); | ||
555 | return -EIO; | ||
556 | } | ||
557 | } | ||
558 | |||
364 | mutex_lock(&mvm->mutex); | 559 | mutex_lock(&mvm->mutex); |
365 | 560 | ||
366 | switch (action) { | 561 | switch (action) { |
@@ -398,6 +593,13 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, | |||
398 | } | 593 | } |
399 | mutex_unlock(&mvm->mutex); | 594 | mutex_unlock(&mvm->mutex); |
400 | 595 | ||
596 | /* | ||
597 | * If the tid is marked as started, we won't use it for offloaded | ||
598 | * traffic on the next D0i3 entry. It's safe to unref. | ||
599 | */ | ||
600 | if (tx_agg_ref) | ||
601 | iwl_mvm_unref(mvm, IWL_MVM_REF_TX_AGG); | ||
602 | |||
401 | return ret; | 603 | return ret; |
402 | } | 604 | } |
403 | 605 | ||
@@ -422,6 +624,15 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, | |||
422 | 624 | ||
423 | static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | 625 | static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) |
424 | { | 626 | { |
627 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
628 | static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL }; | ||
629 | |||
630 | iwl_mvm_fw_error_dump(mvm); | ||
631 | |||
632 | /* notify the userspace about the error we had */ | ||
633 | kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env); | ||
634 | #endif | ||
635 | |||
425 | iwl_trans_stop_device(mvm->trans); | 636 | iwl_trans_stop_device(mvm->trans); |
426 | 637 | ||
427 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 638 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
@@ -434,6 +645,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | |||
434 | iwl_mvm_cleanup_iterator, mvm); | 645 | iwl_mvm_cleanup_iterator, mvm); |
435 | 646 | ||
436 | mvm->p2p_device_vif = NULL; | 647 | mvm->p2p_device_vif = NULL; |
648 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | ||
437 | 649 | ||
438 | iwl_mvm_reset_phy_ctxts(mvm); | 650 | iwl_mvm_reset_phy_ctxts(mvm); |
439 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); | 651 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); |
@@ -441,6 +653,10 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | |||
441 | 653 | ||
442 | ieee80211_wake_queues(mvm->hw); | 654 | ieee80211_wake_queues(mvm->hw); |
443 | 655 | ||
656 | /* cleanup all stale references (scan, roc), but keep the | ||
657 | * ucode_down ref until reconfig is complete */ | ||
658 | iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN); | ||
659 | |||
444 | mvm->vif_count = 0; | 660 | mvm->vif_count = 0; |
445 | mvm->rx_ba_sessions = 0; | 661 | mvm->rx_ba_sessions = 0; |
446 | } | 662 | } |
@@ -470,11 +686,15 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) | |||
470 | mutex_lock(&mvm->mutex); | 686 | mutex_lock(&mvm->mutex); |
471 | 687 | ||
472 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | 688 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); |
689 | iwl_mvm_d0i3_enable_tx(mvm, NULL); | ||
473 | ret = iwl_mvm_update_quotas(mvm, NULL); | 690 | ret = iwl_mvm_update_quotas(mvm, NULL); |
474 | if (ret) | 691 | if (ret) |
475 | IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", | 692 | IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", |
476 | ret); | 693 | ret); |
477 | 694 | ||
695 | /* allow transport/FW low power modes */ | ||
696 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); | ||
697 | |||
478 | mutex_unlock(&mvm->mutex); | 698 | mutex_unlock(&mvm->mutex); |
479 | } | 699 | } |
480 | 700 | ||
@@ -482,9 +702,14 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) | |||
482 | { | 702 | { |
483 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 703 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
484 | 704 | ||
705 | flush_work(&mvm->d0i3_exit_work); | ||
485 | flush_work(&mvm->async_handlers_wk); | 706 | flush_work(&mvm->async_handlers_wk); |
486 | 707 | ||
487 | mutex_lock(&mvm->mutex); | 708 | mutex_lock(&mvm->mutex); |
709 | |||
710 | /* disallow low power states when the FW is down */ | ||
711 | iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); | ||
712 | |||
488 | /* async_handlers_wk is now blocked */ | 713 | /* async_handlers_wk is now blocked */ |
489 | 714 | ||
490 | /* | 715 | /* |
@@ -510,14 +735,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) | |||
510 | cancel_work_sync(&mvm->async_handlers_wk); | 735 | cancel_work_sync(&mvm->async_handlers_wk); |
511 | } | 736 | } |
512 | 737 | ||
513 | static void iwl_mvm_power_update_iterator(void *data, u8 *mac, | ||
514 | struct ieee80211_vif *vif) | ||
515 | { | ||
516 | struct iwl_mvm *mvm = data; | ||
517 | |||
518 | iwl_mvm_power_update_mode(mvm, vif); | ||
519 | } | ||
520 | |||
521 | static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm) | 738 | static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm) |
522 | { | 739 | { |
523 | u16 i; | 740 | u16 i; |
@@ -585,7 +802,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
585 | vif->type == NL80211_IFTYPE_ADHOC) { | 802 | vif->type == NL80211_IFTYPE_ADHOC) { |
586 | u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); | 803 | u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); |
587 | ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, | 804 | ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, |
588 | qmask); | 805 | qmask, |
806 | ieee80211_vif_type_p2p(vif)); | ||
589 | if (ret) { | 807 | if (ret) { |
590 | IWL_ERR(mvm, "Failed to allocate bcast sta\n"); | 808 | IWL_ERR(mvm, "Failed to allocate bcast sta\n"); |
591 | goto out_release; | 809 | goto out_release; |
@@ -599,10 +817,12 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
599 | if (ret) | 817 | if (ret) |
600 | goto out_release; | 818 | goto out_release; |
601 | 819 | ||
602 | iwl_mvm_power_disable(mvm, vif); | 820 | ret = iwl_mvm_power_update_mac(mvm, vif); |
821 | if (ret) | ||
822 | goto out_release; | ||
603 | 823 | ||
604 | /* beacon filtering */ | 824 | /* beacon filtering */ |
605 | ret = iwl_mvm_disable_beacon_filter(mvm, vif); | 825 | ret = iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC); |
606 | if (ret) | 826 | if (ret) |
607 | goto out_remove_mac; | 827 | goto out_remove_mac; |
608 | 828 | ||
@@ -661,11 +881,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
661 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) | 881 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) |
662 | mvm->vif_count--; | 882 | mvm->vif_count--; |
663 | 883 | ||
664 | /* TODO: remove this when legacy PM will be discarded */ | ||
665 | ieee80211_iterate_active_interfaces( | ||
666 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
667 | iwl_mvm_power_update_iterator, mvm); | ||
668 | |||
669 | iwl_mvm_mac_ctxt_release(mvm, vif); | 884 | iwl_mvm_mac_ctxt_release(mvm, vif); |
670 | out_unlock: | 885 | out_unlock: |
671 | mutex_unlock(&mvm->mutex); | 886 | mutex_unlock(&mvm->mutex); |
@@ -754,11 +969,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | |||
754 | if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE) | 969 | if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE) |
755 | mvm->vif_count--; | 970 | mvm->vif_count--; |
756 | 971 | ||
757 | /* TODO: remove this when legacy PM will be discarded */ | 972 | iwl_mvm_power_update_mac(mvm, vif); |
758 | ieee80211_iterate_active_interfaces( | ||
759 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
760 | iwl_mvm_power_update_iterator, mvm); | ||
761 | |||
762 | iwl_mvm_mac_ctxt_remove(mvm, vif); | 973 | iwl_mvm_mac_ctxt_remove(mvm, vif); |
763 | 974 | ||
764 | out_release: | 975 | out_release: |
@@ -876,6 +1087,156 @@ out: | |||
876 | *total_flags = 0; | 1087 | *total_flags = 0; |
877 | } | 1088 | } |
878 | 1089 | ||
1090 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | ||
1091 | struct iwl_bcast_iter_data { | ||
1092 | struct iwl_mvm *mvm; | ||
1093 | struct iwl_bcast_filter_cmd *cmd; | ||
1094 | u8 current_filter; | ||
1095 | }; | ||
1096 | |||
1097 | static void | ||
1098 | iwl_mvm_set_bcast_filter(struct ieee80211_vif *vif, | ||
1099 | const struct iwl_fw_bcast_filter *in_filter, | ||
1100 | struct iwl_fw_bcast_filter *out_filter) | ||
1101 | { | ||
1102 | struct iwl_fw_bcast_filter_attr *attr; | ||
1103 | int i; | ||
1104 | |||
1105 | memcpy(out_filter, in_filter, sizeof(*out_filter)); | ||
1106 | |||
1107 | for (i = 0; i < ARRAY_SIZE(out_filter->attrs); i++) { | ||
1108 | attr = &out_filter->attrs[i]; | ||
1109 | |||
1110 | if (!attr->mask) | ||
1111 | break; | ||
1112 | |||
1113 | switch (attr->reserved1) { | ||
1114 | case cpu_to_le16(BC_FILTER_MAGIC_IP): | ||
1115 | if (vif->bss_conf.arp_addr_cnt != 1) { | ||
1116 | attr->mask = 0; | ||
1117 | continue; | ||
1118 | } | ||
1119 | |||
1120 | attr->val = vif->bss_conf.arp_addr_list[0]; | ||
1121 | break; | ||
1122 | case cpu_to_le16(BC_FILTER_MAGIC_MAC): | ||
1123 | attr->val = *(__be32 *)&vif->addr[2]; | ||
1124 | break; | ||
1125 | default: | ||
1126 | break; | ||
1127 | } | ||
1128 | attr->reserved1 = 0; | ||
1129 | out_filter->num_attrs++; | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | static void iwl_mvm_bcast_filter_iterator(void *_data, u8 *mac, | ||
1134 | struct ieee80211_vif *vif) | ||
1135 | { | ||
1136 | struct iwl_bcast_iter_data *data = _data; | ||
1137 | struct iwl_mvm *mvm = data->mvm; | ||
1138 | struct iwl_bcast_filter_cmd *cmd = data->cmd; | ||
1139 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1140 | struct iwl_fw_bcast_mac *bcast_mac; | ||
1141 | int i; | ||
1142 | |||
1143 | if (WARN_ON(mvmvif->id >= ARRAY_SIZE(cmd->macs))) | ||
1144 | return; | ||
1145 | |||
1146 | bcast_mac = &cmd->macs[mvmvif->id]; | ||
1147 | |||
1148 | /* enable filtering only for associated stations */ | ||
1149 | if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) | ||
1150 | return; | ||
1151 | |||
1152 | bcast_mac->default_discard = 1; | ||
1153 | |||
1154 | /* copy all configured filters */ | ||
1155 | for (i = 0; mvm->bcast_filters[i].attrs[0].mask; i++) { | ||
1156 | /* | ||
1157 | * Make sure we don't exceed our filters limit. | ||
1158 | * if there is still a valid filter to be configured, | ||
1159 | * be on the safe side and just allow bcast for this mac. | ||
1160 | */ | ||
1161 | if (WARN_ON_ONCE(data->current_filter >= | ||
1162 | ARRAY_SIZE(cmd->filters))) { | ||
1163 | bcast_mac->default_discard = 0; | ||
1164 | bcast_mac->attached_filters = 0; | ||
1165 | break; | ||
1166 | } | ||
1167 | |||
1168 | iwl_mvm_set_bcast_filter(vif, | ||
1169 | &mvm->bcast_filters[i], | ||
1170 | &cmd->filters[data->current_filter]); | ||
1171 | |||
1172 | /* skip current filter if it contains no attributes */ | ||
1173 | if (!cmd->filters[data->current_filter].num_attrs) | ||
1174 | continue; | ||
1175 | |||
1176 | /* attach the filter to current mac */ | ||
1177 | bcast_mac->attached_filters |= | ||
1178 | cpu_to_le16(BIT(data->current_filter)); | ||
1179 | |||
1180 | data->current_filter++; | ||
1181 | } | ||
1182 | } | ||
1183 | |||
1184 | bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, | ||
1185 | struct iwl_bcast_filter_cmd *cmd) | ||
1186 | { | ||
1187 | struct iwl_bcast_iter_data iter_data = { | ||
1188 | .mvm = mvm, | ||
1189 | .cmd = cmd, | ||
1190 | }; | ||
1191 | |||
1192 | memset(cmd, 0, sizeof(*cmd)); | ||
1193 | cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters); | ||
1194 | cmd->max_macs = ARRAY_SIZE(cmd->macs); | ||
1195 | |||
1196 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1197 | /* use debugfs filters/macs if override is configured */ | ||
1198 | if (mvm->dbgfs_bcast_filtering.override) { | ||
1199 | memcpy(cmd->filters, &mvm->dbgfs_bcast_filtering.cmd.filters, | ||
1200 | sizeof(cmd->filters)); | ||
1201 | memcpy(cmd->macs, &mvm->dbgfs_bcast_filtering.cmd.macs, | ||
1202 | sizeof(cmd->macs)); | ||
1203 | return true; | ||
1204 | } | ||
1205 | #endif | ||
1206 | |||
1207 | /* if no filters are configured, do nothing */ | ||
1208 | if (!mvm->bcast_filters) | ||
1209 | return false; | ||
1210 | |||
1211 | /* configure and attach these filters for each associated sta vif */ | ||
1212 | ieee80211_iterate_active_interfaces( | ||
1213 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
1214 | iwl_mvm_bcast_filter_iterator, &iter_data); | ||
1215 | |||
1216 | return true; | ||
1217 | } | ||
1218 | static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, | ||
1219 | struct ieee80211_vif *vif) | ||
1220 | { | ||
1221 | struct iwl_bcast_filter_cmd cmd; | ||
1222 | |||
1223 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING)) | ||
1224 | return 0; | ||
1225 | |||
1226 | if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) | ||
1227 | return 0; | ||
1228 | |||
1229 | return iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC, | ||
1230 | sizeof(cmd), &cmd); | ||
1231 | } | ||
1232 | #else | ||
1233 | static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, | ||
1234 | struct ieee80211_vif *vif) | ||
1235 | { | ||
1236 | return 0; | ||
1237 | } | ||
1238 | #endif | ||
1239 | |||
879 | static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | 1240 | static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, |
880 | struct ieee80211_vif *vif, | 1241 | struct ieee80211_vif *vif, |
881 | struct ieee80211_bss_conf *bss_conf, | 1242 | struct ieee80211_bss_conf *bss_conf, |
@@ -928,6 +1289,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
928 | 1289 | ||
929 | iwl_mvm_sf_update(mvm, vif, false); | 1290 | iwl_mvm_sf_update(mvm, vif, false); |
930 | iwl_mvm_power_vif_assoc(mvm, vif); | 1291 | iwl_mvm_power_vif_assoc(mvm, vif); |
1292 | if (vif->p2p) | ||
1293 | iwl_mvm_ref(mvm, IWL_MVM_REF_P2P_CLIENT); | ||
931 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | 1294 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { |
932 | /* | 1295 | /* |
933 | * If update fails - SF might be running in associated | 1296 | * If update fails - SF might be running in associated |
@@ -940,27 +1303,25 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
940 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); | 1303 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); |
941 | if (ret) | 1304 | if (ret) |
942 | IWL_ERR(mvm, "failed to remove AP station\n"); | 1305 | IWL_ERR(mvm, "failed to remove AP station\n"); |
1306 | |||
1307 | if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) | ||
1308 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | ||
943 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | 1309 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; |
944 | /* remove quota for this interface */ | 1310 | /* remove quota for this interface */ |
945 | ret = iwl_mvm_update_quotas(mvm, NULL); | 1311 | ret = iwl_mvm_update_quotas(mvm, NULL); |
946 | if (ret) | 1312 | if (ret) |
947 | IWL_ERR(mvm, "failed to update quotas\n"); | 1313 | IWL_ERR(mvm, "failed to update quotas\n"); |
1314 | |||
1315 | if (vif->p2p) | ||
1316 | iwl_mvm_unref(mvm, IWL_MVM_REF_P2P_CLIENT); | ||
948 | } | 1317 | } |
949 | 1318 | ||
950 | iwl_mvm_recalc_multicast(mvm); | 1319 | iwl_mvm_recalc_multicast(mvm); |
1320 | iwl_mvm_configure_bcast_filter(mvm, vif); | ||
951 | 1321 | ||
952 | /* reset rssi values */ | 1322 | /* reset rssi values */ |
953 | mvmvif->bf_data.ave_beacon_signal = 0; | 1323 | mvmvif->bf_data.ave_beacon_signal = 0; |
954 | 1324 | ||
955 | if (!(mvm->fw->ucode_capa.flags & | ||
956 | IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) { | ||
957 | /* Workaround for FW bug, otherwise FW disables device | ||
958 | * power save upon disassociation | ||
959 | */ | ||
960 | ret = iwl_mvm_power_update_mode(mvm, vif); | ||
961 | if (ret) | ||
962 | IWL_ERR(mvm, "failed to update power mode\n"); | ||
963 | } | ||
964 | iwl_mvm_bt_coex_vif_change(mvm); | 1325 | iwl_mvm_bt_coex_vif_change(mvm); |
965 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, | 1326 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, |
966 | IEEE80211_SMPS_AUTOMATIC); | 1327 | IEEE80211_SMPS_AUTOMATIC); |
@@ -971,9 +1332,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
971 | */ | 1332 | */ |
972 | iwl_mvm_remove_time_event(mvm, mvmvif, | 1333 | iwl_mvm_remove_time_event(mvm, mvmvif, |
973 | &mvmvif->time_event_data); | 1334 | &mvmvif->time_event_data); |
1335 | WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, CMD_SYNC)); | ||
974 | } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | | 1336 | } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | |
975 | BSS_CHANGED_QOS)) { | 1337 | BSS_CHANGED_QOS)) { |
976 | ret = iwl_mvm_power_update_mode(mvm, vif); | 1338 | ret = iwl_mvm_power_update_mac(mvm, vif); |
977 | if (ret) | 1339 | if (ret) |
978 | IWL_ERR(mvm, "failed to update power mode\n"); | 1340 | IWL_ERR(mvm, "failed to update power mode\n"); |
979 | } | 1341 | } |
@@ -987,10 +1349,15 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
987 | IWL_DEBUG_MAC80211(mvm, "cqm info_changed"); | 1349 | IWL_DEBUG_MAC80211(mvm, "cqm info_changed"); |
988 | /* reset cqm events tracking */ | 1350 | /* reset cqm events tracking */ |
989 | mvmvif->bf_data.last_cqm_event = 0; | 1351 | mvmvif->bf_data.last_cqm_event = 0; |
990 | ret = iwl_mvm_update_beacon_filter(mvm, vif); | 1352 | ret = iwl_mvm_update_beacon_filter(mvm, vif, false, CMD_SYNC); |
991 | if (ret) | 1353 | if (ret) |
992 | IWL_ERR(mvm, "failed to update CQM thresholds\n"); | 1354 | IWL_ERR(mvm, "failed to update CQM thresholds\n"); |
993 | } | 1355 | } |
1356 | |||
1357 | if (changes & BSS_CHANGED_ARP_FILTER) { | ||
1358 | IWL_DEBUG_MAC80211(mvm, "arp filter changed"); | ||
1359 | iwl_mvm_configure_bcast_filter(mvm, vif); | ||
1360 | } | ||
994 | } | 1361 | } |
995 | 1362 | ||
996 | static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | 1363 | static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, |
@@ -1024,8 +1391,6 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | |||
1024 | if (ret) | 1391 | if (ret) |
1025 | goto out_remove; | 1392 | goto out_remove; |
1026 | 1393 | ||
1027 | mvmvif->ap_ibss_active = true; | ||
1028 | |||
1029 | /* Send the bcast station. At this stage the TBTT and DTIM time events | 1394 | /* Send the bcast station. At this stage the TBTT and DTIM time events |
1030 | * are added and applied to the scheduler */ | 1395 | * are added and applied to the scheduler */ |
1031 | ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta); | 1396 | ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta); |
@@ -1036,8 +1401,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | |||
1036 | mvmvif->ap_ibss_active = true; | 1401 | mvmvif->ap_ibss_active = true; |
1037 | 1402 | ||
1038 | /* power updated needs to be done before quotas */ | 1403 | /* power updated needs to be done before quotas */ |
1039 | mvm->bound_vif_cnt++; | 1404 | iwl_mvm_power_update_mac(mvm, vif); |
1040 | iwl_mvm_power_update_binding(mvm, vif, true); | ||
1041 | 1405 | ||
1042 | ret = iwl_mvm_update_quotas(mvm, vif); | 1406 | ret = iwl_mvm_update_quotas(mvm, vif); |
1043 | if (ret) | 1407 | if (ret) |
@@ -1047,14 +1411,15 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | |||
1047 | if (vif->p2p && mvm->p2p_device_vif) | 1411 | if (vif->p2p && mvm->p2p_device_vif) |
1048 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); | 1412 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); |
1049 | 1413 | ||
1414 | iwl_mvm_ref(mvm, IWL_MVM_REF_AP_IBSS); | ||
1415 | |||
1050 | iwl_mvm_bt_coex_vif_change(mvm); | 1416 | iwl_mvm_bt_coex_vif_change(mvm); |
1051 | 1417 | ||
1052 | mutex_unlock(&mvm->mutex); | 1418 | mutex_unlock(&mvm->mutex); |
1053 | return 0; | 1419 | return 0; |
1054 | 1420 | ||
1055 | out_quota_failed: | 1421 | out_quota_failed: |
1056 | mvm->bound_vif_cnt--; | 1422 | iwl_mvm_power_update_mac(mvm, vif); |
1057 | iwl_mvm_power_update_binding(mvm, vif, false); | ||
1058 | mvmvif->ap_ibss_active = false; | 1423 | mvmvif->ap_ibss_active = false; |
1059 | iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); | 1424 | iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); |
1060 | out_unbind: | 1425 | out_unbind: |
@@ -1080,6 +1445,8 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, | |||
1080 | 1445 | ||
1081 | iwl_mvm_bt_coex_vif_change(mvm); | 1446 | iwl_mvm_bt_coex_vif_change(mvm); |
1082 | 1447 | ||
1448 | iwl_mvm_unref(mvm, IWL_MVM_REF_AP_IBSS); | ||
1449 | |||
1083 | /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ | 1450 | /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ |
1084 | if (vif->p2p && mvm->p2p_device_vif) | 1451 | if (vif->p2p && mvm->p2p_device_vif) |
1085 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); | 1452 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif); |
@@ -1088,8 +1455,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, | |||
1088 | iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); | 1455 | iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); |
1089 | iwl_mvm_binding_remove_vif(mvm, vif); | 1456 | iwl_mvm_binding_remove_vif(mvm, vif); |
1090 | 1457 | ||
1091 | mvm->bound_vif_cnt--; | 1458 | iwl_mvm_power_update_mac(mvm, vif); |
1092 | iwl_mvm_power_update_binding(mvm, vif, false); | ||
1093 | 1459 | ||
1094 | iwl_mvm_mac_ctxt_remove(mvm, vif); | 1460 | iwl_mvm_mac_ctxt_remove(mvm, vif); |
1095 | 1461 | ||
@@ -1103,26 +1469,20 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, | |||
1103 | u32 changes) | 1469 | u32 changes) |
1104 | { | 1470 | { |
1105 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1471 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1106 | enum ieee80211_bss_change ht_change = BSS_CHANGED_ERP_CTS_PROT | | ||
1107 | BSS_CHANGED_HT | | ||
1108 | BSS_CHANGED_BANDWIDTH; | ||
1109 | int ret; | ||
1110 | 1472 | ||
1111 | /* Changes will be applied when the AP/IBSS is started */ | 1473 | /* Changes will be applied when the AP/IBSS is started */ |
1112 | if (!mvmvif->ap_ibss_active) | 1474 | if (!mvmvif->ap_ibss_active) |
1113 | return; | 1475 | return; |
1114 | 1476 | ||
1115 | if (changes & ht_change) { | 1477 | if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT | |
1116 | ret = iwl_mvm_mac_ctxt_changed(mvm, vif); | 1478 | BSS_CHANGED_BANDWIDTH) && |
1117 | if (ret) | 1479 | iwl_mvm_mac_ctxt_changed(mvm, vif)) |
1118 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); | 1480 | IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); |
1119 | } | ||
1120 | 1481 | ||
1121 | /* Need to send a new beacon template to the FW */ | 1482 | /* Need to send a new beacon template to the FW */ |
1122 | if (changes & BSS_CHANGED_BEACON) { | 1483 | if (changes & BSS_CHANGED_BEACON && |
1123 | if (iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) | 1484 | iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) |
1124 | IWL_WARN(mvm, "Failed updating beacon data\n"); | 1485 | IWL_WARN(mvm, "Failed updating beacon data\n"); |
1125 | } | ||
1126 | } | 1486 | } |
1127 | 1487 | ||
1128 | static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, | 1488 | static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, |
@@ -1162,13 +1522,30 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
1162 | 1522 | ||
1163 | mutex_lock(&mvm->mutex); | 1523 | mutex_lock(&mvm->mutex); |
1164 | 1524 | ||
1165 | if (mvm->scan_status == IWL_MVM_SCAN_NONE) | 1525 | switch (mvm->scan_status) { |
1166 | ret = iwl_mvm_scan_request(mvm, vif, req); | 1526 | case IWL_MVM_SCAN_SCHED: |
1167 | else | 1527 | ret = iwl_mvm_sched_scan_stop(mvm); |
1528 | if (ret) { | ||
1529 | ret = -EBUSY; | ||
1530 | goto out; | ||
1531 | } | ||
1532 | break; | ||
1533 | case IWL_MVM_SCAN_NONE: | ||
1534 | break; | ||
1535 | default: | ||
1168 | ret = -EBUSY; | 1536 | ret = -EBUSY; |
1537 | goto out; | ||
1538 | } | ||
1169 | 1539 | ||
1170 | mutex_unlock(&mvm->mutex); | 1540 | iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); |
1171 | 1541 | ||
1542 | ret = iwl_mvm_scan_request(mvm, vif, req); | ||
1543 | if (ret) | ||
1544 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
1545 | out: | ||
1546 | mutex_unlock(&mvm->mutex); | ||
1547 | /* make sure to flush the Rx handler before the next scan arrives */ | ||
1548 | iwl_mvm_wait_for_async_handlers(mvm); | ||
1172 | return ret; | 1549 | return ret; |
1173 | } | 1550 | } |
1174 | 1551 | ||
@@ -1186,20 +1563,32 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw, | |||
1186 | 1563 | ||
1187 | static void | 1564 | static void |
1188 | iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw, | 1565 | iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw, |
1189 | struct ieee80211_sta *sta, u16 tid, | 1566 | struct ieee80211_sta *sta, u16 tids, |
1190 | int num_frames, | 1567 | int num_frames, |
1191 | enum ieee80211_frame_release_type reason, | 1568 | enum ieee80211_frame_release_type reason, |
1192 | bool more_data) | 1569 | bool more_data) |
1193 | { | 1570 | { |
1194 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1571 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1195 | 1572 | ||
1196 | /* TODO: how do we tell the fw to send frames for a specific TID */ | 1573 | /* Called when we need to transmit (a) frame(s) from mac80211 */ |
1197 | 1574 | ||
1198 | /* | 1575 | iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames, |
1199 | * The fw will send EOSP notification when the last frame will be | 1576 | tids, more_data, false); |
1200 | * transmitted. | 1577 | } |
1201 | */ | 1578 | |
1202 | iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames); | 1579 | static void |
1580 | iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw, | ||
1581 | struct ieee80211_sta *sta, u16 tids, | ||
1582 | int num_frames, | ||
1583 | enum ieee80211_frame_release_type reason, | ||
1584 | bool more_data) | ||
1585 | { | ||
1586 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1587 | |||
1588 | /* Called when we need to transmit (a) frame(s) from agg queue */ | ||
1589 | |||
1590 | iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames, | ||
1591 | tids, more_data, true); | ||
1203 | } | 1592 | } |
1204 | 1593 | ||
1205 | static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, | 1594 | static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, |
@@ -1209,11 +1598,25 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, | |||
1209 | { | 1598 | { |
1210 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1599 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1211 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | 1600 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1601 | int tid; | ||
1212 | 1602 | ||
1213 | switch (cmd) { | 1603 | switch (cmd) { |
1214 | case STA_NOTIFY_SLEEP: | 1604 | case STA_NOTIFY_SLEEP: |
1215 | if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) | 1605 | if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) |
1216 | ieee80211_sta_block_awake(hw, sta, true); | 1606 | ieee80211_sta_block_awake(hw, sta, true); |
1607 | spin_lock_bh(&mvmsta->lock); | ||
1608 | for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { | ||
1609 | struct iwl_mvm_tid_data *tid_data; | ||
1610 | |||
1611 | tid_data = &mvmsta->tid_data[tid]; | ||
1612 | if (tid_data->state != IWL_AGG_ON && | ||
1613 | tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA) | ||
1614 | continue; | ||
1615 | if (iwl_mvm_tid_queued(tid_data) == 0) | ||
1616 | continue; | ||
1617 | ieee80211_sta_set_buffered(sta, tid, true); | ||
1618 | } | ||
1619 | spin_unlock_bh(&mvmsta->lock); | ||
1217 | /* | 1620 | /* |
1218 | * The fw updates the STA to be asleep. Tx packets on the Tx | 1621 | * The fw updates the STA to be asleep. Tx packets on the Tx |
1219 | * queues to this station will not be transmitted. The fw will | 1622 | * queues to this station will not be transmitted. The fw will |
@@ -1304,12 +1707,14 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, | |||
1304 | } else if (old_state == IEEE80211_STA_ASSOC && | 1707 | } else if (old_state == IEEE80211_STA_ASSOC && |
1305 | new_state == IEEE80211_STA_AUTHORIZED) { | 1708 | new_state == IEEE80211_STA_AUTHORIZED) { |
1306 | /* enable beacon filtering */ | 1709 | /* enable beacon filtering */ |
1307 | WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif)); | 1710 | if (vif->bss_conf.dtim_period) |
1711 | WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, | ||
1712 | CMD_SYNC)); | ||
1308 | ret = 0; | 1713 | ret = 0; |
1309 | } else if (old_state == IEEE80211_STA_AUTHORIZED && | 1714 | } else if (old_state == IEEE80211_STA_AUTHORIZED && |
1310 | new_state == IEEE80211_STA_ASSOC) { | 1715 | new_state == IEEE80211_STA_ASSOC) { |
1311 | /* disable beacon filtering */ | 1716 | /* disable beacon filtering */ |
1312 | WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif)); | 1717 | WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC)); |
1313 | ret = 0; | 1718 | ret = 0; |
1314 | } else if (old_state == IEEE80211_STA_ASSOC && | 1719 | } else if (old_state == IEEE80211_STA_ASSOC && |
1315 | new_state == IEEE80211_STA_AUTH) { | 1720 | new_state == IEEE80211_STA_AUTH) { |
@@ -1401,9 +1806,26 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | |||
1401 | 1806 | ||
1402 | mutex_lock(&mvm->mutex); | 1807 | mutex_lock(&mvm->mutex); |
1403 | 1808 | ||
1404 | if (mvm->scan_status != IWL_MVM_SCAN_NONE) { | 1809 | switch (mvm->scan_status) { |
1405 | IWL_DEBUG_SCAN(mvm, | 1810 | case IWL_MVM_SCAN_OS: |
1406 | "SCHED SCAN request during internal scan - abort\n"); | 1811 | IWL_DEBUG_SCAN(mvm, "Stopping previous scan for sched_scan\n"); |
1812 | ret = iwl_mvm_cancel_scan(mvm); | ||
1813 | if (ret) { | ||
1814 | ret = -EBUSY; | ||
1815 | goto out; | ||
1816 | } | ||
1817 | |||
1818 | /* | ||
1819 | * iwl_mvm_rx_scan_complete() will be called soon but will | ||
1820 | * not reset the scan status as it won't be IWL_MVM_SCAN_OS | ||
1821 | * any more since we queue the next scan immediately (below). | ||
1822 | * We make sure it is called before the next scan starts by | ||
1823 | * flushing the async-handlers work. | ||
1824 | */ | ||
1825 | break; | ||
1826 | case IWL_MVM_SCAN_NONE: | ||
1827 | break; | ||
1828 | default: | ||
1407 | ret = -EBUSY; | 1829 | ret = -EBUSY; |
1408 | goto out; | 1830 | goto out; |
1409 | } | 1831 | } |
@@ -1425,17 +1847,23 @@ err: | |||
1425 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 1847 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
1426 | out: | 1848 | out: |
1427 | mutex_unlock(&mvm->mutex); | 1849 | mutex_unlock(&mvm->mutex); |
1850 | /* make sure to flush the Rx handler before the next scan arrives */ | ||
1851 | iwl_mvm_wait_for_async_handlers(mvm); | ||
1428 | return ret; | 1852 | return ret; |
1429 | } | 1853 | } |
1430 | 1854 | ||
1431 | static void iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, | 1855 | static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, |
1432 | struct ieee80211_vif *vif) | 1856 | struct ieee80211_vif *vif) |
1433 | { | 1857 | { |
1434 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1858 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1859 | int ret; | ||
1435 | 1860 | ||
1436 | mutex_lock(&mvm->mutex); | 1861 | mutex_lock(&mvm->mutex); |
1437 | iwl_mvm_sched_scan_stop(mvm); | 1862 | ret = iwl_mvm_sched_scan_stop(mvm); |
1438 | mutex_unlock(&mvm->mutex); | 1863 | mutex_unlock(&mvm->mutex); |
1864 | iwl_mvm_wait_for_async_handlers(mvm); | ||
1865 | |||
1866 | return ret; | ||
1439 | } | 1867 | } |
1440 | 1868 | ||
1441 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, | 1869 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, |
@@ -1773,8 +2201,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, | |||
1773 | * Power state must be updated before quotas, | 2201 | * Power state must be updated before quotas, |
1774 | * otherwise fw will complain. | 2202 | * otherwise fw will complain. |
1775 | */ | 2203 | */ |
1776 | mvm->bound_vif_cnt++; | 2204 | iwl_mvm_power_update_mac(mvm, vif); |
1777 | iwl_mvm_power_update_binding(mvm, vif, true); | ||
1778 | 2205 | ||
1779 | /* Setting the quota at this stage is only required for monitor | 2206 | /* Setting the quota at this stage is only required for monitor |
1780 | * interfaces. For the other types, the bss_info changed flow | 2207 | * interfaces. For the other types, the bss_info changed flow |
@@ -1791,8 +2218,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, | |||
1791 | 2218 | ||
1792 | out_remove_binding: | 2219 | out_remove_binding: |
1793 | iwl_mvm_binding_remove_vif(mvm, vif); | 2220 | iwl_mvm_binding_remove_vif(mvm, vif); |
1794 | mvm->bound_vif_cnt--; | 2221 | iwl_mvm_power_update_mac(mvm, vif); |
1795 | iwl_mvm_power_update_binding(mvm, vif, false); | ||
1796 | out_unlock: | 2222 | out_unlock: |
1797 | mutex_unlock(&mvm->mutex); | 2223 | mutex_unlock(&mvm->mutex); |
1798 | if (ret) | 2224 | if (ret) |
@@ -1824,8 +2250,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, | |||
1824 | } | 2250 | } |
1825 | 2251 | ||
1826 | iwl_mvm_binding_remove_vif(mvm, vif); | 2252 | iwl_mvm_binding_remove_vif(mvm, vif); |
1827 | mvm->bound_vif_cnt--; | 2253 | iwl_mvm_power_update_mac(mvm, vif); |
1828 | iwl_mvm_power_update_binding(mvm, vif, false); | ||
1829 | 2254 | ||
1830 | out_unlock: | 2255 | out_unlock: |
1831 | mvmvif->phy_ctxt = NULL; | 2256 | mvmvif->phy_ctxt = NULL; |
@@ -1892,8 +2317,9 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, | |||
1892 | return -EINVAL; | 2317 | return -EINVAL; |
1893 | 2318 | ||
1894 | if (nla_get_u32(tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE])) | 2319 | if (nla_get_u32(tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE])) |
1895 | return iwl_mvm_enable_beacon_filter(mvm, vif); | 2320 | return iwl_mvm_enable_beacon_filter(mvm, vif, |
1896 | return iwl_mvm_disable_beacon_filter(mvm, vif); | 2321 | CMD_SYNC); |
2322 | return iwl_mvm_disable_beacon_filter(mvm, vif, CMD_SYNC); | ||
1897 | } | 2323 | } |
1898 | 2324 | ||
1899 | return -EOPNOTSUPP; | 2325 | return -EOPNOTSUPP; |
@@ -1914,7 +2340,7 @@ static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, | |||
1914 | } | 2340 | } |
1915 | #endif | 2341 | #endif |
1916 | 2342 | ||
1917 | struct ieee80211_ops iwl_mvm_hw_ops = { | 2343 | const struct ieee80211_ops iwl_mvm_hw_ops = { |
1918 | .tx = iwl_mvm_mac_tx, | 2344 | .tx = iwl_mvm_mac_tx, |
1919 | .ampdu_action = iwl_mvm_mac_ampdu_action, | 2345 | .ampdu_action = iwl_mvm_mac_ampdu_action, |
1920 | .start = iwl_mvm_mac_start, | 2346 | .start = iwl_mvm_mac_start, |
@@ -1932,6 +2358,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = { | |||
1932 | .sta_state = iwl_mvm_mac_sta_state, | 2358 | .sta_state = iwl_mvm_mac_sta_state, |
1933 | .sta_notify = iwl_mvm_mac_sta_notify, | 2359 | .sta_notify = iwl_mvm_mac_sta_notify, |
1934 | .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, | 2360 | .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, |
2361 | .release_buffered_frames = iwl_mvm_mac_release_buffered_frames, | ||
1935 | .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, | 2362 | .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, |
1936 | .sta_rc_update = iwl_mvm_sta_rc_update, | 2363 | .sta_rc_update = iwl_mvm_sta_rc_update, |
1937 | .conf_tx = iwl_mvm_mac_conf_tx, | 2364 | .conf_tx = iwl_mvm_mac_conf_tx, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 2b0ba1fc3c82..d564233a65da 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -91,9 +91,7 @@ enum iwl_mvm_tx_fifo { | |||
91 | IWL_MVM_TX_FIFO_MCAST = 5, | 91 | IWL_MVM_TX_FIFO_MCAST = 5, |
92 | }; | 92 | }; |
93 | 93 | ||
94 | extern struct ieee80211_ops iwl_mvm_hw_ops; | 94 | extern const 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 | 95 | ||
98 | /** | 96 | /** |
99 | * struct iwl_mvm_mod_params - module parameters for iwlmvm | 97 | * struct iwl_mvm_mod_params - module parameters for iwlmvm |
@@ -159,20 +157,6 @@ enum iwl_power_scheme { | |||
159 | IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) | 157 | IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) |
160 | #define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2 | 158 | #define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2 |
161 | 159 | ||
162 | struct iwl_mvm_power_ops { | ||
163 | int (*power_update_mode)(struct iwl_mvm *mvm, | ||
164 | struct ieee80211_vif *vif); | ||
165 | int (*power_update_device_mode)(struct iwl_mvm *mvm); | ||
166 | int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
167 | void (*power_update_binding)(struct iwl_mvm *mvm, | ||
168 | struct ieee80211_vif *vif, bool assign); | ||
169 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
170 | int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
171 | char *buf, int bufsz); | ||
172 | #endif | ||
173 | }; | ||
174 | |||
175 | |||
176 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 160 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
177 | enum iwl_dbgfs_pm_mask { | 161 | enum iwl_dbgfs_pm_mask { |
178 | MVM_DEBUGFS_PM_KEEP_ALIVE = BIT(0), | 162 | MVM_DEBUGFS_PM_KEEP_ALIVE = BIT(0), |
@@ -239,6 +223,19 @@ enum iwl_mvm_smps_type_request { | |||
239 | NUM_IWL_MVM_SMPS_REQ, | 223 | NUM_IWL_MVM_SMPS_REQ, |
240 | }; | 224 | }; |
241 | 225 | ||
226 | enum iwl_mvm_ref_type { | ||
227 | IWL_MVM_REF_UCODE_DOWN, | ||
228 | IWL_MVM_REF_SCAN, | ||
229 | IWL_MVM_REF_ROC, | ||
230 | IWL_MVM_REF_P2P_CLIENT, | ||
231 | IWL_MVM_REF_AP_IBSS, | ||
232 | IWL_MVM_REF_USER, | ||
233 | IWL_MVM_REF_TX, | ||
234 | IWL_MVM_REF_TX_AGG, | ||
235 | |||
236 | IWL_MVM_REF_COUNT, | ||
237 | }; | ||
238 | |||
242 | /** | 239 | /** |
243 | * struct iwl_mvm_vif_bf_data - beacon filtering related data | 240 | * struct iwl_mvm_vif_bf_data - beacon filtering related data |
244 | * @bf_enabled: indicates if beacon filtering is enabled | 241 | * @bf_enabled: indicates if beacon filtering is enabled |
@@ -269,7 +266,9 @@ struct iwl_mvm_vif_bf_data { | |||
269 | * @ap_ibss_active: indicates that AP/IBSS is configured and that the interface | 266 | * @ap_ibss_active: indicates that AP/IBSS is configured and that the interface |
270 | * should get quota etc. | 267 | * should get quota etc. |
271 | * @monitor_active: indicates that monitor context is configured, and that the | 268 | * @monitor_active: indicates that monitor context is configured, and that the |
272 | * interface should get quota etc. | 269 | * interface should get quota etc. |
270 | * @low_latency: indicates that this interface is in low-latency mode | ||
271 | * (VMACLowLatencyMode) | ||
273 | * @queue_params: QoS params for this MAC | 272 | * @queue_params: QoS params for this MAC |
274 | * @bcast_sta: station used for broadcast packets. Used by the following | 273 | * @bcast_sta: station used for broadcast packets. Used by the following |
275 | * vifs: P2P_DEVICE, GO and AP. | 274 | * vifs: P2P_DEVICE, GO and AP. |
@@ -285,6 +284,7 @@ struct iwl_mvm_vif { | |||
285 | bool uploaded; | 284 | bool uploaded; |
286 | bool ap_ibss_active; | 285 | bool ap_ibss_active; |
287 | bool monitor_active; | 286 | bool monitor_active; |
287 | bool low_latency; | ||
288 | struct iwl_mvm_vif_bf_data bf_data; | 288 | struct iwl_mvm_vif_bf_data bf_data; |
289 | 289 | ||
290 | u32 ap_beacon_time; | 290 | u32 ap_beacon_time; |
@@ -319,13 +319,13 @@ struct iwl_mvm_vif { | |||
319 | 319 | ||
320 | bool seqno_valid; | 320 | bool seqno_valid; |
321 | u16 seqno; | 321 | u16 seqno; |
322 | #endif | ||
322 | 323 | ||
323 | #if IS_ENABLED(CONFIG_IPV6) | 324 | #if IS_ENABLED(CONFIG_IPV6) |
324 | /* IPv6 addresses for WoWLAN */ | 325 | /* IPv6 addresses for WoWLAN */ |
325 | struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX]; | 326 | struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX]; |
326 | int num_target_ipv6_addrs; | 327 | int num_target_ipv6_addrs; |
327 | #endif | 328 | #endif |
328 | #endif | ||
329 | 329 | ||
330 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 330 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
331 | struct iwl_mvm *mvm; | 331 | struct iwl_mvm *mvm; |
@@ -333,14 +333,13 @@ struct iwl_mvm_vif { | |||
333 | struct dentry *dbgfs_slink; | 333 | struct dentry *dbgfs_slink; |
334 | struct iwl_dbgfs_pm dbgfs_pm; | 334 | struct iwl_dbgfs_pm dbgfs_pm; |
335 | struct iwl_dbgfs_bf dbgfs_bf; | 335 | struct iwl_dbgfs_bf dbgfs_bf; |
336 | struct iwl_mac_power_cmd mac_pwr_cmd; | ||
336 | #endif | 337 | #endif |
337 | 338 | ||
338 | enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ]; | 339 | enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ]; |
339 | 340 | ||
340 | /* FW identified misbehaving AP */ | 341 | /* FW identified misbehaving AP */ |
341 | u8 uapsd_misbehaving_bssid[ETH_ALEN]; | 342 | u8 uapsd_misbehaving_bssid[ETH_ALEN]; |
342 | |||
343 | bool pm_prevented; | ||
344 | }; | 343 | }; |
345 | 344 | ||
346 | static inline struct iwl_mvm_vif * | 345 | static inline struct iwl_mvm_vif * |
@@ -349,6 +348,8 @@ iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif) | |||
349 | return (void *)vif->drv_priv; | 348 | return (void *)vif->drv_priv; |
350 | } | 349 | } |
351 | 350 | ||
351 | extern const u8 tid_to_mac80211_ac[]; | ||
352 | |||
352 | enum iwl_scan_status { | 353 | enum iwl_scan_status { |
353 | IWL_MVM_SCAN_NONE, | 354 | IWL_MVM_SCAN_NONE, |
354 | IWL_MVM_SCAN_OS, | 355 | IWL_MVM_SCAN_OS, |
@@ -415,6 +416,7 @@ struct iwl_tt_params { | |||
415 | * @ct_kill_exit: worker to exit thermal kill | 416 | * @ct_kill_exit: worker to exit thermal kill |
416 | * @dynamic_smps: Is thermal throttling enabled dynamic_smps? | 417 | * @dynamic_smps: Is thermal throttling enabled dynamic_smps? |
417 | * @tx_backoff: The current thremal throttling tx backoff in uSec. | 418 | * @tx_backoff: The current thremal throttling tx backoff in uSec. |
419 | * @min_backoff: The minimal tx backoff due to power restrictions | ||
418 | * @params: Parameters to configure the thermal throttling algorithm. | 420 | * @params: Parameters to configure the thermal throttling algorithm. |
419 | * @throttle: Is thermal throttling is active? | 421 | * @throttle: Is thermal throttling is active? |
420 | */ | 422 | */ |
@@ -422,10 +424,33 @@ struct iwl_mvm_tt_mgmt { | |||
422 | struct delayed_work ct_kill_exit; | 424 | struct delayed_work ct_kill_exit; |
423 | bool dynamic_smps; | 425 | bool dynamic_smps; |
424 | u32 tx_backoff; | 426 | u32 tx_backoff; |
427 | u32 min_backoff; | ||
425 | const struct iwl_tt_params *params; | 428 | const struct iwl_tt_params *params; |
426 | bool throttle; | 429 | bool throttle; |
427 | }; | 430 | }; |
428 | 431 | ||
432 | #define IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES 8 | ||
433 | |||
434 | struct iwl_mvm_frame_stats { | ||
435 | u32 legacy_frames; | ||
436 | u32 ht_frames; | ||
437 | u32 vht_frames; | ||
438 | u32 bw_20_frames; | ||
439 | u32 bw_40_frames; | ||
440 | u32 bw_80_frames; | ||
441 | u32 bw_160_frames; | ||
442 | u32 sgi_frames; | ||
443 | u32 ngi_frames; | ||
444 | u32 siso_frames; | ||
445 | u32 mimo2_frames; | ||
446 | u32 agg_frames; | ||
447 | u32 ampdu_count; | ||
448 | u32 success_frames; | ||
449 | u32 fail_frames; | ||
450 | u32 last_rates[IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES]; | ||
451 | int last_frame_idx; | ||
452 | }; | ||
453 | |||
429 | struct iwl_mvm { | 454 | struct iwl_mvm { |
430 | /* for logger access */ | 455 | /* for logger access */ |
431 | struct device *dev; | 456 | struct device *dev; |
@@ -457,6 +482,8 @@ struct iwl_mvm { | |||
457 | bool init_ucode_complete; | 482 | bool init_ucode_complete; |
458 | u32 error_event_table; | 483 | u32 error_event_table; |
459 | u32 log_event_table; | 484 | u32 log_event_table; |
485 | u32 umac_error_event_table; | ||
486 | bool support_umac_log; | ||
460 | 487 | ||
461 | u32 ampdu_ref; | 488 | u32 ampdu_ref; |
462 | 489 | ||
@@ -470,7 +497,7 @@ struct iwl_mvm { | |||
470 | 497 | ||
471 | struct iwl_nvm_data *nvm_data; | 498 | struct iwl_nvm_data *nvm_data; |
472 | /* NVM sections */ | 499 | /* NVM sections */ |
473 | struct iwl_nvm_section nvm_sections[NVM_NUM_OF_SECTIONS]; | 500 | struct iwl_nvm_section nvm_sections[NVM_MAX_NUM_SECTIONS]; |
474 | 501 | ||
475 | /* EEPROM MAC addresses */ | 502 | /* EEPROM MAC addresses */ |
476 | struct mac_address addresses[IWL_MVM_MAX_ADDRESSES]; | 503 | struct mac_address addresses[IWL_MVM_MAX_ADDRESSES]; |
@@ -494,6 +521,17 @@ struct iwl_mvm { | |||
494 | /* rx chain antennas set through debugfs for the scan command */ | 521 | /* rx chain antennas set through debugfs for the scan command */ |
495 | u8 scan_rx_ant; | 522 | u8 scan_rx_ant; |
496 | 523 | ||
524 | #ifdef CONFIG_IWLWIFI_BCAST_FILTERING | ||
525 | /* broadcast filters to configure for each associated station */ | ||
526 | const struct iwl_fw_bcast_filter *bcast_filters; | ||
527 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
528 | struct { | ||
529 | u32 override; /* u32 for debugfs_create_bool */ | ||
530 | struct iwl_bcast_filter_cmd cmd; | ||
531 | } dbgfs_bcast_filtering; | ||
532 | #endif | ||
533 | #endif | ||
534 | |||
497 | /* Internal station */ | 535 | /* Internal station */ |
498 | struct iwl_mvm_int_sta aux_sta; | 536 | struct iwl_mvm_int_sta aux_sta; |
499 | 537 | ||
@@ -506,6 +544,7 @@ struct iwl_mvm { | |||
506 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 544 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
507 | struct dentry *debugfs_dir; | 545 | struct dentry *debugfs_dir; |
508 | u32 dbgfs_sram_offset, dbgfs_sram_len; | 546 | u32 dbgfs_sram_offset, dbgfs_sram_len; |
547 | u32 dbgfs_prph_reg_addr; | ||
509 | bool disable_power_off; | 548 | bool disable_power_off; |
510 | bool disable_power_off_d3; | 549 | bool disable_power_off_d3; |
511 | 550 | ||
@@ -513,6 +552,9 @@ struct iwl_mvm { | |||
513 | struct debugfs_blob_wrapper nvm_sw_blob; | 552 | struct debugfs_blob_wrapper nvm_sw_blob; |
514 | struct debugfs_blob_wrapper nvm_calib_blob; | 553 | struct debugfs_blob_wrapper nvm_calib_blob; |
515 | struct debugfs_blob_wrapper nvm_prod_blob; | 554 | struct debugfs_blob_wrapper nvm_prod_blob; |
555 | |||
556 | struct iwl_mvm_frame_stats drv_rx_stats; | ||
557 | spinlock_t drv_stats_lock; | ||
516 | #endif | 558 | #endif |
517 | 559 | ||
518 | struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX]; | 560 | struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX]; |
@@ -526,10 +568,16 @@ struct iwl_mvm { | |||
526 | */ | 568 | */ |
527 | unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; | 569 | unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; |
528 | 570 | ||
571 | /* A bitmap of reference types taken by the driver. */ | ||
572 | unsigned long ref_bitmap[BITS_TO_LONGS(IWL_MVM_REF_COUNT)]; | ||
573 | |||
529 | u8 vif_count; | 574 | u8 vif_count; |
530 | 575 | ||
531 | /* -1 for always, 0 for never, >0 for that many times */ | 576 | /* -1 for always, 0 for never, >0 for that many times */ |
532 | s8 restart_fw; | 577 | s8 restart_fw; |
578 | void *fw_error_dump; | ||
579 | void *fw_error_sram; | ||
580 | u32 fw_error_sram_len; | ||
533 | 581 | ||
534 | struct led_classdev led; | 582 | struct led_classdev led; |
535 | 583 | ||
@@ -548,17 +596,27 @@ struct iwl_mvm { | |||
548 | #endif | 596 | #endif |
549 | #endif | 597 | #endif |
550 | 598 | ||
599 | /* d0i3 */ | ||
600 | u8 d0i3_ap_sta_id; | ||
601 | bool d0i3_offloading; | ||
602 | struct work_struct d0i3_exit_work; | ||
603 | struct sk_buff_head d0i3_tx; | ||
604 | /* sync d0i3_tx queue and IWL_MVM_STATUS_IN_D0I3 status flag */ | ||
605 | spinlock_t d0i3_tx_lock; | ||
606 | wait_queue_head_t d0i3_exit_waitq; | ||
607 | |||
551 | /* BT-Coex */ | 608 | /* BT-Coex */ |
552 | u8 bt_kill_msk; | 609 | u8 bt_kill_msk; |
553 | struct iwl_bt_coex_profile_notif last_bt_notif; | 610 | struct iwl_bt_coex_profile_notif last_bt_notif; |
554 | struct iwl_bt_coex_ci_cmd last_bt_ci_cmd; | 611 | struct iwl_bt_coex_ci_cmd last_bt_ci_cmd; |
612 | u32 last_ant_isol; | ||
613 | u8 last_corun_lut; | ||
614 | u8 bt_tx_prio; | ||
555 | 615 | ||
556 | /* Thermal Throttling and CTkill */ | 616 | /* Thermal Throttling and CTkill */ |
557 | struct iwl_mvm_tt_mgmt thermal_throttle; | 617 | struct iwl_mvm_tt_mgmt thermal_throttle; |
558 | s32 temperature; /* Celsius */ | 618 | s32 temperature; /* Celsius */ |
559 | 619 | ||
560 | const struct iwl_mvm_power_ops *pm_ops; | ||
561 | |||
562 | #ifdef CONFIG_NL80211_TESTMODE | 620 | #ifdef CONFIG_NL80211_TESTMODE |
563 | u32 noa_duration; | 621 | u32 noa_duration; |
564 | struct ieee80211_vif *noa_vif; | 622 | struct ieee80211_vif *noa_vif; |
@@ -569,10 +627,10 @@ struct iwl_mvm { | |||
569 | u8 first_agg_queue; | 627 | u8 first_agg_queue; |
570 | u8 last_agg_queue; | 628 | u8 last_agg_queue; |
571 | 629 | ||
572 | u8 bound_vif_cnt; | ||
573 | |||
574 | /* Indicate if device power save is allowed */ | 630 | /* Indicate if device power save is allowed */ |
575 | bool ps_prevented; | 631 | bool ps_disabled; |
632 | /* Indicate if device power management is allowed */ | ||
633 | bool pm_disabled; | ||
576 | }; | 634 | }; |
577 | 635 | ||
578 | /* Extract MVM priv from op_mode and _hw */ | 636 | /* Extract MVM priv from op_mode and _hw */ |
@@ -587,6 +645,7 @@ enum iwl_mvm_status { | |||
587 | IWL_MVM_STATUS_HW_CTKILL, | 645 | IWL_MVM_STATUS_HW_CTKILL, |
588 | IWL_MVM_STATUS_ROC_RUNNING, | 646 | IWL_MVM_STATUS_ROC_RUNNING, |
589 | IWL_MVM_STATUS_IN_HW_RESTART, | 647 | IWL_MVM_STATUS_IN_HW_RESTART, |
648 | IWL_MVM_STATUS_IN_D0I3, | ||
590 | }; | 649 | }; |
591 | 650 | ||
592 | static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) | 651 | static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) |
@@ -595,6 +654,30 @@ static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) | |||
595 | test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); | 654 | test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); |
596 | } | 655 | } |
597 | 656 | ||
657 | static inline struct iwl_mvm_sta * | ||
658 | iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id) | ||
659 | { | ||
660 | struct ieee80211_sta *sta; | ||
661 | |||
662 | if (sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id)) | ||
663 | return NULL; | ||
664 | |||
665 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | ||
666 | lockdep_is_held(&mvm->mutex)); | ||
667 | |||
668 | /* This can happen if the station has been removed right now */ | ||
669 | if (IS_ERR_OR_NULL(sta)) | ||
670 | return NULL; | ||
671 | |||
672 | return iwl_mvm_sta_from_mac80211(sta); | ||
673 | } | ||
674 | |||
675 | static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) | ||
676 | { | ||
677 | return mvm->trans->cfg->d0i3 && | ||
678 | (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); | ||
679 | } | ||
680 | |||
598 | extern const u8 iwl_mvm_ac_to_tx_fifo[]; | 681 | extern const u8 iwl_mvm_ac_to_tx_fifo[]; |
599 | 682 | ||
600 | struct iwl_rate_info { | 683 | struct iwl_rate_info { |
@@ -619,7 +702,10 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags, | |||
619 | struct ieee80211_tx_rate *r); | 702 | struct ieee80211_tx_rate *r); |
620 | u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); | 703 | u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); |
621 | void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); | 704 | void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); |
622 | void iwl_mvm_dump_sram(struct iwl_mvm *mvm); | 705 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
706 | void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); | ||
707 | void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm); | ||
708 | #endif | ||
623 | u8 first_antenna(u8 mask); | 709 | u8 first_antenna(u8 mask); |
624 | u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); | 710 | u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); |
625 | 711 | ||
@@ -645,6 +731,11 @@ static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; } | |||
645 | int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync); | 731 | int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync); |
646 | void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); | 732 | void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); |
647 | 733 | ||
734 | static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm) | ||
735 | { | ||
736 | flush_work(&mvm->async_handlers_wk); | ||
737 | } | ||
738 | |||
648 | /* Statistics */ | 739 | /* Statistics */ |
649 | int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm, | 740 | int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm, |
650 | struct iwl_rx_cmd_buffer *rxb, | 741 | struct iwl_rx_cmd_buffer *rxb, |
@@ -661,6 +752,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm); | |||
661 | int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm); | 752 | int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm); |
662 | 753 | ||
663 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm); | 754 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm); |
755 | bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, | ||
756 | struct iwl_bcast_filter_cmd *cmd); | ||
664 | 757 | ||
665 | /* | 758 | /* |
666 | * FW notifications / CMD responses handlers | 759 | * FW notifications / CMD responses handlers |
@@ -676,6 +769,9 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
676 | struct iwl_device_cmd *cmd); | 769 | struct iwl_device_cmd *cmd); |
677 | int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | 770 | int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, |
678 | struct iwl_device_cmd *cmd); | 771 | struct iwl_device_cmd *cmd); |
772 | int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, | ||
773 | struct iwl_rx_cmd_buffer *rxb, | ||
774 | struct iwl_device_cmd *cmd); | ||
679 | int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | 775 | int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, |
680 | struct iwl_device_cmd *cmd); | 776 | struct iwl_device_cmd *cmd); |
681 | int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, | 777 | int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, |
@@ -730,7 +826,7 @@ int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
730 | struct iwl_device_cmd *cmd); | 826 | struct iwl_device_cmd *cmd); |
731 | int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | 827 | int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, |
732 | struct iwl_device_cmd *cmd); | 828 | struct iwl_device_cmd *cmd); |
733 | void iwl_mvm_cancel_scan(struct iwl_mvm *mvm); | 829 | int iwl_mvm_cancel_scan(struct iwl_mvm *mvm); |
734 | 830 | ||
735 | /* Scheduled scan */ | 831 | /* Scheduled scan */ |
736 | int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, | 832 | int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, |
@@ -744,7 +840,7 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, | |||
744 | struct cfg80211_sched_scan_request *req); | 840 | struct cfg80211_sched_scan_request *req); |
745 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | 841 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, |
746 | struct cfg80211_sched_scan_request *req); | 842 | struct cfg80211_sched_scan_request *req); |
747 | void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm); | 843 | int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm); |
748 | int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm, | 844 | int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm, |
749 | struct iwl_rx_cmd_buffer *rxb, | 845 | struct iwl_rx_cmd_buffer *rxb, |
750 | struct iwl_device_cmd *cmd); | 846 | struct iwl_device_cmd *cmd); |
@@ -772,49 +868,24 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
772 | 868 | ||
773 | /* rate scaling */ | 869 | /* rate scaling */ |
774 | int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init); | 870 | int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init); |
871 | void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, | ||
872 | struct iwl_mvm_frame_stats *stats, | ||
873 | u32 rate, bool agg); | ||
874 | int rs_pretty_print_rate(char *buf, const u32 rate); | ||
775 | 875 | ||
776 | /* power managment */ | 876 | /* power management */ |
777 | static inline int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, | 877 | int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm); |
778 | struct ieee80211_vif *vif) | ||
779 | { | ||
780 | return mvm->pm_ops->power_update_mode(mvm, vif); | ||
781 | } | ||
782 | |||
783 | static inline int iwl_mvm_power_disable(struct iwl_mvm *mvm, | ||
784 | struct ieee80211_vif *vif) | ||
785 | { | ||
786 | return mvm->pm_ops->power_disable(mvm, vif); | ||
787 | } | ||
788 | |||
789 | static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm) | ||
790 | { | ||
791 | if (mvm->pm_ops->power_update_device_mode) | ||
792 | return mvm->pm_ops->power_update_device_mode(mvm); | ||
793 | return 0; | ||
794 | } | ||
795 | 878 | ||
796 | static inline void iwl_mvm_power_update_binding(struct iwl_mvm *mvm, | 879 | int iwl_mvm_power_update_device(struct iwl_mvm *mvm); |
797 | struct ieee80211_vif *vif, | 880 | int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
798 | bool assign) | 881 | int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
799 | { | 882 | char *buf, int bufsz); |
800 | if (mvm->pm_ops->power_update_binding) | ||
801 | mvm->pm_ops->power_update_binding(mvm, vif, assign); | ||
802 | } | ||
803 | 883 | ||
804 | void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 884 | void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
805 | int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, | 885 | int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, |
806 | struct iwl_rx_cmd_buffer *rxb, | 886 | struct iwl_rx_cmd_buffer *rxb, |
807 | struct iwl_device_cmd *cmd); | 887 | struct iwl_device_cmd *cmd); |
808 | 888 | ||
809 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
810 | static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm, | ||
811 | struct ieee80211_vif *vif, | ||
812 | char *buf, int bufsz) | ||
813 | { | ||
814 | return mvm->pm_ops->power_dbgfs_read(mvm, vif, buf, bufsz); | ||
815 | } | ||
816 | #endif | ||
817 | |||
818 | int iwl_mvm_leds_init(struct iwl_mvm *mvm); | 889 | int iwl_mvm_leds_init(struct iwl_mvm *mvm); |
819 | void iwl_mvm_leds_exit(struct iwl_mvm *mvm); | 890 | void iwl_mvm_leds_exit(struct iwl_mvm *mvm); |
820 | 891 | ||
@@ -840,6 +911,17 @@ iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
840 | { | 911 | { |
841 | } | 912 | } |
842 | #endif | 913 | #endif |
914 | void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, | ||
915 | struct iwl_wowlan_config_cmd_v2 *cmd); | ||
916 | int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | ||
917 | struct ieee80211_vif *vif, | ||
918 | bool disable_offloading, | ||
919 | u32 cmd_flags); | ||
920 | |||
921 | /* D0i3 */ | ||
922 | void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); | ||
923 | void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); | ||
924 | void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); | ||
843 | 925 | ||
844 | /* BT Coex */ | 926 | /* BT Coex */ |
845 | int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm); | 927 | int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm); |
@@ -850,10 +932,13 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, | |||
850 | void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 932 | void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
851 | enum ieee80211_rssi_event rssi_event); | 933 | enum ieee80211_rssi_event rssi_event); |
852 | void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm); | 934 | void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm); |
853 | u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm, | 935 | u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, |
854 | struct ieee80211_sta *sta); | 936 | struct ieee80211_sta *sta); |
855 | bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, | 937 | bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, |
856 | struct ieee80211_sta *sta); | 938 | struct ieee80211_sta *sta); |
939 | u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, | ||
940 | struct ieee80211_tx_info *info, u8 ac); | ||
941 | int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable); | ||
857 | 942 | ||
858 | enum iwl_bt_kill_msk { | 943 | enum iwl_bt_kill_msk { |
859 | BT_KILL_MSK_DEFAULT, | 944 | BT_KILL_MSK_DEFAULT, |
@@ -875,25 +960,53 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, | |||
875 | struct iwl_beacon_filter_cmd *cmd) | 960 | struct iwl_beacon_filter_cmd *cmd) |
876 | {} | 961 | {} |
877 | #endif | 962 | #endif |
963 | int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, | ||
964 | struct ieee80211_vif *vif, | ||
965 | bool enable, u32 flags); | ||
878 | int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, | 966 | int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, |
879 | struct ieee80211_vif *vif); | 967 | struct ieee80211_vif *vif, |
968 | u32 flags); | ||
880 | int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | 969 | int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, |
881 | struct ieee80211_vif *vif); | 970 | struct ieee80211_vif *vif, |
882 | int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, | 971 | u32 flags); |
883 | struct iwl_beacon_filter_cmd *cmd); | ||
884 | int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, | 972 | int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, |
885 | struct ieee80211_vif *vif, bool enable); | 973 | struct ieee80211_vif *vif, bool enable); |
886 | int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, | 974 | int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, |
887 | struct ieee80211_vif *vif); | 975 | struct ieee80211_vif *vif, |
976 | bool force, | ||
977 | u32 flags); | ||
888 | 978 | ||
889 | /* SMPS */ | 979 | /* SMPS */ |
890 | void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 980 | void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
891 | enum iwl_mvm_smps_type_request req_type, | 981 | enum iwl_mvm_smps_type_request req_type, |
892 | enum ieee80211_smps_mode smps_request); | 982 | enum ieee80211_smps_mode smps_request); |
893 | 983 | ||
984 | /* Low latency */ | ||
985 | int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
986 | bool value); | ||
987 | /* get SystemLowLatencyMode - only needed for beacon threshold? */ | ||
988 | bool iwl_mvm_low_latency(struct iwl_mvm *mvm); | ||
989 | /* get VMACLowLatencyMode */ | ||
990 | static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) | ||
991 | { | ||
992 | /* | ||
993 | * should this consider associated/active/... state? | ||
994 | * | ||
995 | * Normally low-latency should only be active on interfaces | ||
996 | * that are active, but at least with debugfs it can also be | ||
997 | * enabled on interfaces that aren't active. However, when | ||
998 | * interface aren't active then they aren't added into the | ||
999 | * binding, so this has no real impact. For now, just return | ||
1000 | * the current desired low-latency state. | ||
1001 | */ | ||
1002 | |||
1003 | return mvmvif->low_latency; | ||
1004 | } | ||
1005 | |||
894 | /* Thermal management and CT-kill */ | 1006 | /* Thermal management and CT-kill */ |
1007 | void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff); | ||
895 | void iwl_mvm_tt_handler(struct iwl_mvm *mvm); | 1008 | void iwl_mvm_tt_handler(struct iwl_mvm *mvm); |
896 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm); | 1009 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff); |
897 | void iwl_mvm_tt_exit(struct iwl_mvm *mvm); | 1010 | void iwl_mvm_tt_exit(struct iwl_mvm *mvm); |
898 | void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); | 1011 | void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); |
899 | 1012 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 35b71af78d02..cf2d09f53782 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c | |||
@@ -67,14 +67,6 @@ | |||
67 | #include "iwl-eeprom-read.h" | 67 | #include "iwl-eeprom-read.h" |
68 | #include "iwl-nvm-parse.h" | 68 | #include "iwl-nvm-parse.h" |
69 | 69 | ||
70 | /* list of NVM sections we are allowed/need to read */ | ||
71 | static const int nvm_to_read[] = { | ||
72 | NVM_SECTION_TYPE_HW, | ||
73 | NVM_SECTION_TYPE_SW, | ||
74 | NVM_SECTION_TYPE_CALIBRATION, | ||
75 | NVM_SECTION_TYPE_PRODUCTION, | ||
76 | }; | ||
77 | |||
78 | /* Default NVM size to read */ | 70 | /* Default NVM size to read */ |
79 | #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) | 71 | #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) |
80 | #define IWL_MAX_NVM_SECTION_SIZE 7000 | 72 | #define IWL_MAX_NVM_SECTION_SIZE 7000 |
@@ -236,24 +228,39 @@ static struct iwl_nvm_data * | |||
236 | iwl_parse_nvm_sections(struct iwl_mvm *mvm) | 228 | iwl_parse_nvm_sections(struct iwl_mvm *mvm) |
237 | { | 229 | { |
238 | struct iwl_nvm_section *sections = mvm->nvm_sections; | 230 | struct iwl_nvm_section *sections = mvm->nvm_sections; |
239 | const __le16 *hw, *sw, *calib; | 231 | const __le16 *hw, *sw, *calib, *regulatory, *mac_override; |
240 | 232 | ||
241 | /* Checking for required sections */ | 233 | /* Checking for required sections */ |
242 | if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || | 234 | if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { |
243 | !mvm->nvm_sections[NVM_SECTION_TYPE_HW].data) { | 235 | if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || |
244 | IWL_ERR(mvm, "Can't parse empty NVM sections\n"); | 236 | !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) { |
245 | return NULL; | 237 | IWL_ERR(mvm, "Can't parse empty NVM sections\n"); |
238 | return NULL; | ||
239 | } | ||
240 | } else { | ||
241 | if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || | ||
242 | !mvm->nvm_sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data || | ||
243 | !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) { | ||
244 | IWL_ERR(mvm, | ||
245 | "Can't parse empty family 8000 NVM sections\n"); | ||
246 | return NULL; | ||
247 | } | ||
246 | } | 248 | } |
247 | 249 | ||
248 | if (WARN_ON(!mvm->cfg)) | 250 | if (WARN_ON(!mvm->cfg)) |
249 | return NULL; | 251 | return NULL; |
250 | 252 | ||
251 | hw = (const __le16 *)sections[NVM_SECTION_TYPE_HW].data; | 253 | hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data; |
252 | sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; | 254 | sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; |
253 | calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; | 255 | calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; |
256 | regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data; | ||
257 | mac_override = | ||
258 | (const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data; | ||
259 | |||
254 | return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, | 260 | return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, |
255 | iwl_fw_valid_tx_ant(mvm->fw), | 261 | regulatory, mac_override, |
256 | iwl_fw_valid_rx_ant(mvm->fw)); | 262 | mvm->fw->valid_tx_ant, |
263 | mvm->fw->valid_rx_ant); | ||
257 | } | 264 | } |
258 | 265 | ||
259 | #define MAX_NVM_FILE_LEN 16384 | 266 | #define MAX_NVM_FILE_LEN 16384 |
@@ -293,6 +300,8 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) | |||
293 | 300 | ||
294 | #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) | 301 | #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) |
295 | #define NVM_WORD2_ID(x) (x >> 12) | 302 | #define NVM_WORD2_ID(x) (x >> 12) |
303 | #define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8)) | ||
304 | #define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4) | ||
296 | 305 | ||
297 | IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); | 306 | IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); |
298 | 307 | ||
@@ -343,8 +352,16 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) | |||
343 | break; | 352 | break; |
344 | } | 353 | } |
345 | 354 | ||
346 | section_size = 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1)); | 355 | if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { |
347 | section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); | 356 | section_size = |
357 | 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1)); | ||
358 | section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); | ||
359 | } else { | ||
360 | section_size = 2 * NVM_WORD2_LEN_FAMILY_8000( | ||
361 | le16_to_cpu(file_sec->word2)); | ||
362 | section_id = NVM_WORD1_ID_FAMILY_8000( | ||
363 | le16_to_cpu(file_sec->word1)); | ||
364 | } | ||
348 | 365 | ||
349 | if (section_size > IWL_MAX_NVM_SECTION_SIZE) { | 366 | if (section_size > IWL_MAX_NVM_SECTION_SIZE) { |
350 | IWL_ERR(mvm, "ERROR - section too large (%d)\n", | 367 | IWL_ERR(mvm, "ERROR - section too large (%d)\n", |
@@ -367,7 +384,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) | |||
367 | break; | 384 | break; |
368 | } | 385 | } |
369 | 386 | ||
370 | if (WARN(section_id >= NVM_NUM_OF_SECTIONS, | 387 | if (WARN(section_id >= NVM_MAX_NUM_SECTIONS, |
371 | "Invalid NVM section ID %d\n", section_id)) { | 388 | "Invalid NVM section ID %d\n", section_id)) { |
372 | ret = -EINVAL; | 389 | ret = -EINVAL; |
373 | break; | 390 | break; |
@@ -414,6 +431,11 @@ int iwl_nvm_init(struct iwl_mvm *mvm) | |||
414 | { | 431 | { |
415 | int ret, i, section; | 432 | int ret, i, section; |
416 | u8 *nvm_buffer, *temp; | 433 | u8 *nvm_buffer, *temp; |
434 | int nvm_to_read[NVM_MAX_NUM_SECTIONS]; | ||
435 | int num_of_sections_to_read; | ||
436 | |||
437 | if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS)) | ||
438 | return -EINVAL; | ||
417 | 439 | ||
418 | /* load external NVM if configured */ | 440 | /* load external NVM if configured */ |
419 | if (iwlwifi_mod_params.nvm_file) { | 441 | if (iwlwifi_mod_params.nvm_file) { |
@@ -422,6 +444,22 @@ int iwl_nvm_init(struct iwl_mvm *mvm) | |||
422 | if (ret) | 444 | if (ret) |
423 | return ret; | 445 | return ret; |
424 | } else { | 446 | } else { |
447 | /* list of NVM sections we are allowed/need to read */ | ||
448 | if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { | ||
449 | nvm_to_read[0] = mvm->cfg->nvm_hw_section_num; | ||
450 | nvm_to_read[1] = NVM_SECTION_TYPE_SW; | ||
451 | nvm_to_read[2] = NVM_SECTION_TYPE_CALIBRATION; | ||
452 | nvm_to_read[3] = NVM_SECTION_TYPE_PRODUCTION; | ||
453 | num_of_sections_to_read = 4; | ||
454 | } else { | ||
455 | nvm_to_read[0] = NVM_SECTION_TYPE_SW; | ||
456 | nvm_to_read[1] = NVM_SECTION_TYPE_CALIBRATION; | ||
457 | nvm_to_read[2] = NVM_SECTION_TYPE_PRODUCTION; | ||
458 | nvm_to_read[3] = NVM_SECTION_TYPE_REGULATORY; | ||
459 | nvm_to_read[4] = NVM_SECTION_TYPE_MAC_OVERRIDE; | ||
460 | num_of_sections_to_read = 5; | ||
461 | } | ||
462 | |||
425 | /* Read From FW NVM */ | 463 | /* Read From FW NVM */ |
426 | IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); | 464 | IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); |
427 | 465 | ||
@@ -430,7 +468,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm) | |||
430 | GFP_KERNEL); | 468 | GFP_KERNEL); |
431 | if (!nvm_buffer) | 469 | if (!nvm_buffer) |
432 | return -ENOMEM; | 470 | return -ENOMEM; |
433 | for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) { | 471 | for (i = 0; i < num_of_sections_to_read; i++) { |
434 | section = nvm_to_read[i]; | 472 | section = nvm_to_read[i]; |
435 | /* we override the constness for initial read */ | 473 | /* we override the constness for initial read */ |
436 | ret = iwl_nvm_read_section(mvm, section, nvm_buffer); | 474 | ret = iwl_nvm_read_section(mvm, section, nvm_buffer); |
@@ -446,10 +484,6 @@ int iwl_nvm_init(struct iwl_mvm *mvm) | |||
446 | 484 | ||
447 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 485 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
448 | switch (section) { | 486 | switch (section) { |
449 | case NVM_SECTION_TYPE_HW: | ||
450 | mvm->nvm_hw_blob.data = temp; | ||
451 | mvm->nvm_hw_blob.size = ret; | ||
452 | break; | ||
453 | case NVM_SECTION_TYPE_SW: | 487 | case NVM_SECTION_TYPE_SW: |
454 | mvm->nvm_sw_blob.data = temp; | 488 | mvm->nvm_sw_blob.data = temp; |
455 | mvm->nvm_sw_blob.size = ret; | 489 | mvm->nvm_sw_blob.size = ret; |
@@ -463,6 +497,11 @@ int iwl_nvm_init(struct iwl_mvm *mvm) | |||
463 | mvm->nvm_prod_blob.size = ret; | 497 | mvm->nvm_prod_blob.size = ret; |
464 | break; | 498 | break; |
465 | default: | 499 | default: |
500 | if (section == mvm->cfg->nvm_hw_section_num) { | ||
501 | mvm->nvm_hw_blob.data = temp; | ||
502 | mvm->nvm_hw_blob.size = ret; | ||
503 | break; | ||
504 | } | ||
466 | WARN(1, "section: %d", section); | 505 | WARN(1, "section: %d", section); |
467 | } | 506 | } |
468 | #endif | 507 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/mvm/offloading.c b/drivers/net/wireless/iwlwifi/mvm/offloading.c new file mode 100644 index 000000000000..9bfb95e89cfb --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/offloading.c | |||
@@ -0,0 +1,215 @@ | |||
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 - 2014 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 - 2014 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 | #include <net/ipv6.h> | ||
64 | #include <net/addrconf.h> | ||
65 | #include "mvm.h" | ||
66 | |||
67 | void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, | ||
68 | struct iwl_wowlan_config_cmd_v2 *cmd) | ||
69 | { | ||
70 | int i; | ||
71 | |||
72 | /* | ||
73 | * For QoS counters, we store the one to use next, so subtract 0x10 | ||
74 | * since the uCode will add 0x10 *before* using the value while we | ||
75 | * increment after using the value (i.e. store the next value to use). | ||
76 | */ | ||
77 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { | ||
78 | u16 seq = mvm_ap_sta->tid_data[i].seq_number; | ||
79 | seq -= 0x10; | ||
80 | cmd->qos_seq[i] = cpu_to_le16(seq); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, | ||
85 | struct ieee80211_vif *vif, | ||
86 | bool disable_offloading, | ||
87 | u32 cmd_flags) | ||
88 | { | ||
89 | union { | ||
90 | struct iwl_proto_offload_cmd_v1 v1; | ||
91 | struct iwl_proto_offload_cmd_v2 v2; | ||
92 | struct iwl_proto_offload_cmd_v3_small v3s; | ||
93 | struct iwl_proto_offload_cmd_v3_large v3l; | ||
94 | } cmd = {}; | ||
95 | struct iwl_host_cmd hcmd = { | ||
96 | .id = PROT_OFFLOAD_CONFIG_CMD, | ||
97 | .flags = cmd_flags, | ||
98 | .data[0] = &cmd, | ||
99 | .dataflags[0] = IWL_HCMD_DFL_DUP, | ||
100 | }; | ||
101 | struct iwl_proto_offload_cmd_common *common; | ||
102 | u32 enabled = 0, size; | ||
103 | u32 capa_flags = mvm->fw->ucode_capa.flags; | ||
104 | #if IS_ENABLED(CONFIG_IPV6) | ||
105 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
106 | int i; | ||
107 | |||
108 | if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL || | ||
109 | capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { | ||
110 | struct iwl_ns_config *nsc; | ||
111 | struct iwl_targ_addr *addrs; | ||
112 | int n_nsc, n_addrs; | ||
113 | int c; | ||
114 | |||
115 | if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { | ||
116 | nsc = cmd.v3s.ns_config; | ||
117 | n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S; | ||
118 | addrs = cmd.v3s.targ_addrs; | ||
119 | n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S; | ||
120 | } else { | ||
121 | nsc = cmd.v3l.ns_config; | ||
122 | n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L; | ||
123 | addrs = cmd.v3l.targ_addrs; | ||
124 | n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L; | ||
125 | } | ||
126 | |||
127 | if (mvmvif->num_target_ipv6_addrs) | ||
128 | enabled |= IWL_D3_PROTO_OFFLOAD_NS; | ||
129 | |||
130 | /* | ||
131 | * For each address we have (and that will fit) fill a target | ||
132 | * address struct and combine for NS offload structs with the | ||
133 | * solicited node addresses. | ||
134 | */ | ||
135 | for (i = 0, c = 0; | ||
136 | i < mvmvif->num_target_ipv6_addrs && | ||
137 | i < n_addrs && c < n_nsc; i++) { | ||
138 | struct in6_addr solicited_addr; | ||
139 | int j; | ||
140 | |||
141 | addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i], | ||
142 | &solicited_addr); | ||
143 | for (j = 0; j < c; j++) | ||
144 | if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr, | ||
145 | &solicited_addr) == 0) | ||
146 | break; | ||
147 | if (j == c) | ||
148 | c++; | ||
149 | addrs[i].addr = mvmvif->target_ipv6_addrs[i]; | ||
150 | addrs[i].config_num = cpu_to_le32(j); | ||
151 | nsc[j].dest_ipv6_addr = solicited_addr; | ||
152 | memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN); | ||
153 | } | ||
154 | |||
155 | if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) | ||
156 | cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i); | ||
157 | else | ||
158 | cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i); | ||
159 | } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { | ||
160 | if (mvmvif->num_target_ipv6_addrs) { | ||
161 | enabled |= IWL_D3_PROTO_OFFLOAD_NS; | ||
162 | memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN); | ||
163 | } | ||
164 | |||
165 | BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) != | ||
166 | sizeof(mvmvif->target_ipv6_addrs[0])); | ||
167 | |||
168 | for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, | ||
169 | IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++) | ||
170 | memcpy(cmd.v2.target_ipv6_addr[i], | ||
171 | &mvmvif->target_ipv6_addrs[i], | ||
172 | sizeof(cmd.v2.target_ipv6_addr[i])); | ||
173 | } else { | ||
174 | if (mvmvif->num_target_ipv6_addrs) { | ||
175 | enabled |= IWL_D3_PROTO_OFFLOAD_NS; | ||
176 | memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN); | ||
177 | } | ||
178 | |||
179 | BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) != | ||
180 | sizeof(mvmvif->target_ipv6_addrs[0])); | ||
181 | |||
182 | for (i = 0; i < min(mvmvif->num_target_ipv6_addrs, | ||
183 | IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++) | ||
184 | memcpy(cmd.v1.target_ipv6_addr[i], | ||
185 | &mvmvif->target_ipv6_addrs[i], | ||
186 | sizeof(cmd.v1.target_ipv6_addr[i])); | ||
187 | } | ||
188 | #endif | ||
189 | |||
190 | if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) { | ||
191 | common = &cmd.v3s.common; | ||
192 | size = sizeof(cmd.v3s); | ||
193 | } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { | ||
194 | common = &cmd.v3l.common; | ||
195 | size = sizeof(cmd.v3l); | ||
196 | } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { | ||
197 | common = &cmd.v2.common; | ||
198 | size = sizeof(cmd.v2); | ||
199 | } else { | ||
200 | common = &cmd.v1.common; | ||
201 | size = sizeof(cmd.v1); | ||
202 | } | ||
203 | |||
204 | if (vif->bss_conf.arp_addr_cnt) { | ||
205 | enabled |= IWL_D3_PROTO_OFFLOAD_ARP; | ||
206 | common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; | ||
207 | memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); | ||
208 | } | ||
209 | |||
210 | if (!disable_offloading) | ||
211 | common->enabled = cpu_to_le32(enabled); | ||
212 | |||
213 | hcmd.len[0] = size; | ||
214 | return iwl_mvm_send_cmd(mvm, &hcmd); | ||
215 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index a3d43de342d7..9545d7fdd4bf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -61,6 +61,7 @@ | |||
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | #include <linux/module.h> | 63 | #include <linux/module.h> |
64 | #include <linux/vmalloc.h> | ||
64 | #include <net/mac80211.h> | 65 | #include <net/mac80211.h> |
65 | 66 | ||
66 | #include "iwl-notif-wait.h" | 67 | #include "iwl-notif-wait.h" |
@@ -78,6 +79,7 @@ | |||
78 | #include "iwl-prph.h" | 79 | #include "iwl-prph.h" |
79 | #include "rs.h" | 80 | #include "rs.h" |
80 | #include "fw-api-scan.h" | 81 | #include "fw-api-scan.h" |
82 | #include "fw-error-dump.h" | ||
81 | #include "time-event.h" | 83 | #include "time-event.h" |
82 | 84 | ||
83 | /* | 85 | /* |
@@ -185,9 +187,10 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) | |||
185 | * (PCIe power is lost before PERST# is asserted), causing ME FW | 187 | * (PCIe power is lost before PERST# is asserted), causing ME FW |
186 | * to lose ownership and not being able to obtain it back. | 188 | * to lose ownership and not being able to obtain it back. |
187 | */ | 189 | */ |
188 | iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG, | 190 | if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) |
189 | APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, | 191 | iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG, |
190 | ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); | 192 | APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, |
193 | ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); | ||
191 | } | 194 | } |
192 | 195 | ||
193 | struct iwl_rx_handlers { | 196 | struct iwl_rx_handlers { |
@@ -219,13 +222,17 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | |||
219 | RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true), | 222 | RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true), |
220 | RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false), | 223 | RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false), |
221 | RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true), | 224 | RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true), |
225 | RX_HANDLER(ANTENNA_COUPLING_NOTIFICATION, | ||
226 | iwl_mvm_rx_ant_coupling_notif, true), | ||
222 | 227 | ||
223 | RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), | 228 | RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), |
224 | 229 | ||
230 | RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false), | ||
231 | |||
225 | RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), | 232 | RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), |
226 | RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), | 233 | RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, true), |
227 | RX_HANDLER(SCAN_OFFLOAD_COMPLETE, | 234 | RX_HANDLER(SCAN_OFFLOAD_COMPLETE, |
228 | iwl_mvm_rx_scan_offload_complete_notif, false), | 235 | iwl_mvm_rx_scan_offload_complete_notif, true), |
229 | RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_sched_scan_results, | 236 | RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_sched_scan_results, |
230 | false), | 237 | false), |
231 | 238 | ||
@@ -242,7 +249,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | |||
242 | #undef RX_HANDLER | 249 | #undef RX_HANDLER |
243 | #define CMD(x) [x] = #x | 250 | #define CMD(x) [x] = #x |
244 | 251 | ||
245 | static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | 252 | static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { |
246 | CMD(MVM_ALIVE), | 253 | CMD(MVM_ALIVE), |
247 | CMD(REPLY_ERROR), | 254 | CMD(REPLY_ERROR), |
248 | CMD(INIT_COMPLETE_NOTIF), | 255 | CMD(INIT_COMPLETE_NOTIF), |
@@ -284,9 +291,11 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
284 | CMD(BEACON_NOTIFICATION), | 291 | CMD(BEACON_NOTIFICATION), |
285 | CMD(BEACON_TEMPLATE_CMD), | 292 | CMD(BEACON_TEMPLATE_CMD), |
286 | CMD(STATISTICS_NOTIFICATION), | 293 | CMD(STATISTICS_NOTIFICATION), |
294 | CMD(EOSP_NOTIFICATION), | ||
287 | CMD(REDUCE_TX_POWER_CMD), | 295 | CMD(REDUCE_TX_POWER_CMD), |
288 | CMD(TX_ANT_CONFIGURATION_CMD), | 296 | CMD(TX_ANT_CONFIGURATION_CMD), |
289 | CMD(D3_CONFIG_CMD), | 297 | CMD(D3_CONFIG_CMD), |
298 | CMD(D0I3_END_CMD), | ||
290 | CMD(PROT_OFFLOAD_CONFIG_CMD), | 299 | CMD(PROT_OFFLOAD_CONFIG_CMD), |
291 | CMD(OFFLOADS_QUERY_CMD), | 300 | CMD(OFFLOADS_QUERY_CMD), |
292 | CMD(REMOTE_WAKE_CONFIG_CMD), | 301 | CMD(REMOTE_WAKE_CONFIG_CMD), |
@@ -309,17 +318,37 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
309 | CMD(BT_PROFILE_NOTIFICATION), | 318 | CMD(BT_PROFILE_NOTIFICATION), |
310 | CMD(BT_CONFIG), | 319 | CMD(BT_CONFIG), |
311 | CMD(MCAST_FILTER_CMD), | 320 | CMD(MCAST_FILTER_CMD), |
321 | CMD(BCAST_FILTER_CMD), | ||
312 | CMD(REPLY_SF_CFG_CMD), | 322 | CMD(REPLY_SF_CFG_CMD), |
313 | CMD(REPLY_BEACON_FILTERING_CMD), | 323 | CMD(REPLY_BEACON_FILTERING_CMD), |
314 | CMD(REPLY_THERMAL_MNG_BACKOFF), | 324 | CMD(REPLY_THERMAL_MNG_BACKOFF), |
315 | CMD(MAC_PM_POWER_TABLE), | 325 | CMD(MAC_PM_POWER_TABLE), |
316 | CMD(BT_COEX_CI), | 326 | CMD(BT_COEX_CI), |
317 | CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), | 327 | CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), |
328 | CMD(ANTENNA_COUPLING_NOTIFICATION), | ||
318 | }; | 329 | }; |
319 | #undef CMD | 330 | #undef CMD |
320 | 331 | ||
321 | /* this forward declaration can avoid to export the function */ | 332 | /* this forward declaration can avoid to export the function */ |
322 | static void iwl_mvm_async_handlers_wk(struct work_struct *wk); | 333 | static void iwl_mvm_async_handlers_wk(struct work_struct *wk); |
334 | static void iwl_mvm_d0i3_exit_work(struct work_struct *wk); | ||
335 | |||
336 | static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg) | ||
337 | { | ||
338 | const struct iwl_pwr_tx_backoff *pwr_tx_backoff = cfg->pwr_tx_backoffs; | ||
339 | |||
340 | if (!pwr_tx_backoff) | ||
341 | return 0; | ||
342 | |||
343 | while (pwr_tx_backoff->pwr) { | ||
344 | if (trans->dflt_pwr_limit >= pwr_tx_backoff->pwr) | ||
345 | return pwr_tx_backoff->backoff; | ||
346 | |||
347 | pwr_tx_backoff++; | ||
348 | } | ||
349 | |||
350 | return 0; | ||
351 | } | ||
323 | 352 | ||
324 | static struct iwl_op_mode * | 353 | static struct iwl_op_mode * |
325 | iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | 354 | iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, |
@@ -333,6 +362,14 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
333 | TX_CMD, | 362 | TX_CMD, |
334 | }; | 363 | }; |
335 | int err, scan_size; | 364 | int err, scan_size; |
365 | u32 min_backoff; | ||
366 | |||
367 | /* | ||
368 | * We use IWL_MVM_STATION_COUNT to check the validity of the station | ||
369 | * index all over the driver - check that its value corresponds to the | ||
370 | * array size. | ||
371 | */ | ||
372 | BUILD_BUG_ON(ARRAY_SIZE(mvm->fw_id_to_mac_id) != IWL_MVM_STATION_COUNT); | ||
336 | 373 | ||
337 | /******************************** | 374 | /******************************** |
338 | * 1. Allocating and configuring HW data | 375 | * 1. Allocating and configuring HW data |
@@ -373,6 +410,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
373 | INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk); | 410 | INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk); |
374 | INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); | 411 | INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); |
375 | INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); | 412 | INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); |
413 | INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); | ||
414 | |||
415 | spin_lock_init(&mvm->d0i3_tx_lock); | ||
416 | skb_queue_head_init(&mvm->d0i3_tx); | ||
417 | init_waitqueue_head(&mvm->d0i3_exit_waitq); | ||
376 | 418 | ||
377 | SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev); | 419 | SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev); |
378 | 420 | ||
@@ -421,7 +463,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
421 | IWL_INFO(mvm, "Detected %s, REV=0x%X\n", | 463 | IWL_INFO(mvm, "Detected %s, REV=0x%X\n", |
422 | mvm->cfg->name, mvm->trans->hw_rev); | 464 | mvm->cfg->name, mvm->trans->hw_rev); |
423 | 465 | ||
424 | iwl_mvm_tt_initialize(mvm); | 466 | min_backoff = calc_min_backoff(trans, cfg); |
467 | iwl_mvm_tt_initialize(mvm, min_backoff); | ||
425 | 468 | ||
426 | /* | 469 | /* |
427 | * If the NVM exists in an external file, | 470 | * If the NVM exists in an external file, |
@@ -462,13 +505,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
462 | if (err) | 505 | if (err) |
463 | goto out_unregister; | 506 | goto out_unregister; |
464 | 507 | ||
465 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT) | ||
466 | mvm->pm_ops = &pm_mac_ops; | ||
467 | else | ||
468 | mvm->pm_ops = &pm_legacy_ops; | ||
469 | |||
470 | memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); | 508 | memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); |
471 | 509 | ||
510 | /* rpm starts with a taken ref. only set the appropriate bit here. */ | ||
511 | set_bit(IWL_MVM_REF_UCODE_DOWN, mvm->ref_bitmap); | ||
512 | |||
472 | return op_mode; | 513 | return op_mode; |
473 | 514 | ||
474 | out_unregister: | 515 | out_unregister: |
@@ -495,6 +536,8 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) | |||
495 | ieee80211_unregister_hw(mvm->hw); | 536 | ieee80211_unregister_hw(mvm->hw); |
496 | 537 | ||
497 | kfree(mvm->scan_cmd); | 538 | kfree(mvm->scan_cmd); |
539 | vfree(mvm->fw_error_dump); | ||
540 | kfree(mvm->fw_error_sram); | ||
498 | kfree(mvm->mcast_filter_cmd); | 541 | kfree(mvm->mcast_filter_cmd); |
499 | mvm->mcast_filter_cmd = NULL; | 542 | mvm->mcast_filter_cmd = NULL; |
500 | 543 | ||
@@ -508,7 +551,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) | |||
508 | mvm->phy_db = NULL; | 551 | mvm->phy_db = NULL; |
509 | 552 | ||
510 | iwl_free_nvm_data(mvm->nvm_data); | 553 | iwl_free_nvm_data(mvm->nvm_data); |
511 | for (i = 0; i < NVM_NUM_OF_SECTIONS; i++) | 554 | for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++) |
512 | kfree(mvm->nvm_sections[i].data); | 555 | kfree(mvm->nvm_sections[i].data); |
513 | 556 | ||
514 | ieee80211_free_hw(mvm->hw); | 557 | ieee80211_free_hw(mvm->hw); |
@@ -658,7 +701,7 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) | |||
658 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); | 701 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); |
659 | } | 702 | } |
660 | 703 | ||
661 | static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) | 704 | static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) |
662 | { | 705 | { |
663 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | 706 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); |
664 | 707 | ||
@@ -667,9 +710,9 @@ static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) | |||
667 | else | 710 | else |
668 | clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); | 711 | clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); |
669 | 712 | ||
670 | if (state && mvm->cur_ucode != IWL_UCODE_INIT) | ||
671 | iwl_trans_stop_device(mvm->trans); | ||
672 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); | 713 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); |
714 | |||
715 | return state && mvm->cur_ucode != IWL_UCODE_INIT; | ||
673 | } | 716 | } |
674 | 717 | ||
675 | static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) | 718 | static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) |
@@ -703,6 +746,29 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) | |||
703 | iwl_abort_notification_waits(&mvm->notif_wait); | 746 | iwl_abort_notification_waits(&mvm->notif_wait); |
704 | 747 | ||
705 | /* | 748 | /* |
749 | * This is a bit racy, but worst case we tell mac80211 about | ||
750 | * a stopped/aborted scan when that was already done which | ||
751 | * is not a problem. It is necessary to abort any os scan | ||
752 | * here because mac80211 requires having the scan cleared | ||
753 | * before restarting. | ||
754 | * We'll reset the scan_status to NONE in restart cleanup in | ||
755 | * the next start() call from mac80211. If restart isn't called | ||
756 | * (no fw restart) scan status will stay busy. | ||
757 | */ | ||
758 | switch (mvm->scan_status) { | ||
759 | case IWL_MVM_SCAN_NONE: | ||
760 | break; | ||
761 | case IWL_MVM_SCAN_OS: | ||
762 | ieee80211_scan_completed(mvm->hw, true); | ||
763 | break; | ||
764 | case IWL_MVM_SCAN_SCHED: | ||
765 | /* Sched scan will be restarted by mac80211 in restart_hw. */ | ||
766 | if (!mvm->restart_fw) | ||
767 | ieee80211_sched_scan_stopped(mvm->hw); | ||
768 | break; | ||
769 | } | ||
770 | |||
771 | /* | ||
706 | * If we're restarting already, don't cycle restarts. | 772 | * If we're restarting already, don't cycle restarts. |
707 | * If INIT fw asserted, it will likely fail again. | 773 | * If INIT fw asserted, it will likely fail again. |
708 | * If WoWLAN fw asserted, don't restart either, mac80211 | 774 | * If WoWLAN fw asserted, don't restart either, mac80211 |
@@ -733,25 +799,8 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) | |||
733 | INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); | 799 | INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); |
734 | schedule_work(&reprobe->work); | 800 | schedule_work(&reprobe->work); |
735 | } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && mvm->restart_fw) { | 801 | } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && mvm->restart_fw) { |
736 | /* | 802 | /* don't let the transport/FW power down */ |
737 | * This is a bit racy, but worst case we tell mac80211 about | 803 | iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); |
738 | * a stopped/aborted (sched) scan when that was already done | ||
739 | * which is not a problem. It is necessary to abort any scan | ||
740 | * here because mac80211 requires having the scan cleared | ||
741 | * before restarting. | ||
742 | * We'll reset the scan_status to NONE in restart cleanup in | ||
743 | * the next start() call from mac80211. | ||
744 | */ | ||
745 | switch (mvm->scan_status) { | ||
746 | case IWL_MVM_SCAN_NONE: | ||
747 | break; | ||
748 | case IWL_MVM_SCAN_OS: | ||
749 | ieee80211_scan_completed(mvm->hw, true); | ||
750 | break; | ||
751 | case IWL_MVM_SCAN_SCHED: | ||
752 | ieee80211_sched_scan_stopped(mvm->hw); | ||
753 | break; | ||
754 | } | ||
755 | 804 | ||
756 | if (mvm->restart_fw > 0) | 805 | if (mvm->restart_fw > 0) |
757 | mvm->restart_fw--; | 806 | mvm->restart_fw--; |
@@ -759,13 +808,52 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) | |||
759 | } | 808 | } |
760 | } | 809 | } |
761 | 810 | ||
811 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
812 | void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) | ||
813 | { | ||
814 | struct iwl_fw_error_dump_file *dump_file; | ||
815 | struct iwl_fw_error_dump_data *dump_data; | ||
816 | u32 file_len; | ||
817 | |||
818 | lockdep_assert_held(&mvm->mutex); | ||
819 | |||
820 | if (mvm->fw_error_dump) | ||
821 | return; | ||
822 | |||
823 | file_len = mvm->fw_error_sram_len + | ||
824 | sizeof(*dump_file) + | ||
825 | sizeof(*dump_data); | ||
826 | |||
827 | dump_file = vmalloc(file_len); | ||
828 | if (!dump_file) | ||
829 | return; | ||
830 | |||
831 | mvm->fw_error_dump = dump_file; | ||
832 | |||
833 | dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); | ||
834 | dump_file->file_len = cpu_to_le32(file_len); | ||
835 | dump_data = (void *)dump_file->data; | ||
836 | dump_data->type = IWL_FW_ERROR_DUMP_SRAM; | ||
837 | dump_data->len = cpu_to_le32(mvm->fw_error_sram_len); | ||
838 | |||
839 | /* | ||
840 | * No need for lock since at the stage the FW isn't loaded. So it | ||
841 | * can't assert - we are the only one who can possibly be accessing | ||
842 | * mvm->fw_error_sram right now. | ||
843 | */ | ||
844 | memcpy(dump_data->data, mvm->fw_error_sram, mvm->fw_error_sram_len); | ||
845 | } | ||
846 | #endif | ||
847 | |||
762 | static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) | 848 | static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) |
763 | { | 849 | { |
764 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | 850 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); |
765 | 851 | ||
766 | iwl_mvm_dump_nic_error_log(mvm); | 852 | iwl_mvm_dump_nic_error_log(mvm); |
767 | if (!mvm->restart_fw) | 853 | |
768 | iwl_mvm_dump_sram(mvm); | 854 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
855 | iwl_mvm_fw_error_sram_dump(mvm); | ||
856 | #endif | ||
769 | 857 | ||
770 | iwl_mvm_nic_restart(mvm); | 858 | iwl_mvm_nic_restart(mvm); |
771 | } | 859 | } |
@@ -778,6 +866,323 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) | |||
778 | iwl_mvm_nic_restart(mvm); | 866 | iwl_mvm_nic_restart(mvm); |
779 | } | 867 | } |
780 | 868 | ||
869 | struct iwl_d0i3_iter_data { | ||
870 | struct iwl_mvm *mvm; | ||
871 | u8 ap_sta_id; | ||
872 | u8 vif_count; | ||
873 | u8 offloading_tid; | ||
874 | bool disable_offloading; | ||
875 | }; | ||
876 | |||
877 | static bool iwl_mvm_disallow_offloading(struct iwl_mvm *mvm, | ||
878 | struct ieee80211_vif *vif, | ||
879 | struct iwl_d0i3_iter_data *iter_data) | ||
880 | { | ||
881 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
882 | struct ieee80211_sta *ap_sta; | ||
883 | struct iwl_mvm_sta *mvmsta; | ||
884 | u32 available_tids = 0; | ||
885 | u8 tid; | ||
886 | |||
887 | if (WARN_ON(vif->type != NL80211_IFTYPE_STATION || | ||
888 | mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)) | ||
889 | return false; | ||
890 | |||
891 | ap_sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id]); | ||
892 | if (IS_ERR_OR_NULL(ap_sta)) | ||
893 | return false; | ||
894 | |||
895 | mvmsta = iwl_mvm_sta_from_mac80211(ap_sta); | ||
896 | spin_lock_bh(&mvmsta->lock); | ||
897 | for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { | ||
898 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; | ||
899 | |||
900 | /* | ||
901 | * in case of pending tx packets, don't use this tid | ||
902 | * for offloading in order to prevent reuse of the same | ||
903 | * qos seq counters. | ||
904 | */ | ||
905 | if (iwl_mvm_tid_queued(tid_data)) | ||
906 | continue; | ||
907 | |||
908 | if (tid_data->state != IWL_AGG_OFF) | ||
909 | continue; | ||
910 | |||
911 | available_tids |= BIT(tid); | ||
912 | } | ||
913 | spin_unlock_bh(&mvmsta->lock); | ||
914 | |||
915 | /* | ||
916 | * disallow protocol offloading if we have no available tid | ||
917 | * (with no pending frames and no active aggregation, | ||
918 | * as we don't handle "holes" properly - the scheduler needs the | ||
919 | * frame's seq number and TFD index to match) | ||
920 | */ | ||
921 | if (!available_tids) | ||
922 | return true; | ||
923 | |||
924 | /* for simplicity, just use the first available tid */ | ||
925 | iter_data->offloading_tid = ffs(available_tids) - 1; | ||
926 | return false; | ||
927 | } | ||
928 | |||
929 | static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, | ||
930 | struct ieee80211_vif *vif) | ||
931 | { | ||
932 | struct iwl_d0i3_iter_data *data = _data; | ||
933 | struct iwl_mvm *mvm = data->mvm; | ||
934 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
935 | u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE; | ||
936 | |||
937 | IWL_DEBUG_RPM(mvm, "entering D0i3 - vif %pM\n", vif->addr); | ||
938 | if (vif->type != NL80211_IFTYPE_STATION || | ||
939 | !vif->bss_conf.assoc) | ||
940 | return; | ||
941 | |||
942 | /* | ||
943 | * in case of pending tx packets or active aggregations, | ||
944 | * avoid offloading features in order to prevent reuse of | ||
945 | * the same qos seq counters. | ||
946 | */ | ||
947 | if (iwl_mvm_disallow_offloading(mvm, vif, data)) | ||
948 | data->disable_offloading = true; | ||
949 | |||
950 | iwl_mvm_update_d0i3_power_mode(mvm, vif, true, flags); | ||
951 | iwl_mvm_send_proto_offload(mvm, vif, data->disable_offloading, flags); | ||
952 | |||
953 | /* | ||
954 | * on init/association, mvm already configures POWER_TABLE_CMD | ||
955 | * and REPLY_MCAST_FILTER_CMD, so currently don't | ||
956 | * reconfigure them (we might want to use different | ||
957 | * params later on, though). | ||
958 | */ | ||
959 | data->ap_sta_id = mvmvif->ap_sta_id; | ||
960 | data->vif_count++; | ||
961 | } | ||
962 | |||
963 | static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, | ||
964 | struct iwl_wowlan_config_cmd_v3 *cmd, | ||
965 | struct iwl_d0i3_iter_data *iter_data) | ||
966 | { | ||
967 | struct ieee80211_sta *ap_sta; | ||
968 | struct iwl_mvm_sta *mvm_ap_sta; | ||
969 | |||
970 | if (iter_data->ap_sta_id == IWL_MVM_STATION_COUNT) | ||
971 | return; | ||
972 | |||
973 | rcu_read_lock(); | ||
974 | |||
975 | ap_sta = rcu_dereference(mvm->fw_id_to_mac_id[iter_data->ap_sta_id]); | ||
976 | if (IS_ERR_OR_NULL(ap_sta)) | ||
977 | goto out; | ||
978 | |||
979 | mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); | ||
980 | cmd->common.is_11n_connection = ap_sta->ht_cap.ht_supported; | ||
981 | cmd->offloading_tid = iter_data->offloading_tid; | ||
982 | |||
983 | /* | ||
984 | * The d0i3 uCode takes care of the nonqos counters, | ||
985 | * so configure only the qos seq ones. | ||
986 | */ | ||
987 | iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &cmd->common); | ||
988 | out: | ||
989 | rcu_read_unlock(); | ||
990 | } | ||
991 | static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) | ||
992 | { | ||
993 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
994 | u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE; | ||
995 | int ret; | ||
996 | struct iwl_d0i3_iter_data d0i3_iter_data = { | ||
997 | .mvm = mvm, | ||
998 | }; | ||
999 | struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = { | ||
1000 | .common = { | ||
1001 | .wakeup_filter = | ||
1002 | cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME | | ||
1003 | IWL_WOWLAN_WAKEUP_BEACON_MISS | | ||
1004 | IWL_WOWLAN_WAKEUP_LINK_CHANGE | | ||
1005 | IWL_WOWLAN_WAKEUP_BCN_FILTERING), | ||
1006 | }, | ||
1007 | }; | ||
1008 | struct iwl_d3_manager_config d3_cfg_cmd = { | ||
1009 | .min_sleep_time = cpu_to_le32(1000), | ||
1010 | }; | ||
1011 | |||
1012 | IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n"); | ||
1013 | |||
1014 | /* make sure we have no running tx while configuring the qos */ | ||
1015 | set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); | ||
1016 | synchronize_net(); | ||
1017 | |||
1018 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | ||
1019 | IEEE80211_IFACE_ITER_NORMAL, | ||
1020 | iwl_mvm_enter_d0i3_iterator, | ||
1021 | &d0i3_iter_data); | ||
1022 | if (d0i3_iter_data.vif_count == 1) { | ||
1023 | mvm->d0i3_ap_sta_id = d0i3_iter_data.ap_sta_id; | ||
1024 | mvm->d0i3_offloading = !d0i3_iter_data.disable_offloading; | ||
1025 | } else { | ||
1026 | WARN_ON_ONCE(d0i3_iter_data.vif_count > 1); | ||
1027 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | ||
1028 | mvm->d0i3_offloading = false; | ||
1029 | } | ||
1030 | |||
1031 | iwl_mvm_set_wowlan_data(mvm, &wowlan_config_cmd, &d0i3_iter_data); | ||
1032 | ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, flags, | ||
1033 | sizeof(wowlan_config_cmd), | ||
1034 | &wowlan_config_cmd); | ||
1035 | if (ret) | ||
1036 | return ret; | ||
1037 | |||
1038 | return iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, | ||
1039 | flags | CMD_MAKE_TRANS_IDLE, | ||
1040 | sizeof(d3_cfg_cmd), &d3_cfg_cmd); | ||
1041 | } | ||
1042 | |||
1043 | static void iwl_mvm_exit_d0i3_iterator(void *_data, u8 *mac, | ||
1044 | struct ieee80211_vif *vif) | ||
1045 | { | ||
1046 | struct iwl_mvm *mvm = _data; | ||
1047 | u32 flags = CMD_ASYNC | CMD_HIGH_PRIO; | ||
1048 | |||
1049 | IWL_DEBUG_RPM(mvm, "exiting D0i3 - vif %pM\n", vif->addr); | ||
1050 | if (vif->type != NL80211_IFTYPE_STATION || | ||
1051 | !vif->bss_conf.assoc) | ||
1052 | return; | ||
1053 | |||
1054 | iwl_mvm_update_d0i3_power_mode(mvm, vif, false, flags); | ||
1055 | } | ||
1056 | |||
1057 | static void iwl_mvm_d0i3_disconnect_iter(void *data, u8 *mac, | ||
1058 | struct ieee80211_vif *vif) | ||
1059 | { | ||
1060 | struct iwl_mvm *mvm = data; | ||
1061 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1062 | |||
1063 | if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc && | ||
1064 | mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) | ||
1065 | ieee80211_connection_loss(vif); | ||
1066 | } | ||
1067 | |||
1068 | void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq) | ||
1069 | { | ||
1070 | struct ieee80211_sta *sta = NULL; | ||
1071 | struct iwl_mvm_sta *mvm_ap_sta; | ||
1072 | int i; | ||
1073 | bool wake_queues = false; | ||
1074 | |||
1075 | lockdep_assert_held(&mvm->mutex); | ||
1076 | |||
1077 | spin_lock_bh(&mvm->d0i3_tx_lock); | ||
1078 | |||
1079 | if (mvm->d0i3_ap_sta_id == IWL_MVM_STATION_COUNT) | ||
1080 | goto out; | ||
1081 | |||
1082 | IWL_DEBUG_RPM(mvm, "re-enqueue packets\n"); | ||
1083 | |||
1084 | /* get the sta in order to update seq numbers and re-enqueue skbs */ | ||
1085 | sta = rcu_dereference_protected( | ||
1086 | mvm->fw_id_to_mac_id[mvm->d0i3_ap_sta_id], | ||
1087 | lockdep_is_held(&mvm->mutex)); | ||
1088 | |||
1089 | if (IS_ERR_OR_NULL(sta)) { | ||
1090 | sta = NULL; | ||
1091 | goto out; | ||
1092 | } | ||
1093 | |||
1094 | if (mvm->d0i3_offloading && qos_seq) { | ||
1095 | /* update qos seq numbers if offloading was enabled */ | ||
1096 | mvm_ap_sta = (struct iwl_mvm_sta *)sta->drv_priv; | ||
1097 | for (i = 0; i < IWL_MAX_TID_COUNT; i++) { | ||
1098 | u16 seq = le16_to_cpu(qos_seq[i]); | ||
1099 | /* firmware stores last-used one, we store next one */ | ||
1100 | seq += 0x10; | ||
1101 | mvm_ap_sta->tid_data[i].seq_number = seq; | ||
1102 | } | ||
1103 | } | ||
1104 | out: | ||
1105 | /* re-enqueue (or drop) all packets */ | ||
1106 | while (!skb_queue_empty(&mvm->d0i3_tx)) { | ||
1107 | struct sk_buff *skb = __skb_dequeue(&mvm->d0i3_tx); | ||
1108 | |||
1109 | if (!sta || iwl_mvm_tx_skb(mvm, skb, sta)) | ||
1110 | ieee80211_free_txskb(mvm->hw, skb); | ||
1111 | |||
1112 | /* if the skb_queue is not empty, we need to wake queues */ | ||
1113 | wake_queues = true; | ||
1114 | } | ||
1115 | clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); | ||
1116 | wake_up(&mvm->d0i3_exit_waitq); | ||
1117 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | ||
1118 | if (wake_queues) | ||
1119 | ieee80211_wake_queues(mvm->hw); | ||
1120 | |||
1121 | spin_unlock_bh(&mvm->d0i3_tx_lock); | ||
1122 | } | ||
1123 | |||
1124 | static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) | ||
1125 | { | ||
1126 | struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, d0i3_exit_work); | ||
1127 | struct iwl_host_cmd get_status_cmd = { | ||
1128 | .id = WOWLAN_GET_STATUSES, | ||
1129 | .flags = CMD_SYNC | CMD_HIGH_PRIO | CMD_WANT_SKB, | ||
1130 | }; | ||
1131 | struct iwl_wowlan_status_v6 *status; | ||
1132 | int ret; | ||
1133 | u32 disconnection_reasons, wakeup_reasons; | ||
1134 | __le16 *qos_seq = NULL; | ||
1135 | |||
1136 | mutex_lock(&mvm->mutex); | ||
1137 | ret = iwl_mvm_send_cmd(mvm, &get_status_cmd); | ||
1138 | if (ret) | ||
1139 | goto out; | ||
1140 | |||
1141 | if (!get_status_cmd.resp_pkt) | ||
1142 | goto out; | ||
1143 | |||
1144 | status = (void *)get_status_cmd.resp_pkt->data; | ||
1145 | wakeup_reasons = le32_to_cpu(status->wakeup_reasons); | ||
1146 | qos_seq = status->qos_seq_ctr; | ||
1147 | |||
1148 | IWL_DEBUG_RPM(mvm, "wakeup reasons: 0x%x\n", wakeup_reasons); | ||
1149 | |||
1150 | disconnection_reasons = | ||
1151 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | | ||
1152 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH; | ||
1153 | if (wakeup_reasons & disconnection_reasons) | ||
1154 | ieee80211_iterate_active_interfaces( | ||
1155 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
1156 | iwl_mvm_d0i3_disconnect_iter, mvm); | ||
1157 | |||
1158 | iwl_free_resp(&get_status_cmd); | ||
1159 | out: | ||
1160 | iwl_mvm_d0i3_enable_tx(mvm, qos_seq); | ||
1161 | mutex_unlock(&mvm->mutex); | ||
1162 | } | ||
1163 | |||
1164 | static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) | ||
1165 | { | ||
1166 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | ||
1167 | u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE | | ||
1168 | CMD_WAKE_UP_TRANS; | ||
1169 | int ret; | ||
1170 | |||
1171 | IWL_DEBUG_RPM(mvm, "MVM exiting D0i3\n"); | ||
1172 | |||
1173 | ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL); | ||
1174 | if (ret) | ||
1175 | goto out; | ||
1176 | |||
1177 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | ||
1178 | IEEE80211_IFACE_ITER_NORMAL, | ||
1179 | iwl_mvm_exit_d0i3_iterator, | ||
1180 | mvm); | ||
1181 | out: | ||
1182 | schedule_work(&mvm->d0i3_exit_work); | ||
1183 | return ret; | ||
1184 | } | ||
1185 | |||
781 | static const struct iwl_op_mode_ops iwl_mvm_ops = { | 1186 | static const struct iwl_op_mode_ops iwl_mvm_ops = { |
782 | .start = iwl_op_mode_mvm_start, | 1187 | .start = iwl_op_mode_mvm_start, |
783 | .stop = iwl_op_mode_mvm_stop, | 1188 | .stop = iwl_op_mode_mvm_stop, |
@@ -789,4 +1194,6 @@ static const struct iwl_op_mode_ops iwl_mvm_ops = { | |||
789 | .nic_error = iwl_mvm_nic_error, | 1194 | .nic_error = iwl_mvm_nic_error, |
790 | .cmd_queue_full = iwl_mvm_cmd_queue_full, | 1195 | .cmd_queue_full = iwl_mvm_cmd_queue_full, |
791 | .nic_config = iwl_mvm_nic_config, | 1196 | .nic_config = iwl_mvm_nic_config, |
1197 | .enter_d0i3 = iwl_mvm_enter_d0i3, | ||
1198 | .exit_d0i3 = iwl_mvm_exit_d0i3, | ||
792 | }; | 1199 | }; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index b7268c0b3333..237efe0ac1c4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | |||
@@ -156,13 +156,13 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, | |||
156 | idle_cnt = chains_static; | 156 | idle_cnt = chains_static; |
157 | active_cnt = chains_dynamic; | 157 | active_cnt = chains_dynamic; |
158 | 158 | ||
159 | cmd->rxchain_info = cpu_to_le32(iwl_fw_valid_rx_ant(mvm->fw) << | 159 | cmd->rxchain_info = cpu_to_le32(mvm->fw->valid_rx_ant << |
160 | PHY_RX_CHAIN_VALID_POS); | 160 | PHY_RX_CHAIN_VALID_POS); |
161 | cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); | 161 | cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); |
162 | cmd->rxchain_info |= cpu_to_le32(active_cnt << | 162 | cmd->rxchain_info |= cpu_to_le32(active_cnt << |
163 | PHY_RX_CHAIN_MIMO_CNT_POS); | 163 | PHY_RX_CHAIN_MIMO_CNT_POS); |
164 | 164 | ||
165 | cmd->txchain_info = cpu_to_le32(iwl_fw_valid_tx_ant(mvm->fw)); | 165 | cmd->txchain_info = cpu_to_le32(mvm->fw->valid_tx_ant); |
166 | } | 166 | } |
167 | 167 | ||
168 | /* | 168 | /* |
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index d9eab3b7bb9f..6b636eab3339 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c | |||
@@ -74,39 +74,36 @@ | |||
74 | 74 | ||
75 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 | 75 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 |
76 | 76 | ||
77 | static | ||
77 | int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, | 78 | int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, |
78 | struct iwl_beacon_filter_cmd *cmd) | 79 | struct iwl_beacon_filter_cmd *cmd, |
80 | u32 flags) | ||
79 | { | 81 | { |
80 | int ret; | 82 | IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n", |
81 | 83 | le32_to_cpu(cmd->ba_enable_beacon_abort)); | |
82 | ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, CMD_SYNC, | 84 | IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n", |
83 | sizeof(struct iwl_beacon_filter_cmd), cmd); | 85 | le32_to_cpu(cmd->ba_escape_timer)); |
84 | 86 | IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n", | |
85 | if (!ret) { | 87 | le32_to_cpu(cmd->bf_debug_flag)); |
86 | IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n", | 88 | IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n", |
87 | le32_to_cpu(cmd->ba_enable_beacon_abort)); | 89 | le32_to_cpu(cmd->bf_enable_beacon_filter)); |
88 | IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n", | 90 | IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n", |
89 | le32_to_cpu(cmd->ba_escape_timer)); | 91 | le32_to_cpu(cmd->bf_energy_delta)); |
90 | IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n", | 92 | IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n", |
91 | le32_to_cpu(cmd->bf_debug_flag)); | 93 | le32_to_cpu(cmd->bf_escape_timer)); |
92 | IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n", | 94 | IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n", |
93 | le32_to_cpu(cmd->bf_enable_beacon_filter)); | 95 | le32_to_cpu(cmd->bf_roaming_energy_delta)); |
94 | IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n", | 96 | IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n", |
95 | le32_to_cpu(cmd->bf_energy_delta)); | 97 | le32_to_cpu(cmd->bf_roaming_state)); |
96 | IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n", | 98 | IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n", |
97 | le32_to_cpu(cmd->bf_escape_timer)); | 99 | le32_to_cpu(cmd->bf_temp_threshold)); |
98 | IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n", | 100 | IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n", |
99 | le32_to_cpu(cmd->bf_roaming_energy_delta)); | 101 | le32_to_cpu(cmd->bf_temp_fast_filter)); |
100 | IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n", | 102 | IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n", |
101 | le32_to_cpu(cmd->bf_roaming_state)); | 103 | le32_to_cpu(cmd->bf_temp_slow_filter)); |
102 | IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n", | 104 | |
103 | le32_to_cpu(cmd->bf_temp_threshold)); | 105 | return iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags, |
104 | IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n", | 106 | sizeof(struct iwl_beacon_filter_cmd), cmd); |
105 | le32_to_cpu(cmd->bf_temp_fast_filter)); | ||
106 | IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n", | ||
107 | le32_to_cpu(cmd->bf_temp_slow_filter)); | ||
108 | } | ||
109 | return ret; | ||
110 | } | 107 | } |
111 | 108 | ||
112 | static | 109 | static |
@@ -145,7 +142,7 @@ int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, | |||
145 | mvmvif->bf_data.ba_enabled = enable; | 142 | mvmvif->bf_data.ba_enabled = enable; |
146 | iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd); | 143 | iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd); |
147 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); | 144 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); |
148 | return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); | 145 | return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, CMD_SYNC); |
149 | } | 146 | } |
150 | 147 | ||
151 | static void iwl_mvm_power_log(struct iwl_mvm *mvm, | 148 | static void iwl_mvm_power_log(struct iwl_mvm *mvm, |
@@ -301,8 +298,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
301 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); | 298 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); |
302 | cmd->keep_alive_seconds = cpu_to_le16(keep_alive); | 299 | cmd->keep_alive_seconds = cpu_to_le16(keep_alive); |
303 | 300 | ||
304 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || | 301 | if (mvm->ps_disabled) |
305 | mvm->ps_prevented) | ||
306 | return; | 302 | return; |
307 | 303 | ||
308 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | 304 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); |
@@ -312,7 +308,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
312 | mvmvif->dbgfs_pm.disable_power_off) | 308 | mvmvif->dbgfs_pm.disable_power_off) |
313 | cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); | 309 | cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); |
314 | #endif | 310 | #endif |
315 | if (!vif->bss_conf.ps || mvmvif->pm_prevented) | 311 | if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || |
312 | mvm->pm_disabled) | ||
316 | return; | 313 | return; |
317 | 314 | ||
318 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); | 315 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); |
@@ -419,72 +416,44 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
419 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | 416 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ |
420 | } | 417 | } |
421 | 418 | ||
422 | static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, | 419 | static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm, |
423 | struct ieee80211_vif *vif) | 420 | struct ieee80211_vif *vif) |
424 | { | 421 | { |
425 | int ret; | ||
426 | bool ba_enable; | ||
427 | struct iwl_mac_power_cmd cmd = {}; | 422 | struct iwl_mac_power_cmd cmd = {}; |
428 | 423 | ||
429 | if (vif->type != NL80211_IFTYPE_STATION) | 424 | if (vif->type != NL80211_IFTYPE_STATION) |
430 | return 0; | 425 | return 0; |
431 | 426 | ||
432 | if (vif->p2p && | 427 | if (vif->p2p && |
433 | !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS)) | 428 | !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) |
434 | return 0; | 429 | return 0; |
435 | 430 | ||
436 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | 431 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); |
437 | iwl_mvm_power_log(mvm, &cmd); | 432 | iwl_mvm_power_log(mvm, &cmd); |
438 | |||
439 | ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC, | ||
440 | sizeof(cmd), &cmd); | ||
441 | if (ret) | ||
442 | return ret; | ||
443 | |||
444 | ba_enable = !!(cmd.flags & | ||
445 | cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); | ||
446 | |||
447 | return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); | ||
448 | } | ||
449 | |||
450 | static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm, | ||
451 | struct ieee80211_vif *vif) | ||
452 | { | ||
453 | struct iwl_mac_power_cmd cmd = {}; | ||
454 | struct iwl_mvm_vif *mvmvif __maybe_unused = | ||
455 | iwl_mvm_vif_from_mac80211(vif); | ||
456 | |||
457 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
458 | return 0; | ||
459 | |||
460 | cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
461 | mvmvif->color)); | ||
462 | |||
463 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) | ||
464 | cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
465 | |||
466 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 433 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
467 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && | 434 | memcpy(&iwl_mvm_vif_from_mac80211(vif)->mac_pwr_cmd, &cmd, sizeof(cmd)); |
468 | mvmvif->dbgfs_pm.disable_power_off) | ||
469 | cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
470 | #endif | 435 | #endif |
471 | iwl_mvm_power_log(mvm, &cmd); | ||
472 | 436 | ||
473 | return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_ASYNC, | 437 | return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC, |
474 | sizeof(cmd), &cmd); | 438 | sizeof(cmd), &cmd); |
475 | } | 439 | } |
476 | 440 | ||
477 | static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable) | 441 | int iwl_mvm_power_update_device(struct iwl_mvm *mvm) |
478 | { | 442 | { |
479 | struct iwl_device_power_cmd cmd = { | 443 | struct iwl_device_power_cmd cmd = { |
480 | .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), | 444 | .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), |
481 | }; | 445 | }; |
482 | 446 | ||
447 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) | ||
448 | return 0; | ||
449 | |||
483 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) | 450 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) |
484 | return 0; | 451 | return 0; |
485 | 452 | ||
486 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || | 453 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) |
487 | force_disable) | 454 | mvm->ps_disabled = true; |
455 | |||
456 | if (mvm->ps_disabled) | ||
488 | cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK); | 457 | cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK); |
489 | 458 | ||
490 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 459 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
@@ -501,11 +470,6 @@ static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable) | |||
501 | &cmd); | 470 | &cmd); |
502 | } | 471 | } |
503 | 472 | ||
504 | static int iwl_mvm_power_update_device(struct iwl_mvm *mvm) | ||
505 | { | ||
506 | return _iwl_mvm_power_update_device(mvm, false); | ||
507 | } | ||
508 | |||
509 | void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 473 | void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
510 | { | 474 | { |
511 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 475 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
@@ -544,44 +508,176 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, | |||
544 | return 0; | 508 | return 0; |
545 | } | 509 | } |
546 | 510 | ||
547 | static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac, | 511 | struct iwl_power_constraint { |
548 | struct ieee80211_vif *vif) | 512 | struct ieee80211_vif *bf_vif; |
513 | struct ieee80211_vif *bss_vif; | ||
514 | struct ieee80211_vif *p2p_vif; | ||
515 | u16 bss_phyctx_id; | ||
516 | u16 p2p_phyctx_id; | ||
517 | bool pm_disabled; | ||
518 | bool ps_disabled; | ||
519 | struct iwl_mvm *mvm; | ||
520 | }; | ||
521 | |||
522 | static void iwl_mvm_power_iterator(void *_data, u8 *mac, | ||
523 | struct ieee80211_vif *vif) | ||
549 | { | 524 | { |
550 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 525 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
551 | struct iwl_mvm *mvm = _data; | 526 | struct iwl_power_constraint *power_iterator = _data; |
552 | int ret; | 527 | struct iwl_mvm *mvm = power_iterator->mvm; |
528 | |||
529 | switch (ieee80211_vif_type_p2p(vif)) { | ||
530 | case NL80211_IFTYPE_P2P_DEVICE: | ||
531 | break; | ||
532 | |||
533 | case NL80211_IFTYPE_P2P_GO: | ||
534 | case NL80211_IFTYPE_AP: | ||
535 | /* no BSS power mgmt if we have an active AP */ | ||
536 | if (mvmvif->ap_ibss_active) | ||
537 | power_iterator->pm_disabled = true; | ||
538 | break; | ||
539 | |||
540 | case NL80211_IFTYPE_MONITOR: | ||
541 | /* no BSS power mgmt and no device power save */ | ||
542 | power_iterator->pm_disabled = true; | ||
543 | power_iterator->ps_disabled = true; | ||
544 | break; | ||
545 | |||
546 | case NL80211_IFTYPE_P2P_CLIENT: | ||
547 | if (mvmvif->phy_ctxt) | ||
548 | power_iterator->p2p_phyctx_id = mvmvif->phy_ctxt->id; | ||
549 | |||
550 | /* we should have only one P2P vif */ | ||
551 | WARN_ON(power_iterator->p2p_vif); | ||
552 | power_iterator->p2p_vif = vif; | ||
553 | |||
554 | IWL_DEBUG_POWER(mvm, "p2p: p2p_id=%d, bss_id=%d\n", | ||
555 | power_iterator->p2p_phyctx_id, | ||
556 | power_iterator->bss_phyctx_id); | ||
557 | if (!(mvm->fw->ucode_capa.flags & | ||
558 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) { | ||
559 | /* no BSS power mgmt if we have a P2P client*/ | ||
560 | power_iterator->pm_disabled = true; | ||
561 | } else if (power_iterator->p2p_phyctx_id < MAX_PHYS && | ||
562 | power_iterator->bss_phyctx_id < MAX_PHYS && | ||
563 | power_iterator->p2p_phyctx_id == | ||
564 | power_iterator->bss_phyctx_id) { | ||
565 | power_iterator->pm_disabled = true; | ||
566 | } | ||
567 | break; | ||
568 | |||
569 | case NL80211_IFTYPE_STATION: | ||
570 | if (mvmvif->phy_ctxt) | ||
571 | power_iterator->bss_phyctx_id = mvmvif->phy_ctxt->id; | ||
572 | |||
573 | /* we should have only one BSS vif */ | ||
574 | WARN_ON(power_iterator->bss_vif); | ||
575 | power_iterator->bss_vif = vif; | ||
576 | |||
577 | if (mvmvif->bf_data.bf_enabled && | ||
578 | !WARN_ON(power_iterator->bf_vif)) | ||
579 | power_iterator->bf_vif = vif; | ||
580 | |||
581 | IWL_DEBUG_POWER(mvm, "bss: p2p_id=%d, bss_id=%d\n", | ||
582 | power_iterator->p2p_phyctx_id, | ||
583 | power_iterator->bss_phyctx_id); | ||
584 | if (mvm->fw->ucode_capa.flags & | ||
585 | IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM && | ||
586 | (power_iterator->p2p_phyctx_id < MAX_PHYS && | ||
587 | power_iterator->bss_phyctx_id < MAX_PHYS && | ||
588 | power_iterator->p2p_phyctx_id == | ||
589 | power_iterator->bss_phyctx_id)) | ||
590 | power_iterator->pm_disabled = true; | ||
591 | break; | ||
592 | |||
593 | default: | ||
594 | break; | ||
595 | } | ||
596 | } | ||
553 | 597 | ||
554 | mvmvif->pm_prevented = (mvm->bound_vif_cnt <= 1) ? false : true; | 598 | static void |
599 | iwl_mvm_power_get_global_constraint(struct iwl_mvm *mvm, | ||
600 | struct iwl_power_constraint *constraint) | ||
601 | { | ||
602 | lockdep_assert_held(&mvm->mutex); | ||
603 | |||
604 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) { | ||
605 | constraint->pm_disabled = true; | ||
606 | constraint->ps_disabled = true; | ||
607 | } | ||
555 | 608 | ||
556 | ret = iwl_mvm_power_mac_update_mode(mvm, vif); | 609 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, |
557 | WARN_ONCE(ret, "Failed to update power parameters on a specific vif\n"); | 610 | IEEE80211_IFACE_ITER_NORMAL, |
611 | iwl_mvm_power_iterator, constraint); | ||
558 | } | 612 | } |
559 | 613 | ||
560 | static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm, | 614 | int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
561 | struct ieee80211_vif *vif, | ||
562 | bool assign) | ||
563 | { | 615 | { |
616 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
617 | struct iwl_power_constraint constraint = { | ||
618 | .p2p_phyctx_id = MAX_PHYS, | ||
619 | .bss_phyctx_id = MAX_PHYS, | ||
620 | .mvm = mvm, | ||
621 | }; | ||
622 | bool ba_enable; | ||
623 | int ret; | ||
624 | |||
625 | lockdep_assert_held(&mvm->mutex); | ||
626 | |||
627 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) | ||
628 | return 0; | ||
629 | |||
630 | iwl_mvm_power_get_global_constraint(mvm, &constraint); | ||
631 | mvm->ps_disabled = constraint.ps_disabled; | ||
632 | mvm->pm_disabled = constraint.pm_disabled; | ||
633 | |||
634 | /* don't update device power state unless we add / remove monitor */ | ||
564 | if (vif->type == NL80211_IFTYPE_MONITOR) { | 635 | if (vif->type == NL80211_IFTYPE_MONITOR) { |
565 | int ret = _iwl_mvm_power_update_device(mvm, assign); | 636 | ret = iwl_mvm_power_update_device(mvm); |
566 | mvm->ps_prevented = assign; | 637 | if (ret) |
567 | WARN_ONCE(ret, "Failed to update power device state\n"); | 638 | return ret; |
568 | } | 639 | } |
569 | 640 | ||
570 | ieee80211_iterate_active_interfaces(mvm->hw, | 641 | if (constraint.bss_vif) { |
571 | IEEE80211_IFACE_ITER_NORMAL, | 642 | ret = iwl_mvm_power_send_cmd(mvm, constraint.bss_vif); |
572 | iwl_mvm_power_binding_iterator, | 643 | if (ret) |
573 | mvm); | 644 | return ret; |
645 | } | ||
646 | |||
647 | if (constraint.p2p_vif) { | ||
648 | ret = iwl_mvm_power_send_cmd(mvm, constraint.p2p_vif); | ||
649 | if (ret) | ||
650 | return ret; | ||
651 | } | ||
652 | |||
653 | if (!constraint.bf_vif) | ||
654 | return 0; | ||
655 | |||
656 | vif = constraint.bf_vif; | ||
657 | mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
658 | |||
659 | ba_enable = !(constraint.pm_disabled || constraint.ps_disabled || | ||
660 | !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif)); | ||
661 | |||
662 | return iwl_mvm_update_beacon_abort(mvm, constraint.bf_vif, ba_enable); | ||
574 | } | 663 | } |
575 | 664 | ||
576 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 665 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
577 | static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, | 666 | int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, |
578 | struct ieee80211_vif *vif, char *buf, | 667 | struct ieee80211_vif *vif, char *buf, |
579 | int bufsz) | 668 | int bufsz) |
580 | { | 669 | { |
670 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
581 | struct iwl_mac_power_cmd cmd = {}; | 671 | struct iwl_mac_power_cmd cmd = {}; |
582 | int pos = 0; | 672 | int pos = 0; |
583 | 673 | ||
584 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | 674 | if (WARN_ON(!(mvm->fw->ucode_capa.flags & |
675 | IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))) | ||
676 | return 0; | ||
677 | |||
678 | mutex_lock(&mvm->mutex); | ||
679 | memcpy(&cmd, &mvmvif->mac_pwr_cmd, sizeof(cmd)); | ||
680 | mutex_unlock(&mvm->mutex); | ||
585 | 681 | ||
586 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) | 682 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) |
587 | pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", | 683 | pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", |
@@ -685,32 +781,46 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, | |||
685 | } | 781 | } |
686 | #endif | 782 | #endif |
687 | 783 | ||
688 | int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, | 784 | static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, |
689 | struct ieee80211_vif *vif) | 785 | struct ieee80211_vif *vif, |
786 | struct iwl_beacon_filter_cmd *cmd, | ||
787 | u32 cmd_flags, | ||
788 | bool d0i3) | ||
690 | { | 789 | { |
691 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 790 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
692 | struct iwl_beacon_filter_cmd cmd = { | ||
693 | IWL_BF_CMD_CONFIG_DEFAULTS, | ||
694 | .bf_enable_beacon_filter = cpu_to_le32(1), | ||
695 | }; | ||
696 | int ret; | 791 | int ret; |
697 | 792 | ||
698 | if (mvmvif != mvm->bf_allowed_vif || | 793 | if (mvmvif != mvm->bf_allowed_vif || |
699 | vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 794 | vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
700 | return 0; | 795 | return 0; |
701 | 796 | ||
702 | iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd); | 797 | iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd); |
703 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); | 798 | if (!d0i3) |
704 | ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); | 799 | iwl_mvm_beacon_filter_debugfs_parameters(vif, cmd); |
800 | ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd, cmd_flags); | ||
705 | 801 | ||
706 | if (!ret) | 802 | /* don't change bf_enabled in case of temporary d0i3 configuration */ |
803 | if (!ret && !d0i3) | ||
707 | mvmvif->bf_data.bf_enabled = true; | 804 | mvmvif->bf_data.bf_enabled = true; |
708 | 805 | ||
709 | return ret; | 806 | return ret; |
710 | } | 807 | } |
711 | 808 | ||
809 | int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, | ||
810 | struct ieee80211_vif *vif, | ||
811 | u32 flags) | ||
812 | { | ||
813 | struct iwl_beacon_filter_cmd cmd = { | ||
814 | IWL_BF_CMD_CONFIG_DEFAULTS, | ||
815 | .bf_enable_beacon_filter = cpu_to_le32(1), | ||
816 | }; | ||
817 | |||
818 | return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, flags, false); | ||
819 | } | ||
820 | |||
712 | int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | 821 | int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, |
713 | struct ieee80211_vif *vif) | 822 | struct ieee80211_vif *vif, |
823 | u32 flags) | ||
714 | { | 824 | { |
715 | struct iwl_beacon_filter_cmd cmd = {}; | 825 | struct iwl_beacon_filter_cmd cmd = {}; |
716 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 826 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
@@ -720,7 +830,7 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | |||
720 | vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 830 | vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
721 | return 0; | 831 | return 0; |
722 | 832 | ||
723 | ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); | 833 | ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags); |
724 | 834 | ||
725 | if (!ret) | 835 | if (!ret) |
726 | mvmvif->bf_data.bf_enabled = false; | 836 | mvmvif->bf_data.bf_enabled = false; |
@@ -728,23 +838,89 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | |||
728 | return ret; | 838 | return ret; |
729 | } | 839 | } |
730 | 840 | ||
731 | int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, | 841 | int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, |
732 | struct ieee80211_vif *vif) | 842 | struct ieee80211_vif *vif, |
843 | bool enable, u32 flags) | ||
733 | { | 844 | { |
845 | int ret; | ||
734 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 846 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
847 | struct iwl_mac_power_cmd cmd = {}; | ||
735 | 848 | ||
736 | if (!mvmvif->bf_data.bf_enabled) | 849 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
737 | return 0; | 850 | return 0; |
738 | 851 | ||
739 | return iwl_mvm_enable_beacon_filter(mvm, vif); | 852 | if (!vif->bss_conf.assoc) |
740 | } | 853 | return 0; |
741 | 854 | ||
742 | const struct iwl_mvm_power_ops pm_mac_ops = { | 855 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); |
743 | .power_update_mode = iwl_mvm_power_mac_update_mode, | 856 | if (enable) { |
744 | .power_update_device_mode = iwl_mvm_power_update_device, | 857 | /* configure skip over dtim up to 300 msec */ |
745 | .power_disable = iwl_mvm_power_mac_disable, | 858 | int dtimper = mvm->hw->conf.ps_dtim_period ?: 1; |
746 | .power_update_binding = _iwl_mvm_power_update_binding, | 859 | int dtimper_msec = dtimper * vif->bss_conf.beacon_int; |
860 | |||
861 | if (WARN_ON(!dtimper_msec)) | ||
862 | return 0; | ||
863 | |||
864 | cmd.flags |= | ||
865 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
866 | cmd.skip_dtim_periods = 300 / dtimper_msec; | ||
867 | } | ||
868 | iwl_mvm_power_log(mvm, &cmd); | ||
747 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 869 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
748 | .power_dbgfs_read = iwl_mvm_power_mac_dbgfs_read, | 870 | memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd)); |
749 | #endif | 871 | #endif |
750 | }; | 872 | ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, flags, |
873 | sizeof(cmd), &cmd); | ||
874 | if (ret) | ||
875 | return ret; | ||
876 | |||
877 | /* configure beacon filtering */ | ||
878 | if (mvmvif != mvm->bf_allowed_vif) | ||
879 | return 0; | ||
880 | |||
881 | if (enable) { | ||
882 | struct iwl_beacon_filter_cmd cmd_bf = { | ||
883 | IWL_BF_CMD_CONFIG_D0I3, | ||
884 | .bf_enable_beacon_filter = cpu_to_le32(1), | ||
885 | }; | ||
886 | ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf, | ||
887 | flags, true); | ||
888 | } else { | ||
889 | if (mvmvif->bf_data.bf_enabled) | ||
890 | ret = iwl_mvm_enable_beacon_filter(mvm, vif, flags); | ||
891 | else | ||
892 | ret = iwl_mvm_disable_beacon_filter(mvm, vif, flags); | ||
893 | } | ||
894 | |||
895 | return ret; | ||
896 | } | ||
897 | |||
898 | int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, | ||
899 | struct ieee80211_vif *vif, | ||
900 | bool force, | ||
901 | u32 flags) | ||
902 | { | ||
903 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
904 | |||
905 | if (mvmvif != mvm->bf_allowed_vif) | ||
906 | return 0; | ||
907 | |||
908 | if (!mvmvif->bf_data.bf_enabled) { | ||
909 | /* disable beacon filtering explicitly if force is true */ | ||
910 | if (force) | ||
911 | return iwl_mvm_disable_beacon_filter(mvm, vif, flags); | ||
912 | return 0; | ||
913 | } | ||
914 | |||
915 | return iwl_mvm_enable_beacon_filter(mvm, vif, flags); | ||
916 | } | ||
917 | |||
918 | int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm) | ||
919 | { | ||
920 | struct iwl_powertable_cmd cmd = { | ||
921 | .keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC, | ||
922 | }; | ||
923 | |||
924 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | ||
925 | sizeof(cmd), &cmd); | ||
926 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/power_legacy.c b/drivers/net/wireless/iwlwifi/mvm/power_legacy.c deleted file mode 100644 index ef712ae5bc62..000000000000 --- a/drivers/net/wireless/iwlwifi/mvm/power_legacy.c +++ /dev/null | |||
@@ -1,319 +0,0 @@ | |||
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 - 2014 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 - 2014 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 ce5db6c4ef7e..35e86e06dffd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c | |||
@@ -65,9 +65,14 @@ | |||
65 | #include "fw-api.h" | 65 | #include "fw-api.h" |
66 | #include "mvm.h" | 66 | #include "mvm.h" |
67 | 67 | ||
68 | #define QUOTA_100 IWL_MVM_MAX_QUOTA | ||
69 | #define QUOTA_LOWLAT_MIN ((QUOTA_100 * IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT) / 100) | ||
70 | |||
68 | struct iwl_mvm_quota_iterator_data { | 71 | struct iwl_mvm_quota_iterator_data { |
69 | int n_interfaces[MAX_BINDINGS]; | 72 | int n_interfaces[MAX_BINDINGS]; |
70 | int colors[MAX_BINDINGS]; | 73 | int colors[MAX_BINDINGS]; |
74 | int low_latency[MAX_BINDINGS]; | ||
75 | int n_low_latency_bindings; | ||
71 | struct ieee80211_vif *new_vif; | 76 | struct ieee80211_vif *new_vif; |
72 | }; | 77 | }; |
73 | 78 | ||
@@ -107,22 +112,29 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, | |||
107 | switch (vif->type) { | 112 | switch (vif->type) { |
108 | case NL80211_IFTYPE_STATION: | 113 | case NL80211_IFTYPE_STATION: |
109 | if (vif->bss_conf.assoc) | 114 | if (vif->bss_conf.assoc) |
110 | data->n_interfaces[id]++; | 115 | break; |
111 | break; | 116 | return; |
112 | case NL80211_IFTYPE_AP: | 117 | case NL80211_IFTYPE_AP: |
113 | case NL80211_IFTYPE_ADHOC: | 118 | case NL80211_IFTYPE_ADHOC: |
114 | if (mvmvif->ap_ibss_active) | 119 | if (mvmvif->ap_ibss_active) |
115 | data->n_interfaces[id]++; | 120 | break; |
116 | break; | 121 | return; |
117 | case NL80211_IFTYPE_MONITOR: | 122 | case NL80211_IFTYPE_MONITOR: |
118 | if (mvmvif->monitor_active) | 123 | if (mvmvif->monitor_active) |
119 | data->n_interfaces[id]++; | 124 | break; |
120 | break; | 125 | return; |
121 | case NL80211_IFTYPE_P2P_DEVICE: | 126 | case NL80211_IFTYPE_P2P_DEVICE: |
122 | break; | 127 | return; |
123 | default: | 128 | default: |
124 | WARN_ON_ONCE(1); | 129 | WARN_ON_ONCE(1); |
125 | break; | 130 | return; |
131 | } | ||
132 | |||
133 | data->n_interfaces[id]++; | ||
134 | |||
135 | if (iwl_mvm_vif_low_latency(mvmvif) && !data->low_latency[id]) { | ||
136 | data->n_low_latency_bindings++; | ||
137 | data->low_latency[id] = true; | ||
126 | } | 138 | } |
127 | } | 139 | } |
128 | 140 | ||
@@ -162,7 +174,7 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm, | |||
162 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | 174 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) |
163 | { | 175 | { |
164 | struct iwl_time_quota_cmd cmd = {}; | 176 | struct iwl_time_quota_cmd cmd = {}; |
165 | int i, idx, ret, num_active_macs, quota, quota_rem; | 177 | int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat; |
166 | struct iwl_mvm_quota_iterator_data data = { | 178 | struct iwl_mvm_quota_iterator_data data = { |
167 | .n_interfaces = {}, | 179 | .n_interfaces = {}, |
168 | .colors = { -1, -1, -1, -1 }, | 180 | .colors = { -1, -1, -1, -1 }, |
@@ -197,11 +209,39 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | |||
197 | num_active_macs += data.n_interfaces[i]; | 209 | num_active_macs += data.n_interfaces[i]; |
198 | } | 210 | } |
199 | 211 | ||
200 | quota = 0; | 212 | n_non_lowlat = num_active_macs; |
201 | quota_rem = 0; | 213 | |
202 | if (num_active_macs) { | 214 | if (data.n_low_latency_bindings == 1) { |
203 | quota = IWL_MVM_MAX_QUOTA / num_active_macs; | 215 | for (i = 0; i < MAX_BINDINGS; i++) { |
204 | quota_rem = IWL_MVM_MAX_QUOTA % num_active_macs; | 216 | if (data.low_latency[i]) { |
217 | n_non_lowlat -= data.n_interfaces[i]; | ||
218 | break; | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
223 | if (data.n_low_latency_bindings == 1 && n_non_lowlat) { | ||
224 | /* | ||
225 | * Reserve quota for the low latency binding in case that | ||
226 | * there are several data bindings but only a single | ||
227 | * low latency one. Split the rest of the quota equally | ||
228 | * between the other data interfaces. | ||
229 | */ | ||
230 | quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat; | ||
231 | quota_rem = QUOTA_100 - n_non_lowlat * quota - | ||
232 | QUOTA_LOWLAT_MIN; | ||
233 | } else if (num_active_macs) { | ||
234 | /* | ||
235 | * There are 0 or more than 1 low latency bindings, or all the | ||
236 | * data interfaces belong to the single low latency binding. | ||
237 | * Split the quota equally between the data interfaces. | ||
238 | */ | ||
239 | quota = QUOTA_100 / num_active_macs; | ||
240 | quota_rem = QUOTA_100 % num_active_macs; | ||
241 | } else { | ||
242 | /* values don't really matter - won't be used */ | ||
243 | quota = 0; | ||
244 | quota_rem = 0; | ||
205 | } | 245 | } |
206 | 246 | ||
207 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { | 247 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { |
@@ -211,19 +251,37 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | |||
211 | cmd.quotas[idx].id_and_color = | 251 | cmd.quotas[idx].id_and_color = |
212 | cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); | 252 | cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); |
213 | 253 | ||
214 | if (data.n_interfaces[i] <= 0) { | 254 | if (data.n_interfaces[i] <= 0) |
215 | cmd.quotas[idx].quota = cpu_to_le32(0); | 255 | cmd.quotas[idx].quota = cpu_to_le32(0); |
216 | cmd.quotas[idx].max_duration = cpu_to_le32(0); | 256 | else if (data.n_low_latency_bindings == 1 && n_non_lowlat && |
217 | } else { | 257 | data.low_latency[i]) |
258 | /* | ||
259 | * There is more than one binding, but only one of the | ||
260 | * bindings is in low latency. For this case, allocate | ||
261 | * the minimal required quota for the low latency | ||
262 | * binding. | ||
263 | */ | ||
264 | cmd.quotas[idx].quota = cpu_to_le32(QUOTA_LOWLAT_MIN); | ||
265 | else | ||
218 | cmd.quotas[idx].quota = | 266 | cmd.quotas[idx].quota = |
219 | cpu_to_le32(quota * data.n_interfaces[i]); | 267 | cpu_to_le32(quota * data.n_interfaces[i]); |
220 | cmd.quotas[idx].max_duration = cpu_to_le32(0); | 268 | |
221 | } | 269 | WARN_ONCE(le32_to_cpu(cmd.quotas[idx].quota) > QUOTA_100, |
270 | "Binding=%d, quota=%u > max=%u\n", | ||
271 | idx, le32_to_cpu(cmd.quotas[idx].quota), QUOTA_100); | ||
272 | |||
273 | cmd.quotas[idx].max_duration = cpu_to_le32(0); | ||
274 | |||
222 | idx++; | 275 | idx++; |
223 | } | 276 | } |
224 | 277 | ||
225 | /* Give the remainder of the session to the first binding */ | 278 | /* Give the remainder of the session to the first data binding */ |
226 | le32_add_cpu(&cmd.quotas[0].quota, quota_rem); | 279 | for (i = 0; i < MAX_BINDINGS; i++) { |
280 | if (le32_to_cpu(cmd.quotas[i].quota) != 0) { | ||
281 | le32_add_cpu(&cmd.quotas[i].quota, quota_rem); | ||
282 | break; | ||
283 | } | ||
284 | } | ||
227 | 285 | ||
228 | iwl_mvm_adjust_quota_for_noa(mvm, &cmd); | 286 | iwl_mvm_adjust_quota_for_noa(mvm, &cmd); |
229 | 287 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 6abf74e1351f..568abd61b14f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
@@ -166,7 +166,7 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
166 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) | 166 | if (sta->smps_mode == IEEE80211_SMPS_STATIC) |
167 | return false; | 167 | return false; |
168 | 168 | ||
169 | if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2) | 169 | if (num_of_ant(mvm->fw->valid_tx_ant) < 2) |
170 | return false; | 170 | return false; |
171 | 171 | ||
172 | if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) | 172 | if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) |
@@ -211,9 +211,9 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
211 | .next_columns = { | 211 | .next_columns = { |
212 | RS_COLUMN_LEGACY_ANT_B, | 212 | RS_COLUMN_LEGACY_ANT_B, |
213 | RS_COLUMN_SISO_ANT_A, | 213 | RS_COLUMN_SISO_ANT_A, |
214 | RS_COLUMN_SISO_ANT_B, | ||
214 | RS_COLUMN_MIMO2, | 215 | RS_COLUMN_MIMO2, |
215 | RS_COLUMN_INVALID, | 216 | RS_COLUMN_MIMO2_SGI, |
216 | RS_COLUMN_INVALID, | ||
217 | }, | 217 | }, |
218 | }, | 218 | }, |
219 | [RS_COLUMN_LEGACY_ANT_B] = { | 219 | [RS_COLUMN_LEGACY_ANT_B] = { |
@@ -221,10 +221,10 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
221 | .ant = ANT_B, | 221 | .ant = ANT_B, |
222 | .next_columns = { | 222 | .next_columns = { |
223 | RS_COLUMN_LEGACY_ANT_A, | 223 | RS_COLUMN_LEGACY_ANT_A, |
224 | RS_COLUMN_SISO_ANT_A, | ||
224 | RS_COLUMN_SISO_ANT_B, | 225 | RS_COLUMN_SISO_ANT_B, |
225 | RS_COLUMN_MIMO2, | 226 | RS_COLUMN_MIMO2, |
226 | RS_COLUMN_INVALID, | 227 | RS_COLUMN_MIMO2_SGI, |
227 | RS_COLUMN_INVALID, | ||
228 | }, | 228 | }, |
229 | }, | 229 | }, |
230 | [RS_COLUMN_SISO_ANT_A] = { | 230 | [RS_COLUMN_SISO_ANT_A] = { |
@@ -234,8 +234,8 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
234 | RS_COLUMN_SISO_ANT_B, | 234 | RS_COLUMN_SISO_ANT_B, |
235 | RS_COLUMN_MIMO2, | 235 | RS_COLUMN_MIMO2, |
236 | RS_COLUMN_SISO_ANT_A_SGI, | 236 | RS_COLUMN_SISO_ANT_A_SGI, |
237 | RS_COLUMN_INVALID, | 237 | RS_COLUMN_SISO_ANT_B_SGI, |
238 | RS_COLUMN_INVALID, | 238 | RS_COLUMN_MIMO2_SGI, |
239 | }, | 239 | }, |
240 | .checks = { | 240 | .checks = { |
241 | rs_siso_allow, | 241 | rs_siso_allow, |
@@ -248,8 +248,8 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
248 | RS_COLUMN_SISO_ANT_A, | 248 | RS_COLUMN_SISO_ANT_A, |
249 | RS_COLUMN_MIMO2, | 249 | RS_COLUMN_MIMO2, |
250 | RS_COLUMN_SISO_ANT_B_SGI, | 250 | RS_COLUMN_SISO_ANT_B_SGI, |
251 | RS_COLUMN_INVALID, | 251 | RS_COLUMN_SISO_ANT_A_SGI, |
252 | RS_COLUMN_INVALID, | 252 | RS_COLUMN_MIMO2_SGI, |
253 | }, | 253 | }, |
254 | .checks = { | 254 | .checks = { |
255 | rs_siso_allow, | 255 | rs_siso_allow, |
@@ -263,8 +263,8 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
263 | RS_COLUMN_SISO_ANT_B_SGI, | 263 | RS_COLUMN_SISO_ANT_B_SGI, |
264 | RS_COLUMN_MIMO2_SGI, | 264 | RS_COLUMN_MIMO2_SGI, |
265 | RS_COLUMN_SISO_ANT_A, | 265 | RS_COLUMN_SISO_ANT_A, |
266 | RS_COLUMN_INVALID, | 266 | RS_COLUMN_SISO_ANT_B, |
267 | RS_COLUMN_INVALID, | 267 | RS_COLUMN_MIMO2, |
268 | }, | 268 | }, |
269 | .checks = { | 269 | .checks = { |
270 | rs_siso_allow, | 270 | rs_siso_allow, |
@@ -279,8 +279,8 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
279 | RS_COLUMN_SISO_ANT_A_SGI, | 279 | RS_COLUMN_SISO_ANT_A_SGI, |
280 | RS_COLUMN_MIMO2_SGI, | 280 | RS_COLUMN_MIMO2_SGI, |
281 | RS_COLUMN_SISO_ANT_B, | 281 | RS_COLUMN_SISO_ANT_B, |
282 | RS_COLUMN_INVALID, | 282 | RS_COLUMN_SISO_ANT_A, |
283 | RS_COLUMN_INVALID, | 283 | RS_COLUMN_MIMO2, |
284 | }, | 284 | }, |
285 | .checks = { | 285 | .checks = { |
286 | rs_siso_allow, | 286 | rs_siso_allow, |
@@ -292,10 +292,10 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
292 | .ant = ANT_AB, | 292 | .ant = ANT_AB, |
293 | .next_columns = { | 293 | .next_columns = { |
294 | RS_COLUMN_SISO_ANT_A, | 294 | RS_COLUMN_SISO_ANT_A, |
295 | RS_COLUMN_SISO_ANT_B, | ||
296 | RS_COLUMN_SISO_ANT_A_SGI, | ||
297 | RS_COLUMN_SISO_ANT_B_SGI, | ||
295 | RS_COLUMN_MIMO2_SGI, | 298 | RS_COLUMN_MIMO2_SGI, |
296 | RS_COLUMN_INVALID, | ||
297 | RS_COLUMN_INVALID, | ||
298 | RS_COLUMN_INVALID, | ||
299 | }, | 299 | }, |
300 | .checks = { | 300 | .checks = { |
301 | rs_mimo_allow, | 301 | rs_mimo_allow, |
@@ -307,10 +307,10 @@ static const struct rs_tx_column rs_tx_columns[] = { | |||
307 | .sgi = true, | 307 | .sgi = true, |
308 | .next_columns = { | 308 | .next_columns = { |
309 | RS_COLUMN_SISO_ANT_A_SGI, | 309 | RS_COLUMN_SISO_ANT_A_SGI, |
310 | RS_COLUMN_SISO_ANT_B_SGI, | ||
311 | RS_COLUMN_SISO_ANT_A, | ||
312 | RS_COLUMN_SISO_ANT_B, | ||
310 | RS_COLUMN_MIMO2, | 313 | RS_COLUMN_MIMO2, |
311 | RS_COLUMN_INVALID, | ||
312 | RS_COLUMN_INVALID, | ||
313 | RS_COLUMN_INVALID, | ||
314 | }, | 314 | }, |
315 | .checks = { | 315 | .checks = { |
316 | rs_mimo_allow, | 316 | rs_mimo_allow, |
@@ -380,49 +380,49 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); | |||
380 | * (2.4 GHz) band. | 380 | * (2.4 GHz) band. |
381 | */ | 381 | */ |
382 | 382 | ||
383 | static s32 expected_tpt_legacy[IWL_RATE_COUNT] = { | 383 | static const u16 expected_tpt_legacy[IWL_RATE_COUNT] = { |
384 | 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0, 0, 0 | 384 | 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0, 0, 0 |
385 | }; | 385 | }; |
386 | 386 | ||
387 | /* Expected TpT tables. 4 indexes: | 387 | /* Expected TpT tables. 4 indexes: |
388 | * 0 - NGI, 1 - SGI, 2 - AGG+NGI, 3 - AGG+SGI | 388 | * 0 - NGI, 1 - SGI, 2 - AGG+NGI, 3 - AGG+SGI |
389 | */ | 389 | */ |
390 | static s32 expected_tpt_siso_20MHz[4][IWL_RATE_COUNT] = { | 390 | static const u16 expected_tpt_siso_20MHz[4][IWL_RATE_COUNT] = { |
391 | {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202, 216, 0}, | 391 | {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202, 216, 0}, |
392 | {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210, 225, 0}, | 392 | {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210, 225, 0}, |
393 | {0, 0, 0, 0, 49, 0, 97, 145, 192, 285, 375, 420, 464, 551, 0}, | 393 | {0, 0, 0, 0, 49, 0, 97, 145, 192, 285, 375, 420, 464, 551, 0}, |
394 | {0, 0, 0, 0, 54, 0, 108, 160, 213, 315, 415, 465, 513, 608, 0}, | 394 | {0, 0, 0, 0, 54, 0, 108, 160, 213, 315, 415, 465, 513, 608, 0}, |
395 | }; | 395 | }; |
396 | 396 | ||
397 | static s32 expected_tpt_siso_40MHz[4][IWL_RATE_COUNT] = { | 397 | static const u16 expected_tpt_siso_40MHz[4][IWL_RATE_COUNT] = { |
398 | {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257, 269, 275}, | 398 | {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257, 269, 275}, |
399 | {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264, 275, 280}, | 399 | {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264, 275, 280}, |
400 | {0, 0, 0, 0, 101, 0, 199, 295, 389, 570, 744, 828, 911, 1070, 1173}, | 400 | {0, 0, 0, 0, 101, 0, 199, 295, 389, 570, 744, 828, 911, 1070, 1173}, |
401 | {0, 0, 0, 0, 112, 0, 220, 326, 429, 629, 819, 912, 1000, 1173, 1284}, | 401 | {0, 0, 0, 0, 112, 0, 220, 326, 429, 629, 819, 912, 1000, 1173, 1284}, |
402 | }; | 402 | }; |
403 | 403 | ||
404 | static s32 expected_tpt_siso_80MHz[4][IWL_RATE_COUNT] = { | 404 | static const u16 expected_tpt_siso_80MHz[4][IWL_RATE_COUNT] = { |
405 | {0, 0, 0, 0, 130, 0, 191, 223, 244, 273, 288, 294, 298, 305, 308}, | 405 | {0, 0, 0, 0, 130, 0, 191, 223, 244, 273, 288, 294, 298, 305, 308}, |
406 | {0, 0, 0, 0, 138, 0, 200, 231, 251, 279, 293, 298, 302, 308, 312}, | 406 | {0, 0, 0, 0, 138, 0, 200, 231, 251, 279, 293, 298, 302, 308, 312}, |
407 | {0, 0, 0, 0, 217, 0, 429, 634, 834, 1220, 1585, 1760, 1931, 2258, 2466}, | 407 | {0, 0, 0, 0, 217, 0, 429, 634, 834, 1220, 1585, 1760, 1931, 2258, 2466}, |
408 | {0, 0, 0, 0, 241, 0, 475, 701, 921, 1343, 1741, 1931, 2117, 2468, 2691}, | 408 | {0, 0, 0, 0, 241, 0, 475, 701, 921, 1343, 1741, 1931, 2117, 2468, 2691}, |
409 | }; | 409 | }; |
410 | 410 | ||
411 | static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { | 411 | static const u16 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { |
412 | {0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250, 261, 0}, | 412 | {0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250, 261, 0}, |
413 | {0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256, 267, 0}, | 413 | {0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256, 267, 0}, |
414 | {0, 0, 0, 0, 98, 0, 193, 286, 375, 550, 718, 799, 878, 1032, 0}, | 414 | {0, 0, 0, 0, 98, 0, 193, 286, 375, 550, 718, 799, 878, 1032, 0}, |
415 | {0, 0, 0, 0, 109, 0, 214, 316, 414, 607, 790, 879, 965, 1132, 0}, | 415 | {0, 0, 0, 0, 109, 0, 214, 316, 414, 607, 790, 879, 965, 1132, 0}, |
416 | }; | 416 | }; |
417 | 417 | ||
418 | static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { | 418 | static const u16 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { |
419 | {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289, 296, 300}, | 419 | {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289, 296, 300}, |
420 | {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293, 300, 303}, | 420 | {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293, 300, 303}, |
421 | {0, 0, 0, 0, 200, 0, 390, 571, 741, 1067, 1365, 1505, 1640, 1894, 2053}, | 421 | {0, 0, 0, 0, 200, 0, 390, 571, 741, 1067, 1365, 1505, 1640, 1894, 2053}, |
422 | {0, 0, 0, 0, 221, 0, 430, 630, 816, 1169, 1490, 1641, 1784, 2053, 2221}, | 422 | {0, 0, 0, 0, 221, 0, 430, 630, 816, 1169, 1490, 1641, 1784, 2053, 2221}, |
423 | }; | 423 | }; |
424 | 424 | ||
425 | static s32 expected_tpt_mimo2_80MHz[4][IWL_RATE_COUNT] = { | 425 | static const u16 expected_tpt_mimo2_80MHz[4][IWL_RATE_COUNT] = { |
426 | {0, 0, 0, 0, 182, 0, 240, 264, 278, 299, 308, 311, 313, 317, 319}, | 426 | {0, 0, 0, 0, 182, 0, 240, 264, 278, 299, 308, 311, 313, 317, 319}, |
427 | {0, 0, 0, 0, 190, 0, 247, 269, 282, 302, 310, 313, 315, 319, 320}, | 427 | {0, 0, 0, 0, 190, 0, 247, 269, 282, 302, 310, 313, 315, 319, 320}, |
428 | {0, 0, 0, 0, 428, 0, 833, 1215, 1577, 2254, 2863, 3147, 3418, 3913, 4219}, | 428 | {0, 0, 0, 0, 428, 0, 833, 1215, 1577, 2254, 2863, 3147, 3418, 3913, 4219}, |
@@ -503,6 +503,14 @@ static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) | |||
503 | window->average_tpt = IWL_INVALID_VALUE; | 503 | window->average_tpt = IWL_INVALID_VALUE; |
504 | } | 504 | } |
505 | 505 | ||
506 | static void rs_rate_scale_clear_tbl_windows(struct iwl_scale_tbl_info *tbl) | ||
507 | { | ||
508 | int i; | ||
509 | |||
510 | for (i = 0; i < IWL_RATE_COUNT; i++) | ||
511 | rs_rate_scale_clear_window(&tbl->win[i]); | ||
512 | } | ||
513 | |||
506 | static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) | 514 | static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) |
507 | { | 515 | { |
508 | return (ant_type & valid_antenna) == ant_type; | 516 | return (ant_type & valid_antenna) == ant_type; |
@@ -566,19 +574,13 @@ static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index) | |||
566 | * at this rate. window->data contains the bitmask of successful | 574 | * at this rate. window->data contains the bitmask of successful |
567 | * packets. | 575 | * packets. |
568 | */ | 576 | */ |
569 | static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, | 577 | static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, |
570 | int scale_index, int attempts, int successes) | 578 | int scale_index, int attempts, int successes, |
579 | struct iwl_rate_scale_data *window) | ||
571 | { | 580 | { |
572 | struct iwl_rate_scale_data *window = NULL; | ||
573 | static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1)); | 581 | static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1)); |
574 | s32 fail_count, tpt; | 582 | s32 fail_count, tpt; |
575 | 583 | ||
576 | if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) | ||
577 | return -EINVAL; | ||
578 | |||
579 | /* Select window for current tx bit rate */ | ||
580 | window = &(tbl->win[scale_index]); | ||
581 | |||
582 | /* Get expected throughput */ | 584 | /* Get expected throughput */ |
583 | tpt = get_expected_tpt(tbl, scale_index); | 585 | tpt = get_expected_tpt(tbl, scale_index); |
584 | 586 | ||
@@ -636,6 +638,21 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, | |||
636 | return 0; | 638 | return 0; |
637 | } | 639 | } |
638 | 640 | ||
641 | static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, | ||
642 | int scale_index, int attempts, int successes) | ||
643 | { | ||
644 | struct iwl_rate_scale_data *window = NULL; | ||
645 | |||
646 | if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) | ||
647 | return -EINVAL; | ||
648 | |||
649 | /* Select window for current tx bit rate */ | ||
650 | window = &(tbl->win[scale_index]); | ||
651 | |||
652 | return _rs_collect_tx_data(tbl, scale_index, attempts, successes, | ||
653 | window); | ||
654 | } | ||
655 | |||
639 | /* Convert rs_rate object into ucode rate bitmask */ | 656 | /* Convert rs_rate object into ucode rate bitmask */ |
640 | static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm, | 657 | static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm, |
641 | struct rs_rate *rate) | 658 | struct rs_rate *rate) |
@@ -905,7 +922,7 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, | |||
905 | 922 | ||
906 | rate->bw = RATE_MCS_CHAN_WIDTH_20; | 923 | rate->bw = RATE_MCS_CHAN_WIDTH_20; |
907 | 924 | ||
908 | WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX && | 925 | WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX || |
909 | rate->index > IWL_RATE_MCS_9_INDEX); | 926 | rate->index > IWL_RATE_MCS_9_INDEX); |
910 | 927 | ||
911 | rate->index = rs_ht_to_legacy[rate->index]; | 928 | rate->index = rs_ht_to_legacy[rate->index]; |
@@ -917,7 +934,7 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, | |||
917 | 934 | ||
918 | 935 | ||
919 | if (num_of_ant(rate->ant) > 1) | 936 | if (num_of_ant(rate->ant) > 1) |
920 | rate->ant = first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); | 937 | rate->ant = first_antenna(mvm->fw->valid_tx_ant); |
921 | 938 | ||
922 | /* Relevant in both switching to SISO or Legacy */ | 939 | /* Relevant in both switching to SISO or Legacy */ |
923 | rate->sgi = false; | 940 | rate->sgi = false; |
@@ -1169,12 +1186,12 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, | |||
1169 | lq_sta->visited_columns = 0; | 1186 | lq_sta->visited_columns = 0; |
1170 | } | 1187 | } |
1171 | 1188 | ||
1172 | static s32 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta, | 1189 | static const u16 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta, |
1173 | const struct rs_tx_column *column, | 1190 | const struct rs_tx_column *column, |
1174 | u32 bw) | 1191 | u32 bw) |
1175 | { | 1192 | { |
1176 | /* Used to choose among HT tables */ | 1193 | /* Used to choose among HT tables */ |
1177 | s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; | 1194 | const u16 (*ht_tbl_pointer)[IWL_RATE_COUNT]; |
1178 | 1195 | ||
1179 | if (WARN_ON_ONCE(column->mode != RS_LEGACY && | 1196 | if (WARN_ON_ONCE(column->mode != RS_LEGACY && |
1180 | column->mode != RS_SISO && | 1197 | column->mode != RS_SISO && |
@@ -1262,9 +1279,8 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, | |||
1262 | &(lq_sta->lq_info[lq_sta->active_tbl]); | 1279 | &(lq_sta->lq_info[lq_sta->active_tbl]); |
1263 | s32 active_sr = active_tbl->win[index].success_ratio; | 1280 | s32 active_sr = active_tbl->win[index].success_ratio; |
1264 | s32 active_tpt = active_tbl->expected_tpt[index]; | 1281 | s32 active_tpt = active_tbl->expected_tpt[index]; |
1265 | |||
1266 | /* expected "search" throughput */ | 1282 | /* expected "search" throughput */ |
1267 | s32 *tpt_tbl = tbl->expected_tpt; | 1283 | const u16 *tpt_tbl = tbl->expected_tpt; |
1268 | 1284 | ||
1269 | s32 new_rate, high, low, start_hi; | 1285 | s32 new_rate, high, low, start_hi; |
1270 | u16 high_low; | 1286 | u16 high_low; |
@@ -1362,7 +1378,6 @@ static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta) | |||
1362 | static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) | 1378 | static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) |
1363 | { | 1379 | { |
1364 | struct iwl_scale_tbl_info *tbl; | 1380 | struct iwl_scale_tbl_info *tbl; |
1365 | int i; | ||
1366 | int active_tbl; | 1381 | int active_tbl; |
1367 | int flush_interval_passed = 0; | 1382 | int flush_interval_passed = 0; |
1368 | struct iwl_mvm *mvm; | 1383 | struct iwl_mvm *mvm; |
@@ -1423,9 +1438,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) | |||
1423 | 1438 | ||
1424 | IWL_DEBUG_RATE(mvm, | 1439 | IWL_DEBUG_RATE(mvm, |
1425 | "LQ: stay in table clear win\n"); | 1440 | "LQ: stay in table clear win\n"); |
1426 | for (i = 0; i < IWL_RATE_COUNT; i++) | 1441 | rs_rate_scale_clear_tbl_windows(tbl); |
1427 | rs_rate_scale_clear_window( | ||
1428 | &(tbl->win[i])); | ||
1429 | } | 1442 | } |
1430 | } | 1443 | } |
1431 | 1444 | ||
@@ -1434,8 +1447,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) | |||
1434 | * "search" table). */ | 1447 | * "search" table). */ |
1435 | if (lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED) { | 1448 | if (lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED) { |
1436 | IWL_DEBUG_RATE(mvm, "Clearing up window stats\n"); | 1449 | IWL_DEBUG_RATE(mvm, "Clearing up window stats\n"); |
1437 | for (i = 0; i < IWL_RATE_COUNT; i++) | 1450 | rs_rate_scale_clear_tbl_windows(tbl); |
1438 | rs_rate_scale_clear_window(&(tbl->win[i])); | ||
1439 | } | 1451 | } |
1440 | } | 1452 | } |
1441 | } | 1453 | } |
@@ -1478,8 +1490,8 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, | |||
1478 | const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column]; | 1490 | const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column]; |
1479 | const struct rs_tx_column *next_col; | 1491 | const struct rs_tx_column *next_col; |
1480 | allow_column_func_t allow_func; | 1492 | allow_column_func_t allow_func; |
1481 | u8 valid_ants = iwl_fw_valid_tx_ant(mvm->fw); | 1493 | u8 valid_ants = mvm->fw->valid_tx_ant; |
1482 | s32 *expected_tpt_tbl; | 1494 | const u16 *expected_tpt_tbl; |
1483 | s32 tpt, max_expected_tpt; | 1495 | s32 tpt, max_expected_tpt; |
1484 | 1496 | ||
1485 | for (i = 0; i < MAX_NEXT_COLUMNS; i++) { | 1497 | for (i = 0; i < MAX_NEXT_COLUMNS; i++) { |
@@ -1725,7 +1737,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
1725 | int low = IWL_RATE_INVALID; | 1737 | int low = IWL_RATE_INVALID; |
1726 | int high = IWL_RATE_INVALID; | 1738 | int high = IWL_RATE_INVALID; |
1727 | int index; | 1739 | int index; |
1728 | int i; | ||
1729 | struct iwl_rate_scale_data *window = NULL; | 1740 | struct iwl_rate_scale_data *window = NULL; |
1730 | int current_tpt = IWL_INVALID_VALUE; | 1741 | int current_tpt = IWL_INVALID_VALUE; |
1731 | int low_tpt = IWL_INVALID_VALUE; | 1742 | int low_tpt = IWL_INVALID_VALUE; |
@@ -2010,8 +2021,7 @@ lq_update: | |||
2010 | if (lq_sta->search_better_tbl) { | 2021 | if (lq_sta->search_better_tbl) { |
2011 | /* Access the "search" table, clear its history. */ | 2022 | /* Access the "search" table, clear its history. */ |
2012 | tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); | 2023 | tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); |
2013 | for (i = 0; i < IWL_RATE_COUNT; i++) | 2024 | rs_rate_scale_clear_tbl_windows(tbl); |
2014 | rs_rate_scale_clear_window(&(tbl->win[i])); | ||
2015 | 2025 | ||
2016 | /* Use new "search" start rate */ | 2026 | /* Use new "search" start rate */ |
2017 | index = tbl->rate.index; | 2027 | index = tbl->rate.index; |
@@ -2090,7 +2100,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, | |||
2090 | 2100 | ||
2091 | i = lq_sta->last_txrate_idx; | 2101 | i = lq_sta->last_txrate_idx; |
2092 | 2102 | ||
2093 | valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); | 2103 | valid_tx_ant = mvm->fw->valid_tx_ant; |
2094 | 2104 | ||
2095 | if (!lq_sta->search_better_tbl) | 2105 | if (!lq_sta->search_better_tbl) |
2096 | active_tbl = lq_sta->active_tbl; | 2106 | active_tbl = lq_sta->active_tbl; |
@@ -2241,6 +2251,73 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta, | |||
2241 | } | 2251 | } |
2242 | } | 2252 | } |
2243 | 2253 | ||
2254 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
2255 | static void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm, | ||
2256 | struct iwl_mvm_frame_stats *stats) | ||
2257 | { | ||
2258 | spin_lock_bh(&mvm->drv_stats_lock); | ||
2259 | memset(stats, 0, sizeof(*stats)); | ||
2260 | spin_unlock_bh(&mvm->drv_stats_lock); | ||
2261 | } | ||
2262 | |||
2263 | void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, | ||
2264 | struct iwl_mvm_frame_stats *stats, | ||
2265 | u32 rate, bool agg) | ||
2266 | { | ||
2267 | u8 nss = 0, mcs = 0; | ||
2268 | |||
2269 | spin_lock(&mvm->drv_stats_lock); | ||
2270 | |||
2271 | if (agg) | ||
2272 | stats->agg_frames++; | ||
2273 | |||
2274 | stats->success_frames++; | ||
2275 | |||
2276 | switch (rate & RATE_MCS_CHAN_WIDTH_MSK) { | ||
2277 | case RATE_MCS_CHAN_WIDTH_20: | ||
2278 | stats->bw_20_frames++; | ||
2279 | break; | ||
2280 | case RATE_MCS_CHAN_WIDTH_40: | ||
2281 | stats->bw_40_frames++; | ||
2282 | break; | ||
2283 | case RATE_MCS_CHAN_WIDTH_80: | ||
2284 | stats->bw_80_frames++; | ||
2285 | break; | ||
2286 | default: | ||
2287 | WARN_ONCE(1, "bad BW. rate 0x%x", rate); | ||
2288 | } | ||
2289 | |||
2290 | if (rate & RATE_MCS_HT_MSK) { | ||
2291 | stats->ht_frames++; | ||
2292 | mcs = rate & RATE_HT_MCS_RATE_CODE_MSK; | ||
2293 | nss = ((rate & RATE_HT_MCS_NSS_MSK) >> RATE_HT_MCS_NSS_POS) + 1; | ||
2294 | } else if (rate & RATE_MCS_VHT_MSK) { | ||
2295 | stats->vht_frames++; | ||
2296 | mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK; | ||
2297 | nss = ((rate & RATE_VHT_MCS_NSS_MSK) >> | ||
2298 | RATE_VHT_MCS_NSS_POS) + 1; | ||
2299 | } else { | ||
2300 | stats->legacy_frames++; | ||
2301 | } | ||
2302 | |||
2303 | if (nss == 1) | ||
2304 | stats->siso_frames++; | ||
2305 | else if (nss == 2) | ||
2306 | stats->mimo2_frames++; | ||
2307 | |||
2308 | if (rate & RATE_MCS_SGI_MSK) | ||
2309 | stats->sgi_frames++; | ||
2310 | else | ||
2311 | stats->ngi_frames++; | ||
2312 | |||
2313 | stats->last_rates[stats->last_frame_idx] = rate; | ||
2314 | stats->last_frame_idx = (stats->last_frame_idx + 1) % | ||
2315 | ARRAY_SIZE(stats->last_rates); | ||
2316 | |||
2317 | spin_unlock(&mvm->drv_stats_lock); | ||
2318 | } | ||
2319 | #endif | ||
2320 | |||
2244 | /* | 2321 | /* |
2245 | * Called after adding a new station to initialize rate scaling | 2322 | * Called after adding a new station to initialize rate scaling |
2246 | */ | 2323 | */ |
@@ -2265,8 +2342,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2265 | lq_sta->lq.sta_id = sta_priv->sta_id; | 2342 | lq_sta->lq.sta_id = sta_priv->sta_id; |
2266 | 2343 | ||
2267 | for (j = 0; j < LQ_SIZE; j++) | 2344 | for (j = 0; j < LQ_SIZE; j++) |
2268 | for (i = 0; i < IWL_RATE_COUNT; i++) | 2345 | rs_rate_scale_clear_tbl_windows(&lq_sta->lq_info[j]); |
2269 | rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); | ||
2270 | 2346 | ||
2271 | lq_sta->flush_timer = 0; | 2347 | lq_sta->flush_timer = 0; |
2272 | 2348 | ||
@@ -2320,7 +2396,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2320 | 2396 | ||
2321 | /* These values will be overridden later */ | 2397 | /* These values will be overridden later */ |
2322 | lq_sta->lq.single_stream_ant_msk = | 2398 | lq_sta->lq.single_stream_ant_msk = |
2323 | first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); | 2399 | first_antenna(mvm->fw->valid_tx_ant); |
2324 | lq_sta->lq.dual_stream_ant_msk = ANT_AB; | 2400 | lq_sta->lq.dual_stream_ant_msk = ANT_AB; |
2325 | 2401 | ||
2326 | /* as default allow aggregation for all tids */ | 2402 | /* as default allow aggregation for all tids */ |
@@ -2335,7 +2411,9 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2335 | #ifdef CONFIG_MAC80211_DEBUGFS | 2411 | #ifdef CONFIG_MAC80211_DEBUGFS |
2336 | lq_sta->dbg_fixed_rate = 0; | 2412 | lq_sta->dbg_fixed_rate = 0; |
2337 | #endif | 2413 | #endif |
2338 | 2414 | #ifdef CONFIG_IWLWIFI_DEBUGFS | |
2415 | iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats); | ||
2416 | #endif | ||
2339 | rs_initialize_lq(mvm, sta, lq_sta, band, init); | 2417 | rs_initialize_lq(mvm, sta, lq_sta, band, init); |
2340 | } | 2418 | } |
2341 | 2419 | ||
@@ -2446,7 +2524,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, | |||
2446 | 2524 | ||
2447 | memcpy(&rate, initial_rate, sizeof(rate)); | 2525 | memcpy(&rate, initial_rate, sizeof(rate)); |
2448 | 2526 | ||
2449 | valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); | 2527 | valid_tx_ant = mvm->fw->valid_tx_ant; |
2450 | 2528 | ||
2451 | if (is_siso(&rate)) { | 2529 | if (is_siso(&rate)) { |
2452 | num_rates = RS_INITIAL_SISO_NUM_RATES; | 2530 | num_rates = RS_INITIAL_SISO_NUM_RATES; |
@@ -2523,7 +2601,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, | |||
2523 | 2601 | ||
2524 | if (sta) | 2602 | if (sta) |
2525 | lq_cmd->agg_time_limit = | 2603 | lq_cmd->agg_time_limit = |
2526 | cpu_to_le16(iwl_mvm_bt_coex_agg_time_limit(mvm, sta)); | 2604 | cpu_to_le16(iwl_mvm_coex_agg_time_limit(mvm, sta)); |
2527 | } | 2605 | } |
2528 | 2606 | ||
2529 | static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | 2607 | static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
@@ -2547,7 +2625,7 @@ static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta, | |||
2547 | } | 2625 | } |
2548 | 2626 | ||
2549 | #ifdef CONFIG_MAC80211_DEBUGFS | 2627 | #ifdef CONFIG_MAC80211_DEBUGFS |
2550 | static int rs_pretty_print_rate(char *buf, const u32 rate) | 2628 | int rs_pretty_print_rate(char *buf, const u32 rate) |
2551 | { | 2629 | { |
2552 | 2630 | ||
2553 | char *type, *bw; | 2631 | char *type, *bw; |
@@ -2596,7 +2674,7 @@ static int rs_pretty_print_rate(char *buf, const u32 rate) | |||
2596 | return sprintf(buf, "%s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s\n", | 2674 | return sprintf(buf, "%s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s\n", |
2597 | type, rs_pretty_ant(ant), bw, mcs, nss, | 2675 | type, rs_pretty_ant(ant), bw, mcs, nss, |
2598 | (rate & RATE_MCS_SGI_MSK) ? "SGI " : "NGI ", | 2676 | (rate & RATE_MCS_SGI_MSK) ? "SGI " : "NGI ", |
2599 | (rate & RATE_MCS_STBC_MSK) ? "STBC " : "", | 2677 | (rate & RATE_MCS_HT_STBC_MSK) ? "STBC " : "", |
2600 | (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "", | 2678 | (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "", |
2601 | (rate & RATE_MCS_BF_MSK) ? "BF " : "", | 2679 | (rate & RATE_MCS_BF_MSK) ? "BF " : "", |
2602 | (rate & RATE_MCS_ZLF_MSK) ? "ZLF " : ""); | 2680 | (rate & RATE_MCS_ZLF_MSK) ? "ZLF " : ""); |
@@ -2677,9 +2755,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | |||
2677 | desc += sprintf(buff+desc, "fixed rate 0x%X\n", | 2755 | desc += sprintf(buff+desc, "fixed rate 0x%X\n", |
2678 | lq_sta->dbg_fixed_rate); | 2756 | lq_sta->dbg_fixed_rate); |
2679 | desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n", | 2757 | desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n", |
2680 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_A) ? "ANT_A," : "", | 2758 | (mvm->fw->valid_tx_ant & ANT_A) ? "ANT_A," : "", |
2681 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "", | 2759 | (mvm->fw->valid_tx_ant & ANT_B) ? "ANT_B," : "", |
2682 | (iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : ""); | 2760 | (mvm->fw->valid_tx_ant & ANT_C) ? "ANT_C" : ""); |
2683 | desc += sprintf(buff+desc, "lq type %s\n", | 2761 | desc += sprintf(buff+desc, "lq type %s\n", |
2684 | (is_legacy(rate)) ? "legacy" : | 2762 | (is_legacy(rate)) ? "legacy" : |
2685 | is_vht(rate) ? "VHT" : "HT"); | 2763 | is_vht(rate) ? "VHT" : "HT"); |
@@ -2815,8 +2893,8 @@ static void rs_rate_init_stub(void *mvm_r, | |||
2815 | struct ieee80211_sta *sta, void *mvm_sta) | 2893 | struct ieee80211_sta *sta, void *mvm_sta) |
2816 | { | 2894 | { |
2817 | } | 2895 | } |
2818 | static struct rate_control_ops rs_mvm_ops = { | 2896 | |
2819 | .module = NULL, | 2897 | static const struct rate_control_ops rs_mvm_ops = { |
2820 | .name = RS_NAME, | 2898 | .name = RS_NAME, |
2821 | .tx_status = rs_tx_status, | 2899 | .tx_status = rs_tx_status, |
2822 | .get_rate = rs_get_rate, | 2900 | .get_rate = rs_get_rate, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 7bc6404f6986..3332b396011e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h | |||
@@ -277,7 +277,7 @@ enum rs_column { | |||
277 | struct iwl_scale_tbl_info { | 277 | struct iwl_scale_tbl_info { |
278 | struct rs_rate rate; | 278 | struct rs_rate rate; |
279 | enum rs_column column; | 279 | enum rs_column column; |
280 | s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ | 280 | const u16 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ |
281 | struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ | 281 | struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ |
282 | }; | 282 | }; |
283 | 283 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index a85b60f7e67e..6061553a5e44 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c | |||
@@ -77,6 +77,15 @@ int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
77 | 77 | ||
78 | memcpy(&mvm->last_phy_info, pkt->data, sizeof(mvm->last_phy_info)); | 78 | memcpy(&mvm->last_phy_info, pkt->data, sizeof(mvm->last_phy_info)); |
79 | mvm->ampdu_ref++; | 79 | mvm->ampdu_ref++; |
80 | |||
81 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
82 | if (mvm->last_phy_info.phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) { | ||
83 | spin_lock(&mvm->drv_stats_lock); | ||
84 | mvm->drv_rx_stats.ampdu_count++; | ||
85 | spin_unlock(&mvm->drv_stats_lock); | ||
86 | } | ||
87 | #endif | ||
88 | |||
80 | return 0; | 89 | return 0; |
81 | } | 90 | } |
82 | 91 | ||
@@ -129,22 +138,16 @@ static void iwl_mvm_calc_rssi(struct iwl_mvm *mvm, | |||
129 | struct ieee80211_rx_status *rx_status) | 138 | struct ieee80211_rx_status *rx_status) |
130 | { | 139 | { |
131 | int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; | 140 | int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm; |
132 | int rssi_all_band_a, rssi_all_band_b; | 141 | u32 agc_a, agc_b; |
133 | u32 agc_a, agc_b, max_agc; | ||
134 | u32 val; | 142 | u32 val; |
135 | 143 | ||
136 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); | 144 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]); |
137 | agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS; | 145 | agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS; |
138 | agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS; | 146 | agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS; |
139 | max_agc = max_t(u32, agc_a, agc_b); | ||
140 | 147 | ||
141 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]); | 148 | val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]); |
142 | rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS; | 149 | rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS; |
143 | rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; | 150 | rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS; |
144 | rssi_all_band_a = (val & IWL_OFDM_RSSI_ALLBAND_A_MSK) >> | ||
145 | IWL_OFDM_RSSI_ALLBAND_A_POS; | ||
146 | rssi_all_band_b = (val & IWL_OFDM_RSSI_ALLBAND_B_MSK) >> | ||
147 | IWL_OFDM_RSSI_ALLBAND_B_POS; | ||
148 | 151 | ||
149 | /* | 152 | /* |
150 | * dBm = rssi dB - agc dB - constant. | 153 | * dBm = rssi dB - agc dB - constant. |
@@ -364,31 +367,43 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
364 | rx_status.flag |= RX_FLAG_40MHZ; | 367 | rx_status.flag |= RX_FLAG_40MHZ; |
365 | break; | 368 | break; |
366 | case RATE_MCS_CHAN_WIDTH_80: | 369 | case RATE_MCS_CHAN_WIDTH_80: |
367 | rx_status.flag |= RX_FLAG_80MHZ; | 370 | rx_status.vht_flag |= RX_VHT_FLAG_80MHZ; |
368 | break; | 371 | break; |
369 | case RATE_MCS_CHAN_WIDTH_160: | 372 | case RATE_MCS_CHAN_WIDTH_160: |
370 | rx_status.flag |= RX_FLAG_160MHZ; | 373 | rx_status.vht_flag |= RX_VHT_FLAG_160MHZ; |
371 | break; | 374 | break; |
372 | } | 375 | } |
373 | if (rate_n_flags & RATE_MCS_SGI_MSK) | 376 | if (rate_n_flags & RATE_MCS_SGI_MSK) |
374 | rx_status.flag |= RX_FLAG_SHORT_GI; | 377 | rx_status.flag |= RX_FLAG_SHORT_GI; |
375 | if (rate_n_flags & RATE_HT_MCS_GF_MSK) | 378 | if (rate_n_flags & RATE_HT_MCS_GF_MSK) |
376 | rx_status.flag |= RX_FLAG_HT_GF; | 379 | rx_status.flag |= RX_FLAG_HT_GF; |
380 | if (rate_n_flags & RATE_MCS_LDPC_MSK) | ||
381 | rx_status.flag |= RX_FLAG_LDPC; | ||
377 | if (rate_n_flags & RATE_MCS_HT_MSK) { | 382 | if (rate_n_flags & RATE_MCS_HT_MSK) { |
383 | u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >> | ||
384 | RATE_MCS_STBC_POS; | ||
378 | rx_status.flag |= RX_FLAG_HT; | 385 | rx_status.flag |= RX_FLAG_HT; |
379 | rx_status.rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; | 386 | rx_status.rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; |
387 | rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT; | ||
380 | } else if (rate_n_flags & RATE_MCS_VHT_MSK) { | 388 | } else if (rate_n_flags & RATE_MCS_VHT_MSK) { |
389 | u8 stbc = (rate_n_flags & RATE_MCS_VHT_STBC_MSK) >> | ||
390 | RATE_MCS_STBC_POS; | ||
381 | rx_status.vht_nss = | 391 | rx_status.vht_nss = |
382 | ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> | 392 | ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> |
383 | RATE_VHT_MCS_NSS_POS) + 1; | 393 | RATE_VHT_MCS_NSS_POS) + 1; |
384 | rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; | 394 | rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; |
385 | rx_status.flag |= RX_FLAG_VHT; | 395 | rx_status.flag |= RX_FLAG_VHT; |
396 | rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT; | ||
386 | } else { | 397 | } else { |
387 | rx_status.rate_idx = | 398 | rx_status.rate_idx = |
388 | iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, | 399 | iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, |
389 | rx_status.band); | 400 | rx_status.band); |
390 | } | 401 | } |
391 | 402 | ||
403 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
404 | iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags, | ||
405 | rx_status.flag & RX_FLAG_AMPDU_DETAILS); | ||
406 | #endif | ||
392 | iwl_mvm_pass_packet_to_mac80211(mvm, hdr, len, ampdu_status, | 407 | iwl_mvm_pass_packet_to_mac80211(mvm, hdr, len, ampdu_status, |
393 | rxb, &rx_status); | 408 | rxb, &rx_status); |
394 | return 0; | 409 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 742afc429c94..c91dc8498852 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
@@ -70,9 +70,16 @@ | |||
70 | 70 | ||
71 | #define IWL_PLCP_QUIET_THRESH 1 | 71 | #define IWL_PLCP_QUIET_THRESH 1 |
72 | #define IWL_ACTIVE_QUIET_TIME 10 | 72 | #define IWL_ACTIVE_QUIET_TIME 10 |
73 | #define LONG_OUT_TIME_PERIOD 600 | 73 | |
74 | #define SHORT_OUT_TIME_PERIOD 200 | 74 | struct iwl_mvm_scan_params { |
75 | #define SUSPEND_TIME_PERIOD 100 | 75 | u32 max_out_time; |
76 | u32 suspend_time; | ||
77 | bool passive_fragmented; | ||
78 | struct _dwell { | ||
79 | u16 passive; | ||
80 | u16 active; | ||
81 | } dwell[IEEE80211_NUM_BANDS]; | ||
82 | }; | ||
76 | 83 | ||
77 | static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) | 84 | static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) |
78 | { | 85 | { |
@@ -82,7 +89,7 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) | |||
82 | if (mvm->scan_rx_ant != ANT_NONE) | 89 | if (mvm->scan_rx_ant != ANT_NONE) |
83 | rx_ant = mvm->scan_rx_ant; | 90 | rx_ant = mvm->scan_rx_ant; |
84 | else | 91 | else |
85 | rx_ant = iwl_fw_valid_rx_ant(mvm->fw); | 92 | rx_ant = mvm->fw->valid_rx_ant; |
86 | rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; | 93 | rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; |
87 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; | 94 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; |
88 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; | 95 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; |
@@ -90,24 +97,6 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) | |||
90 | return cpu_to_le16(rx_chain); | 97 | return cpu_to_le16(rx_chain); |
91 | } | 98 | } |
92 | 99 | ||
93 | static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif, | ||
94 | u32 flags, bool is_assoc) | ||
95 | { | ||
96 | if (!is_assoc) | ||
97 | return 0; | ||
98 | if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY) | ||
99 | return cpu_to_le32(ieee80211_tu_to_usec(SHORT_OUT_TIME_PERIOD)); | ||
100 | return cpu_to_le32(ieee80211_tu_to_usec(LONG_OUT_TIME_PERIOD)); | ||
101 | } | ||
102 | |||
103 | static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif, | ||
104 | bool is_assoc) | ||
105 | { | ||
106 | if (!is_assoc) | ||
107 | return 0; | ||
108 | return cpu_to_le32(ieee80211_tu_to_usec(SUSPEND_TIME_PERIOD)); | ||
109 | } | ||
110 | |||
111 | static inline __le32 | 100 | static inline __le32 |
112 | iwl_mvm_scan_rxon_flags(struct cfg80211_scan_request *req) | 101 | iwl_mvm_scan_rxon_flags(struct cfg80211_scan_request *req) |
113 | { | 102 | { |
@@ -124,7 +113,7 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band, | |||
124 | u32 tx_ant; | 113 | u32 tx_ant; |
125 | 114 | ||
126 | mvm->scan_last_antenna_idx = | 115 | mvm->scan_last_antenna_idx = |
127 | iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw), | 116 | iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, |
128 | mvm->scan_last_antenna_idx); | 117 | mvm->scan_last_antenna_idx); |
129 | tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS; | 118 | tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS; |
130 | 119 | ||
@@ -181,15 +170,14 @@ static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band) | |||
181 | 170 | ||
182 | static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, | 171 | static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, |
183 | struct cfg80211_scan_request *req, | 172 | struct cfg80211_scan_request *req, |
184 | bool basic_ssid) | 173 | bool basic_ssid, |
174 | struct iwl_mvm_scan_params *params) | ||
185 | { | 175 | { |
186 | u16 passive_dwell = iwl_mvm_get_passive_dwell(req->channels[0]->band); | ||
187 | u16 active_dwell = iwl_mvm_get_active_dwell(req->channels[0]->band, | ||
188 | req->n_ssids); | ||
189 | struct iwl_scan_channel *chan = (struct iwl_scan_channel *) | 176 | struct iwl_scan_channel *chan = (struct iwl_scan_channel *) |
190 | (cmd->data + le16_to_cpu(cmd->tx_cmd.len)); | 177 | (cmd->data + le16_to_cpu(cmd->tx_cmd.len)); |
191 | int i; | 178 | int i; |
192 | int type = BIT(req->n_ssids) - 1; | 179 | int type = BIT(req->n_ssids) - 1; |
180 | enum ieee80211_band band = req->channels[0]->band; | ||
193 | 181 | ||
194 | if (!basic_ssid) | 182 | if (!basic_ssid) |
195 | type |= BIT(req->n_ssids); | 183 | type |= BIT(req->n_ssids); |
@@ -199,8 +187,8 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, | |||
199 | chan->type = cpu_to_le32(type); | 187 | chan->type = cpu_to_le32(type); |
200 | if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR) | 188 | if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR) |
201 | chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE); | 189 | chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE); |
202 | chan->active_dwell = cpu_to_le16(active_dwell); | 190 | chan->active_dwell = cpu_to_le16(params->dwell[band].active); |
203 | chan->passive_dwell = cpu_to_le16(passive_dwell); | 191 | chan->passive_dwell = cpu_to_le16(params->dwell[band].passive); |
204 | chan->iteration_count = cpu_to_le16(1); | 192 | chan->iteration_count = cpu_to_le16(1); |
205 | chan++; | 193 | chan++; |
206 | } | 194 | } |
@@ -267,13 +255,76 @@ static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, | |||
267 | return (u16)len; | 255 | return (u16)len; |
268 | } | 256 | } |
269 | 257 | ||
270 | static void iwl_mvm_vif_assoc_iterator(void *data, u8 *mac, | 258 | static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, |
271 | struct ieee80211_vif *vif) | 259 | struct ieee80211_vif *vif) |
272 | { | 260 | { |
273 | bool *is_assoc = data; | 261 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
262 | bool *global_bound = data; | ||
263 | |||
264 | if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < MAX_PHYS) | ||
265 | *global_bound = true; | ||
266 | } | ||
267 | |||
268 | static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, | ||
269 | struct ieee80211_vif *vif, | ||
270 | int n_ssids, | ||
271 | struct iwl_mvm_scan_params *params) | ||
272 | { | ||
273 | bool global_bound = false; | ||
274 | enum ieee80211_band band; | ||
275 | |||
276 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | ||
277 | IEEE80211_IFACE_ITER_NORMAL, | ||
278 | iwl_mvm_scan_condition_iterator, | ||
279 | &global_bound); | ||
280 | /* | ||
281 | * Under low latency traffic passive scan is fragmented meaning | ||
282 | * that dwell on a particular channel will be fragmented. Each fragment | ||
283 | * dwell time is 20ms and fragments period is 105ms. Skipping to next | ||
284 | * channel will be delayed by the same period - 105ms. So suspend_time | ||
285 | * parameter describing both fragments and channels skipping periods is | ||
286 | * set to 105ms. This value is chosen so that overall passive scan | ||
287 | * duration will not be too long. Max_out_time in this case is set to | ||
288 | * 70ms, so for active scanning operating channel will be left for 70ms | ||
289 | * while for passive still for 20ms (fragment dwell). | ||
290 | */ | ||
291 | if (global_bound) { | ||
292 | if (!iwl_mvm_low_latency(mvm)) { | ||
293 | params->suspend_time = ieee80211_tu_to_usec(100); | ||
294 | params->max_out_time = ieee80211_tu_to_usec(600); | ||
295 | } else { | ||
296 | params->suspend_time = ieee80211_tu_to_usec(105); | ||
297 | /* P2P doesn't support fragmented passive scan, so | ||
298 | * configure max_out_time to be at least longest dwell | ||
299 | * time for passive scan. | ||
300 | */ | ||
301 | if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p) { | ||
302 | params->max_out_time = ieee80211_tu_to_usec(70); | ||
303 | params->passive_fragmented = true; | ||
304 | } else { | ||
305 | u32 passive_dwell; | ||
274 | 306 | ||
275 | if (vif->bss_conf.assoc) | 307 | /* |
276 | *is_assoc = true; | 308 | * Use band G so that passive channel dwell time |
309 | * will be assigned with maximum value. | ||
310 | */ | ||
311 | band = IEEE80211_BAND_2GHZ; | ||
312 | passive_dwell = iwl_mvm_get_passive_dwell(band); | ||
313 | params->max_out_time = | ||
314 | ieee80211_tu_to_usec(passive_dwell); | ||
315 | } | ||
316 | } | ||
317 | } | ||
318 | |||
319 | for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { | ||
320 | if (params->passive_fragmented) | ||
321 | params->dwell[band].passive = 20; | ||
322 | else | ||
323 | params->dwell[band].passive = | ||
324 | iwl_mvm_get_passive_dwell(band); | ||
325 | params->dwell[band].active = iwl_mvm_get_active_dwell(band, | ||
326 | n_ssids); | ||
327 | } | ||
277 | } | 328 | } |
278 | 329 | ||
279 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, | 330 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, |
@@ -288,13 +339,13 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, | |||
288 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | 339 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, |
289 | }; | 340 | }; |
290 | struct iwl_scan_cmd *cmd = mvm->scan_cmd; | 341 | struct iwl_scan_cmd *cmd = mvm->scan_cmd; |
291 | bool is_assoc = false; | ||
292 | int ret; | 342 | int ret; |
293 | u32 status; | 343 | u32 status; |
294 | int ssid_len = 0; | 344 | int ssid_len = 0; |
295 | u8 *ssid = NULL; | 345 | u8 *ssid = NULL; |
296 | bool basic_ssid = !(mvm->fw->ucode_capa.flags & | 346 | bool basic_ssid = !(mvm->fw->ucode_capa.flags & |
297 | IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID); | 347 | IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID); |
348 | struct iwl_mvm_scan_params params = {}; | ||
298 | 349 | ||
299 | lockdep_assert_held(&mvm->mutex); | 350 | lockdep_assert_held(&mvm->mutex); |
300 | BUG_ON(mvm->scan_cmd == NULL); | 351 | BUG_ON(mvm->scan_cmd == NULL); |
@@ -304,17 +355,18 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, | |||
304 | memset(cmd, 0, sizeof(struct iwl_scan_cmd) + | 355 | memset(cmd, 0, sizeof(struct iwl_scan_cmd) + |
305 | mvm->fw->ucode_capa.max_probe_length + | 356 | mvm->fw->ucode_capa.max_probe_length + |
306 | (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel))); | 357 | (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel))); |
307 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | 358 | |
308 | IEEE80211_IFACE_ITER_NORMAL, | ||
309 | iwl_mvm_vif_assoc_iterator, | ||
310 | &is_assoc); | ||
311 | cmd->channel_count = (u8)req->n_channels; | 359 | cmd->channel_count = (u8)req->n_channels; |
312 | cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME); | 360 | cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME); |
313 | cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); | 361 | cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); |
314 | cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm); | 362 | cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm); |
315 | cmd->max_out_time = iwl_mvm_scan_max_out_time(vif, req->flags, | 363 | |
316 | is_assoc); | 364 | iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, ¶ms); |
317 | cmd->suspend_time = iwl_mvm_scan_suspend_time(vif, is_assoc); | 365 | cmd->max_out_time = cpu_to_le32(params.max_out_time); |
366 | cmd->suspend_time = cpu_to_le32(params.suspend_time); | ||
367 | if (params.passive_fragmented) | ||
368 | cmd->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN; | ||
369 | |||
318 | cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req); | 370 | cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req); |
319 | cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | | 371 | cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | |
320 | MAC_FILTER_IN_BEACON); | 372 | MAC_FILTER_IN_BEACON); |
@@ -360,7 +412,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, | |||
360 | req->ie, req->ie_len, | 412 | req->ie, req->ie_len, |
361 | mvm->fw->ucode_capa.max_probe_length)); | 413 | mvm->fw->ucode_capa.max_probe_length)); |
362 | 414 | ||
363 | iwl_mvm_scan_fill_channels(cmd, req, basic_ssid); | 415 | iwl_mvm_scan_fill_channels(cmd, req, basic_ssid, ¶ms); |
364 | 416 | ||
365 | cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) + | 417 | cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) + |
366 | le16_to_cpu(cmd->tx_cmd.len) + | 418 | le16_to_cpu(cmd->tx_cmd.len) + |
@@ -402,12 +454,17 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
402 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 454 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
403 | struct iwl_scan_complete_notif *notif = (void *)pkt->data; | 455 | struct iwl_scan_complete_notif *notif = (void *)pkt->data; |
404 | 456 | ||
457 | lockdep_assert_held(&mvm->mutex); | ||
458 | |||
405 | IWL_DEBUG_SCAN(mvm, "Scan complete: status=0x%x scanned channels=%d\n", | 459 | IWL_DEBUG_SCAN(mvm, "Scan complete: status=0x%x scanned channels=%d\n", |
406 | notif->status, notif->scanned_channels); | 460 | notif->status, notif->scanned_channels); |
407 | 461 | ||
408 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 462 | if (mvm->scan_status == IWL_MVM_SCAN_OS) |
463 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
409 | ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK); | 464 | ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK); |
410 | 465 | ||
466 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
467 | |||
411 | return 0; | 468 | return 0; |
412 | } | 469 | } |
413 | 470 | ||
@@ -464,7 +521,7 @@ static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait, | |||
464 | }; | 521 | }; |
465 | } | 522 | } |
466 | 523 | ||
467 | void iwl_mvm_cancel_scan(struct iwl_mvm *mvm) | 524 | int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) |
468 | { | 525 | { |
469 | struct iwl_notification_wait wait_scan_abort; | 526 | struct iwl_notification_wait wait_scan_abort; |
470 | static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD, | 527 | static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD, |
@@ -472,12 +529,13 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm) | |||
472 | int ret; | 529 | int ret; |
473 | 530 | ||
474 | if (mvm->scan_status == IWL_MVM_SCAN_NONE) | 531 | if (mvm->scan_status == IWL_MVM_SCAN_NONE) |
475 | return; | 532 | return 0; |
476 | 533 | ||
477 | if (iwl_mvm_is_radio_killed(mvm)) { | 534 | if (iwl_mvm_is_radio_killed(mvm)) { |
478 | ieee80211_scan_completed(mvm->hw, true); | 535 | ieee80211_scan_completed(mvm->hw, true); |
536 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
479 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 537 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
480 | return; | 538 | return 0; |
481 | } | 539 | } |
482 | 540 | ||
483 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort, | 541 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort, |
@@ -488,18 +546,15 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm) | |||
488 | ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, CMD_SYNC, 0, NULL); | 546 | ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, CMD_SYNC, 0, NULL); |
489 | if (ret) { | 547 | if (ret) { |
490 | IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret); | 548 | IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret); |
491 | /* mac80211's state will be cleaned in the fw_restart flow */ | 549 | /* mac80211's state will be cleaned in the nic_restart flow */ |
492 | goto out_remove_notif; | 550 | goto out_remove_notif; |
493 | } | 551 | } |
494 | 552 | ||
495 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, 1 * HZ); | 553 | return iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, HZ); |
496 | if (ret) | ||
497 | IWL_ERR(mvm, "%s - failed on timeout\n", __func__); | ||
498 | |||
499 | return; | ||
500 | 554 | ||
501 | out_remove_notif: | 555 | out_remove_notif: |
502 | iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort); | 556 | iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort); |
557 | return ret; | ||
503 | } | 558 | } |
504 | 559 | ||
505 | int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, | 560 | int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, |
@@ -509,12 +564,18 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, | |||
509 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 564 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
510 | struct iwl_scan_offload_complete *scan_notif = (void *)pkt->data; | 565 | struct iwl_scan_offload_complete *scan_notif = (void *)pkt->data; |
511 | 566 | ||
567 | /* scan status must be locked for proper checking */ | ||
568 | lockdep_assert_held(&mvm->mutex); | ||
569 | |||
512 | IWL_DEBUG_SCAN(mvm, "Scheduled scan completed, status %s\n", | 570 | IWL_DEBUG_SCAN(mvm, "Scheduled scan completed, status %s\n", |
513 | scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? | 571 | scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? |
514 | "completed" : "aborted"); | 572 | "completed" : "aborted"); |
515 | 573 | ||
516 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 574 | /* only call mac80211 completion if the stop was initiated by FW */ |
517 | ieee80211_sched_scan_stopped(mvm->hw); | 575 | if (mvm->scan_status == IWL_MVM_SCAN_SCHED) { |
576 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
577 | ieee80211_sched_scan_stopped(mvm->hw); | ||
578 | } | ||
518 | 579 | ||
519 | return 0; | 580 | return 0; |
520 | } | 581 | } |
@@ -545,14 +606,9 @@ static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm, | |||
545 | static void iwl_build_scan_cmd(struct iwl_mvm *mvm, | 606 | static void iwl_build_scan_cmd(struct iwl_mvm *mvm, |
546 | struct ieee80211_vif *vif, | 607 | struct ieee80211_vif *vif, |
547 | struct cfg80211_sched_scan_request *req, | 608 | struct cfg80211_sched_scan_request *req, |
548 | struct iwl_scan_offload_cmd *scan) | 609 | struct iwl_scan_offload_cmd *scan, |
610 | struct iwl_mvm_scan_params *params) | ||
549 | { | 611 | { |
550 | bool is_assoc = false; | ||
551 | |||
552 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | ||
553 | IEEE80211_IFACE_ITER_NORMAL, | ||
554 | iwl_mvm_vif_assoc_iterator, | ||
555 | &is_assoc); | ||
556 | scan->channel_count = | 612 | scan->channel_count = |
557 | mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels + | 613 | mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels + |
558 | mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; | 614 | mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; |
@@ -560,13 +616,17 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm, | |||
560 | scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); | 616 | scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); |
561 | scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT; | 617 | scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT; |
562 | scan->rx_chain = iwl_mvm_scan_rx_chain(mvm); | 618 | scan->rx_chain = iwl_mvm_scan_rx_chain(mvm); |
563 | scan->max_out_time = iwl_mvm_scan_max_out_time(vif, req->flags, | 619 | |
564 | is_assoc); | 620 | scan->max_out_time = cpu_to_le32(params->max_out_time); |
565 | scan->suspend_time = iwl_mvm_scan_suspend_time(vif, is_assoc); | 621 | scan->suspend_time = cpu_to_le32(params->suspend_time); |
622 | |||
566 | scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP | | 623 | scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP | |
567 | MAC_FILTER_IN_BEACON); | 624 | MAC_FILTER_IN_BEACON); |
568 | scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND); | 625 | scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND); |
569 | scan->rep_count = cpu_to_le32(1); | 626 | scan->rep_count = cpu_to_le32(1); |
627 | |||
628 | if (params->passive_fragmented) | ||
629 | scan->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN; | ||
570 | } | 630 | } |
571 | 631 | ||
572 | static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list) | 632 | static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list) |
@@ -596,6 +656,9 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req, | |||
596 | * config match list. | 656 | * config match list. |
597 | */ | 657 | */ |
598 | for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) { | 658 | for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) { |
659 | /* skip empty SSID matchsets */ | ||
660 | if (!req->match_sets[i].ssid.ssid_len) | ||
661 | continue; | ||
599 | scan->direct_scan[i].id = WLAN_EID_SSID; | 662 | scan->direct_scan[i].id = WLAN_EID_SSID; |
600 | scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len; | 663 | scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len; |
601 | memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid, | 664 | memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid, |
@@ -628,12 +691,11 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm, | |||
628 | struct iwl_scan_channel_cfg *channels, | 691 | struct iwl_scan_channel_cfg *channels, |
629 | enum ieee80211_band band, | 692 | enum ieee80211_band band, |
630 | int *head, int *tail, | 693 | int *head, int *tail, |
631 | u32 ssid_bitmap) | 694 | u32 ssid_bitmap, |
695 | struct iwl_mvm_scan_params *params) | ||
632 | { | 696 | { |
633 | struct ieee80211_supported_band *s_band; | 697 | struct ieee80211_supported_band *s_band; |
634 | int n_probes = req->n_ssids; | ||
635 | int n_channels = req->n_channels; | 698 | int n_channels = req->n_channels; |
636 | u8 active_dwell, passive_dwell; | ||
637 | int i, j, index = 0; | 699 | int i, j, index = 0; |
638 | bool partial; | 700 | bool partial; |
639 | 701 | ||
@@ -643,8 +705,6 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm, | |||
643 | * to scan. So add requested channels to head of the list and others to | 705 | * to scan. So add requested channels to head of the list and others to |
644 | * the end. | 706 | * the end. |
645 | */ | 707 | */ |
646 | active_dwell = iwl_mvm_get_active_dwell(band, n_probes); | ||
647 | passive_dwell = iwl_mvm_get_passive_dwell(band); | ||
648 | s_band = &mvm->nvm_data->bands[band]; | 708 | s_band = &mvm->nvm_data->bands[band]; |
649 | 709 | ||
650 | for (i = 0; i < s_band->n_channels && *head <= *tail; i++) { | 710 | for (i = 0; i < s_band->n_channels && *head <= *tail; i++) { |
@@ -668,8 +728,8 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm, | |||
668 | channels->channel_number[index] = | 728 | channels->channel_number[index] = |
669 | cpu_to_le16(ieee80211_frequency_to_channel( | 729 | cpu_to_le16(ieee80211_frequency_to_channel( |
670 | s_band->channels[i].center_freq)); | 730 | s_band->channels[i].center_freq)); |
671 | channels->dwell_time[index][0] = active_dwell; | 731 | channels->dwell_time[index][0] = params->dwell[band].active; |
672 | channels->dwell_time[index][1] = passive_dwell; | 732 | channels->dwell_time[index][1] = params->dwell[band].passive; |
673 | 733 | ||
674 | channels->iter_count[index] = cpu_to_le16(1); | 734 | channels->iter_count[index] = cpu_to_le16(1); |
675 | channels->iter_interval[index] = 0; | 735 | channels->iter_interval[index] = 0; |
@@ -698,7 +758,6 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, | |||
698 | struct cfg80211_sched_scan_request *req, | 758 | struct cfg80211_sched_scan_request *req, |
699 | struct ieee80211_sched_scan_ies *ies) | 759 | struct ieee80211_sched_scan_ies *ies) |
700 | { | 760 | { |
701 | int supported_bands = 0; | ||
702 | int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels; | 761 | int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels; |
703 | int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; | 762 | int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; |
704 | int head = 0; | 763 | int head = 0; |
@@ -712,22 +771,19 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, | |||
712 | .id = SCAN_OFFLOAD_CONFIG_CMD, | 771 | .id = SCAN_OFFLOAD_CONFIG_CMD, |
713 | .flags = CMD_SYNC, | 772 | .flags = CMD_SYNC, |
714 | }; | 773 | }; |
774 | struct iwl_mvm_scan_params params = {}; | ||
715 | 775 | ||
716 | lockdep_assert_held(&mvm->mutex); | 776 | lockdep_assert_held(&mvm->mutex); |
717 | 777 | ||
718 | if (band_2ghz) | ||
719 | supported_bands++; | ||
720 | if (band_5ghz) | ||
721 | supported_bands++; | ||
722 | |||
723 | cmd_len = sizeof(struct iwl_scan_offload_cfg) + | 778 | cmd_len = sizeof(struct iwl_scan_offload_cfg) + |
724 | supported_bands * SCAN_OFFLOAD_PROBE_REQ_SIZE; | 779 | 2 * SCAN_OFFLOAD_PROBE_REQ_SIZE; |
725 | 780 | ||
726 | scan_cfg = kzalloc(cmd_len, GFP_KERNEL); | 781 | scan_cfg = kzalloc(cmd_len, GFP_KERNEL); |
727 | if (!scan_cfg) | 782 | if (!scan_cfg) |
728 | return -ENOMEM; | 783 | return -ENOMEM; |
729 | 784 | ||
730 | iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd); | 785 | iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, ¶ms); |
786 | iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd, ¶ms); | ||
731 | scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len); | 787 | scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len); |
732 | 788 | ||
733 | iwl_scan_offload_build_ssid(req, &scan_cfg->scan_cmd, &ssid_bitmap); | 789 | iwl_scan_offload_build_ssid(req, &scan_cfg->scan_cmd, &ssid_bitmap); |
@@ -739,7 +795,7 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, | |||
739 | scan_cfg->data); | 795 | scan_cfg->data); |
740 | iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg, | 796 | iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg, |
741 | IEEE80211_BAND_2GHZ, &head, &tail, | 797 | IEEE80211_BAND_2GHZ, &head, &tail, |
742 | ssid_bitmap); | 798 | ssid_bitmap, ¶ms); |
743 | } | 799 | } |
744 | if (band_5ghz) { | 800 | if (band_5ghz) { |
745 | iwl_scan_offload_build_tx_cmd(mvm, vif, ies, | 801 | iwl_scan_offload_build_tx_cmd(mvm, vif, ies, |
@@ -749,7 +805,7 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, | |||
749 | SCAN_OFFLOAD_PROBE_REQ_SIZE); | 805 | SCAN_OFFLOAD_PROBE_REQ_SIZE); |
750 | iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg, | 806 | iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg, |
751 | IEEE80211_BAND_5GHZ, &head, &tail, | 807 | IEEE80211_BAND_5GHZ, &head, &tail, |
752 | ssid_bitmap); | 808 | ssid_bitmap, ¶ms); |
753 | } | 809 | } |
754 | 810 | ||
755 | cmd.data[0] = scan_cfg; | 811 | cmd.data[0] = scan_cfg; |
@@ -889,26 +945,49 @@ static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm) | |||
889 | * microcode has notified us that a scan is completed. | 945 | * microcode has notified us that a scan is completed. |
890 | */ | 946 | */ |
891 | IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status); | 947 | IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status); |
892 | ret = -EIO; | 948 | ret = -ENOENT; |
893 | } | 949 | } |
894 | 950 | ||
895 | return ret; | 951 | return ret; |
896 | } | 952 | } |
897 | 953 | ||
898 | void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm) | 954 | int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm) |
899 | { | 955 | { |
900 | int ret; | 956 | int ret; |
957 | struct iwl_notification_wait wait_scan_done; | ||
958 | static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, }; | ||
901 | 959 | ||
902 | lockdep_assert_held(&mvm->mutex); | 960 | lockdep_assert_held(&mvm->mutex); |
903 | 961 | ||
904 | if (mvm->scan_status != IWL_MVM_SCAN_SCHED) { | 962 | if (mvm->scan_status != IWL_MVM_SCAN_SCHED) { |
905 | IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n"); | 963 | IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n"); |
906 | return; | 964 | return 0; |
907 | } | 965 | } |
908 | 966 | ||
967 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done, | ||
968 | scan_done_notif, | ||
969 | ARRAY_SIZE(scan_done_notif), | ||
970 | NULL, NULL); | ||
971 | |||
909 | ret = iwl_mvm_send_sched_scan_abort(mvm); | 972 | ret = iwl_mvm_send_sched_scan_abort(mvm); |
910 | if (ret) | 973 | if (ret) { |
911 | IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret); | 974 | IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret); |
912 | else | 975 | iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); |
913 | IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n"); | 976 | return ret; |
977 | } | ||
978 | |||
979 | IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n"); | ||
980 | |||
981 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ); | ||
982 | if (ret) | ||
983 | return ret; | ||
984 | |||
985 | /* | ||
986 | * Clear the scan status so the next scan requests will succeed. This | ||
987 | * also ensures the Rx handler doesn't do anything, as the scan was | ||
988 | * stopped from above. | ||
989 | */ | ||
990 | mvm->scan_status = IWL_MVM_SCAN_NONE; | ||
991 | |||
992 | return 0; | ||
914 | } | 993 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 3397f59cd4e4..f339ef884250 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -66,27 +66,27 @@ | |||
66 | #include "sta.h" | 66 | #include "sta.h" |
67 | #include "rs.h" | 67 | #include "rs.h" |
68 | 68 | ||
69 | static void iwl_mvm_add_sta_cmd_v6_to_v5(struct iwl_mvm_add_sta_cmd_v6 *cmd_v6, | 69 | static void iwl_mvm_add_sta_cmd_v7_to_v5(struct iwl_mvm_add_sta_cmd_v7 *cmd_v7, |
70 | struct iwl_mvm_add_sta_cmd_v5 *cmd_v5) | 70 | struct iwl_mvm_add_sta_cmd_v5 *cmd_v5) |
71 | { | 71 | { |
72 | memset(cmd_v5, 0, sizeof(*cmd_v5)); | 72 | memset(cmd_v5, 0, sizeof(*cmd_v5)); |
73 | 73 | ||
74 | cmd_v5->add_modify = cmd_v6->add_modify; | 74 | cmd_v5->add_modify = cmd_v7->add_modify; |
75 | cmd_v5->tid_disable_tx = cmd_v6->tid_disable_tx; | 75 | cmd_v5->tid_disable_tx = cmd_v7->tid_disable_tx; |
76 | cmd_v5->mac_id_n_color = cmd_v6->mac_id_n_color; | 76 | cmd_v5->mac_id_n_color = cmd_v7->mac_id_n_color; |
77 | memcpy(cmd_v5->addr, cmd_v6->addr, ETH_ALEN); | 77 | memcpy(cmd_v5->addr, cmd_v7->addr, ETH_ALEN); |
78 | cmd_v5->sta_id = cmd_v6->sta_id; | 78 | cmd_v5->sta_id = cmd_v7->sta_id; |
79 | cmd_v5->modify_mask = cmd_v6->modify_mask; | 79 | cmd_v5->modify_mask = cmd_v7->modify_mask; |
80 | cmd_v5->station_flags = cmd_v6->station_flags; | 80 | cmd_v5->station_flags = cmd_v7->station_flags; |
81 | cmd_v5->station_flags_msk = cmd_v6->station_flags_msk; | 81 | cmd_v5->station_flags_msk = cmd_v7->station_flags_msk; |
82 | cmd_v5->add_immediate_ba_tid = cmd_v6->add_immediate_ba_tid; | 82 | cmd_v5->add_immediate_ba_tid = cmd_v7->add_immediate_ba_tid; |
83 | cmd_v5->remove_immediate_ba_tid = cmd_v6->remove_immediate_ba_tid; | 83 | cmd_v5->remove_immediate_ba_tid = cmd_v7->remove_immediate_ba_tid; |
84 | cmd_v5->add_immediate_ba_ssn = cmd_v6->add_immediate_ba_ssn; | 84 | cmd_v5->add_immediate_ba_ssn = cmd_v7->add_immediate_ba_ssn; |
85 | cmd_v5->sleep_tx_count = cmd_v6->sleep_tx_count; | 85 | cmd_v5->sleep_tx_count = cmd_v7->sleep_tx_count; |
86 | cmd_v5->sleep_state_flags = cmd_v6->sleep_state_flags; | 86 | cmd_v5->sleep_state_flags = cmd_v7->sleep_state_flags; |
87 | cmd_v5->assoc_id = cmd_v6->assoc_id; | 87 | cmd_v5->assoc_id = cmd_v7->assoc_id; |
88 | cmd_v5->beamform_flags = cmd_v6->beamform_flags; | 88 | cmd_v5->beamform_flags = cmd_v7->beamform_flags; |
89 | cmd_v5->tfd_queue_msk = cmd_v6->tfd_queue_msk; | 89 | cmd_v5->tfd_queue_msk = cmd_v7->tfd_queue_msk; |
90 | } | 90 | } |
91 | 91 | ||
92 | static void | 92 | static void |
@@ -110,7 +110,7 @@ iwl_mvm_add_sta_key_to_add_sta_cmd_v5(struct iwl_mvm_add_sta_key_cmd *key_cmd, | |||
110 | } | 110 | } |
111 | 111 | ||
112 | static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm, | 112 | static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm, |
113 | struct iwl_mvm_add_sta_cmd_v6 *cmd, | 113 | struct iwl_mvm_add_sta_cmd_v7 *cmd, |
114 | int *status) | 114 | int *status) |
115 | { | 115 | { |
116 | struct iwl_mvm_add_sta_cmd_v5 cmd_v5; | 116 | struct iwl_mvm_add_sta_cmd_v5 cmd_v5; |
@@ -119,14 +119,14 @@ static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm, | |||
119 | return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(*cmd), | 119 | return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(*cmd), |
120 | cmd, status); | 120 | cmd, status); |
121 | 121 | ||
122 | iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5); | 122 | iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5); |
123 | 123 | ||
124 | return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd_v5), | 124 | return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd_v5), |
125 | &cmd_v5, status); | 125 | &cmd_v5, status); |
126 | } | 126 | } |
127 | 127 | ||
128 | static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags, | 128 | static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags, |
129 | struct iwl_mvm_add_sta_cmd_v6 *cmd) | 129 | struct iwl_mvm_add_sta_cmd_v7 *cmd) |
130 | { | 130 | { |
131 | struct iwl_mvm_add_sta_cmd_v5 cmd_v5; | 131 | struct iwl_mvm_add_sta_cmd_v5 cmd_v5; |
132 | 132 | ||
@@ -134,7 +134,7 @@ static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags, | |||
134 | return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, | 134 | return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, |
135 | sizeof(*cmd), cmd); | 135 | sizeof(*cmd), cmd); |
136 | 136 | ||
137 | iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5); | 137 | iwl_mvm_add_sta_cmd_v7_to_v5(cmd, &cmd_v5); |
138 | 138 | ||
139 | return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(cmd_v5), | 139 | return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(cmd_v5), |
140 | &cmd_v5); | 140 | &cmd_v5); |
@@ -175,19 +175,30 @@ static int iwl_mvm_send_add_sta_key_cmd(struct iwl_mvm *mvm, | |||
175 | &sta_cmd); | 175 | &sta_cmd); |
176 | } | 176 | } |
177 | 177 | ||
178 | static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm) | 178 | static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, |
179 | enum nl80211_iftype iftype) | ||
179 | { | 180 | { |
180 | int sta_id; | 181 | int sta_id; |
182 | u32 reserved_ids = 0; | ||
181 | 183 | ||
184 | BUILD_BUG_ON(IWL_MVM_STATION_COUNT > 32); | ||
182 | WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)); | 185 | WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)); |
183 | 186 | ||
184 | lockdep_assert_held(&mvm->mutex); | 187 | lockdep_assert_held(&mvm->mutex); |
185 | 188 | ||
189 | /* d0i3/d3 assumes the AP's sta_id (of sta vif) is 0. reserve it. */ | ||
190 | if (iftype != NL80211_IFTYPE_STATION) | ||
191 | reserved_ids = BIT(0); | ||
192 | |||
186 | /* Don't take rcu_read_lock() since we are protected by mvm->mutex */ | 193 | /* Don't take rcu_read_lock() since we are protected by mvm->mutex */ |
187 | for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++) | 194 | for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++) { |
195 | if (BIT(sta_id) & reserved_ids) | ||
196 | continue; | ||
197 | |||
188 | if (!rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], | 198 | if (!rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], |
189 | lockdep_is_held(&mvm->mutex))) | 199 | lockdep_is_held(&mvm->mutex))) |
190 | return sta_id; | 200 | return sta_id; |
201 | } | ||
191 | return IWL_MVM_STATION_COUNT; | 202 | return IWL_MVM_STATION_COUNT; |
192 | } | 203 | } |
193 | 204 | ||
@@ -196,7 +207,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
196 | bool update) | 207 | bool update) |
197 | { | 208 | { |
198 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 209 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
199 | struct iwl_mvm_add_sta_cmd_v6 add_sta_cmd; | 210 | struct iwl_mvm_add_sta_cmd_v7 add_sta_cmd; |
200 | int ret; | 211 | int ret; |
201 | u32 status; | 212 | u32 status; |
202 | u32 agg_size = 0, mpdu_dens = 0; | 213 | u32 agg_size = 0, mpdu_dens = 0; |
@@ -312,7 +323,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
312 | lockdep_assert_held(&mvm->mutex); | 323 | lockdep_assert_held(&mvm->mutex); |
313 | 324 | ||
314 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | 325 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) |
315 | sta_id = iwl_mvm_find_free_sta_id(mvm); | 326 | sta_id = iwl_mvm_find_free_sta_id(mvm, |
327 | ieee80211_vif_type_p2p(vif)); | ||
316 | else | 328 | else |
317 | sta_id = mvm_sta->sta_id; | 329 | sta_id = mvm_sta->sta_id; |
318 | 330 | ||
@@ -368,7 +380,7 @@ int iwl_mvm_update_sta(struct iwl_mvm *mvm, | |||
368 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | 380 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, |
369 | bool drain) | 381 | bool drain) |
370 | { | 382 | { |
371 | struct iwl_mvm_add_sta_cmd_v6 cmd = {}; | 383 | struct iwl_mvm_add_sta_cmd_v7 cmd = {}; |
372 | int ret; | 384 | int ret; |
373 | u32 status; | 385 | u32 status; |
374 | 386 | ||
@@ -522,6 +534,10 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | |||
522 | 534 | ||
523 | /* unassoc - go ahead - remove the AP STA now */ | 535 | /* unassoc - go ahead - remove the AP STA now */ |
524 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | 536 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; |
537 | |||
538 | /* clear d0i3_ap_sta_id if no longer relevant */ | ||
539 | if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id) | ||
540 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | ||
525 | } | 541 | } |
526 | 542 | ||
527 | /* | 543 | /* |
@@ -560,10 +576,10 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm, | |||
560 | } | 576 | } |
561 | 577 | ||
562 | int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, | 578 | int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, |
563 | u32 qmask) | 579 | u32 qmask, enum nl80211_iftype iftype) |
564 | { | 580 | { |
565 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | 581 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { |
566 | sta->sta_id = iwl_mvm_find_free_sta_id(mvm); | 582 | sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype); |
567 | if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_STATION_COUNT)) | 583 | if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_STATION_COUNT)) |
568 | return -ENOSPC; | 584 | return -ENOSPC; |
569 | } | 585 | } |
@@ -587,13 +603,13 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, | |||
587 | const u8 *addr, | 603 | const u8 *addr, |
588 | u16 mac_id, u16 color) | 604 | u16 mac_id, u16 color) |
589 | { | 605 | { |
590 | struct iwl_mvm_add_sta_cmd_v6 cmd; | 606 | struct iwl_mvm_add_sta_cmd_v7 cmd; |
591 | int ret; | 607 | int ret; |
592 | u32 status; | 608 | u32 status; |
593 | 609 | ||
594 | lockdep_assert_held(&mvm->mutex); | 610 | lockdep_assert_held(&mvm->mutex); |
595 | 611 | ||
596 | memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v6)); | 612 | memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v7)); |
597 | cmd.sta_id = sta->sta_id; | 613 | cmd.sta_id = sta->sta_id; |
598 | cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, | 614 | cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, |
599 | color)); | 615 | color)); |
@@ -627,7 +643,8 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) | |||
627 | lockdep_assert_held(&mvm->mutex); | 643 | lockdep_assert_held(&mvm->mutex); |
628 | 644 | ||
629 | /* Add the aux station, but without any queues */ | 645 | /* Add the aux station, but without any queues */ |
630 | ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0); | 646 | ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0, |
647 | NL80211_IFTYPE_UNSPECIFIED); | ||
631 | if (ret) | 648 | if (ret) |
632 | return ret; | 649 | return ret; |
633 | 650 | ||
@@ -699,7 +716,8 @@ int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
699 | lockdep_assert_held(&mvm->mutex); | 716 | lockdep_assert_held(&mvm->mutex); |
700 | 717 | ||
701 | qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); | 718 | qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); |
702 | ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask); | 719 | ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask, |
720 | ieee80211_vif_type_p2p(vif)); | ||
703 | if (ret) | 721 | if (ret) |
704 | return ret; | 722 | return ret; |
705 | 723 | ||
@@ -735,7 +753,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
735 | int tid, u16 ssn, bool start) | 753 | int tid, u16 ssn, bool start) |
736 | { | 754 | { |
737 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 755 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
738 | struct iwl_mvm_add_sta_cmd_v6 cmd = {}; | 756 | struct iwl_mvm_add_sta_cmd_v7 cmd = {}; |
739 | int ret; | 757 | int ret; |
740 | u32 status; | 758 | u32 status; |
741 | 759 | ||
@@ -794,7 +812,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
794 | int tid, u8 queue, bool start) | 812 | int tid, u8 queue, bool start) |
795 | { | 813 | { |
796 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 814 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
797 | struct iwl_mvm_add_sta_cmd_v6 cmd = {}; | 815 | struct iwl_mvm_add_sta_cmd_v7 cmd = {}; |
798 | int ret; | 816 | int ret; |
799 | u32 status; | 817 | u32 status; |
800 | 818 | ||
@@ -833,7 +851,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
833 | return ret; | 851 | return ret; |
834 | } | 852 | } |
835 | 853 | ||
836 | static const u8 tid_to_ac[] = { | 854 | const u8 tid_to_mac80211_ac[] = { |
837 | IEEE80211_AC_BE, | 855 | IEEE80211_AC_BE, |
838 | IEEE80211_AC_BK, | 856 | IEEE80211_AC_BK, |
839 | IEEE80211_AC_BK, | 857 | IEEE80211_AC_BK, |
@@ -844,6 +862,17 @@ static const u8 tid_to_ac[] = { | |||
844 | IEEE80211_AC_VO, | 862 | IEEE80211_AC_VO, |
845 | }; | 863 | }; |
846 | 864 | ||
865 | static const u8 tid_to_ucode_ac[] = { | ||
866 | AC_BE, | ||
867 | AC_BK, | ||
868 | AC_BK, | ||
869 | AC_BE, | ||
870 | AC_VI, | ||
871 | AC_VI, | ||
872 | AC_VO, | ||
873 | AC_VO, | ||
874 | }; | ||
875 | |||
847 | int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 876 | int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
848 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) | 877 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) |
849 | { | 878 | { |
@@ -873,10 +902,18 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
873 | return -EIO; | 902 | return -EIO; |
874 | } | 903 | } |
875 | 904 | ||
905 | spin_lock_bh(&mvmsta->lock); | ||
906 | |||
907 | /* possible race condition - we entered D0i3 while starting agg */ | ||
908 | if (test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status)) { | ||
909 | spin_unlock_bh(&mvmsta->lock); | ||
910 | IWL_ERR(mvm, "Entered D0i3 while starting Tx agg\n"); | ||
911 | return -EIO; | ||
912 | } | ||
913 | |||
876 | /* the new tx queue is still connected to the same mac80211 queue */ | 914 | /* the new tx queue is still connected to the same mac80211 queue */ |
877 | mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_ac[tid]]; | 915 | mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_mac80211_ac[tid]]; |
878 | 916 | ||
879 | spin_lock_bh(&mvmsta->lock); | ||
880 | tid_data = &mvmsta->tid_data[tid]; | 917 | tid_data = &mvmsta->tid_data[tid]; |
881 | tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); | 918 | tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); |
882 | tid_data->txq_id = txq_id; | 919 | tid_data->txq_id = txq_id; |
@@ -916,7 +953,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
916 | tid_data->ssn = 0xffff; | 953 | tid_data->ssn = 0xffff; |
917 | spin_unlock_bh(&mvmsta->lock); | 954 | spin_unlock_bh(&mvmsta->lock); |
918 | 955 | ||
919 | fifo = iwl_mvm_ac_to_tx_fifo[tid_to_ac[tid]]; | 956 | fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]]; |
920 | 957 | ||
921 | ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); | 958 | ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); |
922 | if (ret) | 959 | if (ret) |
@@ -1411,7 +1448,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, | |||
1411 | struct ieee80211_sta *sta) | 1448 | struct ieee80211_sta *sta) |
1412 | { | 1449 | { |
1413 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | 1450 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1414 | struct iwl_mvm_add_sta_cmd_v6 cmd = { | 1451 | struct iwl_mvm_add_sta_cmd_v7 cmd = { |
1415 | .add_modify = STA_MODE_MODIFY, | 1452 | .add_modify = STA_MODE_MODIFY, |
1416 | .sta_id = mvmsta->sta_id, | 1453 | .sta_id = mvmsta->sta_id, |
1417 | .station_flags_msk = cpu_to_le32(STA_FLG_PS), | 1454 | .station_flags_msk = cpu_to_le32(STA_FLG_PS), |
@@ -1427,28 +1464,102 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, | |||
1427 | void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, | 1464 | void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, |
1428 | struct ieee80211_sta *sta, | 1465 | struct ieee80211_sta *sta, |
1429 | enum ieee80211_frame_release_type reason, | 1466 | enum ieee80211_frame_release_type reason, |
1430 | u16 cnt) | 1467 | u16 cnt, u16 tids, bool more_data, |
1468 | bool agg) | ||
1431 | { | 1469 | { |
1432 | u16 sleep_state_flags = | ||
1433 | (reason == IEEE80211_FRAME_RELEASE_UAPSD) ? | ||
1434 | STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL; | ||
1435 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | 1470 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
1436 | struct iwl_mvm_add_sta_cmd_v6 cmd = { | 1471 | struct iwl_mvm_add_sta_cmd_v7 cmd = { |
1437 | .add_modify = STA_MODE_MODIFY, | 1472 | .add_modify = STA_MODE_MODIFY, |
1438 | .sta_id = mvmsta->sta_id, | 1473 | .sta_id = mvmsta->sta_id, |
1439 | .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT, | 1474 | .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT, |
1440 | .sleep_tx_count = cpu_to_le16(cnt), | 1475 | .sleep_tx_count = cpu_to_le16(cnt), |
1441 | .mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color), | 1476 | .mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color), |
1442 | /* | ||
1443 | * Same modify mask for sleep_tx_count and sleep_state_flags so | ||
1444 | * we must set the sleep_state_flags too. | ||
1445 | */ | ||
1446 | .sleep_state_flags = cpu_to_le16(sleep_state_flags), | ||
1447 | }; | 1477 | }; |
1448 | int ret; | 1478 | int tid, ret; |
1479 | unsigned long _tids = tids; | ||
1480 | |||
1481 | /* convert TIDs to ACs - we don't support TSPEC so that's OK | ||
1482 | * Note that this field is reserved and unused by firmware not | ||
1483 | * supporting GO uAPSD, so it's safe to always do this. | ||
1484 | */ | ||
1485 | for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) | ||
1486 | cmd.awake_acs |= BIT(tid_to_ucode_ac[tid]); | ||
1487 | |||
1488 | /* If we're releasing frames from aggregation queues then check if the | ||
1489 | * all queues combined that we're releasing frames from have | ||
1490 | * - more frames than the service period, in which case more_data | ||
1491 | * needs to be set | ||
1492 | * - fewer than 'cnt' frames, in which case we need to adjust the | ||
1493 | * firmware command (but do that unconditionally) | ||
1494 | */ | ||
1495 | if (agg) { | ||
1496 | int remaining = cnt; | ||
1497 | |||
1498 | spin_lock_bh(&mvmsta->lock); | ||
1499 | for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) { | ||
1500 | struct iwl_mvm_tid_data *tid_data; | ||
1501 | u16 n_queued; | ||
1502 | |||
1503 | tid_data = &mvmsta->tid_data[tid]; | ||
1504 | if (WARN(tid_data->state != IWL_AGG_ON && | ||
1505 | tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA, | ||
1506 | "TID %d state is %d\n", | ||
1507 | tid, tid_data->state)) { | ||
1508 | spin_unlock_bh(&mvmsta->lock); | ||
1509 | ieee80211_sta_eosp(sta); | ||
1510 | return; | ||
1511 | } | ||
1512 | |||
1513 | n_queued = iwl_mvm_tid_queued(tid_data); | ||
1514 | if (n_queued > remaining) { | ||
1515 | more_data = true; | ||
1516 | remaining = 0; | ||
1517 | break; | ||
1518 | } | ||
1519 | remaining -= n_queued; | ||
1520 | } | ||
1521 | spin_unlock_bh(&mvmsta->lock); | ||
1522 | |||
1523 | cmd.sleep_tx_count = cpu_to_le16(cnt - remaining); | ||
1524 | if (WARN_ON(cnt - remaining == 0)) { | ||
1525 | ieee80211_sta_eosp(sta); | ||
1526 | return; | ||
1527 | } | ||
1528 | } | ||
1529 | |||
1530 | /* Note: this is ignored by firmware not supporting GO uAPSD */ | ||
1531 | if (more_data) | ||
1532 | cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_MOREDATA); | ||
1533 | |||
1534 | if (reason == IEEE80211_FRAME_RELEASE_PSPOLL) { | ||
1535 | mvmsta->next_status_eosp = true; | ||
1536 | cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_PS_POLL); | ||
1537 | } else { | ||
1538 | cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_UAPSD); | ||
1539 | } | ||
1449 | 1540 | ||
1450 | /* TODO: somehow the fw doesn't seem to take PS_POLL into account */ | ||
1451 | ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd); | 1541 | ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd); |
1452 | if (ret) | 1542 | if (ret) |
1453 | IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); | 1543 | IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); |
1454 | } | 1544 | } |
1545 | |||
1546 | int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, | ||
1547 | struct iwl_rx_cmd_buffer *rxb, | ||
1548 | struct iwl_device_cmd *cmd) | ||
1549 | { | ||
1550 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1551 | struct iwl_mvm_eosp_notification *notif = (void *)pkt->data; | ||
1552 | struct ieee80211_sta *sta; | ||
1553 | u32 sta_id = le32_to_cpu(notif->sta_id); | ||
1554 | |||
1555 | if (WARN_ON_ONCE(sta_id >= IWL_MVM_STATION_COUNT)) | ||
1556 | return 0; | ||
1557 | |||
1558 | rcu_read_lock(); | ||
1559 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | ||
1560 | if (!IS_ERR_OR_NULL(sta)) | ||
1561 | ieee80211_sta_eosp(sta); | ||
1562 | rcu_read_unlock(); | ||
1563 | |||
1564 | return 0; | ||
1565 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 4968d0237dc5..2ed84c421481 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h | |||
@@ -195,24 +195,33 @@ struct iwl_mvm; | |||
195 | /** | 195 | /** |
196 | * DOC: AP mode - PS | 196 | * DOC: AP mode - PS |
197 | * | 197 | * |
198 | * When a station is asleep, the fw will set it as "asleep". All the | 198 | * When a station is asleep, the fw will set it as "asleep". All frames on |
199 | * non-aggregation frames to that station will be dropped by the fw | 199 | * shared queues (i.e. non-aggregation queues) to that station will be dropped |
200 | * (%TX_STATUS_FAIL_DEST_PS failure code). | 200 | * by the fw (%TX_STATUS_FAIL_DEST_PS failure code). |
201 | * | ||
201 | * AMPDUs are in a separate queue that is stopped by the fw. We just need to | 202 | * AMPDUs are in a separate queue that is stopped by the fw. We just need to |
202 | * let mac80211 know how many frames we have in these queues so that it can | 203 | * let mac80211 know when there are frames in these queues so that it can |
203 | * properly handle trigger frames. | 204 | * properly handle trigger frames. |
204 | * When the a trigger frame is received, mac80211 tells the driver to send | 205 | * |
205 | * frames from the AMPDU queues or AC queue depending on which queue are | 206 | * When a trigger frame is received, mac80211 tells the driver to send frames |
206 | * delivery-enabled and what TID has frames to transmit (Note that mac80211 has | 207 | * from the AMPDU queues or sends frames to non-aggregation queues itself, |
207 | * all the knowledege since all the non-agg frames are buffered / filtered, and | 208 | * depending on which ACs are delivery-enabled and what TID has frames to |
208 | * the driver tells mac80211 about agg frames). The driver needs to tell the fw | 209 | * transmit. Note that mac80211 has all the knowledege since all the non-agg |
209 | * to let frames out even if the station is asleep. This is done by | 210 | * frames are buffered / filtered, and the driver tells mac80211 about agg |
210 | * %iwl_mvm_sta_modify_sleep_tx_count. | 211 | * frames). The driver needs to tell the fw to let frames out even if the |
211 | * When we receive a frame from that station with PM bit unset, the | 212 | * station is asleep. This is done by %iwl_mvm_sta_modify_sleep_tx_count. |
212 | * driver needs to let the fw know that this station isn't alseep any more. | 213 | * |
213 | * This is done by %iwl_mvm_sta_modify_ps_wake. | 214 | * When we receive a frame from that station with PM bit unset, the driver |
214 | * | 215 | * needs to let the fw know that this station isn't asleep any more. This is |
215 | * TODO - EOSP handling | 216 | * done by %iwl_mvm_sta_modify_ps_wake in response to mac80211 signalling the |
217 | * station's wakeup. | ||
218 | * | ||
219 | * For a GO, the Service Period might be cut short due to an absence period | ||
220 | * of the GO. In this (and all other cases) the firmware notifies us with the | ||
221 | * EOSP_NOTIFICATION, and we notify mac80211 of that. Further frames that we | ||
222 | * already sent to the device will be rejected again. | ||
223 | * | ||
224 | * See also "AP support for powersaving clients" in mac80211.h. | ||
216 | */ | 225 | */ |
217 | 226 | ||
218 | /** | 227 | /** |
@@ -261,6 +270,12 @@ struct iwl_mvm_tid_data { | |||
261 | u16 ssn; | 270 | u16 ssn; |
262 | }; | 271 | }; |
263 | 272 | ||
273 | static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) | ||
274 | { | ||
275 | return ieee80211_sn_sub(IEEE80211_SEQ_TO_SN(tid_data->seq_number), | ||
276 | tid_data->next_reclaimed); | ||
277 | } | ||
278 | |||
264 | /** | 279 | /** |
265 | * struct iwl_mvm_sta - representation of a station in the driver | 280 | * struct iwl_mvm_sta - representation of a station in the driver |
266 | * @sta_id: the index of the station in the fw (will be replaced by id_n_color) | 281 | * @sta_id: the index of the station in the fw (will be replaced by id_n_color) |
@@ -269,7 +284,11 @@ struct iwl_mvm_tid_data { | |||
269 | * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for | 284 | * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for |
270 | * tid. | 285 | * tid. |
271 | * @max_agg_bufsize: the maximal size of the AGG buffer for this station | 286 | * @max_agg_bufsize: the maximal size of the AGG buffer for this station |
287 | * @bt_reduced_txpower_dbg: debug mode in which %bt_reduced_txpower is forced | ||
288 | * by debugfs. | ||
272 | * @bt_reduced_txpower: is reduced tx power enabled for this station | 289 | * @bt_reduced_txpower: is reduced tx power enabled for this station |
290 | * @next_status_eosp: the next reclaimed packet is a PS-Poll response and | ||
291 | * we need to signal the EOSP | ||
273 | * @lock: lock to protect the whole struct. Since %tid_data is access from Tx | 292 | * @lock: lock to protect the whole struct. Since %tid_data is access from Tx |
274 | * and from Tx response flow, it needs a spinlock. | 293 | * and from Tx response flow, it needs a spinlock. |
275 | * @tid_data: per tid data. Look at %iwl_mvm_tid_data. | 294 | * @tid_data: per tid data. Look at %iwl_mvm_tid_data. |
@@ -287,7 +306,9 @@ struct iwl_mvm_sta { | |||
287 | u32 mac_id_n_color; | 306 | u32 mac_id_n_color; |
288 | u16 tid_disable_agg; | 307 | u16 tid_disable_agg; |
289 | u8 max_agg_bufsize; | 308 | u8 max_agg_bufsize; |
309 | bool bt_reduced_txpower_dbg; | ||
290 | bool bt_reduced_txpower; | 310 | bool bt_reduced_txpower; |
311 | bool next_status_eosp; | ||
291 | spinlock_t lock; | 312 | spinlock_t lock; |
292 | struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; | 313 | struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; |
293 | struct iwl_lq_sta lq_sta; | 314 | struct iwl_lq_sta lq_sta; |
@@ -345,6 +366,10 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | |||
345 | struct ieee80211_sta *sta, u32 iv32, | 366 | struct ieee80211_sta *sta, u32 iv32, |
346 | u16 *phase1key); | 367 | u16 *phase1key); |
347 | 368 | ||
369 | int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, | ||
370 | struct iwl_rx_cmd_buffer *rxb, | ||
371 | struct iwl_device_cmd *cmd); | ||
372 | |||
348 | /* AMPDU */ | 373 | /* AMPDU */ |
349 | int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | 374 | int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
350 | int tid, u16 ssn, bool start); | 375 | int tid, u16 ssn, bool start); |
@@ -359,7 +384,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
359 | 384 | ||
360 | int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm); | 385 | int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm); |
361 | int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, | 386 | int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, |
362 | u32 qmask); | 387 | u32 qmask, enum nl80211_iftype iftype); |
363 | void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, | 388 | void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, |
364 | struct iwl_mvm_int_sta *sta); | 389 | struct iwl_mvm_int_sta *sta); |
365 | int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 390 | int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
@@ -375,7 +400,8 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, | |||
375 | void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, | 400 | void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, |
376 | struct ieee80211_sta *sta, | 401 | struct ieee80211_sta *sta, |
377 | enum ieee80211_frame_release_type reason, | 402 | enum ieee80211_frame_release_type reason, |
378 | u16 cnt); | 403 | u16 cnt, u16 tids, bool more_data, |
404 | bool agg); | ||
379 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | 405 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, |
380 | bool drain); | 406 | bool drain); |
381 | 407 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index b4c2abaa297b..61331245ad93 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
@@ -126,6 +126,7 @@ static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) | |||
126 | * in iwl_mvm_te_handle_notif). | 126 | * in iwl_mvm_te_handle_notif). |
127 | */ | 127 | */ |
128 | clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); | 128 | clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); |
129 | iwl_mvm_unref(mvm, IWL_MVM_REF_ROC); | ||
129 | 130 | ||
130 | /* | 131 | /* |
131 | * Of course, our status bit is just as racy as mac80211, so in | 132 | * Of course, our status bit is just as racy as mac80211, so in |
@@ -210,6 +211,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
210 | 211 | ||
211 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { | 212 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { |
212 | set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); | 213 | set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); |
214 | iwl_mvm_ref(mvm, IWL_MVM_REF_ROC); | ||
213 | ieee80211_ready_on_channel(mvm->hw); | 215 | ieee80211_ready_on_channel(mvm->hw); |
214 | } | 216 | } |
215 | } else { | 217 | } else { |
@@ -436,7 +438,8 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
436 | time_cmd.duration = cpu_to_le32(duration); | 438 | time_cmd.duration = cpu_to_le32(duration); |
437 | time_cmd.repeat = 1; | 439 | time_cmd.repeat = 1; |
438 | time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | | 440 | time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | |
439 | TE_V2_NOTIF_HOST_EVENT_END); | 441 | TE_V2_NOTIF_HOST_EVENT_END | |
442 | T2_V2_START_IMMEDIATELY); | ||
440 | 443 | ||
441 | iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | 444 | iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
442 | } | 445 | } |
@@ -551,7 +554,8 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
551 | time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); | 554 | time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); |
552 | time_cmd.repeat = 1; | 555 | time_cmd.repeat = 1; |
553 | time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | | 556 | time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | |
554 | TE_V2_NOTIF_HOST_EVENT_END); | 557 | TE_V2_NOTIF_HOST_EVENT_END | |
558 | T2_V2_START_IMMEDIATELY); | ||
555 | 559 | ||
556 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); | 560 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
557 | } | 561 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 3afa6b6bf835..7a99fa361954 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c | |||
@@ -403,7 +403,7 @@ static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable) | |||
403 | } | 403 | } |
404 | } | 404 | } |
405 | 405 | ||
406 | static void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff) | 406 | void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff) |
407 | { | 407 | { |
408 | struct iwl_host_cmd cmd = { | 408 | struct iwl_host_cmd cmd = { |
409 | .id = REPLY_THERMAL_MNG_BACKOFF, | 409 | .id = REPLY_THERMAL_MNG_BACKOFF, |
@@ -412,6 +412,8 @@ static void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff) | |||
412 | .flags = CMD_SYNC, | 412 | .flags = CMD_SYNC, |
413 | }; | 413 | }; |
414 | 414 | ||
415 | backoff = max(backoff, mvm->thermal_throttle.min_backoff); | ||
416 | |||
415 | if (iwl_mvm_send_cmd(mvm, &cmd) == 0) { | 417 | if (iwl_mvm_send_cmd(mvm, &cmd) == 0) { |
416 | IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n", | 418 | IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n", |
417 | backoff); | 419 | backoff); |
@@ -534,7 +536,7 @@ static const struct iwl_tt_params iwl7000_high_temp_tt_params = { | |||
534 | .support_tx_backoff = true, | 536 | .support_tx_backoff = true, |
535 | }; | 537 | }; |
536 | 538 | ||
537 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm) | 539 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff) |
538 | { | 540 | { |
539 | struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; | 541 | struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; |
540 | 542 | ||
@@ -546,6 +548,7 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm) | |||
546 | tt->params = &iwl7000_tt_params; | 548 | tt->params = &iwl7000_tt_params; |
547 | 549 | ||
548 | tt->throttle = false; | 550 | tt->throttle = false; |
551 | tt->min_backoff = min_backoff; | ||
549 | INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); | 552 | INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); |
550 | } | 553 | } |
551 | 554 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 76ee486039d7..879aeac46cc1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -79,6 +79,7 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
79 | __le16 fc = hdr->frame_control; | 79 | __le16 fc = hdr->frame_control; |
80 | u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags); | 80 | u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags); |
81 | u32 len = skb->len + FCS_LEN; | 81 | u32 len = skb->len + FCS_LEN; |
82 | u8 ac; | ||
82 | 83 | ||
83 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) | 84 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) |
84 | tx_flags |= TX_CMD_FLG_ACK; | 85 | tx_flags |= TX_CMD_FLG_ACK; |
@@ -90,13 +91,6 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
90 | else if (ieee80211_is_back_req(fc)) | 91 | else if (ieee80211_is_back_req(fc)) |
91 | tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; | 92 | tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; |
92 | 93 | ||
93 | /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */ | ||
94 | if (info->band == IEEE80211_BAND_2GHZ && | ||
95 | (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO || | ||
96 | is_multicast_ether_addr(hdr->addr1) || | ||
97 | ieee80211_is_back_req(fc) || ieee80211_is_mgmt(fc))) | ||
98 | tx_flags |= TX_CMD_FLG_BT_DIS; | ||
99 | |||
100 | if (ieee80211_has_morefrags(fc)) | 94 | if (ieee80211_has_morefrags(fc)) |
101 | tx_flags |= TX_CMD_FLG_MORE_FRAG; | 95 | tx_flags |= TX_CMD_FLG_MORE_FRAG; |
102 | 96 | ||
@@ -112,6 +106,11 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
112 | tx_flags &= ~TX_CMD_FLG_SEQ_CTL; | 106 | tx_flags &= ~TX_CMD_FLG_SEQ_CTL; |
113 | } | 107 | } |
114 | 108 | ||
109 | /* tid_tspec will default to 0 = BE when QOS isn't enabled */ | ||
110 | ac = tid_to_mac80211_ac[tx_cmd->tid_tspec]; | ||
111 | tx_flags |= iwl_mvm_bt_coex_tx_prio(mvm, hdr, info, ac) << | ||
112 | TX_CMD_FLG_BT_PRIO_POS; | ||
113 | |||
115 | if (ieee80211_is_mgmt(fc)) { | 114 | if (ieee80211_is_mgmt(fc)) { |
116 | if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) | 115 | if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) |
117 | tx_cmd->pm_frame_timeout = cpu_to_le16(3); | 116 | tx_cmd->pm_frame_timeout = cpu_to_le16(3); |
@@ -122,15 +121,12 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
122 | * it | 121 | * it |
123 | */ | 122 | */ |
124 | WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU); | 123 | WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU); |
125 | } else if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { | 124 | } else if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) { |
126 | tx_cmd->pm_frame_timeout = cpu_to_le16(2); | 125 | tx_cmd->pm_frame_timeout = cpu_to_le16(2); |
127 | } else { | 126 | } else { |
128 | tx_cmd->pm_frame_timeout = 0; | 127 | tx_cmd->pm_frame_timeout = 0; |
129 | } | 128 | } |
130 | 129 | ||
131 | if (info->flags & IEEE80211_TX_CTL_AMPDU) | ||
132 | tx_flags |= TX_CMD_FLG_PROT_REQUIRE; | ||
133 | |||
134 | if (ieee80211_is_data(fc) && len > mvm->rts_threshold && | 130 | if (ieee80211_is_data(fc) && len > mvm->rts_threshold && |
135 | !is_multicast_ether_addr(ieee80211_get_DA(hdr))) | 131 | !is_multicast_ether_addr(ieee80211_get_DA(hdr))) |
136 | tx_flags |= TX_CMD_FLG_PROT_REQUIRE; | 132 | tx_flags |= TX_CMD_FLG_PROT_REQUIRE; |
@@ -207,7 +203,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, | |||
207 | rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx); | 203 | rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx); |
208 | 204 | ||
209 | mvm->mgmt_last_antenna_idx = | 205 | mvm->mgmt_last_antenna_idx = |
210 | iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw), | 206 | iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, |
211 | mvm->mgmt_last_antenna_idx); | 207 | mvm->mgmt_last_antenna_idx); |
212 | rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; | 208 | rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; |
213 | 209 | ||
@@ -377,6 +373,13 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
377 | tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; | 373 | tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; |
378 | /* From now on, we cannot access info->control */ | 374 | /* From now on, we cannot access info->control */ |
379 | 375 | ||
376 | /* | ||
377 | * we handle that entirely ourselves -- for uAPSD the firmware | ||
378 | * will always send a notification, and for PS-Poll responses | ||
379 | * we'll notify mac80211 when getting frame status | ||
380 | */ | ||
381 | info->flags &= ~IEEE80211_TX_STATUS_EOSP; | ||
382 | |||
380 | spin_lock(&mvmsta->lock); | 383 | spin_lock(&mvmsta->lock); |
381 | 384 | ||
382 | if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { | 385 | if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { |
@@ -437,6 +440,17 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, | |||
437 | 440 | ||
438 | lockdep_assert_held(&mvmsta->lock); | 441 | lockdep_assert_held(&mvmsta->lock); |
439 | 442 | ||
443 | if ((tid_data->state == IWL_AGG_ON || | ||
444 | tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA) && | ||
445 | iwl_mvm_tid_queued(tid_data) == 0) { | ||
446 | /* | ||
447 | * Now that this aggregation queue is empty tell mac80211 so it | ||
448 | * knows we no longer have frames buffered for the station on | ||
449 | * this TID (for the TIM bitmap calculation.) | ||
450 | */ | ||
451 | ieee80211_sta_set_buffered(sta, tid, false); | ||
452 | } | ||
453 | |||
440 | if (tid_data->ssn != tid_data->next_reclaimed) | 454 | if (tid_data->ssn != tid_data->next_reclaimed) |
441 | return; | 455 | return; |
442 | 456 | ||
@@ -680,6 +694,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
680 | iwl_mvm_check_ratid_empty(mvm, sta, tid); | 694 | iwl_mvm_check_ratid_empty(mvm, sta, tid); |
681 | spin_unlock_bh(&mvmsta->lock); | 695 | spin_unlock_bh(&mvmsta->lock); |
682 | } | 696 | } |
697 | |||
698 | if (mvmsta->next_status_eosp) { | ||
699 | mvmsta->next_status_eosp = false; | ||
700 | ieee80211_sta_eosp(sta); | ||
701 | } | ||
683 | } else { | 702 | } else { |
684 | mvmsta = NULL; | 703 | mvmsta = NULL; |
685 | } | 704 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 86989df69356..d619851745a1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c | |||
@@ -289,8 +289,8 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx) | |||
289 | return last_idx; | 289 | return last_idx; |
290 | } | 290 | } |
291 | 291 | ||
292 | static struct { | 292 | static const struct { |
293 | char *name; | 293 | const char *name; |
294 | u8 num; | 294 | u8 num; |
295 | } advanced_lookup[] = { | 295 | } advanced_lookup[] = { |
296 | { "NMI_INTERRUPT_WDG", 0x34 }, | 296 | { "NMI_INTERRUPT_WDG", 0x34 }, |
@@ -376,9 +376,67 @@ struct iwl_error_event_table { | |||
376 | u32 flow_handler; /* FH read/write pointers, RX credit */ | 376 | u32 flow_handler; /* FH read/write pointers, RX credit */ |
377 | } __packed; | 377 | } __packed; |
378 | 378 | ||
379 | /* | ||
380 | * UMAC error struct - relevant starting from family 8000 chip. | ||
381 | * Note: This structure is read from the device with IO accesses, | ||
382 | * and the reading already does the endian conversion. As it is | ||
383 | * read with u32-sized accesses, any members with a different size | ||
384 | * need to be ordered correctly though! | ||
385 | */ | ||
386 | struct iwl_umac_error_event_table { | ||
387 | u32 valid; /* (nonzero) valid, (0) log is empty */ | ||
388 | u32 error_id; /* type of error */ | ||
389 | u32 pc; /* program counter */ | ||
390 | u32 blink1; /* branch link */ | ||
391 | u32 blink2; /* branch link */ | ||
392 | u32 ilink1; /* interrupt link */ | ||
393 | u32 ilink2; /* interrupt link */ | ||
394 | u32 data1; /* error-specific data */ | ||
395 | u32 data2; /* error-specific data */ | ||
396 | u32 line; /* source code line of error */ | ||
397 | u32 umac_ver; /* umac version */ | ||
398 | } __packed; | ||
399 | |||
379 | #define ERROR_START_OFFSET (1 * sizeof(u32)) | 400 | #define ERROR_START_OFFSET (1 * sizeof(u32)) |
380 | #define ERROR_ELEM_SIZE (7 * sizeof(u32)) | 401 | #define ERROR_ELEM_SIZE (7 * sizeof(u32)) |
381 | 402 | ||
403 | static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) | ||
404 | { | ||
405 | struct iwl_trans *trans = mvm->trans; | ||
406 | struct iwl_umac_error_event_table table; | ||
407 | u32 base; | ||
408 | |||
409 | base = mvm->umac_error_event_table; | ||
410 | |||
411 | if (base < 0x800000 || base >= 0x80C000) { | ||
412 | IWL_ERR(mvm, | ||
413 | "Not valid error log pointer 0x%08X for %s uCode\n", | ||
414 | base, | ||
415 | (mvm->cur_ucode == IWL_UCODE_INIT) | ||
416 | ? "Init" : "RT"); | ||
417 | return; | ||
418 | } | ||
419 | |||
420 | iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); | ||
421 | |||
422 | if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { | ||
423 | IWL_ERR(trans, "Start IWL Error Log Dump:\n"); | ||
424 | IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", | ||
425 | mvm->status, table.valid); | ||
426 | } | ||
427 | |||
428 | IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, | ||
429 | desc_lookup(table.error_id)); | ||
430 | IWL_ERR(mvm, "0x%08X | umac uPc\n", table.pc); | ||
431 | IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1); | ||
432 | IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2); | ||
433 | IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1); | ||
434 | IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2); | ||
435 | IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1); | ||
436 | IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2); | ||
437 | IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_ver); | ||
438 | } | ||
439 | |||
382 | void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) | 440 | void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) |
383 | { | 441 | { |
384 | struct iwl_trans *trans = mvm->trans; | 442 | struct iwl_trans *trans = mvm->trans; |
@@ -394,7 +452,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) | |||
394 | base = mvm->fw->inst_errlog_ptr; | 452 | base = mvm->fw->inst_errlog_ptr; |
395 | } | 453 | } |
396 | 454 | ||
397 | if (base < 0x800000 || base >= 0x80C000) { | 455 | if (base < 0x800000) { |
398 | IWL_ERR(mvm, | 456 | IWL_ERR(mvm, |
399 | "Not valid error log pointer 0x%08X for %s uCode\n", | 457 | "Not valid error log pointer 0x%08X for %s uCode\n", |
400 | base, | 458 | base, |
@@ -453,29 +511,31 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) | |||
453 | IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); | 511 | IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); |
454 | IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp); | 512 | IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp); |
455 | IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); | 513 | IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); |
514 | |||
515 | if (mvm->support_umac_log) | ||
516 | iwl_mvm_dump_umac_error_log(mvm); | ||
456 | } | 517 | } |
457 | 518 | ||
458 | void iwl_mvm_dump_sram(struct iwl_mvm *mvm) | 519 | void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm) |
459 | { | 520 | { |
460 | const struct fw_img *img; | 521 | const struct fw_img *img; |
461 | int ofs, len = 0; | 522 | u32 ofs, sram_len; |
462 | u8 *buf; | 523 | void *sram; |
463 | 524 | ||
464 | if (!mvm->ucode_loaded) | 525 | if (!mvm->ucode_loaded || mvm->fw_error_sram) |
465 | return; | 526 | return; |
466 | 527 | ||
467 | img = &mvm->fw->img[mvm->cur_ucode]; | 528 | img = &mvm->fw->img[mvm->cur_ucode]; |
468 | ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; | 529 | ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; |
469 | len = img->sec[IWL_UCODE_SECTION_DATA].len; | 530 | sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; |
470 | 531 | ||
471 | buf = kzalloc(len, GFP_ATOMIC); | 532 | sram = kzalloc(sram_len, GFP_ATOMIC); |
472 | if (!buf) | 533 | if (!sram) |
473 | return; | 534 | return; |
474 | 535 | ||
475 | iwl_trans_read_mem_bytes(mvm->trans, ofs, buf, len); | 536 | iwl_trans_read_mem_bytes(mvm->trans, ofs, sram, sram_len); |
476 | iwl_print_hex_error(mvm->trans, buf, len); | 537 | mvm->fw_error_sram = sram; |
477 | 538 | mvm->fw_error_sram_len = sram_len; | |
478 | kfree(buf); | ||
479 | } | 539 | } |
480 | 540 | ||
481 | /** | 541 | /** |
@@ -516,15 +576,20 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
516 | enum ieee80211_smps_mode smps_request) | 576 | enum ieee80211_smps_mode smps_request) |
517 | { | 577 | { |
518 | struct iwl_mvm_vif *mvmvif; | 578 | struct iwl_mvm_vif *mvmvif; |
519 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC; | 579 | enum ieee80211_smps_mode smps_mode; |
520 | int i; | 580 | int i; |
521 | 581 | ||
522 | lockdep_assert_held(&mvm->mutex); | 582 | lockdep_assert_held(&mvm->mutex); |
523 | 583 | ||
524 | /* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */ | 584 | /* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */ |
525 | if (num_of_ant(iwl_fw_valid_rx_ant(mvm->fw)) == 1) | 585 | if (num_of_ant(mvm->fw->valid_rx_ant) == 1) |
526 | return; | 586 | return; |
527 | 587 | ||
588 | if (vif->type == NL80211_IFTYPE_AP) | ||
589 | smps_mode = IEEE80211_SMPS_OFF; | ||
590 | else | ||
591 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | ||
592 | |||
528 | mvmvif = iwl_mvm_vif_from_mac80211(vif); | 593 | mvmvif = iwl_mvm_vif_from_mac80211(vif); |
529 | mvmvif->smps_requests[req_type] = smps_request; | 594 | mvmvif->smps_requests[req_type] = smps_request; |
530 | for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { | 595 | for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { |
@@ -538,3 +603,44 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
538 | 603 | ||
539 | ieee80211_request_smps(vif, smps_mode); | 604 | ieee80211_request_smps(vif, smps_mode); |
540 | } | 605 | } |
606 | |||
607 | int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
608 | bool value) | ||
609 | { | ||
610 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
611 | int res; | ||
612 | |||
613 | lockdep_assert_held(&mvm->mutex); | ||
614 | |||
615 | if (mvmvif->low_latency == value) | ||
616 | return 0; | ||
617 | |||
618 | mvmvif->low_latency = value; | ||
619 | |||
620 | res = iwl_mvm_update_quotas(mvm, NULL); | ||
621 | if (res) | ||
622 | return res; | ||
623 | |||
624 | iwl_mvm_bt_coex_vif_change(mvm); | ||
625 | |||
626 | return iwl_mvm_power_update_mac(mvm, vif); | ||
627 | } | ||
628 | |||
629 | static void iwl_mvm_ll_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) | ||
630 | { | ||
631 | bool *result = _data; | ||
632 | |||
633 | if (iwl_mvm_vif_low_latency(iwl_mvm_vif_from_mac80211(vif))) | ||
634 | *result = true; | ||
635 | } | ||
636 | |||
637 | bool iwl_mvm_low_latency(struct iwl_mvm *mvm) | ||
638 | { | ||
639 | bool result = false; | ||
640 | |||
641 | ieee80211_iterate_active_interfaces_atomic( | ||
642 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
643 | iwl_mvm_ll_iter, &result); | ||
644 | |||
645 | return result; | ||
646 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 3872ead75488..edb015c99049 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c | |||
@@ -66,6 +66,7 @@ | |||
66 | #include <linux/module.h> | 66 | #include <linux/module.h> |
67 | #include <linux/pci.h> | 67 | #include <linux/pci.h> |
68 | #include <linux/pci-aspm.h> | 68 | #include <linux/pci-aspm.h> |
69 | #include <linux/acpi.h> | ||
69 | 70 | ||
70 | #include "iwl-trans.h" | 71 | #include "iwl-trans.h" |
71 | #include "iwl-drv.h" | 72 | #include "iwl-drv.h" |
@@ -389,12 +390,92 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { | |||
389 | {IWL_PCI_DEVICE(0x095A, 0x5590, iwl7265_2ac_cfg)}, | 390 | {IWL_PCI_DEVICE(0x095A, 0x5590, iwl7265_2ac_cfg)}, |
390 | {IWL_PCI_DEVICE(0x095B, 0x5290, iwl7265_2ac_cfg)}, | 391 | {IWL_PCI_DEVICE(0x095B, 0x5290, iwl7265_2ac_cfg)}, |
391 | {IWL_PCI_DEVICE(0x095A, 0x5490, iwl7265_2ac_cfg)}, | 392 | {IWL_PCI_DEVICE(0x095A, 0x5490, iwl7265_2ac_cfg)}, |
393 | |||
394 | /* 8000 Series */ | ||
395 | {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, | ||
396 | {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, | ||
392 | #endif /* CONFIG_IWLMVM */ | 397 | #endif /* CONFIG_IWLMVM */ |
393 | 398 | ||
394 | {0} | 399 | {0} |
395 | }; | 400 | }; |
396 | MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); | 401 | MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); |
397 | 402 | ||
403 | #ifdef CONFIG_ACPI | ||
404 | #define SPL_METHOD "SPLC" | ||
405 | #define SPL_DOMAINTYPE_MODULE BIT(0) | ||
406 | #define SPL_DOMAINTYPE_WIFI BIT(1) | ||
407 | #define SPL_DOMAINTYPE_WIGIG BIT(2) | ||
408 | #define SPL_DOMAINTYPE_RFEM BIT(3) | ||
409 | |||
410 | static u64 splx_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splx) | ||
411 | { | ||
412 | union acpi_object *limits, *domain_type, *power_limit; | ||
413 | |||
414 | if (splx->type != ACPI_TYPE_PACKAGE || | ||
415 | splx->package.count != 2 || | ||
416 | splx->package.elements[0].type != ACPI_TYPE_INTEGER || | ||
417 | splx->package.elements[0].integer.value != 0) { | ||
418 | IWL_ERR(trans, "Unsupported splx structure"); | ||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | limits = &splx->package.elements[1]; | ||
423 | if (limits->type != ACPI_TYPE_PACKAGE || | ||
424 | limits->package.count < 2 || | ||
425 | limits->package.elements[0].type != ACPI_TYPE_INTEGER || | ||
426 | limits->package.elements[1].type != ACPI_TYPE_INTEGER) { | ||
427 | IWL_ERR(trans, "Invalid limits element"); | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | domain_type = &limits->package.elements[0]; | ||
432 | power_limit = &limits->package.elements[1]; | ||
433 | if (!(domain_type->integer.value & SPL_DOMAINTYPE_WIFI)) { | ||
434 | IWL_DEBUG_INFO(trans, "WiFi power is not limited"); | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | return power_limit->integer.value; | ||
439 | } | ||
440 | |||
441 | static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) | ||
442 | { | ||
443 | acpi_handle pxsx_handle; | ||
444 | acpi_handle handle; | ||
445 | struct acpi_buffer splx = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
446 | acpi_status status; | ||
447 | |||
448 | pxsx_handle = ACPI_HANDLE(&pdev->dev); | ||
449 | if (!pxsx_handle) { | ||
450 | IWL_DEBUG_INFO(trans, | ||
451 | "Could not retrieve root port ACPI handle"); | ||
452 | return; | ||
453 | } | ||
454 | |||
455 | /* Get the method's handle */ | ||
456 | status = acpi_get_handle(pxsx_handle, (acpi_string)SPL_METHOD, &handle); | ||
457 | if (ACPI_FAILURE(status)) { | ||
458 | IWL_DEBUG_INFO(trans, "SPL method not found"); | ||
459 | return; | ||
460 | } | ||
461 | |||
462 | /* Call SPLC with no arguments */ | ||
463 | status = acpi_evaluate_object(handle, NULL, NULL, &splx); | ||
464 | if (ACPI_FAILURE(status)) { | ||
465 | IWL_ERR(trans, "SPLC invocation failed (0x%x)", status); | ||
466 | return; | ||
467 | } | ||
468 | |||
469 | trans->dflt_pwr_limit = splx_get_pwr_limit(trans, splx.pointer); | ||
470 | IWL_DEBUG_INFO(trans, "Default power limit set to %lld", | ||
471 | trans->dflt_pwr_limit); | ||
472 | kfree(splx.pointer); | ||
473 | } | ||
474 | |||
475 | #else /* CONFIG_ACPI */ | ||
476 | static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) {} | ||
477 | #endif | ||
478 | |||
398 | /* PCI registers */ | 479 | /* PCI registers */ |
399 | #define PCI_CFG_RETRY_TIMEOUT 0x041 | 480 | #define PCI_CFG_RETRY_TIMEOUT 0x041 |
400 | 481 | ||
@@ -419,6 +500,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
419 | goto out_free_trans; | 500 | goto out_free_trans; |
420 | } | 501 | } |
421 | 502 | ||
503 | set_dflt_pwr_limit(iwl_trans, pdev); | ||
504 | |||
422 | /* register transport layer debugfs here */ | 505 | /* register transport layer debugfs here */ |
423 | ret = iwl_trans_dbgfs_register(iwl_trans, iwl_trans->dbgfs_dir); | 506 | ret = iwl_trans_dbgfs_register(iwl_trans, iwl_trans->dbgfs_dir); |
424 | if (ret) | 507 | if (ret) |
@@ -477,7 +560,7 @@ static int iwl_pci_resume(struct device *device) | |||
477 | iwl_enable_rfkill_int(trans); | 560 | iwl_enable_rfkill_int(trans); |
478 | 561 | ||
479 | hw_rfkill = iwl_is_rfkill_set(trans); | 562 | hw_rfkill = iwl_is_rfkill_set(trans); |
480 | iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); | 563 | iwl_trans_pcie_rf_kill(trans, hw_rfkill); |
481 | 564 | ||
482 | return 0; | 565 | return 0; |
483 | } | 566 | } |
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index e851f26fd44c..9091513ea738 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
@@ -304,7 +304,7 @@ struct iwl_trans_pcie { | |||
304 | bool bc_table_dword; | 304 | bool bc_table_dword; |
305 | u32 rx_page_order; | 305 | u32 rx_page_order; |
306 | 306 | ||
307 | const char **command_names; | 307 | const char *const *command_names; |
308 | 308 | ||
309 | /* queue watchdog */ | 309 | /* queue watchdog */ |
310 | unsigned long wd_timeout; | 310 | unsigned long wd_timeout; |
@@ -488,4 +488,6 @@ static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans, | |||
488 | __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask); | 488 | __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask); |
489 | } | 489 | } |
490 | 490 | ||
491 | void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state); | ||
492 | |||
491 | #endif /* __iwl_trans_int_pcie_h__ */ | 493 | #endif /* __iwl_trans_int_pcie_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 08c23d497a02..fdfa3969cac9 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c | |||
@@ -155,37 +155,26 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, | |||
155 | if (rxq->need_update == 0) | 155 | if (rxq->need_update == 0) |
156 | goto exit_unlock; | 156 | goto exit_unlock; |
157 | 157 | ||
158 | if (trans->cfg->base_params->shadow_reg_enable) { | 158 | /* |
159 | /* shadow register enabled */ | 159 | * explicitly wake up the NIC if: |
160 | /* Device expects a multiple of 8 */ | 160 | * 1. shadow registers aren't enabled |
161 | rxq->write_actual = (rxq->write & ~0x7); | 161 | * 2. there is a chance that the NIC is asleep |
162 | iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual); | 162 | */ |
163 | } else { | 163 | if (!trans->cfg->base_params->shadow_reg_enable && |
164 | /* If power-saving is in use, make sure device is awake */ | 164 | test_bit(STATUS_TPOWER_PMI, &trans->status)) { |
165 | if (test_bit(STATUS_TPOWER_PMI, &trans->status)) { | 165 | reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); |
166 | reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); | 166 | |
167 | 167 | if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { | |
168 | if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { | 168 | IWL_DEBUG_INFO(trans, "Rx queue requesting wakeup, GP1 = 0x%x\n", |
169 | IWL_DEBUG_INFO(trans, | 169 | reg); |
170 | "Rx queue requesting wakeup," | 170 | iwl_set_bit(trans, CSR_GP_CNTRL, |
171 | " GP1 = 0x%x\n", reg); | 171 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
172 | iwl_set_bit(trans, CSR_GP_CNTRL, | 172 | goto exit_unlock; |
173 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
174 | goto exit_unlock; | ||
175 | } | ||
176 | |||
177 | rxq->write_actual = (rxq->write & ~0x7); | ||
178 | iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR, | ||
179 | rxq->write_actual); | ||
180 | |||
181 | /* Else device is assumed to be awake */ | ||
182 | } else { | ||
183 | /* Device expects a multiple of 8 */ | ||
184 | rxq->write_actual = (rxq->write & ~0x7); | ||
185 | iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR, | ||
186 | rxq->write_actual); | ||
187 | } | 173 | } |
188 | } | 174 | } |
175 | |||
176 | rxq->write_actual = round_down(rxq->write, 8); | ||
177 | iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual); | ||
189 | rxq->need_update = 0; | 178 | rxq->need_update = 0; |
190 | 179 | ||
191 | exit_unlock: | 180 | exit_unlock: |
@@ -802,10 +791,9 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) | |||
802 | 791 | ||
803 | static u32 iwl_pcie_int_cause_non_ict(struct iwl_trans *trans) | 792 | static u32 iwl_pcie_int_cause_non_ict(struct iwl_trans *trans) |
804 | { | 793 | { |
805 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
806 | u32 inta; | 794 | u32 inta; |
807 | 795 | ||
808 | lockdep_assert_held(&trans_pcie->irq_lock); | 796 | lockdep_assert_held(&IWL_TRANS_GET_PCIE_TRANS(trans)->irq_lock); |
809 | 797 | ||
810 | trace_iwlwifi_dev_irq(trans->dev); | 798 | trace_iwlwifi_dev_irq(trans->dev); |
811 | 799 | ||
@@ -1006,7 +994,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) | |||
1006 | 994 | ||
1007 | isr_stats->rfkill++; | 995 | isr_stats->rfkill++; |
1008 | 996 | ||
1009 | iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); | 997 | iwl_trans_pcie_rf_kill(trans, hw_rfkill); |
1010 | if (hw_rfkill) { | 998 | if (hw_rfkill) { |
1011 | set_bit(STATUS_RFKILL, &trans->status); | 999 | set_bit(STATUS_RFKILL, &trans->status); |
1012 | if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE, | 1000 | if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE, |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index f9507807b486..dcfd6d866d09 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -75,6 +75,20 @@ | |||
75 | #include "iwl-agn-hw.h" | 75 | #include "iwl-agn-hw.h" |
76 | #include "internal.h" | 76 | #include "internal.h" |
77 | 77 | ||
78 | static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg) | ||
79 | { | ||
80 | iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG, | ||
81 | ((reg & 0x0000ffff) | (2 << 28))); | ||
82 | return iwl_read32(trans, HEEP_CTRL_WRD_PCIEX_DATA_REG); | ||
83 | } | ||
84 | |||
85 | static void iwl_trans_pcie_write_shr(struct iwl_trans *trans, u32 reg, u32 val) | ||
86 | { | ||
87 | iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_DATA_REG, val); | ||
88 | iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG, | ||
89 | ((reg & 0x0000ffff) | (3 << 28))); | ||
90 | } | ||
91 | |||
78 | static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) | 92 | static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) |
79 | { | 93 | { |
80 | if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) | 94 | if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) |
@@ -89,6 +103,7 @@ static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) | |||
89 | 103 | ||
90 | /* PCI registers */ | 104 | /* PCI registers */ |
91 | #define PCI_CFG_RETRY_TIMEOUT 0x041 | 105 | #define PCI_CFG_RETRY_TIMEOUT 0x041 |
106 | #define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC | ||
92 | 107 | ||
93 | static void iwl_pcie_apm_config(struct iwl_trans *trans) | 108 | static void iwl_pcie_apm_config(struct iwl_trans *trans) |
94 | { | 109 | { |
@@ -132,8 +147,9 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) | |||
132 | */ | 147 | */ |
133 | 148 | ||
134 | /* Disable L0S exit timer (platform NMI Work/Around) */ | 149 | /* Disable L0S exit timer (platform NMI Work/Around) */ |
135 | iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, | 150 | if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) |
136 | CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); | 151 | iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, |
152 | CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); | ||
137 | 153 | ||
138 | /* | 154 | /* |
139 | * Disable L0s without affecting L1; | 155 | * Disable L0s without affecting L1; |
@@ -203,19 +219,23 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) | |||
203 | /* | 219 | /* |
204 | * Enable DMA clock and wait for it to stabilize. | 220 | * Enable DMA clock and wait for it to stabilize. |
205 | * | 221 | * |
206 | * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits | 222 | * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" |
207 | * do not disable clocks. This preserves any hardware bits already | 223 | * bits do not disable clocks. This preserves any hardware |
208 | * set by default in "CLK_CTRL_REG" after reset. | 224 | * bits already set by default in "CLK_CTRL_REG" after reset. |
209 | */ | 225 | */ |
210 | iwl_write_prph(trans, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); | 226 | if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { |
211 | udelay(20); | 227 | iwl_write_prph(trans, APMG_CLK_EN_REG, |
228 | APMG_CLK_VAL_DMA_CLK_RQT); | ||
229 | udelay(20); | ||
212 | 230 | ||
213 | /* Disable L1-Active */ | 231 | /* Disable L1-Active */ |
214 | iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG, | 232 | iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG, |
215 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); | 233 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); |
216 | 234 | ||
217 | /* Clear the interrupt in APMG if the NIC is in RFKILL */ | 235 | /* Clear the interrupt in APMG if the NIC is in RFKILL */ |
218 | iwl_write_prph(trans, APMG_RTC_INT_STT_REG, APMG_RTC_INT_STT_RFKILL); | 236 | iwl_write_prph(trans, APMG_RTC_INT_STT_REG, |
237 | APMG_RTC_INT_STT_RFKILL); | ||
238 | } | ||
219 | 239 | ||
220 | set_bit(STATUS_DEVICE_ENABLED, &trans->status); | 240 | set_bit(STATUS_DEVICE_ENABLED, &trans->status); |
221 | 241 | ||
@@ -223,6 +243,116 @@ out: | |||
223 | return ret; | 243 | return ret; |
224 | } | 244 | } |
225 | 245 | ||
246 | /* | ||
247 | * Enable LP XTAL to avoid HW bug where device may consume much power if | ||
248 | * FW is not loaded after device reset. LP XTAL is disabled by default | ||
249 | * after device HW reset. Do it only if XTAL is fed by internal source. | ||
250 | * Configure device's "persistence" mode to avoid resetting XTAL again when | ||
251 | * SHRD_HW_RST occurs in S3. | ||
252 | */ | ||
253 | static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) | ||
254 | { | ||
255 | int ret; | ||
256 | u32 apmg_gp1_reg; | ||
257 | u32 apmg_xtal_cfg_reg; | ||
258 | u32 dl_cfg_reg; | ||
259 | |||
260 | /* Force XTAL ON */ | ||
261 | __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, | ||
262 | CSR_GP_CNTRL_REG_FLAG_XTAL_ON); | ||
263 | |||
264 | /* Reset entire device - do controller reset (results in SHRD_HW_RST) */ | ||
265 | iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); | ||
266 | |||
267 | udelay(10); | ||
268 | |||
269 | /* | ||
270 | * Set "initialization complete" bit to move adapter from | ||
271 | * D0U* --> D0A* (powered-up active) state. | ||
272 | */ | ||
273 | iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | ||
274 | |||
275 | /* | ||
276 | * Wait for clock stabilization; once stabilized, access to | ||
277 | * device-internal resources is possible. | ||
278 | */ | ||
279 | ret = iwl_poll_bit(trans, CSR_GP_CNTRL, | ||
280 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | ||
281 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | ||
282 | 25000); | ||
283 | if (WARN_ON(ret < 0)) { | ||
284 | IWL_ERR(trans, "Access time out - failed to enable LP XTAL\n"); | ||
285 | /* Release XTAL ON request */ | ||
286 | __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, | ||
287 | CSR_GP_CNTRL_REG_FLAG_XTAL_ON); | ||
288 | return; | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * Clear "disable persistence" to avoid LP XTAL resetting when | ||
293 | * SHRD_HW_RST is applied in S3. | ||
294 | */ | ||
295 | iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, | ||
296 | APMG_PCIDEV_STT_VAL_PERSIST_DIS); | ||
297 | |||
298 | /* | ||
299 | * Force APMG XTAL to be active to prevent its disabling by HW | ||
300 | * caused by APMG idle state. | ||
301 | */ | ||
302 | apmg_xtal_cfg_reg = iwl_trans_pcie_read_shr(trans, | ||
303 | SHR_APMG_XTAL_CFG_REG); | ||
304 | iwl_trans_pcie_write_shr(trans, SHR_APMG_XTAL_CFG_REG, | ||
305 | apmg_xtal_cfg_reg | | ||
306 | SHR_APMG_XTAL_CFG_XTAL_ON_REQ); | ||
307 | |||
308 | /* | ||
309 | * Reset entire device again - do controller reset (results in | ||
310 | * SHRD_HW_RST). Turn MAC off before proceeding. | ||
311 | */ | ||
312 | iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); | ||
313 | |||
314 | udelay(10); | ||
315 | |||
316 | /* Enable LP XTAL by indirect access through CSR */ | ||
317 | apmg_gp1_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_GP1_REG); | ||
318 | iwl_trans_pcie_write_shr(trans, SHR_APMG_GP1_REG, apmg_gp1_reg | | ||
319 | SHR_APMG_GP1_WF_XTAL_LP_EN | | ||
320 | SHR_APMG_GP1_CHICKEN_BIT_SELECT); | ||
321 | |||
322 | /* Clear delay line clock power up */ | ||
323 | dl_cfg_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_DL_CFG_REG); | ||
324 | iwl_trans_pcie_write_shr(trans, SHR_APMG_DL_CFG_REG, dl_cfg_reg & | ||
325 | ~SHR_APMG_DL_CFG_DL_CLOCK_POWER_UP); | ||
326 | |||
327 | /* | ||
328 | * Enable persistence mode to avoid LP XTAL resetting when | ||
329 | * SHRD_HW_RST is applied in S3. | ||
330 | */ | ||
331 | iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, | ||
332 | CSR_HW_IF_CONFIG_REG_PERSIST_MODE); | ||
333 | |||
334 | /* | ||
335 | * Clear "initialization complete" bit to move adapter from | ||
336 | * D0A* (powered-up Active) --> D0U* (Uninitialized) state. | ||
337 | */ | ||
338 | iwl_clear_bit(trans, CSR_GP_CNTRL, | ||
339 | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | ||
340 | |||
341 | /* Activates XTAL resources monitor */ | ||
342 | __iwl_trans_pcie_set_bit(trans, CSR_MONITOR_CFG_REG, | ||
343 | CSR_MONITOR_XTAL_RESOURCES); | ||
344 | |||
345 | /* Release XTAL ON request */ | ||
346 | __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, | ||
347 | CSR_GP_CNTRL_REG_FLAG_XTAL_ON); | ||
348 | udelay(10); | ||
349 | |||
350 | /* Release APMG XTAL */ | ||
351 | iwl_trans_pcie_write_shr(trans, SHR_APMG_XTAL_CFG_REG, | ||
352 | apmg_xtal_cfg_reg & | ||
353 | ~SHR_APMG_XTAL_CFG_XTAL_ON_REQ); | ||
354 | } | ||
355 | |||
226 | static int iwl_pcie_apm_stop_master(struct iwl_trans *trans) | 356 | static int iwl_pcie_apm_stop_master(struct iwl_trans *trans) |
227 | { | 357 | { |
228 | int ret = 0; | 358 | int ret = 0; |
@@ -250,6 +380,11 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans) | |||
250 | /* Stop device's DMA activity */ | 380 | /* Stop device's DMA activity */ |
251 | iwl_pcie_apm_stop_master(trans); | 381 | iwl_pcie_apm_stop_master(trans); |
252 | 382 | ||
383 | if (trans->cfg->lp_xtal_workaround) { | ||
384 | iwl_pcie_apm_lp_xtal_enable(trans); | ||
385 | return; | ||
386 | } | ||
387 | |||
253 | /* Reset the entire device */ | 388 | /* Reset the entire device */ |
254 | iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); | 389 | iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); |
255 | 390 | ||
@@ -273,7 +408,8 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans) | |||
273 | 408 | ||
274 | spin_unlock(&trans_pcie->irq_lock); | 409 | spin_unlock(&trans_pcie->irq_lock); |
275 | 410 | ||
276 | iwl_pcie_set_pwr(trans, false); | 411 | if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) |
412 | iwl_pcie_set_pwr(trans, false); | ||
277 | 413 | ||
278 | iwl_op_mode_nic_config(trans->op_mode); | 414 | iwl_op_mode_nic_config(trans->op_mode); |
279 | 415 | ||
@@ -435,78 +571,106 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, | |||
435 | return ret; | 571 | return ret; |
436 | } | 572 | } |
437 | 573 | ||
438 | static int iwl_pcie_secure_set(struct iwl_trans *trans, int cpu) | 574 | static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans, |
575 | const struct fw_img *image, | ||
576 | int cpu, | ||
577 | int *first_ucode_section) | ||
439 | { | 578 | { |
440 | int shift_param; | 579 | int shift_param; |
441 | u32 address; | 580 | int i, ret = 0; |
442 | int ret = 0; | 581 | u32 last_read_idx = 0; |
443 | 582 | ||
444 | if (cpu == 1) { | 583 | if (cpu == 1) { |
445 | shift_param = 0; | 584 | shift_param = 0; |
446 | address = CSR_SECURE_BOOT_CPU1_STATUS_ADDR; | 585 | *first_ucode_section = 0; |
447 | } else { | 586 | } else { |
448 | shift_param = 16; | 587 | shift_param = 16; |
449 | address = CSR_SECURE_BOOT_CPU2_STATUS_ADDR; | 588 | (*first_ucode_section)++; |
450 | } | 589 | } |
451 | 590 | ||
452 | /* set CPU to started */ | 591 | for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) { |
453 | iwl_trans_set_bits_mask(trans, | 592 | last_read_idx = i; |
454 | CSR_UCODE_LOAD_STATUS_ADDR, | ||
455 | CSR_CPU_STATUS_LOADING_STARTED << shift_param, | ||
456 | 1); | ||
457 | |||
458 | /* set last complete descriptor number */ | ||
459 | iwl_trans_set_bits_mask(trans, | ||
460 | CSR_UCODE_LOAD_STATUS_ADDR, | ||
461 | CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED | ||
462 | << shift_param, | ||
463 | 1); | ||
464 | |||
465 | /* set last loaded block */ | ||
466 | iwl_trans_set_bits_mask(trans, | ||
467 | CSR_UCODE_LOAD_STATUS_ADDR, | ||
468 | CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK | ||
469 | << shift_param, | ||
470 | 1); | ||
471 | 593 | ||
594 | if (!image->sec[i].data || | ||
595 | image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) { | ||
596 | IWL_DEBUG_FW(trans, | ||
597 | "Break since Data not valid or Empty section, sec = %d\n", | ||
598 | i); | ||
599 | break; | ||
600 | } | ||
601 | |||
602 | if (i == (*first_ucode_section) + 1) | ||
603 | /* set CPU to started */ | ||
604 | iwl_set_bits_prph(trans, | ||
605 | CSR_UCODE_LOAD_STATUS_ADDR, | ||
606 | LMPM_CPU_HDRS_LOADING_COMPLETED | ||
607 | << shift_param); | ||
608 | |||
609 | ret = iwl_pcie_load_section(trans, i, &image->sec[i]); | ||
610 | if (ret) | ||
611 | return ret; | ||
612 | } | ||
472 | /* image loading complete */ | 613 | /* image loading complete */ |
473 | iwl_trans_set_bits_mask(trans, | 614 | iwl_set_bits_prph(trans, |
474 | CSR_UCODE_LOAD_STATUS_ADDR, | 615 | CSR_UCODE_LOAD_STATUS_ADDR, |
475 | CSR_CPU_STATUS_LOADING_COMPLETED | 616 | LMPM_CPU_UCODE_LOADING_COMPLETED << shift_param); |
476 | << shift_param, | 617 | |
477 | 1); | 618 | *first_ucode_section = last_read_idx; |
478 | 619 | ||
479 | /* set FH_TCSR_0_REG */ | 620 | return 0; |
480 | iwl_trans_set_bits_mask(trans, FH_TCSR_0_REG0, 0x00400000, 1); | 621 | } |
481 | 622 | ||
482 | /* verify image verification started */ | 623 | static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, |
483 | ret = iwl_poll_bit(trans, address, | 624 | const struct fw_img *image, |
484 | CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS, | 625 | int cpu, |
485 | CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS, | 626 | int *first_ucode_section) |
486 | CSR_SECURE_TIME_OUT); | 627 | { |
487 | if (ret < 0) { | 628 | int shift_param; |
488 | IWL_ERR(trans, "secure boot process didn't start\n"); | 629 | int i, ret = 0; |
489 | return ret; | 630 | u32 last_read_idx = 0; |
631 | |||
632 | if (cpu == 1) { | ||
633 | shift_param = 0; | ||
634 | *first_ucode_section = 0; | ||
635 | } else { | ||
636 | shift_param = 16; | ||
637 | (*first_ucode_section)++; | ||
490 | } | 638 | } |
491 | 639 | ||
492 | /* wait for image verification to complete */ | 640 | for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) { |
493 | ret = iwl_poll_bit(trans, address, | 641 | last_read_idx = i; |
494 | CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED, | ||
495 | CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED, | ||
496 | CSR_SECURE_TIME_OUT); | ||
497 | 642 | ||
498 | if (ret < 0) { | 643 | if (!image->sec[i].data || |
499 | IWL_ERR(trans, "Time out on secure boot process\n"); | 644 | image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) { |
500 | return ret; | 645 | IWL_DEBUG_FW(trans, |
646 | "Break since Data not valid or Empty section, sec = %d\n", | ||
647 | i); | ||
648 | break; | ||
649 | } | ||
650 | |||
651 | ret = iwl_pcie_load_section(trans, i, &image->sec[i]); | ||
652 | if (ret) | ||
653 | return ret; | ||
501 | } | 654 | } |
502 | 655 | ||
656 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
657 | iwl_set_bits_prph(trans, | ||
658 | CSR_UCODE_LOAD_STATUS_ADDR, | ||
659 | (LMPM_CPU_UCODE_LOADING_COMPLETED | | ||
660 | LMPM_CPU_HDRS_LOADING_COMPLETED | | ||
661 | LMPM_CPU_UCODE_LOADING_STARTED) << | ||
662 | shift_param); | ||
663 | |||
664 | *first_ucode_section = last_read_idx; | ||
665 | |||
503 | return 0; | 666 | return 0; |
504 | } | 667 | } |
505 | 668 | ||
506 | static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | 669 | static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, |
507 | const struct fw_img *image) | 670 | const struct fw_img *image) |
508 | { | 671 | { |
509 | int i, ret = 0; | 672 | int ret = 0; |
673 | int first_ucode_section; | ||
510 | 674 | ||
511 | IWL_DEBUG_FW(trans, | 675 | IWL_DEBUG_FW(trans, |
512 | "working with %s image\n", | 676 | "working with %s image\n", |
@@ -518,53 +682,68 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | |||
518 | /* configure the ucode to be ready to get the secured image */ | 682 | /* configure the ucode to be ready to get the secured image */ |
519 | if (image->is_secure) { | 683 | if (image->is_secure) { |
520 | /* set secure boot inspector addresses */ | 684 | /* set secure boot inspector addresses */ |
521 | iwl_write32(trans, CSR_SECURE_INSPECTOR_CODE_ADDR, 0); | 685 | iwl_write_prph(trans, |
522 | iwl_write32(trans, CSR_SECURE_INSPECTOR_DATA_ADDR, 0); | 686 | LMPM_SECURE_INSPECTOR_CODE_ADDR, |
523 | 687 | LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE); | |
524 | /* release CPU1 reset if secure inspector image burned in OTP */ | 688 | |
525 | iwl_write32(trans, CSR_RESET, 0); | 689 | iwl_write_prph(trans, |
526 | } | 690 | LMPM_SECURE_INSPECTOR_DATA_ADDR, |
527 | 691 | LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE); | |
528 | /* load to FW the binary sections of CPU1 */ | 692 | |
529 | IWL_DEBUG_INFO(trans, "Loading CPU1\n"); | 693 | /* set CPU1 header address */ |
530 | for (i = 0; | 694 | iwl_write_prph(trans, |
531 | i < IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU; | 695 | LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR, |
532 | i++) { | 696 | LMPM_SECURE_CPU1_HDR_MEM_SPACE); |
533 | if (!image->sec[i].data) | 697 | |
534 | break; | 698 | /* load to FW the binary Secured sections of CPU1 */ |
535 | ret = iwl_pcie_load_section(trans, i, &image->sec[i]); | 699 | ret = iwl_pcie_load_cpu_secured_sections(trans, image, 1, |
700 | &first_ucode_section); | ||
536 | if (ret) | 701 | if (ret) |
537 | return ret; | 702 | return ret; |
538 | } | ||
539 | 703 | ||
540 | /* configure the ucode to start secure process on CPU1 */ | 704 | } else { |
541 | if (image->is_secure) { | 705 | /* load to FW the binary Non secured sections of CPU1 */ |
542 | /* config CPU1 to start secure protocol */ | 706 | ret = iwl_pcie_load_cpu_sections(trans, image, 1, |
543 | ret = iwl_pcie_secure_set(trans, 1); | 707 | &first_ucode_section); |
544 | if (ret) | 708 | if (ret) |
545 | return ret; | 709 | return ret; |
546 | } else { | ||
547 | /* Remove all resets to allow NIC to operate */ | ||
548 | iwl_write32(trans, CSR_RESET, 0); | ||
549 | } | 710 | } |
550 | 711 | ||
551 | if (image->is_dual_cpus) { | 712 | if (image->is_dual_cpus) { |
713 | /* set CPU2 header address */ | ||
714 | iwl_write_prph(trans, | ||
715 | LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR, | ||
716 | LMPM_SECURE_CPU2_HDR_MEM_SPACE); | ||
717 | |||
552 | /* load to FW the binary sections of CPU2 */ | 718 | /* load to FW the binary sections of CPU2 */ |
553 | IWL_DEBUG_INFO(trans, "working w/ DUAL CPUs - Loading CPU2\n"); | 719 | if (image->is_secure) |
554 | for (i = IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU; | 720 | ret = iwl_pcie_load_cpu_secured_sections( |
555 | i < IWL_UCODE_SECTION_MAX; i++) { | 721 | trans, image, 2, |
556 | if (!image->sec[i].data) | 722 | &first_ucode_section); |
557 | break; | 723 | else |
558 | ret = iwl_pcie_load_section(trans, i, &image->sec[i]); | 724 | ret = iwl_pcie_load_cpu_sections(trans, image, 2, |
559 | if (ret) | 725 | &first_ucode_section); |
560 | return ret; | 726 | if (ret) |
561 | } | 727 | return ret; |
728 | } | ||
729 | |||
730 | /* release CPU reset */ | ||
731 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
732 | iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); | ||
733 | else | ||
734 | iwl_write32(trans, CSR_RESET, 0); | ||
562 | 735 | ||
563 | if (image->is_secure) { | 736 | if (image->is_secure) { |
564 | /* set CPU2 for secure protocol */ | 737 | /* wait for image verification to complete */ |
565 | ret = iwl_pcie_secure_set(trans, 2); | 738 | ret = iwl_poll_prph_bit(trans, |
566 | if (ret) | 739 | LMPM_SECURE_BOOT_CPU1_STATUS_ADDR, |
567 | return ret; | 740 | LMPM_SECURE_BOOT_STATUS_SUCCESS, |
741 | LMPM_SECURE_BOOT_STATUS_SUCCESS, | ||
742 | LMPM_SECURE_TIME_OUT); | ||
743 | |||
744 | if (ret < 0) { | ||
745 | IWL_ERR(trans, "Time out on secure boot process\n"); | ||
746 | return ret; | ||
568 | } | 747 | } |
569 | } | 748 | } |
570 | 749 | ||
@@ -591,7 +770,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, | |||
591 | set_bit(STATUS_RFKILL, &trans->status); | 770 | set_bit(STATUS_RFKILL, &trans->status); |
592 | else | 771 | else |
593 | clear_bit(STATUS_RFKILL, &trans->status); | 772 | clear_bit(STATUS_RFKILL, &trans->status); |
594 | iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); | 773 | iwl_trans_pcie_rf_kill(trans, hw_rfkill); |
595 | if (hw_rfkill && !run_in_rfkill) | 774 | if (hw_rfkill && !run_in_rfkill) |
596 | return -ERFKILL; | 775 | return -ERFKILL; |
597 | 776 | ||
@@ -706,7 +885,13 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | |||
706 | else | 885 | else |
707 | clear_bit(STATUS_RFKILL, &trans->status); | 886 | clear_bit(STATUS_RFKILL, &trans->status); |
708 | if (hw_rfkill != was_hw_rfkill) | 887 | if (hw_rfkill != was_hw_rfkill) |
709 | iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); | 888 | iwl_trans_pcie_rf_kill(trans, hw_rfkill); |
889 | } | ||
890 | |||
891 | void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) | ||
892 | { | ||
893 | if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) | ||
894 | iwl_trans_pcie_stop_device(trans); | ||
710 | } | 895 | } |
711 | 896 | ||
712 | static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) | 897 | static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) |
@@ -815,7 +1000,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) | |||
815 | set_bit(STATUS_RFKILL, &trans->status); | 1000 | set_bit(STATUS_RFKILL, &trans->status); |
816 | else | 1001 | else |
817 | clear_bit(STATUS_RFKILL, &trans->status); | 1002 | clear_bit(STATUS_RFKILL, &trans->status); |
818 | iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); | 1003 | iwl_trans_pcie_rf_kill(trans, hw_rfkill); |
819 | 1004 | ||
820 | return 0; | 1005 | return 0; |
821 | } | 1006 | } |
@@ -1158,6 +1343,7 @@ static const char *get_csr_string(int cmd) | |||
1158 | IWL_CMD(CSR_GIO_CHICKEN_BITS); | 1343 | IWL_CMD(CSR_GIO_CHICKEN_BITS); |
1159 | IWL_CMD(CSR_ANA_PLL_CFG); | 1344 | IWL_CMD(CSR_ANA_PLL_CFG); |
1160 | IWL_CMD(CSR_HW_REV_WA_REG); | 1345 | IWL_CMD(CSR_HW_REV_WA_REG); |
1346 | IWL_CMD(CSR_MONITOR_STATUS_REG); | ||
1161 | IWL_CMD(CSR_DBG_HPET_MEM_REG); | 1347 | IWL_CMD(CSR_DBG_HPET_MEM_REG); |
1162 | default: | 1348 | default: |
1163 | return "UNKNOWN"; | 1349 | return "UNKNOWN"; |
@@ -1190,6 +1376,7 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans) | |||
1190 | CSR_DRAM_INT_TBL_REG, | 1376 | CSR_DRAM_INT_TBL_REG, |
1191 | CSR_GIO_CHICKEN_BITS, | 1377 | CSR_GIO_CHICKEN_BITS, |
1192 | CSR_ANA_PLL_CFG, | 1378 | CSR_ANA_PLL_CFG, |
1379 | CSR_MONITOR_STATUS_REG, | ||
1193 | CSR_HW_REV_WA_REG, | 1380 | CSR_HW_REV_WA_REG, |
1194 | CSR_DBG_HPET_MEM_REG | 1381 | CSR_DBG_HPET_MEM_REG |
1195 | }; | 1382 | }; |
@@ -1407,16 +1594,15 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, | |||
1407 | { | 1594 | { |
1408 | struct iwl_trans *trans = file->private_data; | 1595 | struct iwl_trans *trans = file->private_data; |
1409 | char *buf = NULL; | 1596 | char *buf = NULL; |
1410 | int pos = 0; | 1597 | ssize_t ret; |
1411 | ssize_t ret = -EFAULT; | ||
1412 | |||
1413 | ret = pos = iwl_dump_fh(trans, &buf); | ||
1414 | if (buf) { | ||
1415 | ret = simple_read_from_buffer(user_buf, | ||
1416 | count, ppos, buf, pos); | ||
1417 | kfree(buf); | ||
1418 | } | ||
1419 | 1598 | ||
1599 | ret = iwl_dump_fh(trans, &buf); | ||
1600 | if (ret < 0) | ||
1601 | return ret; | ||
1602 | if (!buf) | ||
1603 | return -EINVAL; | ||
1604 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); | ||
1605 | kfree(buf); | ||
1420 | return ret; | 1606 | return ret; |
1421 | } | 1607 | } |
1422 | 1608 | ||
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 3d549008b3e2..3b0c72c10054 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -207,7 +207,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) | |||
207 | IWL_ERR(trans, "scratch %d = 0x%08x\n", i, | 207 | IWL_ERR(trans, "scratch %d = 0x%08x\n", i, |
208 | le32_to_cpu(txq->scratchbufs[i].scratch)); | 208 | le32_to_cpu(txq->scratchbufs[i].scratch)); |
209 | 209 | ||
210 | iwl_trans_fw_error(trans); | 210 | iwl_write_prph(trans, DEVICE_SET_NMI_REG, 1); |
211 | } | 211 | } |
212 | 212 | ||
213 | /* | 213 | /* |
@@ -296,43 +296,38 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq) | |||
296 | if (txq->need_update == 0) | 296 | if (txq->need_update == 0) |
297 | return; | 297 | return; |
298 | 298 | ||
299 | if (trans->cfg->base_params->shadow_reg_enable || | 299 | /* |
300 | txq_id == trans_pcie->cmd_queue) { | 300 | * explicitly wake up the NIC if: |
301 | /* shadow register enabled */ | 301 | * 1. shadow registers aren't enabled |
302 | iwl_write32(trans, HBUS_TARG_WRPTR, | 302 | * 2. NIC is woken up for CMD regardless of shadow outside this function |
303 | txq->q.write_ptr | (txq_id << 8)); | 303 | * 3. there is a chance that the NIC is asleep |
304 | } else { | 304 | */ |
305 | /* if we're trying to save power */ | 305 | if (!trans->cfg->base_params->shadow_reg_enable && |
306 | if (test_bit(STATUS_TPOWER_PMI, &trans->status)) { | 306 | txq_id != trans_pcie->cmd_queue && |
307 | /* wake up nic if it's powered down ... | 307 | test_bit(STATUS_TPOWER_PMI, &trans->status)) { |
308 | * uCode will wake up, and interrupt us again, so next | ||
309 | * time we'll skip this part. */ | ||
310 | reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); | ||
311 | |||
312 | if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { | ||
313 | IWL_DEBUG_INFO(trans, | ||
314 | "Tx queue %d requesting wakeup," | ||
315 | " GP1 = 0x%x\n", txq_id, reg); | ||
316 | iwl_set_bit(trans, CSR_GP_CNTRL, | ||
317 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
318 | return; | ||
319 | } | ||
320 | |||
321 | IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, | ||
322 | txq->q.write_ptr); | ||
323 | |||
324 | iwl_write_direct32(trans, HBUS_TARG_WRPTR, | ||
325 | txq->q.write_ptr | (txq_id << 8)); | ||
326 | |||
327 | /* | 308 | /* |
328 | * else not in power-save mode, | 309 | * wake up nic if it's powered down ... |
329 | * uCode will never sleep when we're | 310 | * uCode will wake up, and interrupt us again, so next |
330 | * trying to tx (during RFKILL, we're not trying to tx). | 311 | * time we'll skip this part. |
331 | */ | 312 | */ |
332 | } else | 313 | reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); |
333 | iwl_write32(trans, HBUS_TARG_WRPTR, | 314 | |
334 | txq->q.write_ptr | (txq_id << 8)); | 315 | if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { |
316 | IWL_DEBUG_INFO(trans, "Tx queue %d requesting wakeup, GP1 = 0x%x\n", | ||
317 | txq_id, reg); | ||
318 | iwl_set_bit(trans, CSR_GP_CNTRL, | ||
319 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
320 | return; | ||
321 | } | ||
335 | } | 322 | } |
323 | |||
324 | /* | ||
325 | * if not in power-save mode, uCode will never sleep when we're | ||
326 | * trying to tx (during RFKILL, we're not trying to tx). | ||
327 | */ | ||
328 | IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, txq->q.write_ptr); | ||
329 | iwl_write32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); | ||
330 | |||
336 | txq->need_update = 0; | 331 | txq->need_update = 0; |
337 | } | 332 | } |
338 | 333 | ||
@@ -705,8 +700,9 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) | |||
705 | reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); | 700 | reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); |
706 | 701 | ||
707 | /* Enable L1-Active */ | 702 | /* Enable L1-Active */ |
708 | iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, | 703 | if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) |
709 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); | 704 | iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, |
705 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); | ||
710 | } | 706 | } |
711 | 707 | ||
712 | void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) | 708 | void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) |
@@ -1028,7 +1024,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) | |||
1028 | if (nfreed++ > 0) { | 1024 | if (nfreed++ > 0) { |
1029 | IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", | 1025 | IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", |
1030 | idx, q->write_ptr, q->read_ptr); | 1026 | idx, q->write_ptr, q->read_ptr); |
1031 | iwl_trans_fw_error(trans); | 1027 | iwl_write_prph(trans, DEVICE_SET_NMI_REG, 1); |
1032 | } | 1028 | } |
1033 | } | 1029 | } |
1034 | 1030 | ||
@@ -1587,6 +1583,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, | |||
1587 | get_cmd_string(trans_pcie, cmd->id)); | 1583 | get_cmd_string(trans_pcie, cmd->id)); |
1588 | ret = -ETIMEDOUT; | 1584 | ret = -ETIMEDOUT; |
1589 | 1585 | ||
1586 | iwl_write_prph(trans, DEVICE_SET_NMI_REG, 1); | ||
1590 | iwl_trans_fw_error(trans); | 1587 | iwl_trans_fw_error(trans); |
1591 | 1588 | ||
1592 | goto cancel; | 1589 | goto cancel; |