summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/DocBook/80211.tmpl1
-rw-r--r--Documentation/kernel-parameters.txt12
-rw-r--r--Documentation/rfkill.txt3
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/bcma/bcma_private.h18
-rw-r--r--drivers/bcma/driver_chipcommon.c20
-rw-r--r--drivers/bcma/driver_pci.c68
-rw-r--r--drivers/bcma/host_pci.c6
-rw-r--r--drivers/bcma/host_soc.c2
-rw-r--r--drivers/bcma/main.c76
-rw-r--r--drivers/bcma/scan.c67
-rw-r--r--drivers/bcma/sprom.c3
-rw-r--r--drivers/net/wireless/adm8211.c1
-rw-r--r--drivers/net/wireless/ath/ath.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c3
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c8
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c16
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c17
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c80
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c61
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_hw.c61
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c47
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.h19
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_wow.c315
-rw-r--r--drivers/net/wireless/ath/ath9k/ar953x_initvals.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/ar956x_initvals.h1046
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h15
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c202
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_gpio.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c54
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h40
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/link.c16
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c90
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h129
-rw-r--r--drivers/net/wireless/ath/ath9k/reg_wow.h128
-rw-r--r--drivers/net/wireless/ath/ath9k/wow.c228
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c83
-rw-r--r--drivers/net/wireless/ath/carl9170/cmd.c12
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c6
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.c3
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c16
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c73
-rw-r--r--drivers/net/wireless/ath/wcn36xx/txrx.c83
-rw-r--r--drivers/net/wireless/ath/wcn36xx/txrx.h9
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx.h20
-rw-r--r--drivers/net/wireless/ath/wil6210/Kconfig9
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile1
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c179
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c160
-rw-r--r--drivers/net/wireless/ath/wil6210/ethtool.c46
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c109
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c205
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c15
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c65
-rw-r--r--drivers/net/wireless/ath/wil6210/rx_reorder.c277
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c151
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h158
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h183
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.c12
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform_msm.c257
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform_msm.h24
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c239
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h70
-rw-r--r--drivers/net/wireless/atmel.c12
-rw-r--r--drivers/net/wireless/b43/Kconfig9
-rw-r--r--drivers/net/wireless/b43/Makefile1
-rw-r--r--drivers/net/wireless/b43/b43.h3
-rw-r--r--drivers/net/wireless/b43/main.c71
-rw-r--r--drivers/net/wireless/b43/phy_ac.c92
-rw-r--r--drivers/net/wireless/b43/phy_ac.h38
-rw-r--r--drivers/net/wireless/b43/phy_common.c9
-rw-r--r--drivers/net/wireless/b43/phy_common.h2
-rw-r--r--drivers/net/wireless/b43legacy/radio.c19
-rw-r--r--drivers/net/wireless/b43legacy/radio.h1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c70
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bus.h24
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c51
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/common.c31
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/commonring.h2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/core.c39
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/core.h30
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/firmware.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil.h1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h41
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c30
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/pcie.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio.c171
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio.h12
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/debug.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmutil/utils.c32
-rw-r--r--drivers/net/wireless/brcm80211/include/brcmu_utils.h4
-rw-r--r--drivers/net/wireless/cw1200/fwio.c40
-rw-r--r--drivers/net/wireless/cw1200/main.c1
-rw-r--r--drivers/net/wireless/cw1200/scan.c8
-rw-r--r--drivers/net/wireless/cw1200/sta.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/main.c7
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tx.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/ucode.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-7000.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-8000.c16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-config.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-modparams.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h47
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scd.h41
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h29
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex.c16
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex_legacy.c16
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/constants.h11
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c31
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c195
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-power.h20
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h40
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h277
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h39
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h301
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c98
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c22
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c250
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h54
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c42
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c392
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.h14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c10
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c120
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c28
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tdls.c63
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c29
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/utils.c77
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c6
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h10
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c16
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c72
-rw-r--r--drivers/net/wireless/libertas/cfg.c12
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c30
-rw-r--r--drivers/net/wireless/mwifiex/11h.c198
-rw-r--r--drivers/net/wireless/mwifiex/11n.c6
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c10
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c852
-rw-r--r--drivers/net/wireless/mwifiex/cfp.c4
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c40
-rw-r--r--drivers/net/wireless/mwifiex/decl.h21
-rw-r--r--drivers/net/wireless/mwifiex/fw.h58
-rw-r--r--drivers/net/wireless/mwifiex/ie.c89
-rw-r--r--drivers/net/wireless/mwifiex/init.c12
-rw-r--r--drivers/net/wireless/mwifiex/main.c14
-rw-r--r--drivers/net/wireless/mwifiex/main.h60
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c2
-rw-r--r--drivers/net/wireless/mwifiex/pcie.h3
-rw-r--r--drivers/net/wireless/mwifiex/scan.c16
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c7
-rw-r--r--drivers/net/wireless/mwifiex/sdio.h23
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c17
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c5
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c15
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c32
-rw-r--r--drivers/net/wireless/mwifiex/sta_tx.c9
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c2
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c70
-rw-r--r--drivers/net/wireless/mwifiex/uap_event.c48
-rw-r--r--drivers/net/wireless/mwifiex/usb.c16
-rw-r--r--drivers/net/wireless/mwifiex/usb.h4
-rw-r--r--drivers/net/wireless/mwifiex/util.c2
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c3
-rw-r--r--drivers/net/wireless/mwl8k.c12
-rw-r--r--drivers/net/wireless/orinoco/Kconfig3
-rw-r--r--drivers/net/wireless/orinoco/main.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_plx.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_tmd.c2
-rw-r--r--drivers/net/wireless/p54/eeprom.c6
-rw-r--r--drivers/net/wireless/p54/fwio.c9
-rw-r--r--drivers/net/wireless/p54/main.c10
-rw-r--r--drivers/net/wireless/p54/p54pci.c7
-rw-r--r--drivers/net/wireless/p54/txrx.c12
-rw-r--r--drivers/net/wireless/rndis_wlan.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c12
-rw-r--r--drivers/net/wireless/rtlwifi/core.c11
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c31
-rw-r--r--drivers/net/wireless/rtlwifi/pci.h7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/hw.c4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/hw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/fw.c6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/hw.c166
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/reg.h2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/sw.c3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/trx.c36
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/trx.h3
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h1
-rw-r--r--drivers/net/wireless/ti/wl1251/main.c5
-rw-r--r--drivers/net/wireless/ti/wlcore/acx.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c26
-rw-r--r--drivers/ssb/main.c19
-rw-r--r--drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c10
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c4
-rw-r--r--include/linux/bcma/bcma.h1
-rw-r--r--include/linux/bcma/bcma_driver_pci.h2
-rw-r--r--include/linux/bcma/bcma_regs.h2
-rw-r--r--include/linux/bcma/bcma_soc.h2
-rw-r--r--include/linux/ssb/ssb_regs.h1
-rw-r--r--include/net/cfg80211.h288
-rw-r--r--include/net/mac80211.h54
-rw-r--r--include/net/regulatory.h19
-rw-r--r--include/uapi/linux/nl80211.h187
-rw-r--r--net/mac80211/cfg.c40
-rw-r--r--net/mac80211/chan.c37
-rw-r--r--net/mac80211/debugfs.c2
-rw-r--r--net/mac80211/driver-ops.h30
-rw-r--r--net/mac80211/ethtool.c26
-rw-r--r--net/mac80211/ibss.c11
-rw-r--r--net/mac80211/ieee80211_i.h8
-rw-r--r--net/mac80211/iface.c2
-rw-r--r--net/mac80211/key.c9
-rw-r--r--net/mac80211/main.c4
-rw-r--r--net/mac80211/mesh_plink.c7
-rw-r--r--net/mac80211/mlme.c93
-rw-r--r--net/mac80211/offchannel.c4
-rw-r--r--net/mac80211/pm.c2
-rw-r--r--net/mac80211/rc80211_minstrel.c6
-rw-r--r--net/mac80211/rc80211_minstrel.h15
-rw-r--r--net/mac80211/rx.c25
-rw-r--r--net/mac80211/scan.c8
-rw-r--r--net/mac80211/spectmgmt.c4
-rw-r--r--net/mac80211/sta_info.c175
-rw-r--r--net/mac80211/sta_info.h12
-rw-r--r--net/mac80211/status.c26
-rw-r--r--net/mac80211/tdls.c32
-rw-r--r--net/mac80211/trace.h33
-rw-r--r--net/mac80211/tx.c5
-rw-r--r--net/mac80211/util.c56
-rw-r--r--net/mac80211/vht.c73
-rw-r--r--net/wireless/core.c34
-rw-r--r--net/wireless/core.h11
-rw-r--r--net/wireless/nl80211.c670
-rw-r--r--net/wireless/nl80211.h16
-rw-r--r--net/wireless/reg.c160
-rw-r--r--net/wireless/reg.h1
-rw-r--r--net/wireless/scan.c13
-rw-r--r--net/wireless/trace.h31
-rw-r--r--net/wireless/util.c25
-rw-r--r--net/wireless/wext-compat.c10
270 files changed, 9402 insertions, 3754 deletions
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl
index d9b9416c989f..49b8b8907f36 100644
--- a/Documentation/DocBook/80211.tmpl
+++ b/Documentation/DocBook/80211.tmpl
@@ -113,7 +113,6 @@
!Finclude/net/cfg80211.h cfg80211_beacon_data
!Finclude/net/cfg80211.h cfg80211_ap_settings
!Finclude/net/cfg80211.h station_parameters
-!Finclude/net/cfg80211.h station_info_flags
!Finclude/net/cfg80211.h rate_info_flags
!Finclude/net/cfg80211.h rate_info
!Finclude/net/cfg80211.h station_info
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 4df73da11adc..cdb815e833b5 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -3206,6 +3206,18 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
retain_initrd [RAM] Keep initrd memory after extraction
+ rfkill.default_state=
+ 0 "airplane mode". All wifi, bluetooth, wimax, gps, fm,
+ etc. communication is blocked by default.
+ 1 Unblocked.
+
+ rfkill.master_switch_mode=
+ 0 The "airplane mode" button does nothing.
+ 1 The "airplane mode" button toggles between everything
+ blocked and the previous configuration.
+ 2 The "airplane mode" button toggles between everything
+ blocked and everything unblocked.
+
rhash_entries= [KNL,NET]
Set number of hash buckets for route cache
diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt
index 427e89712f4a..2ee6ef9a6554 100644
--- a/Documentation/rfkill.txt
+++ b/Documentation/rfkill.txt
@@ -25,6 +25,9 @@ whether they can be changed or not:
- soft block: writable radio block (need not be readable) that is set by
the system software.
+The rfkill subsystem has two parameters, rfkill.default_state and
+rfkill.master_switch_mode, which are documented in kernel-parameters.txt.
+
2. Implementation details
diff --git a/MAINTAINERS b/MAINTAINERS
index 33098956d930..788d3a1fc723 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1657,7 +1657,6 @@ M: Jiri Slaby <jirislaby@gmail.com>
M: Nick Kossifidis <mickflemm@gmail.com>
M: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
L: linux-wireless@vger.kernel.org
-L: ath5k-devel@lists.ath5k.org
W: http://wireless.kernel.org/en/users/Drivers/ath5k
S: Maintained
F: drivers/net/wireless/ath/ath5k/
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 314ae4032f3e..ac6c5fca906d 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -25,22 +25,18 @@ struct bcma_bus;
bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
int timeout);
void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core);
+void bcma_init_bus(struct bcma_bus *bus);
int bcma_bus_register(struct bcma_bus *bus);
void bcma_bus_unregister(struct bcma_bus *bus);
-int __init bcma_bus_early_register(struct bcma_bus *bus,
- struct bcma_device *core_cc,
- struct bcma_device *core_mips);
+int __init bcma_bus_early_register(struct bcma_bus *bus);
#ifdef CONFIG_PM
int bcma_bus_suspend(struct bcma_bus *bus);
int bcma_bus_resume(struct bcma_bus *bus);
#endif
/* scan.c */
+void bcma_detect_chip(struct bcma_bus *bus);
int bcma_bus_scan(struct bcma_bus *bus);
-int __init bcma_bus_scan_early(struct bcma_bus *bus,
- struct bcma_device_id *match,
- struct bcma_device *core);
-void bcma_init_bus(struct bcma_bus *bus);
/* sprom.c */
int bcma_sprom_get(struct bcma_bus *bus);
@@ -111,6 +107,14 @@ extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc);
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
+#else
+static inline bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
+{
+ return false;
+}
+static inline void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
+{
+}
#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
#ifdef CONFIG_BCMA_DRIVER_GPIO
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index 19f679667ca4..b7c8a8d4e6d1 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -79,7 +79,9 @@ static int bcma_chipco_watchdog_ticks_per_ms(struct bcma_drv_cc *cc)
if (cc->capabilities & BCMA_CC_CAP_PMU) {
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
- /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP clock */
+ /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP
+ * clock
+ */
return bcma_chipco_get_alp_clock(cc) / 4000;
else
/* based on 32KHz ILP clock */
@@ -97,7 +99,8 @@ int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc)
wdt.driver_data = cc;
wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt;
wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt;
- wdt.max_timer_ms = bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
+ wdt.max_timer_ms =
+ bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
pdev = platform_device_register_data(NULL, "bcm47xx-wdt",
cc->core->bus->num, &wdt,
@@ -175,7 +178,6 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
{
u32 maxt;
- enum bcma_clkmode clkmode;
maxt = bcma_chipco_watchdog_get_max_timer(cc);
if (cc->capabilities & BCMA_CC_CAP_PMU) {
@@ -185,8 +187,13 @@ u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
ticks = maxt;
bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
} else {
- clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC;
- bcma_core_set_clockmode(cc->core, clkmode);
+ struct bcma_bus *bus = cc->core->bus;
+
+ if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 &&
+ bus->chipinfo.id != BCMA_CHIP_ID_BCM53018)
+ bcma_core_set_clockmode(cc->core,
+ ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC);
+
if (ticks > maxt)
ticks = maxt;
/* instant NMI */
@@ -335,7 +342,8 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
| BCMA_CC_CORECTL_UARTCLKEN);
}
} else {
- bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ccrev);
+ bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n",
+ ccrev);
return;
}
diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c
index 50329d1057ed..786666488a2d 100644
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -145,6 +145,47 @@ static u16 bcma_pcie_mdio_writeread(struct bcma_drv_pci *pc, u16 device,
}
/**************************************************
+ * Early init.
+ **************************************************/
+
+static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc)
+{
+ struct bcma_device *core = pc->core;
+ u16 val16, core_index;
+ uint regoff;
+
+ regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET);
+ core_index = (u16)core->core_index;
+
+ val16 = pcicore_read16(pc, regoff);
+ if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT)
+ != core_index) {
+ val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) |
+ (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK);
+ pcicore_write16(pc, regoff, val16);
+ }
+}
+
+/*
+ * Apply some early fixes required before accessing SPROM.
+ * See also si_pci_fixcfg.
+ */
+void bcma_core_pci_early_init(struct bcma_drv_pci *pc)
+{
+ if (pc->early_setup_done)
+ return;
+
+ pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
+ if (pc->hostmode)
+ goto out;
+
+ bcma_core_pci_fixcfg(pc);
+
+out:
+ pc->early_setup_done = true;
+}
+
+/**************************************************
* Workarounds.
**************************************************/
@@ -175,24 +216,6 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN);
}
-static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc)
-{
- struct bcma_device *core = pc->core;
- u16 val16, core_index;
- uint regoff;
-
- regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET);
- core_index = (u16)core->core_index;
-
- val16 = pcicore_read16(pc, regoff);
- if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT)
- != core_index) {
- val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) |
- (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK);
- pcicore_write16(pc, regoff, val16);
- }
-}
-
/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
@@ -216,7 +239,6 @@ static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
{
- bcma_core_pci_fixcfg(pc);
bcma_pcicore_serdes_workaround(pc);
bcma_core_pci_config_fixup(pc);
}
@@ -226,13 +248,11 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc)
if (pc->setup_done)
return;
-#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
- pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
+ bcma_core_pci_early_init(pc);
+
if (pc->hostmode)
bcma_core_pci_hostmode_init(pc);
-#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
-
- if (!pc->hostmode)
+ else
bcma_core_pci_clientmode_init(pc);
}
diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c
index cd9161a8b3a1..53c6a8a58859 100644
--- a/drivers/bcma/host_pci.c
+++ b/drivers/bcma/host_pci.c
@@ -13,10 +13,12 @@
static void bcma_host_pci_switch_core(struct bcma_device *core)
{
+ int win2 = core->bus->host_is_pcie2 ?
+ BCMA_PCIE2_BAR0_WIN2 : BCMA_PCI_BAR0_WIN2;
+
pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN,
core->addr);
- pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2,
- core->wrap);
+ pci_write_config_dword(core->bus->host_pci, win2, core->wrap);
core->bus->mapped_core = core;
bcma_debug(core->bus, "Switched to core: 0x%X\n", core->id.id);
}
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c
index 335cbcfd945b..2dce34789329 100644
--- a/drivers/bcma/host_soc.c
+++ b/drivers/bcma/host_soc.c
@@ -193,7 +193,7 @@ int __init bcma_host_soc_init(struct bcma_soc *soc)
int err;
/* Scan bus and initialize it */
- err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
+ err = bcma_bus_early_register(bus);
if (err)
iounmap(bus->mmio);
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 534e1337766d..38bde6eab8a4 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -268,6 +268,18 @@ void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core)
}
}
+void bcma_init_bus(struct bcma_bus *bus)
+{
+ mutex_lock(&bcma_buses_mutex);
+ bus->num = bcma_bus_next_num++;
+ mutex_unlock(&bcma_buses_mutex);
+
+ INIT_LIST_HEAD(&bus->cores);
+ bus->nr_cores = 0;
+
+ bcma_detect_chip(bus);
+}
+
static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
{
int err;
@@ -356,12 +368,19 @@ static void bcma_unregister_cores(struct bcma_bus *bus)
struct bcma_device *core, *tmp;
list_for_each_entry_safe(core, tmp, &bus->cores, list) {
+ if (!core->dev_registered)
+ continue;
list_del(&core->list);
- if (core->dev_registered)
- device_unregister(&core->dev);
+ device_unregister(&core->dev);
}
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
platform_device_unregister(bus->drv_cc.watchdog);
+
+ /* Now noone uses internally-handled cores, we can free them */
+ list_for_each_entry_safe(core, tmp, &bus->cores, list) {
+ list_del(&core->list);
+ kfree(core);
+ }
}
int bcma_bus_register(struct bcma_bus *bus)
@@ -369,10 +388,6 @@ int bcma_bus_register(struct bcma_bus *bus)
int err;
struct bcma_device *core;
- mutex_lock(&bcma_buses_mutex);
- bus->num = bcma_bus_next_num++;
- mutex_unlock(&bcma_buses_mutex);
-
/* Scan for devices (cores) */
err = bcma_bus_scan(bus);
if (err) {
@@ -387,6 +402,13 @@ int bcma_bus_register(struct bcma_bus *bus)
bcma_core_chipcommon_early_init(&bus->drv_cc);
}
+ /* Early init PCIE core */
+ core = bcma_find_core(bus, BCMA_CORE_PCIE);
+ if (core) {
+ bus->drv_pci[0].core = core;
+ bcma_core_pci_early_init(&bus->drv_pci[0]);
+ }
+
/* Cores providing flash access go before SPROM init */
list_for_each_entry(core, &bus->cores, list) {
if (bcma_is_core_needed_early(core->id.id))
@@ -459,7 +481,6 @@ int bcma_bus_register(struct bcma_bus *bus)
void bcma_bus_unregister(struct bcma_bus *bus)
{
- struct bcma_device *cores[3];
int err;
err = bcma_gpio_unregister(&bus->drv_cc);
@@ -470,46 +491,23 @@ void bcma_bus_unregister(struct bcma_bus *bus)
bcma_core_chipcommon_b_free(&bus->drv_cc_b);
- cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
- cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
- cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
-
bcma_unregister_cores(bus);
-
- kfree(cores[2]);
- kfree(cores[1]);
- kfree(cores[0]);
}
-int __init bcma_bus_early_register(struct bcma_bus *bus,
- struct bcma_device *core_cc,
- struct bcma_device *core_mips)
+/*
+ * This is a special version of bus registration function designed for SoCs.
+ * It scans bus and performs basic initialization of main cores only.
+ * Please note it requires memory allocation, however it won't try to sleep.
+ */
+int __init bcma_bus_early_register(struct bcma_bus *bus)
{
int err;
struct bcma_device *core;
- struct bcma_device_id match;
- match.manuf = BCMA_MANUF_BCM;
- match.id = bcma_cc_core_id(bus);
- match.class = BCMA_CL_SIM;
- match.rev = BCMA_ANY_REV;
-
- /* Scan for chip common core */
- err = bcma_bus_scan_early(bus, &match, core_cc);
- if (err) {
- bcma_err(bus, "Failed to scan for common core: %d\n", err);
- return -1;
- }
-
- match.manuf = BCMA_MANUF_MIPS;
- match.id = BCMA_CORE_MIPS_74K;
- match.class = BCMA_CL_SIM;
- match.rev = BCMA_ANY_REV;
-
- /* Scan for mips core */
- err = bcma_bus_scan_early(bus, &match, core_mips);
+ /* Scan for devices (cores) */
+ err = bcma_bus_scan(bus);
if (err) {
- bcma_err(bus, "Failed to scan for mips core: %d\n", err);
+ bcma_err(bus, "Failed to scan bus: %d\n", err);
return -1;
}
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 917520776879..df806b9c5490 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -435,15 +435,12 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
return 0;
}
-void bcma_init_bus(struct bcma_bus *bus)
+void bcma_detect_chip(struct bcma_bus *bus)
{
s32 tmp;
struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
char chip_id[8];
- INIT_LIST_HEAD(&bus->cores);
- bus->nr_cores = 0;
-
bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
@@ -464,6 +461,10 @@ int bcma_bus_scan(struct bcma_bus *bus)
int err, core_num = 0;
+ /* Skip if bus was already scanned (e.g. during early register) */
+ if (bus->nr_cores)
+ return 0;
+
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
@@ -522,61 +523,3 @@ out:
return err;
}
-
-int __init bcma_bus_scan_early(struct bcma_bus *bus,
- struct bcma_device_id *match,
- struct bcma_device *core)
-{
- u32 erombase;
- u32 __iomem *eromptr, *eromend;
-
- int err = -ENODEV;
- int core_num = 0;
-
- erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
- if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
- eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
- if (!eromptr)
- return -ENOMEM;
- } else {
- eromptr = bus->mmio;
- }
-
- eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
-
- bcma_scan_switch_core(bus, erombase);
-
- while (eromptr < eromend) {
- memset(core, 0, sizeof(*core));
- INIT_LIST_HEAD(&core->list);
- core->bus = bus;
-
- err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
- if (err == -ENODEV) {
- core_num++;
- continue;
- } else if (err == -ENXIO)
- continue;
- else if (err == -ESPIPE)
- break;
- else if (err < 0)
- goto out;
-
- core->core_index = core_num++;
- bus->nr_cores++;
- bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
- core->core_index, bcma_device_name(&core->id),
- core->id.manuf, core->id.id, core->id.rev,
- core->id.class);
-
- list_add_tail(&core->list, &bus->cores);
- err = 0;
- break;
- }
-
-out:
- if (bus->hosttype == BCMA_HOSTTYPE_SOC)
- iounmap(eromptr);
-
- return err;
-}
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
index efb037f9c98a..206edd3ba668 100644
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -579,7 +579,8 @@ int bcma_sprom_get(struct bcma_bus *bus)
u16 offset = BCMA_CC_SPROM;
u16 *sprom;
size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
- SSB_SPROMSIZE_WORDS_R10, };
+ SSB_SPROMSIZE_WORDS_R10,
+ SSB_SPROMSIZE_WORDS_R11, };
int i, err = 0;
if (!bus->drv_cc.core)
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 17fcaabb2687..f07a61899545 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -1837,6 +1837,7 @@ static int adm8211_probe(struct pci_dev *pdev,
if (!priv->map) {
printk(KERN_ERR "%s (adm8211): Cannot map device memory\n",
pci_name(pdev));
+ err = -ENOMEM;
goto err_free_dev;
}
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index ccba4fea7269..1eebe2ea3dfb 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -64,6 +64,7 @@ enum ath_op_flags {
ATH_OP_HW_RESET,
ATH_OP_SCANNING,
ATH_OP_MULTI_CHANNEL,
+ ATH_OP_WOW_ENABLED,
};
enum ath_bus_type {
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index d0d882d632d1..1cebd3219068 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3078,6 +3078,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
int bit;
u32 vdev_param;
+ vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
+
mutex_lock(&ar->conf_mutex);
memset(arvif, 0, sizeof(*arvif));
@@ -5336,7 +5338,6 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_SUPPORTS_UAPSD |
IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_HAS_RATE_CONTROL |
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index fd213d9e4214..aeea1c793943 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1670,11 +1670,11 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
rx_clear_count -= ar->survey_last_rx_clear_count;
survey = &ar->survey[idx];
- survey->channel_time = WMI_CHAN_INFO_MSEC(cycle_count);
- survey->channel_time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count);
+ survey->time = WMI_CHAN_INFO_MSEC(cycle_count);
+ survey->time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count);
survey->noise = noise_floor;
- survey->filled = SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_RX |
+ survey->filled = SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_RX |
SURVEY_INFO_NOISE_DBM;
}
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 19eab2a69ad5..3b4a6463d87a 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -672,10 +672,10 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
spin_lock_bh(&common->cc_lock);
ath_hw_cycle_counters_update(common);
if (cc->cycles > 0) {
- ah->survey.channel_time += cc->cycles / div;
- ah->survey.channel_time_busy += cc->rx_busy / div;
- ah->survey.channel_time_rx += cc->rx_frame / div;
- ah->survey.channel_time_tx += cc->tx_frame / div;
+ ah->survey.time += cc->cycles / div;
+ ah->survey.time_busy += cc->rx_busy / div;
+ ah->survey.time_rx += cc->rx_frame / div;
+ ah->survey.time_tx += cc->tx_frame / div;
}
memset(cc, 0, sizeof(*cc));
spin_unlock_bh(&common->cc_lock);
@@ -686,10 +686,10 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
survey->noise = ah->ah_noise_floor;
survey->filled = SURVEY_INFO_NOISE_DBM |
SURVEY_INFO_IN_USE |
- SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_BUSY |
- SURVEY_INFO_CHANNEL_TIME_RX |
- SURVEY_INFO_CHANNEL_TIME_TX;
+ SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY |
+ SURVEY_INFO_TIME_RX |
+ SURVEY_INFO_TIME_TX;
return 0;
}
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index c60d36aa13e2..bf29da5e90da 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -912,6 +912,7 @@ ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
| (ah->ah_version == AR5K_AR5210 ?
AR5K_STA_ID1_PWR_SV : 0);
+ /* fall through */
case NL80211_IFTYPE_MONITOR:
pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
| (ah->ah_version == AR5K_AR5210 ?
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index a3399c4f13a9..b9b651ea9851 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -478,7 +478,7 @@ ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
regval = ioread32(reg);
iowrite32(regval | val, reg);
regval = ioread32(reg);
- usleep_range(100, 150);
+ udelay(100); /* NB: should be atomic */
/* Bring BB/MAC out of reset */
iowrite32(regval & ~val, reg);
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 7a5337877a0c..85da63a67faf 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1799,20 +1799,20 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
if (vif->target_stats.rx_byte) {
sinfo->rx_bytes = vif->target_stats.rx_byte;
- sinfo->filled |= STATION_INFO_RX_BYTES64;
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
sinfo->rx_packets = vif->target_stats.rx_pkt;
- sinfo->filled |= STATION_INFO_RX_PACKETS;
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
}
if (vif->target_stats.tx_byte) {
sinfo->tx_bytes = vif->target_stats.tx_byte;
- sinfo->filled |= STATION_INFO_TX_BYTES64;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64);
sinfo->tx_packets = vif->target_stats.tx_pkt;
- sinfo->filled |= STATION_INFO_TX_PACKETS;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
}
sinfo->signal = vif->target_stats.cs_rssi;
- sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
rate = vif->target_stats.tx_ucast_rate;
@@ -1827,6 +1827,7 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
}
sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
+ sinfo->txrate.bw = RATE_INFO_BW_20;
} else if (is_rate_ht40(rate, &mcs, &sgi)) {
if (sgi) {
sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
@@ -1835,7 +1836,7 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
sinfo->txrate.mcs = mcs;
}
- sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ sinfo->txrate.bw = RATE_INFO_BW_40;
sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
} else {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
@@ -1844,12 +1845,12 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
- sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
if (test_bit(CONNECTED, &vif->flags) &&
test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
vif->nw_type == INFRA_NETWORK) {
- sinfo->filled |= STATION_INFO_BSS_PARAM;
+ sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
sinfo->bss_param.flags = 0;
sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 933aef025698..b42ba46b5030 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -488,7 +488,6 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr,
sinfo.assoc_req_ies = ies;
sinfo.assoc_req_ies_len = ies_len;
- sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
cfg80211_new_sta(vif->ndev, mac_addr, &sinfo, GFP_KERNEL);
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index e000c4c27881..bd4a1a655f42 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -43,6 +43,10 @@ static const struct platform_device_id ath9k_platform_id_table[] = {
.name = "qca953x_wmac",
.driver_data = AR9300_DEVID_AR953X,
},
+ {
+ .name = "qca956x_wmac",
+ .driver_data = AR9300_DEVID_QCA956X,
+ },
{},
};
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index ba502a2d199b..ca01d17d130f 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -259,7 +259,8 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
entry_cck->fir_step_level);
/* Skip MRC CCK for pre AR9003 families */
- if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah))
+ if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah) ||
+ AR_SREV_9565(ah) || AR_SREV_9561(ah))
return;
if (aniState->mrcCCK != entry_cck->mrc_cck_on)
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index 5829074208fa..f273427fdd29 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -22,6 +22,21 @@
/* All code below is for AR5008, AR9001, AR9002 */
+#define AR5008_OFDM_RATES 8
+#define AR5008_HT_SS_RATES 8
+#define AR5008_HT_DS_RATES 8
+
+#define AR5008_HT20_SHIFT 16
+#define AR5008_HT40_SHIFT 24
+
+#define AR5008_11NA_OFDM_SHIFT 0
+#define AR5008_11NA_HT_SS_SHIFT 8
+#define AR5008_11NA_HT_DS_SHIFT 16
+
+#define AR5008_11NG_OFDM_SHIFT 4
+#define AR5008_11NG_HT_SS_SHIFT 12
+#define AR5008_11NG_HT_DS_SHIFT 20
+
static const int firstep_table[] =
/* level: 0 1 2 3 4 5 6 7 8 */
{ -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */
@@ -1235,6 +1250,71 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah)
conf->radar_inband = 8;
}
+static void ar5008_hw_init_txpower_cck(struct ath_hw *ah, int16_t *rate_array)
+{
+#define CCK_DELTA(x) ((OLC_FOR_AR9280_20_LATER) ? max((x) - 2, 0) : (x))
+ ah->tx_power[0] = CCK_DELTA(rate_array[rate1l]);
+ ah->tx_power[1] = CCK_DELTA(min(rate_array[rate2l],
+ rate_array[rate2s]));
+ ah->tx_power[2] = CCK_DELTA(min(rate_array[rate5_5l],
+ rate_array[rate5_5s]));
+ ah->tx_power[3] = CCK_DELTA(min(rate_array[rate11l],
+ rate_array[rate11s]));
+#undef CCK_DELTA
+}
+
+static void ar5008_hw_init_txpower_ofdm(struct ath_hw *ah, int16_t *rate_array,
+ int offset)
+{
+ int i, idx = 0;
+
+ for (i = offset; i < offset + AR5008_OFDM_RATES; i++) {
+ ah->tx_power[i] = rate_array[idx];
+ idx++;
+ }
+}
+
+static void ar5008_hw_init_txpower_ht(struct ath_hw *ah, int16_t *rate_array,
+ int ss_offset, int ds_offset,
+ bool is_40, int ht40_delta)
+{
+ int i, mcs_idx = (is_40) ? AR5008_HT40_SHIFT : AR5008_HT20_SHIFT;
+
+ for (i = ss_offset; i < ss_offset + AR5008_HT_SS_RATES; i++) {
+ ah->tx_power[i] = rate_array[mcs_idx] + ht40_delta;
+ mcs_idx++;
+ }
+ memcpy(&ah->tx_power[ds_offset], &ah->tx_power[ss_offset],
+ AR5008_HT_SS_RATES);
+}
+
+void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array,
+ struct ath9k_channel *chan, int ht40_delta)
+{
+ if (IS_CHAN_5GHZ(chan)) {
+ ar5008_hw_init_txpower_ofdm(ah, rate_array,
+ AR5008_11NA_OFDM_SHIFT);
+ if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) {
+ ar5008_hw_init_txpower_ht(ah, rate_array,
+ AR5008_11NA_HT_SS_SHIFT,
+ AR5008_11NA_HT_DS_SHIFT,
+ IS_CHAN_HT40(chan),
+ ht40_delta);
+ }
+ } else {
+ ar5008_hw_init_txpower_cck(ah, rate_array);
+ ar5008_hw_init_txpower_ofdm(ah, rate_array,
+ AR5008_11NG_OFDM_SHIFT);
+ if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) {
+ ar5008_hw_init_txpower_ht(ah, rate_array,
+ AR5008_11NG_HT_SS_SHIFT,
+ AR5008_11NG_HT_DS_SHIFT,
+ IS_CHAN_HT40(chan),
+ ht40_delta);
+ }
+ }
+}
+
int ar5008_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 06ab71db6e80..174442beb952 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -1203,24 +1203,41 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)
static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
{
int offset[8] = {0}, total = 0, test;
- int agc_out, i;
+ int agc_out, i, peak_detect_threshold;
+ if (AR_SREV_9550(ah) || AR_SREV_9531(ah))
+ peak_detect_threshold = 8;
+ else
+ peak_detect_threshold = 0;
+
+ /*
+ * Turn off LNA/SW.
+ */
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0x1);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC, 0x0);
- if (is_2g)
- REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
- AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0);
- else
- REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
- AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0);
+ if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9330_11(ah)) {
+ if (is_2g)
+ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
+ AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0);
+ else
+ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
+ AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0);
+ }
+
+ /*
+ * Turn off RXON.
+ */
REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
AR_PHY_65NM_RXTX2_RXON_OVR, 0x1);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
AR_PHY_65NM_RXTX2_RXON, 0x0);
+ /*
+ * Turn on AGC for cal.
+ */
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
@@ -1228,16 +1245,19 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1);
- if (AR_SREV_9330_11(ah)) {
+ if (AR_SREV_9330_11(ah))
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0);
- } else {
+
+ if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
if (is_2g)
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
- AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0);
+ AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR,
+ peak_detect_threshold);
else
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
- AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, 0x0);
+ AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR,
+ peak_detect_threshold);
}
for (i = 6; i > 0; i--) {
@@ -1266,10 +1286,19 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, total);
+ /*
+ * Turn on LNA.
+ */
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0);
+ /*
+ * Turn off RXON.
+ */
REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
AR_PHY_65NM_RXTX2_RXON_OVR, 0);
+ /*
+ * Turn off peak detect calibration.
+ */
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0);
}
@@ -1611,8 +1640,14 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
skip_tx_iqcal:
if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
- if (AR_SREV_9330_11(ah))
- ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan));
+ if (AR_SREV_9330_11(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) {
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (!(ah->rxchainmask & (1 << i)))
+ continue;
+ ar9003_hw_manual_peak_cal(ah, i,
+ IS_CHAN_2GHZ(chan));
+ }
+ }
/*
* For non-AR9550 chips, we just trigger AGC calibration
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 08225a0067c2..8b4561e8ce1a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -3536,7 +3536,7 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
int bias = ar9003_modal_header(ah, is2ghz)->xpaBiasLvl;
if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah) ||
- AR_SREV_9531(ah))
+ AR_SREV_9531(ah) || AR_SREV_9561(ah))
REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias);
else if (AR_SREV_9462(ah) || AR_SREV_9550(ah) || AR_SREV_9565(ah))
REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias);
@@ -3599,7 +3599,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
AR_SWITCH_TABLE_COM_AR9462_ALL, value);
- } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+ } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) {
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
AR_SWITCH_TABLE_COM_AR9550_ALL, value);
} else
@@ -3929,9 +3929,13 @@ void ar9003_hw_internal_regulator_apply(struct ath_hw *ah)
REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set);
if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set))
return;
- } else if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
+ } else if (AR_SREV_9462(ah) || AR_SREV_9565(ah) ||
+ AR_SREV_9561(ah)) {
reg_val = le32_to_cpu(pBase->swreg);
REG_WRITE(ah, AR_PHY_PMU1, reg_val);
+
+ if (AR_SREV_9561(ah))
+ REG_WRITE(ah, AR_PHY_PMU2, 0x10200000);
} else {
/* Internal regulator is ON. Write swreg register. */
reg_val = le32_to_cpu(pBase->swreg);
@@ -4034,7 +4038,8 @@ static void ar9003_hw_xpa_timing_control_apply(struct ath_hw *ah, bool is2ghz)
if (!AR_SREV_9300(ah) &&
!AR_SREV_9340(ah) &&
!AR_SREV_9580(ah) &&
- !AR_SREV_9531(ah))
+ !AR_SREV_9531(ah) &&
+ !AR_SREV_9561(ah))
return;
xpa_ctl = ar9003_modal_header(ah, is2ghz)->txFrameToXpaOn;
@@ -4812,7 +4817,7 @@ static void ar9003_hw_power_control_override(struct ath_hw *ah,
}
tempslope:
- if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+ if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) {
u8 txmask = (eep->baseEepHeader.txrxMask & 0xf0) >> 4;
/*
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index 06ad2172030e..4335ccbe7d7e 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -29,6 +29,7 @@
#include "ar9565_1p0_initvals.h"
#include "ar9565_1p1_initvals.h"
#include "ar953x_initvals.h"
+#include "ar956x_initvals.h"
/* General hardware code for the AR9003 hadware family */
@@ -358,6 +359,40 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniModesFastClock,
qca953x_1p0_modes_fast_clock);
+ } else if (AR_SREV_9561(ah)) {
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+ qca956x_1p0_mac_core);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+ qca956x_1p0_mac_postamble);
+
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+ qca956x_1p0_baseband_core);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+ qca956x_1p0_baseband_postamble);
+
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+ qca956x_1p0_radio_core);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+ qca956x_1p0_radio_postamble);
+
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+ qca956x_1p0_soc_preamble);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+ qca956x_1p0_soc_postamble);
+
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ qca956x_1p0_common_wo_xlna_rx_gain_table);
+ INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
+ qca956x_1p0_common_wo_xlna_rx_gain_bounds);
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ qca956x_1p0_modes_no_xpa_tx_gain_table);
+
+ INIT_INI_ARRAY(&ah->ini_dfs,
+ qca956x_1p0_baseband_postamble_dfs_channel);
+ INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+ qca956x_1p0_baseband_core_txfir_coeff_japan_2484);
+ INIT_INI_ARRAY(&ah->iniModesFastClock,
+ qca956x_1p0_modes_fast_clock);
} else if (AR_SREV_9580(ah)) {
/* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
@@ -544,6 +579,9 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah)
else if (AR_SREV_9531_20(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
qca953x_2p0_modes_xpa_tx_gain_table);
+ else if (AR_SREV_9561(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ qca956x_1p0_modes_xpa_tx_gain_table);
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_lowest_ob_db_tx_gain_table);
@@ -594,7 +632,10 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah)
else
INIT_INI_ARRAY(&ah->iniModesTxGain,
qca953x_1p0_modes_no_xpa_tx_gain_table);
- } else if (AR_SREV_9462_21(ah))
+ } else if (AR_SREV_9561(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ qca956x_1p0_modes_no_xpa_tx_gain_table);
+ else if (AR_SREV_9462_21(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9462_2p1_modes_high_ob_db_tx_gain);
else if (AR_SREV_9462_20(ah))
@@ -628,6 +669,9 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah)
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_low_ob_db_tx_gain_table);
+ else if (AR_SREV_9561(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ qca956x_1p0_modes_no_xpa_low_ob_db_tx_gain_table);
else if (AR_SREV_9565_11(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9565_1p1_modes_low_ob_db_tx_gain_table);
@@ -699,6 +743,9 @@ static void ar9003_tx_gain_table_mode5(struct ath_hw *ah)
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_type5_tx_gain_table);
+ else if (AR_SREV_9561(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ qca956x_1p0_modes_no_xpa_green_tx_gain_table);
else if (AR_SREV_9300_22(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9300Modes_type5_tx_gain_table_2p2);
@@ -770,6 +817,13 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
qca953x_1p0_common_rx_gain_table);
INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
qca953x_1p0_common_rx_gain_bounds);
+ } else if (AR_SREV_9561(ah)) {
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ qca956x_1p0_common_rx_gain_table);
+ INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
+ qca956x_1p0_common_rx_gain_bounds);
+ INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna,
+ qca956x_1p0_xlna_only);
} else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9580_1p0_rx_gain_table);
@@ -825,6 +879,11 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah)
qca953x_2p0_common_wo_xlna_rx_gain_table);
INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
qca953x_2p0_common_wo_xlna_rx_gain_bounds);
+ } else if (AR_SREV_9561(ah)) {
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ qca956x_1p0_common_wo_xlna_rx_gain_table);
+ INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
+ qca956x_1p0_common_wo_xlna_rx_gain_bounds);
} else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9580_1p0_wo_xlna_rx_gain_table);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index ae6cde273414..1ad66b76749b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -183,7 +183,8 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
} else {
channelSel = CHANSEL_2G(freq) >> 1;
}
- } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+ } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah)) {
if (ah->is_clk_25mhz)
div = 75;
else
@@ -198,7 +199,8 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
/* Set to 2G mode */
bMode = 1;
} else {
- if ((AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) &&
+ if ((AR_SREV_9340(ah) || AR_SREV_9550(ah) ||
+ AR_SREV_9531(ah) || AR_SREV_9561(ah)) &&
ah->is_clk_25mhz) {
channelSel = freq / 75;
chan_frac = ((freq % 75) * 0x20000) / 75;
@@ -265,7 +267,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
*/
if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) ||
- AR_SREV_9550(ah)) {
+ AR_SREV_9550(ah) || AR_SREV_9561(ah)) {
if (spur_fbin_ptr[0] == 0) /* No spur */
return;
max_spur_cnts = 5;
@@ -292,7 +294,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
negative = 0;
if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) ||
- AR_SREV_9550(ah))
+ AR_SREV_9550(ah) || AR_SREV_9561(ah))
cur_bb_spur = ath9k_hw_fbin2freq(spur_fbin_ptr[i],
IS_CHAN_2GHZ(chan));
else
@@ -641,8 +643,10 @@ static void ar9003_hw_set_channel_regs(struct ath_hw *ah,
(REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO);
/* Enable 11n HT, 20 MHz */
- phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 |
- AR_PHY_GC_SHORT_GI_40 | enableDacFifo;
+ phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SHORT_GI_40 | enableDacFifo;
+
+ if (!AR_SREV_9561(ah))
+ phymode |= AR_PHY_GC_SINGLE_HT_LTF1;
/* Configure baseband for dynamic 20/40 operation */
if (IS_CHAN_HT40(chan)) {
@@ -745,7 +749,8 @@ static void ar9003_hw_override_ini(struct ath_hw *ah)
else
ah->enabled_cals &= ~TX_CL_CAL;
- if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) {
+ if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah) ||
+ AR_SREV_9561(ah)) {
if (ah->is_clk_25mhz) {
REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1);
REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
@@ -812,6 +817,19 @@ static int ar9550_hw_get_modes_txgain_index(struct ath_hw *ah,
return ret;
}
+static int ar9561_hw_get_modes_txgain_index(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ if (IS_CHAN_2GHZ(chan)) {
+ if (IS_CHAN_HT40(chan))
+ return 1;
+ else
+ return 2;
+ }
+
+ return 0;
+}
+
static void ar9003_doubler_fix(struct ath_hw *ah)
{
if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9550(ah)) {
@@ -911,21 +929,29 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
REG_WRITE_ARRAY(&ah->ini_modes_rxgain_5g_xlna,
modesIndex, regWrites);
}
+
+ if (AR_SREV_9561(ah) && (ar9003_hw_get_rx_gain_idx(ah) == 0))
+ REG_WRITE_ARRAY(&ah->ini_modes_rxgain_5g_xlna,
+ modesIndex, regWrites);
}
- if (AR_SREV_9550(ah))
+ if (AR_SREV_9550(ah) || AR_SREV_9561(ah))
REG_WRITE_ARRAY(&ah->ini_modes_rx_gain_bounds, modesIndex,
regWrites);
/*
* TXGAIN initvals.
*/
- if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+ if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) {
int modes_txgain_index = 1;
if (AR_SREV_9550(ah))
modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan);
+ if (AR_SREV_9561(ah))
+ modes_txgain_index =
+ ar9561_hw_get_modes_txgain_index(ah, chan);
+
if (modes_txgain_index < 0)
return -EINVAL;
@@ -1989,7 +2015,8 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->rf_set_freq = ar9003_hw_set_channel;
priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate;
- if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah))
+ if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah))
priv_ops->compute_pll_control = ar9003_hw_compute_pll_control_soc;
else
priv_ops->compute_pll_control = ar9003_hw_compute_pll_control;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index fd090b1f2d0f..c311b2bfdb00 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -454,7 +454,7 @@
#define AR_PHY_GEN_CTRL (AR_SM_BASE + 0x4)
#define AR_PHY_MODE (AR_SM_BASE + 0x8)
#define AR_PHY_ACTIVE (AR_SM_BASE + 0xc)
-#define AR_PHY_SPUR_MASK_A (AR_SM_BASE + 0x20)
+#define AR_PHY_SPUR_MASK_A (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x18 : 0x20))
#define AR_PHY_SPUR_MASK_B (AR_SM_BASE + 0x24)
#define AR_PHY_SPECTRAL_SCAN (AR_SM_BASE + 0x28)
#define AR_PHY_RADAR_BW_FILTER (AR_SM_BASE + 0x2c)
@@ -506,7 +506,7 @@
#define AR_PHY_TEST_CHAIN_SEL 0xC0000000
#define AR_PHY_TEST_CHAIN_SEL_S 30
-#define AR_PHY_TEST_CTL_STATUS (AR_SM_BASE + 0x164)
+#define AR_PHY_TEST_CTL_STATUS (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x160 : 0x164))
#define AR_PHY_TEST_CTL_TSTDAC_EN 0x1
#define AR_PHY_TEST_CTL_TSTDAC_EN_S 0
#define AR_PHY_TEST_CTL_TX_OBS_SEL 0x1C
@@ -525,7 +525,7 @@
#define AR_PHY_CHAN_STATUS (AR_SM_BASE + 0x16c)
-#define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + 0x170)
+#define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x16c : 0x170))
#define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ 0x00000008
#define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ_S 3
@@ -536,7 +536,7 @@
#define AR_PHY_SCRAMBLER_SEED (AR_SM_BASE + 0x190)
#define AR_PHY_CCK_TX_CTRL (AR_SM_BASE + 0x194)
-#define AR_PHY_HEAVYCLIP_CTL (AR_SM_BASE + 0x1a4)
+#define AR_PHY_HEAVYCLIP_CTL (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x198 : 0x1a4))
#define AR_PHY_HEAVYCLIP_20 (AR_SM_BASE + 0x1a8)
#define AR_PHY_HEAVYCLIP_40 (AR_SM_BASE + 0x1ac)
#define AR_PHY_ILLEGAL_TXRATE (AR_SM_BASE + 0x1b0)
@@ -726,21 +726,24 @@
#define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \
(AR_SREV_9462(ah) ? 0x16290 : 0x16284))
-#define AR_CH0_TOP2_XPABIASLVL 0xf000
+#define AR_CH0_TOP2_XPABIASLVL (AR_SREV_9561(ah) ? 0x1e00 : 0xf000)
#define AR_CH0_TOP2_XPABIASLVL_S 12
#define AR_CH0_XTAL (AR_SREV_9300(ah) ? 0x16294 : \
- ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16298 : 0x16290))
+ ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16298 : \
+ (AR_SREV_9561(ah) ? 0x162c0 : 0x16290)))
#define AR_CH0_XTAL_CAPINDAC 0x7f000000
#define AR_CH0_XTAL_CAPINDAC_S 24
#define AR_CH0_XTAL_CAPOUTDAC 0x00fe0000
#define AR_CH0_XTAL_CAPOUTDAC_S 17
-#define AR_PHY_PMU1 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16340 : 0x16c40)
+#define AR_PHY_PMU1 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16340 : \
+ (AR_SREV_9561(ah) ? 0x16cc0 : 0x16c40))
#define AR_PHY_PMU1_PWD 0x1
#define AR_PHY_PMU1_PWD_S 0
-#define AR_PHY_PMU2 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16344 : 0x16c44)
+#define AR_PHY_PMU2 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16344 : \
+ (AR_SREV_9561(ah) ? 0x16cc4 : 0x16c44))
#define AR_PHY_PMU2_PGM 0x00200000
#define AR_PHY_PMU2_PGM_S 21
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c
index 81c88dd606dc..86bfc9604dca 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c
@@ -17,23 +17,9 @@
#include <linux/export.h>
#include "ath9k.h"
#include "reg.h"
+#include "reg_wow.h"
#include "hw-ops.h"
-const char *ath9k_hw_wow_event_to_string(u32 wow_event)
-{
- if (wow_event & AH_WOW_MAGIC_PATTERN_EN)
- return "Magic pattern";
- if (wow_event & AH_WOW_USER_PATTERN_EN)
- return "User pattern";
- if (wow_event & AH_WOW_LINK_CHANGE)
- return "Link change";
- if (wow_event & AH_WOW_BEACON_MISS)
- return "Beacon miss";
-
- return "unknown reason";
-}
-EXPORT_SYMBOL(ath9k_hw_wow_event_to_string);
-
static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
@@ -49,6 +35,15 @@ static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
return;
}
+ if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
+ if (!REG_READ(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL))
+ REG_CLR_BIT(ah, AR_DIRECT_CONNECT, AR_DC_TSF2_ENABLE);
+ } else if (AR_SREV_9485(ah)){
+ if (!(REG_READ(ah, AR_NDP2_TIMER_MODE) &
+ AR_GEN_TIMERS2_MODE_ENABLE_MASK))
+ REG_CLR_BIT(ah, AR_DIRECT_CONNECT, AR_DC_TSF2_ENABLE);
+ }
+
REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);
}
@@ -67,11 +62,15 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
/* set the transmit buffer */
ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16));
ctl[1] = 0;
- ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */
ctl[4] = 0;
ctl[7] = (ah->txchainmask) << 2;
ctl[2] = 0xf << 16; /* tx_tries 0 */
+ if (IS_CHAN_2GHZ(ah->curchan))
+ ctl[3] = 0x1b; /* CCK_1M */
+ else
+ ctl[3] = 0xb; /* OFDM_6M */
+
for (i = 0; i < KAL_NUM_DESC_WORDS; i++)
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
@@ -103,21 +102,22 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
}
-void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
- u8 *user_mask, int pattern_count,
- int pattern_len)
+int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
+ u8 *user_mask, int pattern_count,
+ int pattern_len)
{
int i;
u32 pattern_val, mask_val;
u32 set, clr;
- /* FIXME: should check count by querying the hardware capability */
- if (pattern_count >= MAX_NUM_PATTERN)
- return;
+ if (pattern_count >= ah->wow.max_patterns)
+ return -ENOSPC;
- REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count));
+ if (pattern_count < MAX_NUM_PATTERN_LEGACY)
+ REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count));
+ else
+ REG_SET_BIT(ah, AR_MAC_PCU_WOW4, BIT(pattern_count - 8));
- /* set the registers for pattern */
for (i = 0; i < MAX_PATTERN_SIZE; i += 4) {
memcpy(&pattern_val, user_pattern, 4);
REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i),
@@ -125,49 +125,42 @@ void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
user_pattern += 4;
}
- /* set the registers for mask */
for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) {
memcpy(&mask_val, user_mask, 4);
REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val);
user_mask += 4;
}
- /* set the pattern length to be matched
- *
- * AR_WOW_LENGTH1_REG1
- * bit 31:24 pattern 0 length
- * bit 23:16 pattern 1 length
- * bit 15:8 pattern 2 length
- * bit 7:0 pattern 3 length
- *
- * AR_WOW_LENGTH1_REG2
- * bit 31:24 pattern 4 length
- * bit 23:16 pattern 5 length
- * bit 15:8 pattern 6 length
- * bit 7:0 pattern 7 length
- *
- * the below logic writes out the new
- * pattern length for the corresponding
- * pattern_count, while masking out the
- * other fields
- */
-
- ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT);
+ if (pattern_count < MAX_NUM_PATTERN_LEGACY)
+ ah->wow.wow_event_mask |=
+ BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT);
+ else
+ ah->wow.wow_event_mask2 |=
+ BIT((pattern_count - 8) + AR_WOW_PAT_FOUND_SHIFT);
if (pattern_count < 4) {
- /* Pattern 0-3 uses AR_WOW_LENGTH1 register */
set = (pattern_len & AR_WOW_LENGTH_MAX) <<
AR_WOW_LEN1_SHIFT(pattern_count);
clr = AR_WOW_LENGTH1_MASK(pattern_count);
REG_RMW(ah, AR_WOW_LENGTH1, set, clr);
- } else {
- /* Pattern 4-7 uses AR_WOW_LENGTH2 register */
+ } else if (pattern_count < 8) {
set = (pattern_len & AR_WOW_LENGTH_MAX) <<
AR_WOW_LEN2_SHIFT(pattern_count);
clr = AR_WOW_LENGTH2_MASK(pattern_count);
REG_RMW(ah, AR_WOW_LENGTH2, set, clr);
+ } else if (pattern_count < 12) {
+ set = (pattern_len & AR_WOW_LENGTH_MAX) <<
+ AR_WOW_LEN3_SHIFT(pattern_count);
+ clr = AR_WOW_LENGTH3_MASK(pattern_count);
+ REG_RMW(ah, AR_WOW_LENGTH3, set, clr);
+ } else if (pattern_count < MAX_NUM_PATTERN) {
+ set = (pattern_len & AR_WOW_LENGTH_MAX) <<
+ AR_WOW_LEN4_SHIFT(pattern_count);
+ clr = AR_WOW_LENGTH4_MASK(pattern_count);
+ REG_RMW(ah, AR_WOW_LENGTH4, set, clr);
}
+ return 0;
}
EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern);
@@ -189,7 +182,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
* register. This mask will clean it up.
*/
- val &= ah->wow_event_mask;
+ val &= ah->wow.wow_event_mask;
if (val) {
if (val & AR_WOW_MAGIC_PAT_FOUND)
@@ -233,190 +226,192 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
if (ah->is_pciexpress)
ath9k_hw_configpcipowersave(ah, false);
- ah->wow_event_mask = 0;
+ ah->wow.wow_event_mask = 0;
return wow_status;
}
EXPORT_SYMBOL(ath9k_hw_wow_wakeup);
-void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
+static void ath9k_hw_wow_set_arwr_reg(struct ath_hw *ah)
{
- u32 wow_event_mask;
- u32 set, clr;
+ u32 wa_reg;
- /*
- * wow_event_mask is a mask to the AR_WOW_PATTERN register to
- * indicate which WoW events we have enabled. The WoW events
- * are from the 'pattern_enable' in this function and
- * 'pattern_count' of ath9k_hw_wow_apply_pattern()
- */
- wow_event_mask = ah->wow_event_mask;
+ if (!ah->is_pciexpress)
+ return;
/*
- * Untie Power-on-Reset from the PCI-E-Reset. When we are in
- * WOW sleep, we do want the Reset from the PCI-E to disturb
- * our hw state
+ * We need to untie the internal POR (power-on-reset)
+ * to the external PCI-E reset. We also need to tie
+ * the PCI-E Phy reset to the PCI-E reset.
*/
- if (ah->is_pciexpress) {
- /*
- * we need to untie the internal POR (power-on-reset)
- * to the external PCI-E reset. We also need to tie
- * the PCI-E Phy reset to the PCI-E reset.
- */
- set = AR_WA_RESET_EN | AR_WA_POR_SHORT;
- clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;
- REG_RMW(ah, AR_WA, set, clr);
- }
+ wa_reg = REG_READ(ah, AR_WA);
+ wa_reg &= ~AR_WA_UNTIE_RESET_EN;
+ wa_reg |= AR_WA_RESET_EN;
+ wa_reg |= AR_WA_POR_SHORT;
- /*
- * set the power states appropriately and enable PME
- */
- set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA |
- AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR;
+ REG_WRITE(ah, AR_WA, wa_reg);
+}
+
+void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
+{
+ u32 wow_event_mask;
+ u32 keep_alive, magic_pattern, host_pm_ctrl;
+
+ wow_event_mask = ah->wow.wow_event_mask;
/*
- * set and clear WOW_PME_CLEAR registers for the chip
+ * AR_PMCTRL_HOST_PME_EN - Override PME enable in configuration
+ * space and allow MAC to generate WoW anyway.
+ *
+ * AR_PMCTRL_PWR_PM_CTRL_ENA - ???
+ *
+ * AR_PMCTRL_AUX_PWR_DET - PCI core SYS_AUX_PWR_DET signal,
+ * needs to be set for WoW in PCI mode.
+ *
+ * AR_PMCTRL_WOW_PME_CLR - WoW Clear Signal going to the MAC.
+ *
+ * Set the power states appropriately and enable PME.
+ *
+ * Set and clear WOW_PME_CLEAR for the chip
* to generate next wow signal.
*/
- REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
- clr = AR_PMCTRL_WOW_PME_CLR;
- REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
+ REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_HOST_PME_EN |
+ AR_PMCTRL_PWR_PM_CTRL_ENA |
+ AR_PMCTRL_AUX_PWR_DET |
+ AR_PMCTRL_WOW_PME_CLR);
+ REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR);
/*
- * Setup for:
- * - beacon misses
- * - magic pattern
- * - keep alive timeout
- * - pattern matching
+ * Random Backoff.
+ *
+ * 31:28 in AR_WOW_PATTERN : Indicates the number of bits used in the
+ * contention window. For value N,
+ * the random backoff will be selected between
+ * 0 and (2 ^ N) - 1.
*/
+ REG_SET_BIT(ah, AR_WOW_PATTERN,
+ AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF));
/*
- * Program default values for pattern backoff, aifs/slot/KAL count,
- * beacon miss timeout, KAL timeout, etc.
+ * AIFS time, Slot time, Keep Alive count.
+ */
+ REG_SET_BIT(ah, AR_WOW_COUNT, AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) |
+ AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) |
+ AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT));
+ /*
+ * Beacon timeout.
*/
- set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF);
- REG_SET_BIT(ah, AR_WOW_PATTERN, set);
-
- set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) |
- AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) |
- AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT);
- REG_SET_BIT(ah, AR_WOW_COUNT, set);
-
if (pattern_enable & AH_WOW_BEACON_MISS)
- set = AR_WOW_BEACON_TIMO;
- /* We are not using beacon miss, program a large value */
+ REG_WRITE(ah, AR_WOW_BCN_TIMO, AR_WOW_BEACON_TIMO);
else
- set = AR_WOW_BEACON_TIMO_MAX;
-
- REG_WRITE(ah, AR_WOW_BCN_TIMO, set);
+ REG_WRITE(ah, AR_WOW_BCN_TIMO, AR_WOW_BEACON_TIMO_MAX);
/*
- * Keep alive timo in ms except AR9280
+ * Keep alive timeout in ms.
*/
if (!pattern_enable)
- set = AR_WOW_KEEP_ALIVE_NEVER;
+ REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, AR_WOW_KEEP_ALIVE_NEVER);
else
- set = KAL_TIMEOUT * 32;
-
- REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set);
+ REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, KAL_TIMEOUT * 32);
/*
- * Keep alive delay in us. based on 'power on clock',
- * therefore in usec
+ * Keep alive delay in us.
*/
- set = KAL_DELAY * 1000;
- REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set);
+ REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, KAL_DELAY * 1000);
/*
- * Create keep alive pattern to respond to beacons
+ * Create keep alive pattern to respond to beacons.
*/
ath9k_wow_create_keep_alive_pattern(ah);
/*
- * Configure MAC WoW Registers
+ * Configure keep alive register.
*/
- set = 0;
+ keep_alive = REG_READ(ah, AR_WOW_KEEP_ALIVE);
+
/* Send keep alive timeouts anyway */
- clr = AR_WOW_KEEP_ALIVE_AUTO_DIS;
+ keep_alive &= ~AR_WOW_KEEP_ALIVE_AUTO_DIS;
- if (pattern_enable & AH_WOW_LINK_CHANGE)
+ if (pattern_enable & AH_WOW_LINK_CHANGE) {
+ keep_alive &= ~AR_WOW_KEEP_ALIVE_FAIL_DIS;
wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL;
- else
- set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
+ } else {
+ keep_alive |= AR_WOW_KEEP_ALIVE_FAIL_DIS;
+ }
- set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
- REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr);
+ REG_WRITE(ah, AR_WOW_KEEP_ALIVE, keep_alive);
/*
- * we are relying on a bmiss failure. ensure we have
- * enough threshold to prevent false positives
+ * We are relying on a bmiss failure, ensure we have
+ * enough threshold to prevent false positives.
*/
REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR,
AR_WOW_BMISSTHRESHOLD);
- set = 0;
- clr = 0;
-
if (pattern_enable & AH_WOW_BEACON_MISS) {
- set = AR_WOW_BEACON_FAIL_EN;
wow_event_mask |= AR_WOW_BEACON_FAIL;
+ REG_SET_BIT(ah, AR_WOW_BCN_EN, AR_WOW_BEACON_FAIL_EN);
} else {
- clr = AR_WOW_BEACON_FAIL_EN;
+ REG_CLR_BIT(ah, AR_WOW_BCN_EN, AR_WOW_BEACON_FAIL_EN);
}
- REG_RMW(ah, AR_WOW_BCN_EN, set, clr);
-
- set = 0;
- clr = 0;
/*
- * Enable the magic packet registers
+ * Enable the magic packet registers.
*/
+ magic_pattern = REG_READ(ah, AR_WOW_PATTERN);
+ magic_pattern |= AR_WOW_MAC_INTR_EN;
+
if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) {
- set = AR_WOW_MAGIC_EN;
+ magic_pattern |= AR_WOW_MAGIC_EN;
wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND;
} else {
- clr = AR_WOW_MAGIC_EN;
+ magic_pattern &= ~AR_WOW_MAGIC_EN;
}
- set |= AR_WOW_MAC_INTR_EN;
- REG_RMW(ah, AR_WOW_PATTERN, set, clr);
+ REG_WRITE(ah, AR_WOW_PATTERN, magic_pattern);
+
+ /*
+ * Enable pattern matching for packets which are less
+ * than 256 bytes.
+ */
REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,
AR_WOW_PATTERN_SUPPORTED);
/*
- * Set the power states appropriately and enable PME
+ * Set the power states appropriately and enable PME.
*/
- clr = 0;
- set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN |
- AR_PMCTRL_PWR_PM_CTRL_ENA;
+ host_pm_ctrl = REG_READ(ah, AR_PCIE_PM_CTRL);
+ host_pm_ctrl |= AR_PMCTRL_PWR_STATE_D1D3 |
+ AR_PMCTRL_HOST_PME_EN |
+ AR_PMCTRL_PWR_PM_CTRL_ENA;
+ host_pm_ctrl &= ~AR_PCIE_PM_CTRL_ENA;
- clr = AR_PCIE_PM_CTRL_ENA;
- REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr);
+ if (AR_SREV_9462(ah)) {
+ /*
+ * This is needed to prevent the chip waking up
+ * the host within 3-4 seconds with certain
+ * platform/BIOS.
+ */
+ host_pm_ctrl &= ~AR_PMCTRL_PWR_STATE_D1D3;
+ host_pm_ctrl |= AR_PMCTRL_PWR_STATE_D1D3_REAL;
+ }
+
+ REG_WRITE(ah, AR_PCIE_PM_CTRL, host_pm_ctrl);
/*
- * this is needed to prevent the chip waking up
- * the host within 3-4 seconds with certain
- * platform/BIOS. The fix is to enable
- * D1 & D3 to match original definition and
- * also match the OTP value. Anyway this
- * is more related to SW WOW.
+ * Enable sequence number generation when asleep.
*/
- clr = AR_PMCTRL_PWR_STATE_D1D3;
- REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
+ REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
- set = AR_PMCTRL_PWR_STATE_D1D3_REAL;
- REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
+ /* To bring down WOW power low margin */
+ REG_SET_BIT(ah, AR_PCIE_PHY_REG3, BIT(13));
- REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
+ ath9k_hw_wow_set_arwr_reg(ah);
- /* to bring down WOW power low margin */
- set = BIT(13);
- REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);
/* HW WoW */
- clr = BIT(5);
- REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
+ REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, BIT(5));
ath9k_hw_set_powermode_wow_sleep(ah);
- ah->wow_event_mask = wow_event_mask;
+ ah->wow.wow_event_mask = wow_event_mask;
}
EXPORT_SYMBOL(ath9k_hw_wow_enable);
diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h
index 159cc6fd2362..6fc0d07e5ec6 100644
--- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h
@@ -358,7 +358,7 @@ static const u32 qca953x_1p0_baseband_postamble[][5] = {
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
- {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822},
+ {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10820, 0xcfa10820},
{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
@@ -378,7 +378,7 @@ static const u32 qca953x_1p0_baseband_postamble[][5] = {
{0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
- {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+ {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18},
{0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33},
{0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982},
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
diff --git a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
index fd6a84ccd49e..148562addd38 100644
--- a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
@@ -63,7 +63,7 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = {
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
- {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822},
+ {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10820, 0xcfa10820},
{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
@@ -83,7 +83,7 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = {
{0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
- {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+ {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18},
{0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33},
{0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982},
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
diff --git a/drivers/net/wireless/ath/ath9k/ar956x_initvals.h b/drivers/net/wireless/ath/ath9k/ar956x_initvals.h
new file mode 100644
index 000000000000..c3a47eaaf0c0
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar956x_initvals.h
@@ -0,0 +1,1046 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INITVALS_956X_H
+#define INITVALS_956X_H
+
+#define qca956x_1p0_mac_core ar955x_1p0_mac_core
+
+#define qca956x_1p0_mac_postamble ar9331_1p1_mac_postamble
+
+#define qca956x_1p0_soc_preamble ar955x_1p0_soc_preamble
+
+#define qca956x_1p0_soc_postamble ar9300_2p2_soc_postamble
+
+#define qca956x_1p0_common_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2
+
+#define qca956x_1p0_baseband_postamble_dfs_channel ar9300_2p2_baseband_postamble_dfs_channel
+
+#define qca956x_1p0_common_wo_xlna_rx_gain_bounds ar955x_1p0_common_wo_xlna_rx_gain_bounds
+
+#define qca956x_1p0_common_rx_gain_bounds ar955x_1p0_common_rx_gain_bounds
+
+#define qca956x_1p0_modes_fast_clock ar9462_2p0_modes_fast_clock
+
+static const u32 qca956x_1p0_baseband_core[][2] = {
+ /* Addr allmodes */
+ {0x00009800, 0xafe68e30},
+ {0x00009804, 0xfd14e000},
+ {0x00009808, 0x9c0a9f6b},
+ {0x0000980c, 0x04900000},
+ {0x00009814, 0x0280c00a},
+ {0x00009818, 0x00000000},
+ {0x0000981c, 0x00020028},
+ {0x00009834, 0x6400a190},
+ {0x00009838, 0x0108ecff},
+ {0x0000983c, 0x14000600},
+ {0x00009880, 0x201fff00},
+ {0x00009884, 0x00001042},
+ {0x000098a4, 0x00200400},
+ {0x000098b0, 0x32840cbf},
+ {0x000098bc, 0x00000002},
+ {0x000098d0, 0x004b6a8e},
+ {0x000098d4, 0x00000820},
+ {0x000098dc, 0x00000000},
+ {0x000098f0, 0x00000000},
+ {0x000098f4, 0x00000000},
+ {0x00009c04, 0xff55ff55},
+ {0x00009c08, 0x0320ff55},
+ {0x00009c0c, 0x00000000},
+ {0x00009c10, 0x00000000},
+ {0x00009c14, 0x00046384},
+ {0x00009c18, 0x05b6b440},
+ {0x00009c1c, 0x00b6b440},
+ {0x00009d00, 0xc080a333},
+ {0x00009d04, 0x40206c10},
+ {0x00009d08, 0x009c4060},
+ {0x00009d0c, 0x9883800a},
+ {0x00009d10, 0x01834061},
+ {0x00009d14, 0x00c0040b},
+ {0x00009d18, 0x00000000},
+ {0x00009e08, 0x0038230c},
+ {0x00009e24, 0x990bb514},
+ {0x00009e28, 0x0c6f0000},
+ {0x00009e30, 0x06336f77},
+ {0x00009e34, 0x6af6532f},
+ {0x00009e38, 0x0cc80c00},
+ {0x00009e40, 0x0d261820},
+ {0x00009e4c, 0x00001004},
+ {0x00009e50, 0x00ff03f1},
+ {0x00009fc0, 0x813e4789},
+ {0x00009fc4, 0x0001efb5},
+ {0x00009fcc, 0x40000014},
+ {0x00009fd0, 0x02993b93},
+ {0x0000a20c, 0x00000000},
+ {0x0000a218, 0x00000000},
+ {0x0000a21c, 0x00000000},
+ {0x0000a228, 0x10002310},
+ {0x0000a23c, 0x00000000},
+ {0x0000a244, 0x0c000000},
+ {0x0000a248, 0x00000140},
+ {0x0000a2a0, 0x00000007},
+ {0x0000a2c0, 0x00000007},
+ {0x0000a2c8, 0x00000000},
+ {0x0000a2d4, 0x00000000},
+ {0x0000a2ec, 0x00000000},
+ {0x0000a2f0, 0x00000000},
+ {0x0000a2f4, 0x00000000},
+ {0x0000a2f8, 0x00000000},
+ {0x0000a344, 0x00000000},
+ {0x0000a34c, 0x00000000},
+ {0x0000a350, 0x0000a000},
+ {0x0000a360, 0x00000000},
+ {0x0000a36c, 0x00000000},
+ {0x0000a384, 0x00000001},
+ {0x0000a388, 0x00000444},
+ {0x0000a38c, 0x00000000},
+ {0x0000a390, 0x210d0401},
+ {0x0000a394, 0xab9a7144},
+ {0x0000a398, 0x00000201},
+ {0x0000a39c, 0x42424848},
+ {0x0000a3a0, 0x3c466478},
+ {0x0000a3a4, 0x3a363600},
+ {0x0000a3a8, 0x0000003a},
+ {0x0000a3ac, 0x00000000},
+ {0x0000a3b0, 0x009011fe},
+ {0x0000a3b4, 0x00000034},
+ {0x0000a3b8, 0x00b3ec0a},
+ {0x0000a3bc, 0x00000036},
+ {0x0000a3c0, 0x20202020},
+ {0x0000a3c4, 0x22222220},
+ {0x0000a3c8, 0x20200020},
+ {0x0000a3cc, 0x20202020},
+ {0x0000a3d0, 0x20202020},
+ {0x0000a3d4, 0x20202020},
+ {0x0000a3d8, 0x20202020},
+ {0x0000a3dc, 0x20202020},
+ {0x0000a3e0, 0x20202020},
+ {0x0000a3e4, 0x20202020},
+ {0x0000a3e8, 0x20202020},
+ {0x0000a3ec, 0x20202020},
+ {0x0000a3f0, 0x00000000},
+ {0x0000a3f4, 0x00000000},
+ {0x0000a3f8, 0x0c9bd380},
+ {0x0000a3fc, 0x000f0f01},
+ {0x0000a400, 0x8fa91f01},
+ {0x0000a404, 0x00000000},
+ {0x0000a408, 0x0e79e5c6},
+ {0x0000a40c, 0x00820820},
+ {0x0000a414, 0x1ce739ce},
+ {0x0000a418, 0x2d0019ce},
+ {0x0000a41c, 0x1ce739ce},
+ {0x0000a420, 0x000001ce},
+ {0x0000a424, 0x1ce739ce},
+ {0x0000a428, 0x000001ce},
+ {0x0000a42c, 0x1ce739ce},
+ {0x0000a430, 0x1ce739ce},
+ {0x0000a434, 0x00000000},
+ {0x0000a438, 0x00001801},
+ {0x0000a43c, 0x00100000},
+ {0x0000a444, 0x00000000},
+ {0x0000a448, 0x05000080},
+ {0x0000a44c, 0x00000001},
+ {0x0000a450, 0x00010000},
+ {0x0000a454, 0x05000000},
+ {0x0000a458, 0x00000000},
+ {0x0000a644, 0xbfad9fee},
+ {0x0000a648, 0x0048660d},
+ {0x0000a64c, 0x00003c37},
+ {0x0000a670, 0x03020100},
+ {0x0000a674, 0x21200504},
+ {0x0000a678, 0x61602322},
+ {0x0000a67c, 0x65646362},
+ {0x0000a680, 0x6b6a6968},
+ {0x0000a684, 0xe2706d6c},
+ {0x0000a688, 0x000000e3},
+ {0x0000a690, 0x00000838},
+ {0x0000a7cc, 0x00000000},
+ {0x0000a7d0, 0x00000000},
+ {0x0000a7d4, 0x00000004},
+ {0x0000a7dc, 0x00000000},
+ {0x0000a8d0, 0x004b6a8e},
+ {0x0000a8d4, 0x00000820},
+ {0x0000a8dc, 0x00000000},
+ {0x0000a8f0, 0x00000000},
+ {0x0000a8f4, 0x00000000},
+ {0x0000b2d0, 0x00000080},
+ {0x0000b2d4, 0x00000000},
+ {0x0000b2ec, 0x00000000},
+ {0x0000b2f0, 0x00000000},
+ {0x0000b2f4, 0x00000000},
+ {0x0000b2f8, 0x00000000},
+ {0x0000b408, 0x0e79e5c0},
+ {0x0000b40c, 0x00820820},
+ {0x0000b420, 0x00000000},
+ {0x0000b8d0, 0x004b6a8e},
+ {0x0000b8d4, 0x00000820},
+ {0x0000b8dc, 0x00000000},
+ {0x0000b8f0, 0x00000000},
+ {0x0000b8f4, 0x00000000},
+ {0x0000c2d0, 0x00000080},
+ {0x0000c2d4, 0x00000000},
+ {0x0000c2ec, 0x00000000},
+ {0x0000c2f0, 0x00000000},
+ {0x0000c2f4, 0x00000000},
+ {0x0000c2f8, 0x00000000},
+ {0x0000c408, 0x0e79e5c0},
+ {0x0000c40c, 0x00820820},
+ {0x0000c420, 0x00000000},
+};
+
+static const u32 qca956x_1p0_baseband_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
+ {0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae},
+ {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac621f1, 0x5ac621f1},
+ {0x00009828, 0x06903081, 0x06903081, 0x07d43881, 0x07d43881},
+ {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
+ {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
+ {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
+ {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
+ {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000de, 0x6c4000de},
+ {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e},
+ {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x337d605e, 0x337d5d5e},
+ {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+ {0x00009e20, 0x000003b5, 0x000003b5, 0x000003a6, 0x000003a6},
+ {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+ {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcf946222, 0xcf946222},
+ {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
+ {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+ {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+ {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x045c0cc4, 0x045c0cc0},
+ {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+ {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f},
+ {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
+ {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
+ {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018},
+ {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+ {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+ {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
+ {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e},
+ {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
+ {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e},
+ {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
+ {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
+ {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
+ {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
+ {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
+ {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33},
+ {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982},
+ {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
+ {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
+ {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001a6, 0x000001a6},
+ {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
+ {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000be04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
+ {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000be20, 0x000001b5, 0x000001b5, 0x000001a6, 0x000001a6},
+ {0x0000c284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
+};
+
+static const u32 qca956x_1p0_radio_core[][2] = {
+ /* Addr allmodes */
+ {0x00016000, 0x36db6db6},
+ {0x00016004, 0x6db6db40},
+ {0x00016008, 0x73f00000},
+ {0x0001600c, 0x00000000},
+ {0x00016040, 0x3f80fff8},
+ {0x0001604c, 0x000f0278},
+ {0x00016050, 0x8036db6c},
+ {0x00016054, 0x6db60000},
+ {0x00016080, 0x00080000},
+ {0x00016084, 0x0e48048c},
+ {0x00016088, 0x14214514},
+ {0x0001608c, 0x119f080a},
+ {0x00016090, 0x24926490},
+ {0x00016094, 0x00000000},
+ {0x000160a0, 0xc2108ffe},
+ {0x000160a4, 0x812fc370},
+ {0x000160a8, 0x423c8000},
+ {0x000160b4, 0x92480000},
+ {0x000160c0, 0x006db6d8},
+ {0x000160c4, 0x24b6db6c},
+ {0x000160c8, 0x6db6db6c},
+ {0x000160cc, 0x6db6fb7c},
+ {0x000160d0, 0x6db6da44},
+ {0x00016100, 0x07ff8001},
+ {0x00016108, 0x00080010},
+ {0x00016144, 0x01884080},
+ {0x00016148, 0x00008058},
+ {0x00016288, 0x001c6000},
+ {0x0001628c, 0x50000000},
+ {0x000162c0, 0x4b962100},
+ {0x000162c4, 0x00000480},
+ {0x000162c8, 0x04000144},
+ {0x00016380, 0x00000000},
+ {0x00016384, 0x00000000},
+ {0x00016388, 0x00800700},
+ {0x0001638c, 0x00800700},
+ {0x00016390, 0x00800700},
+ {0x00016394, 0x00000000},
+ {0x00016398, 0x00000000},
+ {0x0001639c, 0x00000000},
+ {0x000163a0, 0x00000001},
+ {0x000163a4, 0x00000001},
+ {0x000163a8, 0x00000000},
+ {0x000163ac, 0x00000000},
+ {0x000163b0, 0x00000000},
+ {0x000163b4, 0x00000000},
+ {0x000163b8, 0x00000000},
+ {0x000163bc, 0x00000000},
+ {0x000163c0, 0x000000a0},
+ {0x000163c4, 0x000c0000},
+ {0x000163c8, 0x14021402},
+ {0x000163cc, 0x00001402},
+ {0x000163d0, 0x00000000},
+ {0x000163d4, 0x00000000},
+ {0x00016400, 0x36db6db6},
+ {0x00016404, 0x6db6db40},
+ {0x00016408, 0x73f00000},
+ {0x0001640c, 0x00000000},
+ {0x00016440, 0x3f80fff8},
+ {0x0001644c, 0x000f0278},
+ {0x00016450, 0x8036db6c},
+ {0x00016454, 0x6db60000},
+ {0x00016500, 0x07ff8001},
+ {0x00016508, 0x00080010},
+ {0x00016544, 0x01884080},
+ {0x00016548, 0x00008058},
+ {0x00016780, 0x00000000},
+ {0x00016784, 0x00000000},
+ {0x00016788, 0x00800700},
+ {0x0001678c, 0x00800700},
+ {0x00016790, 0x00800700},
+ {0x00016794, 0x00000000},
+ {0x00016798, 0x00000000},
+ {0x0001679c, 0x00000000},
+ {0x000167a0, 0x00000001},
+ {0x000167a4, 0x00000001},
+ {0x000167a8, 0x00000000},
+ {0x000167ac, 0x00000000},
+ {0x000167b0, 0x00000000},
+ {0x000167b4, 0x00000000},
+ {0x000167b8, 0x00000000},
+ {0x000167bc, 0x00000000},
+ {0x000167c0, 0x000000a0},
+ {0x000167c4, 0x000c0000},
+ {0x000167c8, 0x14021402},
+ {0x000167cc, 0x00001402},
+ {0x000167d0, 0x00000000},
+ {0x000167d4, 0x00000000},
+ {0x00016800, 0x36db6db6},
+ {0x00016804, 0x6db6db40},
+ {0x00016808, 0x73f00000},
+ {0x0001680c, 0x00000000},
+ {0x00016840, 0x3f80fff8},
+ {0x0001684c, 0x000f0278},
+ {0x00016850, 0x8036db6c},
+ {0x00016854, 0x6db60000},
+ {0x00016900, 0x07ff8001},
+ {0x00016908, 0x00080010},
+ {0x00016944, 0x01884080},
+ {0x00016948, 0x00008058},
+ {0x00016b80, 0x00000000},
+ {0x00016b84, 0x00000000},
+ {0x00016b88, 0x00800700},
+ {0x00016b8c, 0x00800700},
+ {0x00016b90, 0x00800700},
+ {0x00016b94, 0x00000000},
+ {0x00016b98, 0x00000000},
+ {0x00016b9c, 0x00000000},
+ {0x00016ba0, 0x00000001},
+ {0x00016ba4, 0x00000001},
+ {0x00016ba8, 0x00000000},
+ {0x00016bac, 0x00000000},
+ {0x00016bb0, 0x00000000},
+ {0x00016bb4, 0x00000000},
+ {0x00016bb8, 0x00000000},
+ {0x00016bbc, 0x00000000},
+ {0x00016bc0, 0x000000a0},
+ {0x00016bc4, 0x000c0000},
+ {0x00016bc8, 0x14021402},
+ {0x00016bcc, 0x00001402},
+ {0x00016bd0, 0x00000000},
+ {0x00016bd4, 0x00000000},
+};
+
+static const u32 qca956x_1p0_radio_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xc4128f5c, 0xc4128f5c},
+ {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0fd08f25, 0x0fd08f25},
+ {0x000160ac, 0xa4647c00, 0xa4647c00, 0x24646800, 0x24646800},
+ {0x000160b0, 0x01885f52, 0x01885f52, 0x00fe7f46, 0x00fe7f46},
+ {0x00016104, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001},
+ {0x0001610c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000},
+ {0x00016140, 0x10804008, 0x10804008, 0x50804000, 0x50804000},
+ {0x00016504, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001},
+ {0x0001650c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000},
+ {0x00016540, 0x10804008, 0x10804008, 0x50804000, 0x50804000},
+ {0x00016904, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001},
+ {0x0001690c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000},
+ {0x00016940, 0x10804008, 0x10804008, 0x50804000, 0x50804000},
+};
+
+static const u32 qca956x_1p0_baseband_core_txfir_coeff_japan_2484[][2] = {
+ /* Addr allmodes */
+ {0x0000a38c, 0x00000000},
+ {0x0000a390, 0x6f7f0301},
+ {0x0000a394, 0xca9228ee},
+};
+
+static const u32 qca956x_1p0_modes_no_xpa_tx_gain_table[][3] = {
+ /* Addr 5G 2G */
+ {0x0000a2dc, 0xffa9ac94, 0xffa9ac94},
+ {0x0000a2e0, 0xff323118, 0xff323118},
+ {0x0000a2e4, 0xff3ffe00, 0xff3ffe00},
+ {0x0000a2e8, 0xffc00000, 0xffc00000},
+ {0x0000a39c, 0x42424242, 0x42424242},
+ {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00},
+ {0x0000a3b0, 0x00a01404, 0x00a01404},
+ {0x0000a3b4, 0x00000034, 0x00000034},
+ {0x0000a3b8, 0x00800408, 0x00800408},
+ {0x0000a3bc, 0x00000036, 0x00000036},
+ {0x0000a410, 0x000050dc, 0x000050dc},
+ {0x0000a500, 0x09000040, 0x09000040},
+ {0x0000a504, 0x0b000041, 0x0b000041},
+ {0x0000a508, 0x0d000042, 0x0d000042},
+ {0x0000a50c, 0x11000044, 0x11000044},
+ {0x0000a510, 0x15000046, 0x15000046},
+ {0x0000a514, 0x1d000440, 0x1d000440},
+ {0x0000a518, 0x1f000441, 0x1f000441},
+ {0x0000a51c, 0x23000443, 0x23000443},
+ {0x0000a520, 0x25000444, 0x25000444},
+ {0x0000a524, 0x280004e0, 0x280004e0},
+ {0x0000a528, 0x2c0004e2, 0x2c0004e2},
+ {0x0000a52c, 0x2e0004e3, 0x2e0004e3},
+ {0x0000a530, 0x300004e4, 0x300004e4},
+ {0x0000a534, 0x340004e6, 0x340004e6},
+ {0x0000a538, 0x37000ce0, 0x37000ce0},
+ {0x0000a53c, 0x3b000ce2, 0x3b000ce2},
+ {0x0000a540, 0x3d000ce3, 0x3d000ce3},
+ {0x0000a544, 0x3f000ce4, 0x3f000ce4},
+ {0x0000a548, 0x45001ee0, 0x45001ee0},
+ {0x0000a54c, 0x49001ee2, 0x49001ee2},
+ {0x0000a550, 0x4d001ee4, 0x4d001ee4},
+ {0x0000a554, 0x51001ee6, 0x51001ee6},
+ {0x0000a558, 0x55001eea, 0x55001eea},
+ {0x0000a55c, 0x59001eec, 0x59001eec},
+ {0x0000a560, 0x5d001ef0, 0x5d001ef0},
+ {0x0000a564, 0x5f001ef1, 0x5f001ef1},
+ {0x0000a568, 0x60001ef2, 0x60001ef2},
+ {0x0000a56c, 0x61001ef3, 0x61001ef3},
+ {0x0000a570, 0x62001ef4, 0x62001ef4},
+ {0x0000a574, 0x63001ef5, 0x63001ef5},
+ {0x0000a578, 0x64001ffc, 0x64001ffc},
+ {0x0000a57c, 0x64001ffc, 0x64001ffc},
+ {0x0000a600, 0x00000000, 0x00000000},
+ {0x0000a604, 0x00000000, 0x00000000},
+ {0x0000a608, 0x00000000, 0x00000000},
+ {0x0000a60c, 0x00000000, 0x00000000},
+ {0x0000a610, 0x00804000, 0x00804000},
+ {0x0000a614, 0x00804201, 0x00804201},
+ {0x0000a618, 0x00804201, 0x00804201},
+ {0x0000a61c, 0x00804201, 0x00804201},
+ {0x0000a620, 0x00804201, 0x00804201},
+ {0x0000a624, 0x00804201, 0x00804201},
+ {0x0000a628, 0x00804201, 0x00804201},
+ {0x0000a62c, 0x02808a02, 0x02808a02},
+ {0x0000a630, 0x0340cd03, 0x0340cd03},
+ {0x0000a634, 0x0340cd03, 0x0340cd03},
+ {0x0000a638, 0x0340cd03, 0x0340cd03},
+ {0x0000a63c, 0x05011404, 0x05011404},
+ {0x0000b2dc, 0xffa9ac94, 0xffa9ac94},
+ {0x0000b2e0, 0xff323118, 0xff323118},
+ {0x0000b2e4, 0xff3ffe00, 0xff3ffe00},
+ {0x0000b2e8, 0xffc00000, 0xffc00000},
+ {0x0000c2dc, 0xffa9ac94, 0xffa9ac94},
+ {0x0000c2e0, 0xff323118, 0xff323118},
+ {0x0000c2e4, 0xff3ffe00, 0xff3ffe00},
+ {0x0000c2e8, 0xffc00000, 0xffc00000},
+ {0x00016044, 0x049242db, 0x049242db},
+ {0x00016048, 0x64925a70, 0x64925a70},
+ {0x00016148, 0x00008050, 0x00008050},
+ {0x00016280, 0x41110005, 0x41110005},
+ {0x00016284, 0x453a6000, 0x453a6000},
+ {0x00016444, 0x049242db, 0x049242db},
+ {0x00016448, 0x6c925a70, 0x6c925a70},
+ {0x00016548, 0x00008050, 0x00008050},
+ {0x00016844, 0x049242db, 0x049242db},
+ {0x00016848, 0x6c925a70, 0x6c925a70},
+ {0x00016948, 0x00008050, 0x00008050},
+};
+
+static const u32 qca956x_1p0_modes_xpa_tx_gain_table[][3] = {
+ /* Addr 5G 2G */
+ {0x0000a2dc, 0xcc69ac94, 0xcc69ac94},
+ {0x0000a2e0, 0xf0b23118, 0xf0b23118},
+ {0x0000a2e4, 0xffffc000, 0xffffc000},
+ {0x0000a2e8, 0xc0000000, 0xc0000000},
+ {0x0000a410, 0x000050d2, 0x000050d2},
+ {0x0000a500, 0x0a000040, 0x0a000040},
+ {0x0000a504, 0x0c000041, 0x0c000041},
+ {0x0000a508, 0x0e000042, 0x0e000042},
+ {0x0000a50c, 0x12000044, 0x12000044},
+ {0x0000a510, 0x16000046, 0x16000046},
+ {0x0000a514, 0x1d000440, 0x1d000440},
+ {0x0000a518, 0x1f000441, 0x1f000441},
+ {0x0000a51c, 0x23000443, 0x23000443},
+ {0x0000a520, 0x25000444, 0x25000444},
+ {0x0000a524, 0x29000a40, 0x29000a40},
+ {0x0000a528, 0x2d000a42, 0x2d000a42},
+ {0x0000a52c, 0x2f000a43, 0x2f000a43},
+ {0x0000a530, 0x31000a44, 0x31000a44},
+ {0x0000a534, 0x35000a46, 0x35000a46},
+ {0x0000a538, 0x38000ce0, 0x38000ce0},
+ {0x0000a53c, 0x3c000ce2, 0x3c000ce2},
+ {0x0000a540, 0x3e000ce3, 0x3e000ce3},
+ {0x0000a544, 0x40000ce4, 0x40000ce4},
+ {0x0000a548, 0x46001ee0, 0x46001ee0},
+ {0x0000a54c, 0x4a001ee2, 0x4a001ee2},
+ {0x0000a550, 0x4e001ee4, 0x4e001ee4},
+ {0x0000a554, 0x52001ee6, 0x52001ee6},
+ {0x0000a558, 0x56001eea, 0x56001eea},
+ {0x0000a55c, 0x5a001eec, 0x5a001eec},
+ {0x0000a560, 0x5e001ef0, 0x5e001ef0},
+ {0x0000a564, 0x60001ef1, 0x60001ef1},
+ {0x0000a568, 0x61001ef2, 0x61001ef2},
+ {0x0000a56c, 0x62001ef3, 0x62001ef3},
+ {0x0000a570, 0x63001ef4, 0x63001ef4},
+ {0x0000a574, 0x64001ef5, 0x64001ef5},
+ {0x0000a578, 0x65001ffc, 0x65001ffc},
+ {0x0000a57c, 0x65001ffc, 0x65001ffc},
+ {0x0000a600, 0x00000000, 0x00000000},
+ {0x0000a604, 0x00000000, 0x00000000},
+ {0x0000a608, 0x00000000, 0x00000000},
+ {0x0000a60c, 0x00000000, 0x00000000},
+ {0x0000a610, 0x00000000, 0x00000000},
+ {0x0000a614, 0x00000000, 0x00000000},
+ {0x0000a618, 0x00000000, 0x00000000},
+ {0x0000a61c, 0x00804201, 0x00804201},
+ {0x0000a620, 0x00804201, 0x00804201},
+ {0x0000a624, 0x00804201, 0x00804201},
+ {0x0000a628, 0x00804201, 0x00804201},
+ {0x0000a62c, 0x02808a02, 0x02808a02},
+ {0x0000a630, 0x0340cd03, 0x0340cd03},
+ {0x0000a634, 0x0340cd03, 0x0340cd03},
+ {0x0000a638, 0x0340cd03, 0x0340cd03},
+ {0x0000a63c, 0x05011404, 0x05011404},
+ {0x0000b2dc, 0xcc69ac94, 0xcc69ac94},
+ {0x0000b2e0, 0xf0b23118, 0xf0b23118},
+ {0x0000b2e4, 0xffffc000, 0xffffc000},
+ {0x0000b2e8, 0xc0000000, 0xc0000000},
+ {0x0000c2dc, 0xcc69ac94, 0xcc69ac94},
+ {0x0000c2e0, 0xf0b23118, 0xf0b23118},
+ {0x0000c2e4, 0xffffc000, 0xffffc000},
+ {0x0000c2e8, 0xc0000000, 0xc0000000},
+ {0x00016044, 0x012492db, 0x012492db},
+ {0x00016048, 0x6c927a70, 0x6c927a70},
+ {0x00016050, 0x8036d36c, 0x8036d36c},
+ {0x00016280, 0x41110005, 0x41110005},
+ {0x00016284, 0x453a7e00, 0x453a7e00},
+ {0x00016444, 0x012492db, 0x012492db},
+ {0x00016448, 0x6c927a70, 0x6c927a70},
+ {0x00016450, 0x8036d36c, 0x8036d36c},
+ {0x00016844, 0x012492db, 0x012492db},
+ {0x00016848, 0x6c927a70, 0x6c927a70},
+ {0x00016850, 0x8036d36c, 0x8036d36c},
+};
+
+static const u32 qca956x_1p0_modes_no_xpa_low_ob_db_tx_gain_table[][3] = {
+ /* Addr 5G 2G */
+ {0x0000a2dc, 0xffa9ac94, 0xffa9ac94},
+ {0x0000a2e0, 0xff323118, 0xff323118},
+ {0x0000a2e4, 0xff3ffe00, 0xff3ffe00},
+ {0x0000a2e8, 0xffc00000, 0xffc00000},
+ {0x0000a39c, 0x42424242, 0x42424242},
+ {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00},
+ {0x0000a3b0, 0x00a01404, 0x00a01404},
+ {0x0000a3b4, 0x00000034, 0x00000034},
+ {0x0000a3b8, 0x00800408, 0x00800408},
+ {0x0000a3bc, 0x00000036, 0x00000036},
+ {0x0000a410, 0x000050dc, 0x000050dc},
+ {0x0000a414, 0x16b739ce, 0x16b739ce},
+ {0x0000a418, 0x2d00198b, 0x2d00198b},
+ {0x0000a41c, 0x16b5adce, 0x16b5adce},
+ {0x0000a420, 0x0000014a, 0x0000014a},
+ {0x0000a424, 0x14a525cc, 0x14a525cc},
+ {0x0000a428, 0x0000012a, 0x0000012a},
+ {0x0000a42c, 0x14a5294a, 0x14a5294a},
+ {0x0000a430, 0x1294a929, 0x1294a929},
+ {0x0000a500, 0x09000040, 0x09000040},
+ {0x0000a504, 0x0b000041, 0x0b000041},
+ {0x0000a508, 0x0d000042, 0x0d000042},
+ {0x0000a50c, 0x11000044, 0x11000044},
+ {0x0000a510, 0x15000046, 0x15000046},
+ {0x0000a514, 0x1d000440, 0x1d000440},
+ {0x0000a518, 0x1f000441, 0x1f000441},
+ {0x0000a51c, 0x23000443, 0x23000443},
+ {0x0000a520, 0x25000444, 0x25000444},
+ {0x0000a524, 0x280004e0, 0x280004e0},
+ {0x0000a528, 0x2c0004e2, 0x2c0004e2},
+ {0x0000a52c, 0x2e0004e3, 0x2e0004e3},
+ {0x0000a530, 0x300004e4, 0x300004e4},
+ {0x0000a534, 0x340004e6, 0x340004e6},
+ {0x0000a538, 0x37000ce0, 0x37000ce0},
+ {0x0000a53c, 0x3b000ce2, 0x3b000ce2},
+ {0x0000a540, 0x3d000ce3, 0x3d000ce3},
+ {0x0000a544, 0x3f000ce4, 0x3f000ce4},
+ {0x0000a548, 0x45001ee0, 0x45001ee0},
+ {0x0000a54c, 0x49001ee2, 0x49001ee2},
+ {0x0000a550, 0x4d001ee4, 0x4d001ee4},
+ {0x0000a554, 0x51001ee6, 0x51001ee6},
+ {0x0000a558, 0x55001eea, 0x55001eea},
+ {0x0000a55c, 0x59001eec, 0x59001eec},
+ {0x0000a560, 0x5d001ef0, 0x5d001ef0},
+ {0x0000a564, 0x5f001ef1, 0x5f001ef1},
+ {0x0000a568, 0x60001ef2, 0x60001ef2},
+ {0x0000a56c, 0x61001ef3, 0x61001ef3},
+ {0x0000a570, 0x62001ef4, 0x62001ef4},
+ {0x0000a574, 0x63001ef5, 0x63001ef5},
+ {0x0000a578, 0x64001ffc, 0x64001ffc},
+ {0x0000a57c, 0x64001ffc, 0x64001ffc},
+ {0x0000a600, 0x00000000, 0x00000000},
+ {0x0000a604, 0x00000000, 0x00000000},
+ {0x0000a608, 0x00000000, 0x00000000},
+ {0x0000a60c, 0x00000000, 0x00000000},
+ {0x0000a610, 0x00804000, 0x00804000},
+ {0x0000a614, 0x00804201, 0x00804201},
+ {0x0000a618, 0x00804201, 0x00804201},
+ {0x0000a61c, 0x00804201, 0x00804201},
+ {0x0000a620, 0x00804201, 0x00804201},
+ {0x0000a624, 0x00804201, 0x00804201},
+ {0x0000a628, 0x00804201, 0x00804201},
+ {0x0000a62c, 0x02808a02, 0x02808a02},
+ {0x0000a630, 0x0340cd03, 0x0340cd03},
+ {0x0000a634, 0x0340cd03, 0x0340cd03},
+ {0x0000a638, 0x0340cd03, 0x0340cd03},
+ {0x0000a63c, 0x05011404, 0x05011404},
+ {0x0000b2dc, 0xffa9ac94, 0xffa9ac94},
+ {0x0000b2e0, 0xff323118, 0xff323118},
+ {0x0000b2e4, 0xff3ffe00, 0xff3ffe00},
+ {0x0000b2e8, 0xffc00000, 0xffc00000},
+ {0x0000c2dc, 0xffa9ac94, 0xffa9ac94},
+ {0x0000c2e0, 0xff323118, 0xff323118},
+ {0x0000c2e4, 0xff3ffe00, 0xff3ffe00},
+ {0x0000c2e8, 0xffc00000, 0xffc00000},
+ {0x00016044, 0x046e42db, 0x046e42db},
+ {0x00016048, 0x64925a70, 0x64925a70},
+ {0x00016148, 0x00008050, 0x00008050},
+ {0x00016280, 0x41110005, 0x41110005},
+ {0x00016284, 0x453a6000, 0x453a6000},
+ {0x00016444, 0x046e42db, 0x046e42db},
+ {0x00016448, 0x6c925a70, 0x6c925a70},
+ {0x00016548, 0x00008050, 0x00008050},
+ {0x00016844, 0x046e42db, 0x046e42db},
+ {0x00016848, 0x6c925a70, 0x6c925a70},
+ {0x00016948, 0x00008050, 0x00008050},
+};
+
+static const u32 qca956x_1p0_modes_no_xpa_green_tx_gain_table[][3] = {
+ /* Addr 5G 2G */
+ {0x000098bc, 0x00000001, 0x00000001},
+ {0x0000a2dc, 0xd3555284, 0xd3555284},
+ {0x0000a2e0, 0x1c666318, 0x1c666318},
+ {0x0000a2e4, 0xe07bbc00, 0xe07bbc00},
+ {0x0000a2e8, 0xff800000, 0xff800000},
+ {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00},
+ {0x0000a410, 0x000050dc, 0x000050dc},
+ {0x0000a500, 0x02000040, 0x02000040},
+ {0x0000a504, 0x04000041, 0x04000041},
+ {0x0000a508, 0x06000042, 0x06000042},
+ {0x0000a50c, 0x0a000044, 0x0a000044},
+ {0x0000a510, 0x0c000045, 0x0c000045},
+ {0x0000a514, 0x13000440, 0x13000440},
+ {0x0000a518, 0x15000441, 0x15000441},
+ {0x0000a51c, 0x19000443, 0x19000443},
+ {0x0000a520, 0x1b000444, 0x1b000444},
+ {0x0000a524, 0x1e0004e0, 0x1e0004e0},
+ {0x0000a528, 0x220004e2, 0x220004e2},
+ {0x0000a52c, 0x240004e3, 0x240004e3},
+ {0x0000a530, 0x260004e4, 0x260004e4},
+ {0x0000a534, 0x2a0004e6, 0x2a0004e6},
+ {0x0000a538, 0x32000ce0, 0x32000ce0},
+ {0x0000a53c, 0x36000ce2, 0x36000ce2},
+ {0x0000a540, 0x3a000ce4, 0x3a000ce4},
+ {0x0000a544, 0x3e000ce6, 0x3e000ce6},
+ {0x0000a548, 0x45001ee0, 0x45001ee0},
+ {0x0000a54c, 0x49001ee2, 0x49001ee2},
+ {0x0000a550, 0x4d001ee4, 0x4d001ee4},
+ {0x0000a554, 0x51001ee6, 0x51001ee6},
+ {0x0000a558, 0x55001eea, 0x55001eea},
+ {0x0000a55c, 0x59001eec, 0x59001eec},
+ {0x0000a560, 0x5d001ef0, 0x5d001ef0},
+ {0x0000a564, 0x5f001ef1, 0x5f001ef1},
+ {0x0000a568, 0x60001ef2, 0x60001ef2},
+ {0x0000a56c, 0x61001ef3, 0x61001ef3},
+ {0x0000a570, 0x62001ef4, 0x62001ef4},
+ {0x0000a574, 0x63001ff5, 0x63001ff5},
+ {0x0000a578, 0x64001ffc, 0x64001ffc},
+ {0x0000a57c, 0x64001ffc, 0x64001ffc},
+ {0x0000a600, 0x00000000, 0x00000000},
+ {0x0000a604, 0x00000000, 0x00000000},
+ {0x0000a608, 0x00000000, 0x00000000},
+ {0x0000a60c, 0x00000000, 0x00000000},
+ {0x0000a610, 0x00804000, 0x00804000},
+ {0x0000a614, 0x00804201, 0x00804201},
+ {0x0000a618, 0x00804201, 0x00804201},
+ {0x0000a61c, 0x00804201, 0x00804201},
+ {0x0000a620, 0x00804201, 0x00804201},
+ {0x0000a624, 0x00804201, 0x00804201},
+ {0x0000a628, 0x00804201, 0x00804201},
+ {0x0000a62c, 0x02808a02, 0x02808a02},
+ {0x0000a630, 0x0340cd03, 0x0340cd03},
+ {0x0000a634, 0x0340cd03, 0x0340cd03},
+ {0x0000a638, 0x0340cd03, 0x0340cd03},
+ {0x0000a63c, 0x05011404, 0x05011404},
+ {0x0000b2dc, 0xd3555284, 0xd3555284},
+ {0x0000b2e0, 0x1c666318, 0x1c666318},
+ {0x0000b2e4, 0xe07bbc00, 0xe07bbc00},
+ {0x0000b2e8, 0xff800000, 0xff800000},
+ {0x0000c2dc, 0xd3555284, 0xd3555284},
+ {0x0000c2e0, 0x1c666318, 0x1c666318},
+ {0x0000c2e4, 0xe07bbc00, 0xe07bbc00},
+ {0x0000c2e8, 0xff800000, 0xff800000},
+ {0x00016044, 0x849242db, 0x849242db},
+ {0x00016048, 0x64925a70, 0x64925a70},
+ {0x00016280, 0x41110005, 0x41110005},
+ {0x00016284, 0x453a6000, 0x453a6000},
+ {0x00016444, 0x849242db, 0x849242db},
+ {0x00016448, 0x6c925a70, 0x6c925a70},
+ {0x00016844, 0x849242db, 0x849242db},
+ {0x00016848, 0x6c925a70, 0x6c925a70},
+ {0x0000a7f0, 0x800002cc, 0x800002cc},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000028, 0x00000028},
+ {0x0000a7f4, 0x00000028, 0x00000028},
+ {0x0000a7f4, 0x00000028, 0x00000028},
+ {0x0000a7f4, 0x00000028, 0x00000028},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+};
+
+static const u32 qca956x_1p0_common_rx_gain_table[][2] = {
+ /* Addr allmodes */
+ {0x0000a000, 0x00010000},
+ {0x0000a004, 0x00030002},
+ {0x0000a008, 0x00050004},
+ {0x0000a00c, 0x00810080},
+ {0x0000a010, 0x00830082},
+ {0x0000a014, 0x01810180},
+ {0x0000a018, 0x01830182},
+ {0x0000a01c, 0x01850184},
+ {0x0000a020, 0x01890188},
+ {0x0000a024, 0x018b018a},
+ {0x0000a028, 0x018d018c},
+ {0x0000a02c, 0x01910190},
+ {0x0000a030, 0x01930192},
+ {0x0000a034, 0x01950194},
+ {0x0000a038, 0x038a0196},
+ {0x0000a03c, 0x038c038b},
+ {0x0000a040, 0x0390038d},
+ {0x0000a044, 0x03920391},
+ {0x0000a048, 0x03940393},
+ {0x0000a04c, 0x03960395},
+ {0x0000a050, 0x00000000},
+ {0x0000a054, 0x00000000},
+ {0x0000a058, 0x00000000},
+ {0x0000a05c, 0x00000000},
+ {0x0000a060, 0x00000000},
+ {0x0000a064, 0x00000000},
+ {0x0000a068, 0x00000000},
+ {0x0000a06c, 0x00000000},
+ {0x0000a070, 0x00000000},
+ {0x0000a074, 0x00000000},
+ {0x0000a078, 0x00000000},
+ {0x0000a07c, 0x00000000},
+ {0x0000a080, 0x22222222},
+ {0x0000a084, 0x1d1d1d1d},
+ {0x0000a088, 0x1d1d1d1d},
+ {0x0000a08c, 0x1d1d1d1d},
+ {0x0000a090, 0x17171717},
+ {0x0000a094, 0x11111717},
+ {0x0000a098, 0x00030311},
+ {0x0000a09c, 0x00000000},
+ {0x0000a0a0, 0x00000000},
+ {0x0000a0a4, 0x00000000},
+ {0x0000a0a8, 0x00000000},
+ {0x0000a0ac, 0x00000000},
+ {0x0000a0b0, 0x00000000},
+ {0x0000a0b4, 0x00000000},
+ {0x0000a0b8, 0x00000000},
+ {0x0000a0bc, 0x00000000},
+ {0x0000a0c0, 0x001f0000},
+ {0x0000a0c4, 0x01000101},
+ {0x0000a0c8, 0x011e011f},
+ {0x0000a0cc, 0x011c011d},
+ {0x0000a0d0, 0x02030204},
+ {0x0000a0d4, 0x02010202},
+ {0x0000a0d8, 0x021f0200},
+ {0x0000a0dc, 0x0302021e},
+ {0x0000a0e0, 0x03000301},
+ {0x0000a0e4, 0x031e031f},
+ {0x0000a0e8, 0x0402031d},
+ {0x0000a0ec, 0x04000401},
+ {0x0000a0f0, 0x041e041f},
+ {0x0000a0f4, 0x0502041d},
+ {0x0000a0f8, 0x05000501},
+ {0x0000a0fc, 0x051e051f},
+ {0x0000a100, 0x06010602},
+ {0x0000a104, 0x061f0600},
+ {0x0000a108, 0x061d061e},
+ {0x0000a10c, 0x07020703},
+ {0x0000a110, 0x07000701},
+ {0x0000a114, 0x00000000},
+ {0x0000a118, 0x00000000},
+ {0x0000a11c, 0x00000000},
+ {0x0000a120, 0x00000000},
+ {0x0000a124, 0x00000000},
+ {0x0000a128, 0x00000000},
+ {0x0000a12c, 0x00000000},
+ {0x0000a130, 0x00000000},
+ {0x0000a134, 0x00000000},
+ {0x0000a138, 0x00000000},
+ {0x0000a13c, 0x00000000},
+ {0x0000a140, 0x001f0000},
+ {0x0000a144, 0x01000101},
+ {0x0000a148, 0x011e011f},
+ {0x0000a14c, 0x011c011d},
+ {0x0000a150, 0x02030204},
+ {0x0000a154, 0x02010202},
+ {0x0000a158, 0x021f0200},
+ {0x0000a15c, 0x0302021e},
+ {0x0000a160, 0x03000301},
+ {0x0000a164, 0x031e031f},
+ {0x0000a168, 0x0402031d},
+ {0x0000a16c, 0x04000401},
+ {0x0000a170, 0x041e041f},
+ {0x0000a174, 0x0502041d},
+ {0x0000a178, 0x05000501},
+ {0x0000a17c, 0x051e051f},
+ {0x0000a180, 0x06010602},
+ {0x0000a184, 0x061f0600},
+ {0x0000a188, 0x061d061e},
+ {0x0000a18c, 0x07020703},
+ {0x0000a190, 0x07000701},
+ {0x0000a194, 0x00000000},
+ {0x0000a198, 0x00000000},
+ {0x0000a19c, 0x00000000},
+ {0x0000a1a0, 0x00000000},
+ {0x0000a1a4, 0x00000000},
+ {0x0000a1a8, 0x00000000},
+ {0x0000a1ac, 0x00000000},
+ {0x0000a1b0, 0x00000000},
+ {0x0000a1b4, 0x00000000},
+ {0x0000a1b8, 0x00000000},
+ {0x0000a1bc, 0x00000000},
+ {0x0000a1c0, 0x00000000},
+ {0x0000a1c4, 0x00000000},
+ {0x0000a1c8, 0x00000000},
+ {0x0000a1cc, 0x00000000},
+ {0x0000a1d0, 0x00000000},
+ {0x0000a1d4, 0x00000000},
+ {0x0000a1d8, 0x00000000},
+ {0x0000a1dc, 0x00000000},
+ {0x0000a1e0, 0x00000000},
+ {0x0000a1e4, 0x00000000},
+ {0x0000a1e8, 0x00000000},
+ {0x0000a1ec, 0x00000000},
+ {0x0000a1f0, 0x00000396},
+ {0x0000a1f4, 0x00000396},
+ {0x0000a1f8, 0x00000396},
+ {0x0000a1fc, 0x00000196},
+ {0x0000b000, 0x00010000},
+ {0x0000b004, 0x00030002},
+ {0x0000b008, 0x00050004},
+ {0x0000b00c, 0x00810080},
+ {0x0000b010, 0x00830082},
+ {0x0000b014, 0x01810180},
+ {0x0000b018, 0x01830182},
+ {0x0000b01c, 0x01850184},
+ {0x0000b020, 0x02810280},
+ {0x0000b024, 0x02830282},
+ {0x0000b028, 0x02850284},
+ {0x0000b02c, 0x02890288},
+ {0x0000b030, 0x028b028a},
+ {0x0000b034, 0x0388028c},
+ {0x0000b038, 0x038a0389},
+ {0x0000b03c, 0x038c038b},
+ {0x0000b040, 0x0390038d},
+ {0x0000b044, 0x03920391},
+ {0x0000b048, 0x03940393},
+ {0x0000b04c, 0x03960395},
+ {0x0000b050, 0x00000000},
+ {0x0000b054, 0x00000000},
+ {0x0000b058, 0x00000000},
+ {0x0000b05c, 0x00000000},
+ {0x0000b060, 0x00000000},
+ {0x0000b064, 0x00000000},
+ {0x0000b068, 0x00000000},
+ {0x0000b06c, 0x00000000},
+ {0x0000b070, 0x00000000},
+ {0x0000b074, 0x00000000},
+ {0x0000b078, 0x00000000},
+ {0x0000b07c, 0x00000000},
+ {0x0000b080, 0x23232323},
+ {0x0000b084, 0x21232323},
+ {0x0000b088, 0x19191c1e},
+ {0x0000b08c, 0x12141417},
+ {0x0000b090, 0x07070e0e},
+ {0x0000b094, 0x03030305},
+ {0x0000b098, 0x00000003},
+ {0x0000b09c, 0x00000000},
+ {0x0000b0a0, 0x00000000},
+ {0x0000b0a4, 0x00000000},
+ {0x0000b0a8, 0x00000000},
+ {0x0000b0ac, 0x00000000},
+ {0x0000b0b0, 0x00000000},
+ {0x0000b0b4, 0x00000000},
+ {0x0000b0b8, 0x00000000},
+ {0x0000b0bc, 0x00000000},
+ {0x0000b0c0, 0x003f0020},
+ {0x0000b0c4, 0x00400041},
+ {0x0000b0c8, 0x0140005f},
+ {0x0000b0cc, 0x0160015f},
+ {0x0000b0d0, 0x017e017f},
+ {0x0000b0d4, 0x02410242},
+ {0x0000b0d8, 0x025f0240},
+ {0x0000b0dc, 0x027f0260},
+ {0x0000b0e0, 0x0341027e},
+ {0x0000b0e4, 0x035f0340},
+ {0x0000b0e8, 0x037f0360},
+ {0x0000b0ec, 0x04400441},
+ {0x0000b0f0, 0x0460045f},
+ {0x0000b0f4, 0x0541047f},
+ {0x0000b0f8, 0x055f0540},
+ {0x0000b0fc, 0x057f0560},
+ {0x0000b100, 0x06400641},
+ {0x0000b104, 0x0660065f},
+ {0x0000b108, 0x067e067f},
+ {0x0000b10c, 0x07410742},
+ {0x0000b110, 0x075f0740},
+ {0x0000b114, 0x077f0760},
+ {0x0000b118, 0x07800781},
+ {0x0000b11c, 0x07a0079f},
+ {0x0000b120, 0x07c107bf},
+ {0x0000b124, 0x000007c0},
+ {0x0000b128, 0x00000000},
+ {0x0000b12c, 0x00000000},
+ {0x0000b130, 0x00000000},
+ {0x0000b134, 0x00000000},
+ {0x0000b138, 0x00000000},
+ {0x0000b13c, 0x00000000},
+ {0x0000b140, 0x003f0020},
+ {0x0000b144, 0x00400041},
+ {0x0000b148, 0x0140005f},
+ {0x0000b14c, 0x0160015f},
+ {0x0000b150, 0x017e017f},
+ {0x0000b154, 0x02410242},
+ {0x0000b158, 0x025f0240},
+ {0x0000b15c, 0x027f0260},
+ {0x0000b160, 0x0341027e},
+ {0x0000b164, 0x035f0340},
+ {0x0000b168, 0x037f0360},
+ {0x0000b16c, 0x04400441},
+ {0x0000b170, 0x0460045f},
+ {0x0000b174, 0x0541047f},
+ {0x0000b178, 0x055f0540},
+ {0x0000b17c, 0x057f0560},
+ {0x0000b180, 0x06400641},
+ {0x0000b184, 0x0660065f},
+ {0x0000b188, 0x067e067f},
+ {0x0000b18c, 0x07410742},
+ {0x0000b190, 0x075f0740},
+ {0x0000b194, 0x077f0760},
+ {0x0000b198, 0x07800781},
+ {0x0000b19c, 0x07a0079f},
+ {0x0000b1a0, 0x07c107bf},
+ {0x0000b1a4, 0x000007c0},
+ {0x0000b1a8, 0x00000000},
+ {0x0000b1ac, 0x00000000},
+ {0x0000b1b0, 0x00000000},
+ {0x0000b1b4, 0x00000000},
+ {0x0000b1b8, 0x00000000},
+ {0x0000b1bc, 0x00000000},
+ {0x0000b1c0, 0x00000000},
+ {0x0000b1c4, 0x00000000},
+ {0x0000b1c8, 0x00000000},
+ {0x0000b1cc, 0x00000000},
+ {0x0000b1d0, 0x00000000},
+ {0x0000b1d4, 0x00000000},
+ {0x0000b1d8, 0x00000000},
+ {0x0000b1dc, 0x00000000},
+ {0x0000b1e0, 0x00000000},
+ {0x0000b1e4, 0x00000000},
+ {0x0000b1e8, 0x00000000},
+ {0x0000b1ec, 0x00000000},
+ {0x0000b1f0, 0x00000396},
+ {0x0000b1f4, 0x00000396},
+ {0x0000b1f8, 0x00000396},
+ {0x0000b1fc, 0x00000196},
+};
+
+static const u32 qca956x_1p0_xlna_only[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae},
+ {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac621f1, 0x5ac621f1},
+ {0x00009828, 0x06903081, 0x06903081, 0x07d43881, 0x07d43881},
+ {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x03721720},
+ {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000de, 0x6c4000da},
+ {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec86d2e, 0x7ec8ad2e},
+ {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x317a6062, 0x317a5ae2},
+ {0x00009e18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000},
+ {0x00009e20, 0x000003b5, 0x000003b5, 0x000003b2, 0x000003b2},
+ {0x00009fc0, 0x813e4788, 0x813e4788, 0x813e4789, 0x813e4789},
+ {0x0000ae18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000},
+ {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001b2, 0x000001b2},
+ {0x0000be18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000},
+ {0x0000be20, 0x000001b5, 0x000001b5, 0x000001b2, 0x000001b2},
+};
+
+#endif /* INITVALS_956X_H */
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 1a9fe0983a6b..0f8e9464e4ab 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -34,7 +34,7 @@ struct ath_vif;
extern struct ieee80211_ops ath9k_ops;
extern int ath9k_modparam_nohwcrypt;
-extern int led_blink;
+extern int ath9k_led_blink;
extern bool is_ath9k_unloaded;
extern int ath9k_use_chanctx;
@@ -830,14 +830,9 @@ static inline void ath_fill_led_pin(struct ath_softc *sc)
/* Wake on Wireless LAN */
/************************/
-struct ath9k_wow_pattern {
- u8 pattern_bytes[MAX_PATTERN_SIZE];
- u8 mask_bytes[MAX_PATTERN_SIZE];
- u32 pattern_len;
-};
-
#ifdef CONFIG_ATH9K_WOW
void ath9k_init_wow(struct ieee80211_hw *hw);
+void ath9k_deinit_wow(struct ieee80211_hw *hw);
int ath9k_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan);
int ath9k_resume(struct ieee80211_hw *hw);
@@ -846,6 +841,9 @@ void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled);
static inline void ath9k_init_wow(struct ieee80211_hw *hw)
{
}
+static inline void ath9k_deinit_wow(struct ieee80211_hw *hw)
+{
+}
static inline int ath9k_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan)
{
@@ -1039,9 +1037,8 @@ struct ath_softc {
s16 tx99_power;
#ifdef CONFIG_ATH9K_WOW
- atomic_t wow_got_bmiss_intr;
- atomic_t wow_sleep_proc_intr; /* in the middle of WoW sleep ? */
u32 wow_intr_before_sleep;
+ bool force_wow;
#endif
};
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index ec93ddf0863a..5cee231cca1f 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -582,7 +582,7 @@ static struct rchan_callbacks rfs_spec_scan_cb = {
void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv)
{
- if (config_enabled(CONFIG_ATH9K_DEBUGFS) && spec_priv->rfs_chan_spec_scan) {
+ if (config_enabled(CONFIG_ATH9K_DEBUGFS)) {
relay_close(spec_priv->rfs_chan_spec_scan);
spec_priv->rfs_chan_spec_scan = NULL;
}
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index c43e2ad36587..50a2e0ac3b8b 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -403,7 +403,8 @@ static const struct file_operations fops_antenna_diversity = {
static int read_file_dma(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
int i, qcuOffset = 0, dcuOffset = 0;
@@ -470,20 +471,6 @@ static int read_file_dma(struct seq_file *file, void *data)
return 0;
}
-static int open_file_dma(struct inode *inode, struct file *f)
-{
- return single_open(f, read_file_dma, inode->i_private);
-}
-
-static const struct file_operations fops_dma = {
- .open = open_file_dma,
- .read = seq_read,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
{
if (status)
@@ -539,7 +526,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
static int read_file_interrupt(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
#define PR_IS(a, s) \
do { \
@@ -600,22 +588,10 @@ static int read_file_interrupt(struct seq_file *file, void *data)
return 0;
}
-static int open_file_interrupt(struct inode *inode, struct file *f)
-{
- return single_open(f, read_file_interrupt, inode->i_private);
-}
-
-static const struct file_operations fops_interrupt = {
- .read = seq_read,
- .open = open_file_interrupt,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
static int read_file_xmit(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
seq_printf(file, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO");
@@ -661,7 +637,8 @@ static void print_queue(struct ath_softc *sc, struct ath_txq *txq,
static int read_file_queues(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
struct ath_txq *txq;
int i;
static const char *qname[4] = {
@@ -682,7 +659,8 @@ static int read_file_queues(struct seq_file *file, void *data)
static int read_file_misc(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_vif_iter_data iter_data;
struct ath_chanctx *ctx;
@@ -773,7 +751,8 @@ static int read_file_misc(struct seq_file *file, void *data)
static int read_file_reset(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
static const char * const reset_cause[__RESET_TYPE_MAX] = {
[RESET_TYPE_BB_HANG] = "Baseband Hang",
[RESET_TYPE_BB_WATCHDOG] = "Baseband Watchdog",
@@ -837,58 +816,6 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
TX_STAT_INC(qnum, delim_underrun);
}
-static int open_file_xmit(struct inode *inode, struct file *f)
-{
- return single_open(f, read_file_xmit, inode->i_private);
-}
-
-static const struct file_operations fops_xmit = {
- .read = seq_read,
- .open = open_file_xmit,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int open_file_queues(struct inode *inode, struct file *f)
-{
- return single_open(f, read_file_queues, inode->i_private);
-}
-
-static const struct file_operations fops_queues = {
- .read = seq_read,
- .open = open_file_queues,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int open_file_misc(struct inode *inode, struct file *f)
-{
- return single_open(f, read_file_misc, inode->i_private);
-}
-
-static const struct file_operations fops_misc = {
- .read = seq_read,
- .open = open_file_misc,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int open_file_reset(struct inode *inode, struct file *f)
-{
- return single_open(f, read_file_reset, inode->i_private);
-}
-
-static const struct file_operations fops_reset = {
- .read = seq_read,
- .open = open_file_reset,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
{
ath9k_cmn_debug_stat_rx(&sc->debug.stats.rxstats, rs);
@@ -1018,7 +945,8 @@ static const struct file_operations fops_regdump = {
static int read_file_dump_nfcal(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath9k_nfcal_hist *h = sc->cur_chan->caldata.nfCalHist;
struct ath_common *common = ath9k_hw_common(ah);
@@ -1115,6 +1043,69 @@ static const struct file_operations fops_ackto = {
};
#endif
+#ifdef CONFIG_ATH9K_WOW
+
+static ssize_t read_file_wow(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ unsigned int len = 0, size = 32;
+ ssize_t retval;
+ char *buf;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len += scnprintf(buf + len, size - len, "WOW: %s\n",
+ sc->force_wow ? "ENABLED" : "DISABLED");
+
+ if (len > size)
+ len = size;
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+}
+
+static ssize_t write_file_wow(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ unsigned long val;
+ char buf[32];
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val != 1)
+ return -EINVAL;
+
+ if (!sc->force_wow) {
+ sc->force_wow = true;
+ ath9k_init_wow(sc->hw);
+ }
+
+ return count;
+}
+
+static const struct file_operations fops_wow = {
+ .read = read_file_wow,
+ .write = write_file_wow,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+#endif
+
static ssize_t read_file_tpc(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -1150,11 +1141,6 @@ static ssize_t write_file_tpc(struct file *file, const char __user *user_buf,
ssize_t len;
bool tpc_enabled;
- if (!AR_SREV_9300_20_OR_LATER(ah)) {
- /* ar9002 does not support TPC for the moment */
- return -EOPNOTSUPP;
- }
-
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
@@ -1329,14 +1315,14 @@ int ath9k_init_debug(struct ath_hw *ah)
ath9k_tx99_init_debug(sc);
ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy);
- debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_dma);
- debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_interrupt);
- debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_xmit);
- debugfs_create_file("queues", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_queues);
+ debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy,
+ read_file_dma);
+ debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy,
+ read_file_interrupt);
+ debugfs_create_devm_seqfile(sc->dev, "xmit", sc->debug.debugfs_phy,
+ read_file_xmit);
+ debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy,
+ read_file_queues);
debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
&sc->tx.txq_max_pending[IEEE80211_AC_BK]);
debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
@@ -1345,10 +1331,10 @@ int ath9k_init_debug(struct ath_hw *ah)
&sc->tx.txq_max_pending[IEEE80211_AC_VI]);
debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
&sc->tx.txq_max_pending[IEEE80211_AC_VO]);
- debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_misc);
- debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_reset);
+ debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy,
+ read_file_misc);
+ debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy,
+ read_file_reset);
ath9k_cmn_debug_recv(sc->debug.debugfs_phy, &sc->debug.stats.rxstats);
ath9k_cmn_debug_phy_err(sc->debug.debugfs_phy, &sc->debug.stats.rxstats);
@@ -1370,8 +1356,9 @@ int ath9k_init_debug(struct ath_hw *ah)
&ah->config.cwm_ignore_extcca);
debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_regdump);
- debugfs_create_file("dump_nfcal", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_dump_nfcal);
+ debugfs_create_devm_seqfile(sc->dev, "dump_nfcal",
+ sc->debug.debugfs_phy,
+ read_file_dump_nfcal);
ath9k_cmn_debug_base_eeprom(sc->debug.debugfs_phy, sc->sc_ah);
ath9k_cmn_debug_modal_eeprom(sc->debug.debugfs_phy, sc->sc_ah);
@@ -1389,6 +1376,11 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_btcoex);
#endif
+#ifdef CONFIG_ATH9K_WOW
+ debugfs_create_file("wow", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, sc, &fops_wow);
+#endif
+
#ifdef CONFIG_ATH9K_DYNACK
debugfs_create_file("ack_to", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
sc, &fops_ackto);
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 07b806c56c56..e5a78d4fd66e 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -748,6 +748,20 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
| ATH9K_POW_SM(ratesArray[rateDupCck], 0));
}
+ /* TPC initializations */
+ if (ah->tpc_enabled) {
+ int ht40_delta;
+
+ ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0;
+ ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta);
+ /* Enable TPC */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX,
+ MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE);
+ } else {
+ /* Disable TPC */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER);
+ }
+
REGWRITE_BUFFER_FLUSH(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index 5ba1385c9838..6ca33dfde1fd 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -886,6 +886,21 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
| ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
| ATH9K_POW_SM(ratesArray[rateDupCck], 0));
}
+
+ /* TPC initializations */
+ if (ah->tpc_enabled) {
+ int ht40_delta;
+
+ ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0;
+ ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta);
+ /* Enable TPC */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX,
+ MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE);
+ } else {
+ /* Disable TPC */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER);
+ }
+
REGWRITE_BUFFER_FLUSH(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 122b846b8ec0..098059039351 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -1332,6 +1332,20 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
| ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
+ /* TPC initializations */
+ if (ah->tpc_enabled) {
+ int ht40_delta;
+
+ ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0;
+ ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta);
+ /* Enable TPC */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX,
+ MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE);
+ } else {
+ /* Disable TPC */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER);
+ }
+
REGWRITE_BUFFER_FLUSH(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index 2fef7a480fec..da344b27326c 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -49,7 +49,7 @@ void ath_init_leds(struct ath_softc *sc)
if (AR_SREV_9100(sc->sc_ah))
return;
- if (!led_blink)
+ if (!ath9k_led_blink)
sc->led_cdev.default_trigger =
ieee80211_get_radio_led_name(sc->hw);
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 9dde265d3f84..300d3671d0ef 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -44,6 +44,9 @@
extern struct ieee80211_ops ath9k_htc_ops;
extern int htc_modparam_nohwcrypt;
+#ifdef CONFIG_MAC80211_LEDS
+extern int ath9k_htc_led_blink;
+#endif
enum htc_phymode {
HTC_MODE_11NA = 0,
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
index 50f74a2a4cf8..2aabcbdaba4e 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
@@ -279,6 +279,10 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv)
else
priv->ah->led_pin = ATH_LED_PIN_DEF;
+ if (!ath9k_htc_led_blink)
+ priv->led_cdev.default_trigger =
+ ieee80211_get_radio_led_name(priv->hw);
+
ath9k_configure_leds(priv);
snprintf(priv->led_name, sizeof(priv->led_name),
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index e8fa9448da24..fd229409f676 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -39,6 +39,10 @@ module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
#ifdef CONFIG_MAC80211_LEDS
+int ath9k_htc_led_blink = 1;
+module_param_named(blink, ath9k_htc_led_blink, int, 0444);
+MODULE_PARM_DESC(blink, "Enable LED blink on activity");
+
static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
{ .throughput = 0 * 1024, .blink_time = 334 },
{ .throughput = 1 * 1024, .blink_time = 260 },
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index a0ff5b637054..d2408da38c1c 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -351,11 +351,7 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
return;
ret:
- /* HTC-generated packets are freed here. */
- if (htc_hdr && htc_hdr->endpoint_id != ENDPOINT0)
- dev_kfree_skb_any(skb);
- else
- kfree_skb(skb);
+ kfree_skb(skb);
}
static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle,
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 258c4d236cbe..60aa8d71e753 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -246,6 +246,8 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
case AR9300_DEVID_AR953X:
ah->hw_version.macVersion = AR_SREV_VERSION_9531;
return;
+ case AR9300_DEVID_QCA956X:
+ ah->hw_version.macVersion = AR_SREV_VERSION_9561;
}
val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
@@ -422,8 +424,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
ah->power_mode = ATH9K_PM_UNDEFINED;
ah->htc_reset_init = true;
- /* ar9002 does not support TPC for the moment */
- ah->tpc_enabled = !!AR_SREV_9300_20_OR_LATER(ah);
+ ah->tpc_enabled = true;
ah->ani_function = ATH9K_ANI_ALL;
if (!AR_SREV_9300_20_OR_LATER(ah))
@@ -539,6 +540,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
case AR_SREV_VERSION_9550:
case AR_SREV_VERSION_9565:
case AR_SREV_VERSION_9531:
+ case AR_SREV_VERSION_9561:
break;
default:
ath_err(common,
@@ -639,6 +641,7 @@ int ath9k_hw_init(struct ath_hw *ah)
case AR9485_DEVID_AR1111:
case AR9300_DEVID_AR9565:
case AR9300_DEVID_AR953X:
+ case AR9300_DEVID_QCA956X:
break;
default:
if (common->bus_ops->ath_bus_type == ATH_USB)
@@ -779,7 +782,8 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
/* program BB PLL phase_shift */
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x1);
- } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+ } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah)) {
u32 regval, pll2_divint, pll2_divfrac, refdiv;
REG_WRITE(ah, AR_RTC_PLL_CONTROL,
@@ -790,7 +794,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
udelay(100);
if (ah->is_clk_25mhz) {
- if (AR_SREV_9531(ah)) {
+ if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) {
pll2_divint = 0x1c;
pll2_divfrac = 0xa3d2;
refdiv = 1;
@@ -806,14 +810,15 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
refdiv = 5;
} else {
pll2_divint = 0x11;
- pll2_divfrac =
- AR_SREV_9531(ah) ? 0x26665 : 0x26666;
+ pll2_divfrac = (AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah)) ?
+ 0x26665 : 0x26666;
refdiv = 1;
}
}
regval = REG_READ(ah, AR_PHY_PLL_MODE);
- if (AR_SREV_9531(ah))
+ if (AR_SREV_9531(ah) || AR_SREV_9561(ah))
regval |= (0x1 << 22);
else
regval |= (0x1 << 16);
@@ -831,14 +836,16 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
(0x1 << 13) |
(0x4 << 26) |
(0x18 << 19);
- else if (AR_SREV_9531(ah))
+ else if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) {
regval = (regval & 0x01c00fff) |
(0x1 << 31) |
(0x2 << 29) |
(0xa << 25) |
- (0x1 << 19) |
- (0x6 << 12);
- else
+ (0x1 << 19);
+
+ if (AR_SREV_9531(ah))
+ regval |= (0x6 << 12);
+ } else
regval = (regval & 0x80071fff) |
(0x3 << 30) |
(0x1 << 13) |
@@ -846,7 +853,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
(0x60 << 19);
REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
- if (AR_SREV_9531(ah))
+ if (AR_SREV_9531(ah) || AR_SREV_9561(ah))
REG_WRITE(ah, AR_PHY_PLL_MODE,
REG_READ(ah, AR_PHY_PLL_MODE) & 0xffbfffff);
else
@@ -885,7 +892,8 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
AR_IMR_RXORN |
AR_IMR_BCNMISC;
- if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah))
+ if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah))
sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
if (AR_SREV_9300_20_OR_LATER(ah)) {
@@ -1674,7 +1682,8 @@ static void ath9k_hw_init_desc(struct ath_hw *ah)
}
#ifdef __BIG_ENDIAN
else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) ||
- AR_SREV_9550(ah) || AR_SREV_9531(ah))
+ AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah))
REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0);
else
REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
@@ -2462,7 +2471,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9300_20_OR_LATER(ah)) {
pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_FASTCLOCK;
- if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah) && !AR_SREV_9565(ah))
+ if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah) &&
+ !AR_SREV_9561(ah) && !AR_SREV_9565(ah))
pCap->hw_caps |= ATH9K_HW_CAP_LDPC;
pCap->rx_hp_qdepth = ATH9K_HW_RX_HP_QDEPTH;
@@ -2479,7 +2489,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9300_20_OR_LATER(ah))
pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED;
- if (AR_SREV_9300_20_OR_LATER(ah))
+ if (AR_SREV_9561(ah))
+ ah->ent_mode = 0x3BDA000;
+ else if (AR_SREV_9300_20_OR_LATER(ah))
ah->ent_mode = REG_READ(ah, AR_ENT_OTP);
if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah))
@@ -2532,13 +2544,17 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->hw_caps |= ATH9K_HW_CAP_RTT;
}
- if (AR_SREV_9462(ah))
- pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE;
-
if (AR_SREV_9300_20_OR_LATER(ah) &&
ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
+#ifdef CONFIG_ATH9K_WOW
+ if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565_11_OR_LATER(ah))
+ ah->wow.max_patterns = MAX_NUM_PATTERN;
+ else
+ ah->wow.max_patterns = MAX_NUM_PATTERN_LEGACY;
+#endif
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 1cbd33551513..e82e570de330 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -54,6 +54,7 @@
#define AR9485_DEVID_AR1111 0x0037
#define AR9300_DEVID_AR9565 0x0036
#define AR9300_DEVID_AR953X 0x003d
+#define AR9300_DEVID_QCA956X 0x003f
#define AR5416_AR9100_DEVID 0x000b
@@ -198,12 +199,13 @@
#define KAL_NUM_DESC_WORDS 12
#define KAL_ANTENNA_MODE 1
#define KAL_TO_DS 1
-#define KAL_DELAY 4 /*delay of 4ms between 2 KAL frames */
+#define KAL_DELAY 4 /* delay of 4ms between 2 KAL frames */
#define KAL_TIMEOUT 900
#define MAX_PATTERN_SIZE 256
#define MAX_PATTERN_MASK_SIZE 32
-#define MAX_NUM_PATTERN 8
+#define MAX_NUM_PATTERN 16
+#define MAX_NUM_PATTERN_LEGACY 8
#define MAX_NUM_USER_PATTERN 6 /* deducting the disassociate and
deauthenticate packets */
@@ -247,12 +249,10 @@ enum ath9k_hw_caps {
#ifdef CONFIG_ATH9K_PCOEM
ATH9K_HW_CAP_RTT = BIT(14),
ATH9K_HW_CAP_MCI = BIT(15),
- ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(16),
ATH9K_HW_CAP_BT_ANT_DIV = BIT(17),
#else
ATH9K_HW_CAP_RTT = 0,
ATH9K_HW_CAP_MCI = 0,
- ATH9K_HW_WOW_DEVICE_CAPABLE = 0,
ATH9K_HW_CAP_BT_ANT_DIV = 0,
#endif
ATH9K_HW_CAP_DFS = BIT(18),
@@ -271,6 +271,12 @@ enum ath9k_hw_caps {
* of those types.
*/
+struct ath9k_hw_wow {
+ u32 wow_event_mask;
+ u32 wow_event_mask2;
+ u8 max_patterns;
+};
+
struct ath9k_hw_capabilities {
u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */
u16 rts_aggr_limit;
@@ -929,7 +935,7 @@ struct ath_hw {
u32 ent_mode;
#ifdef CONFIG_ATH9K_WOW
- u32 wow_event_mask;
+ struct ath9k_hw_wow wow;
#endif
bool is_clk_25mhz;
int (*get_mac_revision)(void);
@@ -1086,6 +1092,8 @@ bool ar9003_is_paprd_enabled(struct ath_hw *ah);
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array,
struct ath9k_channel *chan);
+void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array,
+ struct ath9k_channel *chan, int ht40_delta);
/* Hardware family op attach helpers */
int ar5008_hw_attach_phy_ops(struct ath_hw *ah);
@@ -1145,23 +1153,19 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah)
#ifdef CONFIG_ATH9K_WOW
-const char *ath9k_hw_wow_event_to_string(u32 wow_event);
-void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
- u8 *user_mask, int pattern_count,
- int pattern_len);
+int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
+ u8 *user_mask, int pattern_count,
+ int pattern_len);
u32 ath9k_hw_wow_wakeup(struct ath_hw *ah);
void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable);
#else
-static inline const char *ath9k_hw_wow_event_to_string(u32 wow_event)
-{
- return NULL;
-}
-static inline void ath9k_hw_wow_apply_pattern(struct ath_hw *ah,
- u8 *user_pattern,
- u8 *user_mask,
- int pattern_count,
- int pattern_len)
+static inline int ath9k_hw_wow_apply_pattern(struct ath_hw *ah,
+ u8 *user_pattern,
+ u8 *user_mask,
+ int pattern_count,
+ int pattern_len)
{
+ return 0;
}
static inline u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
{
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index d1c39346b264..6c6e88495394 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -45,8 +45,8 @@ int ath9k_modparam_nohwcrypt;
module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
-int led_blink;
-module_param_named(blink, led_blink, int, 0444);
+int ath9k_led_blink;
+module_param_named(blink, ath9k_led_blink, int, 0444);
MODULE_PARM_DESC(blink, "Enable LED blink on activity");
static int ath9k_btcoex_enable;
@@ -996,6 +996,7 @@ void ath9k_deinit_device(struct ath_softc *sc)
ath9k_ps_restore(sc);
ath9k_deinit_debug(sc);
+ ath9k_deinit_wow(hw);
ieee80211_unregister_hw(hw);
ath_rx_cleanup(sc);
ath9k_deinit_softc(sc);
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index b829263e3d0a..90631d768a60 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -516,14 +516,14 @@ int ath_update_survey_stats(struct ath_softc *sc)
ath_hw_cycle_counters_update(common);
if (cc->cycles > 0) {
- survey->filled |= SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_BUSY |
- SURVEY_INFO_CHANNEL_TIME_RX |
- SURVEY_INFO_CHANNEL_TIME_TX;
- survey->channel_time += cc->cycles / div;
- survey->channel_time_busy += cc->rx_busy / div;
- survey->channel_time_rx += cc->rx_frame / div;
- survey->channel_time_tx += cc->tx_frame / div;
+ survey->filled |= SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY |
+ SURVEY_INFO_TIME_RX |
+ SURVEY_INFO_TIME_TX;
+ survey->time += cc->cycles / div;
+ survey->time_busy += cc->rx_busy / div;
+ survey->time_rx += cc->rx_frame / div;
+ survey->time_tx += cc->tx_frame / div;
}
if (cc->cycles < div)
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 3e58bfa0c1fd..bba85d1a6cd1 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -820,7 +820,8 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
return;
}
- if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah))
+ if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah))
sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
async_mask = AR_INTR_MAC_IRQ;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 9a72640237cb..98b1e4aa1506 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -556,15 +556,6 @@ irqreturn_t ath_isr(int irq, void *dev)
(status & ATH9K_INT_BB_WATCHDOG))
goto chip_reset;
-#ifdef CONFIG_ATH9K_WOW
- if (status & ATH9K_INT_BMISS) {
- if (atomic_read(&sc->wow_sleep_proc_intr) == 0) {
- atomic_inc(&sc->wow_got_bmiss_intr);
- atomic_dec(&sc->wow_sleep_proc_intr);
- }
- }
-#endif
-
if (status & ATH9K_INT_SWBA)
tasklet_schedule(&sc->bcon_tasklet);
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index f009b5b57e5e..e6fef1be9977 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -427,6 +427,11 @@ static const struct pci_device_id ath_pci_id_table[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
0x11AD, /* LITEON */
+ 0x1842),
+ .driver_data = ATH9K_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
0x6671),
.driver_data = ATH9K_PCI_AR9565_1ANT },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
@@ -446,9 +451,19 @@ static const struct pci_device_id ath_pci_id_table[] = {
.driver_data = ATH9K_PCI_AR9565_1ANT },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ 0x1B9A, /* XAVI */
+ 0x28A3),
+ .driver_data = ATH9K_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
PCI_VENDOR_ID_AZWAVE,
0x218A),
.driver_data = ATH9K_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2F8A),
+ .driver_data = ATH9K_PCI_AR9565_1ANT },
/* WB335 1-ANT / Antenna Diversity */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
@@ -508,6 +523,11 @@ static const struct pci_device_id ath_pci_id_table[] = {
.driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x213C),
+ .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
PCI_VENDOR_ID_HP,
0x18E3),
.driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -555,6 +575,16 @@ static const struct pci_device_id ath_pci_id_table[] = {
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x4129),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x412A),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
PCI_VENDOR_ID_ATHEROS,
0x3027),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -586,10 +616,25 @@ static const struct pci_device_id ath_pci_id_table[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
0x11AD, /* LITEON */
+ 0x1832),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
0x0692),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ 0x11AD, /* LITEON */
+ 0x0803),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x0813),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
PCI_VENDOR_ID_AZWAVE,
0x2130),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -605,6 +650,21 @@ static const struct pci_device_id ath_pci_id_table[] = {
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x218B),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x218C),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2F82),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
0x144F, /* ASKEY */
0x7202),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -616,10 +676,20 @@ static const struct pci_device_id ath_pci_id_table[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
0x1B9A, /* XAVI */
+ 0x2813),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x1B9A, /* XAVI */
0x28A2),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ 0x1B9A, /* XAVI */
+ 0x28A4),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
0x185F, /* WNC */
0x3027),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -636,10 +706,25 @@ static const struct pci_device_id ath_pci_id_table[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
PCI_VENDOR_ID_FOXCONN,
+ 0xE08F),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_FOXCONN,
0xE081),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ PCI_VENDOR_ID_FOXCONN,
+ 0xE091),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_FOXCONN,
+ 0xE099),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
PCI_VENDOR_ID_LENOVO,
0x3026),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -913,9 +998,12 @@ static int ath_pci_suspend(struct device *device)
struct pci_dev *pdev = to_pci_dev(device);
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- if (sc->wow_enabled)
+ if (test_bit(ATH_OP_WOW_ENABLED, &common->op_flags)) {
+ dev_info(&pdev->dev, "WOW is enabled, bypassing PCI suspend\n");
return 0;
+ }
/* The device has to be moved to FULLSLEEP forcibly.
* Otherwise the chip never moved to full sleep,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 7395afbc5124..6fb40ef86fd6 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -425,7 +425,8 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
}
- if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah))
+ if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah) ||
+ AR_SREV_9561(sc->sc_ah))
rfilt |= ATH9K_RX_FILTER_4ADDRESS;
if (ath9k_is_chanctx_enabled() &&
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index fb11a9172f38..9587ec655680 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -814,6 +814,7 @@
#define AR_SREV_REVISION_9531_10 0
#define AR_SREV_REVISION_9531_11 1
#define AR_SREV_REVISION_9531_20 2
+#define AR_SREV_VERSION_9561 0x600
#define AR_SREV_5416(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -899,10 +900,13 @@
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
#define AR_SREV_9565(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565))
+#define AR_SREV_9003_PCOEM(_ah) \
+ (AR_SREV_9462(_ah) || AR_SREV_9485(_ah) || AR_SREV_9565(_ah))
#else
#define AR_SREV_9462(_ah) 0
#define AR_SREV_9485(_ah) 0
#define AR_SREV_9565(_ah) 0
+#define AR_SREV_9003_PCOEM(_ah) 0
#endif
#define AR_SREV_9485_11_OR_LATER(_ah) \
@@ -974,6 +978,9 @@
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_20))
+#define AR_SREV_9561(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9561))
+
/* NOTE: When adding chips newer than Peacock, add chip check here */
#define AR_SREV_9580_10_OR_LATER(_ah) \
(AR_SREV_9580(_ah))
@@ -1876,6 +1883,7 @@ enum {
#define AR_FIRST_NDP_TIMER 7
#define AR_NDP2_PERIOD 0x81a0
#define AR_NDP2_TIMER_MODE 0x81c0
+#define AR_GEN_TIMERS2_MODE_ENABLE_MASK 0x000000FF
#define AR_GEN_TIMERS(_i) (0x8200 + ((_i) << 2))
#define AR_NEXT_TBTT_TIMER AR_GEN_TIMERS(0)
@@ -1971,6 +1979,7 @@ enum {
#define AR_DIRECT_CONNECT 0x83a0
#define AR_DC_AP_STA_EN 0x00000001
+#define AR_DC_TSF2_ENABLE 0x00000001
#define AR_AES_MUTE_MASK0 0x805c
#define AR_AES_MUTE_MASK0_FC 0x0000FFFF
@@ -2003,126 +2012,6 @@ enum {
#define AR_WOW_BEACON_TIMO_MAX 0xffffffff
-/*
- * MAC WoW Registers
- */
-
-#define AR_WOW_PATTERN 0x825C
-#define AR_WOW_COUNT 0x8260
-#define AR_WOW_BCN_EN 0x8270
-#define AR_WOW_BCN_TIMO 0x8274
-#define AR_WOW_KEEP_ALIVE_TIMO 0x8278
-#define AR_WOW_KEEP_ALIVE 0x827c
-#define AR_WOW_US_SCALAR 0x8284
-#define AR_WOW_KEEP_ALIVE_DELAY 0x8288
-#define AR_WOW_PATTERN_MATCH 0x828c
-#define AR_WOW_PATTERN_OFF1 0x8290 /* pattern bytes 0 -> 3 */
-#define AR_WOW_PATTERN_OFF2 0x8294 /* pattern bytes 4 -> 7 */
-
-/* for AR9285 or later version of chips */
-#define AR_WOW_EXACT 0x829c
-#define AR_WOW_LENGTH1 0x8360
-#define AR_WOW_LENGTH2 0X8364
-/* register to enable match for less than 256 bytes packets */
-#define AR_WOW_PATTERN_MATCH_LT_256B 0x8368
-
-#define AR_SW_WOW_CONTROL 0x20018
-#define AR_SW_WOW_ENABLE 0x1
-#define AR_SWITCH_TO_REFCLK 0x2
-#define AR_RESET_CONTROL 0x4
-#define AR_RESET_VALUE_MASK 0x8
-#define AR_HW_WOW_DISABLE 0x10
-#define AR_CLR_MAC_INTERRUPT 0x20
-#define AR_CLR_KA_INTERRUPT 0x40
-
-/* AR_WOW_PATTERN register values */
-#define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 28) /* in usecs */
-#define AR_WOW_MAC_INTR_EN 0x00040000
-#define AR_WOW_MAGIC_EN 0x00010000
-#define AR_WOW_PATTERN_EN(x) (x & 0xff)
-#define AR_WOW_PAT_FOUND_SHIFT 8
-#define AR_WOW_PATTERN_FOUND(x) (x & (0xff << AR_WOW_PAT_FOUND_SHIFT))
-#define AR_WOW_PATTERN_FOUND_MASK ((0xff) << AR_WOW_PAT_FOUND_SHIFT)
-#define AR_WOW_MAGIC_PAT_FOUND 0x00020000
-#define AR_WOW_MAC_INTR 0x00080000
-#define AR_WOW_KEEP_ALIVE_FAIL 0x00100000
-#define AR_WOW_BEACON_FAIL 0x00200000
-
-#define AR_WOW_STATUS(x) (x & (AR_WOW_PATTERN_FOUND_MASK | \
- AR_WOW_MAGIC_PAT_FOUND | \
- AR_WOW_KEEP_ALIVE_FAIL | \
- AR_WOW_BEACON_FAIL))
-#define AR_WOW_CLEAR_EVENTS(x) (x & ~(AR_WOW_PATTERN_EN(0xff) | \
- AR_WOW_MAGIC_EN | \
- AR_WOW_MAC_INTR_EN | \
- AR_WOW_BEACON_FAIL | \
- AR_WOW_KEEP_ALIVE_FAIL))
-
-/* AR_WOW_COUNT register values */
-#define AR_WOW_AIFS_CNT(x) (x & 0xff)
-#define AR_WOW_SLOT_CNT(x) ((x & 0xff) << 8)
-#define AR_WOW_KEEP_ALIVE_CNT(x) ((x & 0xff) << 16)
-
-/* AR_WOW_BCN_EN register */
-#define AR_WOW_BEACON_FAIL_EN 0x00000001
-
-/* AR_WOW_BCN_TIMO rgister */
-#define AR_WOW_BEACON_TIMO 0x40000000 /* valid if BCN_EN is set */
-
-/* AR_WOW_KEEP_ALIVE_TIMO register */
-#define AR_WOW_KEEP_ALIVE_TIMO_VALUE
-#define AR_WOW_KEEP_ALIVE_NEVER 0xffffffff
-
-/* AR_WOW_KEEP_ALIVE register */
-#define AR_WOW_KEEP_ALIVE_AUTO_DIS 0x00000001
-#define AR_WOW_KEEP_ALIVE_FAIL_DIS 0x00000002
-
-/* AR_WOW_KEEP_ALIVE_DELAY register */
-#define AR_WOW_KEEP_ALIVE_DELAY_VALUE 0x000003e8 /* 1 msec */
-
-
-/*
- * keep it long for beacon workaround - ensure no false alarm
- */
-#define AR_WOW_BMISSTHRESHOLD 0x20
-
-/* AR_WOW_PATTERN_MATCH register */
-#define AR_WOW_PAT_END_OF_PKT(x) (x & 0xf)
-#define AR_WOW_PAT_OFF_MATCH(x) ((x & 0xf) << 8)
-
-/*
- * default values for Wow Configuration for backoff, aifs, slot, keep-alive
- * to be programmed into various registers.
- */
-#define AR_WOW_PAT_BACKOFF 0x00000004 /* AR_WOW_PATTERN_REG */
-#define AR_WOW_CNT_AIFS_CNT 0x00000022 /* AR_WOW_COUNT_REG */
-#define AR_WOW_CNT_SLOT_CNT 0x00000009 /* AR_WOW_COUNT_REG */
-/*
- * Keepalive count applicable for AR9280 2.0 and above.
- */
-#define AR_WOW_CNT_KA_CNT 0x00000008 /* AR_WOW_COUNT register */
-
-/* WoW - Transmit buffer for keep alive frames */
-#define AR_WOW_TRANSMIT_BUFFER 0xe000 /* E000 - EFFC */
-
-#define AR_WOW_TXBUF(i) (AR_WOW_TRANSMIT_BUFFER + ((i) << 2))
-
-#define AR_WOW_KA_DESC_WORD2 0xe000
-
-#define AR_WOW_KA_DATA_WORD0 0xe030
-
-/* WoW Transmit Buffer for patterns */
-#define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8))
-#define AR_WOW_TB_MASK(i) (0xec00 + (i << 5))
-
-/* Currently Pattern 0-7 are supported - so bit 0-7 are set */
-#define AR_WOW_PATTERN_SUPPORTED 0xff
-#define AR_WOW_LENGTH_MAX 0xff
-#define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3)
-#define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i))
-#define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3)
-#define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i))
-
#define AR9271_CORE_CLOCK 117 /* clock to 117Mhz */
#define AR9271_TARGET_BAUD_RATE 19200 /* 115200 */
diff --git a/drivers/net/wireless/ath/ath9k/reg_wow.h b/drivers/net/wireless/ath/ath9k/reg_wow.h
new file mode 100644
index 000000000000..3abfca56ca58
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/reg_wow.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015 Qualcomm Atheros Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef REG_WOW_H
+#define REG_WOW_H
+
+#define AR_WOW_PATTERN 0x825C
+#define AR_WOW_COUNT 0x8260
+#define AR_WOW_BCN_EN 0x8270
+#define AR_WOW_BCN_TIMO 0x8274
+#define AR_WOW_KEEP_ALIVE_TIMO 0x8278
+#define AR_WOW_KEEP_ALIVE 0x827c
+#define AR_WOW_KEEP_ALIVE_DELAY 0x8288
+#define AR_WOW_PATTERN_MATCH 0x828c
+
+/*
+ * AR_WOW_LENGTH1
+ * bit 31:24 pattern 0 length
+ * bit 23:16 pattern 1 length
+ * bit 15:8 pattern 2 length
+ * bit 7:0 pattern 3 length
+ *
+ * AR_WOW_LENGTH2
+ * bit 31:24 pattern 4 length
+ * bit 23:16 pattern 5 length
+ * bit 15:8 pattern 6 length
+ * bit 7:0 pattern 7 length
+ *
+ * AR_WOW_LENGTH3
+ * bit 31:24 pattern 8 length
+ * bit 23:16 pattern 9 length
+ * bit 15:8 pattern 10 length
+ * bit 7:0 pattern 11 length
+ *
+ * AR_WOW_LENGTH4
+ * bit 31:24 pattern 12 length
+ * bit 23:16 pattern 13 length
+ * bit 15:8 pattern 14 length
+ * bit 7:0 pattern 15 length
+ */
+#define AR_WOW_LENGTH1 0x8360
+#define AR_WOW_LENGTH2 0X8364
+#define AR_WOW_LENGTH3 0X8380
+#define AR_WOW_LENGTH4 0X8384
+
+#define AR_WOW_PATTERN_MATCH_LT_256B 0x8368
+#define AR_MAC_PCU_WOW4 0x8370
+
+#define AR_SW_WOW_CONTROL 0x20018
+#define AR_SW_WOW_ENABLE 0x1
+#define AR_SWITCH_TO_REFCLK 0x2
+#define AR_RESET_CONTROL 0x4
+#define AR_RESET_VALUE_MASK 0x8
+#define AR_HW_WOW_DISABLE 0x10
+#define AR_CLR_MAC_INTERRUPT 0x20
+#define AR_CLR_KA_INTERRUPT 0x40
+
+#define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 27) /* in usecs */
+#define AR_WOW_MAC_INTR_EN 0x00040000
+#define AR_WOW_MAGIC_EN 0x00010000
+#define AR_WOW_PATTERN_EN(x) (x & 0xff)
+#define AR_WOW_PAT_FOUND_SHIFT 8
+#define AR_WOW_PATTERN_FOUND(x) (x & (0xff << AR_WOW_PAT_FOUND_SHIFT))
+#define AR_WOW_PATTERN_FOUND_MASK ((0xff) << AR_WOW_PAT_FOUND_SHIFT)
+#define AR_WOW_MAGIC_PAT_FOUND 0x00020000
+#define AR_WOW_MAC_INTR 0x00080000
+#define AR_WOW_KEEP_ALIVE_FAIL 0x00100000
+#define AR_WOW_BEACON_FAIL 0x00200000
+
+#define AR_WOW_STATUS(x) (x & (AR_WOW_PATTERN_FOUND_MASK | \
+ AR_WOW_MAGIC_PAT_FOUND | \
+ AR_WOW_KEEP_ALIVE_FAIL | \
+ AR_WOW_BEACON_FAIL))
+#define AR_WOW_CLEAR_EVENTS(x) (x & ~(AR_WOW_PATTERN_EN(0xff) | \
+ AR_WOW_MAGIC_EN | \
+ AR_WOW_MAC_INTR_EN | \
+ AR_WOW_BEACON_FAIL | \
+ AR_WOW_KEEP_ALIVE_FAIL))
+
+#define AR_WOW_AIFS_CNT(x) (x & 0xff)
+#define AR_WOW_SLOT_CNT(x) ((x & 0xff) << 8)
+#define AR_WOW_KEEP_ALIVE_CNT(x) ((x & 0xff) << 16)
+
+#define AR_WOW_BEACON_FAIL_EN 0x00000001
+#define AR_WOW_BEACON_TIMO 0x40000000
+#define AR_WOW_KEEP_ALIVE_NEVER 0xffffffff
+#define AR_WOW_KEEP_ALIVE_AUTO_DIS 0x00000001
+#define AR_WOW_KEEP_ALIVE_FAIL_DIS 0x00000002
+#define AR_WOW_KEEP_ALIVE_DELAY_VALUE 0x000003e8 /* 1 msec */
+#define AR_WOW_BMISSTHRESHOLD 0x20
+#define AR_WOW_PAT_END_OF_PKT(x) (x & 0xf)
+#define AR_WOW_PAT_OFF_MATCH(x) ((x & 0xf) << 8)
+#define AR_WOW_PAT_BACKOFF 0x00000004
+#define AR_WOW_CNT_AIFS_CNT 0x00000022
+#define AR_WOW_CNT_SLOT_CNT 0x00000009
+#define AR_WOW_CNT_KA_CNT 0x00000008
+
+#define AR_WOW_TRANSMIT_BUFFER 0xe000
+#define AR_WOW_TXBUF(i) (AR_WOW_TRANSMIT_BUFFER + ((i) << 2))
+#define AR_WOW_KA_DESC_WORD2 0xe000
+#define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8))
+#define AR_WOW_TB_MASK(i) (0xec00 + (i << 5))
+#define AR_WOW_PATTERN_SUPPORTED_LEGACY 0xff
+#define AR_WOW_PATTERN_SUPPORTED 0xffff
+#define AR_WOW_LENGTH_MAX 0xff
+#define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3)
+#define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i))
+#define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3)
+#define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i))
+#define AR_WOW_LEN3_SHIFT(_i) ((0xb - ((_i) & 0xb)) << 0x3)
+#define AR_WOW_LENGTH3_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN3_SHIFT(_i))
+#define AR_WOW_LEN4_SHIFT(_i) ((0xf - ((_i) & 0xf)) << 0x3)
+#define AR_WOW_LENGTH4_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN4_SHIFT(_i))
+
+#endif /* REG_WOW_H */
diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c
index 5f30e580d942..8d0b1730a9d5 100644
--- a/drivers/net/wireless/ath/ath9k/wow.c
+++ b/drivers/net/wireless/ath/ath9k/wow.c
@@ -16,36 +16,43 @@
#include "ath9k.h"
-static const struct wiphy_wowlan_support ath9k_wowlan_support = {
+static const struct wiphy_wowlan_support ath9k_wowlan_support_legacy = {
.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
.n_patterns = MAX_NUM_USER_PATTERN,
.pattern_min_len = 1,
.pattern_max_len = MAX_PATTERN_SIZE,
};
-static void ath9k_wow_map_triggers(struct ath_softc *sc,
- struct cfg80211_wowlan *wowlan,
- u32 *wow_triggers)
+static const struct wiphy_wowlan_support ath9k_wowlan_support = {
+ .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
+ .n_patterns = MAX_NUM_PATTERN - 2,
+ .pattern_min_len = 1,
+ .pattern_max_len = MAX_PATTERN_SIZE,
+};
+
+static u8 ath9k_wow_map_triggers(struct ath_softc *sc,
+ struct cfg80211_wowlan *wowlan)
{
+ u8 wow_triggers = 0;
+
if (wowlan->disconnect)
- *wow_triggers |= AH_WOW_LINK_CHANGE |
- AH_WOW_BEACON_MISS;
+ wow_triggers |= AH_WOW_LINK_CHANGE |
+ AH_WOW_BEACON_MISS;
if (wowlan->magic_pkt)
- *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
+ wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
if (wowlan->n_patterns)
- *wow_triggers |= AH_WOW_USER_PATTERN_EN;
-
- sc->wow_enabled = *wow_triggers;
+ wow_triggers |= AH_WOW_USER_PATTERN_EN;
+ return wow_triggers;
}
-static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
+static int ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
int pattern_count = 0;
- int i, byte_cnt;
+ int ret, i, byte_cnt = 0;
u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
u8 dis_deauth_mask[MAX_PATTERN_SIZE];
@@ -80,12 +87,7 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
* | x:x:x:x:x:x -- 22 bytes
*/
- /* Create Disassociate Pattern first */
-
- byte_cnt = 0;
-
/* Fill out the mask with all FF's */
-
for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++)
dis_deauth_mask[i] = 0xff;
@@ -108,19 +110,17 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
byte_cnt += 6;
/* copy the bssid, its same as the source mac address */
-
memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
/* Create Disassociate pattern mask */
-
dis_deauth_mask[0] = 0xfe;
dis_deauth_mask[1] = 0x03;
dis_deauth_mask[2] = 0xc0;
- ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");
-
- ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
- pattern_count, byte_cnt);
+ ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
+ pattern_count, byte_cnt);
+ if (ret)
+ goto exit;
pattern_count++;
/*
@@ -129,59 +129,39 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
*/
dis_deauth_pattern[0] = 0xC0;
- ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
- pattern_count, byte_cnt);
-
+ ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
+ pattern_count, byte_cnt);
+exit:
+ return ret;
}
-static void ath9k_wow_add_pattern(struct ath_softc *sc,
- struct cfg80211_wowlan *wowlan)
+static int ath9k_wow_add_pattern(struct ath_softc *sc,
+ struct cfg80211_wowlan *wowlan)
{
struct ath_hw *ah = sc->sc_ah;
- struct ath9k_wow_pattern *wow_pattern = NULL;
struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
- int mask_len;
+ u8 wow_pattern[MAX_PATTERN_SIZE];
+ u8 wow_mask[MAX_PATTERN_SIZE];
+ int mask_len, ret = 0;
s8 i = 0;
- if (!wowlan->n_patterns)
- return;
-
- /*
- * Add the new user configured patterns
- */
for (i = 0; i < wowlan->n_patterns; i++) {
-
- wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL);
-
- if (!wow_pattern)
- return;
-
- /*
- * TODO: convert the generic user space pattern to
- * appropriate chip specific/802.11 pattern.
- */
-
- mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
- memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE);
- memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE);
- memcpy(wow_pattern->pattern_bytes, patterns[i].pattern,
- patterns[i].pattern_len);
- memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len);
- wow_pattern->pattern_len = patterns[i].pattern_len;
-
- /*
- * just need to take care of deauth and disssoc pattern,
- * make sure we don't overwrite them.
- */
-
- ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes,
- wow_pattern->mask_bytes,
- i + 2,
- wow_pattern->pattern_len);
- kfree(wow_pattern);
-
+ mask_len = DIV_ROUND_UP(patterns[i].pattern_len, 8);
+ memset(wow_pattern, 0, MAX_PATTERN_SIZE);
+ memset(wow_mask, 0, MAX_PATTERN_SIZE);
+ memcpy(wow_pattern, patterns[i].pattern, patterns[i].pattern_len);
+ memcpy(wow_mask, patterns[i].mask, mask_len);
+
+ ret = ath9k_hw_wow_apply_pattern(ah,
+ wow_pattern,
+ wow_mask,
+ i + 2,
+ patterns[i].pattern_len);
+ if (ret)
+ break;
}
+ return ret;
}
int ath9k_suspend(struct ieee80211_hw *hw,
@@ -190,41 +170,39 @@ int ath9k_suspend(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- u32 wow_triggers_enabled = 0;
+ u8 triggers;
int ret = 0;
ath9k_deinit_channel_context(sc);
mutex_lock(&sc->mutex);
- ath_cancel_work(sc);
- ath_stop_ani(sc);
-
if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
- ath_dbg(common, ANY, "Device not present\n");
- ret = -EINVAL;
+ ath_err(common, "Device not present\n");
+ ret = -ENODEV;
goto fail_wow;
}
if (WARN_ON(!wowlan)) {
- ath_dbg(common, WOW, "None of the WoW triggers enabled\n");
+ ath_err(common, "None of the WoW triggers enabled\n");
ret = -EINVAL;
goto fail_wow;
}
- if (!device_can_wakeup(sc->dev)) {
- ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n");
+ if (sc->cur_chan->nvifs > 1) {
+ ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
ret = 1;
goto fail_wow;
}
- /*
- * none of the sta vifs are associated
- * and we are not currently handling multivif
- * cases, for instance we have to seperately
- * configure 'keep alive frame' for each
- * STA.
- */
+ if (ath9k_is_chanctx_enabled()) {
+ if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) {
+ ath_dbg(common, WOW,
+ "Multi-channel WOW is not supported\n");
+ ret = 1;
+ goto fail_wow;
+ }
+ }
if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {
ath_dbg(common, WOW, "None of the STA vifs are associated\n");
@@ -232,16 +210,15 @@ int ath9k_suspend(struct ieee80211_hw *hw,
goto fail_wow;
}
- if (sc->cur_chan->nvifs > 1) {
- ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
+ triggers = ath9k_wow_map_triggers(sc, wowlan);
+ if (!triggers) {
+ ath_dbg(common, WOW, "No valid WoW triggers\n");
ret = 1;
goto fail_wow;
}
- ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled);
-
- ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n",
- wow_triggers_enabled);
+ ath_cancel_work(sc);
+ ath_stop_ani(sc);
ath9k_ps_wakeup(sc);
@@ -251,10 +228,21 @@ int ath9k_suspend(struct ieee80211_hw *hw,
* Enable wake up on recieving disassoc/deauth
* frame by default.
*/
- ath9k_wow_add_disassoc_deauth_pattern(sc);
+ ret = ath9k_wow_add_disassoc_deauth_pattern(sc);
+ if (ret) {
+ ath_err(common,
+ "Unable to add disassoc/deauth pattern: %d\n", ret);
+ goto fail_wow;
+ }
- if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN)
- ath9k_wow_add_pattern(sc, wowlan);
+ if (triggers & AH_WOW_USER_PATTERN_EN) {
+ ret = ath9k_wow_add_pattern(sc, wowlan);
+ if (ret) {
+ ath_err(common,
+ "Unable to add user pattern: %d\n", ret);
+ goto fail_wow;
+ }
+ }
spin_lock_bh(&sc->sc_pcu_lock);
/*
@@ -278,12 +266,12 @@ int ath9k_suspend(struct ieee80211_hw *hw,
synchronize_irq(sc->irq);
tasklet_kill(&sc->intr_tq);
- ath9k_hw_wow_enable(ah, wow_triggers_enabled);
+ ath9k_hw_wow_enable(ah, triggers);
ath9k_ps_restore(sc);
- ath_dbg(common, ANY, "WoW enabled in ath9k\n");
- atomic_inc(&sc->wow_sleep_proc_intr);
+ ath_dbg(common, WOW, "Suspend with WoW triggers: 0x%x\n", triggers);
+ set_bit(ATH_OP_WOW_ENABLED, &common->op_flags);
fail_wow:
mutex_unlock(&sc->mutex);
return ret;
@@ -294,7 +282,7 @@ int ath9k_resume(struct ieee80211_hw *hw)
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- u32 wow_status;
+ u8 status;
mutex_lock(&sc->mutex);
@@ -309,29 +297,14 @@ int ath9k_resume(struct ieee80211_hw *hw)
spin_unlock_bh(&sc->sc_pcu_lock);
- wow_status = ath9k_hw_wow_wakeup(ah);
-
- if (atomic_read(&sc->wow_got_bmiss_intr) == 0) {
- /*
- * some devices may not pick beacon miss
- * as the reason they woke up so we add
- * that here for that shortcoming.
- */
- wow_status |= AH_WOW_BEACON_MISS;
- atomic_dec(&sc->wow_got_bmiss_intr);
- ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n");
- }
-
- atomic_dec(&sc->wow_sleep_proc_intr);
-
- if (wow_status) {
- ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n",
- ath9k_hw_wow_event_to_string(wow_status), wow_status);
- }
+ status = ath9k_hw_wow_wakeup(ah);
+ ath_dbg(common, WOW, "Resume with WoW status: 0x%x\n", status);
ath_restart_work(sc);
ath9k_start_btcoex(sc);
+ clear_bit(ATH_OP_WOW_ENABLED, &common->op_flags);
+
ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex);
@@ -341,22 +314,35 @@ int ath9k_resume(struct ieee80211_hw *hw)
void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
mutex_lock(&sc->mutex);
- device_init_wakeup(sc->dev, 1);
device_set_wakeup_enable(sc->dev, enabled);
mutex_unlock(&sc->mutex);
+
+ ath_dbg(common, WOW, "WoW wakeup source is %s\n",
+ (enabled) ? "enabled" : "disabled");
}
void ath9k_init_wow(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
+ struct ath_hw *ah = sc->sc_ah;
+
+ if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) {
+ if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565_11_OR_LATER(ah))
+ hw->wiphy->wowlan = &ath9k_wowlan_support;
+ else
+ hw->wiphy->wowlan = &ath9k_wowlan_support_legacy;
- if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) &&
- (sc->driver_data & ATH9K_PCI_WOW) &&
- device_can_wakeup(sc->dev))
- hw->wiphy->wowlan = &ath9k_wowlan_support;
+ device_init_wakeup(sc->dev, 1);
+ }
+}
+
+void ath9k_deinit_wow(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
- atomic_set(&sc->wow_sleep_proc_intr, -1);
- atomic_set(&sc->wow_got_bmiss_intr, -1);
+ if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow)
+ device_init_wakeup(sc->dev, 0);
}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 52d63de4a93d..1b8e75c4d2c2 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1097,24 +1097,65 @@ void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop)
}
static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf,
- u8 rateidx)
+ u8 rateidx, bool is_40, bool is_cck)
{
u8 max_power;
+ struct sk_buff *skb;
+ struct ath_frame_info *fi;
+ struct ieee80211_tx_info *info;
struct ath_hw *ah = sc->sc_ah;
- if (sc->tx99_state)
+ if (sc->tx99_state || !ah->tpc_enabled)
return MAX_RATE_POWER;
+ skb = bf->bf_mpdu;
+ fi = get_frame_info(skb);
+ info = IEEE80211_SKB_CB(skb);
+
if (!AR_SREV_9300_20_OR_LATER(ah)) {
- /* ar9002 does not support TPC for the moment */
- return MAX_RATE_POWER;
- }
+ int txpower = fi->tx_power;
- if (!bf->bf_state.bfs_paprd) {
- struct sk_buff *skb = bf->bf_mpdu;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ath_frame_info *fi = get_frame_info(skb);
+ if (is_40) {
+ u8 power_ht40delta;
+ struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+
+ if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) {
+ bool is_2ghz;
+ struct modal_eep_header *pmodal;
+ is_2ghz = info->band == IEEE80211_BAND_2GHZ;
+ pmodal = &eep->modalHeader[is_2ghz];
+ power_ht40delta = pmodal->ht40PowerIncForPdadc;
+ } else {
+ power_ht40delta = 2;
+ }
+ txpower += power_ht40delta;
+ }
+
+ if (AR_SREV_9287(ah) || AR_SREV_9285(ah) ||
+ AR_SREV_9271(ah)) {
+ txpower -= 2 * AR9287_PWR_TABLE_OFFSET_DB;
+ } else if (AR_SREV_9280_20_OR_LATER(ah)) {
+ s8 power_offset;
+
+ power_offset = ah->eep_ops->get_eeprom(ah,
+ EEP_PWR_TABLE_OFFSET);
+ txpower -= 2 * power_offset;
+ }
+
+ if (OLC_FOR_AR9280_20_LATER && is_cck)
+ txpower -= 2;
+
+ txpower = max(txpower, 0);
+ max_power = min_t(u8, ah->tx_power[rateidx], txpower);
+
+ /* XXX: clamp minimum TX power at 1 for AR9160 since if
+ * max_power is set to 0, frames are transmitted at max
+ * TX power
+ */
+ if (!max_power && !AR_SREV_9280_20_OR_LATER(ah))
+ max_power = 1;
+ } else if (!bf->bf_state.bfs_paprd) {
if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC))
max_power = min(ah->tx_power_stbc[rateidx],
fi->tx_power);
@@ -1152,7 +1193,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
info->rtscts_rate = fi->rtscts_rate;
for (i = 0; i < ARRAY_SIZE(bf->rates); i++) {
- bool is_40, is_sgi, is_sp;
+ bool is_40, is_sgi, is_sp, is_cck;
int phy;
if (!rates[i].count || (rates[i].idx < 0))
@@ -1198,7 +1239,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC;
- info->txpower[i] = ath_get_rate_txpower(sc, bf, rix);
+ info->txpower[i] = ath_get_rate_txpower(sc, bf, rix,
+ is_40, false);
continue;
}
@@ -1227,7 +1269,9 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
phy, rate->bitrate * 100, len, rix, is_sp);
- info->txpower[i] = ath_get_rate_txpower(sc, bf, rix);
+ is_cck = IS_CCK_RATE(info->rates[i].Rate);
+ info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, false,
+ is_cck);
}
/* For AR5416 - RTS cannot be followed by a frame larger than 8K */
@@ -2259,7 +2303,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_txq *txq = txctl->txq;
struct ath_atx_tid *tid = NULL;
struct ath_buf *bf;
- bool queue, skip_uapsd = false;
+ bool queue, skip_uapsd = false, ps_resp;
int q, ret;
if (vif)
@@ -2268,6 +2312,8 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
txctl->force_channel = true;
+ ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
+
ret = ath_tx_prepare(hw, skb, txctl);
if (ret)
return ret;
@@ -2310,7 +2356,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
if (txctl->an && queue)
tid = ath_get_skb_tid(sc, txctl->an, skb);
- if (!skip_uapsd && (info->flags & IEEE80211_TX_CTL_PS_RESPONSE)) {
+ if (!skip_uapsd && ps_resp) {
ath_txq_unlock(sc, txq);
txq = sc->tx.uapsdq;
ath_txq_lock(sc, txq);
@@ -2443,9 +2489,12 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
if (sc->sc_ah->caldata)
set_bit(PAPRD_PACKET_SENT, &sc->sc_ah->caldata->cal_flags);
- if (!(tx_flags & ATH_TX_ERROR))
- /* Frame was ACKed */
- tx_info->flags |= IEEE80211_TX_STAT_ACK;
+ if (!(tx_flags & ATH_TX_ERROR)) {
+ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
+ tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+ else
+ tx_info->flags |= IEEE80211_TX_STAT_ACK;
+ }
padpos = ieee80211_hdrlen(hdr->frame_control);
padsize = padpos & 3;
diff --git a/drivers/net/wireless/ath/carl9170/cmd.c b/drivers/net/wireless/ath/carl9170/cmd.c
index 39a63874b275..f2b4f537e4c1 100644
--- a/drivers/net/wireless/ath/carl9170/cmd.c
+++ b/drivers/net/wireless/ath/carl9170/cmd.c
@@ -188,12 +188,12 @@ int carl9170_collect_tally(struct ar9170 *ar)
if (ar->channel) {
info = &ar->survey[ar->channel->hw_value];
- info->channel_time = ar->tally.active;
- info->channel_time_busy = ar->tally.cca;
- info->channel_time_tx = ar->tally.tx_time;
- do_div(info->channel_time, 1000);
- do_div(info->channel_time_busy, 1000);
- do_div(info->channel_time_tx, 1000);
+ info->time = ar->tally.active;
+ info->time_busy = ar->tally.cca;
+ info->time_tx = ar->tally.tx_time;
+ do_div(info->time, 1000);
+ do_div(info->time_busy, 1000);
+ do_div(info->time_tx, 1000);
}
}
return 0;
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index ef5b6dc7b7f1..f1455a04cb62 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1690,9 +1690,9 @@ found:
survey->filled |= SURVEY_INFO_IN_USE;
if (ar->fw.hw_counters) {
- survey->filled |= SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_BUSY |
- SURVEY_INFO_CHANNEL_TIME_TX;
+ survey->filled |= SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY |
+ SURVEY_INFO_TIME_TX;
}
return 0;
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index 73f12f196f14..086549b732b9 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -84,6 +84,7 @@ static int wcn36xx_dxe_allocate_ctl_block(struct wcn36xx_dxe_ch *ch)
if (!cur_ctl)
goto out_fail;
+ spin_lock_init(&cur_ctl->skb_lock);
cur_ctl->ctl_blk_order = i;
if (i == 0) {
ch->head_blk_ctl = cur_ctl;
@@ -354,6 +355,8 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
* and while-do will not make any cycles.
*/
do {
+ if (ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)
+ break;
if (ctl->skb) {
dma_unmap_single(NULL, ctl->desc->src_addr_l,
ctl->skb->len, DMA_TO_DEVICE);
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 7dd8873f757e..0783d2ed8238 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -298,6 +298,8 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
wcn36xx_debugfs_init(wcn);
INIT_LIST_HEAD(&wcn->vif_list);
+ spin_lock_init(&wcn->dxe_lock);
+
return 0;
out_smd_stop:
@@ -795,6 +797,7 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n",
vif, sta->addr);
+ spin_lock_init(&sta_priv->ampdu_lock);
vif_priv->sta = sta_priv;
sta_priv->vif = vif_priv;
/*
@@ -873,21 +876,32 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
get_sta_index(vif, sta_priv));
wcn36xx_smd_add_ba(wcn);
wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv));
- ieee80211_start_tx_ba_session(sta, tid, 0);
break;
case IEEE80211_AMPDU_RX_STOP:
wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv));
break;
case IEEE80211_AMPDU_TX_START:
+ spin_lock_bh(&sta_priv->ampdu_lock);
+ sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
+ spin_unlock_bh(&sta_priv->ampdu_lock);
+
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
+ spin_lock_bh(&sta_priv->ampdu_lock);
+ sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL;
+ spin_unlock_bh(&sta_priv->ampdu_lock);
+
wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1,
get_sta_index(vif, sta_priv));
break;
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
case IEEE80211_AMPDU_TX_STOP_CONT:
+ spin_lock_bh(&sta_priv->ampdu_lock);
+ sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_NONE;
+ spin_unlock_bh(&sta_priv->ampdu_lock);
+
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
default:
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 63986931829e..69ed39731902 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -21,6 +21,61 @@
#include <linux/bitops.h>
#include "smd.h"
+struct wcn36xx_cfg_val {
+ u32 cfg_id;
+ u32 value;
+};
+
+#define WCN36XX_CFG_VAL(id, val) \
+{ \
+ .cfg_id = WCN36XX_HAL_CFG_ ## id, \
+ .value = val \
+}
+
+static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = {
+ WCN36XX_CFG_VAL(CURRENT_TX_ANTENNA, 1),
+ WCN36XX_CFG_VAL(CURRENT_RX_ANTENNA, 1),
+ WCN36XX_CFG_VAL(LOW_GAIN_OVERRIDE, 0),
+ WCN36XX_CFG_VAL(POWER_STATE_PER_CHAIN, 785),
+ WCN36XX_CFG_VAL(CAL_PERIOD, 5),
+ WCN36XX_CFG_VAL(CAL_CONTROL, 1),
+ WCN36XX_CFG_VAL(PROXIMITY, 0),
+ WCN36XX_CFG_VAL(NETWORK_DENSITY, 3),
+ WCN36XX_CFG_VAL(MAX_MEDIUM_TIME, 6000),
+ WCN36XX_CFG_VAL(MAX_MPDUS_IN_AMPDU, 64),
+ WCN36XX_CFG_VAL(RTS_THRESHOLD, 2347),
+ WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 6),
+ WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 6),
+ WCN36XX_CFG_VAL(FRAGMENTATION_THRESHOLD, 8000),
+ WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ZERO, 5),
+ WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ONE, 10),
+ WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_TWO, 15),
+ WCN36XX_CFG_VAL(FIXED_RATE, 0),
+ WCN36XX_CFG_VAL(RETRYRATE_POLICY, 4),
+ WCN36XX_CFG_VAL(RETRYRATE_SECONDARY, 0),
+ WCN36XX_CFG_VAL(RETRYRATE_TERTIARY, 0),
+ WCN36XX_CFG_VAL(FORCE_POLICY_PROTECTION, 5),
+ WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_24GHZ, 1),
+ WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_5GHZ, 5),
+ WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_5GHZ, 5),
+ WCN36XX_CFG_VAL(MAX_BA_SESSIONS, 40),
+ WCN36XX_CFG_VAL(PS_DATA_INACTIVITY_TIMEOUT, 200),
+ WCN36XX_CFG_VAL(PS_ENABLE_BCN_FILTER, 1),
+ WCN36XX_CFG_VAL(PS_ENABLE_RSSI_MONITOR, 1),
+ WCN36XX_CFG_VAL(NUM_BEACON_PER_RSSI_AVERAGE, 20),
+ WCN36XX_CFG_VAL(STATS_PERIOD, 10),
+ WCN36XX_CFG_VAL(CFP_MAX_DURATION, 30000),
+ WCN36XX_CFG_VAL(FRAME_TRANS_ENABLED, 0),
+ WCN36XX_CFG_VAL(BA_THRESHOLD_HIGH, 128),
+ WCN36XX_CFG_VAL(MAX_BA_BUFFERS, 2560),
+ WCN36XX_CFG_VAL(DYNAMIC_PS_POLL_VALUE, 0),
+ WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1),
+ WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1),
+ WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0),
+ WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10),
+ WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0),
+};
+
static int put_cfg_tlv_u32(struct wcn36xx *wcn, size_t *len, u32 id, u32 value)
{
struct wcn36xx_hal_cfg *entry;
@@ -357,8 +412,10 @@ static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len)
int wcn36xx_smd_start(struct wcn36xx *wcn)
{
- struct wcn36xx_hal_mac_start_req_msg msg_body;
+ struct wcn36xx_hal_mac_start_req_msg msg_body, *body;
int ret = 0;
+ int i;
+ size_t len;
mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_REQ);
@@ -368,10 +425,22 @@ int wcn36xx_smd_start(struct wcn36xx *wcn)
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+ body = (struct wcn36xx_hal_mac_start_req_msg *)wcn->hal_buf;
+ len = body->header.len;
+
+ for (i = 0; i < ARRAY_SIZE(wcn36xx_cfg_vals); i++) {
+ ret = put_cfg_tlv_u32(wcn, &len, wcn36xx_cfg_vals[i].cfg_id,
+ wcn36xx_cfg_vals[i].value);
+ if (ret)
+ goto out;
+ }
+ body->header.len = len;
+ body->params.len = len - sizeof(*body);
+
wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start type %d\n",
msg_body.params.type);
- ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+ ret = wcn36xx_smd_send_and_wait(wcn, body->header.len);
if (ret) {
wcn36xx_err("Sending hal_start failed\n");
goto out;
diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c
index 32bb26a0db2a..9bec8237231d 100644
--- a/drivers/net/wireless/ath/wcn36xx/txrx.c
+++ b/drivers/net/wireless/ath/wcn36xx/txrx.c
@@ -93,6 +93,7 @@ static void wcn36xx_set_tx_pdu(struct wcn36xx_tx_bd *bd,
bd->pdu.mpdu_header_off;
bd->pdu.mpdu_len = len;
bd->pdu.tid = tid;
+ bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_QOS;
}
static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn,
@@ -110,15 +111,54 @@ static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn,
wcn36xx_warn("vif %pM not found\n", addr);
return NULL;
}
+
+static void wcn36xx_tx_start_ampdu(struct wcn36xx *wcn,
+ struct wcn36xx_sta *sta_priv,
+ struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_sta *sta;
+ u8 *qc, tid;
+
+ if (!conf_is_ht(&wcn->hw->conf))
+ return;
+
+ sta = wcn36xx_priv_to_sta(sta_priv);
+
+ if (WARN_ON(!ieee80211_is_data_qos(hdr->frame_control)))
+ return;
+
+ if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
+ return;
+
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+
+ spin_lock(&sta_priv->ampdu_lock);
+ if (sta_priv->ampdu_state[tid] != WCN36XX_AMPDU_NONE)
+ goto out_unlock;
+
+ if (sta_priv->non_agg_frame_ct++ >= WCN36XX_AMPDU_START_THRESH) {
+ sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
+ sta_priv->non_agg_frame_ct = 0;
+ ieee80211_start_tx_ba_session(sta, tid, 0);
+ }
+out_unlock:
+ spin_unlock(&sta_priv->ampdu_lock);
+}
+
static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
struct wcn36xx *wcn,
struct wcn36xx_vif **vif_priv,
struct wcn36xx_sta *sta_priv,
- struct ieee80211_hdr *hdr,
+ struct sk_buff *skb,
bool bcast)
{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_vif *vif = NULL;
struct wcn36xx_vif *__vif_priv = NULL;
+ bool is_data_qos;
+
bd->bd_rate = WCN36XX_BD_RATE_DATA;
/*
@@ -157,14 +197,26 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
bd->ack_policy = 1;
}
*vif_priv = __vif_priv;
+
+ is_data_qos = ieee80211_is_data_qos(hdr->frame_control);
+
+ wcn36xx_set_tx_pdu(bd,
+ is_data_qos ?
+ sizeof(struct ieee80211_qos_hdr) :
+ sizeof(struct ieee80211_hdr_3addr),
+ skb->len, sta_priv ? sta_priv->tid : 0);
+
+ if (sta_priv && is_data_qos)
+ wcn36xx_tx_start_ampdu(wcn, sta_priv, skb);
}
static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
struct wcn36xx *wcn,
struct wcn36xx_vif **vif_priv,
- struct ieee80211_hdr *hdr,
+ struct sk_buff *skb,
bool bcast)
{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct wcn36xx_vif *__vif_priv =
get_vif_by_addr(wcn, hdr->addr2);
bd->sta_index = __vif_priv->self_sta_index;
@@ -198,6 +250,12 @@ static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
} else
bd->queue_id = WCN36XX_TX_U_WQ_ID;
*vif_priv = __vif_priv;
+
+ wcn36xx_set_tx_pdu(bd,
+ ieee80211_is_data_qos(hdr->frame_control) ?
+ sizeof(struct ieee80211_qos_hdr) :
+ sizeof(struct ieee80211_hdr_3addr),
+ skb->len, WCN36XX_TID);
}
int wcn36xx_start_tx(struct wcn36xx *wcn,
@@ -237,7 +295,7 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
bd->dpu_rf = WCN36XX_BMU_WQ_TX;
- bd->tx_comp = info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS;
+ bd->tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS);
if (bd->tx_comp) {
wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n");
spin_lock_irqsave(&wcn->dxe_lock, flags);
@@ -259,22 +317,11 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
}
/* Data frames served first*/
- if (is_low) {
- wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, hdr, bcast);
- wcn36xx_set_tx_pdu(bd,
- ieee80211_is_data_qos(hdr->frame_control) ?
- sizeof(struct ieee80211_qos_hdr) :
- sizeof(struct ieee80211_hdr_3addr),
- skb->len, sta_priv ? sta_priv->tid : 0);
- } else {
+ if (is_low)
+ wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, skb, bcast);
+ else
/* MGMT and CTRL frames are handeld here*/
- wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, hdr, bcast);
- wcn36xx_set_tx_pdu(bd,
- ieee80211_is_data_qos(hdr->frame_control) ?
- sizeof(struct ieee80211_qos_hdr) :
- sizeof(struct ieee80211_hdr_3addr),
- skb->len, WCN36XX_TID);
- }
+ wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, skb, bcast);
buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32));
bd->tx_bd_sign = 0xbdbdbdbd;
diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.h b/drivers/net/wireless/ath/wcn36xx/txrx.h
index bbfbcf808c77..032216e82b2b 100644
--- a/drivers/net/wireless/ath/wcn36xx/txrx.h
+++ b/drivers/net/wireless/ath/wcn36xx/txrx.h
@@ -32,6 +32,12 @@
#define WCN36XX_BD_RATE_MGMT 2
#define WCN36XX_BD_RATE_CTRL 3
+enum wcn36xx_txbd_ssn_type {
+ WCN36XX_TXBD_SSN_FILL_HOST = 0,
+ WCN36XX_TXBD_SSN_FILL_DPU_NON_QOS = 1,
+ WCN36XX_TXBD_SSN_FILL_DPU_QOS = 2,
+};
+
struct wcn36xx_pdu {
u32 dpu_fb:8;
u32 adu_fb:8;
@@ -50,7 +56,8 @@ struct wcn36xx_pdu {
/* 0x0c*/
u32 reserved4:8;
u32 tid:4;
- u32 reserved3:4;
+ u32 bd_ssn:2;
+ u32 reserved3:2;
u32 mpdu_len:16;
};
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index f0fb81dfd17b..7b41e833e18c 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -32,6 +32,9 @@
#define WLAN_NV_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin"
#define WCN36XX_AGGR_BUFFER_SIZE 64
+/* How many frames until we start a-mpdu TX session */
+#define WCN36XX_AMPDU_START_THRESH 20
+
extern unsigned int wcn36xx_dbg_mask;
enum wcn36xx_debug_mask {
@@ -74,6 +77,13 @@ enum wcn36xx_debug_mask {
buf, len, false); \
} while (0)
+enum wcn36xx_ampdu_state {
+ WCN36XX_AMPDU_NONE,
+ WCN36XX_AMPDU_INIT,
+ WCN36XX_AMPDU_START,
+ WCN36XX_AMPDU_OPERATIONAL,
+};
+
#define WCN36XX_HW_CHANNEL(__wcn) (__wcn->hw->conf.chandef.chan->hw_value)
#define WCN36XX_BAND(__wcn) (__wcn->hw->conf.chandef.chan->band)
#define WCN36XX_CENTER_FREQ(__wcn) (__wcn->hw->conf.chandef.chan->center_freq)
@@ -165,6 +175,10 @@ struct wcn36xx_sta {
bool is_data_encrypted;
/* Rates */
struct wcn36xx_hal_supported_rates supported_rates;
+
+ spinlock_t ampdu_lock; /* protects next two fields */
+ enum wcn36xx_ampdu_state ampdu_state[16];
+ int non_agg_frame_ct;
};
struct wcn36xx_dxe_ch;
struct wcn36xx {
@@ -243,4 +257,10 @@ static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn,
}
void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates);
+static inline
+struct ieee80211_sta *wcn36xx_priv_to_sta(struct wcn36xx_sta *sta_priv)
+{
+ return container_of((void *)sta_priv, struct ieee80211_sta, drv_priv);
+}
+
#endif /* _WCN36XX_H_ */
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig
index 481680a3aa55..ce8c0381825e 100644
--- a/drivers/net/wireless/ath/wil6210/Kconfig
+++ b/drivers/net/wireless/ath/wil6210/Kconfig
@@ -39,12 +39,3 @@ config WIL6210_TRACING
option if you are interested in debugging the driver.
If unsure, say Y to make it easier to debug problems.
-
-config WIL6210_PLATFORM_MSM
- bool "wil6210 MSM platform specific support"
- depends on WIL6210
- depends on ARCH_MSM
- default y
- ---help---
- Say Y here to enable wil6210 driver support for MSM
- platform specific features
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index 8ad4b5f97e04..caa717bf52f3 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -14,7 +14,6 @@ wil6210-y += ioctl.o
wil6210-y += fw.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
wil6210-y += wil_platform.o
-wil6210-$(CONFIG_WIL6210_PLATFORM_MSM) += wil_platform_msm.o
wil6210-y += ethtool.o
# for tracing framework to find trace.h
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 38332a6dfb3a..2d5ea21be47e 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -142,14 +142,14 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
sinfo->generation = wil->sinfo_gen;
- sinfo->filled = STATION_INFO_RX_BYTES |
- STATION_INFO_TX_BYTES |
- STATION_INFO_RX_PACKETS |
- STATION_INFO_TX_PACKETS |
- STATION_INFO_RX_BITRATE |
- STATION_INFO_TX_BITRATE |
- STATION_INFO_RX_DROP_MISC |
- STATION_INFO_TX_FAILED;
+ sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) |
+ BIT(NL80211_STA_INFO_TX_BYTES) |
+ BIT(NL80211_STA_INFO_RX_PACKETS) |
+ BIT(NL80211_STA_INFO_TX_PACKETS) |
+ BIT(NL80211_STA_INFO_RX_BITRATE) |
+ BIT(NL80211_STA_INFO_TX_BITRATE) |
+ BIT(NL80211_STA_INFO_RX_DROP_MISC) |
+ BIT(NL80211_STA_INFO_TX_FAILED);
sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
@@ -162,8 +162,8 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
sinfo->tx_packets = stats->tx_packets;
sinfo->tx_failed = stats->tx_errors;
- if (test_bit(wil_status_fwconnected, &wil->status)) {
- sinfo->filled |= STATION_INFO_SIGNAL;
+ if (test_bit(wil_status_fwconnected, wil->status)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
sinfo->signal = reply.evt.sqi;
}
@@ -282,7 +282,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
}
/* FW don't support scan after connection attempt */
- if (test_bit(wil_status_dontscan, &wil->status)) {
+ if (test_bit(wil_status_dontscan, wil->status)) {
wil_err(wil, "Can't scan now\n");
return -EBUSY;
}
@@ -334,6 +334,30 @@ out:
return rc;
}
+static void wil_print_crypto(struct wil6210_priv *wil,
+ struct cfg80211_crypto_settings *c)
+{
+ int i, n;
+
+ wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n",
+ c->wpa_versions, c->cipher_group);
+ wil_dbg_misc(wil, "Pairwise ciphers [%d] {\n", c->n_ciphers_pairwise);
+ n = min_t(int, c->n_ciphers_pairwise, ARRAY_SIZE(c->ciphers_pairwise));
+ for (i = 0; i < n; i++)
+ wil_dbg_misc(wil, " [%d] = 0x%08x\n", i,
+ c->ciphers_pairwise[i]);
+ wil_dbg_misc(wil, "}\n");
+ wil_dbg_misc(wil, "AKM suites [%d] {\n", c->n_akm_suites);
+ n = min_t(int, c->n_akm_suites, ARRAY_SIZE(c->akm_suites));
+ for (i = 0; i < n; i++)
+ wil_dbg_misc(wil, " [%d] = 0x%08x\n", i,
+ c->akm_suites[i]);
+ wil_dbg_misc(wil, "}\n");
+ wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n",
+ c->control_port, be16_to_cpu(c->control_port_ethertype),
+ c->control_port_no_encrypt);
+}
+
static void wil_print_connect_params(struct wil6210_priv *wil,
struct cfg80211_connect_params *sme)
{
@@ -348,6 +372,7 @@ static void wil_print_connect_params(struct wil6210_priv *wil,
print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET,
16, 1, sme->ssid, sme->ssid_len, true);
wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open");
+ wil_print_crypto(wil, &sme->crypto);
}
static int wil_cfg80211_connect(struct wiphy *wiphy,
@@ -362,8 +387,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
int ch;
int rc = 0;
- if (test_bit(wil_status_fwconnecting, &wil->status) ||
- test_bit(wil_status_fwconnected, &wil->status))
+ if (test_bit(wil_status_fwconnecting, wil->status) ||
+ test_bit(wil_status_fwconnected, wil->status))
return -EALREADY;
wil_print_connect_params(wil, sme);
@@ -450,15 +475,16 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
memcpy(conn.bssid, bss->bssid, ETH_ALEN);
memcpy(conn.dst_mac, bss->bssid, ETH_ALEN);
- set_bit(wil_status_fwconnecting, &wil->status);
+ set_bit(wil_status_fwconnecting, wil->status);
rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
if (rc == 0) {
+ netif_carrier_on(ndev);
/* Connect can take lots of time */
mod_timer(&wil->connect_timer,
jiffies + msecs_to_jiffies(2000));
} else {
- clear_bit(wil_status_fwconnecting, &wil->status);
+ clear_bit(wil_status_fwconnecting, wil->status);
}
out:
@@ -618,18 +644,6 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
b->assocresp_ies, b->assocresp_ies_len);
}
-static void wil_print_crypto(struct wil6210_priv *wil,
- struct cfg80211_crypto_settings *c)
-{
- wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n",
- c->wpa_versions, c->cipher_group);
- wil_dbg_misc(wil, "Pairwise ciphers [%d]\n", c->n_ciphers_pairwise);
- wil_dbg_misc(wil, "AKM suites [%d]\n", c->n_akm_suites);
- wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n",
- c->control_port, be16_to_cpu(c->control_port_ethertype),
- c->control_port_no_encrypt);
-}
-
static int wil_fix_bcon(struct wil6210_priv *wil,
struct cfg80211_beacon_data *bcon)
{
@@ -757,12 +771,12 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
wil->secure_pcp = info->privacy;
+ netif_carrier_on(ndev);
+
rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype,
channel->hw_value);
if (rc)
- goto out;
-
- netif_carrier_on(ndev);
+ netif_carrier_off(ndev);
out:
mutex_unlock(&wil->mutex);
@@ -772,23 +786,26 @@ out:
static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
struct net_device *ndev)
{
- int rc, rc1;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
wil_dbg_misc(wil, "%s()\n", __func__);
+ netif_carrier_off(ndev);
wil_set_recovery_state(wil, fw_recovery_idle);
mutex_lock(&wil->mutex);
- rc = wmi_pcp_stop(wil);
+ wmi_pcp_stop(wil);
__wil_down(wil);
- rc1 = __wil_up(wil);
+ __wil_up(wil);
mutex_unlock(&wil->mutex);
- return min(rc, rc1);
+ /* some functions above might fail (e.g. __wil_up). Nevertheless, we
+ * return success because AP has stopped
+ */
+ return 0;
}
static int wil_cfg80211_del_station(struct wiphy *wiphy,
@@ -804,6 +821,96 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy,
return 0;
}
+/* probe_client handling */
+static void wil_probe_client_handle(struct wil6210_priv *wil,
+ struct wil_probe_client_req *req)
+{
+ struct net_device *ndev = wil_to_ndev(wil);
+ struct wil_sta_info *sta = &wil->sta[req->cid];
+ /* assume STA is alive if it is still connected,
+ * else FW will disconnect it
+ */
+ bool alive = (sta->status == wil_sta_connected);
+
+ cfg80211_probe_status(ndev, sta->addr, req->cookie, alive, GFP_KERNEL);
+}
+
+static struct list_head *next_probe_client(struct wil6210_priv *wil)
+{
+ struct list_head *ret = NULL;
+
+ mutex_lock(&wil->probe_client_mutex);
+
+ if (!list_empty(&wil->probe_client_pending)) {
+ ret = wil->probe_client_pending.next;
+ list_del(ret);
+ }
+
+ mutex_unlock(&wil->probe_client_mutex);
+
+ return ret;
+}
+
+void wil_probe_client_worker(struct work_struct *work)
+{
+ struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+ probe_client_worker);
+ struct wil_probe_client_req *req;
+ struct list_head *lh;
+
+ while ((lh = next_probe_client(wil)) != NULL) {
+ req = list_entry(lh, struct wil_probe_client_req, list);
+
+ wil_probe_client_handle(wil, req);
+ kfree(req);
+ }
+}
+
+void wil_probe_client_flush(struct wil6210_priv *wil)
+{
+ struct wil_probe_client_req *req, *t;
+
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
+ mutex_lock(&wil->probe_client_mutex);
+
+ list_for_each_entry_safe(req, t, &wil->probe_client_pending, list) {
+ list_del(&req->list);
+ kfree(req);
+ }
+
+ mutex_unlock(&wil->probe_client_mutex);
+}
+
+static int wil_cfg80211_probe_client(struct wiphy *wiphy,
+ struct net_device *dev,
+ const u8 *peer, u64 *cookie)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil_probe_client_req *req;
+ int cid = wil_find_cid(wil, peer);
+
+ wil_dbg_misc(wil, "%s(%pM => CID %d)\n", __func__, peer, cid);
+
+ if (cid < 0)
+ return -ENOLINK;
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ req->cid = cid;
+ req->cookie = cid;
+
+ mutex_lock(&wil->probe_client_mutex);
+ list_add_tail(&req->list, &wil->probe_client_pending);
+ mutex_unlock(&wil->probe_client_mutex);
+
+ *cookie = req->cookie;
+ queue_work(wil->wq_service, &wil->probe_client_worker);
+ return 0;
+}
+
static struct cfg80211_ops wil_cfg80211_ops = {
.scan = wil_cfg80211_scan,
.connect = wil_cfg80211_connect,
@@ -823,6 +930,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
.start_ap = wil_cfg80211_start_ap,
.stop_ap = wil_cfg80211_stop_ap,
.del_station = wil_cfg80211_del_station,
+ .probe_client = wil_cfg80211_probe_client,
};
static void wil_wiphy_init(struct wiphy *wiphy)
@@ -854,6 +962,7 @@ static void wil_wiphy_init(struct wiphy *wiphy)
wiphy->cipher_suites = wil_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites);
wiphy->mgmt_stypes = wil_mgmt_stypes;
+ wiphy->features |= NL80211_FEATURE_SK_TX_STATUS;
}
struct wireless_dev *wil_cfg80211_init(struct device *dev)
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index cd991fa1cc3f..45c3558ec804 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -50,6 +50,7 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
char _s, char _h)
{
void __iomem *x = wmi_addr(wil, vring->hwtail);
+ u32 v;
seq_printf(s, "VRING %s = {\n", name);
seq_printf(s, " pa = %pad\n", &vring->pa);
@@ -58,10 +59,12 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
seq_printf(s, " swtail = %d\n", vring->swtail);
seq_printf(s, " swhead = %d\n", vring->swhead);
seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail);
- if (x)
- seq_printf(s, "0x%08x\n", ioread32(x));
- else
+ if (x) {
+ v = ioread32(x);
+ seq_printf(s, "0x%08x = %d\n", v, v);
+ } else {
seq_puts(s, "???\n");
+ }
if (vring->va && (vring->size < 1025)) {
uint i;
@@ -110,9 +113,12 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
snprintf(name, sizeof(name), "tx_%2d", i);
- seq_printf(s, "\n%pM CID %d TID %d [%3d|%3d] idle %3d%%\n",
- wil->sta[cid].addr, cid, tid, used, avail,
- (int)idle);
+ seq_printf(s,
+ "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %3d%%\n",
+ wil->sta[cid].addr, cid, tid,
+ txdata->agg_wsize, txdata->agg_timeout,
+ txdata->agg_amsdu ? "+" : "-",
+ used, avail, (int)idle);
wil_print_vring(s, wil, name, vring, '_', 'H');
}
@@ -384,24 +390,67 @@ static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
return 0;
}
-static const struct dbg_off itr_cnt_off[] = {
+static const struct dbg_off lgc_itr_cnt_off[] = {
{"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
{"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
{"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
{},
};
+static const struct dbg_off tx_itr_cnt_off[] = {
+ {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH),
+ doff_io32},
+ {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA),
+ doff_io32},
+ {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL),
+ doff_io32},
+ {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH),
+ doff_io32},
+ {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA),
+ doff_io32},
+ {"IDL_CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL),
+ doff_io32},
+ {},
+};
+
+static const struct dbg_off rx_itr_cnt_off[] = {
+ {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH),
+ doff_io32},
+ {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA),
+ doff_io32},
+ {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL),
+ doff_io32},
+ {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH),
+ doff_io32},
+ {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA),
+ doff_io32},
+ {"IDL_CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL),
+ doff_io32},
+ {},
+};
+
static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
struct dentry *parent)
{
- struct dentry *d = debugfs_create_dir("ITR_CNT", parent);
+ struct dentry *d, *dtx, *drx;
+ d = debugfs_create_dir("ITR_CNT", parent);
if (IS_ERR_OR_NULL(d))
return -ENODEV;
+ dtx = debugfs_create_dir("TX", d);
+ drx = debugfs_create_dir("RX", d);
+ if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx))
+ return -ENODEV;
+
wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
- itr_cnt_off);
+ lgc_itr_cnt_off);
+
+ wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr,
+ tx_itr_cnt_off);
+ wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr,
+ rx_itr_cnt_off);
return 0;
}
@@ -558,6 +607,87 @@ static const struct file_operations fops_rxon = {
.open = simple_open,
};
+/* block ack control, write:
+ * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
+ * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
+ * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side
+ */
+static ssize_t wil_write_back(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ struct wil6210_priv *wil = file->private_data;
+ int rc;
+ char *kbuf = kmalloc(len + 1, GFP_KERNEL);
+ char cmd[8];
+ int p1, p2, p3;
+
+ if (!kbuf)
+ return -ENOMEM;
+
+ rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
+ if (rc != len) {
+ kfree(kbuf);
+ return rc >= 0 ? -EIO : rc;
+ }
+
+ kbuf[len] = '\0';
+ rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3);
+ kfree(kbuf);
+
+ if (rc < 0)
+ return rc;
+ if (rc < 2)
+ return -EINVAL;
+
+ if (0 == strcmp(cmd, "add")) {
+ if (rc < 3) {
+ wil_err(wil, "BACK: add require at least 2 params\n");
+ return -EINVAL;
+ }
+ if (rc < 4)
+ p3 = 0;
+ wmi_addba(wil, p1, p2, p3);
+ } else if (0 == strcmp(cmd, "del_tx")) {
+ if (rc < 3)
+ p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
+ wmi_delba_tx(wil, p1, p2);
+ } else if (0 == strcmp(cmd, "del_rx")) {
+ if (rc < 3) {
+ wil_err(wil,
+ "BACK: del_rx require at least 2 params\n");
+ return -EINVAL;
+ }
+ if (rc < 4)
+ p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
+ wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3);
+ } else {
+ wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
+ return -EINVAL;
+ }
+
+ return len;
+}
+
+static ssize_t wil_read_back(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ static const char text[] = "block ack control, write:\n"
+ " - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n"
+ "If missing, <timeout> defaults to 0\n"
+ " - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n"
+ " - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n"
+ "If missing, <reason> set to \"STA_LEAVING\" (36)\n";
+
+ return simple_read_from_buffer(user_buf, count, ppos, text,
+ sizeof(text));
+}
+
+static const struct file_operations fops_back = {
+ .read = wil_read_back,
+ .write = wil_write_back,
+ .open = simple_open,
+};
+
/*---tx_mgmt---*/
/* Write mgmt frame to this file to send it */
static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
@@ -1116,7 +1246,8 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
int i;
u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
- seq_printf(s, "0x%03x [", r->head_seq_num);
+ seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout,
+ r->head_seq_num);
for (i = 0; i < r->buf_size; i++) {
if (i == index)
seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
@@ -1127,10 +1258,10 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
}
static int wil_sta_debugfs_show(struct seq_file *s, void *data)
+__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
{
struct wil6210_priv *wil = s->private;
int i, tid;
- unsigned long flags;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i];
@@ -1151,7 +1282,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
(p->data_port_open ? " data_port_open" : ""));
if (p->status == wil_sta_connected) {
- spin_lock_irqsave(&p->tid_rx_lock, flags);
+ spin_lock_bh(&p->tid_rx_lock);
for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
@@ -1160,7 +1291,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
wil_print_rxtid(s, r);
}
}
- spin_unlock_irqrestore(&p->tid_rx_lock, flags);
+ spin_unlock_bh(&p->tid_rx_lock);
}
}
@@ -1217,6 +1348,7 @@ static const struct {
{"rxon", S_IWUSR, &fops_rxon},
{"tx_mgmt", S_IWUSR, &fops_txmgmt},
{"wmi_send", S_IWUSR, &fops_wmi},
+ {"back", S_IRUGO | S_IWUSR, &fops_back},
{"temp", S_IRUGO, &fops_temp},
{"freq", S_IRUGO, &fops_freq},
{"link", S_IRUGO, &fops_link},
@@ -1261,7 +1393,7 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
/* fields in struct wil6210_priv */
static const struct dbg_off dbg_wil_off[] = {
WIL_FIELD(secure_pcp, S_IRUGO | S_IWUSR, doff_u32),
- WIL_FIELD(status, S_IRUGO | S_IWUSR, doff_ulong),
+ WIL_FIELD(status[0], S_IRUGO | S_IWUSR, doff_ulong),
WIL_FIELD(fw_version, S_IRUGO, doff_u32),
WIL_FIELD(hw_version, S_IRUGO, doff_x32),
WIL_FIELD(recovery_count, S_IRUGO, doff_u32),
diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c
index d686638972be..4c44a82c34d7 100644
--- a/drivers/net/wireless/ath/wil6210/ethtool.c
+++ b/drivers/net/wireless/ath/wil6210/ethtool.c
@@ -45,16 +45,35 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev,
struct ethtool_coalesce *cp)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
- u32 itr_en, itr_val = 0;
+ u32 tx_itr_en, tx_itr_val = 0;
+ u32 rx_itr_en, rx_itr_val = 0;
wil_dbg_misc(wil, "%s()\n", __func__);
- itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
- if (itr_en & BIT_DMA_ITR_CNT_CRL_EN)
- itr_val = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
-
- cp->rx_coalesce_usecs = itr_val;
+ if (test_bit(hw_capability_advanced_itr_moderation,
+ wil->hw_capabilities)) {
+ tx_itr_en = ioread32(wil->csr +
+ HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL));
+ if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN)
+ tx_itr_val =
+ ioread32(wil->csr +
+ HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH));
+
+ rx_itr_en = ioread32(wil->csr +
+ HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL));
+ if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN)
+ rx_itr_val =
+ ioread32(wil->csr +
+ HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH));
+ } else {
+ rx_itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+ if (rx_itr_en & BIT_DMA_ITR_CNT_CRL_EN)
+ rx_itr_val = ioread32(wil->csr +
+ HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
+ }
+ cp->tx_coalesce_usecs = tx_itr_val;
+ cp->rx_coalesce_usecs = rx_itr_val;
return 0;
}
@@ -63,22 +82,25 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev,
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
- wil_dbg_misc(wil, "%s(%d usec)\n", __func__, cp->rx_coalesce_usecs);
+ wil_dbg_misc(wil, "%s(rx %d usec, tx %d usec)\n", __func__,
+ cp->rx_coalesce_usecs, cp->tx_coalesce_usecs);
if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n");
return -EINVAL;
}
- /* only @rx_coalesce_usecs supported, ignore
- * other parameters
+ /* only @rx_coalesce_usecs and @tx_coalesce_usecs supported,
+ * ignore other parameters
*/
- if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX)
+ if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX ||
+ cp->tx_coalesce_usecs > WIL6210_ITR_TRSH_MAX)
goto out_bad;
- wil->itr_trsh = cp->rx_coalesce_usecs;
- wil_set_itr_trsh(wil);
+ wil->tx_max_burst_duration = cp->tx_coalesce_usecs;
+ wil->rx_max_burst_duration = cp->rx_coalesce_usecs;
+ wil_configure_interrupt_moderation(wil);
return 0;
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 4bcbd6297b3e..a6f923086f31 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -102,7 +102,7 @@ static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
- clear_bit(wil_status_irqen, &wil->status);
+ clear_bit(wil_status_irqen, wil->status);
}
void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
@@ -130,7 +130,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
{
wil_dbg_irq(wil, "%s()\n", __func__);
- set_bit(wil_status_irqen, &wil->status);
+ set_bit(wil_status_irqen, wil->status);
iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr +
HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
@@ -157,15 +157,91 @@ void wil_unmask_irq(struct wil6210_priv *wil)
iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
offsetof(struct RGF_ICR, ICC));
- /* interrupt moderation parameters */
- wil_set_itr_trsh(wil);
-
wil6210_unmask_irq_pseudo(wil);
wil6210_unmask_irq_tx(wil);
wil6210_unmask_irq_rx(wil);
wil6210_unmask_irq_misc(wil);
}
+/* target write operation */
+#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
+
+static
+void wil_configure_interrupt_moderation_new(struct wil6210_priv *wil)
+{
+ /* Disable and clear tx counter before (re)configuration */
+ W(RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR);
+ W(RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration);
+ wil_info(wil, "set ITR_TX_CNT_TRSH = %d usec\n",
+ wil->tx_max_burst_duration);
+ /* Configure TX max burst duration timer to use usec units */
+ W(RGF_DMA_ITR_TX_CNT_CTL,
+ BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL);
+
+ /* Disable and clear tx idle counter before (re)configuration */
+ W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR);
+ W(RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout);
+ wil_info(wil, "set ITR_TX_IDL_CNT_TRSH = %d usec\n",
+ wil->tx_interframe_timeout);
+ /* Configure TX max burst duration timer to use usec units */
+ W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN |
+ BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL);
+
+ /* Disable and clear rx counter before (re)configuration */
+ W(RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR);
+ W(RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration);
+ wil_info(wil, "set ITR_RX_CNT_TRSH = %d usec\n",
+ wil->rx_max_burst_duration);
+ /* Configure TX max burst duration timer to use usec units */
+ W(RGF_DMA_ITR_RX_CNT_CTL,
+ BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL);
+
+ /* Disable and clear rx idle counter before (re)configuration */
+ W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR);
+ W(RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout);
+ wil_info(wil, "set ITR_RX_IDL_CNT_TRSH = %d usec\n",
+ wil->rx_interframe_timeout);
+ /* Configure TX max burst duration timer to use usec units */
+ W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN |
+ BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL);
+}
+
+static
+void wil_configure_interrupt_moderation_lgc(struct wil6210_priv *wil)
+{
+ /* disable, use usec resolution */
+ W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_CLR);
+
+ wil_info(wil, "set ITR_TRSH = %d usec\n", wil->rx_max_burst_duration);
+ W(RGF_DMA_ITR_CNT_TRSH, wil->rx_max_burst_duration);
+ /* start it */
+ W(RGF_DMA_ITR_CNT_CRL,
+ BIT_DMA_ITR_CNT_CRL_EN | BIT_DMA_ITR_CNT_CRL_EXT_TICK);
+}
+
+#undef W
+
+void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
+{
+ wil_dbg_irq(wil, "%s()\n", __func__);
+
+ /* disable interrupt moderation for monitor
+ * to get better timestamp precision
+ */
+ if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR)
+ return;
+
+ if (test_bit(hw_capability_advanced_itr_moderation,
+ wil->hw_capabilities))
+ wil_configure_interrupt_moderation_new(wil);
+ else {
+ /* Advanced interrupt moderation is not available before
+ * Sparrow v2. Will use legacy interrupt moderation
+ */
+ wil_configure_interrupt_moderation_lgc(wil);
+ }
+}
+
static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
@@ -194,18 +270,19 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
wil_dbg_irq(wil, "RX done\n");
if (isr & BIT_DMA_EP_RX_ICR_RX_HTRSH)
- wil_err_ratelimited(wil, "Received \"Rx buffer is in risk "
- "of overflow\" interrupt\n");
+ wil_err_ratelimited(wil,
+ "Received \"Rx buffer is in risk of overflow\" interrupt\n");
- isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH);
- if (test_bit(wil_status_reset_done, &wil->status)) {
- if (test_bit(wil_status_napi_en, &wil->status)) {
+ isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE |
+ BIT_DMA_EP_RX_ICR_RX_HTRSH);
+ if (test_bit(wil_status_reset_done, wil->status)) {
+ if (test_bit(wil_status_napi_en, wil->status)) {
wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
need_unmask = false;
napi_schedule(&wil->napi_rx);
} else {
- wil_err(wil, "Got Rx interrupt while "
- "stopping interface\n");
+ wil_err(wil,
+ "Got Rx interrupt while stopping interface\n");
}
} else {
wil_err(wil, "Got Rx interrupt while in reset\n");
@@ -248,7 +325,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
/* clear also all VRING interrupts */
isr &= ~(BIT(25) - 1UL);
- if (test_bit(wil_status_reset_done, &wil->status)) {
+ if (test_bit(wil_status_reset_done, wil->status)) {
wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
need_unmask = false;
napi_schedule(&wil->napi_tx);
@@ -310,7 +387,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
if (isr & ISR_MISC_FW_ERROR) {
wil_err(wil, "Firmware error detected\n");
- clear_bit(wil_status_fwready, &wil->status);
+ clear_bit(wil_status_fwready, wil->status);
/*
* do not clear @isr here - we do 2-nd part in thread
* there, user space get notified, and it should be done
@@ -321,7 +398,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
if (isr & ISR_MISC_FW_READY) {
wil_dbg_irq(wil, "IRQ: FW ready\n");
wil_cache_mbox_regs(wil);
- set_bit(wil_status_reset_done, &wil->status);
+ set_bit(wil_status_reset_done, wil->status);
/**
* Actual FW ready indicated by the
* WMI_FW_READY_EVENTID
@@ -394,7 +471,7 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
*/
static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)
{
- if (!test_bit(wil_status_irqen, &wil->status)) {
+ if (!test_bit(wil_status_irqen, wil->status)) {
u32 icm_rx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_RX_ICR) +
offsetof(struct RGF_ICR, ICM));
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 8ff3fe34fe05..b04e0afdcb21 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -33,15 +33,18 @@ static bool no_fw_load = true;
module_param(no_fw_load, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash.");
-static unsigned int itr_trsh = WIL6210_ITR_TRSH_DEFAULT;
-
-module_param(itr_trsh, uint, S_IRUGO);
-MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs.");
+/* if not set via modparam, will be set to default value of 1/8 of
+ * rx ring size during init flow
+ */
+unsigned short rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_INIT;
+module_param(rx_ring_overflow_thrsh, ushort, S_IRUGO);
+MODULE_PARM_DESC(rx_ring_overflow_thrsh,
+ " RX ring overflow threshold in descriptors.");
/* We allow allocation of more than 1 page buffers to support large packets.
* It is suboptimal behavior performance wise in case MTU above page size.
*/
-unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - ETH_HLEN;
+unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD;
static int mtu_max_set(const char *val, const struct kernel_param *kp)
{
int ret;
@@ -53,7 +56,7 @@ static int mtu_max_set(const char *val, const struct kernel_param *kp)
if (ret)
return ret;
- if (mtu_max < 68 || mtu_max > IEEE80211_MAX_DATA_LEN_DMG)
+ if (mtu_max < 68 || mtu_max > WIL_MAX_ETH_MTU)
ret = -EINVAL;
return ret;
@@ -135,12 +138,14 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
u16 reason_code, bool from_event)
+__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{
uint i;
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
struct wil_sta_info *sta = &wil->sta[cid];
+ might_sleep();
wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
sta->status);
@@ -163,15 +168,14 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
for (i = 0; i < WIL_STA_TID_NUM; i++) {
struct wil_tid_ampdu_rx *r;
- unsigned long flags;
- spin_lock_irqsave(&sta->tid_rx_lock, flags);
+ spin_lock_bh(&sta->tid_rx_lock);
r = sta->tid_rx[i];
sta->tid_rx[i] = NULL;
wil_tid_ampdu_rx_free(wil, r);
- spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+ spin_unlock_bh(&sta->tid_rx_lock);
}
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
if (wil->vring2cid_tid[i][0] == cid)
@@ -188,34 +192,47 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
struct wireless_dev *wdev = wil->wdev;
might_sleep();
- if (bssid) {
+ wil_dbg_misc(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid,
+ reason_code, from_event ? "+" : "-");
+
+ /* Cases are:
+ * - disconnect single STA, still connected
+ * - disconnect single STA, already disconnected
+ * - disconnect all
+ *
+ * For "disconnect all", there are 2 options:
+ * - bssid == NULL
+ * - bssid is our MAC address
+ */
+ if (bssid && memcmp(ndev->dev_addr, bssid, ETH_ALEN)) {
cid = wil_find_cid(wil, bssid);
- wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
- } else {
- wil_dbg_misc(wil, "%s(all)\n", __func__);
- }
-
- if (cid >= 0) /* disconnect 1 peer */
- wil_disconnect_cid(wil, cid, reason_code, from_event);
- else /* disconnect all */
+ wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n",
+ bssid, cid, reason_code);
+ if (cid >= 0) /* disconnect 1 peer */
+ wil_disconnect_cid(wil, cid, reason_code, from_event);
+ } else { /* all */
+ wil_dbg_misc(wil, "Disconnect all\n");
for (cid = 0; cid < WIL6210_MAX_CID; cid++)
wil_disconnect_cid(wil, cid, reason_code, from_event);
+ }
/* link state */
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
- wil_link_off(wil);
- if (test_bit(wil_status_fwconnected, &wil->status)) {
- clear_bit(wil_status_fwconnected, &wil->status);
+ netif_tx_stop_all_queues(ndev);
+ netif_carrier_off(ndev);
+
+ if (test_bit(wil_status_fwconnected, wil->status)) {
+ clear_bit(wil_status_fwconnected, wil->status);
cfg80211_disconnected(ndev, reason_code,
NULL, 0, GFP_KERNEL);
- } else if (test_bit(wil_status_fwconnecting, &wil->status)) {
+ } else if (test_bit(wil_status_fwconnecting, wil->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
}
- clear_bit(wil_status_fwconnecting, &wil->status);
+ clear_bit(wil_status_fwconnecting, wil->status);
break;
default:
break;
@@ -248,7 +265,7 @@ static void wil_scan_timer_fn(ulong x)
{
struct wil6210_priv *wil = (void *)x;
- clear_bit(wil_status_fwready, &wil->status);
+ clear_bit(wil_status_fwready, wil->status);
wil_err(wil, "Scan timeout detected, start fw error recovery\n");
wil->recovery_state = fw_recovery_pending;
schedule_work(&wil->fw_error_worker);
@@ -352,6 +369,8 @@ static void wil_connect_worker(struct work_struct *work)
int rc;
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
connect_worker);
+ struct net_device *ndev = wil_to_ndev(wil);
+
int cid = wil->pending_connect_cid;
int ringid = wil_find_free_vring(wil);
@@ -366,7 +385,7 @@ static void wil_connect_worker(struct work_struct *work)
wil->pending_connect_cid = -1;
if (rc == 0) {
wil->sta[cid].status = wil_sta_connected;
- wil_link_on(wil);
+ netif_tx_wake_all_queues(ndev);
} else {
wil->sta[cid].status = wil_sta_unused;
}
@@ -384,6 +403,9 @@ int wil_priv_init(struct wil6210_priv *wil)
mutex_init(&wil->mutex);
mutex_init(&wil->wmi_mutex);
+ mutex_init(&wil->back_rx_mutex);
+ mutex_init(&wil->back_tx_mutex);
+ mutex_init(&wil->probe_client_mutex);
init_completion(&wil->wmi_ready);
init_completion(&wil->wmi_call);
@@ -396,25 +418,39 @@ int wil_priv_init(struct wil6210_priv *wil)
INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
+ INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker);
+ INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker);
+ INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker);
INIT_LIST_HEAD(&wil->pending_wmi_ev);
+ INIT_LIST_HEAD(&wil->back_rx_pending);
+ INIT_LIST_HEAD(&wil->back_tx_pending);
+ INIT_LIST_HEAD(&wil->probe_client_pending);
spin_lock_init(&wil->wmi_ev_lock);
init_waitqueue_head(&wil->wq);
- wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi");
+ wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
if (!wil->wmi_wq)
return -EAGAIN;
- wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect");
- if (!wil->wmi_wq_conn) {
- destroy_workqueue(wil->wmi_wq);
- return -EAGAIN;
- }
+ wil->wq_service = create_singlethread_workqueue(WIL_NAME "_service");
+ if (!wil->wq_service)
+ goto out_wmi_wq;
wil->last_fw_recovery = jiffies;
- wil->itr_trsh = itr_trsh;
+ wil->tx_interframe_timeout = WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT;
+ wil->rx_interframe_timeout = WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT;
+ wil->tx_max_burst_duration = WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT;
+ wil->rx_max_burst_duration = WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT;
+ if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT)
+ rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT;
return 0;
+
+out_wmi_wq:
+ destroy_workqueue(wil->wmi_wq);
+
+ return -EAGAIN;
}
/**
@@ -448,7 +484,13 @@ void wil_priv_deinit(struct wil6210_priv *wil)
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
mutex_unlock(&wil->mutex);
wmi_event_flush(wil);
- destroy_workqueue(wil->wmi_wq_conn);
+ wil_back_rx_flush(wil);
+ cancel_work_sync(&wil->back_rx_worker);
+ wil_back_tx_flush(wil);
+ cancel_work_sync(&wil->back_tx_worker);
+ wil_probe_client_flush(wil);
+ cancel_work_sync(&wil->probe_client_worker);
+ destroy_workqueue(wil->wq_service);
destroy_workqueue(wil->wmi_wq);
}
@@ -478,13 +520,10 @@ static int wil_target_reset(struct wil6210_priv *wil)
{
int delay = 0;
u32 x;
- u32 rev_id;
- bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW);
+ bool is_reset_v2 = test_bit(hw_capability_reset_v2,
+ wil->hw_capabilities);
- wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name);
-
- wil->hw_version = R(RGF_USER_FW_REV_ID);
- rev_id = wil->hw_version & 0xff;
+ wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name);
/* Clear MAC link up */
S(RGF_HP_CTRL, BIT(15));
@@ -496,7 +535,7 @@ static int wil_target_reset(struct wil6210_priv *wil)
/* Clear Fw Download notification */
C(RGF_USER_USAGE_6, BIT(0));
- if (is_sparrow) {
+ if (is_reset_v2) {
S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN);
/* XTAL stabilization should take about 3ms */
usleep_range(5000, 7000);
@@ -517,10 +556,11 @@ static int wil_target_reset(struct wil6210_priv *wil)
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170);
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_3,
+ is_reset_v2 ? 0x000000f0 : 0x00000170);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
- if (is_sparrow) {
+ if (is_reset_v2) {
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
}
@@ -530,19 +570,14 @@ static int wil_target_reset(struct wil6210_priv *wil)
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
- if (is_sparrow) {
+ if (is_reset_v2) {
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
/* reset A2 PCIE AHB */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
} else {
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
- if (rev_id == 1) {
- /* reset A1 BOTH PCIE AHB & PCIE RGF */
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
- } else {
- W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
- }
+ W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
}
/* TODO: check order here!!! Erez code is different */
@@ -559,8 +594,7 @@ static int wil_target_reset(struct wil6210_priv *wil)
}
} while (x != HW_MACHINE_BOOT_DONE);
- /* TODO: Erez check rev_id != 1 */
- if (!is_sparrow && (rev_id != 1))
+ if (!is_reset_v2)
W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
@@ -569,26 +603,6 @@ static int wil_target_reset(struct wil6210_priv *wil)
return 0;
}
-/**
- * wil_set_itr_trsh: - apply interrupt coalescing params
- */
-void wil_set_itr_trsh(struct wil6210_priv *wil)
-{
- /* disable, use usec resolution */
- W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EXT_TICK);
-
- /* disable interrupt moderation for monitor
- * to get better timestamp precision
- */
- if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR)
- return;
-
- wil_info(wil, "set ITR_TRSH = %d usec\n", wil->itr_trsh);
- W(RGF_DMA_ITR_CNT_TRSH, wil->itr_trsh);
- W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EN |
- BIT_DMA_ITR_CNT_CRL_EXT_TICK); /* start it */
-}
-
#undef R
#undef W
#undef S
@@ -629,13 +643,17 @@ int wil_reset(struct wil6210_priv *wil)
wil_dbg_misc(wil, "%s()\n", __func__);
+ if (wil->hw_version == HW_VER_UNKNOWN)
+ return -ENODEV;
+
WARN_ON(!mutex_is_locked(&wil->mutex));
- WARN_ON(test_bit(wil_status_napi_en, &wil->status));
+ WARN_ON(test_bit(wil_status_napi_en, wil->status));
cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
- wil->status = 0; /* prevent NAPI from being scheduled */
+ /* prevent NAPI from being scheduled */
+ bitmap_zero(wil->status, wil_status_last);
if (wil->scan_request) {
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
@@ -649,7 +667,7 @@ int wil_reset(struct wil6210_priv *wil)
wmi_event_flush(wil);
- flush_workqueue(wil->wmi_wq_conn);
+ flush_workqueue(wil->wq_service);
flush_workqueue(wil->wmi_wq);
rc = wil_target_reset(wil);
@@ -688,6 +706,7 @@ int wil_reset(struct wil6210_priv *wil)
reinit_completion(&wil->wmi_ready);
reinit_completion(&wil->wmi_call);
+ wil_configure_interrupt_moderation(wil);
wil_unmask_irq(wil);
/* we just started MAC, wait for FW ready */
@@ -703,28 +722,6 @@ void wil_fw_error_recovery(struct wil6210_priv *wil)
schedule_work(&wil->fw_error_worker);
}
-void wil_link_on(struct wil6210_priv *wil)
-{
- struct net_device *ndev = wil_to_ndev(wil);
-
- wil_dbg_misc(wil, "%s()\n", __func__);
-
- netif_carrier_on(ndev);
- wil_dbg_misc(wil, "netif_tx_wake : link on\n");
- netif_tx_wake_all_queues(ndev);
-}
-
-void wil_link_off(struct wil6210_priv *wil)
-{
- struct net_device *ndev = wil_to_ndev(wil);
-
- wil_dbg_misc(wil, "%s()\n", __func__);
-
- netif_tx_stop_all_queues(ndev);
- wil_dbg_misc(wil, "netif_tx_stop : link off\n");
- netif_carrier_off(ndev);
-}
-
int __wil_up(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
@@ -774,7 +771,7 @@ int __wil_up(struct wil6210_priv *wil)
wil_dbg_misc(wil, "NAPI enable\n");
napi_enable(&wil->napi_rx);
napi_enable(&wil->napi_tx);
- set_bit(wil_status_napi_en, &wil->status);
+ set_bit(wil_status_napi_en, wil->status);
if (wil->platform_ops.bus_request)
wil->platform_ops.bus_request(wil->platform_handle,
@@ -807,7 +804,7 @@ int __wil_down(struct wil6210_priv *wil)
wil->platform_ops.bus_request(wil->platform_handle, 0);
wil_disable_irq(wil);
- if (test_and_clear_bit(wil_status_napi_en, &wil->status)) {
+ if (test_and_clear_bit(wil_status_napi_en, wil->status)) {
napi_disable(&wil->napi_rx);
napi_disable(&wil->napi_tx);
wil_dbg_misc(wil, "NAPI disable\n");
@@ -822,15 +819,15 @@ int __wil_down(struct wil6210_priv *wil)
wil->scan_request = NULL;
}
- if (test_bit(wil_status_fwconnected, &wil->status) ||
- test_bit(wil_status_fwconnecting, &wil->status))
+ if (test_bit(wil_status_fwconnected, wil->status) ||
+ test_bit(wil_status_fwconnecting, wil->status))
wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
/* make sure wil is idle (not connected) */
mutex_unlock(&wil->mutex);
while (iter--) {
- int idle = !test_bit(wil_status_fwconnected, &wil->status) &&
- !test_bit(wil_status_fwconnecting, &wil->status);
+ int idle = !test_bit(wil_status_fwconnected, wil->status) &&
+ !test_bit(wil_status_fwconnecting, wil->status);
if (idle)
break;
msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS);
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index e81703ca7701..ace30c1b5c64 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -15,7 +15,6 @@
*/
#include <linux/etherdevice.h>
-
#include "wil6210.h"
#include "txrx.h"
@@ -122,6 +121,12 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
return min(tx_done, budget);
}
+static void wil_dev_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+ dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT;
+}
+
void *wil_if_alloc(struct device *dev, void __iomem *csr)
{
struct net_device *ndev;
@@ -153,7 +158,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels;
cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);
- ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, ether_setup);
+ ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup);
if (!ndev) {
dev_err(dev, "alloc_netdev_mqs failed\n");
rc = -ENOMEM;
@@ -174,7 +179,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
WIL6210_NAPI_BUDGET);
- wil_link_off(wil);
+ netif_tx_stop_all_queues(ndev);
return wil;
@@ -217,8 +222,6 @@ int wil_if_add(struct wil6210_priv *wil)
return rc;
}
- wil_link_off(wil);
-
return 0;
}
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 66626a8ee728..3dd26709ccb2 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -31,6 +31,46 @@ static bool debug_fw; /* = false; */
module_param(debug_fw, bool, S_IRUGO);
MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug");
+static
+void wil_set_capabilities(struct wil6210_priv *wil)
+{
+ u32 rev_id = ioread32(wil->csr + HOSTADDR(RGF_USER_JTAG_DEV_ID));
+
+ bitmap_zero(wil->hw_capabilities, hw_capability_last);
+
+ switch (rev_id) {
+ case JTAG_DEV_ID_MARLON_B0:
+ wil->hw_name = "Marlon B0";
+ wil->hw_version = HW_VER_MARLON_B0;
+ break;
+ case JTAG_DEV_ID_SPARROW_A0:
+ wil->hw_name = "Sparrow A0";
+ wil->hw_version = HW_VER_SPARROW_A0;
+ break;
+ case JTAG_DEV_ID_SPARROW_A1:
+ wil->hw_name = "Sparrow A1";
+ wil->hw_version = HW_VER_SPARROW_A1;
+ break;
+ case JTAG_DEV_ID_SPARROW_B0:
+ wil->hw_name = "Sparrow B0";
+ wil->hw_version = HW_VER_SPARROW_B0;
+ break;
+ default:
+ wil_err(wil, "Unknown board hardware 0x%08x\n", rev_id);
+ wil->hw_name = "Unknown";
+ wil->hw_version = HW_VER_UNKNOWN;
+ }
+
+ wil_info(wil, "Board hardware is %s\n", wil->hw_name);
+
+ if (wil->hw_version >= HW_VER_SPARROW_A0)
+ set_bit(hw_capability_reset_v2, wil->hw_capabilities);
+
+ if (wil->hw_version >= HW_VER_SPARROW_B0)
+ set_bit(hw_capability_advanced_itr_moderation,
+ wil->hw_capabilities);
+}
+
void wil_disable_irq(struct wil6210_priv *wil)
{
int irq = wil->pdev->irq;
@@ -149,12 +189,11 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct wil6210_priv *wil;
struct device *dev = &pdev->dev;
void __iomem *csr;
- struct wil_board *board = (struct wil_board *)id->driver_data;
int rc;
/* check HW */
dev_info(&pdev->dev, WIL_NAME
- " \"%s\" device found [%04x:%04x] (rev %x)\n", board->name,
+ " device found [%04x:%04x] (rev %x)\n",
(int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) {
@@ -204,8 +243,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_drvdata(pdev, wil);
wil->pdev = pdev;
- wil->board = board;
-
+ wil_set_capabilities(wil);
wil6210_clear_irq(wil);
wil->platform_handle =
@@ -266,23 +304,10 @@ static void wil_pcie_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-static const struct wil_board wil_board_marlon = {
- .board = WIL_BOARD_MARLON,
- .name = "marlon",
-};
-
-static const struct wil_board wil_board_sparrow = {
- .board = WIL_BOARD_SPARROW,
- .name = "sparrow",
-};
-
static const struct pci_device_id wil6210_pcie_ids[] = {
- { PCI_DEVICE(0x1ae9, 0x0301),
- .driver_data = (kernel_ulong_t)&wil_board_marlon },
- { PCI_DEVICE(0x1ae9, 0x0310),
- .driver_data = (kernel_ulong_t)&wil_board_sparrow },
- { PCI_DEVICE(0x1ae9, 0x0302), /* same as above, firmware broken */
- .driver_data = (kernel_ulong_t)&wil_board_sparrow },
+ { PCI_DEVICE(0x1ae9, 0x0301) },
+ { PCI_DEVICE(0x1ae9, 0x0310) },
+ { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 489cb73d139b..ca10dcf0986e 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -89,7 +89,9 @@ static void wil_reorder_release(struct wil6210_priv *wil,
}
}
+/* called in NAPI context */
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
+__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{
struct net_device *ndev = wil_to_ndev(wil);
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
@@ -97,22 +99,26 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
int cid = wil_rxdesc_cid(d);
int mid = wil_rxdesc_mid(d);
u16 seq = wil_rxdesc_seq(d);
+ int mcast = wil_rxdesc_mcast(d);
struct wil_sta_info *sta = &wil->sta[cid];
struct wil_tid_ampdu_rx *r;
u16 hseq;
int index;
- unsigned long flags;
- wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n",
- mid, cid, tid, seq);
+ wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n",
+ mid, cid, tid, seq, mcast);
- spin_lock_irqsave(&sta->tid_rx_lock, flags);
+ if (unlikely(mcast)) {
+ wil_netif_rx_any(skb, ndev);
+ return;
+ }
+
+ spin_lock(&sta->tid_rx_lock);
r = sta->tid_rx[tid];
if (!r) {
- spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
wil_netif_rx_any(skb, ndev);
- return;
+ goto out;
}
hseq = r->head_seq_num;
@@ -121,13 +127,24 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
* reported, and data Rx, few packets may be pass up before reorder
* buffer get allocated. Catch up by pretending SSN is what we
* see in the 1-st Rx packet
+ *
+ * Another scenario, Rx get delayed and we got packet from before
+ * BACK. Pass it to the stack and wait.
*/
if (r->first_time) {
r->first_time = false;
if (seq != r->head_seq_num) {
- wil_err(wil, "Error: 1-st frame with wrong sequence"
- " %d, should be %d. Fixing...\n", seq,
- r->head_seq_num);
+ if (seq_less(seq, r->head_seq_num)) {
+ wil_err(wil,
+ "Error: frame with early sequence 0x%03x, should be 0x%03x. Waiting...\n",
+ seq, r->head_seq_num);
+ r->first_time = true;
+ wil_netif_rx_any(skb, ndev);
+ goto out;
+ }
+ wil_err(wil,
+ "Error: 1-st frame with wrong sequence 0x%03x, should be 0x%03x. Fixing...\n",
+ seq, r->head_seq_num);
r->head_seq_num = seq;
r->ssn = seq;
}
@@ -179,7 +196,7 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
wil_reorder_release(wil, r);
out:
- spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+ spin_unlock(&sta->tid_rx_lock);
}
struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
@@ -219,3 +236,241 @@ void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
kfree(r->reorder_time);
kfree(r);
}
+
+/* ADDBA processing */
+static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize)
+{
+ u16 max_agg_size = min_t(u16, WIL_MAX_AGG_WSIZE, WIL_MAX_AMPDU_SIZE /
+ (mtu_max + WIL_MAX_MPDU_OVERHEAD));
+
+ if (!req_agg_wsize)
+ return max_agg_size;
+
+ return min(max_agg_size, req_agg_wsize);
+}
+
+/* Block Ack - Rx side (recipient */
+int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
+ u8 dialog_token, __le16 ba_param_set,
+ __le16 ba_timeout, __le16 ba_seq_ctrl)
+{
+ struct wil_back_rx *req = kzalloc(sizeof(*req), GFP_KERNEL);
+
+ if (!req)
+ return -ENOMEM;
+
+ req->cidxtid = cidxtid;
+ req->dialog_token = dialog_token;
+ req->ba_param_set = le16_to_cpu(ba_param_set);
+ req->ba_timeout = le16_to_cpu(ba_timeout);
+ req->ba_seq_ctrl = le16_to_cpu(ba_seq_ctrl);
+
+ mutex_lock(&wil->back_rx_mutex);
+ list_add_tail(&req->list, &wil->back_rx_pending);
+ mutex_unlock(&wil->back_rx_mutex);
+
+ queue_work(wil->wq_service, &wil->back_rx_worker);
+
+ return 0;
+}
+
+static void wil_back_rx_handle(struct wil6210_priv *wil,
+ struct wil_back_rx *req)
+__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
+{
+ struct wil_sta_info *sta;
+ u8 cid, tid;
+ u16 agg_wsize = 0;
+ /* bit 0: A-MSDU supported
+ * bit 1: policy (should be 0 for us)
+ * bits 2..5: TID
+ * bits 6..15: buffer size
+ */
+ u16 req_agg_wsize = WIL_GET_BITS(req->ba_param_set, 6, 15);
+ bool agg_amsdu = !!(req->ba_param_set & BIT(0));
+ int ba_policy = req->ba_param_set & BIT(1);
+ u16 agg_timeout = req->ba_timeout;
+ u16 status = WLAN_STATUS_SUCCESS;
+ u16 ssn = req->ba_seq_ctrl >> 4;
+ struct wil_tid_ampdu_rx *r;
+ int rc;
+
+ might_sleep();
+ parse_cidxtid(req->cidxtid, &cid, &tid);
+
+ /* sanity checks */
+ if (cid >= WIL6210_MAX_CID) {
+ wil_err(wil, "BACK: invalid CID %d\n", cid);
+ return;
+ }
+
+ sta = &wil->sta[cid];
+ if (sta->status != wil_sta_connected) {
+ wil_err(wil, "BACK: CID %d not connected\n", cid);
+ return;
+ }
+
+ wil_dbg_wmi(wil,
+ "ADDBA request for CID %d %pM TID %d size %d timeout %d AMSDU%s policy %d token %d SSN 0x%03x\n",
+ cid, sta->addr, tid, req_agg_wsize, req->ba_timeout,
+ agg_amsdu ? "+" : "-", !!ba_policy, req->dialog_token, ssn);
+
+ /* apply policies */
+ if (ba_policy) {
+ wil_err(wil, "BACK requested unsupported ba_policy == 1\n");
+ status = WLAN_STATUS_INVALID_QOS_PARAM;
+ }
+ if (status == WLAN_STATUS_SUCCESS)
+ agg_wsize = wil_agg_size(wil, req_agg_wsize);
+
+ rc = wmi_addba_rx_resp(wil, cid, tid, req->dialog_token, status,
+ agg_amsdu, agg_wsize, agg_timeout);
+ if (rc || (status != WLAN_STATUS_SUCCESS))
+ return;
+
+ /* apply */
+ r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
+ spin_lock_bh(&sta->tid_rx_lock);
+ wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
+ sta->tid_rx[tid] = r;
+ spin_unlock_bh(&sta->tid_rx_lock);
+}
+
+void wil_back_rx_flush(struct wil6210_priv *wil)
+{
+ struct wil_back_rx *evt, *t;
+
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
+ mutex_lock(&wil->back_rx_mutex);
+
+ list_for_each_entry_safe(evt, t, &wil->back_rx_pending, list) {
+ list_del(&evt->list);
+ kfree(evt);
+ }
+
+ mutex_unlock(&wil->back_rx_mutex);
+}
+
+/* Retrieve next ADDBA request from the pending list */
+static struct list_head *next_back_rx(struct wil6210_priv *wil)
+{
+ struct list_head *ret = NULL;
+
+ mutex_lock(&wil->back_rx_mutex);
+
+ if (!list_empty(&wil->back_rx_pending)) {
+ ret = wil->back_rx_pending.next;
+ list_del(ret);
+ }
+
+ mutex_unlock(&wil->back_rx_mutex);
+
+ return ret;
+}
+
+void wil_back_rx_worker(struct work_struct *work)
+{
+ struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+ back_rx_worker);
+ struct wil_back_rx *evt;
+ struct list_head *lh;
+
+ while ((lh = next_back_rx(wil)) != NULL) {
+ evt = list_entry(lh, struct wil_back_rx, list);
+
+ wil_back_rx_handle(wil, evt);
+ kfree(evt);
+ }
+}
+
+/* BACK - Tx (originator) side */
+static void wil_back_tx_handle(struct wil6210_priv *wil,
+ struct wil_back_tx *req)
+{
+ struct vring_tx_data *txdata = &wil->vring_tx_data[req->ringid];
+ int rc;
+
+ if (txdata->addba_in_progress) {
+ wil_dbg_misc(wil, "ADDBA for vring[%d] already in progress\n",
+ req->ringid);
+ return;
+ }
+ if (txdata->agg_wsize) {
+ wil_dbg_misc(wil,
+ "ADDBA for vring[%d] already established wsize %d\n",
+ req->ringid, txdata->agg_wsize);
+ return;
+ }
+ txdata->addba_in_progress = true;
+ rc = wmi_addba(wil, req->ringid, req->agg_wsize, req->agg_timeout);
+ if (rc)
+ txdata->addba_in_progress = false;
+}
+
+static struct list_head *next_back_tx(struct wil6210_priv *wil)
+{
+ struct list_head *ret = NULL;
+
+ mutex_lock(&wil->back_tx_mutex);
+
+ if (!list_empty(&wil->back_tx_pending)) {
+ ret = wil->back_tx_pending.next;
+ list_del(ret);
+ }
+
+ mutex_unlock(&wil->back_tx_mutex);
+
+ return ret;
+}
+
+void wil_back_tx_worker(struct work_struct *work)
+{
+ struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+ back_tx_worker);
+ struct wil_back_tx *evt;
+ struct list_head *lh;
+
+ while ((lh = next_back_tx(wil)) != NULL) {
+ evt = list_entry(lh, struct wil_back_tx, list);
+
+ wil_back_tx_handle(wil, evt);
+ kfree(evt);
+ }
+}
+
+void wil_back_tx_flush(struct wil6210_priv *wil)
+{
+ struct wil_back_tx *evt, *t;
+
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
+ mutex_lock(&wil->back_tx_mutex);
+
+ list_for_each_entry_safe(evt, t, &wil->back_tx_pending, list) {
+ list_del(&evt->list);
+ kfree(evt);
+ }
+
+ mutex_unlock(&wil->back_tx_mutex);
+}
+
+int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize)
+{
+ struct wil_back_tx *req = kzalloc(sizeof(*req), GFP_KERNEL);
+
+ if (!req)
+ return -ENOMEM;
+
+ req->ringid = ringid;
+ req->agg_wsize = wil_agg_size(wil, wsize);
+ req->agg_timeout = 0;
+
+ mutex_lock(&wil->back_tx_mutex);
+ list_add_tail(&req->list, &wil->back_tx_pending);
+ mutex_unlock(&wil->back_tx_mutex);
+
+ queue_work(wil->wq_service, &wil->back_tx_worker);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index e3f8bdce5abc..8439f65db259 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -463,7 +463,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
* and in case of error drop the packet
* higher stack layers will handle retransmission (if required)
*/
- if (d->dma.status & RX_DMA_STATUS_L4_IDENT) {
+ if (d->dma.status & RX_DMA_STATUS_L4I) {
/* L4 protocol identified, csum calculated */
if ((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0)
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -581,14 +581,8 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
skb->protocol = htons(ETH_P_802_2);
wil_netif_rx_any(skb, ndev);
} else {
- struct ethhdr *eth = (void *)skb->data;
-
skb->protocol = eth_type_trans(skb, ndev);
-
- if (is_unicast_ether_addr(eth->h_dest))
- wil_rx_reorder(wil, skb);
- else
- wil_netif_rx_any(skb, ndev);
+ wil_rx_reorder(wil, skb);
}
}
wil_rx_refill(wil, v->size);
@@ -645,7 +639,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
.vring_cfg = {
.tx_sw_ring = {
.max_mpdu_size =
- cpu_to_le16(mtu_max + ETH_HLEN),
+ cpu_to_le16(wil_mtu2macbuf(mtu_max)),
.ring_size = cpu_to_le16(size),
},
.ringid = id,
@@ -653,7 +647,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
.mac_ctrl = 0,
.to_resolution = 0,
- .agg_max_wsize = 16,
+ .agg_max_wsize = 0,
.schd_params = {
.priority = cpu_to_le16(0),
.timeslot_us = cpu_to_le16(0xfff),
@@ -677,6 +671,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
}
memset(txdata, 0, sizeof(*txdata));
+ spin_lock_init(&txdata->lock);
vring->size = size;
rc = wil_vring_alloc(wil, vring);
if (rc)
@@ -701,6 +696,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
txdata->enabled = 1;
+ if (wil->sta[cid].data_port_open && (agg_wsize >= 0))
+ wil_addba_tx_request(wil, id, agg_wsize);
return 0;
out_free:
@@ -713,6 +710,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
{
struct vring *vring = &wil->vring_tx[id];
+ struct vring_tx_data *txdata = &wil->vring_tx_data[id];
WARN_ON(!mutex_is_locked(&wil->mutex));
@@ -721,12 +719,15 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
wil_dbg_misc(wil, "%s() id=%d\n", __func__, id);
+ spin_lock_bh(&txdata->lock);
+ txdata->enabled = 0; /* no Tx can be in progress or start anew */
+ spin_unlock_bh(&txdata->lock);
/* make sure NAPI won't touch this vring */
- wil->vring_tx_data[id].enabled = 0;
- if (test_bit(wil_status_napi_en, &wil->status))
+ if (test_bit(wil_status_napi_en, wil->status))
napi_synchronize(&wil->napi_tx);
wil_vring_free(wil, vring, 1);
+ memset(txdata, 0, sizeof(*txdata));
}
static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
@@ -773,6 +774,38 @@ static void wil_set_da_for_vring(struct wil6210_priv *wil,
static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
struct sk_buff *skb);
+
+static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
+ struct sk_buff *skb)
+{
+ struct vring *v;
+ int i;
+ u8 cid;
+
+ /* In the STA mode, it is expected to have only 1 VRING
+ * for the AP we connected to.
+ * find 1-st vring and see whether it is eligible for data
+ */
+ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+ v = &wil->vring_tx[i];
+ if (!v->va)
+ continue;
+
+ cid = wil->vring2cid_tid[i][0];
+ if (!wil->sta[cid].data_port_open &&
+ (skb->protocol != cpu_to_be16(ETH_P_PAE)))
+ break;
+
+ wil_dbg_txrx(wil, "Tx -> ring %d\n", i);
+
+ return v;
+ }
+
+ wil_dbg_txrx(wil, "Tx while no vrings active?\n");
+
+ return NULL;
+}
+
/*
* Find 1-st vring and return it; set dest address for this vring in skb
* duplicate skb and send it to other active vrings
@@ -843,9 +876,6 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
d->mac.d[1] = 0;
d->mac.d[2] = 0;
d->mac.ucode_cmd = 0;
- /* use dst index 0 */
- d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS) |
- (0 << MAC_CFG_DESC_TX_1_DST_INDEX_POS);
/* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */
d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) |
(1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS);
@@ -908,8 +938,8 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,
return 0;
}
-static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
- struct sk_buff *skb)
+static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
+ struct sk_buff *skb)
{
struct device *dev = wil_to_dev(wil);
struct vring_tx_desc dd, *d = &dd;
@@ -925,18 +955,21 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
wil_dbg_txrx(wil, "%s()\n", __func__);
+ if (unlikely(!txdata->enabled))
+ return -EINVAL;
+
if (avail < 1 + nr_frags) {
wil_err_ratelimited(wil,
- "Tx ring full. No space for %d fragments\n",
- 1 + nr_frags);
+ "Tx ring[%2d] full. No space for %d fragments\n",
+ vring_index, 1 + nr_frags);
return -ENOMEM;
}
_d = &vring->va[i].tx;
pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
- wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb),
- skb->data, &pa);
+ wil_dbg_txrx(wil, "Tx[%2d] skb %d bytes 0x%p -> %pad\n", vring_index,
+ skb_headlen(skb), skb->data, &pa);
wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb_headlen(skb), false);
@@ -947,15 +980,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index);
/* Process TCP/UDP checksum offloading */
if (wil_tx_desc_offload_cksum_set(wil, d, skb)) {
- wil_err(wil, "VRING #%d Failed to set cksum, drop packet\n",
+ wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n",
vring_index);
goto dma_error;
}
vring->ctx[i].nr_frags = nr_frags;
wil_tx_desc_set_nr_frags(d, nr_frags);
- if (nr_frags)
- *_d = *d;
/* middle segments */
for (; f < nr_frags; f++) {
@@ -963,6 +994,10 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
&skb_shinfo(skb)->frags[f];
int len = skb_frag_size(frag);
+ *_d = *d;
+ wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i);
+ wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4,
+ (const void *)d, sizeof(*d), false);
i = (swhead + f + 1) % vring->size;
_d = &vring->va[i].tx;
pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
@@ -976,13 +1011,15 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
* it will succeed here too
*/
wil_tx_desc_offload_cksum_set(wil, d, skb);
- *_d = *d;
}
/* for the last seg only */
d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS);
d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_MARK_WB_POS);
d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS);
*_d = *d;
+ wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i);
+ wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4,
+ (const void *)d, sizeof(*d), false);
/* hold reference to skb
* to prevent skb release before accounting
@@ -990,15 +1027,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
*/
vring->ctx[i].skb = skb_get(skb);
- wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4,
- (const void *)d, sizeof(*d), false);
-
if (wil_vring_is_empty(vring)) /* performance monitoring */
txdata->idle += get_cycles() - txdata->last_idle;
/* advance swhead */
wil_vring_advance_head(vring, nr_frags + 1);
- wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead);
+ wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead,
+ vring->swhead);
trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags);
iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail));
@@ -1025,6 +1060,19 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
return -EINVAL;
}
+static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
+ struct sk_buff *skb)
+{
+ int vring_index = vring - wil->vring_tx;
+ struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index];
+ int rc;
+
+ spin_lock(&txdata->lock);
+ rc = __wil_tx_vring(wil, vring, skb);
+ spin_unlock(&txdata->lock);
+ return rc;
+}
+
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
@@ -1034,14 +1082,14 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
int rc;
wil_dbg_txrx(wil, "%s()\n", __func__);
- if (!test_bit(wil_status_fwready, &wil->status)) {
+ if (!test_bit(wil_status_fwready, wil->status)) {
if (!pr_once_fw) {
wil_err(wil, "FW not ready\n");
pr_once_fw = true;
}
goto drop;
}
- if (!test_bit(wil_status_fwconnected, &wil->status)) {
+ if (!test_bit(wil_status_fwconnected, wil->status)) {
wil_err(wil, "FW not connected\n");
goto drop;
}
@@ -1052,15 +1100,19 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
pr_once_fw = false;
/* find vring */
- if (is_unicast_ether_addr(eth->h_dest))
- vring = wil_find_tx_vring(wil, skb);
- else
- vring = wil_tx_bcast(wil, skb);
+ if (wil->wdev->iftype == NL80211_IFTYPE_STATION) {
+ /* in STA mode (ESS), all to same VRING */
+ vring = wil_find_tx_vring_sta(wil, skb);
+ } else { /* direct communication, find matching VRING */
+ if (is_unicast_ether_addr(eth->h_dest))
+ vring = wil_find_tx_vring(wil, skb);
+ else
+ vring = wil_tx_bcast(wil, skb);
+ }
if (!vring) {
wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest);
goto drop;
}
-
/* set up vring entry */
rc = wil_tx_vring(wil, vring, skb);
@@ -1087,6 +1139,22 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return NET_XMIT_DROP;
}
+static inline bool wil_need_txstat(struct sk_buff *skb)
+{
+ struct ethhdr *eth = (void *)skb->data;
+
+ return is_unicast_ether_addr(eth->h_dest) && skb->sk &&
+ (skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS);
+}
+
+static inline void wil_consume_skb(struct sk_buff *skb, bool acked)
+{
+ if (unlikely(wil_need_txstat(skb)))
+ skb_complete_wifi_ack(skb, acked);
+ else
+ acked ? dev_consume_skb_any(skb) : dev_kfree_skb_any(skb);
+}
+
/**
* Clean up transmitted skb's from the Tx VRING
*
@@ -1147,10 +1215,10 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
trace_wil6210_tx_done(ringid, vring->swtail, dmalen,
d->dma.error);
wil_dbg_txrx(wil,
- "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n",
- vring->swtail, dmalen, d->dma.status,
- d->dma.error);
- wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4,
+ "TxC[%2d][%3d] : %d bytes, status 0x%02x err 0x%02x\n",
+ ringid, vring->swtail, dmalen,
+ d->dma.status, d->dma.error);
+ wil_hex_dump_txrx("TxCD ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false);
wil_txdesc_unmap(dev, d, ctx);
@@ -1165,8 +1233,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
ndev->stats.tx_errors++;
stats->tx_errors++;
}
-
- dev_kfree_skb_any(skb);
+ wil_consume_skb(skb, d->dma.error == 0);
}
memset(ctx, 0, sizeof(*ctx));
/* There is no need to touch HW descriptor:
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index 630aeb5fa7f4..d90c8aa20c15 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -20,17 +20,15 @@
#define BUF_SW_OWNED (1)
#define BUF_HW_OWNED (0)
-/* size of max. Tx/Rx buffers, as supported by FW */
-#define TXRX_BUF_LEN_DEFAULT (2242)
+/* default size of MAC Tx/Rx buffers */
+#define TXRX_BUF_LEN_DEFAULT (2048)
/* how many bytes to reserve for rtap header? */
#define WIL6210_RTAP_SIZE (128)
/* Tx/Rx path */
-/*
- * Common representation of physical address in Vring
- */
+/* Common representation of physical address in Vring */
struct vring_dma_addr {
__le32 addr_low;
__le16 addr_high;
@@ -49,11 +47,10 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
addr->addr_high = cpu_to_le16((u16)upper_32_bits(pa));
}
-/*
- * Tx descriptor - MAC part
+/* Tx descriptor - MAC part
* [dword 0]
* bit 0.. 9 : lifetime_expiry_value:10
- * bit 10 : interrup_en:1
+ * bit 10 : interrupt_en:1
* bit 11 : status_en:1
* bit 12..13 : txss_override:2
* bit 14 : timestamp_insertion:1
@@ -61,15 +58,12 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
* bit 16..21 : reserved0:6
* bit 22..26 : mcs_index:5
* bit 27 : mcs_en:1
- * bit 28..29 : reserved1:2
- * bit 30 : reserved2:1
+ * bit 28..30 : reserved1:3
* bit 31 : sn_preserved:1
* [dword 1]
* bit 0.. 3 : pkt_mode:4
* bit 4 : pkt_mode_en:1
- * bit 5.. 7 : reserved0:3
- * bit 8..13 : reserved1:6
- * bit 14 : reserved2:1
+ * bit 5..14 : reserved0:10
* bit 15 : ack_policy_en:1
* bit 16..19 : dst_index:4
* bit 20 : dst_index_en:1
@@ -80,7 +74,7 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
* [dword 2]
* bit 0.. 7 : num_of_descriptors:8
* bit 8..17 : reserved:10
- * bit 18..19 : l2_translation_type:2
+ * bit 18..19 : l2_translation_type:2 00 - bypass, 01 - 802.3, 10 - 802.11
* bit 20 : snap_hdr_insertion_en:1
* bit 21 : vlan_removal_en:1
* bit 22..31 : reserved0:10
@@ -247,6 +241,46 @@ struct vring_tx_mac {
#define TX_DMA_STATUS_DU BIT(0)
+/* Tx descriptor - DMA part
+ * [dword 0]
+ * bit 0.. 7 : l4_length:8 layer 4 length
+ * bit 8 : cmd_eop:1 This descriptor is the last one in the packet
+ * bit 9 : reserved
+ * bit 10 : cmd_dma_it:1 immediate interrupt
+ * bit 11..12 : SBD - Segment Buffer Details
+ * 00 - Header Segment
+ * 01 - First Data Segment
+ * 10 - Medium Data Segment
+ * 11 - Last Data Segment
+ * bit 13 : TSE - TCP Segmentation Enable
+ * bit 14 : IIC - Directs the HW to Insert IPv4 Checksum
+ * bit 15 : ITC - Directs the HW to Insert TCP/UDP Checksum
+ * bit 16..20 : QID - The target QID that the packet should be stored
+ * in the MAC.
+ * bit 21 : PO - Pseudo header Offload:
+ * 0 - Use the pseudo header value from the TCP checksum field
+ * 1- Calculate Pseudo header Checksum
+ * bit 22 : NC - No UDP Checksum
+ * bit 23..29 : reserved
+ * bit 30..31 : L4T - Layer 4 Type: 00 - UDP , 10 - TCP , 10, 11 - Reserved
+ * If L4Len equal 0, no L4 at all
+ * [dword 1]
+ * bit 0..31 : addr_low:32 The payload buffer low address
+ * [dword 2]
+ * bit 0..15 : addr_high:16 The payload buffer high address
+ * bit 16..23 : ip_length:8 The IP header length for the TX IP checksum
+ * offload feature
+ * bit 24..30 : mac_length:7
+ * bit 31 : ip_version:1 1 - IPv4, 0 - IPv6
+ * [dword 3]
+ * [byte 12] error
+ * bit 0 2 : mac_status:3
+ * bit 3 7 : reserved:5
+ * [byte 13] status
+ * bit 0 : DU:1 Descriptor Used
+ * bit 1 7 : reserved:7
+ * [word 7] length
+ */
struct vring_tx_dma {
u32 d0;
struct vring_dma_addr addr;
@@ -257,45 +291,45 @@ struct vring_tx_dma {
__le16 length;
} __packed;
-/*
- * Rx descriptor - MAC part
+/* Rx descriptor - MAC part
* [dword 0]
* bit 0.. 3 : tid:4 The QoS (b3-0) TID Field
- * bit 4.. 6 : connection_id:3 :The Source index that was found during
- * Parsing the TA. This field is used to define the source of the packet
+ * bit 4.. 6 : cid:3 The Source index that was found during parsing the TA.
+ * This field is used to define the source of the packet
* bit 7 : reserved:1
- * bit 8.. 9 : mac_id:2 : The MAC virtual Ring number (always zero)
- * bit 10..11 : frame_type:2 : The FC Control (b3-2) - MPDU Type
- * (management, data, control and extension)
- * bit 12..15 : frame_subtype:4 : The FC Control (b7-4) - Frame Subtype
+ * bit 8.. 9 : mid:2 The MAC virtual number
+ * bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type
+ * (management, data, control and extension)
+ * bit 12..15 : frame_subtype:4 : The FC (b7-4) - Frame Subtype
* bit 16..27 : seq_number:12 The received Sequence number field
* bit 28..31 : extended:4 extended subtype
* [dword 1]
* bit 0.. 3 : reserved
* bit 4.. 5 : key_id:2
* bit 6 : decrypt_bypass:1
- * bit 7 : security:1
- * bit 8.. 9 : ds_bits:2
- * bit 10 : a_msdu_present:1 from qos header
- * bit 11 : a_msdu_type:1 from qos header
+ * bit 7 : security:1 FC (b14)
+ * bit 8.. 9 : ds_bits:2 FC (b9-8)
+ * bit 10 : a_msdu_present:1 QoS (b7)
+ * bit 11 : a_msdu_type:1 QoS (b8)
* bit 12 : a_mpdu:1 part of AMPDU aggregation
* bit 13 : broadcast:1
* bit 14 : mutlicast:1
* bit 15 : reserved:1
- * bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet
- * is received from
+ * bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet
+ * is received from
* bit 21..24 : mcs:4
- * bit 25..28 : mic_icr:4
+ * bit 25..28 : mic_icr:4 this signal tells the DMA to assert an interrupt
+ * after it writes the packet
* bit 29..31 : reserved:3
* [dword 2]
* bit 0.. 2 : time_slot:3 The timeslot that the MPDU is received
- * bit 3 : fc_protocol_ver:1 The FC Control (b0) - Protocol Version
- * bit 4 : fc_order:1 The FC Control (b15) -Order
- * bit 5.. 7 : qos_ack_policy:3 The QoS (b6-5) ack policy Field
+ * bit 3.. 4 : fc_protocol_ver:1 The FC (b1-0) - Protocol Version
+ * bit 5 : fc_order:1 The FC Control (b15) -Order
+ * bit 6.. 7 : qos_ack_policy:2 The QoS (b6-5) ack policy Field
* bit 8 : esop:1 The QoS (b4) ESOP field
- * bit 9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field
- * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field
- * bit 15 : qos_ac_constraint:1
+ * bit 9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field
+ * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field
+ * bit 15 : qos_ac_constraint:1 QoS (b15)
* bit 16..31 : pn_15_0:16 low 2 bytes of PN
* [dword 3]
* bit 0..31 : pn_47_16:32 high 4 bytes of PN
@@ -308,35 +342,46 @@ struct vring_rx_mac {
u32 pn_47_16;
} __packed;
-/*
- * Rx descriptor - DMA part
+/* Rx descriptor - DMA part
* [dword 0]
- * bit 0.. 7 : l4_length:8 layer 4 length
- * bit 8.. 9 : reserved:2
- * bit 10 : cmd_dma_it:1
+ * bit 0.. 7 : l4_length:8 layer 4 length. The field is only valid if
+ * L4I bit is set
+ * bit 8 : cmd_eop:1 set to 1
+ * bit 9 : cmd_rt:1 set to 1
+ * bit 10 : cmd_dma_it:1 immediate interrupt
* bit 11..15 : reserved:5
- * bit 16..29 : phy_info_length:14
+ * bit 16..29 : phy_info_length:14 It is valid when the PII is set.
+ * When the FFM bit is set bits 29-27 are used for for
+ * Flex Filter Match. Matching Index to one of the L2
+ * EtherType Flex Filter
* bit 30..31 : l4_type:2 valid if the L4I bit is set in the status field
+ * 00 - UDP, 01 - TCP, 10, 11 - reserved
* [dword 1]
* bit 0..31 : addr_low:32 The payload buffer low address
* [dword 2]
* bit 0..15 : addr_high:16 The payload buffer high address
- * bit 16..23 : ip_length:8
+ * bit 16..23 : ip_length:8 The filed is valid only if the L3I bit is set
* bit 24..30 : mac_length:7
- * bit 31 : ip_version:1
+ * bit 31 : ip_version:1 1 - IPv4, 0 - IPv6
* [dword 3]
* [byte 12] error
+ * bit 0 : FCS:1
+ * bit 1 : MIC:1
+ * bit 2 : Key miss:1
+ * bit 3 : Replay:1
+ * bit 4 : L3:1 IPv4 checksum
+ * bit 5 : L4:1 TCP/UDP checksum
+ * bit 6 7 : reserved:2
* [byte 13] status
- * bit 0 : du:1
- * bit 1 : eop:1
+ * bit 0 : DU:1 Descriptor Used
+ * bit 1 : EOP:1 The descriptor indicates the End of Packet
* bit 2 : error:1
- * bit 3 : mi:1
- * bit 4 : l3_identified:1
- * bit 5 : l4_identified:1
- * bit 6 : phy_info_included:1
- * bit 7 : reserved:1
+ * bit 3 : MI:1 MAC Interrupt is asserted (according to parser decision)
+ * bit 4 : L3I:1 L3 identified and checksum calculated
+ * bit 5 : L4I:1 L4 identified and checksum calculated
+ * bit 6 : PII:1 PHY Info Included in the packet
+ * bit 7 : FFM:1 EtherType Flex Filter Match
* [word 7] length
- *
*/
#define RX_DMA_D0_CMD_DMA_IT BIT(10)
@@ -349,9 +394,9 @@ struct vring_rx_mac {
#define RX_DMA_STATUS_DU BIT(0)
#define RX_DMA_STATUS_ERROR BIT(2)
-#define RX_DMA_STATUS_L3_IDENT BIT(4)
-#define RX_DMA_STATUS_L4_IDENT BIT(5)
-#define RX_DMA_STATUS_PHY_INFO BIT(6)
+#define RX_DMA_STATUS_L3I BIT(4)
+#define RX_DMA_STATUS_L4I BIT(5)
+#define RX_DMA_STATUS_PHY_INFO BIT(6)
struct vring_rx_dma {
u32 d0;
@@ -423,6 +468,11 @@ static inline int wil_rxdesc_mcs(struct vring_rx_desc *d)
return WIL_GET_BITS(d->mac.d1, 21, 24);
}
+static inline int wil_rxdesc_mcast(struct vring_rx_desc *d)
+{
+ return WIL_GET_BITS(d->mac.d1, 13, 14);
+}
+
static inline int wil_rxdesc_phy_length(struct vring_rx_desc *d)
{
return WIL_GET_BITS(d->dma.d0, 16, 29);
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index c6ec5b99ac7d..94611568fc9a 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -25,19 +25,14 @@
extern bool no_fw_recovery;
extern unsigned int mtu_max;
+extern unsigned short rx_ring_overflow_thrsh;
+extern int agg_wsize;
#define WIL_NAME "wil6210"
#define WIL_FW_NAME "wil6210.fw"
#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
-struct wil_board {
- int board;
-#define WIL_BOARD_MARLON (1)
-#define WIL_BOARD_SPARROW (2)
- const char * const name;
-};
-
/**
* extract bits [@b0:@b1] (inclusive) from the value @x
* it should be @b0 <= @b1, or result is incorrect
@@ -49,21 +44,50 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
#define WIL6210_MEM_SIZE (2*1024*1024UL)
-#define WIL_RX_RING_SIZE_ORDER_DEFAULT (9)
-#define WIL_TX_RING_SIZE_ORDER_DEFAULT (9)
+#define WIL_TX_Q_LEN_DEFAULT (4000)
+#define WIL_RX_RING_SIZE_ORDER_DEFAULT (10)
+#define WIL_TX_RING_SIZE_ORDER_DEFAULT (10)
/* limit ring size in range [32..32k] */
#define WIL_RING_SIZE_ORDER_MIN (5)
#define WIL_RING_SIZE_ORDER_MAX (15)
#define WIL6210_MAX_TX_RINGS (24) /* HW limit */
#define WIL6210_MAX_CID (8) /* HW limit */
#define WIL6210_NAPI_BUDGET (16) /* arbitrary */
+#define WIL_MAX_AMPDU_SIZE (64 * 1024) /* FW/HW limit */
+#define WIL_MAX_AGG_WSIZE (32) /* FW/HW limit */
+/* Hardware offload block adds the following:
+ * 26 bytes - 3-address QoS data header
+ * 8 bytes - IV + EIV (for GCMP)
+ * 8 bytes - SNAP
+ * 16 bytes - MIC (for GCMP)
+ * 4 bytes - CRC
+ */
+#define WIL_MAX_MPDU_OVERHEAD (62)
+
+/* Calculate MAC buffer size for the firmware. It includes all overhead,
+ * as it will go over the air, and need to be 8 byte aligned
+ */
+static inline u32 wil_mtu2macbuf(u32 mtu)
+{
+ return ALIGN(mtu + WIL_MAX_MPDU_OVERHEAD, 8);
+}
+
+/* MTU for Ethernet need to take into account 8-byte SNAP header
+ * to be added when encapsulating Ethernet frame into 802.11
+ */
+#define WIL_MAX_ETH_MTU (IEEE80211_MAX_DATA_LEN_DMG - 8)
/* Max supported by wil6210 value for interrupt threshold is 5sec. */
#define WIL6210_ITR_TRSH_MAX (5000000)
-#define WIL6210_ITR_TRSH_DEFAULT (300) /* usec */
+#define WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */
+#define WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */
+#define WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT (500) /* usec */
+#define WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT (500) /* usec */
#define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */
#define WIL6210_FW_RECOVERY_TO msecs_to_jiffies(5000)
#define WIL6210_SCAN_TO msecs_to_jiffies(10000)
-
+#define WIL6210_RX_HIGH_TRSH_INIT (0)
+#define WIL6210_RX_HIGH_TRSH_DEFAULT \
+ (1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3))
/* Hardware definitions begin */
/*
@@ -135,7 +159,7 @@ struct RGF_ICR {
#define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1)
#define BIT_DMA_EP_MISC_ICR_FW_INT(n) BIT(28+n) /* n = [0..3] */
-/* Interrupt moderation control */
+/* Legacy interrupt moderation control (before Sparrow v2)*/
#define RGF_DMA_ITR_CNT_TRSH (0x881c5c)
#define RGF_DMA_ITR_CNT_DATA (0x881c60)
#define RGF_DMA_ITR_CNT_CRL (0x881c64)
@@ -145,6 +169,46 @@ struct RGF_ICR {
#define BIT_DMA_ITR_CNT_CRL_CLR BIT(3)
#define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4)
+/* New (sparrow v2+) interrupt moderation control */
+#define RGF_DMA_ITR_TX_DESQ_NO_MOD (0x881d40)
+#define RGF_DMA_ITR_TX_CNT_TRSH (0x881d34)
+#define RGF_DMA_ITR_TX_CNT_DATA (0x881d38)
+#define RGF_DMA_ITR_TX_CNT_CTL (0x881d3c)
+ #define BIT_DMA_ITR_TX_CNT_CTL_EN BIT(0)
+ #define BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL BIT(1)
+ #define BIT_DMA_ITR_TX_CNT_CTL_FOREVER BIT(2)
+ #define BIT_DMA_ITR_TX_CNT_CTL_CLR BIT(3)
+ #define BIT_DMA_ITR_TX_CNT_CTL_REACHED_TRESH BIT(4)
+ #define BIT_DMA_ITR_TX_CNT_CTL_CROSS_EN BIT(5)
+ #define BIT_DMA_ITR_TX_CNT_CTL_FREE_RUNNIG BIT(6)
+#define RGF_DMA_ITR_TX_IDL_CNT_TRSH (0x881d60)
+#define RGF_DMA_ITR_TX_IDL_CNT_DATA (0x881d64)
+#define RGF_DMA_ITR_TX_IDL_CNT_CTL (0x881d68)
+ #define BIT_DMA_ITR_TX_IDL_CNT_CTL_EN BIT(0)
+ #define BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL BIT(1)
+ #define BIT_DMA_ITR_TX_IDL_CNT_CTL_FOREVER BIT(2)
+ #define BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR BIT(3)
+ #define BIT_DMA_ITR_TX_IDL_CNT_CTL_REACHED_TRESH BIT(4)
+#define RGF_DMA_ITR_RX_DESQ_NO_MOD (0x881d50)
+#define RGF_DMA_ITR_RX_CNT_TRSH (0x881d44)
+#define RGF_DMA_ITR_RX_CNT_DATA (0x881d48)
+#define RGF_DMA_ITR_RX_CNT_CTL (0x881d4c)
+ #define BIT_DMA_ITR_RX_CNT_CTL_EN BIT(0)
+ #define BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL BIT(1)
+ #define BIT_DMA_ITR_RX_CNT_CTL_FOREVER BIT(2)
+ #define BIT_DMA_ITR_RX_CNT_CTL_CLR BIT(3)
+ #define BIT_DMA_ITR_RX_CNT_CTL_REACHED_TRESH BIT(4)
+ #define BIT_DMA_ITR_RX_CNT_CTL_CROSS_EN BIT(5)
+ #define BIT_DMA_ITR_RX_CNT_CTL_FREE_RUNNIG BIT(6)
+#define RGF_DMA_ITR_RX_IDL_CNT_TRSH (0x881d54)
+#define RGF_DMA_ITR_RX_IDL_CNT_DATA (0x881d58)
+#define RGF_DMA_ITR_RX_IDL_CNT_CTL (0x881d5c)
+ #define BIT_DMA_ITR_RX_IDL_CNT_CTL_EN BIT(0)
+ #define BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL BIT(1)
+ #define BIT_DMA_ITR_RX_IDL_CNT_CTL_FOREVER BIT(2)
+ #define BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR BIT(3)
+ #define BIT_DMA_ITR_RX_IDL_CNT_CTL_REACHED_TRESH BIT(4)
+
#define RGF_DMA_PSEUDO_CAUSE (0x881c68)
#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c)
#define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70)
@@ -164,6 +228,20 @@ struct RGF_ICR {
#define RGF_CAF_PLL_LOCK_STATUS (0x88afec)
#define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0)
+#define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */
+ #define JTAG_DEV_ID_MARLON_B0 (0x0612072f)
+ #define JTAG_DEV_ID_SPARROW_A0 (0x0632072f)
+ #define JTAG_DEV_ID_SPARROW_A1 (0x1632072f)
+ #define JTAG_DEV_ID_SPARROW_B0 (0x2632072f)
+
+enum {
+ HW_VER_UNKNOWN,
+ HW_VER_MARLON_B0, /* JTAG_DEV_ID_MARLON_B0 */
+ HW_VER_SPARROW_A0, /* JTAG_DEV_ID_SPARROW_A0 */
+ HW_VER_SPARROW_A1, /* JTAG_DEV_ID_SPARROW_A1 */
+ HW_VER_SPARROW_B0, /* JTAG_DEV_ID_SPARROW_B0 */
+};
+
/* popular locations */
#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
@@ -303,6 +381,11 @@ struct vring {
struct vring_tx_data {
int enabled;
cycles_t idle, last_idle, begin;
+ u8 agg_wsize; /* agreed aggregation window, 0 - no agg */
+ u16 agg_timeout;
+ u8 agg_amsdu;
+ bool addba_in_progress; /* if set, agg_xxx is for request in progress */
+ spinlock_t lock;
};
enum { /* for wil6210_priv.status */
@@ -313,6 +396,7 @@ enum { /* for wil6210_priv.status */
wil_status_reset_done,
wil_status_irqen, /* FIXME: interrupts enabled - for debug */
wil_status_napi_en, /* NAPI enabled protected by wil->mutex */
+ wil_status_last /* keep last */
};
struct pci_dev;
@@ -397,15 +481,46 @@ enum {
fw_recovery_running = 2,
};
+enum {
+ hw_capability_reset_v2 = 0,
+ hw_capability_advanced_itr_moderation = 1,
+ hw_capability_last
+};
+
+struct wil_back_rx {
+ struct list_head list;
+ /* request params, converted to CPU byte order - what we asked for */
+ u8 cidxtid;
+ u8 dialog_token;
+ u16 ba_param_set;
+ u16 ba_timeout;
+ u16 ba_seq_ctrl;
+};
+
+struct wil_back_tx {
+ struct list_head list;
+ /* request params, converted to CPU byte order - what we asked for */
+ u8 ringid;
+ u8 agg_wsize;
+ u16 agg_timeout;
+};
+
+struct wil_probe_client_req {
+ struct list_head list;
+ u64 cookie;
+ u8 cid;
+};
+
struct wil6210_priv {
struct pci_dev *pdev;
int n_msi;
struct wireless_dev *wdev;
void __iomem *csr;
- ulong status;
+ DECLARE_BITMAP(status, wil_status_last);
u32 fw_version;
u32 hw_version;
- struct wil_board *board;
+ const char *hw_name;
+ DECLARE_BITMAP(hw_capabilities, hw_capability_last);
u8 n_mids; /* number of additional MIDs as reported by FW */
u32 recovery_count; /* num of FW recovery attempts in a short time */
u32 recovery_state; /* FW recovery state machine */
@@ -415,7 +530,11 @@ struct wil6210_priv {
u32 monitor_flags;
u32 secure_pcp; /* create secure PCP? */
int sinfo_gen;
- u32 itr_trsh;
+ /* interrupt moderation */
+ u32 tx_max_burst_duration;
+ u32 tx_interframe_timeout;
+ u32 rx_max_burst_duration;
+ u32 rx_interframe_timeout;
/* cached ISR registers */
u32 isr_misc;
/* mailbox related */
@@ -429,7 +548,7 @@ struct wil6210_priv {
u16 reply_size;
struct workqueue_struct *wmi_wq; /* for deferred calls */
struct work_struct wmi_event_worker;
- struct workqueue_struct *wmi_wq_conn; /* for connect worker */
+ struct workqueue_struct *wq_service;
struct work_struct connect_worker;
struct work_struct disconnect_worker;
struct work_struct fw_error_worker; /* for FW error recovery */
@@ -445,6 +564,17 @@ struct wil6210_priv {
spinlock_t wmi_ev_lock;
struct napi_struct napi_rx;
struct napi_struct napi_tx;
+ /* BACK */
+ struct list_head back_rx_pending;
+ struct mutex back_rx_mutex; /* protect @back_rx_pending */
+ struct work_struct back_rx_worker;
+ struct list_head back_tx_pending;
+ struct mutex back_tx_mutex; /* protect @back_tx_pending */
+ struct work_struct back_tx_worker;
+ /* keep alive */
+ struct list_head probe_client_pending;
+ struct mutex probe_client_mutex; /* protect @probe_client_pending */
+ struct work_struct probe_client_worker;
/* DMA related */
struct vring vring_rx;
struct vring vring_tx[WIL6210_MAX_TX_RINGS];
@@ -529,11 +659,8 @@ void wil_if_remove(struct wil6210_priv *wil);
int wil_priv_init(struct wil6210_priv *wil);
void wil_priv_deinit(struct wil6210_priv *wil);
int wil_reset(struct wil6210_priv *wil);
-void wil_set_itr_trsh(struct wil6210_priv *wil);
void wil_fw_error_recovery(struct wil6210_priv *wil);
void wil_set_recovery_state(struct wil6210_priv *wil, int state);
-void wil_link_on(struct wil6210_priv *wil);
-void wil_link_off(struct wil6210_priv *wil);
int wil_up(struct wil6210_priv *wil);
int __wil_up(struct wil6210_priv *wil);
int wil_down(struct wil6210_priv *wil);
@@ -567,12 +694,26 @@ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel);
int wmi_rxon(struct wil6210_priv *wil, bool on);
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason);
+int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout);
+int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason);
+int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason);
+int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
+ u16 status, bool amsdu, u16 agg_wsize, u16 timeout);
+int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
+ u8 dialog_token, __le16 ba_param_set,
+ __le16 ba_timeout, __le16 ba_seq_ctrl);
+void wil_back_rx_worker(struct work_struct *work);
+void wil_back_rx_flush(struct wil6210_priv *wil);
+int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize);
+void wil_back_tx_worker(struct work_struct *work);
+void wil_back_tx_flush(struct wil6210_priv *wil);
void wil6210_clear_irq(struct wil6210_priv *wil);
int wil6210_init_irq(struct wil6210_priv *wil, int irq);
void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
void wil_mask_irq(struct wil6210_priv *wil);
void wil_unmask_irq(struct wil6210_priv *wil);
+void wil_configure_interrupt_moderation(struct wil6210_priv *wil);
void wil_disable_irq(struct wil6210_priv *wil);
void wil_enable_irq(struct wil6210_priv *wil);
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
@@ -592,6 +733,8 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
int wmi_pcp_stop(struct wil6210_priv *wil);
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
u16 reason_code, bool from_event);
+void wil_probe_client_flush(struct wil6210_priv *wil);
+void wil_probe_client_worker(struct work_struct *work);
int wil_rx_init(struct wil6210_priv *wil, u16 size);
void wil_rx_fini(struct wil6210_priv *wil);
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c
index 8f1d78f8a74d..976a071ba74e 100644
--- a/drivers/net/wireless/ath/wil6210/wil_platform.c
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.c
@@ -17,10 +17,6 @@
#include "linux/device.h"
#include "wil_platform.h"
-#ifdef CONFIG_WIL6210_PLATFORM_MSM
-#include "wil_platform_msm.h"
-#endif
-
/**
* wil_platform_init() - wil6210 platform module init
*
@@ -37,13 +33,7 @@ void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops)
return NULL;
}
-#ifdef CONFIG_WIL6210_PLATFORM_MSM
- handle = wil_platform_msm_init(dev, ops);
- if (handle)
- return handle;
-#endif
-
- /* other platform specific init functions should be called here */
+ /* platform specific init functions should be called here */
return handle;
}
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.c b/drivers/net/wireless/ath/wil6210/wil_platform_msm.c
deleted file mode 100644
index b354a743240d..000000000000
--- a/drivers/net/wireless/ath/wil6210/wil_platform_msm.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (c) 2014 Qualcomm Atheros, Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/of.h>
-#include <linux/slab.h>
-#include <linux/msm-bus.h>
-
-#include "wil_platform.h"
-#include "wil_platform_msm.h"
-
-/**
- * struct wil_platform_msm - wil6210 msm platform module info
- *
- * @dev: device object
- * @msm_bus_handle: handle for using msm_bus API
- * @pdata: bus scale info retrieved from DT
- */
-struct wil_platform_msm {
- struct device *dev;
- uint32_t msm_bus_handle;
- struct msm_bus_scale_pdata *pdata;
-};
-
-#define KBTOB(a) (a * 1000ULL)
-
-/**
- * wil_platform_get_pdata() - Generate bus client data from device tree
- * provided by clients.
- *
- * dev: device object
- * of_node: Device tree node to extract information from
- *
- * The function returns a valid pointer to the allocated bus-scale-pdata
- * if the vectors were correctly read from the client's device node.
- * Any error in reading or parsing the device node will return NULL
- * to the caller.
- */
-static struct msm_bus_scale_pdata *wil_platform_get_pdata(
- struct device *dev,
- struct device_node *of_node)
-{
- struct msm_bus_scale_pdata *pdata;
- struct msm_bus_paths *usecase;
- int i, j, ret, len;
- unsigned int num_usecases, num_paths, mem_size;
- const uint32_t *vec_arr;
- struct msm_bus_vectors *vectors;
-
- /* first read num_usecases and num_paths so we can calculate
- * amount of memory to allocate
- */
- ret = of_property_read_u32(of_node, "qcom,msm-bus,num-cases",
- &num_usecases);
- if (ret) {
- dev_err(dev, "Error: num-usecases not found\n");
- return NULL;
- }
-
- ret = of_property_read_u32(of_node, "qcom,msm-bus,num-paths",
- &num_paths);
- if (ret) {
- dev_err(dev, "Error: num_paths not found\n");
- return NULL;
- }
-
- /* pdata memory layout:
- * msm_bus_scale_pdata
- * msm_bus_paths[num_usecases]
- * msm_bus_vectors[num_usecases][num_paths]
- */
- mem_size = sizeof(struct msm_bus_scale_pdata) +
- sizeof(struct msm_bus_paths) * num_usecases +
- sizeof(struct msm_bus_vectors) * num_usecases * num_paths;
-
- pdata = kzalloc(mem_size, GFP_KERNEL);
- if (!pdata)
- return NULL;
-
- ret = of_property_read_string(of_node, "qcom,msm-bus,name",
- &pdata->name);
- if (ret) {
- dev_err(dev, "Error: Client name not found\n");
- goto err;
- }
-
- if (of_property_read_bool(of_node, "qcom,msm-bus,active-only")) {
- pdata->active_only = 1;
- } else {
- dev_info(dev, "active_only flag absent.\n");
- dev_info(dev, "Using dual context by default\n");
- }
-
- pdata->num_usecases = num_usecases;
- pdata->usecase = (struct msm_bus_paths *)(pdata + 1);
-
- vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len);
- if (vec_arr == NULL) {
- dev_err(dev, "Error: Vector array not found\n");
- goto err;
- }
-
- if (len != num_usecases * num_paths * sizeof(uint32_t) * 4) {
- dev_err(dev, "Error: Length-error on getting vectors\n");
- goto err;
- }
-
- vectors = (struct msm_bus_vectors *)(pdata->usecase + num_usecases);
- for (i = 0; i < num_usecases; i++) {
- usecase = &pdata->usecase[i];
- usecase->num_paths = num_paths;
- usecase->vectors = &vectors[i];
-
- for (j = 0; j < num_paths; j++) {
- int index = ((i * num_paths) + j) * 4;
-
- usecase->vectors[j].src = be32_to_cpu(vec_arr[index]);
- usecase->vectors[j].dst =
- be32_to_cpu(vec_arr[index + 1]);
- usecase->vectors[j].ab = (uint64_t)
- KBTOB(be32_to_cpu(vec_arr[index + 2]));
- usecase->vectors[j].ib = (uint64_t)
- KBTOB(be32_to_cpu(vec_arr[index + 3]));
- }
- }
-
- return pdata;
-
-err:
- kfree(pdata);
-
- return NULL;
-}
-
-/* wil_platform API (callbacks) */
-
-static int wil_platform_bus_request(void *handle,
- uint32_t kbps /* KBytes/Sec */)
-{
- int rc, i;
- struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
- int vote = 0; /* vote 0 in case requested kbps cannot be satisfied */
- struct msm_bus_paths *usecase;
- uint32_t usecase_kbps;
- uint32_t min_kbps = ~0;
-
- /* find the lowest usecase that is bigger than requested kbps */
- for (i = 0; i < msm->pdata->num_usecases; i++) {
- usecase = &msm->pdata->usecase[i];
- /* assume we have single path (vectors[0]). If we ever
- * have multiple paths, need to define the behavior */
- usecase_kbps = div64_u64(usecase->vectors[0].ib, 1000);
- if (usecase_kbps >= kbps && usecase_kbps < min_kbps) {
- min_kbps = usecase_kbps;
- vote = i;
- }
- }
-
- rc = msm_bus_scale_client_update_request(msm->msm_bus_handle, vote);
- if (rc)
- dev_err(msm->dev, "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n",
- kbps, vote, rc);
- else
- /* TOOD: remove */
- dev_info(msm->dev, "msm_bus_scale_client_update_request succeeded. kbps=%d vote=%d\n",
- kbps, vote);
-
- return rc;
-}
-
-static void wil_platform_uninit(void *handle)
-{
- struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
-
- dev_info(msm->dev, "wil_platform_uninit\n");
-
- if (msm->msm_bus_handle)
- msm_bus_scale_unregister_client(msm->msm_bus_handle);
-
- kfree(msm->pdata);
- kfree(msm);
-}
-
-static int wil_platform_msm_bus_register(struct wil_platform_msm *msm,
- struct device_node *node)
-{
- msm->pdata = wil_platform_get_pdata(msm->dev, node);
- if (!msm->pdata) {
- dev_err(msm->dev, "Failed getting DT info\n");
- return -EINVAL;
- }
-
- msm->msm_bus_handle = msm_bus_scale_register_client(msm->pdata);
- if (!msm->msm_bus_handle) {
- dev_err(msm->dev, "Failed msm_bus registration\n");
- return -EINVAL;
- }
-
- dev_info(msm->dev, "msm_bus registration succeeded! handle 0x%x\n",
- msm->msm_bus_handle);
-
- return 0;
-}
-
-/**
- * wil_platform_msm_init() - wil6210 msm platform module init
- *
- * The function must be called before all other functions in this module.
- * It returns a handle which is used with the rest of the API
- *
- */
-void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops)
-{
- struct device_node *of_node;
- struct wil_platform_msm *msm;
- int rc;
-
- of_node = of_find_compatible_node(NULL, NULL, "qcom,wil6210");
- if (!of_node) {
- /* this could mean non-msm platform */
- dev_err(dev, "DT node not found\n");
- return NULL;
- }
-
- msm = kzalloc(sizeof(*msm), GFP_KERNEL);
- if (!msm)
- return NULL;
-
- msm->dev = dev;
-
- /* register with msm_bus module for scaling requests */
- rc = wil_platform_msm_bus_register(msm, of_node);
- if (rc)
- goto cleanup;
-
- memset(ops, 0, sizeof(*ops));
- ops->bus_request = wil_platform_bus_request;
- ops->uninit = wil_platform_uninit;
-
- return (void *)msm;
-
-cleanup:
- kfree(msm);
- return NULL;
-}
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.h b/drivers/net/wireless/ath/wil6210/wil_platform_msm.h
deleted file mode 100644
index 2f2229edb498..000000000000
--- a/drivers/net/wireless/ath/wil6210/wil_platform_msm.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2014 Qualcomm Atheros, Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef __WIL_PLATFORM__MSM_H__
-#define __WIL_PLATFORM_MSM_H__
-
-#include "wil_platform.h"
-
-void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops);
-
-#endif /* __WIL_PLATFORM__MSM_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 63476c86cd0e..0f3e4334c8e3 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -23,10 +23,15 @@
#include "wmi.h"
#include "trace.h"
-static uint max_assoc_sta = 1;
+static uint max_assoc_sta = WIL6210_MAX_CID;
module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
+int agg_wsize; /* = 0; */
+module_param(agg_wsize, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;"
+ " 0 - use default; < 0 - don't auto-establish");
+
/**
* WMI event receiving - theory of operations
*
@@ -197,7 +202,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
might_sleep();
- if (!test_bit(wil_status_fwready, &wil->status)) {
+ if (!test_bit(wil_status_fwready, wil->status)) {
wil_err(wil, "WMI: cannot send command while FW not ready\n");
return -EAGAIN;
}
@@ -300,7 +305,7 @@ static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
wil_dbg_wmi(wil, "WMI: got FW ready event\n");
wil_set_recovery_state(wil, fw_recovery_idle);
- set_bit(wil_status_fwready, &wil->status);
+ set_bit(wil_status_fwready, wil->status);
/* let the reset sequence continue */
complete(&wil->wmi_ready);
}
@@ -438,7 +443,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
- if (!test_bit(wil_status_fwconnecting, &wil->status)) {
+ if (!test_bit(wil_status_fwconnecting, wil->status)) {
wil_err(wil, "Not in connecting state\n");
return;
}
@@ -457,13 +462,12 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
if (assoc_req_ie) {
sinfo.assoc_req_ies = assoc_req_ie;
sinfo.assoc_req_ies_len = assoc_req_ielen;
- sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
}
cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
}
- clear_bit(wil_status_fwconnecting, &wil->status);
- set_bit(wil_status_fwconnected, &wil->status);
+ clear_bit(wil_status_fwconnecting, wil->status);
+ set_bit(wil_status_fwconnected, wil->status);
/* FIXME FW can transmit only ucast frames to peer */
/* FIXME real ring_id instead of hard coded 0 */
@@ -471,7 +475,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
wil->sta[evt->cid].status = wil_sta_conn_pending;
wil->pending_connect_cid = evt->cid;
- queue_work(wil->wmi_wq_conn, &wil->connect_worker);
+ queue_work(wil->wq_service, &wil->connect_worker);
}
static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
@@ -544,9 +548,24 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
}
}
+static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid, u16 wsize)
+{
+ struct vring_tx_data *t;
+ int i;
+
+ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+ if (cid != wil->vring2cid_tid[i][0])
+ continue;
+ t = &wil->vring_tx_data[i];
+ if (!t->enabled)
+ continue;
+
+ wil_addba_tx_request(wil, i, wsize);
+ }
+}
+
static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
{
- struct net_device *ndev = wil_to_ndev(wil);
struct wmi_data_port_open_event *evt = d;
u8 cid = evt->cid;
@@ -558,7 +577,8 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
}
wil->sta[cid].data_port_open = true;
- netif_carrier_on(ndev);
+ if (agg_wsize >= 0)
+ wil_addba_tx_cid(wil, cid, agg_wsize);
}
static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len)
@@ -583,55 +603,89 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
int len)
{
struct wmi_vring_ba_status_event *evt = d;
- struct wil_sta_info *sta;
- uint i, cid;
+ struct vring_tx_data *txdata;
- /* TODO: use Rx BA status, not Tx one */
-
- wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n",
+ wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d AMSDU%s\n",
evt->ringid,
evt->status == WMI_BA_AGREED ? "OK" : "N/A",
- evt->agg_wsize, __le16_to_cpu(evt->ba_timeout));
+ evt->agg_wsize, __le16_to_cpu(evt->ba_timeout),
+ evt->amsdu ? "+" : "-");
if (evt->ringid >= WIL6210_MAX_TX_RINGS) {
wil_err(wil, "invalid ring id %d\n", evt->ringid);
return;
}
- mutex_lock(&wil->mutex);
-
- cid = wil->vring2cid_tid[evt->ringid][0];
- if (cid >= WIL6210_MAX_CID) {
- wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid);
- goto out;
+ if (evt->status != WMI_BA_AGREED) {
+ evt->ba_timeout = 0;
+ evt->agg_wsize = 0;
+ evt->amsdu = 0;
}
- sta = &wil->sta[cid];
- if (sta->status == wil_sta_unused) {
- wil_err(wil, "CID %d unused\n", cid);
- goto out;
- }
+ txdata = &wil->vring_tx_data[evt->ringid];
- wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr);
- for (i = 0; i < WIL_STA_TID_NUM; i++) {
- struct wil_tid_ampdu_rx *r;
- unsigned long flags;
+ txdata->agg_timeout = le16_to_cpu(evt->ba_timeout);
+ txdata->agg_wsize = evt->agg_wsize;
+ txdata->agg_amsdu = evt->amsdu;
+ txdata->addba_in_progress = false;
+}
- spin_lock_irqsave(&sta->tid_rx_lock, flags);
+static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d,
+ int len)
+{
+ struct wmi_rcp_addba_req_event *evt = d;
- r = sta->tid_rx[i];
- sta->tid_rx[i] = NULL;
- wil_tid_ampdu_rx_free(wil, r);
+ wil_addba_rx_request(wil, evt->cidxtid, evt->dialog_token,
+ evt->ba_param_set, evt->ba_timeout,
+ evt->ba_seq_ctrl);
+}
- spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len)
+__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
+{
+ struct wmi_delba_event *evt = d;
+ u8 cid, tid;
+ u16 reason = __le16_to_cpu(evt->reason);
+ struct wil_sta_info *sta;
+ struct wil_tid_ampdu_rx *r;
- if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize)
- sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil,
- evt->agg_wsize, 0);
+ might_sleep();
+ parse_cidxtid(evt->cidxtid, &cid, &tid);
+ wil_dbg_wmi(wil, "DELBA CID %d TID %d from %s reason %d\n",
+ cid, tid,
+ evt->from_initiator ? "originator" : "recipient",
+ reason);
+ if (!evt->from_initiator) {
+ int i;
+ /* find Tx vring it belongs to */
+ for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
+ if ((wil->vring2cid_tid[i][0] == cid) &&
+ (wil->vring2cid_tid[i][1] == tid)) {
+ struct vring_tx_data *txdata =
+ &wil->vring_tx_data[i];
+
+ wil_dbg_wmi(wil, "DELBA Tx vring %d\n", i);
+ txdata->agg_timeout = 0;
+ txdata->agg_wsize = 0;
+ txdata->addba_in_progress = false;
+
+ break; /* max. 1 matching ring */
+ }
+ }
+ if (i >= ARRAY_SIZE(wil->vring2cid_tid))
+ wil_err(wil, "DELBA: unable to find Tx vring\n");
+ return;
}
-out:
- mutex_unlock(&wil->mutex);
+ sta = &wil->sta[cid];
+
+ spin_lock_bh(&sta->tid_rx_lock);
+
+ r = sta->tid_rx[tid];
+ sta->tid_rx[tid] = NULL;
+ wil_tid_ampdu_rx_free(wil, r);
+
+ spin_unlock_bh(&sta->tid_rx_lock);
}
static const struct {
@@ -649,6 +703,8 @@ static const struct {
{WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup},
{WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown},
{WMI_BA_STATUS_EVENTID, wmi_evt_ba_status},
+ {WMI_RCP_ADDBA_REQ_EVENTID, wmi_evt_addba_rx_req},
+ {WMI_DELBA_EVENTID, wmi_evt_delba},
};
/*
@@ -668,7 +724,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
ulong flags;
unsigned n;
- if (!test_bit(wil_status_reset_done, &wil->status)) {
+ if (!test_bit(wil_status_reset_done, wil->status)) {
wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
return;
}
@@ -1025,13 +1081,14 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
struct wmi_cfg_rx_chain_cmd cmd = {
.action = WMI_RX_CHAIN_ADD,
.rx_sw_ring = {
- .max_mpdu_size = cpu_to_le16(mtu_max + ETH_HLEN),
+ .max_mpdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)),
.ring_mem_base = cpu_to_le64(vring->pa),
.ring_size = cpu_to_le16(vring->size),
},
.mid = 0, /* TODO - what is it? */
.decap_trans_type = WMI_DECAP_TYPE_802_3,
.reorder_type = WMI_RX_SW_REORDER,
+ .host_thrsh = cpu_to_le16(rx_ring_overflow_thrsh),
};
struct {
struct wil6210_mbox_hdr_wmi wmi;
@@ -1074,12 +1131,13 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
return rc;
}
-int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
+int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
{
int rc;
struct wmi_temp_sense_cmd cmd = {
- .measure_marlon_m_en = cpu_to_le32(!!t_m),
- .measure_marlon_r_en = cpu_to_le32(!!t_r),
+ .measure_baseband_en = cpu_to_le32(!!t_bb),
+ .measure_rf_en = cpu_to_le32(!!t_rf),
+ .measure_mode = cpu_to_le32(TEMPERATURE_MEASURE_NOW),
};
struct {
struct wil6210_mbox_hdr_wmi wmi;
@@ -1091,10 +1149,10 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
if (rc)
return rc;
- if (t_m)
- *t_m = le32_to_cpu(reply.evt.marlon_m_t1000);
- if (t_r)
- *t_r = le32_to_cpu(reply.evt.marlon_r_t1000);
+ if (t_bb)
+ *t_bb = le32_to_cpu(reply.evt.baseband_t1000);
+ if (t_rf)
+ *t_rf = le32_to_cpu(reply.evt.rf_t1000);
return 0;
}
@@ -1111,6 +1169,87 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason)
return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd));
}
+int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout)
+{
+ struct wmi_vring_ba_en_cmd cmd = {
+ .ringid = ringid,
+ .agg_max_wsize = size,
+ .ba_timeout = cpu_to_le16(timeout),
+ .amsdu = 0,
+ };
+
+ wil_dbg_wmi(wil, "%s(ring %d size %d timeout %d)\n", __func__,
+ ringid, size, timeout);
+
+ return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason)
+{
+ struct wmi_vring_ba_dis_cmd cmd = {
+ .ringid = ringid,
+ .reason = cpu_to_le16(reason),
+ };
+
+ wil_dbg_wmi(wil, "%s(ring %d reason %d)\n", __func__,
+ ringid, reason);
+
+ return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason)
+{
+ struct wmi_rcp_delba_cmd cmd = {
+ .cidxtid = cidxtid,
+ .reason = cpu_to_le16(reason),
+ };
+
+ wil_dbg_wmi(wil, "%s(CID %d TID %d reason %d)\n", __func__,
+ cidxtid & 0xf, (cidxtid >> 4) & 0xf, reason);
+
+ return wmi_send(wil, WMI_RCP_DELBA_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
+ u16 status, bool amsdu, u16 agg_wsize, u16 timeout)
+{
+ int rc;
+ struct wmi_rcp_addba_resp_cmd cmd = {
+ .cidxtid = mk_cidxtid(cid, tid),
+ .dialog_token = token,
+ .status_code = cpu_to_le16(status),
+ /* bit 0: A-MSDU supported
+ * bit 1: policy (should be 0 for us)
+ * bits 2..5: TID
+ * bits 6..15: buffer size
+ */
+ .ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) |
+ (agg_wsize << 6)),
+ .ba_timeout = cpu_to_le16(timeout),
+ };
+ struct {
+ struct wil6210_mbox_hdr_wmi wmi;
+ struct wmi_rcp_addba_resp_sent_event evt;
+ } __packed reply;
+
+ wil_dbg_wmi(wil,
+ "ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s\n",
+ cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-");
+
+ rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, &cmd, sizeof(cmd),
+ WMI_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply), 100);
+ if (rc)
+ return rc;
+
+ if (reply.evt.status) {
+ wil_err(wil, "ADDBA response failed with status %d\n",
+ le16_to_cpu(reply.evt.status));
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
void wmi_event_flush(struct wil6210_priv *wil)
{
struct pending_wmi_event *evt, *t;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 27b97432d1c2..8a4af613e191 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -29,8 +29,10 @@
/* General */
#define WILOCITY_MAX_ASSOC_STA (8)
+#define WILOCITY_DEFAULT_ASSOC_STA (1)
#define WMI_MAC_LEN (6)
#define WMI_PROX_RANGE_NUM (3)
+#define WMI_MAX_LOSS_DMG_BEACONS (32)
/* List of Commands */
enum wmi_command_id {
@@ -48,7 +50,7 @@ enum wmi_command_id {
WMI_SET_WSC_STATUS_CMDID = 0x0041,
WMI_PXMT_RANGE_CFG_CMDID = 0x0042,
WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x0043,
- WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300,
+/* WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, */
WMI_MEM_READ_CMDID = 0x0800,
WMI_MEM_WR_CMDID = 0x0801,
WMI_ECHO_CMDID = 0x0803,
@@ -102,6 +104,8 @@ enum wmi_command_id {
WMI_MAINTAIN_RESUME_CMDID = 0x0851,
WMI_RS_MGMT_CMDID = 0x0852,
WMI_RF_MGMT_CMDID = 0x0853,
+ WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x0854,
+ WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x0855,
/* Performance monitoring commands */
WMI_BF_CTRL_CMDID = 0x0862,
WMI_NOTIFY_REQ_CMDID = 0x0863,
@@ -136,6 +140,7 @@ enum wmi_command_id {
WMI_EAPOL_TX_CMDID = 0xf04c,
WMI_MAC_ADDR_REQ_CMDID = 0xf04d,
WMI_FW_VER_CMDID = 0xf04e,
+ WMI_PMC_CMDID = 0xf04f,
};
/*
@@ -283,8 +288,8 @@ enum wmi_scan_type {
WMI_LONG_SCAN = 0,
WMI_SHORT_SCAN = 1,
WMI_PBC_SCAN = 2,
- WMI_ACTIVE_SCAN = 3,
- WMI_DIRECT_SCAN = 4,
+ WMI_DIRECT_SCAN = 3,
+ WMI_ACTIVE_SCAN = 4,
};
struct wmi_start_scan_cmd {
@@ -375,6 +380,17 @@ struct wmi_rf_mgmt_cmd {
} __packed;
/*
+ * WMI_THERMAL_THROTTLING_CTRL_CMDID
+ */
+#define THERMAL_THROTTLING_USE_DEFAULT_MAX_TXOP_LENGTH (0xFFFFFFFF)
+
+struct wmi_thermal_throttling_ctrl_cmd {
+ __le32 time_on_usec;
+ __le32 time_off_usec;
+ __le32 max_txop_length_usec;
+} __packed;
+
+/*
* WMI_RF_RX_TEST_CMDID
*/
struct wmi_rf_rx_test_cmd {
@@ -586,6 +602,7 @@ struct wmi_vring_ba_en_cmd {
u8 ringid;
u8 agg_max_wsize;
__le16 ba_timeout;
+ u8 amsdu;
} __packed;
/*
@@ -647,6 +664,7 @@ enum wmi_cfg_rx_chain_cmd_action {
enum wmi_cfg_rx_chain_cmd_decap_trans_type {
WMI_DECAP_TYPE_802_3 = 0,
WMI_DECAP_TYPE_NATIVE_WIFI = 1,
+ WMI_DECAP_TYPE_NONE = 2,
};
enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type {
@@ -784,9 +802,17 @@ struct wmi_echo_cmd {
*
* Measure MAC and radio temperatures
*/
+
+/* Possible modes for temperature measurement */
+enum wmi_temperature_measure_mode {
+ TEMPERATURE_USE_OLD_VALUE = 0x1,
+ TEMPERATURE_MEASURE_NOW = 0x2,
+};
+
struct wmi_temp_sense_cmd {
- __le32 measure_marlon_m_en;
- __le32 measure_marlon_r_en;
+ __le32 measure_baseband_en;
+ __le32 measure_rf_en;
+ __le32 measure_mode;
} __packed;
/*
@@ -842,6 +868,7 @@ enum wmi_event_id {
WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839,
WMI_RS_MGMT_DONE_EVENTID = 0x1852,
WMI_RF_MGMT_STATUS_EVENTID = 0x1853,
+ WMI_THERMAL_THROTTLING_STATUS_EVENTID = 0x1855,
WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838,
WMI_RX_MGMT_PACKET_EVENTID = 0x1840,
WMI_TX_MGMT_PACKET_EVENTID = 0x1841,
@@ -858,6 +885,7 @@ enum wmi_event_id {
WMI_FLASH_READ_DONE_EVENTID = 0x1902,
WMI_FLASH_WRITE_DONE_EVENTID = 0x1903,
/*P2P*/
+ WMI_P2P_CFG_DONE_EVENTID = 0x1910,
WMI_PORT_ALLOCATED_EVENTID = 0x1911,
WMI_PORT_DELETED_EVENTID = 0x1912,
WMI_LISTEN_STARTED_EVENTID = 0x1914,
@@ -898,6 +926,15 @@ struct wmi_rf_mgmt_status_event {
} __packed;
/*
+ * WMI_THERMAL_THROTTLING_STATUS_EVENTID
+ */
+struct wmi_thermal_throttling_status_event {
+ __le32 time_on_usec;
+ __le32 time_off_usec;
+ __le32 max_txop_length_usec;
+} __packed;
+
+/*
* WMI_GET_STATUS_DONE_EVENTID
*/
struct wmi_get_status_done_event {
@@ -1052,14 +1089,23 @@ struct wmi_scan_complete_event {
enum wmi_vring_ba_status {
WMI_BA_AGREED = 0,
WMI_BA_NON_AGREED = 1,
+ /* BA_EN in middle of teardown flow */
+ WMI_BA_TD_WIP = 2,
+ /* BA_DIS or BA_EN in middle of BA SETUP flow */
+ WMI_BA_SETUP_WIP = 3,
+ /* BA_EN when the BA session is already active */
+ WMI_BA_SESSION_ACTIVE = 4,
+ /* BA_DIS when the BA session is not active */
+ WMI_BA_SESSION_NOT_ACTIVE = 5,
};
struct wmi_vring_ba_status_event {
- __le16 status;
+ __le16 status; /* enum wmi_vring_ba_status */
u8 reserved[2];
u8 ringid;
u8 agg_wsize;
__le16 ba_timeout;
+ u8 amsdu;
} __packed;
/*
@@ -1145,6 +1191,14 @@ struct wmi_get_pcp_channel_event {
} __packed;
/*
+ * WMI_P2P_CFG_DONE_EVENTID
+ */
+struct wmi_p2p_cfg_done_event {
+ u8 status; /* wmi_fw_status */
+ u8 reserved[3];
+} __packed;
+
+/*
* WMI_PORT_ALLOCATED_EVENTID
*/
struct wmi_port_allocated_event {
@@ -1272,8 +1326,8 @@ struct wmi_echo_event {
* Measure MAC and radio temperatures
*/
struct wmi_temp_sense_done_event {
- __le32 marlon_m_t1000;
- __le32 marlon_r_t1000;
+ __le32 baseband_t1000;
+ __le32 rf_t1000;
} __packed;
#endif /* __WILOCITY_WMI_H__ */
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 9183f1cf89a7..55db9f03eb2a 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -45,7 +45,6 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/ctype.h>
#include <linux/timer.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -2699,16 +2698,7 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
domain[REGDOMAINSZ] = 0;
rc = -EINVAL;
for (i = 0; i < ARRAY_SIZE(channel_table); i++) {
- /* strcasecmp doesn't exist in the library */
- char *a = channel_table[i].name;
- char *b = domain;
- while (*a) {
- char c1 = *a++;
- char c2 = *b++;
- if (tolower(c1) != tolower(c2))
- break;
- }
- if (!*a && !*b) {
+ if (!strcasecmp(channel_table[i].name, domain)) {
priv->config_reg_domain = channel_table[i].reg_domain;
rc = 0;
}
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 64a5b672e30a..759fb8d41fc9 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -166,6 +166,15 @@ config B43_PHY_LCN
Say N, this is BROKEN and crashes driver.
+config B43_PHY_AC
+ bool "Support for AC-PHY (802.11ac) devices (BROKEN)"
+ depends on B43 && B43_BCMA && BROKEN
+ ---help---
+ This PHY type can be found in the following chipsets:
+ PCI: BCM4352, BCM4360
+
+ Say N, this is BROKEN and crashes driver.
+
# This config option automatically enables b43 LEDS support,
# if it's possible.
config B43_LEDS
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
index 9f7965aae93d..c624d4d90e4f 100644
--- a/drivers/net/wireless/b43/Makefile
+++ b/drivers/net/wireless/b43/Makefile
@@ -13,6 +13,7 @@ b43-$(CONFIG_B43_PHY_HT) += phy_ht.o
b43-$(CONFIG_B43_PHY_HT) += tables_phy_ht.o
b43-$(CONFIG_B43_PHY_HT) += radio_2059.o
b43-$(CONFIG_B43_PHY_LCN) += phy_lcn.o tables_phy_lcn.o
+b43-$(CONFIG_B43_PHY_AC) += phy_ac.o
b43-y += sysfs.o
b43-y += xmit.o
b43-y += dma.o
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index bb12586cd7cd..036552439816 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -500,6 +500,8 @@ enum {
#define B43_BCMA_IOCTL_PHY_BW_10MHZ 0x00000000 /* 10 MHz bandwidth, 40 MHz PHY */
#define B43_BCMA_IOCTL_PHY_BW_20MHZ 0x00000040 /* 20 MHz bandwidth, 80 MHz PHY */
#define B43_BCMA_IOCTL_PHY_BW_40MHZ 0x00000080 /* 40 MHz bandwidth, 160 MHz PHY */
+#define B43_BCMA_IOCTL_PHY_BW_80MHZ 0x000000C0 /* 80 MHz bandwidth */
+#define B43_BCMA_IOCTL_DAC 0x00000300 /* Highspeed DAC mode control field */
#define B43_BCMA_IOCTL_GMODE 0x00002000 /* G Mode Enable */
/* BCMA 802.11 core specific IO status (BCMA_IOST) flags */
@@ -941,6 +943,7 @@ struct b43_wl {
bool beacon1_uploaded;
bool beacon_templates_virgin; /* Never wrote the templates? */
struct work_struct beacon_update_trigger;
+ spinlock_t beacon_lock;
/* The current QOS parameters for the 4 queues. */
struct b43_qos_params qos_params[B43_QOS_QUEUE_NUM];
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 47731cb0d815..2c9088633ec6 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1262,6 +1262,23 @@ static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode)
flags |= B43_BCMA_IOCTL_GMODE;
b43_device_enable(dev, flags);
+ if (dev->phy.type == B43_PHYTYPE_AC) {
+ u16 tmp;
+
+ tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+ tmp &= ~B43_BCMA_IOCTL_DAC;
+ tmp |= 0x100;
+ bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
+
+ tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+ tmp &= ~B43_BCMA_IOCTL_PHY_CLKEN;
+ bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
+
+ tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+ tmp |= B43_BCMA_IOCTL_PHY_CLKEN;
+ bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
+ }
+
bcma_core_set_clockmode(dev->dev->bdev, BCMA_CLKMODE_FAST);
b43_bcma_phy_reset(dev);
bcma_core_pll_ctl(dev->dev->bdev, req, status, true);
@@ -1601,12 +1618,26 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
unsigned int rate;
u16 ctl;
int antenna;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
+ struct ieee80211_tx_info *info;
+ unsigned long flags;
+ struct sk_buff *beacon_skb;
- bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
- len = min_t(size_t, dev->wl->current_beacon->len,
- 0x200 - sizeof(struct b43_plcp_hdr6));
+ spin_lock_irqsave(&dev->wl->beacon_lock, flags);
+ info = IEEE80211_SKB_CB(dev->wl->current_beacon);
rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
+ /* Clone the beacon, so it cannot go away, while we write it to hw. */
+ beacon_skb = skb_clone(dev->wl->current_beacon, GFP_ATOMIC);
+ spin_unlock_irqrestore(&dev->wl->beacon_lock, flags);
+
+ if (!beacon_skb) {
+ b43dbg(dev->wl, "Could not upload beacon. "
+ "Failed to clone beacon skb.");
+ return;
+ }
+
+ bcn = (const struct ieee80211_mgmt *)(beacon_skb->data);
+ len = min_t(size_t, beacon_skb->len,
+ 0x200 - sizeof(struct b43_plcp_hdr6));
b43_write_template_common(dev, (const u8 *)bcn,
len, ram_offset, shm_size_offset, rate);
@@ -1674,6 +1705,8 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
B43_SHM_SH_DTIMPER, 0);
}
b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset);
+
+ dev_kfree_skb_any(beacon_skb);
}
static void b43_upload_beacon0(struct b43_wldev *dev)
@@ -1790,13 +1823,13 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
mutex_unlock(&wl->mutex);
}
-/* Asynchronously update the packet templates in template RAM.
- * Locking: Requires wl->mutex to be locked. */
+/* Asynchronously update the packet templates in template RAM. */
static void b43_update_templates(struct b43_wl *wl)
{
- struct sk_buff *beacon;
+ struct sk_buff *beacon, *old_beacon;
+ unsigned long flags;
- /* This is the top half of the ansynchronous beacon update.
+ /* This is the top half of the asynchronous beacon update.
* The bottom half is the beacon IRQ.
* Beacon update must be asynchronous to avoid sending an
* invalid beacon. This can happen for example, if the firmware
@@ -1810,12 +1843,17 @@ static void b43_update_templates(struct b43_wl *wl)
if (unlikely(!beacon))
return;
- if (wl->current_beacon)
- dev_kfree_skb_any(wl->current_beacon);
+ spin_lock_irqsave(&wl->beacon_lock, flags);
+ old_beacon = wl->current_beacon;
wl->current_beacon = beacon;
wl->beacon0_uploaded = false;
wl->beacon1_uploaded = false;
+ spin_unlock_irqrestore(&wl->beacon_lock, flags);
+
ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
+
+ if (old_beacon)
+ dev_kfree_skb_any(old_beacon);
}
static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
@@ -4318,6 +4356,7 @@ redo:
mutex_unlock(&wl->mutex);
cancel_delayed_work_sync(&dev->periodic_work);
cancel_work_sync(&wl->tx_work);
+ b43_leds_stop(dev);
mutex_lock(&wl->mutex);
dev = wl->current_dev;
if (!dev || b43_status(dev) < B43_STAT_STARTED) {
@@ -4505,6 +4544,12 @@ static int b43_phy_versioning(struct b43_wldev *dev)
unsupported = 1;
break;
#endif
+#ifdef CONFIG_B43_PHY_AC
+ case B43_PHYTYPE_AC:
+ if (phy_rev > 1)
+ unsupported = 1;
+ break;
+#endif
default:
unsupported = 1;
}
@@ -4601,6 +4646,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
if (radio_id != 0x2064)
unsupported = 1;
break;
+ case B43_PHYTYPE_AC:
+ if (radio_id != 0x2069)
+ unsupported = 1;
+ break;
default:
B43_WARN_ON(1);
}
@@ -5094,7 +5143,6 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
{
struct b43_wl *wl = hw_to_b43_wl(hw);
- /* FIXME: add locking */
b43_update_templates(wl);
return 0;
@@ -5584,6 +5632,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
wl->hw = hw;
mutex_init(&wl->mutex);
spin_lock_init(&wl->hardirq_lock);
+ spin_lock_init(&wl->beacon_lock);
INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
INIT_WORK(&wl->tx_work, b43_tx_work);
diff --git a/drivers/net/wireless/b43/phy_ac.c b/drivers/net/wireless/b43/phy_ac.c
new file mode 100644
index 000000000000..e75633d67938
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_ac.c
@@ -0,0 +1,92 @@
+/*
+ * Broadcom B43 wireless driver
+ * IEEE 802.11ac AC-PHY support
+ *
+ * Copyright (c) 2015 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include "b43.h"
+#include "phy_ac.h"
+
+/**************************************************
+ * Basic PHY ops
+ **************************************************/
+
+static int b43_phy_ac_op_allocate(struct b43_wldev *dev)
+{
+ struct b43_phy_ac *phy_ac;
+
+ phy_ac = kzalloc(sizeof(*phy_ac), GFP_KERNEL);
+ if (!phy_ac)
+ return -ENOMEM;
+ dev->phy.ac = phy_ac;
+
+ return 0;
+}
+
+static void b43_phy_ac_op_free(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_phy_ac *phy_ac = phy->ac;
+
+ kfree(phy_ac);
+ phy->ac = NULL;
+}
+
+static void b43_phy_ac_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
+ u16 set)
+{
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_PHY_DATA,
+ (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
+}
+
+static u16 b43_phy_ac_op_radio_read(struct b43_wldev *dev, u16 reg)
+{
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ return b43_read16(dev, B43_MMIO_RADIO24_DATA);
+}
+
+static void b43_phy_ac_op_radio_write(struct b43_wldev *dev, u16 reg,
+ u16 value)
+{
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
+}
+
+static unsigned int b43_phy_ac_op_get_default_chan(struct b43_wldev *dev)
+{
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ return 11;
+ return 36;
+}
+
+static enum b43_txpwr_result
+b43_phy_ac_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi)
+{
+ return B43_TXPWR_RES_DONE;
+}
+
+static void b43_phy_ac_op_adjust_txpower(struct b43_wldev *dev)
+{
+}
+
+/**************************************************
+ * PHY ops struct
+ **************************************************/
+
+const struct b43_phy_operations b43_phyops_ac = {
+ .allocate = b43_phy_ac_op_allocate,
+ .free = b43_phy_ac_op_free,
+ .phy_maskset = b43_phy_ac_op_maskset,
+ .radio_read = b43_phy_ac_op_radio_read,
+ .radio_write = b43_phy_ac_op_radio_write,
+ .get_default_chan = b43_phy_ac_op_get_default_chan,
+ .recalc_txpower = b43_phy_ac_op_recalc_txpower,
+ .adjust_txpower = b43_phy_ac_op_adjust_txpower,
+};
diff --git a/drivers/net/wireless/b43/phy_ac.h b/drivers/net/wireless/b43/phy_ac.h
new file mode 100644
index 000000000000..d1ca79e0eb24
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_ac.h
@@ -0,0 +1,38 @@
+#ifndef B43_PHY_AC_H_
+#define B43_PHY_AC_H_
+
+#include "phy_common.h"
+
+#define B43_PHY_AC_BBCFG 0x001
+#define B43_PHY_AC_BBCFG_RSTCCA 0x4000 /* Reset CCA */
+#define B43_PHY_AC_BANDCTL 0x003 /* Band control */
+#define B43_PHY_AC_BANDCTL_5GHZ 0x0001
+#define B43_PHY_AC_TABLE_ID 0x00d
+#define B43_PHY_AC_TABLE_OFFSET 0x00e
+#define B43_PHY_AC_TABLE_DATA1 0x00f
+#define B43_PHY_AC_TABLE_DATA2 0x010
+#define B43_PHY_AC_TABLE_DATA3 0x011
+#define B43_PHY_AC_CLASSCTL 0x140 /* Classifier control */
+#define B43_PHY_AC_CLASSCTL_CCKEN 0x0001 /* CCK enable */
+#define B43_PHY_AC_CLASSCTL_OFDMEN 0x0002 /* OFDM enable */
+#define B43_PHY_AC_CLASSCTL_WAITEDEN 0x0004 /* Waited enable */
+#define B43_PHY_AC_BW1A 0x371
+#define B43_PHY_AC_BW2 0x372
+#define B43_PHY_AC_BW3 0x373
+#define B43_PHY_AC_BW4 0x374
+#define B43_PHY_AC_BW5 0x375
+#define B43_PHY_AC_BW6 0x376
+#define B43_PHY_AC_RFCTL_CMD 0x408
+#define B43_PHY_AC_C1_CLIP 0x6d4
+#define B43_PHY_AC_C1_CLIP_DIS 0x4000
+#define B43_PHY_AC_C2_CLIP 0x8d4
+#define B43_PHY_AC_C2_CLIP_DIS 0x4000
+#define B43_PHY_AC_C3_CLIP 0xad4
+#define B43_PHY_AC_C3_CLIP_DIS 0x4000
+
+struct b43_phy_ac {
+};
+
+extern const struct b43_phy_operations b43_phyops_ac;
+
+#endif /* B43_PHY_AC_H_ */
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index ee27b06074e1..ec2b9c577b90 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -33,6 +33,7 @@
#include "phy_lp.h"
#include "phy_ht.h"
#include "phy_lcn.h"
+#include "phy_ac.h"
#include "b43.h"
#include "main.h"
@@ -70,6 +71,11 @@ int b43_phy_allocate(struct b43_wldev *dev)
phy->ops = &b43_phyops_lcn;
#endif
break;
+ case B43_PHYTYPE_AC:
+#ifdef CONFIG_B43_PHY_AC
+ phy->ops = &b43_phyops_ac;
+#endif
+ break;
}
if (B43_WARN_ON(!phy->ops))
return -ENODEV;
@@ -572,7 +578,8 @@ void b43_phy_force_clock(struct b43_wldev *dev, bool force)
u32 tmp;
WARN_ON(dev->phy.type != B43_PHYTYPE_N &&
- dev->phy.type != B43_PHYTYPE_HT);
+ dev->phy.type != B43_PHYTYPE_HT &&
+ dev->phy.type != B43_PHYTYPE_AC);
switch (dev->dev->bus_type) {
#ifdef CONFIG_B43_BCMA
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h
index 3912274f71e3..78d86526799e 100644
--- a/drivers/net/wireless/b43/phy_common.h
+++ b/drivers/net/wireless/b43/phy_common.h
@@ -222,6 +222,8 @@ struct b43_phy {
struct b43_phy_ht *ht;
/* LCN-PHY specific information */
struct b43_phy_lcn *lcn;
+ /* AC-PHY specific information */
+ struct b43_phy_ac *ac;
};
/* Band support flags. */
diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c
index 896177690394..9501420340a9 100644
--- a/drivers/net/wireless/b43legacy/radio.c
+++ b/drivers/net/wireless/b43legacy/radio.c
@@ -1743,25 +1743,6 @@ u16 freq_r3A_value(u16 frequency)
return value;
}
-void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev)
-{
- static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
- static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
- u16 tmp = b43legacy_radio_read16(dev, 0x001E);
- int i;
- int j;
-
- for (i = 0; i < 5; i++) {
- for (j = 0; j < 5; j++) {
- if (tmp == (data_high[i] | data_low[j])) {
- b43legacy_phy_write(dev, 0x0069, (i - j) << 8 |
- 0x00C0);
- return;
- }
- }
- }
-}
-
int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,
u8 channel,
int synthetic_pu_workaround)
diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h
index bccb3d7da682..dd2976d1d561 100644
--- a/drivers/net/wireless/b43legacy/radio.h
+++ b/drivers/net/wireless/b43legacy/radio.h
@@ -92,7 +92,6 @@ void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val);
void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val);
void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev);
-void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev);
u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev);
#endif /* B43legacy_RADIO_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index 00ba90b89455..7944224e3fc9 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -97,25 +97,6 @@ static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func)
{
}
-static bool brcmf_sdiod_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
-{
- bool is_err = false;
-#ifdef CONFIG_PM_SLEEP
- is_err = atomic_read(&sdiodev->suspend);
-#endif
- return is_err;
-}
-
-static void brcmf_sdiod_pm_resume_wait(struct brcmf_sdio_dev *sdiodev,
- wait_queue_head_t *wq)
-{
-#ifdef CONFIG_PM_SLEEP
- int retry = 0;
- while (atomic_read(&sdiodev->suspend) && retry++ != 30)
- wait_event_timeout(*wq, false, HZ/100);
-#endif
-}
-
int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
{
int ret = 0;
@@ -244,10 +225,6 @@ static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn,
brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
write, fn, addr, regsz);
- brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
- if (brcmf_sdiod_pm_resume_error(sdiodev))
- return -EIO;
-
/* only allow byte access on F0 */
if (WARN_ON(regsz > 1 && !fn))
return -EINVAL;
@@ -292,6 +269,12 @@ static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn,
return ret;
}
+static void brcmf_sdiod_nomedium_state(struct brcmf_sdio_dev *sdiodev)
+{
+ sdiodev->state = BRCMF_STATE_NOMEDIUM;
+ brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN);
+}
+
static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
u8 regsz, void *data, bool write)
{
@@ -299,7 +282,7 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
s32 retry = 0;
int ret;
- if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM)
+ if (sdiodev->state == BRCMF_STATE_NOMEDIUM)
return -ENOMEDIUM;
/*
@@ -325,7 +308,7 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
if (ret == -ENOMEDIUM)
- brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM);
+ brcmf_sdiod_nomedium_state(sdiodev);
else if (ret != 0) {
/*
* SleepCSR register access can fail when
@@ -348,7 +331,7 @@ brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
int err = 0, i;
u8 addr[3];
- if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM)
+ if (sdiodev->state == BRCMF_STATE_NOMEDIUM)
return -ENOMEDIUM;
addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
@@ -462,10 +445,6 @@ static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
unsigned int req_sz;
int err;
- brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
- if (brcmf_sdiod_pm_resume_error(sdiodev))
- return -EIO;
-
/* Single skb use the standard mmc interface */
req_sz = pkt->len + 3;
req_sz &= (uint)~3;
@@ -481,7 +460,7 @@ static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
err = sdio_readsb(sdiodev->func[fn], ((u8 *)(pkt->data)), addr,
req_sz);
if (err == -ENOMEDIUM)
- brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM);
+ brcmf_sdiod_nomedium_state(sdiodev);
return err;
}
@@ -516,10 +495,6 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
if (!pktlist->qlen)
return -EINVAL;
- brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
- if (brcmf_sdiod_pm_resume_error(sdiodev))
- return -EIO;
-
target_list = pktlist;
/* for host with broken sg support, prepare a page aligned list */
__skb_queue_head_init(&local_list);
@@ -620,8 +595,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error;
if (ret == -ENOMEDIUM) {
- brcmf_bus_change_state(sdiodev->bus_if,
- BRCMF_BUS_NOMEDIUM);
+ brcmf_sdiod_nomedium_state(sdiodev);
break;
} else if (ret != 0) {
brcmf_err("CMD53 sg block %s failed %d\n",
@@ -1076,9 +1050,9 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
bus_if->wowl_supported = true;
#endif
+ sdiodev->sleeping = false;
atomic_set(&sdiodev->suspend, false);
- init_waitqueue_head(&sdiodev->request_word_wait);
- init_waitqueue_head(&sdiodev->request_buffer_wait);
+ init_waitqueue_head(&sdiodev->idle_wait);
brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n");
err = brcmf_sdiod_probe(sdiodev);
@@ -1140,12 +1114,23 @@ void brcmf_sdio_wowl_config(struct device *dev, bool enabled)
#ifdef CONFIG_PM_SLEEP
static int brcmf_ops_sdio_suspend(struct device *dev)
{
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_bus *bus_if;
+ struct brcmf_sdio_dev *sdiodev;
mmc_pm_flag_t sdio_flags;
brcmf_dbg(SDIO, "Enter\n");
+ bus_if = dev_get_drvdata(dev);
+ sdiodev = bus_if->bus_priv.sdio;
+
+ /* wait for watchdog to go idle */
+ if (wait_event_timeout(sdiodev->idle_wait, sdiodev->sleeping,
+ msecs_to_jiffies(3 * BRCMF_WD_POLL_MS)) == 0) {
+ brcmf_err("bus still active\n");
+ return -EBUSY;
+ }
+ /* disable watchdog */
+ brcmf_sdio_wd_timer(sdiodev->bus, 0);
atomic_set(&sdiodev->suspend, true);
if (sdiodev->wowl_enabled) {
@@ -1157,9 +1142,6 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags))
brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
}
-
- brcmf_sdio_wd_timer(sdiodev->bus, 0);
-
return 0;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/brcm80211/brcmfmac/bus.h
index ef344e47218a..89e6a4dc105e 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h
@@ -33,11 +33,8 @@
/* The level of bus communication with the dongle */
enum brcmf_bus_state {
- BRCMF_BUS_UNKNOWN, /* Not determined yet */
- BRCMF_BUS_NOMEDIUM, /* No medium access to dongle */
BRCMF_BUS_DOWN, /* Not ready for frame transfers */
- BRCMF_BUS_LOAD, /* Download access only (CPU reset) */
- BRCMF_BUS_DATA /* Ready for frame transfers */
+ BRCMF_BUS_UP /* Ready for frame transfers */
};
/* The level of bus communication with the dongle */
@@ -188,22 +185,6 @@ void brcmf_bus_wowl_config(struct brcmf_bus *bus, bool enabled)
bus->ops->wowl_config(bus->dev, enabled);
}
-static inline bool brcmf_bus_ready(struct brcmf_bus *bus)
-{
- return bus->state == BRCMF_BUS_LOAD || bus->state == BRCMF_BUS_DATA;
-}
-
-static inline void brcmf_bus_change_state(struct brcmf_bus *bus,
- enum brcmf_bus_state new_state)
-{
- /* NOMEDIUM is permanent */
- if (bus->state == BRCMF_BUS_NOMEDIUM)
- return;
-
- brcmf_dbg(TRACE, "%d -> %d\n", bus->state, new_state);
- bus->state = new_state;
-}
-
/*
* interface functions from common layer
*/
@@ -226,6 +207,9 @@ void brcmf_txflowblock(struct device *dev, bool state);
/* Notify the bus has transferred the tx packet to firmware */
void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success);
+/* Configure the "global" bus state used by upper layers */
+void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state);
+
int brcmf_bus_start(struct device *dev);
s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len);
void brcmf_bus_add_txhdrlen(struct device *dev, uint len);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
index 1783c0350e1f..b59b8c6c42ab 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
@@ -1229,7 +1229,25 @@ static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
memset(prof, 0, sizeof(*prof));
}
-static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
+static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
+{
+ u16 reason;
+
+ switch (e->event_code) {
+ case BRCMF_E_DEAUTH:
+ case BRCMF_E_DEAUTH_IND:
+ case BRCMF_E_DISASSOC_IND:
+ reason = e->reason;
+ break;
+ case BRCMF_E_LINK:
+ default:
+ reason = 0;
+ break;
+ }
+ return reason;
+}
+
+static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
s32 err = 0;
@@ -1244,7 +1262,8 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
brcmf_err("WLC_DISASSOC failed (%d)\n", err);
}
clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
- cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);
+ cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
+ GFP_KERNEL);
}
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
@@ -1414,7 +1433,7 @@ brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
if (!check_vif_up(ifp->vif))
return -EIO;
- brcmf_link_down(ifp->vif);
+ brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
brcmf_dbg(TRACE, "Exit\n");
@@ -2375,10 +2394,10 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
brcmf_err("GET STA INFO failed, %d\n", err);
goto done;
}
- sinfo->filled = STATION_INFO_INACTIVE_TIME;
+ sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
- sinfo->filled |= STATION_INFO_CONNECTED_TIME;
+ sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
sinfo->connected_time = le32_to_cpu(sta_info_le.in);
}
brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
@@ -2396,7 +2415,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
brcmf_err("Could not get rate (%d)\n", err);
goto done;
} else {
- sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
sinfo->txrate.legacy = rate * 5;
brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
}
@@ -2411,7 +2430,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
goto done;
} else {
rssi = le32_to_cpu(scb_val.val);
- sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
sinfo->signal = rssi;
brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
}
@@ -2438,7 +2457,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
brcmf_dbg(CONN, "DTIM peroid %d\n",
dtim_period);
}
- sinfo->filled |= STATION_INFO_BSS_PARAM;
+ sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
}
} else
err = -EPERM;
@@ -3041,7 +3060,7 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
* disassociate from AP to save power while system is
* in suspended state
*/
- brcmf_link_down(vif);
+ brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
/* Make sure WPA_Supplicant receives all the event
* generated due to DISASSOC call to the fw to keep
* the state fw and WPA_Supplicant state consistent
@@ -3737,17 +3756,12 @@ static u32
brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
{
- __le32 iecount_le;
- __le32 pktflag_le;
-
strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
- iecount_le = cpu_to_le32(1);
- memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
+ put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
- pktflag_le = cpu_to_le32(pktflag);
- memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
+ put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
@@ -4878,7 +4892,6 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
(reason == BRCMF_E_STATUS_SUCCESS)) {
memset(&sinfo, 0, sizeof(sinfo));
- sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
if (!data) {
brcmf_err("No IEs present in ASSOC/REASSOC_IND");
return -EINVAL;
@@ -4933,7 +4946,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
if (!brcmf_is_ibssmode(ifp->vif)) {
brcmf_bss_connect_done(cfg, ndev, e, false);
}
- brcmf_link_down(ifp->vif);
+ brcmf_link_down(ifp->vif, brcmf_map_fw_linkdown_reason(e));
brcmf_init_prof(ndev_to_prof(ndev));
if (ndev != cfg_to_ndev(cfg))
complete(&cfg->vif_disabled);
@@ -5874,7 +5887,7 @@ static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
* from AP to save power
*/
if (check_vif_up(ifp->vif)) {
- brcmf_link_down(ifp->vif);
+ brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
/* Make sure WPA_Supplicant receives all the event
generated due to DISASSOC call to the fw to keep
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/common.c b/drivers/net/wireless/brcm80211/brcmfmac/common.c
index ddf05af13d44..fe54844c75e0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/common.c
@@ -41,6 +41,8 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
s8 eventmask[BRCMF_EVENTING_MASK_LEN];
u8 buf[BRCMF_DCMD_SMLEN];
struct brcmf_join_pref_params join_pref_params[2];
+ struct brcmf_rev_info_le revinfo;
+ struct brcmf_rev_info *ri;
char *ptr;
s32 err;
@@ -48,12 +50,37 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
sizeof(ifp->mac_addr));
if (err < 0) {
- brcmf_err("Retreiving cur_etheraddr failed, %d\n",
- err);
+ brcmf_err("Retreiving cur_etheraddr failed, %d\n", err);
goto done;
}
memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO,
+ &revinfo, sizeof(revinfo));
+ ri = &ifp->drvr->revinfo;
+ if (err < 0) {
+ brcmf_err("retrieving revision info failed, %d\n", err);
+ } else {
+ ri->vendorid = le32_to_cpu(revinfo.vendorid);
+ ri->deviceid = le32_to_cpu(revinfo.deviceid);
+ ri->radiorev = le32_to_cpu(revinfo.radiorev);
+ ri->chiprev = le32_to_cpu(revinfo.chiprev);
+ ri->corerev = le32_to_cpu(revinfo.corerev);
+ ri->boardid = le32_to_cpu(revinfo.boardid);
+ ri->boardvendor = le32_to_cpu(revinfo.boardvendor);
+ ri->boardrev = le32_to_cpu(revinfo.boardrev);
+ ri->driverrev = le32_to_cpu(revinfo.driverrev);
+ ri->ucoderev = le32_to_cpu(revinfo.ucoderev);
+ ri->bus = le32_to_cpu(revinfo.bus);
+ ri->chipnum = le32_to_cpu(revinfo.chipnum);
+ ri->phytype = le32_to_cpu(revinfo.phytype);
+ ri->phyrev = le32_to_cpu(revinfo.phyrev);
+ ri->anarev = le32_to_cpu(revinfo.anarev);
+ ri->chippkg = le32_to_cpu(revinfo.chippkg);
+ ri->nvramrev = le32_to_cpu(revinfo.nvramrev);
+ }
+ ri->result = err;
+
/* query for 'ver' to get version info from firmware */
memset(buf, 0, sizeof(buf));
strcpy(buf, "ver");
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
index 002336e35764..3d404016a92e 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
@@ -37,6 +37,8 @@ struct brcmf_commonring {
unsigned long flags;
bool inited;
bool was_full;
+
+ atomic_t outstanding_tx;
};
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c
index e2a9e33f71ab..2d6e2cc1b12c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -197,7 +197,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
brcmf_dbg(DATA, "Enter, idx=%d\n", ifp->bssidx);
/* Can the device send data? */
- if (drvr->bus_if->state != BRCMF_BUS_DATA) {
+ if (drvr->bus_if->state != BRCMF_BUS_UP) {
brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state);
netif_stop_queue(ndev);
dev_kfree_skb(skb);
@@ -601,9 +601,12 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
+ char drev[BRCMU_DOTREV_LEN] = "n/a";
+ if (drvr->revinfo.result == 0)
+ brcmu_dotrev_str(drvr->revinfo.driverrev, drev);
strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
- snprintf(info->version, sizeof(info->version), "n/a");
+ strlcpy(info->version, drev, sizeof(info->version));
strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version));
strlcpy(info->bus_info, dev_name(drvr->bus_if->dev),
sizeof(info->bus_info));
@@ -637,7 +640,7 @@ static int brcmf_netdev_open(struct net_device *ndev)
brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
/* If bus is not ready, can't continue */
- if (bus_if->state != BRCMF_BUS_DATA) {
+ if (bus_if->state != BRCMF_BUS_UP) {
brcmf_err("failed bus is not ready\n");
return -EAGAIN;
}
@@ -964,13 +967,20 @@ int brcmf_bus_start(struct device *dev)
p2p_ifp = NULL;
/* signal bus ready */
- brcmf_bus_change_state(bus_if, BRCMF_BUS_DATA);
+ brcmf_bus_change_state(bus_if, BRCMF_BUS_UP);
/* Bus is ready, do any initialization */
ret = brcmf_c_preinit_dcmds(ifp);
if (ret < 0)
goto fail;
+ /* assure we have chipid before feature attach */
+ if (!bus_if->chip) {
+ bus_if->chip = drvr->revinfo.chipnum;
+ bus_if->chiprev = drvr->revinfo.chiprev;
+ brcmf_dbg(INFO, "firmware revinfo: chip %x (%d) rev %d\n",
+ bus_if->chip, bus_if->chip, bus_if->chiprev);
+ }
brcmf_feat_attach(drvr);
ret = brcmf_fws_init(drvr);
@@ -1106,6 +1116,27 @@ int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp)
return !err;
}
+void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state)
+{
+ struct brcmf_pub *drvr = bus->drvr;
+ struct net_device *ndev;
+ int ifidx;
+
+ brcmf_dbg(TRACE, "%d -> %d\n", bus->state, state);
+ bus->state = state;
+
+ if (state == BRCMF_BUS_UP) {
+ for (ifidx = 0; ifidx < BRCMF_MAX_IFS; ifidx++) {
+ if ((drvr->iflist[ifidx]) &&
+ (drvr->iflist[ifidx]->ndev)) {
+ ndev = drvr->iflist[ifidx]->ndev;
+ if (netif_queue_stopped(ndev))
+ netif_wake_queue(ndev);
+ }
+ }
+ }
+}
+
static void brcmf_driver_register(struct work_struct *work)
{
#ifdef CONFIG_BRCMFMAC_SDIO
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.h b/drivers/net/wireless/brcm80211/brcmfmac/core.h
index f2f7d3d1a8ef..fd74a9c6e9ac 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
@@ -71,6 +71,35 @@ struct brcmf_proto; /* device communication protocol info */
struct brcmf_cfg80211_dev; /* cfg80211 device info */
struct brcmf_fws_info; /* firmware signalling info */
+/*
+ * struct brcmf_rev_info
+ *
+ * The result field stores the error code of the
+ * revision info request from firmware. For the
+ * other fields see struct brcmf_rev_info_le in
+ * fwil_types.h
+ */
+struct brcmf_rev_info {
+ int result;
+ u32 vendorid;
+ u32 deviceid;
+ u32 radiorev;
+ u32 chiprev;
+ u32 corerev;
+ u32 boardid;
+ u32 boardvendor;
+ u32 boardrev;
+ u32 driverrev;
+ u32 ucoderev;
+ u32 bus;
+ u32 chipnum;
+ u32 phytype;
+ u32 phyrev;
+ u32 anarev;
+ u32 chippkg;
+ u32 nvramrev;
+};
+
/* Common structure for module and instance linkage */
struct brcmf_pub {
/* Linkage ponters */
@@ -104,6 +133,7 @@ struct brcmf_pub {
u32 feat_flags;
u32 chip_quirks;
+ struct brcmf_rev_info revinfo;
#ifdef DEBUG
struct dentry *dbgfs_dir;
#endif
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
index 1ff787d1a36b..9cb99152ad17 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
@@ -103,7 +103,11 @@ static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp)
c = nvp->fwnv->data[nvp->pos];
if (c == '=') {
- st = VALUE;
+ /* ignore RAW1 by treating as comment */
+ if (strncmp(&nvp->fwnv->data[nvp->entry], "RAW1", 4) == 0)
+ st = COMMENT;
+ else
+ st = VALUE;
} else if (!is_nvram_char(c)) {
brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
nvp->line, nvp->column);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
index 03f2c406a17b..dcfa0bb149ce 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
@@ -109,7 +109,7 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
struct brcmf_pub *drvr = ifp->drvr;
s32 err;
- if (drvr->bus_if->state != BRCMF_BUS_DATA) {
+ if (drvr->bus_if->state != BRCMF_BUS_UP) {
brcmf_err("bus is down. we have nothing to do.\n");
return -EIO;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h
index 37345e7b873d..5434dcf64f7d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h
@@ -59,6 +59,7 @@
#define BRCMF_C_SET_COUNTRY 84
#define BRCMF_C_GET_PM 85
#define BRCMF_C_SET_PM 86
+#define BRCMF_C_GET_REVINFO 98
#define BRCMF_C_GET_CURR_RATESET 114
#define BRCMF_C_GET_AP 117
#define BRCMF_C_SET_AP 118
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
index 619669bbdb83..374920965108 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
@@ -539,4 +539,45 @@ struct brcmf_fil_country_le {
char ccode[BRCMF_COUNTRY_BUF_SZ];
};
+/**
+ * struct brcmf_rev_info_le - device revision info.
+ *
+ * @vendorid: PCI vendor id.
+ * @deviceid: device id of chip.
+ * @radiorev: radio revision.
+ * @chiprev: chip revision.
+ * @corerev: core revision.
+ * @boardid: board identifier (usu. PCI sub-device id).
+ * @boardvendor: board vendor (usu. PCI sub-vendor id).
+ * @boardrev: board revision.
+ * @driverrev: driver version.
+ * @ucoderev: microcode version.
+ * @bus: bus type.
+ * @chipnum: chip number.
+ * @phytype: phy type.
+ * @phyrev: phy revision.
+ * @anarev: anacore rev.
+ * @chippkg: chip package info.
+ * @nvramrev: nvram revision number.
+ */
+struct brcmf_rev_info_le {
+ __le32 vendorid;
+ __le32 deviceid;
+ __le32 radiorev;
+ __le32 chiprev;
+ __le32 corerev;
+ __le32 boardid;
+ __le32 boardvendor;
+ __le32 boardrev;
+ __le32 driverrev;
+ __le32 ucoderev;
+ __le32 bus;
+ __le32 chipnum;
+ __le32 phytype;
+ __le32 phyrev;
+ __le32 anarev;
+ __le32 chippkg;
+ __le32 nvramrev;
+};
+
#endif /* FWIL_TYPES_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
index ee147f5c706a..6262612dec45 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
@@ -73,6 +73,8 @@
#define BRCMF_MSGBUF_TX_FLUSH_CNT1 32
#define BRCMF_MSGBUF_TX_FLUSH_CNT2 96
+#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 64
+#define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS 32
struct msgbuf_common_hdr {
u8 msgtype;
@@ -749,6 +751,7 @@ static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid)
tx_msghdr->metadata_buf_len = 0;
tx_msghdr->metadata_buf_addr.high_addr = 0;
tx_msghdr->metadata_buf_addr.low_addr = 0;
+ atomic_inc(&commonring->outstanding_tx);
if (count >= BRCMF_MSGBUF_TX_FLUSH_CNT2) {
brcmf_commonring_write_complete(commonring);
count = 0;
@@ -773,10 +776,16 @@ static void brcmf_msgbuf_txflow_worker(struct work_struct *worker)
}
-static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid)
+static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid,
+ bool force)
{
+ struct brcmf_commonring *commonring;
+
set_bit(flowid, msgbuf->flow_map);
- queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work);
+ commonring = msgbuf->flowrings[flowid];
+ if ((force) || (atomic_read(&commonring->outstanding_tx) <
+ BRCMF_MSGBUF_DELAY_TXWORKER_THRS))
+ queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work);
return 0;
}
@@ -797,7 +806,7 @@ static int brcmf_msgbuf_txdata(struct brcmf_pub *drvr, int ifidx,
return -ENOMEM;
}
brcmf_flowring_enqueue(flow, flowid, skb);
- brcmf_msgbuf_schedule_txdata(msgbuf, flowid);
+ brcmf_msgbuf_schedule_txdata(msgbuf, flowid, false);
return 0;
}
@@ -854,6 +863,7 @@ brcmf_msgbuf_process_ioctl_complete(struct brcmf_msgbuf *msgbuf, void *buf)
static void
brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf)
{
+ struct brcmf_commonring *commonring;
struct msgbuf_tx_status *tx_status;
u32 idx;
struct sk_buff *skb;
@@ -871,6 +881,8 @@ brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf)
}
set_bit(flowid, msgbuf->txstatus_done_map);
+ commonring = msgbuf->flowrings[flowid];
+ atomic_dec(&commonring->outstanding_tx);
brcmf_txfinalize(msgbuf->drvr, skb, tx_status->msg.ifidx, true);
}
@@ -1181,7 +1193,7 @@ brcmf_msgbuf_process_flow_ring_create_response(struct brcmf_msgbuf *msgbuf,
brcmf_flowring_open(msgbuf->flow, flowid);
- brcmf_msgbuf_schedule_txdata(msgbuf, flowid);
+ brcmf_msgbuf_schedule_txdata(msgbuf, flowid, true);
}
@@ -1280,8 +1292,10 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev)
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
+ struct brcmf_commonring *commonring;
void *buf;
u32 flowid;
+ int qlen;
buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE];
brcmf_msgbuf_process_rx(msgbuf, buf);
@@ -1293,8 +1307,12 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev)
for_each_set_bit(flowid, msgbuf->txstatus_done_map,
msgbuf->nrof_flowrings) {
clear_bit(flowid, msgbuf->txstatus_done_map);
- if (brcmf_flowring_qlen(msgbuf->flow, flowid))
- brcmf_msgbuf_schedule_txdata(msgbuf, flowid);
+ commonring = msgbuf->flowrings[flowid];
+ qlen = brcmf_flowring_qlen(msgbuf->flow, flowid);
+ if ((qlen > BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) ||
+ ((qlen) && (atomic_read(&commonring->outstanding_tx) <
+ BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS)))
+ brcmf_msgbuf_schedule_txdata(msgbuf, flowid, true);
}
return 0;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
index e91fa9a2c885..61c053a729be 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
@@ -1828,7 +1828,7 @@ static int brcmf_pcie_resume(struct pci_dev *pdev)
goto cleanup;
brcmf_dbg(PCIE, "Hot resume, continue....\n");
brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
- brcmf_bus_change_state(bus, BRCMF_BUS_DATA);
+ brcmf_bus_change_state(bus, BRCMF_BUS_UP);
brcmf_pcie_intr_enable(devinfo);
return 0;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
index 99a37765888d..faec35c899ec 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
@@ -44,7 +44,8 @@
#include "chip.h"
#include "firmware.h"
-#define DCMD_RESP_TIMEOUT 2000 /* In milli second */
+#define DCMD_RESP_TIMEOUT 2000 /* In milli second */
+#define CTL_DONE_TIMEOUT 2000 /* In milli second */
#ifdef DEBUG
@@ -495,9 +496,9 @@ struct brcmf_sdio {
u8 *ctrl_frame_buf;
u16 ctrl_frame_len;
bool ctrl_frame_stat;
+ int ctrl_frame_err;
spinlock_t txq_lock; /* protect bus->txq */
- struct semaphore tx_seq_lock; /* protect bus->tx_seq */
wait_queue_head_t ctrl_wait;
wait_queue_head_t dcmd_resp_wait;
@@ -514,7 +515,6 @@ struct brcmf_sdio {
bool txoff; /* Transmit flow-controlled */
struct brcmf_sdio_count sdcnt;
bool sr_enabled; /* SaveRestore enabled */
- bool sleeping; /* SDIO bus sleeping */
u8 tx_hdrlen; /* sdio bus header length for tx packet */
bool txglom; /* host tx glomming enable flag */
@@ -1013,12 +1013,12 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
brcmf_dbg(SDIO, "Enter: request %s currently %s\n",
(sleep ? "SLEEP" : "WAKE"),
- (bus->sleeping ? "SLEEP" : "WAKE"));
+ (bus->sdiodev->sleeping ? "SLEEP" : "WAKE"));
/* If SR is enabled control bus state with KSO */
if (bus->sr_enabled) {
/* Done if we're already in the requested state */
- if (sleep == bus->sleeping)
+ if (sleep == bus->sdiodev->sleeping)
goto end;
/* Going to sleep */
@@ -1050,12 +1050,7 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
bus->idlecount = 0;
err = brcmf_sdio_kso_control(bus, true);
}
- if (!err) {
- /* Change state */
- bus->sleeping = sleep;
- brcmf_dbg(SDIO, "new state %s\n",
- (sleep ? "SLEEP" : "WAKE"));
- } else {
+ if (err) {
brcmf_err("error while changing bus sleep state %d\n",
err);
goto done;
@@ -1070,6 +1065,11 @@ end:
} else {
brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok);
}
+ bus->sdiodev->sleeping = sleep;
+ if (sleep)
+ wake_up(&bus->sdiodev->idle_wait);
+ brcmf_dbg(SDIO, "new state %s\n",
+ (sleep ? "SLEEP" : "WAKE"));
done:
brcmf_dbg(SDIO, "Exit: err=%d\n", err);
return err;
@@ -1909,7 +1909,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
bus->rxpending = true;
for (rd->seq_num = bus->rx_seq, rxleft = maxframes;
- !bus->rxskip && rxleft && brcmf_bus_ready(bus->sdiodev->bus_if);
+ !bus->rxskip && rxleft && bus->sdiodev->state == BRCMF_STATE_DATA;
rd->seq_num++, rxleft--) {
/* Handle glomming separately */
@@ -2376,8 +2376,6 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
/* Send frames until the limit or some other event */
for (cnt = 0; (cnt < maxframes) && data_ok(bus);) {
pkt_num = 1;
- if (down_interruptible(&bus->tx_seq_lock))
- return cnt;
if (bus->txglom)
pkt_num = min_t(u8, bus->tx_max - bus->tx_seq,
bus->sdiodev->txglomsz);
@@ -2393,13 +2391,10 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
__skb_queue_tail(&pktq, pkt);
}
spin_unlock_bh(&bus->txq_lock);
- if (i == 0) {
- up(&bus->tx_seq_lock);
+ if (i == 0)
break;
- }
ret = brcmf_sdio_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL);
- up(&bus->tx_seq_lock);
cnt += i;
@@ -2420,7 +2415,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
}
/* Deflow-control stack if needed */
- if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
+ if ((bus->sdiodev->state == BRCMF_STATE_DATA) &&
bus->txoff && (pktq_len(&bus->txq) < TXLOW)) {
bus->txoff = false;
brcmf_txflowblock(bus->sdiodev->dev, false);
@@ -2508,7 +2503,7 @@ static void brcmf_sdio_bus_stop(struct device *dev)
bus->watchdog_tsk = NULL;
}
- if (bus_if->state == BRCMF_BUS_DOWN) {
+ if (sdiodev->state != BRCMF_STATE_NOMEDIUM) {
sdio_claim_host(sdiodev->func[1]);
/* Enable clock for device interrupts */
@@ -2543,8 +2538,7 @@ static void brcmf_sdio_bus_stop(struct device *dev)
brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
/* Clear any held glomming stuff */
- if (bus->glomd)
- brcmu_pkt_buf_free_skb(bus->glomd);
+ brcmu_pkt_buf_free_skb(bus->glomd);
brcmf_sdio_free_glom(bus);
/* Clear rx control and wake any waiters */
@@ -2609,6 +2603,21 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
return ret;
}
+static int brcmf_sdio_pm_resume_wait(struct brcmf_sdio_dev *sdiodev)
+{
+#ifdef CONFIG_PM_SLEEP
+ int retry;
+
+ /* Wait for possible resume to complete */
+ retry = 0;
+ while ((atomic_read(&sdiodev->suspend)) && (retry++ != 50))
+ msleep(20);
+ if (atomic_read(&sdiodev->suspend))
+ return -EIO;
+#endif
+ return 0;
+}
+
static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
{
u32 newstatus = 0;
@@ -2619,6 +2628,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
brcmf_dbg(TRACE, "Enter\n");
+ if (brcmf_sdio_pm_resume_wait(bus->sdiodev))
+ return;
+
sdio_claim_host(bus->sdiodev->func[1]);
/* If waiting for HTAVAIL, check status */
@@ -2725,17 +2737,14 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
brcmf_sdio_clrintr(bus);
if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
- (down_interruptible(&bus->tx_seq_lock) == 0)) {
- if (data_ok(bus)) {
- sdio_claim_host(bus->sdiodev->func[1]);
- err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
- bus->ctrl_frame_len);
- sdio_release_host(bus->sdiodev->func[1]);
-
- bus->ctrl_frame_stat = false;
- brcmf_sdio_wait_event_wakeup(bus);
- }
- up(&bus->tx_seq_lock);
+ data_ok(bus)) {
+ sdio_claim_host(bus->sdiodev->func[1]);
+ err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
+ bus->ctrl_frame_len);
+ sdio_release_host(bus->sdiodev->func[1]);
+ bus->ctrl_frame_err = err;
+ bus->ctrl_frame_stat = false;
+ brcmf_sdio_wait_event_wakeup(bus);
}
/* Send queued frames (limit 1 if rx may still be pending) */
if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) &&
@@ -2746,7 +2755,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
brcmf_sdio_sendfromq(bus, framecnt);
}
- if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) {
+ if ((bus->sdiodev->state != BRCMF_STATE_DATA) || (err != 0)) {
brcmf_err("failed backplane access over SDIO, halting operation\n");
atomic_set(&bus->intstatus, 0);
} else if (atomic_read(&bus->intstatus) ||
@@ -2947,43 +2956,30 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
- int ret = -1;
+ int ret;
brcmf_dbg(TRACE, "Enter\n");
- if (down_interruptible(&bus->tx_seq_lock))
- return -EINTR;
-
- if (!data_ok(bus)) {
- brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
- bus->tx_max, bus->tx_seq);
- up(&bus->tx_seq_lock);
- /* Send from dpc */
- bus->ctrl_frame_buf = msg;
- bus->ctrl_frame_len = msglen;
- bus->ctrl_frame_stat = true;
-
- wait_event_interruptible_timeout(bus->ctrl_wait,
- !bus->ctrl_frame_stat,
- msecs_to_jiffies(2000));
-
- if (!bus->ctrl_frame_stat) {
- brcmf_dbg(SDIO, "ctrl_frame_stat == false\n");
- ret = 0;
- } else {
- brcmf_dbg(SDIO, "ctrl_frame_stat == true\n");
- bus->ctrl_frame_stat = false;
- if (down_interruptible(&bus->tx_seq_lock))
- return -EINTR;
- ret = -1;
- }
+ /* Send from dpc */
+ bus->ctrl_frame_buf = msg;
+ bus->ctrl_frame_len = msglen;
+ bus->ctrl_frame_stat = true;
+ if (atomic_read(&bus->dpc_tskcnt) == 0) {
+ atomic_inc(&bus->dpc_tskcnt);
+ queue_work(bus->brcmf_wq, &bus->datawork);
}
- if (ret == -1) {
- sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdio_bus_sleep(bus, false, false);
- ret = brcmf_sdio_tx_ctrlframe(bus, msg, msglen);
- sdio_release_host(bus->sdiodev->func[1]);
- up(&bus->tx_seq_lock);
+
+ wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat,
+ msecs_to_jiffies(CTL_DONE_TIMEOUT));
+
+ if (!bus->ctrl_frame_stat) {
+ brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n",
+ bus->ctrl_frame_err);
+ ret = bus->ctrl_frame_err;
+ } else {
+ brcmf_dbg(SDIO, "ctrl_frame timeout\n");
+ bus->ctrl_frame_stat = false;
+ ret = -ETIMEDOUT;
}
if (ret)
@@ -2991,7 +2987,7 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
else
bus->sdcnt.tx_ctlpkts++;
- return ret ? -EIO : 0;
+ return ret;
}
#ifdef DEBUG
@@ -3414,8 +3410,8 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus,
goto err;
}
- /* Allow HT Clock now that the ARM is running. */
- brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_LOAD);
+ /* Allow full data communication using DPC from now on. */
+ bus->sdiodev->state = BRCMF_STATE_DATA;
bcmerror = 0;
err:
@@ -3561,7 +3557,7 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus)
return;
}
- if (!brcmf_bus_ready(bus->sdiodev->bus_if)) {
+ if (bus->sdiodev->state != BRCMF_STATE_DATA) {
brcmf_err("bus is down. we have nothing to do\n");
return;
}
@@ -3584,10 +3580,6 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus)
static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
{
-#ifdef DEBUG
- struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev);
-#endif /* DEBUG */
-
brcmf_dbg(TIMER, "Enter\n");
/* Poll period: check device if appropriate. */
@@ -3631,7 +3623,7 @@ static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
}
#ifdef DEBUG
/* Poll for console output periodically */
- if (bus_if && bus_if->state == BRCMF_BUS_DATA &&
+ if (bus->sdiodev->state == BRCMF_STATE_DATA &&
bus->console_interval != 0) {
bus->console.count += BRCMF_WD_POLL_MS;
if (bus->console.count >= bus->console_interval) {
@@ -3872,11 +3864,6 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
goto fail;
}
- /* SDIO register access works so moving
- * state from UNKNOWN to DOWN.
- */
- brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN);
-
bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops);
if (IS_ERR(bus->ci)) {
brcmf_err("brcmf_chip_attach failed!\n");
@@ -4010,18 +3997,16 @@ static void brcmf_sdio_firmware_callback(struct device *dev,
brcmf_dbg(TRACE, "Enter: dev=%s\n", dev_name(dev));
- /* try to download image and nvram to the dongle */
- if (bus_if->state == BRCMF_BUS_DOWN) {
- bus->alp_only = true;
- err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
- if (err)
- goto fail;
- bus->alp_only = false;
- }
-
if (!bus_if->drvr)
return;
+ /* try to download image and nvram to the dongle */
+ bus->alp_only = true;
+ err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
+ if (err)
+ goto fail;
+ bus->alp_only = false;
+
/* Start the watchdog timer */
bus->sdcnt.tickcnt = 0;
brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
@@ -4147,7 +4132,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
spin_lock_init(&bus->rxctl_lock);
spin_lock_init(&bus->txq_lock);
- sema_init(&bus->tx_seq_lock, 1);
init_waitqueue_head(&bus->ctrl_wait);
init_waitqueue_head(&bus->dcmd_resp_wait);
@@ -4218,7 +4202,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
bus->idleclock = BRCMF_IDLE_ACTIVE;
/* SR state */
- bus->sleeping = false;
bus->sr_enabled = false;
brcmf_sdio_debugfs_create(bus);
@@ -4259,7 +4242,7 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
destroy_workqueue(bus->brcmf_wq);
if (bus->ci) {
- if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) {
+ if (bus->sdiodev->state != BRCMF_STATE_NOMEDIUM) {
sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
/* Leave the device in state where it is
@@ -4294,7 +4277,7 @@ void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick)
}
/* don't start the wd until fw is loaded */
- if (bus->sdiodev->bus_if->state != BRCMF_BUS_DATA)
+ if (bus->sdiodev->state != BRCMF_STATE_DATA)
return;
if (wdtick) {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h
index 8eb42620129c..ec2586a8425c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h
@@ -155,6 +155,13 @@
/* watchdog polling interval in ms */
#define BRCMF_WD_POLL_MS 10
+/* The state of the bus */
+enum brcmf_sdio_state {
+ BRCMF_STATE_DOWN, /* Device available, still initialising */
+ BRCMF_STATE_DATA, /* Ready for data transfers, DPC enabled */
+ BRCMF_STATE_NOMEDIUM /* No medium access to dongle possible */
+};
+
struct brcmf_sdreg {
int func;
int offset;
@@ -169,8 +176,8 @@ struct brcmf_sdio_dev {
u32 sbwad; /* Save backplane window address */
struct brcmf_sdio *bus;
atomic_t suspend; /* suspend flag */
- wait_queue_head_t request_word_wait;
- wait_queue_head_t request_buffer_wait;
+ bool sleeping;
+ wait_queue_head_t idle_wait;
struct device *dev;
struct brcmf_bus *bus_if;
struct brcmfmac_sdio_platform_data *pdata;
@@ -187,6 +194,7 @@ struct brcmf_sdio_dev {
char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
bool wowl_enabled;
+ enum brcmf_sdio_state state;
};
/* sdio core registers */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 4572defc280f..5df6aa72cc2d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -421,7 +421,7 @@ fail:
brcmf_err("fail!\n");
while (!list_empty(q)) {
req = list_entry(q->next, struct brcmf_usbreq, list);
- if (req && req->urb)
+ if (req)
usb_free_urb(req->urb);
list_del(q->next);
}
@@ -576,7 +576,7 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)
brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DOWN);
} else if (state == BRCMFMAC_USB_STATE_UP) {
brcmf_dbg(USB, "DBUS is up\n");
- brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DATA);
+ brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_UP);
} else {
brcmf_dbg(USB, "DBUS current state=%d\n", state);
}
@@ -1263,6 +1263,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
ret = brcmf_usb_bus_setup(devinfo);
if (ret)
goto fail;
+ /* we are done */
+ return 0;
}
bus->chip = bus_pub->devid;
bus->chiprev = bus_pub->chiprev;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/brcm80211/brcmsmac/debug.c
index c9a8b9360ab1..7a1fbb2e3a71 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/debug.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/debug.c
@@ -78,7 +78,7 @@ int brcms_debugfs_hardware_read(struct seq_file *s, void *data)
struct brcms_hardware *hw = drvr->wlc->hw;
struct bcma_device *core = hw->d11core;
struct bcma_bus *bus = core->bus;
- char boardrev[10];
+ char boardrev[BRCMU_BOARDREV_LEN];
seq_printf(s, "chipnum 0x%x\n"
"chiprev 0x%x\n"
diff --git a/drivers/net/wireless/brcm80211/brcmutil/utils.c b/drivers/net/wireless/brcm80211/brcmutil/utils.c
index 906e89ddf319..0543607002fd 100644
--- a/drivers/net/wireless/brcm80211/brcmutil/utils.c
+++ b/drivers/net/wireless/brcm80211/brcmutil/utils.c
@@ -267,15 +267,43 @@ char *brcmu_boardrev_str(u32 brev, char *buf)
char c;
if (brev < 0x100) {
- snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
+ snprintf(buf, BRCMU_BOARDREV_LEN, "%d.%d",
+ (brev & 0xf0) >> 4, brev & 0xf);
} else {
c = (brev & 0xf000) == 0x1000 ? 'P' : 'A';
- snprintf(buf, 8, "%c%03x", c, brev & 0xfff);
+ snprintf(buf, BRCMU_BOARDREV_LEN, "%c%03x", c, brev & 0xfff);
}
return buf;
}
EXPORT_SYMBOL(brcmu_boardrev_str);
+char *brcmu_dotrev_str(u32 dotrev, char *buf)
+{
+ u8 dotval[4];
+
+ if (!dotrev) {
+ snprintf(buf, BRCMU_DOTREV_LEN, "unknown");
+ return buf;
+ }
+ dotval[0] = (dotrev >> 24) & 0xFF;
+ dotval[1] = (dotrev >> 16) & 0xFF;
+ dotval[2] = (dotrev >> 8) & 0xFF;
+ dotval[3] = dotrev & 0xFF;
+
+ if (dotval[3])
+ snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d.%d.%d", dotval[0],
+ dotval[1], dotval[2], dotval[3]);
+ else if (dotval[2])
+ snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d.%d", dotval[0],
+ dotval[1], dotval[2]);
+ else
+ snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d", dotval[0],
+ dotval[1]);
+
+ return buf;
+}
+EXPORT_SYMBOL(brcmu_dotrev_str);
+
#if defined(DEBUG)
/* pretty hex print a pkt buffer chain */
void brcmu_prpkt(const char *msg, struct sk_buff *p0)
diff --git a/drivers/net/wireless/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/brcm80211/include/brcmu_utils.h
index a043e29f07e2..41969527b459 100644
--- a/drivers/net/wireless/brcm80211/include/brcmu_utils.h
+++ b/drivers/net/wireless/brcm80211/include/brcmu_utils.h
@@ -218,6 +218,10 @@ void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...)
}
#endif
+#define BRCMU_BOARDREV_LEN 8
+#define BRCMU_DOTREV_LEN 16
+
char *brcmu_boardrev_str(u32 brev, char *buf);
+char *brcmu_dotrev_str(u32 dotrev, char *buf);
#endif /* _BRCMU_UTILS_H_ */
diff --git a/drivers/net/wireless/cw1200/fwio.c b/drivers/net/wireless/cw1200/fwio.c
index 6f1b9aace8b3..30e7646d04af 100644
--- a/drivers/net/wireless/cw1200/fwio.c
+++ b/drivers/net/wireless/cw1200/fwio.c
@@ -66,25 +66,31 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
do { \
ret = cw1200_apb_write_32(priv, CW1200_APB(reg), (val)); \
if (ret < 0) \
- goto error; \
+ goto exit; \
+ } while (0)
+#define APB_WRITE2(reg, val) \
+ do { \
+ ret = cw1200_apb_write_32(priv, CW1200_APB(reg), (val)); \
+ if (ret < 0) \
+ goto free_buffer; \
} while (0)
#define APB_READ(reg, val) \
do { \
ret = cw1200_apb_read_32(priv, CW1200_APB(reg), &(val)); \
if (ret < 0) \
- goto error; \
+ goto free_buffer; \
} while (0)
#define REG_WRITE(reg, val) \
do { \
ret = cw1200_reg_write_32(priv, (reg), (val)); \
if (ret < 0) \
- goto error; \
+ goto exit; \
} while (0)
#define REG_READ(reg, val) \
do { \
ret = cw1200_reg_read_32(priv, (reg), &(val)); \
if (ret < 0) \
- goto error; \
+ goto exit; \
} while (0)
switch (priv->hw_revision) {
@@ -142,14 +148,14 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
ret = request_firmware(&firmware, fw_path, priv->pdev);
if (ret) {
pr_err("Can't load firmware file %s.\n", fw_path);
- goto error;
+ goto exit;
}
buf = kmalloc(DOWNLOAD_BLOCK_SIZE, GFP_KERNEL | GFP_DMA);
if (!buf) {
pr_err("Can't allocate firmware load buffer.\n");
ret = -ENOMEM;
- goto error;
+ goto firmware_release;
}
/* Check if the bootloader is ready */
@@ -163,7 +169,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
if (val32 != DOWNLOAD_I_AM_HERE) {
pr_err("Bootloader is not ready.\n");
ret = -ETIMEDOUT;
- goto error;
+ goto free_buffer;
}
/* Calculcate number of download blocks */
@@ -171,7 +177,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
/* Updating the length in Download Ctrl Area */
val32 = firmware->size; /* Explicit cast from size_t to u32 */
- APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, val32);
+ APB_WRITE2(DOWNLOAD_IMAGE_SIZE_REG, val32);
/* Firmware downloading loop */
for (block = 0; block < num_blocks; block++) {
@@ -183,7 +189,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
if (val32 != DOWNLOAD_PENDING) {
pr_err("Bootloader reported error %d.\n", val32);
ret = -EIO;
- goto error;
+ goto free_buffer;
}
/* loop until put - get <= 24K */
@@ -198,7 +204,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
if ((put - get) > (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) {
pr_err("Timeout waiting for FIFO.\n");
ret = -ETIMEDOUT;
- goto error;
+ goto free_buffer;
}
/* calculate the block size */
@@ -220,12 +226,12 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
if (ret < 0) {
pr_err("Can't write firmware block @ %d!\n",
put & (DOWNLOAD_FIFO_SIZE - 1));
- goto error;
+ goto free_buffer;
}
/* update the put register */
put += block_size;
- APB_WRITE(DOWNLOAD_PUT_REG, put);
+ APB_WRITE2(DOWNLOAD_PUT_REG, put);
} /* End of firmware download loop */
/* Wait for the download completion */
@@ -238,19 +244,21 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
if (val32 != DOWNLOAD_SUCCESS) {
pr_err("Wait for download completion failed: 0x%.8X\n", val32);
ret = -ETIMEDOUT;
- goto error;
+ goto free_buffer;
} else {
pr_info("Firmware download completed.\n");
ret = 0;
}
-error:
+free_buffer:
kfree(buf);
- if (firmware)
- release_firmware(firmware);
+firmware_release:
+ release_firmware(firmware);
+exit:
return ret;
#undef APB_WRITE
+#undef APB_WRITE2
#undef APB_READ
#undef REG_WRITE
#undef REG_READ
diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c
index fa965ee9f56b..3689dbbd10bd 100644
--- a/drivers/net/wireless/cw1200/main.c
+++ b/drivers/net/wireless/cw1200/main.c
@@ -282,7 +282,6 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SUPPORTS_UAPSD |
IEEE80211_HW_CONNECTION_MONITOR |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c
index f2e276faca70..bff81b8d4164 100644
--- a/drivers/net/wireless/cw1200/scan.c
+++ b/drivers/net/wireless/cw1200/scan.c
@@ -39,9 +39,9 @@ static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan)
cancel_delayed_work_sync(&priv->clear_recent_scan_work);
atomic_set(&priv->scan.in_progress, 1);
atomic_set(&priv->recent_scan, 1);
- cw1200_pm_stay_awake(&priv->pm_state, tmo * HZ / 1000);
+ cw1200_pm_stay_awake(&priv->pm_state, msecs_to_jiffies(tmo));
queue_delayed_work(priv->workqueue, &priv->scan.timeout,
- tmo * HZ / 1000);
+ msecs_to_jiffies(tmo));
ret = wsm_scan(priv, scan);
if (ret) {
atomic_set(&priv->scan.in_progress, 0);
@@ -386,8 +386,8 @@ void cw1200_probe_work(struct work_struct *work)
if (down_trylock(&priv->scan.lock)) {
/* Scan is already in progress. Requeue self. */
schedule();
- queue_delayed_work(priv->workqueue,
- &priv->scan.probe_work, HZ / 10);
+ queue_delayed_work(priv->workqueue, &priv->scan.probe_work,
+ msecs_to_jiffies(100));
mutex_unlock(&priv->conf_mutex);
return;
}
diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c
index 5b84664db13b..4a47c7f8a246 100644
--- a/drivers/net/wireless/cw1200/sta.c
+++ b/drivers/net/wireless/cw1200/sta.c
@@ -213,6 +213,7 @@ int cw1200_add_interface(struct ieee80211_hw *dev,
/* __le32 auto_calibration_mode = __cpu_to_le32(1); */
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
+ IEEE80211_VIF_SUPPORTS_UAPSD |
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
mutex_lock(&priv->conf_mutex);
@@ -708,7 +709,8 @@ int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
if (sta)
peer_addr = sta->addr;
- key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
+ key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE |
+ IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 596525528f50..fd8d83dd4f62 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -145,7 +145,7 @@ static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
if (sta->aid > 0)
ap->sta_aid[sta->aid - 1] = NULL;
- if (!sta->ap && sta->u.sta.challenge)
+ if (!sta->ap)
kfree(sta->u.sta.challenge);
del_timer_sync(&sta->timer);
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index de43dd7e170a..c4d6dd7402d9 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -1228,11 +1228,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
- if (!iwlwifi_mod_params.wd_disable)
- trans_cfg.queue_watchdog_timeout =
- priv->cfg->base_params->wd_timeout;
- else
- trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED;
+ trans_cfg.cmd_q_wdg_timeout = IWL_WATCHDOG_DISABLED;
+
trans_cfg.command_names = iwl_dvm_cmd_strings;
trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM;
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
index d1ce3ce13591..1e40a12de077 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tx.c
@@ -715,7 +715,7 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
fifo = ctx->ac_to_fifo[tid_to_ac[tid]];
iwl_trans_txq_enable(priv->trans, q, fifo, sta_priv->sta_id, tid,
- buf_size, ssn);
+ buf_size, ssn, 0);
/*
* If the limit is 0, then it wasn't initialised yet,
diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c
index d5cee1530597..4dbef7e58c2e 100644
--- a/drivers/net/wireless/iwlwifi/dvm/ucode.c
+++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c
@@ -267,7 +267,7 @@ static int iwl_alive_notify(struct iwl_priv *priv)
for (i = 0; i < n_queues; i++)
if (queue_to_txf[i] != IWL_TX_FIFO_UNUSED)
iwl_trans_ac_txq_enable(priv->trans, i,
- queue_to_txf[i]);
+ queue_to_txf[i], 0);
priv->passive_no_rx = false;
priv->transport_queue_stop = 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
index 9e76799c4750..97e38d2e2983 100644
--- a/drivers/net/wireless/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -69,8 +69,8 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
-#define IWL7260_UCODE_API_MAX 10
-#define IWL3160_UCODE_API_MAX 10
+#define IWL7260_UCODE_API_MAX 12
+#define IWL3160_UCODE_API_MAX 12
/* Oldest version we won't warn about */
#define IWL7260_UCODE_API_OK 10
@@ -111,7 +111,7 @@
#define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode"
#define IWL7265D_FW_PRE "iwlwifi-7265D-"
-#define IWL7265D_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode"
+#define IWL7265D_MODULE_FIRMWARE(api) IWL7265D_FW_PRE __stringify(api) ".ucode"
#define NVM_HW_SECTION_NUM_FAMILY_7000 0
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c
index 46e9c9ac6ba2..2f7fe8167dc9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-8000.c
@@ -69,7 +69,7 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
-#define IWL8000_UCODE_API_MAX 10
+#define IWL8000_UCODE_API_MAX 12
/* Oldest version we won't warn about */
#define IWL8000_UCODE_API_OK 10
@@ -84,6 +84,8 @@
/* Memory offsets and lengths */
#define IWL8260_DCCM_OFFSET 0x800000
#define IWL8260_DCCM_LEN 0x18000
+#define IWL8260_DCCM2_OFFSET 0x880000
+#define IWL8260_DCCM2_LEN 0x8000
#define IWL8260_SMEM_OFFSET 0x400000
#define IWL8260_SMEM_LEN 0x68000
@@ -134,6 +136,8 @@ static const struct iwl_ht_params iwl8000_ht_params = {
.non_shared_ant = ANT_A, \
.dccm_offset = IWL8260_DCCM_OFFSET, \
.dccm_len = IWL8260_DCCM_LEN, \
+ .dccm2_offset = IWL8260_DCCM2_OFFSET, \
+ .dccm2_len = IWL8260_DCCM2_LEN, \
.smem_offset = IWL8260_SMEM_OFFSET, \
.smem_len = IWL8260_SMEM_LEN
@@ -156,6 +160,16 @@ const struct iwl_cfg iwl8260_2ac_cfg = {
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
};
+const struct iwl_cfg iwl4165_2ac_cfg = {
+ .name = "Intel(R) Dual Band Wireless AC 4165",
+ .fw_name_pre = IWL8000_FW_PRE,
+ IWL_DEVICE_8000,
+ .ht_params = &iwl8000_ht_params,
+ .nvm_ver = IWL8000_NVM_VERSION,
+ .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
+ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+};
+
const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
.name = "Intel(R) Dual Band Wireless-AC 8260",
.fw_name_pre = IWL8000_FW_PRE,
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index fa0bc4845e1a..4b190d98a1ec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -126,7 +126,7 @@ enum iwl_led_mode {
/* TX queue watchdog timeouts in mSecs */
#define IWL_WATCHDOG_DISABLED 0
-#define IWL_DEF_WD_TIMEOUT 2000
+#define IWL_DEF_WD_TIMEOUT 2500
#define IWL_LONG_WD_TIMEOUT 10000
#define IWL_MAX_WD_TIMEOUT 120000
@@ -263,6 +263,8 @@ struct iwl_pwr_tx_backoff {
* station can receive in VHT
* @dccm_offset: offset from which DCCM begins
* @dccm_len: length of DCCM (including runtime stack CCM)
+ * @dccm2_offset: offset from which the second DCCM begins
+ * @dccm2_len: length of the second DCCM
* @smem_offset: offset from which the SMEM begins
* @smem_len: the length of SMEM
*
@@ -310,6 +312,8 @@ struct iwl_cfg {
unsigned int max_vht_ampdu_exponent;
const u32 dccm_offset;
const u32 dccm_len;
+ const u32 dccm2_offset;
+ const u32 dccm2_len;
const u32 smem_offset;
const u32 smem_len;
};
@@ -378,6 +382,7 @@ extern const struct iwl_cfg iwl7265d_2n_cfg;
extern const struct iwl_cfg iwl7265d_n_cfg;
extern const struct iwl_cfg iwl8260_2n_cfg;
extern const struct iwl_cfg iwl8260_2ac_cfg;
+extern const struct iwl_cfg iwl4165_2ac_cfg;
extern const struct iwl_cfg iwl8260_2ac_sdio_cfg;
extern const struct iwl_cfg iwl4165_2ac_sdio_cfg;
#endif /* CONFIG_IWLMVM */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 7f40cf36ec0e..faa17f2e352a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -307,6 +307,7 @@
enum {
SILICON_A_STEP = 0,
SILICON_B_STEP,
+ SILICON_C_STEP,
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index e766dcdf72ab..996e7f16adf9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -1367,7 +1367,6 @@ struct iwl_mod_params iwlwifi_mod_params = {
.restart_fw = true,
.bt_coex_active = true,
.power_level = IWL_POWER_INDEX_1,
- .wd_disable = true,
.d0i3_disable = true,
#ifndef CONFIG_IWLWIFI_UAPSD
.uapsd_disable = true,
@@ -1478,10 +1477,6 @@ module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling,
MODULE_PARM_DESC(antenna_coupling,
"specify antenna coupling in dB (default: 0 dB)");
-module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO);
-MODULE_PARM_DESC(wd_disable,
- "Disable stuck queue watchdog timer 0=system default, 1=disable (default: 1)");
-
module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO);
MODULE_PARM_DESC(nvm_file, "NVM file name");
@@ -1490,7 +1485,7 @@ module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable,
MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)");
module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable,
- bool, S_IRUGO);
+ bool, S_IRUGO | S_IWUSR);
#ifdef CONFIG_IWLWIFI_UAPSD
MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: N)");
#else
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index ec115bded88a..919a2548a92c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -134,6 +134,27 @@ struct iwl_fw_error_dump_txcmd {
u8 data[];
} __packed;
+/**
+ * struct iwl_fw_error_dump_fifo - RX/TX FIFO data
+ * @fifo_num: number of FIFO (starting from 0)
+ * @available_bytes: num of bytes available in FIFO (may be less than FIFO size)
+ * @wr_ptr: position of write pointer
+ * @rd_ptr: position of read pointer
+ * @fence_ptr: position of fence pointer
+ * @fence_mode: the current mode of the fence (before locking) -
+ * 0=follow RD pointer ; 1 = freeze
+ * @data: all of the FIFO's data
+ */
+struct iwl_fw_error_dump_fifo {
+ __le32 fifo_num;
+ __le32 available_bytes;
+ __le32 wr_ptr;
+ __le32 rd_ptr;
+ __le32 fence_ptr;
+ __le32 fence_mode;
+ u8 data[];
+} __packed;
+
enum iwl_fw_error_dump_family {
IWL_FW_ERROR_DUMP_FAMILY_7 = 7,
IWL_FW_ERROR_DUMP_FAMILY_8 = 8,
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 752c72b77fba..016d91384681 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -235,25 +235,34 @@ enum iwl_ucode_tlv_flag {
/**
* enum iwl_ucode_tlv_api - ucode api
- * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field.
- * @IWL_UCODE_TLV_CAPA_EXTENDED_BEACON: Support Extended beacon notification
* @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex
- * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA.
* @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit.
* @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API.
* @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif.
* @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time
* longer than the passive one, which is essential for fragmented scan.
+ * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR
+ * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command,
+ * regardless of the band or the number of the probes. FW will calculate
+ * the actual dwell time.
+ * @IWL_UCODE_TLV_API_SCD_CFG: This firmware can configure the scheduler
+ * through the dedicated host command.
+ * @IWL_UCODE_TLV_API_SINGLE_SCAN_EBS: EBS is supported for single scans too.
+ * @IWL_UCODE_TLV_API_ASYNC_DTM: Async temperature notifications are supported.
+ * @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params
*/
enum iwl_ucode_tlv_api {
- IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0),
- IWL_UCODE_TLV_CAPA_EXTENDED_BEACON = BIT(1),
IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3),
- IWL_UCODE_TLV_API_CSA_FLOW = BIT(4),
IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5),
IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6),
IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7),
IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8),
+ IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10),
+ IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13),
+ IWL_UCODE_TLV_API_SCD_CFG = BIT(15),
+ IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = BIT(16),
+ IWL_UCODE_TLV_API_ASYNC_DTM = BIT(17),
+ IWL_UCODE_TLV_API_LQ_SS_PARAMS = BIT(18),
};
/**
@@ -261,6 +270,7 @@ enum iwl_ucode_tlv_api {
* @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3
* @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory
* @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan.
+ * @IWL_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer
* @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality
* @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current
* tx power value into TPC Report action frame and Link Measurement Report
@@ -279,6 +289,7 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0),
IWL_UCODE_TLV_CAPA_LAR_SUPPORT = BIT(1),
IWL_UCODE_TLV_CAPA_UMAC_SCAN = BIT(2),
+ IWL_UCODE_TLV_CAPA_BEAMFORMER = BIT(3),
IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = BIT(6),
IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8),
IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9),
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index 7a2cbf6f90db..03250a45272e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -193,11 +193,15 @@ void iwl_force_nmi(struct iwl_trans *trans)
* DEVICE_SET_NMI_8000B_REG - is used.
*/
if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) ||
- (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP))
- iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL);
- else
+ (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) {
+ iwl_write_prph(trans, DEVICE_SET_NMI_REG,
+ DEVICE_SET_NMI_VAL_DRV);
+ iwl_write_prph(trans, DEVICE_SET_NMI_REG,
+ DEVICE_SET_NMI_VAL_HW);
+ } else {
iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG,
DEVICE_SET_NMI_8000B_VAL);
+ }
}
IWL_EXPORT_SYMBOL(iwl_force_nmi);
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h
index 2a8cf4b2445c..e8eabd21ccfe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-modparams.h
+++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h
@@ -96,7 +96,6 @@ enum iwl_disable_11n {
* use IWL_[DIS,EN]ABLE_HT_* constants
* @amsdu_size_8K: enable 8K amsdu size, default = 0
* @restart_fw: restart firmware, default = 1
- * @wd_disable: disable stuck queue check, default = 1
* @bt_coex_active: enable bt coex, default = true
* @led_mode: system default, default = 0
* @power_save: enable power save, default = false
@@ -111,7 +110,6 @@ struct iwl_mod_params {
unsigned int disable_11n;
int amsdu_size_8K;
bool restart_fw;
- int wd_disable;
bool bt_coex_active;
int led_mode;
bool power_save;
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 83ab4239082c..6221e4dfc64f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -108,7 +108,8 @@
/* Device NMI register */
#define DEVICE_SET_NMI_REG 0x00a01c30
-#define DEVICE_SET_NMI_VAL 0x1
+#define DEVICE_SET_NMI_VAL_HW BIT(0)
+#define DEVICE_SET_NMI_VAL_DRV BIT(7)
#define DEVICE_SET_NMI_8000B_REG 0x00a01c24
#define DEVICE_SET_NMI_8000B_VAL 0x1000000
@@ -251,6 +252,7 @@
#define SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F)
#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16)
#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000)
+#define SCD_GP_CTRL_ENABLE_31_QUEUES BIT(0)
/* Context Data */
#define SCD_CONTEXT_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x600)
@@ -284,32 +286,9 @@
#define SCD_CHAINEXT_EN (SCD_BASE + 0x244)
#define SCD_AGGR_SEL (SCD_BASE + 0x248)
#define SCD_INTERRUPT_MASK (SCD_BASE + 0x108)
+#define SCD_GP_CTRL (SCD_BASE + 0x1a8)
#define SCD_EN_CTRL (SCD_BASE + 0x254)
-static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl)
-{
- if (chnl < 20)
- return SCD_BASE + 0x18 + chnl * 4;
- WARN_ON_ONCE(chnl >= 32);
- return SCD_BASE + 0x284 + (chnl - 20) * 4;
-}
-
-static inline unsigned int SCD_QUEUE_RDPTR(unsigned int chnl)
-{
- if (chnl < 20)
- return SCD_BASE + 0x68 + chnl * 4;
- WARN_ON_ONCE(chnl >= 32);
- return SCD_BASE + 0x2B4 + (chnl - 20) * 4;
-}
-
-static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl)
-{
- if (chnl < 20)
- return SCD_BASE + 0x10c + chnl * 4;
- WARN_ON_ONCE(chnl >= 32);
- return SCD_BASE + 0x384 + (chnl - 20) * 4;
-}
-
/*********************** END TX SCHEDULER *************************************/
/* Oscillator clock */
@@ -359,12 +338,30 @@ enum secure_load_status_reg {
/* Rx FIFO */
#define RXF_SIZE_ADDR (0xa00c88)
+#define RXF_RD_D_SPACE (0xa00c40)
+#define RXF_RD_WR_PTR (0xa00c50)
+#define RXF_RD_RD_PTR (0xa00c54)
+#define RXF_RD_FENCE_PTR (0xa00c4c)
+#define RXF_SET_FENCE_MODE (0xa00c14)
+#define RXF_LD_WR2FENCE (0xa00c1c)
+#define RXF_FIFO_RD_FENCE_INC (0xa00c68)
#define RXF_SIZE_BYTE_CND_POS (7)
#define RXF_SIZE_BYTE_CNT_MSK (0x3ff << RXF_SIZE_BYTE_CND_POS)
+#define RXF_DIFF_FROM_PREV (0x200)
#define RXF_LD_FENCE_OFFSET_ADDR (0xa00c10)
#define RXF_FIFO_RD_FENCE_ADDR (0xa00c0c)
+/* Tx FIFO */
+#define TXF_FIFO_ITEM_CNT (0xa00438)
+#define TXF_WR_PTR (0xa00414)
+#define TXF_RD_PTR (0xa00410)
+#define TXF_FENCE_PTR (0xa00418)
+#define TXF_LOCK_FENCE (0xa00424)
+#define TXF_LARC_NUM (0xa0043c)
+#define TXF_READ_MODIFY_DATA (0xa00448)
+#define TXF_READ_MODIFY_ADDR (0xa0044c)
+
/* FW monitor */
#define MON_BUFF_SAMPLE_CTL (0xa03c00)
#define MON_BUFF_BASE_ADDR (0xa03c3c)
diff --git a/drivers/net/wireless/iwlwifi/iwl-scd.h b/drivers/net/wireless/iwlwifi/iwl-scd.h
index 6c622b21bba7..f2353ebf2666 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scd.h
+++ b/drivers/net/wireless/iwlwifi/iwl-scd.h
@@ -69,14 +69,6 @@
#include "iwl-prph.h"
-static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans,
- u16 txq_id)
-{
- iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
- (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
- (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
-}
-
static inline void iwl_scd_txq_set_chain(struct iwl_trans *trans,
u16 txq_id)
{
@@ -115,4 +107,37 @@ static inline void iwl_scd_enable_set_active(struct iwl_trans *trans,
{
iwl_write_prph(trans, SCD_EN_CTRL, value);
}
+
+static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl)
+{
+ if (chnl < 20)
+ return SCD_BASE + 0x18 + chnl * 4;
+ WARN_ON_ONCE(chnl >= 32);
+ return SCD_BASE + 0x284 + (chnl - 20) * 4;
+}
+
+static inline unsigned int SCD_QUEUE_RDPTR(unsigned int chnl)
+{
+ if (chnl < 20)
+ return SCD_BASE + 0x68 + chnl * 4;
+ WARN_ON_ONCE(chnl >= 32);
+ return SCD_BASE + 0x2B4 + chnl * 4;
+}
+
+static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl)
+{
+ if (chnl < 20)
+ return SCD_BASE + 0x10c + chnl * 4;
+ WARN_ON_ONCE(chnl >= 32);
+ return SCD_BASE + 0x334 + chnl * 4;
+}
+
+static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans,
+ u16 txq_id)
+{
+ iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
+ (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+ (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 84d8477432a2..a96bd8db6ceb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -368,6 +368,7 @@ enum iwl_trans_status {
* @cmd_queue: the index of the command queue.
* Must be set before start_fw.
* @cmd_fifo: the fifo for host commands
+ * @cmd_q_wdg_timeout: the timeout of the watchdog timer for the command queue.
* @no_reclaim_cmds: Some devices erroneously don't set the
* SEQ_RX_FRAME bit on some notifications, this is the
* list of such notifications to filter. Max length is
@@ -378,8 +379,6 @@ enum iwl_trans_status {
* @bc_table_dword: set to true if the BC table expects the byte count to be
* in DWORD (as opposed to bytes)
* @scd_set_active: should the transport configure the SCD for HCMD queue
- * @queue_watchdog_timeout: time (in ms) after which queues
- * are considered stuck and will trigger device restart
* @command_names: array of command names, must be 256 entries
* (one for each command); for debugging only
* @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until
@@ -390,13 +389,13 @@ struct iwl_trans_config {
u8 cmd_queue;
u8 cmd_fifo;
+ unsigned int cmd_q_wdg_timeout;
const u8 *no_reclaim_cmds;
unsigned int n_no_reclaim_cmds;
bool rx_buf_size_8k;
bool bc_table_dword;
bool scd_set_active;
- unsigned int queue_watchdog_timeout;
const char *const *command_names;
u32 sdio_adma_addr;
@@ -511,7 +510,8 @@ struct iwl_trans_ops {
struct sk_buff_head *skbs);
void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn,
- const struct iwl_trans_txq_scd_cfg *cfg);
+ const struct iwl_trans_txq_scd_cfg *cfg,
+ unsigned int queue_wdg_timeout);
void (*txq_disable)(struct iwl_trans *trans, int queue,
bool configure_scd);
@@ -829,19 +829,21 @@ static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue,
static inline void
iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn,
- const struct iwl_trans_txq_scd_cfg *cfg)
+ const struct iwl_trans_txq_scd_cfg *cfg,
+ unsigned int queue_wdg_timeout)
{
might_sleep();
if (unlikely((trans->state != IWL_TRANS_FW_ALIVE)))
IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
- trans->ops->txq_enable(trans, queue, ssn, cfg);
+ trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout);
}
static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
int fifo, int sta_id, int tid,
- int frame_limit, u16 ssn)
+ int frame_limit, u16 ssn,
+ unsigned int queue_wdg_timeout)
{
struct iwl_trans_txq_scd_cfg cfg = {
.fifo = fifo,
@@ -851,11 +853,12 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
.aggregate = sta_id >= 0,
};
- iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg);
+ iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg, queue_wdg_timeout);
}
-static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue,
- int fifo)
+static inline
+void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, int fifo,
+ unsigned int queue_wdg_timeout)
{
struct iwl_trans_txq_scd_cfg cfg = {
.fifo = fifo,
@@ -865,16 +868,16 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue,
.aggregate = false,
};
- iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg);
+ iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg, queue_wdg_timeout);
}
static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans,
- u32 txq_bm)
+ u32 txqs)
{
if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
- return trans->ops->wait_tx_queue_empty(trans, txq_bm);
+ return trans->ops->wait_tx_queue_empty(trans, txqs);
}
static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c
index d2fd48c31d3d..1ec4d55155f7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex.c
@@ -342,7 +342,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 12,
.lut20 = {
- cpu_to_le32(0x00000001), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -363,7 +363,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 20,
.lut20 = {
- cpu_to_le32(0x00000002), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -384,7 +384,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 21,
.lut20 = {
- cpu_to_le32(0x00000003), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -405,7 +405,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 23,
.lut20 = {
- cpu_to_le32(0x00000004), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -426,7 +426,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 27,
.lut20 = {
- cpu_to_le32(0x00000005), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -447,7 +447,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 30,
.lut20 = {
- cpu_to_le32(0x00000006), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -468,7 +468,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 32,
.lut20 = {
- cpu_to_le32(0x00000007), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -489,7 +489,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 33,
.lut20 = {
- cpu_to_le32(0x00000008), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
index 973f2881dd1d..d530ef3da107 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
@@ -330,7 +330,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 12,
.lut20 = {
- cpu_to_le32(0x00000001), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -351,7 +351,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 20,
.lut20 = {
- cpu_to_le32(0x00000002), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -372,7 +372,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 21,
.lut20 = {
- cpu_to_le32(0x00000003), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -393,7 +393,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 23,
.lut20 = {
- cpu_to_le32(0x00000004), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -414,7 +414,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 27,
.lut20 = {
- cpu_to_le32(0x00000005), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -435,7 +435,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 30,
.lut20 = {
- cpu_to_le32(0x00000006), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -456,7 +456,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 32,
.lut20 = {
- cpu_to_le32(0x00000007), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -477,7 +477,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 33,
.lut20 = {
- cpu_to_le32(0x00000008), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h
index 7cd1de820ca7..beba375489f1 100644
--- a/drivers/net/wireless/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/iwlwifi/mvm/constants.h
@@ -94,21 +94,22 @@
#define IWL_MVM_BT_COEX_MPLUT 1
#define IWL_MVM_BT_COEX_RRC 1
#define IWL_MVM_BT_COEX_TTC 1
-#define IWL_MVM_BT_COEX_MPLUT_REG0 0x28412201
+#define IWL_MVM_BT_COEX_MPLUT_REG0 0x22002200
#define IWL_MVM_BT_COEX_MPLUT_REG1 0x11118451
#define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30
#define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0
#define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0
-#define IWL_MVM_QUOTA_THRESHOLD 8
+#define IWL_MVM_QUOTA_THRESHOLD 4
#define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0
-#define IWL_MVM_RS_DISABLE_MIMO 0
+#define IWL_MVM_RS_DISABLE_P2P_MIMO 0
#define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1
-#define IWL_MVM_RS_LEGACY_RETRIES_PER_RATE 1
#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2
#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1
#define IWL_MVM_RS_INITIAL_MIMO_NUM_RATES 3
#define IWL_MVM_RS_INITIAL_SISO_NUM_RATES 3
-#define IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES 16
+#define IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES 2
+#define IWL_MVM_RS_INITIAL_LEGACY_RETRIES 2
+#define IWL_MVM_RS_SECONDARY_LEGACY_RETRIES 1
#define IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES 16
#define IWL_MVM_RS_SECONDARY_SISO_NUM_RATES 3
#define IWL_MVM_RS_SECONDARY_SISO_RETRIES 1
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
index 8dc3ca9f4904..5fe14591e1c4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
@@ -517,6 +517,34 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
}
+static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_vif *vif = file->private_data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ char buf[20];
+ int len;
+
+ len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif,
+ char *buf, size_t count,
+ loff_t *ppos)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->mvm;
+ bool ret;
+
+ mutex_lock(&mvm->mutex);
+ ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid);
+ mutex_unlock(&mvm->mutex);
+
+ return ret ? count : -EINVAL;
+}
+
#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
@@ -531,6 +559,7 @@ MVM_DEBUGFS_READ_FILE_OPS(mac_params);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
@@ -564,6 +593,8 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir,
S_IRUSR | S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir,
+ S_IRUSR | S_IWUSR);
if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
mvmvif == mvm->bf_allowed_vif)
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index a1b276c4dee0..82c09d86af8c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -654,10 +654,10 @@ out:
return ret ?: count;
}
-#define PRINT_STATS_LE32(_str, _val) \
+#define PRINT_STATS_LE32(_struct, _memb) \
pos += scnprintf(buf + pos, bufsz - pos, \
- fmt_table, _str, \
- le32_to_cpu(_val))
+ fmt_table, #_memb, \
+ le32_to_cpu(_struct->_memb))
static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
char __user *user_buf, size_t count,
@@ -692,97 +692,89 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
"Statistics_Rx - OFDM");
- PRINT_STATS_LE32("ina_cnt", ofdm->ina_cnt);
- PRINT_STATS_LE32("fina_cnt", ofdm->fina_cnt);
- PRINT_STATS_LE32("plcp_err", ofdm->plcp_err);
- PRINT_STATS_LE32("crc32_err", ofdm->crc32_err);
- PRINT_STATS_LE32("overrun_err", ofdm->overrun_err);
- PRINT_STATS_LE32("early_overrun_err", ofdm->early_overrun_err);
- PRINT_STATS_LE32("crc32_good", ofdm->crc32_good);
- PRINT_STATS_LE32("false_alarm_cnt", ofdm->false_alarm_cnt);
- PRINT_STATS_LE32("fina_sync_err_cnt", ofdm->fina_sync_err_cnt);
- PRINT_STATS_LE32("sfd_timeout", ofdm->sfd_timeout);
- PRINT_STATS_LE32("fina_timeout", ofdm->fina_timeout);
- PRINT_STATS_LE32("unresponded_rts", ofdm->unresponded_rts);
- PRINT_STATS_LE32("rxe_frame_lmt_overrun",
- ofdm->rxe_frame_limit_overrun);
- PRINT_STATS_LE32("sent_ack_cnt", ofdm->sent_ack_cnt);
- PRINT_STATS_LE32("sent_cts_cnt", ofdm->sent_cts_cnt);
- PRINT_STATS_LE32("sent_ba_rsp_cnt", ofdm->sent_ba_rsp_cnt);
- PRINT_STATS_LE32("dsp_self_kill", ofdm->dsp_self_kill);
- PRINT_STATS_LE32("mh_format_err", ofdm->mh_format_err);
- PRINT_STATS_LE32("re_acq_main_rssi_sum", ofdm->re_acq_main_rssi_sum);
- PRINT_STATS_LE32("reserved", ofdm->reserved);
+ PRINT_STATS_LE32(ofdm, ina_cnt);
+ PRINT_STATS_LE32(ofdm, fina_cnt);
+ PRINT_STATS_LE32(ofdm, plcp_err);
+ PRINT_STATS_LE32(ofdm, crc32_err);
+ PRINT_STATS_LE32(ofdm, overrun_err);
+ PRINT_STATS_LE32(ofdm, early_overrun_err);
+ PRINT_STATS_LE32(ofdm, crc32_good);
+ PRINT_STATS_LE32(ofdm, false_alarm_cnt);
+ PRINT_STATS_LE32(ofdm, fina_sync_err_cnt);
+ PRINT_STATS_LE32(ofdm, sfd_timeout);
+ PRINT_STATS_LE32(ofdm, fina_timeout);
+ PRINT_STATS_LE32(ofdm, unresponded_rts);
+ PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun);
+ PRINT_STATS_LE32(ofdm, sent_ack_cnt);
+ PRINT_STATS_LE32(ofdm, sent_cts_cnt);
+ PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt);
+ PRINT_STATS_LE32(ofdm, dsp_self_kill);
+ PRINT_STATS_LE32(ofdm, mh_format_err);
+ PRINT_STATS_LE32(ofdm, re_acq_main_rssi_sum);
+ PRINT_STATS_LE32(ofdm, reserved);
pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
"Statistics_Rx - CCK");
- PRINT_STATS_LE32("ina_cnt", cck->ina_cnt);
- PRINT_STATS_LE32("fina_cnt", cck->fina_cnt);
- PRINT_STATS_LE32("plcp_err", cck->plcp_err);
- PRINT_STATS_LE32("crc32_err", cck->crc32_err);
- PRINT_STATS_LE32("overrun_err", cck->overrun_err);
- PRINT_STATS_LE32("early_overrun_err", cck->early_overrun_err);
- PRINT_STATS_LE32("crc32_good", cck->crc32_good);
- PRINT_STATS_LE32("false_alarm_cnt", cck->false_alarm_cnt);
- PRINT_STATS_LE32("fina_sync_err_cnt", cck->fina_sync_err_cnt);
- PRINT_STATS_LE32("sfd_timeout", cck->sfd_timeout);
- PRINT_STATS_LE32("fina_timeout", cck->fina_timeout);
- PRINT_STATS_LE32("unresponded_rts", cck->unresponded_rts);
- PRINT_STATS_LE32("rxe_frame_lmt_overrun",
- cck->rxe_frame_limit_overrun);
- PRINT_STATS_LE32("sent_ack_cnt", cck->sent_ack_cnt);
- PRINT_STATS_LE32("sent_cts_cnt", cck->sent_cts_cnt);
- PRINT_STATS_LE32("sent_ba_rsp_cnt", cck->sent_ba_rsp_cnt);
- PRINT_STATS_LE32("dsp_self_kill", cck->dsp_self_kill);
- PRINT_STATS_LE32("mh_format_err", cck->mh_format_err);
- PRINT_STATS_LE32("re_acq_main_rssi_sum", cck->re_acq_main_rssi_sum);
- PRINT_STATS_LE32("reserved", cck->reserved);
+ PRINT_STATS_LE32(cck, ina_cnt);
+ PRINT_STATS_LE32(cck, fina_cnt);
+ PRINT_STATS_LE32(cck, plcp_err);
+ PRINT_STATS_LE32(cck, crc32_err);
+ PRINT_STATS_LE32(cck, overrun_err);
+ PRINT_STATS_LE32(cck, early_overrun_err);
+ PRINT_STATS_LE32(cck, crc32_good);
+ PRINT_STATS_LE32(cck, false_alarm_cnt);
+ PRINT_STATS_LE32(cck, fina_sync_err_cnt);
+ PRINT_STATS_LE32(cck, sfd_timeout);
+ PRINT_STATS_LE32(cck, fina_timeout);
+ PRINT_STATS_LE32(cck, unresponded_rts);
+ PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun);
+ PRINT_STATS_LE32(cck, sent_ack_cnt);
+ PRINT_STATS_LE32(cck, sent_cts_cnt);
+ PRINT_STATS_LE32(cck, sent_ba_rsp_cnt);
+ PRINT_STATS_LE32(cck, dsp_self_kill);
+ PRINT_STATS_LE32(cck, mh_format_err);
+ PRINT_STATS_LE32(cck, re_acq_main_rssi_sum);
+ PRINT_STATS_LE32(cck, reserved);
pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
"Statistics_Rx - GENERAL");
- PRINT_STATS_LE32("bogus_cts", general->bogus_cts);
- PRINT_STATS_LE32("bogus_ack", general->bogus_ack);
- PRINT_STATS_LE32("non_bssid_frames", general->non_bssid_frames);
- PRINT_STATS_LE32("filtered_frames", general->filtered_frames);
- PRINT_STATS_LE32("non_channel_beacons", general->non_channel_beacons);
- PRINT_STATS_LE32("channel_beacons", general->channel_beacons);
- PRINT_STATS_LE32("num_missed_bcon", general->num_missed_bcon);
- PRINT_STATS_LE32("adc_rx_saturation_time",
- general->adc_rx_saturation_time);
- PRINT_STATS_LE32("ina_detection_search_time",
- general->ina_detection_search_time);
- PRINT_STATS_LE32("beacon_silence_rssi_a",
- general->beacon_silence_rssi_a);
- PRINT_STATS_LE32("beacon_silence_rssi_b",
- general->beacon_silence_rssi_b);
- PRINT_STATS_LE32("beacon_silence_rssi_c",
- general->beacon_silence_rssi_c);
- PRINT_STATS_LE32("interference_data_flag",
- general->interference_data_flag);
- PRINT_STATS_LE32("channel_load", general->channel_load);
- PRINT_STATS_LE32("dsp_false_alarms", general->dsp_false_alarms);
- PRINT_STATS_LE32("beacon_rssi_a", general->beacon_rssi_a);
- PRINT_STATS_LE32("beacon_rssi_b", general->beacon_rssi_b);
- PRINT_STATS_LE32("beacon_rssi_c", general->beacon_rssi_c);
- PRINT_STATS_LE32("beacon_energy_a", general->beacon_energy_a);
- PRINT_STATS_LE32("beacon_energy_b", general->beacon_energy_b);
- PRINT_STATS_LE32("beacon_energy_c", general->beacon_energy_c);
- PRINT_STATS_LE32("num_bt_kills", general->num_bt_kills);
- PRINT_STATS_LE32("mac_id", general->mac_id);
- PRINT_STATS_LE32("directed_data_mpdu", general->directed_data_mpdu);
+ PRINT_STATS_LE32(general, bogus_cts);
+ PRINT_STATS_LE32(general, bogus_ack);
+ PRINT_STATS_LE32(general, non_bssid_frames);
+ PRINT_STATS_LE32(general, filtered_frames);
+ PRINT_STATS_LE32(general, non_channel_beacons);
+ PRINT_STATS_LE32(general, channel_beacons);
+ PRINT_STATS_LE32(general, num_missed_bcon);
+ PRINT_STATS_LE32(general, adc_rx_saturation_time);
+ PRINT_STATS_LE32(general, ina_detection_search_time);
+ PRINT_STATS_LE32(general, beacon_silence_rssi_a);
+ PRINT_STATS_LE32(general, beacon_silence_rssi_b);
+ PRINT_STATS_LE32(general, beacon_silence_rssi_c);
+ PRINT_STATS_LE32(general, interference_data_flag);
+ PRINT_STATS_LE32(general, channel_load);
+ PRINT_STATS_LE32(general, dsp_false_alarms);
+ PRINT_STATS_LE32(general, beacon_rssi_a);
+ PRINT_STATS_LE32(general, beacon_rssi_b);
+ PRINT_STATS_LE32(general, beacon_rssi_c);
+ PRINT_STATS_LE32(general, beacon_energy_a);
+ PRINT_STATS_LE32(general, beacon_energy_b);
+ PRINT_STATS_LE32(general, beacon_energy_c);
+ PRINT_STATS_LE32(general, num_bt_kills);
+ PRINT_STATS_LE32(general, mac_id);
+ PRINT_STATS_LE32(general, directed_data_mpdu);
pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
"Statistics_Rx - HT");
- PRINT_STATS_LE32("plcp_err", ht->plcp_err);
- PRINT_STATS_LE32("overrun_err", ht->overrun_err);
- PRINT_STATS_LE32("early_overrun_err", ht->early_overrun_err);
- PRINT_STATS_LE32("crc32_good", ht->crc32_good);
- PRINT_STATS_LE32("crc32_err", ht->crc32_err);
- PRINT_STATS_LE32("mh_format_err", ht->mh_format_err);
- PRINT_STATS_LE32("agg_crc32_good", ht->agg_crc32_good);
- PRINT_STATS_LE32("agg_mpdu_cnt", ht->agg_mpdu_cnt);
- PRINT_STATS_LE32("agg_cnt", ht->agg_cnt);
- PRINT_STATS_LE32("unsupport_mcs", ht->unsupport_mcs);
+ PRINT_STATS_LE32(ht, plcp_err);
+ PRINT_STATS_LE32(ht, overrun_err);
+ PRINT_STATS_LE32(ht, early_overrun_err);
+ PRINT_STATS_LE32(ht, crc32_good);
+ PRINT_STATS_LE32(ht, crc32_err);
+ PRINT_STATS_LE32(ht, mh_format_err);
+ PRINT_STATS_LE32(ht, agg_crc32_good);
+ PRINT_STATS_LE32(ht, agg_mpdu_cnt);
+ PRINT_STATS_LE32(ht, agg_cnt);
+ PRINT_STATS_LE32(ht, unsupport_mcs);
mutex_unlock(&mvm->mutex);
@@ -988,9 +980,14 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
char *buf, size_t count,
loff_t *ppos)
{
- mutex_lock(&mvm->mutex);
+ int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
+
+ if (ret)
+ return ret;
+
iwl_mvm_fw_dbg_collect(mvm);
- mutex_unlock(&mvm->mutex);
+
+ iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);
return count;
}
@@ -1390,6 +1387,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
PRINT_MVM_REF(IWL_MVM_REF_TM_CMD);
PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK);
PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA);
+ PRINT_MVM_REF(IWL_MVM_REF_FW_DBG_COLLECT);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
@@ -1489,6 +1487,26 @@ out:
return count;
}
+static ssize_t iwl_dbgfs_enable_scan_iteration_notif_write(struct iwl_mvm *mvm,
+ char *buf,
+ size_t count,
+ loff_t *ppos)
+{
+ int val;
+
+ mutex_lock(&mvm->mutex);
+
+ if (kstrtoint(buf, 10, &val)) {
+ mutex_unlock(&mvm->mutex);
+ return -EINVAL;
+ }
+
+ mvm->scan_iter_notif_enabled = val;
+ mutex_unlock(&mvm->mutex);
+
+ return count;
+}
+
MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
/* Device wide debugfs entries */
@@ -1511,6 +1529,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 8);
+MVM_DEBUGFS_WRITE_FILE_OPS(enable_scan_iteration_notif, 8);
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
@@ -1554,6 +1573,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE(enable_scan_iteration_notif, mvm->debugfs_dir,
+ S_IWUSR);
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
index 430020047b77..4fc0938b3fb6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
@@ -92,14 +92,32 @@ enum iwl_ltr_config_flags {
};
/**
+ * struct iwl_ltr_config_cmd_v1 - configures the LTR
+ * @flags: See %enum iwl_ltr_config_flags
+ */
+struct iwl_ltr_config_cmd_v1 {
+ __le32 flags;
+ __le32 static_long;
+ __le32 static_short;
+} __packed; /* LTR_CAPABLE_API_S_VER_1 */
+
+#define LTR_VALID_STATES_NUM 4
+
+/**
* struct iwl_ltr_config_cmd - configures the LTR
* @flags: See %enum iwl_ltr_config_flags
+ * @static_long:
+ * @static_short:
+ * @ltr_cfg_values:
+ * @ltr_short_idle_timeout:
*/
struct iwl_ltr_config_cmd {
__le32 flags;
__le32 static_long;
__le32 static_short;
-} __packed;
+ __le32 ltr_cfg_values[LTR_VALID_STATES_NUM];
+ __le32 ltr_short_idle_timeout;
+} __packed; /* LTR_CAPABLE_API_S_VER_2 */
/* Radio LP RX Energy Threshold measured in dBm */
#define POWER_LPRX_RSSI_THRESHOLD 75
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
index 8bb5b94bf963..0f1ea80a55ef 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
@@ -308,6 +308,42 @@ enum {
#define LQ_FLAG_DYNAMIC_BW_POS 6
#define LQ_FLAG_DYNAMIC_BW_MSK (1 << LQ_FLAG_DYNAMIC_BW_POS)
+/* Single Stream Tx Parameters (lq_cmd->ss_params)
+ * Flags to control a smart FW decision about whether BFER/STBC/SISO will be
+ * used for single stream Tx.
+ */
+
+/* Bit 0-1: Max STBC streams allowed. Can be 0-3.
+ * (0) - No STBC allowed
+ * (1) - 2x1 STBC allowed (HT/VHT)
+ * (2) - 4x2 STBC allowed (HT/VHT)
+ * (3) - 3x2 STBC allowed (HT only)
+ * All our chips are at most 2 antennas so only (1) is valid for now.
+ */
+#define LQ_SS_STBC_ALLOWED_POS 0
+#define LQ_SS_STBC_ALLOWED_MSK (3 << LQ_SS_STBC_ALLOWED_MSK)
+
+/* 2x1 STBC is allowed */
+#define LQ_SS_STBC_1SS_ALLOWED (1 << LQ_SS_STBC_ALLOWED_POS)
+
+/* Bit 2: Beamformer (VHT only) is allowed */
+#define LQ_SS_BFER_ALLOWED_POS 2
+#define LQ_SS_BFER_ALLOWED (1 << LQ_SS_BFER_ALLOWED_POS)
+
+/* Bit 3: Force BFER or STBC for testing
+ * If this is set:
+ * If BFER is allowed then force the ucode to choose BFER else
+ * If STBC is allowed then force the ucode to choose STBC over SISO
+ */
+#define LQ_SS_FORCE_POS 3
+#define LQ_SS_FORCE (1 << LQ_SS_FORCE_POS)
+
+/* Bit 31: ss_params field is valid. Used for FW backward compatibility
+ * with other drivers which don't support the ss_params API yet
+ */
+#define LQ_SS_PARAMS_VALID_POS 31
+#define LQ_SS_PARAMS_VALID (1 << LQ_SS_PARAMS_VALID_POS)
+
/**
* struct iwl_lq_cmd - link quality command
* @sta_id: station to update
@@ -330,7 +366,7 @@ enum {
* 2 - 0x3f: maximal number of frames (up to 3f == 63)
* @rs_table: array of rates for each TX try, each is rate_n_flags,
* meaning it is a combination of RATE_MCS_* and IWL_RATE_*_PLCP
- * @bf_params: beam forming params, currently not used
+ * @ss_params: single stream features. declare whether STBC or BFER are allowed.
*/
struct iwl_lq_cmd {
u8 sta_id;
@@ -348,6 +384,6 @@ struct iwl_lq_cmd {
u8 agg_frame_cnt_limit;
__le32 reserved2;
__le32 rs_table[LQ_MAX_RETRY_NUM];
- __le32 bf_params;
+ __le32 ss_params;
}; /* LINK_QUALITY_CMD_API_S_VER_1 */
#endif /* __fw_api_rs_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
index 2d1a81c493f1..cfc0e65b34a5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -675,6 +675,7 @@ struct iwl_scan_channel_opt {
* @IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented
* @IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED: insert WFA vendor-specific TPC report
* and DS parameter set IEs into probe requests.
+ * @IWL_MVM_LMAC_SCAN_FLAG_MATCH: Send match found notification on matches
*/
enum iwl_mvm_lmac_scan_flags {
IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL = BIT(0),
@@ -684,6 +685,7 @@ enum iwl_mvm_lmac_scan_flags {
IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS = BIT(4),
IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED = BIT(5),
IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED = BIT(6),
+ IWL_MVM_LMAC_SCAN_FLAG_MATCH = BIT(9),
};
enum iwl_scan_priority {
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h
new file mode 100644
index 000000000000..928168b18346
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h
@@ -0,0 +1,277 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __fw_api_stats_h__
+#define __fw_api_stats_h__
+
+struct mvm_statistics_dbg {
+ __le32 burst_check;
+ __le32 burst_count;
+ __le32 wait_for_silence_timeout_cnt;
+ __le32 reserved[3];
+} __packed; /* STATISTICS_DEBUG_API_S_VER_2 */
+
+struct mvm_statistics_div {
+ __le32 tx_on_a;
+ __le32 tx_on_b;
+ __le32 exec_time;
+ __le32 probe_time;
+ __le32 rssi_ant;
+ __le32 reserved2;
+} __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */
+
+struct mvm_statistics_rx_non_phy {
+ __le32 bogus_cts; /* CTS received when not expecting CTS */
+ __le32 bogus_ack; /* ACK received when not expecting ACK */
+ __le32 non_bssid_frames; /* number of frames with BSSID that
+ * doesn't belong to the STA BSSID */
+ __le32 filtered_frames; /* count frames that were dumped in the
+ * filtering process */
+ __le32 non_channel_beacons; /* beacons with our bss id but not on
+ * our serving channel */
+ __le32 channel_beacons; /* beacons with our bss id and in our
+ * serving channel */
+ __le32 num_missed_bcon; /* number of missed beacons */
+ __le32 adc_rx_saturation_time; /* count in 0.8us units the time the
+ * ADC was in saturation */
+ __le32 ina_detection_search_time;/* total time (in 0.8us) searched
+ * for INA */
+ __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */
+ __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */
+ __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */
+ __le32 interference_data_flag; /* flag for interference data
+ * availability. 1 when data is
+ * available. */
+ __le32 channel_load; /* counts RX Enable time in uSec */
+ __le32 dsp_false_alarms; /* DSP false alarm (both OFDM
+ * and CCK) counter */
+ __le32 beacon_rssi_a;
+ __le32 beacon_rssi_b;
+ __le32 beacon_rssi_c;
+ __le32 beacon_energy_a;
+ __le32 beacon_energy_b;
+ __le32 beacon_energy_c;
+ __le32 num_bt_kills;
+ __le32 mac_id;
+ __le32 directed_data_mpdu;
+} __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_3 */
+
+struct mvm_statistics_rx_phy {
+ __le32 ina_cnt;
+ __le32 fina_cnt;
+ __le32 plcp_err;
+ __le32 crc32_err;
+ __le32 overrun_err;
+ __le32 early_overrun_err;
+ __le32 crc32_good;
+ __le32 false_alarm_cnt;
+ __le32 fina_sync_err_cnt;
+ __le32 sfd_timeout;
+ __le32 fina_timeout;
+ __le32 unresponded_rts;
+ __le32 rxe_frame_lmt_overrun;
+ __le32 sent_ack_cnt;
+ __le32 sent_cts_cnt;
+ __le32 sent_ba_rsp_cnt;
+ __le32 dsp_self_kill;
+ __le32 mh_format_err;
+ __le32 re_acq_main_rssi_sum;
+ __le32 reserved;
+} __packed; /* STATISTICS_RX_PHY_API_S_VER_2 */
+
+struct mvm_statistics_rx_ht_phy {
+ __le32 plcp_err;
+ __le32 overrun_err;
+ __le32 early_overrun_err;
+ __le32 crc32_good;
+ __le32 crc32_err;
+ __le32 mh_format_err;
+ __le32 agg_crc32_good;
+ __le32 agg_mpdu_cnt;
+ __le32 agg_cnt;
+ __le32 unsupport_mcs;
+} __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_1 */
+
+struct mvm_statistics_tx_non_phy {
+ __le32 preamble_cnt;
+ __le32 rx_detected_cnt;
+ __le32 bt_prio_defer_cnt;
+ __le32 bt_prio_kill_cnt;
+ __le32 few_bytes_cnt;
+ __le32 cts_timeout;
+ __le32 ack_timeout;
+ __le32 expected_ack_cnt;
+ __le32 actual_ack_cnt;
+ __le32 dump_msdu_cnt;
+ __le32 burst_abort_next_frame_mismatch_cnt;
+ __le32 burst_abort_missing_next_frame_cnt;
+ __le32 cts_timeout_collision;
+ __le32 ack_or_ba_timeout_collision;
+} __packed; /* STATISTICS_TX_NON_PHY_API_S_VER_3 */
+
+#define MAX_CHAINS 3
+
+struct mvm_statistics_tx_non_phy_agg {
+ __le32 ba_timeout;
+ __le32 ba_reschedule_frames;
+ __le32 scd_query_agg_frame_cnt;
+ __le32 scd_query_no_agg;
+ __le32 scd_query_agg;
+ __le32 scd_query_mismatch;
+ __le32 frame_not_ready;
+ __le32 underrun;
+ __le32 bt_prio_kill;
+ __le32 rx_ba_rsp_cnt;
+ __s8 txpower[MAX_CHAINS];
+ __s8 reserved;
+ __le32 reserved2;
+} __packed; /* STATISTICS_TX_NON_PHY_AGG_API_S_VER_1 */
+
+struct mvm_statistics_tx_channel_width {
+ __le32 ext_cca_narrow_ch20[1];
+ __le32 ext_cca_narrow_ch40[2];
+ __le32 ext_cca_narrow_ch80[3];
+ __le32 ext_cca_narrow_ch160[4];
+ __le32 last_tx_ch_width_indx;
+ __le32 rx_detected_per_ch_width[4];
+ __le32 success_per_ch_width[4];
+ __le32 fail_per_ch_width[4];
+}; /* STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */
+
+struct mvm_statistics_tx {
+ struct mvm_statistics_tx_non_phy general;
+ struct mvm_statistics_tx_non_phy_agg agg;
+ struct mvm_statistics_tx_channel_width channel_width;
+} __packed; /* STATISTICS_TX_API_S_VER_4 */
+
+
+struct mvm_statistics_bt_activity {
+ __le32 hi_priority_tx_req_cnt;
+ __le32 hi_priority_tx_denied_cnt;
+ __le32 lo_priority_tx_req_cnt;
+ __le32 lo_priority_tx_denied_cnt;
+ __le32 hi_priority_rx_req_cnt;
+ __le32 hi_priority_rx_denied_cnt;
+ __le32 lo_priority_rx_req_cnt;
+ __le32 lo_priority_rx_denied_cnt;
+} __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */
+
+struct mvm_statistics_general {
+ __le32 radio_temperature;
+ __le32 radio_voltage;
+ struct mvm_statistics_dbg dbg;
+ __le32 sleep_time;
+ __le32 slots_out;
+ __le32 slots_idle;
+ __le32 ttl_timestamp;
+ struct mvm_statistics_div slow_div;
+ __le32 rx_enable_counter;
+ /*
+ * num_of_sos_states:
+ * count the number of times we have to re-tune
+ * in order to get out of bad PHY status
+ */
+ __le32 num_of_sos_states;
+ __le32 beacon_filtered;
+ __le32 missed_beacons;
+ __s8 beacon_filter_average_energy;
+ __s8 beacon_filter_reason;
+ __s8 beacon_filter_current_energy;
+ __s8 beacon_filter_reserved;
+ __le32 beacon_filter_delta_time;
+ struct mvm_statistics_bt_activity bt_activity;
+} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */
+
+struct mvm_statistics_rx {
+ struct mvm_statistics_rx_phy ofdm;
+ struct mvm_statistics_rx_phy cck;
+ struct mvm_statistics_rx_non_phy general;
+ struct mvm_statistics_rx_ht_phy ofdm_ht;
+} __packed; /* STATISTICS_RX_API_S_VER_3 */
+
+/*
+ * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
+ *
+ * By default, uCode issues this notification after receiving a beacon
+ * while associated. To disable this behavior, set DISABLE_NOTIF flag in the
+ * REPLY_STATISTICS_CMD 0x9c, above.
+ *
+ * Statistics counters continue to increment beacon after beacon, but are
+ * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
+ * 0x9c with CLEAR_STATS bit set (see above).
+ *
+ * uCode also issues this notification during scans. uCode clears statistics
+ * appropriately so that each notification contains statistics for only the
+ * one channel that has just been scanned.
+ */
+
+struct iwl_notif_statistics {
+ __le32 flag;
+ struct mvm_statistics_rx rx;
+ struct mvm_statistics_tx tx;
+ struct mvm_statistics_general general;
+} __packed; /* STATISTICS_NTFY_API_S_VER_8 */
+
+#endif /* __fw_api_stats_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
index 5bca1f8bfebf..81c4ea3c6958 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
@@ -592,4 +592,43 @@ static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm_tx_resp *tx_resp)
tx_resp->frame_count) & 0xfff;
}
+/**
+ * struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command
+ * @token:
+ * @sta_id: station id
+ * @tid:
+ * @scd_queue: scheduler queue to confiug
+ * @enable: 1 queue enable, 0 queue disable
+ * @aggregate: 1 aggregated queue, 0 otherwise
+ * @tx_fifo: %enum iwl_mvm_tx_fifo
+ * @window: BA window size
+ * @ssn: SSN for the BA agreement
+ */
+struct iwl_scd_txq_cfg_cmd {
+ u8 token;
+ u8 sta_id;
+ u8 tid;
+ u8 scd_queue;
+ u8 enable;
+ u8 aggregate;
+ u8 tx_fifo;
+ u8 window;
+ __le16 ssn;
+ __le16 reserved;
+} __packed; /* SCD_QUEUE_CFG_CMD_API_S_VER_1 */
+
+/**
+ * struct iwl_scd_txq_cfg_rsp
+ * @token: taken from the command
+ * @sta_id: station id from the command
+ * @tid: tid from the command
+ * @scd_queue: scd_queue from the command
+ */
+struct iwl_scd_txq_cfg_rsp {
+ u8 token;
+ u8 sta_id;
+ u8 tid;
+ u8 scd_queue;
+} __packed; /* SCD_QUEUE_CFG_RSP_API_S_VER_1 */
+
#endif /* __fw_api_tx_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 88af6dd2ceaa..b56154fe8ec5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -74,6 +74,7 @@
#include "fw-api-d3.h"
#include "fw-api-coex.h"
#include "fw-api-scan.h"
+#include "fw-api-stats.h"
/* Tx queue numbers */
enum {
@@ -128,6 +129,9 @@ enum {
/* global key */
WEP_KEY = 0x20,
+ /* Memory */
+ SHARED_MEM_CFG = 0x25,
+
/* TDLS */
TDLS_CHANNEL_SWITCH_CMD = 0x27,
TDLS_CHANNEL_SWITCH_NOTIFICATION = 0xaa,
@@ -1381,214 +1385,6 @@ struct iwl_mvm_marker {
__le32 metadata[0];
} __packed; /* MARKER_API_S_VER_1 */
-struct mvm_statistics_dbg {
- __le32 burst_check;
- __le32 burst_count;
- __le32 wait_for_silence_timeout_cnt;
- __le32 reserved[3];
-} __packed; /* STATISTICS_DEBUG_API_S_VER_2 */
-
-struct mvm_statistics_div {
- __le32 tx_on_a;
- __le32 tx_on_b;
- __le32 exec_time;
- __le32 probe_time;
- __le32 rssi_ant;
- __le32 reserved2;
-} __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */
-
-struct mvm_statistics_general_common {
- __le32 temperature; /* radio temperature */
- __le32 temperature_m; /* radio voltage */
- struct mvm_statistics_dbg dbg;
- __le32 sleep_time;
- __le32 slots_out;
- __le32 slots_idle;
- __le32 ttl_timestamp;
- struct mvm_statistics_div div;
- __le32 rx_enable_counter;
- /*
- * num_of_sos_states:
- * count the number of times we have to re-tune
- * in order to get out of bad PHY status
- */
- __le32 num_of_sos_states;
-} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */
-
-struct mvm_statistics_rx_non_phy {
- __le32 bogus_cts; /* CTS received when not expecting CTS */
- __le32 bogus_ack; /* ACK received when not expecting ACK */
- __le32 non_bssid_frames; /* number of frames with BSSID that
- * doesn't belong to the STA BSSID */
- __le32 filtered_frames; /* count frames that were dumped in the
- * filtering process */
- __le32 non_channel_beacons; /* beacons with our bss id but not on
- * our serving channel */
- __le32 channel_beacons; /* beacons with our bss id and in our
- * serving channel */
- __le32 num_missed_bcon; /* number of missed beacons */
- __le32 adc_rx_saturation_time; /* count in 0.8us units the time the
- * ADC was in saturation */
- __le32 ina_detection_search_time;/* total time (in 0.8us) searched
- * for INA */
- __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */
- __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */
- __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */
- __le32 interference_data_flag; /* flag for interference data
- * availability. 1 when data is
- * available. */
- __le32 channel_load; /* counts RX Enable time in uSec */
- __le32 dsp_false_alarms; /* DSP false alarm (both OFDM
- * and CCK) counter */
- __le32 beacon_rssi_a;
- __le32 beacon_rssi_b;
- __le32 beacon_rssi_c;
- __le32 beacon_energy_a;
- __le32 beacon_energy_b;
- __le32 beacon_energy_c;
- __le32 num_bt_kills;
- __le32 mac_id;
- __le32 directed_data_mpdu;
-} __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_3 */
-
-struct mvm_statistics_rx_phy {
- __le32 ina_cnt;
- __le32 fina_cnt;
- __le32 plcp_err;
- __le32 crc32_err;
- __le32 overrun_err;
- __le32 early_overrun_err;
- __le32 crc32_good;
- __le32 false_alarm_cnt;
- __le32 fina_sync_err_cnt;
- __le32 sfd_timeout;
- __le32 fina_timeout;
- __le32 unresponded_rts;
- __le32 rxe_frame_limit_overrun;
- __le32 sent_ack_cnt;
- __le32 sent_cts_cnt;
- __le32 sent_ba_rsp_cnt;
- __le32 dsp_self_kill;
- __le32 mh_format_err;
- __le32 re_acq_main_rssi_sum;
- __le32 reserved;
-} __packed; /* STATISTICS_RX_PHY_API_S_VER_2 */
-
-struct mvm_statistics_rx_ht_phy {
- __le32 plcp_err;
- __le32 overrun_err;
- __le32 early_overrun_err;
- __le32 crc32_good;
- __le32 crc32_err;
- __le32 mh_format_err;
- __le32 agg_crc32_good;
- __le32 agg_mpdu_cnt;
- __le32 agg_cnt;
- __le32 unsupport_mcs;
-} __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_1 */
-
-#define MAX_CHAINS 3
-
-struct mvm_statistics_tx_non_phy_agg {
- __le32 ba_timeout;
- __le32 ba_reschedule_frames;
- __le32 scd_query_agg_frame_cnt;
- __le32 scd_query_no_agg;
- __le32 scd_query_agg;
- __le32 scd_query_mismatch;
- __le32 frame_not_ready;
- __le32 underrun;
- __le32 bt_prio_kill;
- __le32 rx_ba_rsp_cnt;
- __s8 txpower[MAX_CHAINS];
- __s8 reserved;
- __le32 reserved2;
-} __packed; /* STATISTICS_TX_NON_PHY_AGG_API_S_VER_1 */
-
-struct mvm_statistics_tx_channel_width {
- __le32 ext_cca_narrow_ch20[1];
- __le32 ext_cca_narrow_ch40[2];
- __le32 ext_cca_narrow_ch80[3];
- __le32 ext_cca_narrow_ch160[4];
- __le32 last_tx_ch_width_indx;
- __le32 rx_detected_per_ch_width[4];
- __le32 success_per_ch_width[4];
- __le32 fail_per_ch_width[4];
-}; /* STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */
-
-struct mvm_statistics_tx {
- __le32 preamble_cnt;
- __le32 rx_detected_cnt;
- __le32 bt_prio_defer_cnt;
- __le32 bt_prio_kill_cnt;
- __le32 few_bytes_cnt;
- __le32 cts_timeout;
- __le32 ack_timeout;
- __le32 expected_ack_cnt;
- __le32 actual_ack_cnt;
- __le32 dump_msdu_cnt;
- __le32 burst_abort_next_frame_mismatch_cnt;
- __le32 burst_abort_missing_next_frame_cnt;
- __le32 cts_timeout_collision;
- __le32 ack_or_ba_timeout_collision;
- struct mvm_statistics_tx_non_phy_agg agg;
- struct mvm_statistics_tx_channel_width channel_width;
-} __packed; /* STATISTICS_TX_API_S_VER_4 */
-
-
-struct mvm_statistics_bt_activity {
- __le32 hi_priority_tx_req_cnt;
- __le32 hi_priority_tx_denied_cnt;
- __le32 lo_priority_tx_req_cnt;
- __le32 lo_priority_tx_denied_cnt;
- __le32 hi_priority_rx_req_cnt;
- __le32 hi_priority_rx_denied_cnt;
- __le32 lo_priority_rx_req_cnt;
- __le32 lo_priority_rx_denied_cnt;
-} __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */
-
-struct mvm_statistics_general {
- struct mvm_statistics_general_common common;
- __le32 beacon_filtered;
- __le32 missed_beacons;
- __s8 beacon_filter_average_energy;
- __s8 beacon_filter_reason;
- __s8 beacon_filter_current_energy;
- __s8 beacon_filter_reserved;
- __le32 beacon_filter_delta_time;
- struct mvm_statistics_bt_activity bt_activity;
-} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */
-
-struct mvm_statistics_rx {
- struct mvm_statistics_rx_phy ofdm;
- struct mvm_statistics_rx_phy cck;
- struct mvm_statistics_rx_non_phy general;
- struct mvm_statistics_rx_ht_phy ofdm_ht;
-} __packed; /* STATISTICS_RX_API_S_VER_3 */
-
-/*
- * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
- *
- * By default, uCode issues this notification after receiving a beacon
- * while associated. To disable this behavior, set DISABLE_NOTIF flag in the
- * REPLY_STATISTICS_CMD 0x9c, above.
- *
- * Statistics counters continue to increment beacon after beacon, but are
- * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
- * 0x9c with CLEAR_STATS bit set (see above).
- *
- * uCode also issues this notification during scans. uCode clears statistics
- * appropriately so that each notification contains statistics for only the
- * one channel that has just been scanned.
- */
-
-struct iwl_notif_statistics { /* STATISTICS_NTFY_API_S_VER_8 */
- __le32 flag;
- struct mvm_statistics_rx rx;
- struct mvm_statistics_tx tx;
- struct mvm_statistics_general general;
-} __packed;
-
/***********************************
* Smart Fifo API
***********************************/
@@ -1680,63 +1476,6 @@ struct iwl_dts_measurement_notif {
__le32 voltage;
} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */
-/**
- * enum iwl_scd_control - scheduler config command control flags
- * @IWL_SCD_CONTROL_RM_TID: remove TID from this queue
- * @IWL_SCD_CONTROL_SET_SSN: use the SSN and program it into HW
- */
-enum iwl_scd_control {
- IWL_SCD_CONTROL_RM_TID = BIT(4),
- IWL_SCD_CONTROL_SET_SSN = BIT(5),
-};
-
-/**
- * enum iwl_scd_flags - scheduler config command flags
- * @IWL_SCD_FLAGS_SHARE_TID: multiple TIDs map to this queue
- * @IWL_SCD_FLAGS_SHARE_RA: multiple RAs map to this queue
- * @IWL_SCD_FLAGS_DQA_ENABLED: DQA is enabled
- */
-enum iwl_scd_flags {
- IWL_SCD_FLAGS_SHARE_TID = BIT(0),
- IWL_SCD_FLAGS_SHARE_RA = BIT(1),
- IWL_SCD_FLAGS_DQA_ENABLED = BIT(2),
-};
-
-#define IWL_SCDQ_INVALID_STA 0xff
-
-/**
- * struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command
- * @token: dialog token addba - unused legacy
- * @sta_id: station id 4-bit
- * @tid: TID 0..7
- * @scd_queue: TFD queue num 0 .. 31
- * @enable: 1 queue enable, 0 queue disable
- * @aggregate: 1 aggregated queue, 0 otherwise
- * @tx_fifo: tx fifo num 0..7
- * @window: up to 64
- * @ssn: starting seq num 12-bit
- * @control: command control flags
- * @flags: flags - see &enum iwl_scd_flags
- *
- * Note that every time the command is sent, all parameters must
- * be filled with the exception of
- * - the SSN, which is only used with @IWL_SCD_CONTROL_SET_SSN
- * - the window, which is only relevant when starting aggregation
- */
-struct iwl_scd_txq_cfg_cmd {
- u8 token;
- u8 sta_id;
- u8 tid;
- u8 scd_queue;
- u8 enable;
- u8 aggregate;
- u8 tx_fifo;
- u8 window;
- __le16 ssn;
- u8 control;
- u8 flags;
-} __packed;
-
/***********************************
* TDLS API
***********************************/
@@ -1878,4 +1617,36 @@ struct iwl_tdls_config_res {
struct iwl_tdls_config_sta_info_res sta_info[IWL_MVM_TDLS_STA_COUNT];
} __packed; /* TDLS_CONFIG_RSP_API_S_VER_1 */
+#define TX_FIFO_MAX_NUM 8
+#define RX_FIFO_MAX_NUM 2
+
+/**
+ * Shared memory configuration information from the FW
+ *
+ * @shared_mem_addr: shared memory addr (pre 8000 HW set to 0x0 as MARBH is not
+ * accessible)
+ * @shared_mem_size: shared memory size
+ * @sample_buff_addr: internal sample (mon/adc) buff addr (pre 8000 HW set to
+ * 0x0 as accessible only via DBGM RDAT)
+ * @sample_buff_size: internal sample buff size
+ * @txfifo_addr: start addr of TXF0 (excluding the context table 0.5KB), (pre
+ * 8000 HW set to 0x0 as not accessible)
+ * @txfifo_size: size of TXF0 ... TXF7
+ * @rxfifo_size: RXF1, RXF2 sizes. If there is no RXF2, it'll have a value of 0
+ * @page_buff_addr: used by UMAC and performance debug (page miss analysis),
+ * when paging is not supported this should be 0
+ * @page_buff_size: size of %page_buff_addr
+ */
+struct iwl_shared_mem_cfg {
+ __le32 shared_mem_addr;
+ __le32 shared_mem_size;
+ __le32 sample_buff_addr;
+ __le32 sample_buff_size;
+ __le32 txfifo_addr;
+ __le32 txfifo_size[TX_FIFO_MAX_NUM];
+ __le32 rxfifo_size[RX_FIFO_MAX_NUM];
+ __le32 page_buff_addr;
+ __le32 page_buff_size;
+} __packed; /* SHARED_MEM_ALLOC_API_S_VER_1 */
+
#endif /* __fw_api_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index 534ee3123a63..ca38e9817374 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -400,10 +400,59 @@ out:
return ret;
}
-void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm)
+static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm)
{
+ struct iwl_host_cmd cmd = {
+ .id = SHARED_MEM_CFG,
+ .flags = CMD_WANT_SKB,
+ .data = { NULL, },
+ .len = { 0, },
+ };
+ struct iwl_rx_packet *pkt;
+ struct iwl_shared_mem_cfg *mem_cfg;
+ u32 i;
+
lockdep_assert_held(&mvm->mutex);
+ if (WARN_ON(iwl_mvm_send_cmd(mvm, &cmd)))
+ return;
+
+ pkt = cmd.resp_pkt;
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERR(mvm, "Bad return from SHARED_MEM_CFG (0x%08X)\n",
+ pkt->hdr.flags);
+ goto exit;
+ }
+
+ mem_cfg = (void *)pkt->data;
+
+ mvm->shared_mem_cfg.shared_mem_addr =
+ le32_to_cpu(mem_cfg->shared_mem_addr);
+ mvm->shared_mem_cfg.shared_mem_size =
+ le32_to_cpu(mem_cfg->shared_mem_size);
+ mvm->shared_mem_cfg.sample_buff_addr =
+ le32_to_cpu(mem_cfg->sample_buff_addr);
+ mvm->shared_mem_cfg.sample_buff_size =
+ le32_to_cpu(mem_cfg->sample_buff_size);
+ mvm->shared_mem_cfg.txfifo_addr = le32_to_cpu(mem_cfg->txfifo_addr);
+ for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size); i++)
+ mvm->shared_mem_cfg.txfifo_size[i] =
+ le32_to_cpu(mem_cfg->txfifo_size[i]);
+ for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.rxfifo_size); i++)
+ mvm->shared_mem_cfg.rxfifo_size[i] =
+ le32_to_cpu(mem_cfg->rxfifo_size[i]);
+ mvm->shared_mem_cfg.page_buff_addr =
+ le32_to_cpu(mem_cfg->page_buff_addr);
+ mvm->shared_mem_cfg.page_buff_size =
+ le32_to_cpu(mem_cfg->page_buff_size);
+ IWL_DEBUG_INFO(mvm, "SHARED MEM CFG: got memory offsets/sizes\n");
+
+exit:
+ iwl_free_resp(&cmd);
+}
+
+void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm)
+{
/* stop recording */
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
@@ -412,11 +461,7 @@ void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm)
iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0);
}
- iwl_mvm_fw_error_dump(mvm);
-
- /* start recording again */
- WARN_ON_ONCE(mvm->fw->dbg_dest_tlv &&
- iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf));
+ schedule_work(&mvm->fw_error_dump_wk);
}
int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id)
@@ -454,6 +499,35 @@ int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id)
return ret;
}
+static int iwl_mvm_config_ltr_v1(struct iwl_mvm *mvm)
+{
+ struct iwl_ltr_config_cmd_v1 cmd_v1 = {
+ .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE),
+ };
+
+ if (!mvm->trans->ltr_enabled)
+ return 0;
+
+ return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
+ sizeof(cmd_v1), &cmd_v1);
+}
+
+static int iwl_mvm_config_ltr(struct iwl_mvm *mvm)
+{
+ struct iwl_ltr_config_cmd cmd = {
+ .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE),
+ };
+
+ if (!mvm->trans->ltr_enabled)
+ return 0;
+
+ if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_HDC_PHASE_0))
+ return iwl_mvm_config_ltr_v1(mvm);
+
+ return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
+ sizeof(cmd), &cmd);
+}
+
int iwl_mvm_up(struct iwl_mvm *mvm)
{
int ret, i;
@@ -501,6 +575,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto error;
}
+ if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10)
+ iwl_mvm_get_shared_mem_conf(mvm);
+
ret = iwl_mvm_sf_update(mvm, NULL, false);
if (ret)
IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
@@ -557,14 +634,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
/* Initialize tx backoffs to the minimal possible */
iwl_mvm_tt_tx_backoff(mvm, 0);
- if (mvm->trans->ltr_enabled) {
- struct iwl_ltr_config_cmd cmd = {
- .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE),
- };
-
- WARN_ON(iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
- sizeof(cmd), &cmd));
- }
+ WARN_ON(iwl_mvm_config_ltr(mvm));
ret = iwl_mvm_power_update_device(mvm);
if (ret)
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 7196b4d6b7cc..7bdc6220743f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -208,8 +208,10 @@ u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif)
if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
return BIT(IWL_MVM_OFFCHANNEL_QUEUE);
- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
- qmask |= BIT(vif->hw_queue[ac]);
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
+ qmask |= BIT(vif->hw_queue[ac]);
+ }
if (vif->type == NL80211_IFTYPE_AP)
qmask |= BIT(vif->cab_queue);
@@ -460,6 +462,9 @@ exit_fail:
int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
+ unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ?
+ mvm->cfg->base_params->wd_timeout :
+ IWL_WATCHDOG_DISABLED;
u32 ac;
int ret;
@@ -472,16 +477,17 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
switch (vif->type) {
case NL80211_IFTYPE_P2P_DEVICE:
iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
- IWL_MVM_TX_FIFO_VO);
+ IWL_MVM_TX_FIFO_VO, wdg_timeout);
break;
case NL80211_IFTYPE_AP:
iwl_mvm_enable_ac_txq(mvm, vif->cab_queue,
- IWL_MVM_TX_FIFO_MCAST);
+ IWL_MVM_TX_FIFO_MCAST, wdg_timeout);
/* fall through */
default:
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac],
- iwl_mvm_ac_to_tx_fifo[ac]);
+ iwl_mvm_ac_to_tx_fifo[ac],
+ wdg_timeout);
break;
}
@@ -496,14 +502,14 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
switch (vif->type) {
case NL80211_IFTYPE_P2P_DEVICE:
- iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE);
+ iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, 0);
break;
case NL80211_IFTYPE_AP:
- iwl_mvm_disable_txq(mvm, vif->cab_queue);
+ iwl_mvm_disable_txq(mvm, vif->cab_queue, 0);
/* fall through */
default:
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
- iwl_mvm_disable_txq(mvm, vif->hw_queue[ac]);
+ iwl_mvm_disable_txq(mvm, vif->hw_queue[ac], 0);
}
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 3756c03e752f..1ff7ec08532d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -327,6 +327,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC |
IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED;
hw->rate_control_algorithm = "iwl-mvm-rs";
+ hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
+ hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
/*
* Enable 11w if advertised by firmware and software crypto
@@ -337,13 +339,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
!iwlwifi_mod_params.sw_crypto)
hw->flags |= IEEE80211_HW_MFP_CAPABLE;
- if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT &&
- !iwlwifi_mod_params.uapsd_disable) {
- hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD;
- hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
- hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
- }
-
if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN ||
mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS;
@@ -406,10 +401,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels)
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&mvm->nvm_data->bands[IEEE80211_BAND_2GHZ];
- if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels)
+ if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels) {
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
+ if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER)
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
+ }
+
hw->wiphy->hw_version = mvm->trans->hw_id;
if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)
@@ -712,9 +712,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
mvmvif->uploaded = false;
mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
- /* does this make sense at all? */
- mvmvif->color++;
-
spin_lock_bh(&mvm->time_event_lock);
iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data);
spin_unlock_bh(&mvm->time_event_lock);
@@ -766,6 +763,132 @@ static void iwl_mvm_free_coredump(const void *data)
kfree(fw_error_dump);
}
+static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
+ struct iwl_fw_error_dump_data **dump_data)
+{
+ struct iwl_fw_error_dump_fifo *fifo_hdr;
+ u32 *fifo_data;
+ u32 fifo_len;
+ unsigned long flags;
+ int i, j;
+
+ if (!iwl_trans_grab_nic_access(mvm->trans, false, &flags))
+ return;
+
+ /* Pull RXF data from all RXFs */
+ for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.rxfifo_size); i++) {
+ /*
+ * Keep aside the additional offset that might be needed for
+ * next RXF
+ */
+ u32 offset_diff = RXF_DIFF_FROM_PREV * i;
+
+ fifo_hdr = (void *)(*dump_data)->data;
+ fifo_data = (void *)fifo_hdr->data;
+ fifo_len = mvm->shared_mem_cfg.rxfifo_size[i];
+
+ /* No need to try to read the data if the length is 0 */
+ if (fifo_len == 0)
+ continue;
+
+ /* Add a TLV for the RXF */
+ (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF);
+ (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr));
+
+ fifo_hdr->fifo_num = cpu_to_le32(i);
+ fifo_hdr->available_bytes =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ RXF_RD_D_SPACE +
+ offset_diff));
+ fifo_hdr->wr_ptr =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ RXF_RD_WR_PTR +
+ offset_diff));
+ fifo_hdr->rd_ptr =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ RXF_RD_RD_PTR +
+ offset_diff));
+ fifo_hdr->fence_ptr =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ RXF_RD_FENCE_PTR +
+ offset_diff));
+ fifo_hdr->fence_mode =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ RXF_SET_FENCE_MODE +
+ offset_diff));
+
+ /* Lock fence */
+ iwl_trans_write_prph(mvm->trans,
+ RXF_SET_FENCE_MODE + offset_diff, 0x1);
+ /* Set fence pointer to the same place like WR pointer */
+ iwl_trans_write_prph(mvm->trans,
+ RXF_LD_WR2FENCE + offset_diff, 0x1);
+ /* Set fence offset */
+ iwl_trans_write_prph(mvm->trans,
+ RXF_LD_FENCE_OFFSET_ADDR + offset_diff,
+ 0x0);
+
+ /* Read FIFO */
+ fifo_len /= sizeof(u32); /* Size in DWORDS */
+ for (j = 0; j < fifo_len; j++)
+ fifo_data[j] = iwl_trans_read_prph(mvm->trans,
+ RXF_FIFO_RD_FENCE_INC +
+ offset_diff);
+ *dump_data = iwl_fw_error_next_data(*dump_data);
+ }
+
+ /* Pull TXF data from all TXFs */
+ for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size); i++) {
+ /* Mark the number of TXF we're pulling now */
+ iwl_trans_write_prph(mvm->trans, TXF_LARC_NUM, i);
+
+ fifo_hdr = (void *)(*dump_data)->data;
+ fifo_data = (void *)fifo_hdr->data;
+ fifo_len = mvm->shared_mem_cfg.txfifo_size[i];
+
+ /* No need to try to read the data if the length is 0 */
+ if (fifo_len == 0)
+ continue;
+
+ /* Add a TLV for the FIFO */
+ (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXF);
+ (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr));
+
+ fifo_hdr->fifo_num = cpu_to_le32(i);
+ fifo_hdr->available_bytes =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ TXF_FIFO_ITEM_CNT));
+ fifo_hdr->wr_ptr =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ TXF_WR_PTR));
+ fifo_hdr->rd_ptr =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ TXF_RD_PTR));
+ fifo_hdr->fence_ptr =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ TXF_FENCE_PTR));
+ fifo_hdr->fence_mode =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ TXF_LOCK_FENCE));
+
+ /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */
+ iwl_trans_write_prph(mvm->trans, TXF_READ_MODIFY_ADDR,
+ TXF_WR_PTR);
+
+ /* Dummy-read to advance the read pointer to the head */
+ iwl_trans_read_prph(mvm->trans, TXF_READ_MODIFY_DATA);
+
+ /* Read FIFO */
+ fifo_len /= sizeof(u32); /* Size in DWORDS */
+ for (j = 0; j < fifo_len; j++)
+ fifo_data[j] = iwl_trans_read_prph(mvm->trans,
+ TXF_READ_MODIFY_DATA);
+ *dump_data = iwl_fw_error_next_data(*dump_data);
+ }
+
+ iwl_trans_release_nic_access(mvm->trans, &flags);
+}
+
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
{
struct iwl_fw_error_dump_file *dump_file;
@@ -774,18 +897,21 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
struct iwl_fw_error_dump_mem *dump_mem;
struct iwl_mvm_dump_ptrs *fw_error_dump;
u32 sram_len, sram_ofs;
- u32 file_len, rxf_len;
- unsigned long flags;
- int reg_val;
+ u32 file_len, fifo_data_len = 0;
u32 smem_len = mvm->cfg->smem_len;
+ u32 sram2_len = mvm->cfg->dccm2_len;
lockdep_assert_held(&mvm->mutex);
/* W/A for 8000 HW family A-step */
- if (mvm->cfg->smem_len &&
- mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
- CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP)
- smem_len = 0x38000;
+ if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
+ CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) {
+ if (smem_len)
+ smem_len = 0x38000;
+
+ if (sram2_len)
+ sram2_len = 0x10000;
+ }
fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
if (!fw_error_dump)
@@ -803,23 +929,49 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
sram_len = mvm->cfg->dccm_len;
}
- /* reading buffer size */
- reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR);
- rxf_len = (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS;
+ /* reading RXF/TXF sizes */
+ if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) {
+ struct iwl_mvm_shared_mem_cfg *mem_cfg = &mvm->shared_mem_cfg;
+ int i;
+
+ fifo_data_len = 0;
+
+ /* Count RXF size */
+ for (i = 0; i < ARRAY_SIZE(mem_cfg->rxfifo_size); i++) {
+ if (!mem_cfg->rxfifo_size[i])
+ continue;
+
+ /* Add header info */
+ fifo_data_len += mem_cfg->rxfifo_size[i] +
+ sizeof(*dump_data) +
+ sizeof(struct iwl_fw_error_dump_fifo);
+ }
- /* the register holds the value divided by 128 */
- rxf_len = rxf_len << 7;
+ for (i = 0; i < ARRAY_SIZE(mem_cfg->txfifo_size); i++) {
+ if (!mem_cfg->txfifo_size[i])
+ continue;
+
+ /* Add header info */
+ fifo_data_len += mem_cfg->txfifo_size[i] +
+ sizeof(*dump_data) +
+ sizeof(struct iwl_fw_error_dump_fifo);
+ }
+ }
file_len = sizeof(*dump_file) +
- sizeof(*dump_data) * 3 +
+ sizeof(*dump_data) * 2 +
sram_len + sizeof(*dump_mem) +
- rxf_len +
+ fifo_data_len +
sizeof(*dump_info);
/* Make room for the SMEM, if it exists */
if (smem_len)
file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len;
+ /* Make room for the secondary SRAM, if it exists */
+ if (sram2_len)
+ file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len;
+
dump_file = vzalloc(file_len);
if (!dump_file) {
kfree(fw_error_dump);
@@ -847,24 +999,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
sizeof(dump_info->bus_human_readable));
dump_data = iwl_fw_error_next_data(dump_data);
- dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF);
- dump_data->len = cpu_to_le32(rxf_len);
+ /* We only dump the FIFOs if the FW is in error state */
+ if (test_bit(STATUS_FW_ERROR, &mvm->trans->status))
+ iwl_mvm_dump_fifos(mvm, &dump_data);
- if (iwl_trans_grab_nic_access(mvm->trans, false, &flags)) {
- u32 *rxf = (void *)dump_data->data;
- int i;
-
- for (i = 0; i < (rxf_len / sizeof(u32)); i++) {
- iwl_trans_write_prph(mvm->trans,
- RXF_LD_FENCE_OFFSET_ADDR,
- i * sizeof(u32));
- rxf[i] = iwl_trans_read_prph(mvm->trans,
- RXF_FIFO_RD_FENCE_ADDR);
- }
- iwl_trans_release_nic_access(mvm->trans, &flags);
- }
-
- dump_data = iwl_fw_error_next_data(dump_data);
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem));
dump_mem = (void *)dump_data->data;
@@ -884,6 +1022,17 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
dump_mem->data, smem_len);
}
+ if (sram2_len) {
+ dump_data = iwl_fw_error_next_data(dump_data);
+ dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
+ dump_data->len = cpu_to_le32(sram2_len + sizeof(*dump_mem));
+ dump_mem = (void *)dump_data->data;
+ dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM);
+ dump_mem->offset = cpu_to_le32(mvm->cfg->dccm2_offset);
+ iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->dccm2_offset,
+ dump_mem->data, sram2_len);
+ }
+
fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans);
fw_error_dump->op_mode_len = file_len;
if (fw_error_dump->trans_ptr)
@@ -1206,7 +1355,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
ret = iwl_mvm_power_update_mac(mvm);
if (ret)
- goto out_release;
+ goto out_remove_mac;
/* beacon filtering */
ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
@@ -2165,6 +2314,20 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
mutex_unlock(&mvm->mutex);
}
+static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ const u8 *bssid)
+{
+ if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT))
+ return;
+
+ if (iwlwifi_mod_params.uapsd_disable) {
+ vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
+ return;
+ }
+
+ vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
+}
+
static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -2224,6 +2387,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
* Reset EBS status here assuming environment has been changed.
*/
mvm->last_ebs_successful = true;
+ iwl_mvm_check_uapsd(mvm, vif, sta->addr);
ret = 0;
} else if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC) {
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index b2100b414055..6c69d0584f6c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -119,11 +119,13 @@ extern const struct ieee80211_ops iwl_mvm_hw_ops;
* We will register to mac80211 to have testmode working. The NIC must not
* be up'ed after the INIT fw asserted. This is useful to be able to use
* proprietary tools over testmode to debug the INIT fw.
+ * @tfd_q_hang_detect: enabled the detection of hung transmit queues
* @power_scheme: CAM(Continuous Active Mode)-1, BPS(Balanced Power
* Save)-2(default), LP(Low Power)-3
*/
struct iwl_mvm_mod_params {
bool init_dbg;
+ bool tfd_q_hang_detect;
int power_scheme;
};
extern struct iwl_mvm_mod_params iwlmvm_mod_params;
@@ -276,6 +278,7 @@ enum iwl_mvm_ref_type {
IWL_MVM_REF_TM_CMD,
IWL_MVM_REF_EXIT_WORK,
IWL_MVM_REF_PROTECT_CSA,
+ IWL_MVM_REF_FW_DBG_COLLECT,
/* update debugfs.c when changing this */
@@ -531,10 +534,23 @@ enum {
enum iwl_mvm_tdls_cs_state {
IWL_MVM_TDLS_SW_IDLE = 0,
IWL_MVM_TDLS_SW_REQ_SENT,
+ IWL_MVM_TDLS_SW_RESP_RCVD,
IWL_MVM_TDLS_SW_REQ_RCVD,
IWL_MVM_TDLS_SW_ACTIVE,
};
+struct iwl_mvm_shared_mem_cfg {
+ u32 shared_mem_addr;
+ u32 shared_mem_size;
+ u32 sample_buff_addr;
+ u32 sample_buff_size;
+ u32 txfifo_addr;
+ u32 txfifo_size[TX_FIFO_MAX_NUM];
+ u32 rxfifo_size[RX_FIFO_MAX_NUM];
+ u32 page_buff_addr;
+ u32 page_buff_size;
+};
+
struct iwl_mvm {
/* for logger access */
struct device *dev;
@@ -641,6 +657,8 @@ struct iwl_mvm {
bool disable_power_off;
bool disable_power_off_d3;
+ bool scan_iter_notif_enabled;
+
struct debugfs_blob_wrapper nvm_hw_blob;
struct debugfs_blob_wrapper nvm_sw_blob;
struct debugfs_blob_wrapper nvm_calib_blob;
@@ -782,8 +800,13 @@ struct iwl_mvm {
struct cfg80211_chan_def chandef;
struct sk_buff *skb; /* ch sw template */
u32 ch_sw_tm_ie;
+
+ /* timestamp of last ch-sw request sent (GP2 time) */
+ u32 sent_timestamp;
} peer;
} tdls_cs;
+
+ struct iwl_mvm_shared_mem_cfg shared_mem_cfg;
};
/* Extract MVM priv from op_mode and _hw */
@@ -855,9 +878,9 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)
(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
}
-static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm)
+static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm)
{
- return mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_DQA_SUPPORT;
+ return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG;
}
extern const u8 iwl_mvm_ac_to_tx_fifo[];
@@ -999,6 +1022,9 @@ int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
/* MVM PHY */
int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
@@ -1060,6 +1086,9 @@ int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan);
int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req,
@@ -1120,9 +1149,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
/* rate scaling */
int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init);
-void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm,
- struct iwl_mvm_frame_stats *stats,
- u32 rate, bool agg);
+void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg);
int rs_pretty_print_rate(char *buf, const u32 rate);
void rs_update_last_rssi(struct iwl_mvm *mvm,
struct iwl_lq_sta *lq_sta,
@@ -1291,11 +1318,13 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif)
/* hw scheduler queue config */
void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn,
- const struct iwl_trans_txq_scd_cfg *cfg);
-void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue);
+ const struct iwl_trans_txq_scd_cfg *cfg,
+ unsigned int wdg_timeout);
+void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags);
-static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue,
- u8 fifo)
+static inline
+void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue,
+ u8 fifo, unsigned int wdg_timeout)
{
struct iwl_trans_txq_scd_cfg cfg = {
.fifo = fifo,
@@ -1304,12 +1333,13 @@ static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue,
.frame_limit = IWL_FRAME_LIMIT,
};
- iwl_mvm_enable_txq(mvm, queue, 0, &cfg);
+ iwl_mvm_enable_txq(mvm, queue, 0, &cfg, wdg_timeout);
}
static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue,
int fifo, int sta_id, int tid,
- int frame_limit, u16 ssn)
+ int frame_limit, u16 ssn,
+ unsigned int wdg_timeout)
{
struct iwl_trans_txq_scd_cfg cfg = {
.fifo = fifo,
@@ -1319,7 +1349,7 @@ static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue,
.aggregate = true,
};
- iwl_mvm_enable_txq(mvm, queue, ssn, &cfg);
+ iwl_mvm_enable_txq(mvm, queue, ssn, &cfg, wdg_timeout);
}
/* Assoc status */
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index d55fd8e3654c..5383429d96c1 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -356,7 +356,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
max_section_size = IWL_MAX_NVM_SECTION_SIZE;
else if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP)
max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE;
- else /* Family 8000 B-step */
+ else /* Family 8000 B-step or C-step */
max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE;
/*
@@ -565,6 +565,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
mvm->nvm_data = iwl_parse_nvm_sections(mvm);
if (!mvm->nvm_data)
return -ENODATA;
+ IWL_DEBUG_EEPROM(mvm->trans->dev, "nvm version = %x\n",
+ mvm->nvm_data->nvm_version);
return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 239f033e3b93..2dffc3600ed3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -93,6 +93,7 @@ static const struct iwl_op_mode_ops iwl_mvm_ops;
struct iwl_mvm_mod_params iwlmvm_mod_params = {
.power_scheme = IWL_POWER_SCHEME_BPS,
+ .tfd_q_hang_detect = true
/* rest of fields are 0 by default */
};
@@ -102,6 +103,10 @@ MODULE_PARM_DESC(init_dbg,
module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, S_IRUGO);
MODULE_PARM_DESC(power_scheme,
"power management scheme: 1-active, 2-balanced, 3-low power, default: 2");
+module_param_named(tfd_q_hang_detect, iwlmvm_mod_params.tfd_q_hang_detect,
+ bool, S_IRUGO);
+MODULE_PARM_DESC(tfd_q_hang_detect,
+ "TFD queues hang detection (default: true");
/*
* module init and exit functions
@@ -234,6 +239,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, true),
+ RX_HANDLER(SCAN_ITERATION_COMPLETE,
+ iwl_mvm_rx_scan_offload_iter_complete_notif, false),
RX_HANDLER(SCAN_OFFLOAD_COMPLETE,
iwl_mvm_rx_scan_offload_complete_notif, true),
RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results,
@@ -268,6 +275,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(MGMT_MCAST_KEY),
CMD(TX_CMD),
CMD(TXPATH_FLUSH),
+ CMD(SHARED_MEM_CFG),
CMD(MAC_CONTEXT_CMD),
CMD(TIME_EVENT_CMD),
CMD(TIME_EVENT_NOTIFICATION),
@@ -470,11 +478,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE)
trans_cfg.bc_table_dword = true;
- if (!iwlwifi_mod_params.wd_disable)
- trans_cfg.queue_watchdog_timeout = cfg->base_params->wd_timeout;
- else
- trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED;
-
trans_cfg.command_names = iwl_mvm_cmd_strings;
trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE;
@@ -483,6 +486,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
trans_cfg.sdio_adma_addr = fw->sdio_adma_addr;
+ /* Set a short watchdog for the command queue */
+ trans_cfg.cmd_q_wdg_timeout =
+ iwlmvm_mod_params.tfd_q_hang_detect ? IWL_DEF_WD_TIMEOUT :
+ IWL_WATCHDOG_DISABLED;
+
snprintf(mvm->hw->wiphy->fw_version,
sizeof(mvm->hw->wiphy->fw_version),
"%s", fw->fw_version);
@@ -560,6 +568,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if (!mvm->scan_cmd)
goto out_free;
+ /* Set EBS as successful as long as not stated otherwise by the FW. */
+ mvm->last_ebs_successful = true;
+
err = iwl_mvm_mac_setup_register(mvm);
if (err)
goto out_free;
@@ -818,9 +829,20 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work)
struct iwl_mvm *mvm =
container_of(work, struct iwl_mvm, fw_error_dump_wk);
+ if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_FW_DBG_COLLECT))
+ return;
+
mutex_lock(&mvm->mutex);
iwl_mvm_fw_error_dump(mvm);
+
+ /* start recording again if the firmware is not crashed */
+ WARN_ON_ONCE((!test_bit(STATUS_FW_ERROR, &mvm->trans->status)) &&
+ mvm->fw->dbg_dest_tlv &&
+ iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf));
+
mutex_unlock(&mvm->mutex);
+
+ iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT);
}
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
@@ -856,7 +878,10 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
* If WoWLAN fw asserted, don't restart either, mac80211
* can't recover this since we're already half suspended.
*/
- if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+ if (!mvm->restart_fw && fw_error) {
+ schedule_work(&mvm->fw_error_dump_wk);
+ } else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART,
+ &mvm->status)) {
struct iwl_mvm_reprobe *reprobe;
IWL_ERR(mvm,
@@ -880,16 +905,13 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
reprobe->dev = mvm->trans->dev;
INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk);
schedule_work(&reprobe->work);
- } else if (mvm->cur_ucode == IWL_UCODE_REGULAR &&
- (!fw_error || mvm->restart_fw)) {
+ } else if (mvm->cur_ucode == IWL_UCODE_REGULAR) {
/* don't let the transport/FW power down */
iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
if (fw_error && mvm->restart_fw > 0)
mvm->restart_fw--;
ieee80211_restart_hw(mvm->hw);
- } else if (fw_error) {
- schedule_work(&mvm->fw_error_dump_wk);
}
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
index 540c36bae268..5b43616eeb06 100644
--- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
@@ -170,7 +170,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
active_cnt = 2;
}
- cmd->rxchain_info = cpu_to_le32(mvm->fw->valid_rx_ant <<
+ cmd->rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) <<
PHY_RX_CHAIN_VALID_POS);
cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS);
cmd->rxchain_info |= cpu_to_le32(active_cnt <<
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 7ba6e5dbbbd0..194bd1f939ca 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -39,6 +39,7 @@
#include "sta.h"
#include "iwl-op-mode.h"
#include "mvm.h"
+#include "debugfs.h"
#define RS_NAME "iwl-mvm-rs"
@@ -917,7 +918,6 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
break;
if (rate_mask & (1 << low))
break;
- IWL_DEBUG_RATE(mvm, "Skipping masked lower rate: %d\n", low);
}
high = index;
@@ -927,7 +927,6 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
break;
if (rate_mask & (1 << high))
break;
- IWL_DEBUG_RATE(mvm, "Skipping masked higher rate: %d\n", high);
}
return (high << 8) | low;
@@ -1804,18 +1803,10 @@ out:
static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta)
{
- struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- struct ieee80211_vif *vif = mvmsta->vif;
- bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION &&
- !vif->bss_conf.ps);
-
/* Our chip supports Tx STBC and the peer is an HT/VHT STA which
* supports STBC of at least 1*SS
*/
- if (!lq_sta->stbc)
- return false;
-
- if (!mvm->ps_disabled && !sta_ps_disabled)
+ if (!lq_sta->stbc_capable)
return false;
if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
@@ -2610,68 +2601,121 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
}
}
+static void rs_ht_init(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_sta_ht_cap *ht_cap)
+{
+ /* active_siso_rate mask includes 9 MBits (bit 5),
+ * and CCK (bits 0-3), supp_rates[] does not;
+ * shift to convert format, force 9 MBits off.
+ */
+ lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
+ lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
+ lq_sta->active_siso_rate &= ~((u16)0x2);
+ lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
+
+ lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
+ lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
+ lq_sta->active_mimo2_rate &= ~((u16)0x2);
+ lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
+
+ if (mvm->cfg->ht_params->ldpc &&
+ (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
+ lq_sta->ldpc = true;
+
+ if (mvm->cfg->ht_params->stbc &&
+ (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
+ (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC))
+ lq_sta->stbc_capable = true;
+
+ lq_sta->is_vht = false;
+}
+
+static void rs_vht_init(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_sta_vht_cap *vht_cap)
+{
+ rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
+
+ if (mvm->cfg->ht_params->ldpc &&
+ (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
+ lq_sta->ldpc = true;
+
+ if (mvm->cfg->ht_params->stbc &&
+ (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
+ (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))
+ lq_sta->stbc_capable = true;
+
+ if ((mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
+ (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
+ (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+ lq_sta->bfer_capable = true;
+
+ lq_sta->is_vht = true;
+}
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
-static void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm,
- struct iwl_mvm_frame_stats *stats)
+static void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm)
{
spin_lock_bh(&mvm->drv_stats_lock);
- memset(stats, 0, sizeof(*stats));
+ memset(&mvm->drv_rx_stats, 0, sizeof(mvm->drv_rx_stats));
spin_unlock_bh(&mvm->drv_stats_lock);
}
-void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm,
- struct iwl_mvm_frame_stats *stats,
- u32 rate, bool agg)
+void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg)
{
u8 nss = 0, mcs = 0;
spin_lock(&mvm->drv_stats_lock);
if (agg)
- stats->agg_frames++;
+ mvm->drv_rx_stats.agg_frames++;
- stats->success_frames++;
+ mvm->drv_rx_stats.success_frames++;
switch (rate & RATE_MCS_CHAN_WIDTH_MSK) {
case RATE_MCS_CHAN_WIDTH_20:
- stats->bw_20_frames++;
+ mvm->drv_rx_stats.bw_20_frames++;
break;
case RATE_MCS_CHAN_WIDTH_40:
- stats->bw_40_frames++;
+ mvm->drv_rx_stats.bw_40_frames++;
break;
case RATE_MCS_CHAN_WIDTH_80:
- stats->bw_80_frames++;
+ mvm->drv_rx_stats.bw_80_frames++;
break;
default:
WARN_ONCE(1, "bad BW. rate 0x%x", rate);
}
if (rate & RATE_MCS_HT_MSK) {
- stats->ht_frames++;
+ mvm->drv_rx_stats.ht_frames++;
mcs = rate & RATE_HT_MCS_RATE_CODE_MSK;
nss = ((rate & RATE_HT_MCS_NSS_MSK) >> RATE_HT_MCS_NSS_POS) + 1;
} else if (rate & RATE_MCS_VHT_MSK) {
- stats->vht_frames++;
+ mvm->drv_rx_stats.vht_frames++;
mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK;
nss = ((rate & RATE_VHT_MCS_NSS_MSK) >>
RATE_VHT_MCS_NSS_POS) + 1;
} else {
- stats->legacy_frames++;
+ mvm->drv_rx_stats.legacy_frames++;
}
if (nss == 1)
- stats->siso_frames++;
+ mvm->drv_rx_stats.siso_frames++;
else if (nss == 2)
- stats->mimo2_frames++;
+ mvm->drv_rx_stats.mimo2_frames++;
if (rate & RATE_MCS_SGI_MSK)
- stats->sgi_frames++;
+ mvm->drv_rx_stats.sgi_frames++;
else
- stats->ngi_frames++;
+ mvm->drv_rx_stats.ngi_frames++;
- stats->last_rates[stats->last_frame_idx] = rate;
- stats->last_frame_idx = (stats->last_frame_idx + 1) %
- ARRAY_SIZE(stats->last_rates);
+ mvm->drv_rx_stats.last_rates[mvm->drv_rx_stats.last_frame_idx] = rate;
+ mvm->drv_rx_stats.last_frame_idx =
+ (mvm->drv_rx_stats.last_frame_idx + 1) %
+ ARRAY_SIZE(mvm->drv_rx_stats.last_rates);
spin_unlock(&mvm->drv_stats_lock);
}
@@ -2724,46 +2768,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value);
/* TODO: should probably account for rx_highest for both HT/VHT */
- if (!vht_cap || !vht_cap->vht_supported) {
- /* active_siso_rate mask includes 9 MBits (bit 5),
- * and CCK (bits 0-3), supp_rates[] does not;
- * shift to convert format, force 9 MBits off.
- */
- lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
- lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
- lq_sta->active_siso_rate &= ~((u16)0x2);
- lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
-
- /* Same here */
- lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
- lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
- lq_sta->active_mimo2_rate &= ~((u16)0x2);
- lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
-
- lq_sta->is_vht = false;
- if (mvm->cfg->ht_params->ldpc &&
- (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
- lq_sta->ldpc = true;
-
- if (mvm->cfg->ht_params->stbc &&
- (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
- (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC))
- lq_sta->stbc = true;
- } else {
- rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
- lq_sta->is_vht = true;
-
- if (mvm->cfg->ht_params->ldpc &&
- (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
- lq_sta->ldpc = true;
-
- if (mvm->cfg->ht_params->stbc &&
- (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
- (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))
- lq_sta->stbc = true;
- }
+ if (!vht_cap || !vht_cap->vht_supported)
+ rs_ht_init(mvm, sta, lq_sta, ht_cap);
+ else
+ rs_vht_init(mvm, sta, lq_sta, vht_cap);
- if (IWL_MVM_RS_DISABLE_MIMO)
+ if (IWL_MVM_RS_DISABLE_P2P_MIMO && sta_priv->vif->p2p)
lq_sta->active_mimo2_rate = 0;
lq_sta->max_legacy_rate_idx =
@@ -2774,11 +2784,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
rs_get_max_rate_from_mask(lq_sta->active_mimo2_rate);
IWL_DEBUG_RATE(mvm,
- "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC%d\n",
+ "LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC=%d BFER=%d\n",
lq_sta->active_legacy_rate,
lq_sta->active_siso_rate,
lq_sta->active_mimo2_rate,
- lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc);
+ lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc_capable,
+ lq_sta->bfer_capable);
IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n",
lq_sta->max_legacy_rate_idx,
lq_sta->max_siso_rate_idx,
@@ -2793,7 +2804,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
lq_sta->is_agg = 0;
#ifdef CONFIG_IWLWIFI_DEBUGFS
- iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats);
+ iwl_mvm_reset_frame_stats(mvm);
#endif
rs_initialize_lq(mvm, sta, lq_sta, band, init);
}
@@ -2862,12 +2873,13 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm,
int index = *rs_table_index;
for (i = 0; i < num_rates && index < end; i++) {
- ucode_rate = cpu_to_le32(ucode_rate_from_rs_rate(mvm, rate));
- for (j = 0; j < num_retries && index < end; j++, index++)
+ for (j = 0; j < num_retries && index < end; j++, index++) {
+ ucode_rate = cpu_to_le32(ucode_rate_from_rs_rate(mvm,
+ rate));
rs_table[index] = ucode_rate;
-
- if (toggle_ant)
- rs_toggle_antenna(valid_tx_ant, rate);
+ if (toggle_ant)
+ rs_toggle_antenna(valid_tx_ant, rate);
+ }
prev_rate_idx = rate->index;
bottom_reached = rs_get_lower_rate_in_column(lq_sta, rate);
@@ -2875,7 +2887,7 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm,
break;
}
- if (!bottom_reached)
+ if (!bottom_reached && !is_legacy(rate))
rate->index = prev_rate_idx;
*rs_table_index = index;
@@ -2915,7 +2927,11 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
memcpy(&rate, initial_rate, sizeof(rate));
valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm);
- rate.stbc = rs_stbc_allow(mvm, sta, lq_sta);
+
+ /* TODO: remove old API when min FW API hits 14 */
+ if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) &&
+ rs_stbc_allow(mvm, sta, lq_sta))
+ rate.stbc = true;
if (is_siso(&rate)) {
num_rates = IWL_MVM_RS_INITIAL_SISO_NUM_RATES;
@@ -2925,7 +2941,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
num_retries = IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE;
} else {
num_rates = IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES;
- num_retries = IWL_MVM_RS_LEGACY_RETRIES_PER_RATE;
+ num_retries = IWL_MVM_RS_INITIAL_LEGACY_RETRIES;
toggle_ant = true;
}
@@ -2941,7 +2957,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
lq_cmd->mimo_delim = index;
} else if (is_legacy(&rate)) {
num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES;
- num_retries = IWL_MVM_RS_LEGACY_RETRIES_PER_RATE;
+ num_retries = IWL_MVM_RS_SECONDARY_LEGACY_RETRIES;
} else {
WARN_ON_ONCE(1);
}
@@ -2955,7 +2971,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
rs_get_lower_rate_down_column(lq_sta, &rate);
num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES;
- num_retries = IWL_MVM_RS_LEGACY_RETRIES_PER_RATE;
+ num_retries = IWL_MVM_RS_SECONDARY_LEGACY_RETRIES;
rs_fill_rates_for_column(mvm, lq_sta, &rate, lq_cmd->rs_table, &index,
num_rates, num_retries, valid_tx_ant,
@@ -2963,6 +2979,142 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
}
+struct rs_bfer_active_iter_data {
+ struct ieee80211_sta *exclude_sta;
+ struct iwl_mvm_sta *bfer_mvmsta;
+};
+
+static void rs_bfer_active_iter(void *_data,
+ struct ieee80211_sta *sta)
+{
+ struct rs_bfer_active_iter_data *data = _data;
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ struct iwl_lq_cmd *lq_cmd = &mvmsta->lq_sta.lq;
+ u32 ss_params = le32_to_cpu(lq_cmd->ss_params);
+
+ if (sta == data->exclude_sta)
+ return;
+
+ /* The current sta has BFER allowed */
+ if (ss_params & LQ_SS_BFER_ALLOWED) {
+ WARN_ON_ONCE(data->bfer_mvmsta != NULL);
+
+ data->bfer_mvmsta = mvmsta;
+ }
+}
+
+static int rs_bfer_priority(struct iwl_mvm_sta *sta)
+{
+ int prio = -1;
+ enum nl80211_iftype viftype = ieee80211_vif_type_p2p(sta->vif);
+
+ switch (viftype) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ prio = 3;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ prio = 2;
+ break;
+ case NL80211_IFTYPE_STATION:
+ prio = 1;
+ break;
+ default:
+ WARN_ONCE(true, "viftype %d sta_id %d", viftype, sta->sta_id);
+ prio = -1;
+ }
+
+ return prio;
+}
+
+/* Returns >0 if sta1 has a higher BFER priority compared to sta2 */
+static int rs_bfer_priority_cmp(struct iwl_mvm_sta *sta1,
+ struct iwl_mvm_sta *sta2)
+{
+ int prio1 = rs_bfer_priority(sta1);
+ int prio2 = rs_bfer_priority(sta2);
+
+ if (prio1 > prio2)
+ return 1;
+ if (prio1 < prio2)
+ return -1;
+ return 0;
+}
+
+static void rs_set_lq_ss_params(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ struct iwl_lq_sta *lq_sta,
+ const struct rs_rate *initial_rate)
+{
+ struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ struct rs_bfer_active_iter_data data = {
+ .exclude_sta = sta,
+ .bfer_mvmsta = NULL,
+ };
+ struct iwl_mvm_sta *bfer_mvmsta = NULL;
+ u32 ss_params = LQ_SS_PARAMS_VALID;
+
+ if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
+ goto out;
+
+ /* Check if forcing the decision is configured.
+ * Note that SISO is forced by not allowing STBC or BFER
+ */
+ if (lq_sta->ss_force == RS_SS_FORCE_STBC)
+ ss_params |= (LQ_SS_STBC_1SS_ALLOWED | LQ_SS_FORCE);
+ else if (lq_sta->ss_force == RS_SS_FORCE_BFER)
+ ss_params |= (LQ_SS_BFER_ALLOWED | LQ_SS_FORCE);
+
+ if (lq_sta->ss_force != RS_SS_FORCE_NONE) {
+ IWL_DEBUG_RATE(mvm, "Forcing single stream Tx decision %d\n",
+ lq_sta->ss_force);
+ goto out;
+ }
+
+ if (lq_sta->stbc_capable)
+ ss_params |= LQ_SS_STBC_1SS_ALLOWED;
+
+ if (!lq_sta->bfer_capable)
+ goto out;
+
+ ieee80211_iterate_stations_atomic(mvm->hw,
+ rs_bfer_active_iter,
+ &data);
+ bfer_mvmsta = data.bfer_mvmsta;
+
+ /* This code is safe as it doesn't run concurrently for different
+ * stations. This is guaranteed by the fact that calls to
+ * ieee80211_tx_status wouldn't run concurrently for a single HW.
+ */
+ if (!bfer_mvmsta) {
+ IWL_DEBUG_RATE(mvm, "No sta with BFER allowed found. Allow\n");
+
+ ss_params |= LQ_SS_BFER_ALLOWED;
+ goto out;
+ }
+
+ IWL_DEBUG_RATE(mvm, "Found existing sta %d with BFER activated\n",
+ bfer_mvmsta->sta_id);
+
+ /* Disallow BFER on another STA if active and we're a higher priority */
+ if (rs_bfer_priority_cmp(mvmsta, bfer_mvmsta) > 0) {
+ struct iwl_lq_cmd *bfersta_lq_cmd = &bfer_mvmsta->lq_sta.lq;
+ u32 bfersta_ss_params = le32_to_cpu(bfersta_lq_cmd->ss_params);
+
+ bfersta_ss_params &= ~LQ_SS_BFER_ALLOWED;
+ bfersta_lq_cmd->ss_params = cpu_to_le32(bfersta_ss_params);
+ iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd, false);
+
+ ss_params |= LQ_SS_BFER_ALLOWED;
+ IWL_DEBUG_RATE(mvm,
+ "Lower priority BFER sta found (%d). Switch BFER\n",
+ bfer_mvmsta->sta_id);
+ }
+out:
+ lq_cmd->ss_params = cpu_to_le32(ss_params);
+}
+
static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta,
@@ -2989,6 +3141,9 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
rs_build_rates_table(mvm, sta, lq_sta, initial_rate);
+ if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS)
+ rs_set_lq_ss_params(mvm, sta, lq_sta, initial_rate);
+
if (num_of_ant(initial_rate->ant) == 1)
lq_cmd->single_stream_ant_msk = initial_rate->ant;
@@ -3362,9 +3517,73 @@ static const struct file_operations rs_sta_dbgfs_drv_tx_stats_ops = {
.llseek = default_llseek,
};
+static ssize_t iwl_dbgfs_ss_force_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_lq_sta *lq_sta = file->private_data;
+ char buf[12];
+ int bufsz = sizeof(buf);
+ int pos = 0;
+ static const char * const ss_force_name[] = {
+ [RS_SS_FORCE_NONE] = "none",
+ [RS_SS_FORCE_STBC] = "stbc",
+ [RS_SS_FORCE_BFER] = "bfer",
+ [RS_SS_FORCE_SISO] = "siso",
+ };
+
+ pos += scnprintf(buf+pos, bufsz-pos, "%s\n",
+ ss_force_name[lq_sta->ss_force]);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_ss_force_write(struct iwl_lq_sta *lq_sta, char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = lq_sta->pers.drv;
+ int ret = 0;
+
+ if (!strncmp("none", buf, 4)) {
+ lq_sta->ss_force = RS_SS_FORCE_NONE;
+ } else if (!strncmp("siso", buf, 4)) {
+ lq_sta->ss_force = RS_SS_FORCE_SISO;
+ } else if (!strncmp("stbc", buf, 4)) {
+ if (lq_sta->stbc_capable) {
+ lq_sta->ss_force = RS_SS_FORCE_STBC;
+ } else {
+ IWL_ERR(mvm,
+ "can't force STBC. peer doesn't support\n");
+ ret = -EINVAL;
+ }
+ } else if (!strncmp("bfer", buf, 4)) {
+ if (lq_sta->bfer_capable) {
+ lq_sta->ss_force = RS_SS_FORCE_BFER;
+ } else {
+ IWL_ERR(mvm,
+ "can't force BFER. peer doesn't support\n");
+ ret = -EINVAL;
+ }
+ } else {
+ IWL_ERR(mvm, "valid values none|siso|stbc|bfer\n");
+ ret = -EINVAL;
+ }
+ return ret ?: count;
+}
+
+#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
+ _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_lq_sta)
+#define MVM_DEBUGFS_ADD_FILE_RS(name, parent, mode) do { \
+ if (!debugfs_create_file(#name, mode, parent, lq_sta, \
+ &iwl_dbgfs_##name##_ops)) \
+ goto err; \
+ } while (0)
+
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(ss_force, 32);
+
static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
{
struct iwl_lq_sta *lq_sta = mvm_sta;
+
debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
lq_sta, &rs_sta_dbgfs_scale_table_ops);
debugfs_create_file("rate_stats_table", S_IRUSR, dir,
@@ -3375,6 +3594,11 @@ static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
&lq_sta->tx_agg_tid_en);
debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir,
&lq_sta->pers.dbg_fixed_txp_reduction);
+
+ MVM_DEBUGFS_ADD_FILE_RS(ss_force, dir, S_IRUSR | S_IWUSR);
+ return;
+err:
+ IWL_ERR((struct iwl_mvm *)mvm, "Can't create debugfs entity\n");
}
static void rs_remove_debugfs(void *mvm, void *mvm_sta)
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index f8f5bf21cc38..dc4ef3dfafe1 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -240,6 +240,13 @@ enum rs_column {
RS_COLUMN_INVALID,
};
+enum rs_ss_force_opt {
+ RS_SS_FORCE_NONE = 0,
+ RS_SS_FORCE_STBC,
+ RS_SS_FORCE_BFER,
+ RS_SS_FORCE_SISO,
+};
+
/* Packet stats per rate */
struct rs_rate_stats {
u64 success;
@@ -293,7 +300,9 @@ struct iwl_lq_sta {
u64 last_tx;
bool is_vht;
bool ldpc; /* LDPC Rx is supported by the STA */
- bool stbc; /* Tx STBC is supported by chip and Rx by STA */
+ bool stbc_capable; /* Tx STBC is supported by chip and Rx by STA */
+ bool bfer_capable; /* Remote supports beamformee and we BFer */
+
enum ieee80211_band band;
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
@@ -322,6 +331,9 @@ struct iwl_lq_sta {
/* tx power reduce for this sta */
int tpc_reduce;
+ /* force STBC/BFER/SISO for testing */
+ enum rs_ss_force_opt ss_force;
+
/* persistent fields - initialized only once - keep last! */
struct lq_sta_pers {
#ifdef CONFIG_MAC80211_DEBUGFS
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index 94b6e7297a1e..f922131b4eab 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -407,7 +407,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
- iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags,
+ iwl_mvm_update_frame_stats(mvm, rate_n_flags,
rx_status->flag & RX_FLAG_AMPDU_DETAILS);
#endif
iwl_mvm_pass_packet_to_mac80211(mvm, skb, hdr, len, ampdu_status,
@@ -511,13 +511,17 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_notif_statistics *stats = (void *)&pkt->data;
- struct mvm_statistics_general_common *common = &stats->general.common;
struct iwl_mvm_stat_data data = {
.stats = stats,
.mvm = mvm,
};
- iwl_mvm_tt_temp_changed(mvm, le32_to_cpu(common->temperature));
+ /* Only handle rx statistics temperature changes if async temp
+ * notifications are not supported
+ */
+ if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_ASYNC_DTM))
+ iwl_mvm_tt_temp_changed(mvm,
+ le32_to_cpu(stats->general.radio_temperature));
iwl_mvm_update_rx_statistics(mvm, stats);
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 348b9c4b694a..7e9aa3cb3254 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -173,15 +173,21 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid,
* already included in the probe template, so we need to set only
* req->n_ssids - 1 bits in addition to the first bit.
*/
-static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
+static u16 iwl_mvm_get_active_dwell(struct iwl_mvm *mvm,
+ enum ieee80211_band band, int n_ssids)
{
+ if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BASIC_DWELL)
+ return 10;
if (band == IEEE80211_BAND_2GHZ)
return 20 + 3 * (n_ssids + 1);
return 10 + 2 * (n_ssids + 1);
}
-static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band)
+static u16 iwl_mvm_get_passive_dwell(struct iwl_mvm *mvm,
+ enum ieee80211_band band)
{
+ if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BASIC_DWELL)
+ return 110;
return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10;
}
@@ -309,18 +315,18 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
goto not_bound;
params->suspend_time = 30;
- params->max_out_time = 170;
+ params->max_out_time = 120;
if (iwl_mvm_low_latency(mvm)) {
if (mvm->fw->ucode_capa.api[0] &
IWL_UCODE_TLV_API_FRAGMENTED_SCAN) {
params->suspend_time = 105;
- params->max_out_time = 70;
/*
* If there is more than one active interface make
* passive scan more fragmented.
*/
frag_passive_dwell = (global_cnt < 2) ? 40 : 20;
+ params->max_out_time = frag_passive_dwell;
} else {
params->suspend_time = 120;
params->max_out_time = 120;
@@ -337,7 +343,8 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
*/
if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
u32 passive_dwell =
- iwl_mvm_get_passive_dwell(IEEE80211_BAND_2GHZ);
+ iwl_mvm_get_passive_dwell(mvm,
+ IEEE80211_BAND_2GHZ);
params->max_out_time = passive_dwell;
} else {
params->passive_fragmented = true;
@@ -354,8 +361,8 @@ not_bound:
params->dwell[band].passive = frag_passive_dwell;
else
params->dwell[band].passive =
- iwl_mvm_get_passive_dwell(band);
- params->dwell[band].active = iwl_mvm_get_active_dwell(band,
+ iwl_mvm_get_passive_dwell(mvm, band);
+ params->dwell[band].active = iwl_mvm_get_active_dwell(mvm, band,
n_ssids);
}
}
@@ -536,6 +543,19 @@ int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
return 0;
}
+int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_scan_complete_notif *notif = (void *)pkt->data;
+
+ IWL_DEBUG_SCAN(mvm,
+ "Scan offload iteration complete: status=0x%x scanned channels=%d\n",
+ notif->status, notif->scanned_channels);
+ return 0;
+}
+
int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
{
@@ -684,7 +704,8 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
}
- mvm->last_ebs_successful = !ebs_status;
+ if (ebs_status)
+ mvm->last_ebs_successful = false;
return 0;
}
@@ -1104,6 +1125,12 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN,
notify);
+ if (mvm->scan_status == IWL_MVM_SCAN_NONE)
+ return 0;
+
+ if (iwl_mvm_is_radio_killed(mvm))
+ goto out;
+
if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
(!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) ||
mvm->scan_status != IWL_MVM_SCAN_OS)) {
@@ -1140,6 +1167,7 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
if (mvm->scan_status == IWL_MVM_SCAN_OS)
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
+out:
mvm->scan_status = IWL_MVM_SCAN_NONE;
if (notify) {
@@ -1296,22 +1324,6 @@ iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm,
cmd->scan_prio = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
cmd->iter_num = cpu_to_le32(1);
- if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT &&
- mvm->last_ebs_successful) {
- cmd->channel_opt[0].flags =
- cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
- IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
- IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
- cmd->channel_opt[0].non_ebs_ratio =
- cpu_to_le16(IWL_DENSE_EBS_SCAN_RATIO);
- cmd->channel_opt[1].flags =
- cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
- IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
- IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
- cmd->channel_opt[1].non_ebs_ratio =
- cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO);
- }
-
if (iwl_mvm_rrm_scan_needed(mvm))
cmd->scan_flags |=
cpu_to_le32(IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED);
@@ -1386,6 +1398,22 @@ int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm,
cmd->schedule[1].iterations = 0;
cmd->schedule[1].full_scan_mul = 0;
+ if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SINGLE_SCAN_EBS &&
+ mvm->last_ebs_successful) {
+ cmd->channel_opt[0].flags =
+ cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
+ IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
+ IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
+ cmd->channel_opt[0].non_ebs_ratio =
+ cpu_to_le16(IWL_DENSE_EBS_SCAN_RATIO);
+ cmd->channel_opt[1].flags =
+ cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
+ IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
+ IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
+ cmd->channel_opt[1].non_ebs_ratio =
+ cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO);
+ }
+
for (i = 1; i <= req->req.n_ssids; i++)
ssid_bitmap |= BIT(i);
@@ -1458,6 +1486,8 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
if (iwl_mvm_scan_pass_all(mvm, req))
flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
+ else
+ flags |= IWL_MVM_LMAC_SCAN_FLAG_MATCH;
if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0)
flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION;
@@ -1468,6 +1498,11 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
if (req->n_ssids == 0)
flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ if (mvm->scan_iter_notif_enabled)
+ flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE;
+#endif
+
cmd->scan_flags |= cpu_to_le32(flags);
cmd->flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band);
@@ -1484,6 +1519,22 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
cmd->schedule[1].iterations = 0xff;
cmd->schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER;
+ if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT &&
+ mvm->last_ebs_successful) {
+ cmd->channel_opt[0].flags =
+ cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
+ IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
+ IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
+ cmd->channel_opt[0].non_ebs_ratio =
+ cpu_to_le16(IWL_DENSE_EBS_SCAN_RATIO);
+ cmd->channel_opt[1].flags =
+ cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
+ IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
+ IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
+ cmd->channel_opt[1].non_ebs_ratio =
+ cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO);
+ }
+
iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels,
ssid_bitmap, cmd);
@@ -1632,10 +1683,10 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ];
for (i = 0; i < band->n_channels; i++, j++)
- scan_config->channel_array[j] = band->channels[i].center_freq;
+ scan_config->channel_array[j] = band->channels[i].hw_value;
band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
for (i = 0; i < band->n_channels; i++, j++)
- scan_config->channel_array[j] = band->channels[i].center_freq;
+ scan_config->channel_array[j] = band->channels[i].hw_value;
cmd.data[0] = scan_config;
cmd.len[0] = cmd_size;
@@ -1812,6 +1863,13 @@ int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL;
cmd->general_flags = cpu_to_le32(flags);
+
+ if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SINGLE_SCAN_EBS &&
+ mvm->last_ebs_successful)
+ cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |
+ IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
+ IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;
+
cmd->n_channels = req->req.n_channels;
for (i = 0; i < req->req.n_ssids; i++)
@@ -1975,7 +2033,9 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
notif->ebs_status == IWL_SCAN_EBS_SUCCESS ?
"success" : "failed");
- mvm->last_ebs_successful = !notif->ebs_status;
+ if (notif->ebs_status)
+ mvm->last_ebs_successful = false;
+
mvm->scan_uid[uid_idx] = 0;
if (!sched) {
@@ -2008,10 +2068,14 @@ static bool iwl_scan_umac_done_check(struct iwl_notif_wait_data *notif_wait,
/*
* Clear scan uid of scans that was aborted from above and completed
- * in FW so the RX handler does nothing.
+ * in FW so the RX handler does nothing. Set last_ebs_successful here if
+ * needed.
*/
scan_done->mvm->scan_uid[uid_idx] = 0;
+ if (notif->ebs_status)
+ scan_done->mvm->last_ebs_successful = false;
+
return !iwl_mvm_find_scan_type(scan_done->mvm, scan_done->type);
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index ad327984b099..5c23cddaaae3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -209,6 +209,9 @@ static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm,
{
unsigned long used_hw_queues;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ?
+ mvm->cfg->base_params->wd_timeout :
+ IWL_WATCHDOG_DISABLED;
u32 ac;
lockdep_assert_held(&mvm->mutex);
@@ -232,7 +235,7 @@ static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm,
/* Found a place for all queues - enable them */
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac],
- iwl_mvm_ac_to_tx_fifo[ac]);
+ iwl_mvm_ac_to_tx_fifo[ac], wdg_timeout);
mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]);
}
@@ -250,8 +253,8 @@ static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm,
/* disable the TDLS STA-specific queues */
sta_msk = mvmsta->tfd_queue_msk;
- for_each_set_bit(i, &sta_msk, sizeof(sta_msk))
- iwl_mvm_disable_txq(mvm, i);
+ for_each_set_bit(i, &sta_msk, sizeof(sta_msk) * BITS_PER_BYTE)
+ iwl_mvm_disable_txq(mvm, i, 0);
}
int iwl_mvm_add_sta(struct iwl_mvm *mvm,
@@ -464,8 +467,8 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk)
if (mvm->tfd_drained[sta_id]) {
unsigned long i, msk = mvm->tfd_drained[sta_id];
- for_each_set_bit(i, &msk, sizeof(msk))
- iwl_mvm_disable_txq(mvm, i);
+ for_each_set_bit(i, &msk, sizeof(msk) * BITS_PER_BYTE)
+ iwl_mvm_disable_txq(mvm, i, 0);
mvm->tfd_drained[sta_id] = 0;
IWL_DEBUG_TDLS(mvm, "Drained sta %d, with queues %ld\n",
@@ -626,13 +629,16 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
{
+ unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ?
+ mvm->cfg->base_params->wd_timeout :
+ IWL_WATCHDOG_DISABLED;
int ret;
lockdep_assert_held(&mvm->mutex);
/* Map Aux queue to fifo - needs to happen before adding Aux station */
iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue,
- IWL_MVM_TX_FIFO_MCAST);
+ IWL_MVM_TX_FIFO_MCAST, wdg_timeout);
/* Allocate aux station and assign to it the aux queue */
ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue),
@@ -965,6 +971,9 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
+ unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ?
+ mvm->cfg->base_params->wd_timeout :
+ IWL_WATCHDOG_DISABLED;
int queue, fifo, ret;
u16 ssn;
@@ -988,7 +997,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return -EIO;
iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid,
- buf_size, ssn);
+ buf_size, ssn, wdg_timeout);
/*
* Even though in theory the peer could have different
@@ -1058,7 +1067,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
- iwl_mvm_disable_txq(mvm, txq_id);
+ iwl_mvm_disable_txq(mvm, txq_id, 0);
return 0;
case IWL_AGG_STARTING:
case IWL_EMPTYING_HW_QUEUE_ADDBA:
@@ -1116,7 +1125,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
- iwl_mvm_disable_txq(mvm, tid_data->txq_id);
+ iwl_mvm_disable_txq(mvm, tid_data->txq_id, 0);
}
mvm->queue_to_mac80211[tid_data->txq_id] =
@@ -1196,6 +1205,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
break;
case WLAN_CIPHER_SUITE_WEP104:
key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_13BYTES);
+ /* fall through */
case WLAN_CIPHER_SUITE_WEP40:
key_flags |= cpu_to_le16(STA_KEY_FLG_WEP);
memcpy(cmd.key + 3, keyconf->key, keyconf->keylen);
diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c
index c0e00bae5bd0..a87b506c8c72 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tdls.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c
@@ -64,6 +64,8 @@
#include <linux/etherdevice.h>
#include "mvm.h"
#include "time-event.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
#define TU_TO_US(x) (x * 1024)
#define TU_TO_MS(x) (TU_TO_US(x) / 1000)
@@ -228,6 +230,8 @@ iwl_mvm_tdls_cs_state_str(enum iwl_mvm_tdls_cs_state state)
return "IDLE";
case IWL_MVM_TDLS_SW_REQ_SENT:
return "REQ SENT";
+ case IWL_MVM_TDLS_SW_RESP_RCVD:
+ return "RESP RECEIVED";
case IWL_MVM_TDLS_SW_REQ_RCVD:
return "REQ RECEIVED";
case IWL_MVM_TDLS_SW_ACTIVE:
@@ -248,6 +252,11 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm,
iwl_mvm_tdls_cs_state_str(state));
mvm->tdls_cs.state = state;
+ /* we only send requests to our switching peer - update sent time */
+ if (state == IWL_MVM_TDLS_SW_REQ_SENT)
+ mvm->tdls_cs.peer.sent_timestamp =
+ iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG);
+
if (state == IWL_MVM_TDLS_SW_IDLE)
mvm->tdls_cs.cur_sta_id = IWL_MVM_STATION_COUNT;
}
@@ -300,7 +309,7 @@ out:
static int
iwl_mvm_tdls_check_action(struct iwl_mvm *mvm,
enum iwl_tdls_channel_switch_type type,
- const u8 *peer, bool peer_initiator)
+ const u8 *peer, bool peer_initiator, u32 timestamp)
{
bool same_peer = false;
int ret = 0;
@@ -325,17 +334,30 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm,
ret = -EINVAL;
break;
case IWL_MVM_TDLS_SW_REQ_SENT:
+ /* only allow requests from the same peer */
+ if (!same_peer)
+ ret = -EBUSY;
+ else if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH &&
+ !peer_initiator)
+ /*
+ * We received a ch-switch request while an outgoing
+ * one is pending. Allow it if the peer is the link
+ * initiator.
+ */
+ ret = -EBUSY;
+ else if (type == TDLS_SEND_CHAN_SW_REQ)
+ /* wait for idle before sending another request */
+ ret = -EBUSY;
+ else if (timestamp <= mvm->tdls_cs.peer.sent_timestamp)
+ /* we got a stale response - ignore it */
+ ret = -EINVAL;
+ break;
+ case IWL_MVM_TDLS_SW_RESP_RCVD:
/*
- * We received a ch-switch request while an outgoing one is
- * pending. Allow it to proceed if the other peer is the same
- * one we sent to, and we are not the link initiator.
+ * we are waiting for the FW to give an "active" notification,
+ * so ignore requests in the meantime
*/
- if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH) {
- if (!same_peer)
- ret = -EBUSY;
- else if (!peer_initiator) /* we are the initiator */
- ret = -EBUSY;
- }
+ ret = -EBUSY;
break;
case IWL_MVM_TDLS_SW_REQ_RCVD:
/* as above, allow the link initiator to proceed */
@@ -349,9 +371,12 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm,
}
break;
case IWL_MVM_TDLS_SW_ACTIVE:
- /* we don't allow initiations during active channel switch */
- if (type == TDLS_SEND_CHAN_SW_REQ)
- ret = -EINVAL;
+ /*
+ * the only valid request when active is a request to return
+ * to the base channel by the current off-channel peer
+ */
+ if (type != TDLS_MOVE_CH || !same_peer)
+ ret = -EBUSY;
break;
}
@@ -384,7 +409,8 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
- ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator);
+ ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator,
+ timestamp);
if (ret)
return ret;
@@ -473,6 +499,8 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,
type == TDLS_SEND_CHAN_SW_REQ ?
IWL_MVM_TDLS_SW_REQ_SENT :
IWL_MVM_TDLS_SW_REQ_RCVD);
+ } else {
+ iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_RESP_RCVD);
}
out:
@@ -657,12 +685,15 @@ iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw,
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
enum iwl_tdls_channel_switch_type type;
unsigned int delay;
+ const char *action_str =
+ params->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ?
+ "REQ" : "RESP";
mutex_lock(&mvm->mutex);
IWL_DEBUG_TDLS(mvm,
- "Received TDLS ch switch action %d from %pM status %d\n",
- params->action_code, params->sta->addr, params->status);
+ "Received TDLS ch switch action %s from %pM status %d\n",
+ action_str, params->sta->addr, params->status);
/*
* we got a non-zero status from a peer we were switching to - move to
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index d6cdb770881a..07304e1fd64a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -90,8 +90,6 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
if (ieee80211_is_probe_resp(fc))
tx_flags |= TX_CMD_FLG_TSF;
- else if (ieee80211_is_back_req(fc))
- tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR;
if (ieee80211_has_morefrags(fc))
tx_flags |= TX_CMD_FLG_MORE_FRAG;
@@ -100,6 +98,15 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
u8 *qc = ieee80211_get_qos_ctl(hdr);
tx_cmd->tid_tspec = qc[0] & 0xf;
tx_flags &= ~TX_CMD_FLG_SEQ_CTL;
+ } else if (ieee80211_is_back_req(fc)) {
+ struct ieee80211_bar *bar = (void *)skb->data;
+ u16 control = le16_to_cpu(bar->control);
+
+ tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR;
+ tx_cmd->tid_tspec = (control &
+ IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
+ IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
+ WARN_ON_ONCE(tx_cmd->tid_tspec >= IWL_MAX_TID_COUNT);
} else {
tx_cmd->tid_tspec = IWL_TID_NON_QOS;
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
@@ -108,8 +115,12 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
tx_flags &= ~TX_CMD_FLG_SEQ_CTL;
}
- /* tid_tspec will default to 0 = BE when QOS isn't enabled */
- ac = tid_to_mac80211_ac[tx_cmd->tid_tspec];
+ /* Default to 0 (BE) when tid_spec is set to IWL_TID_NON_QOS */
+ if (tx_cmd->tid_tspec < IWL_MAX_TID_COUNT)
+ ac = tid_to_mac80211_ac[tx_cmd->tid_tspec];
+ else
+ ac = tid_to_mac80211_ac[0];
+
tx_flags |= iwl_mvm_bt_coex_tx_prio(mvm, hdr, info, ac) <<
TX_CMD_FLG_BT_PRIO_POS;
@@ -496,7 +507,7 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
IWL_DEBUG_TX_QUEUES(mvm,
"Can continue DELBA flow ssn = next_recl = %d\n",
tid_data->next_reclaimed);
- iwl_mvm_disable_txq(mvm, tid_data->txq_id);
+ iwl_mvm_disable_txq(mvm, tid_data->txq_id, CMD_ASYNC);
tid_data->state = IWL_AGG_OFF;
/*
* we can't hold the mutex - but since we are after a sequence
@@ -656,7 +667,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
/* Single frame failure in an AMPDU queue => send BAR */
if (txq_id >= mvm->first_agg_queue &&
- !(info->flags & IEEE80211_TX_STAT_ACK))
+ !(info->flags & IEEE80211_TX_STAT_ACK) &&
+ !(info->flags & IEEE80211_TX_STAT_TX_FILTERED))
info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
/* W/A FW bug: seq_ctl is wrong when the status isn't success */
@@ -919,6 +931,11 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
sta_id = ba_notif->sta_id;
tid = ba_notif->tid;
+ if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT ||
+ tid >= IWL_MAX_TID_COUNT,
+ "sta_id %d tid %d", sta_id, tid))
+ return 0;
+
rcu_read_lock();
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index f0a114102c3f..8decf9953229 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -432,7 +432,7 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
mvm->status, table.valid);
}
- IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id,
+ IWL_ERR(mvm, "0x%08X | %s\n", table.error_id,
desc_lookup(table.error_id));
IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1);
IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2);
@@ -531,49 +531,50 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
}
void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn,
- const struct iwl_trans_txq_scd_cfg *cfg)
+ const struct iwl_trans_txq_scd_cfg *cfg,
+ unsigned int wdg_timeout)
{
- if (iwl_mvm_is_dqa_supported(mvm)) {
- struct iwl_scd_txq_cfg_cmd cmd = {
- .scd_queue = queue,
- .enable = 1,
- .window = cfg->frame_limit,
- .sta_id = cfg->sta_id,
- .ssn = cpu_to_le16(ssn),
- .tx_fifo = cfg->fifo,
- .aggregate = cfg->aggregate,
- .flags = IWL_SCD_FLAGS_DQA_ENABLED,
- .tid = cfg->tid,
- .control = IWL_SCD_CONTROL_SET_SSN,
- };
- int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0,
- sizeof(cmd), &cmd);
- if (ret)
- IWL_ERR(mvm,
- "Failed to configure queue %d on FIFO %d\n",
- queue, cfg->fifo);
+ struct iwl_scd_txq_cfg_cmd cmd = {
+ .scd_queue = queue,
+ .enable = 1,
+ .window = cfg->frame_limit,
+ .sta_id = cfg->sta_id,
+ .ssn = cpu_to_le16(ssn),
+ .tx_fifo = cfg->fifo,
+ .aggregate = cfg->aggregate,
+ .tid = cfg->tid,
+ };
+
+ if (!iwl_mvm_is_scd_cfg_supported(mvm)) {
+ iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, cfg,
+ wdg_timeout);
+ return;
}
- iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn,
- iwl_mvm_is_dqa_supported(mvm) ? NULL : cfg);
+ iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL, wdg_timeout);
+ WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd),
+ "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo);
}
-void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue)
+void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags)
{
- iwl_trans_txq_disable(mvm->trans, queue,
- !iwl_mvm_is_dqa_supported(mvm));
-
- if (iwl_mvm_is_dqa_supported(mvm)) {
- struct iwl_scd_txq_cfg_cmd cmd = {
- .scd_queue = queue,
- .enable = 0,
- };
- int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, CMD_ASYNC,
- sizeof(cmd), &cmd);
- if (ret)
- IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n",
- queue, ret);
+ struct iwl_scd_txq_cfg_cmd cmd = {
+ .scd_queue = queue,
+ .enable = 0,
+ };
+ int ret;
+
+ if (!iwl_mvm_is_scd_cfg_supported(mvm)) {
+ iwl_trans_txq_disable(mvm->trans, queue, true);
+ return;
}
+
+ iwl_trans_txq_disable(mvm->trans, queue, false);
+ ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags,
+ sizeof(cmd), &cmd);
+ if (ret)
+ IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n",
+ queue, ret);
}
/**
@@ -665,7 +666,7 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm)
if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1)
return false;
- if (!mvm->cfg->rx_with_siso_diversity)
+ if (mvm->cfg->rx_with_siso_diversity)
return false;
ieee80211_iterate_active_interfaces_atomic(
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
index 2f0c4b170344..dbd6bcf52205 100644
--- a/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -415,6 +415,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)},
{IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F5, 0x0010, iwl4165_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F6, 0x0030, iwl4165_2ac_cfg)},
#endif /* CONFIG_IWLMVM */
{0}
@@ -527,8 +529,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
else if (cfg == &iwl7265_n_cfg)
cfg_7265d = &iwl7265d_n_cfg;
if (cfg_7265d &&
- (iwl_trans->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D)
+ (iwl_trans->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D) {
cfg = cfg_7265d;
+ iwl_trans->cfg = cfg_7265d;
+ }
#endif
pci_set_drvdata(pdev, iwl_trans);
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index e5652d82d79e..cae0eb8835ce 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -216,6 +216,7 @@ struct iwl_pcie_txq_scratch_buf {
* @need_update: indicates need to update read/write index
* @active: stores if queue is active
* @ampdu: true if this queue is an ampdu queue for an specific RA/TID
+ * @wd_timeout: queue watchdog timeout (jiffies) - per queue
*
* A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
* descriptors) and required locking structures.
@@ -232,6 +233,7 @@ struct iwl_txq {
bool need_update;
u8 active;
bool ampdu;
+ unsigned long wd_timeout;
};
static inline dma_addr_t
@@ -259,7 +261,6 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
* @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
* @scd_set_active: should the transport configure the SCD for HCMD queue
* @rx_page_order: page order for receive buffer size
- * @wd_timeout: queue watchdog timeout (jiffies)
* @reg_lock: protect hw register access
* @cmd_in_flight: true when we have a host command in flight
* @fw_mon_phys: physical address of the buffer for the firmware monitor
@@ -302,6 +303,7 @@ struct iwl_trans_pcie {
u8 cmd_queue;
u8 cmd_fifo;
+ unsigned int cmd_q_wdg_timeout;
u8 n_no_reclaim_cmds;
u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];
@@ -312,9 +314,6 @@ struct iwl_trans_pcie {
const char *const *command_names;
- /* queue watchdog */
- unsigned long wd_timeout;
-
/*protect hw register */
spinlock_t reg_lock;
bool cmd_in_flight;
@@ -373,7 +372,8 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr);
int iwl_pcie_tx_stop(struct iwl_trans *trans);
void iwl_pcie_tx_free(struct iwl_trans *trans);
void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn,
- const struct iwl_trans_txq_scd_cfg *cfg);
+ const struct iwl_trans_txq_scd_cfg *cfg,
+ unsigned int wdg_timeout);
void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue,
bool configure_scd);
int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 9ee4ca0ba8d3..69935aa5a1b3 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -75,6 +75,7 @@
#include "iwl-trans.h"
#include "iwl-csr.h"
#include "iwl-prph.h"
+#include "iwl-scd.h"
#include "iwl-agn-hw.h"
#include "iwl-fw-error-dump.h"
#include "internal.h"
@@ -722,6 +723,11 @@ static int iwl_pcie_load_cpu_sections_8000b(struct iwl_trans *trans,
*first_ucode_section = last_read_idx;
+ if (cpu == 1)
+ iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFF);
+ else
+ iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFFFFFF);
+
return 0;
}
@@ -911,9 +917,6 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans,
if (trans->dbg_dest_tlv)
iwl_pcie_apply_destination(trans);
- /* Notify FW loading is done */
- iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFFFFFF);
-
/* wait for image verification to complete */
ret = iwl_poll_prph_bit(trans, LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0,
LMPM_SECURE_BOOT_STATUS_SUCCESS,
@@ -982,7 +985,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
/* Load the given image to the HW */
if ((trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) &&
- (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_B_STEP))
+ (CSR_HW_REV_STEP(trans->hw_rev) != SILICON_A_STEP))
return iwl_pcie_load_given_ucode_8000b(trans, fw);
else
return iwl_pcie_load_given_ucode(trans, fw);
@@ -1266,6 +1269,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
trans_pcie->cmd_queue = trans_cfg->cmd_queue;
trans_pcie->cmd_fifo = trans_cfg->cmd_fifo;
+ trans_pcie->cmd_q_wdg_timeout = trans_cfg->cmd_q_wdg_timeout;
if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS))
trans_pcie->n_no_reclaim_cmds = 0;
else
@@ -1280,9 +1284,6 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
else
trans_pcie->rx_page_order = get_order(4 * 1024);
- trans_pcie->wd_timeout =
- msecs_to_jiffies(trans_cfg->queue_watchdog_timeout);
-
trans_pcie->command_names = trans_cfg->command_names;
trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;
trans_pcie->scd_set_active = trans_cfg->scd_set_active;
@@ -2348,6 +2349,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
trans_pcie->trans = trans;
spin_lock_init(&trans_pcie->irq_lock);
spin_lock_init(&trans_pcie->reg_lock);
+ spin_lock_init(&trans_pcie->ref_lock);
init_waitqueue_head(&trans_pcie->ucode_write_waitq);
err = pci_enable_device(pdev);
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index c1c4c75026b2..af0bce736358 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -147,7 +147,6 @@ static void iwl_pcie_free_dma_ptr(struct iwl_trans *trans,
static void iwl_pcie_txq_stuck_timer(unsigned long data)
{
struct iwl_txq *txq = (void *)data;
- struct iwl_queue *q = &txq->q;
struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie);
u32 scd_sram_addr = trans_pcie->scd_base_addr +
@@ -164,7 +163,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
spin_unlock(&txq->lock);
IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id,
- jiffies_to_msecs(trans_pcie->wd_timeout));
+ jiffies_to_msecs(txq->wd_timeout));
IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
txq->q.read_ptr, txq->q.write_ptr);
@@ -198,11 +197,6 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
iwl_read_prph(trans, SCD_QUEUE_WRPTR(i)));
}
- for (i = q->read_ptr; i != q->write_ptr;
- i = iwl_queue_inc_wrap(i))
- IWL_ERR(trans, "scratch %d = 0x%08x\n", i,
- le32_to_cpu(txq->scratchbufs[i].scratch));
-
iwl_force_nmi(trans);
}
@@ -680,7 +674,8 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
iwl_write_prph(trans, SCD_CHAINEXT_EN, 0);
iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue,
- trans_pcie->cmd_fifo);
+ trans_pcie->cmd_fifo,
+ trans_pcie->cmd_q_wdg_timeout);
/* Activate all Tx DMA/FIFO channels */
iwl_scd_activate_fifos(trans);
@@ -722,7 +717,12 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans)
iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
trans_pcie->kw.dma >> 4);
- iwl_pcie_tx_start(trans, trans_pcie->scd_base_addr);
+ /*
+ * Send 0 as the scd_base_addr since the device may have be reset
+ * while we were in WoWLAN in which case SCD_SRAM_BASE_ADDR will
+ * contain garbage.
+ */
+ iwl_pcie_tx_start(trans, 0);
}
/*
@@ -898,6 +898,10 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
}
}
+ if (trans->cfg->base_params->num_of_queues > 20)
+ iwl_set_bits_prph(trans, SCD_GP_CTRL,
+ SCD_GP_CTRL_ENABLE_31_QUEUES);
+
return 0;
error:
/*Upon error, free only if we allocated something */
@@ -906,10 +910,9 @@ error:
return ret;
}
-static inline void iwl_pcie_txq_progress(struct iwl_trans_pcie *trans_pcie,
- struct iwl_txq *txq)
+static inline void iwl_pcie_txq_progress(struct iwl_txq *txq)
{
- if (!trans_pcie->wd_timeout)
+ if (!txq->wd_timeout)
return;
/*
@@ -919,7 +922,7 @@ static inline void iwl_pcie_txq_progress(struct iwl_trans_pcie *trans_pcie,
if (txq->q.read_ptr == txq->q.write_ptr)
del_timer(&txq->stuck_timer);
else
- mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+ mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);
}
/* Frees buffers until index _not_ inclusive */
@@ -981,7 +984,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
iwl_pcie_txq_free_tfd(trans, txq);
}
- iwl_pcie_txq_progress(trans_pcie, txq);
+ iwl_pcie_txq_progress(txq);
if (iwl_queue_space(&txq->q) > txq->q.low_mark)
iwl_wake_queue(trans, txq);
@@ -1109,7 +1112,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
}
- iwl_pcie_txq_progress(trans_pcie, txq);
+ iwl_pcie_txq_progress(txq);
}
static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
@@ -1142,14 +1145,18 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid))
void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
- const struct iwl_trans_txq_scd_cfg *cfg)
+ const struct iwl_trans_txq_scd_cfg *cfg,
+ unsigned int wdg_timeout)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_txq *txq = &trans_pcie->txq[txq_id];
int fifo = -1;
if (test_and_set_bit(txq_id, trans_pcie->queue_used))
WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
+ txq->wd_timeout = msecs_to_jiffies(wdg_timeout);
+
if (cfg) {
fifo = cfg->fifo;
@@ -1173,7 +1180,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
/* enable aggregations for the queue */
iwl_scd_txq_enable_agg(trans, txq_id);
- trans_pcie->txq[txq_id].ampdu = true;
+ txq->ampdu = true;
} else {
/*
* disable aggregations for the queue, this will also
@@ -1182,20 +1189,20 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
*/
iwl_scd_txq_disable_agg(trans, txq_id);
- ssn = trans_pcie->txq[txq_id].q.read_ptr;
+ ssn = txq->q.read_ptr;
}
}
/* Place first TFD at index corresponding to start sequence number.
* Assumes that ssn_idx is valid (!= 0xFFF) */
- trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff);
- trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff);
+ txq->q.read_ptr = (ssn & 0xff);
+ txq->q.write_ptr = (ssn & 0xff);
+ iwl_write_direct32(trans, HBUS_TARG_WRPTR,
+ (ssn & 0xff) | (txq_id << 8));
if (cfg) {
u8 frame_limit = cfg->frame_limit;
- iwl_write_direct32(trans, HBUS_TARG_WRPTR,
- (ssn & 0xff) | (txq_id << 8));
iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
/* Set up Tx window size and frame limit for this queue */
@@ -1220,11 +1227,17 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
if (txq_id == trans_pcie->cmd_queue &&
trans_pcie->scd_set_active)
iwl_scd_enable_set_active(trans, BIT(txq_id));
+
+ IWL_DEBUG_TX_QUEUES(trans,
+ "Activate queue %d on FIFO %d WrPtr: %d\n",
+ txq_id, fifo, ssn & 0xff);
+ } else {
+ IWL_DEBUG_TX_QUEUES(trans,
+ "Activate queue %d WrPtr: %d\n",
+ txq_id, ssn & 0xff);
}
- trans_pcie->txq[txq_id].active = true;
- IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n",
- txq_id, fifo, ssn & 0xff);
+ txq->active = true;
}
void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id,
@@ -1489,8 +1502,8 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr);
/* start timer if queue currently empty */
- if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
- mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+ if (q->read_ptr == q->write_ptr && txq->wd_timeout)
+ mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);
spin_lock_irqsave(&trans_pcie->reg_lock, flags);
ret = iwl_pcie_set_cmd_in_flight(trans, cmd);
@@ -1840,9 +1853,8 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
/* start timer if queue currently empty */
if (q->read_ptr == q->write_ptr) {
- if (txq->need_update && trans_pcie->wd_timeout)
- mod_timer(&txq->stuck_timer,
- jiffies + trans_pcie->wd_timeout);
+ if (txq->wd_timeout)
+ mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);
IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id);
iwl_trans_pcie_ref(trans);
}
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 34f09ef90bb3..a92985a6ea21 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -1616,10 +1616,10 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
lbs_deb_enter(LBS_DEB_CFG80211);
- sinfo->filled |= STATION_INFO_TX_BYTES |
- STATION_INFO_TX_PACKETS |
- STATION_INFO_RX_BYTES |
- STATION_INFO_RX_PACKETS;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) |
+ BIT(NL80211_STA_INFO_TX_PACKETS) |
+ BIT(NL80211_STA_INFO_RX_BYTES) |
+ BIT(NL80211_STA_INFO_RX_PACKETS);
sinfo->tx_bytes = priv->dev->stats.tx_bytes;
sinfo->tx_packets = priv->dev->stats.tx_packets;
sinfo->rx_bytes = priv->dev->stats.rx_bytes;
@@ -1629,14 +1629,14 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
ret = lbs_get_rssi(priv, &signal, &noise);
if (ret == 0) {
sinfo->signal = signal;
- sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
}
/* Convert priv->cur_rate from hw_value to NL80211 value */
for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
if (priv->cur_rate == lbs_rates[i].hw_value) {
sinfo->txrate.legacy = lbs_rates[i].bitrate;
- sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
break;
}
}
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index ef58a8862d91..494e7335aa64 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -625,22 +625,22 @@ static int hwsim_fops_ps_write(void *dat, u64 val)
old_ps = data->ps;
data->ps = val;
+ local_bh_disable();
if (val == PS_MANUAL_POLL) {
- ieee80211_iterate_active_interfaces(data->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- hwsim_send_ps_poll, data);
+ ieee80211_iterate_active_interfaces_atomic(
+ data->hw, IEEE80211_IFACE_ITER_NORMAL,
+ hwsim_send_ps_poll, data);
data->ps_poll_pending = true;
} else if (old_ps == PS_DISABLED && val != PS_DISABLED) {
- ieee80211_iterate_active_interfaces(data->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- hwsim_send_nullfunc_ps,
- data);
+ ieee80211_iterate_active_interfaces_atomic(
+ data->hw, IEEE80211_IFACE_ITER_NORMAL,
+ hwsim_send_nullfunc_ps, data);
} else if (old_ps != PS_DISABLED && val == PS_DISABLED) {
- ieee80211_iterate_active_interfaces(data->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- hwsim_send_nullfunc_no_ps,
- data);
+ ieee80211_iterate_active_interfaces_atomic(
+ data->hw, IEEE80211_IFACE_ITER_NORMAL,
+ hwsim_send_nullfunc_no_ps, data);
}
+ local_bh_enable();
return 0;
}
@@ -2149,14 +2149,14 @@ static int append_radio_msg(struct sk_buff *skb, int id,
if (param->regd) {
int i;
- for (i = 0; hwsim_world_regdom_custom[i] != param->regd &&
- i < ARRAY_SIZE(hwsim_world_regdom_custom); i++)
- ;
+ for (i = 0; i < ARRAY_SIZE(hwsim_world_regdom_custom); i++) {
+ if (hwsim_world_regdom_custom[i] != param->regd)
+ continue;
- if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) {
ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i);
if (ret < 0)
return ret;
+ break;
}
}
diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c
index 2668e83afbb6..3ab87a855122 100644
--- a/drivers/net/wireless/mwifiex/11h.c
+++ b/drivers/net/wireless/mwifiex/11h.c
@@ -21,6 +21,16 @@
#include "fw.h"
+void mwifiex_init_11h_params(struct mwifiex_private *priv)
+{
+ priv->state_11h.is_11h_enabled = true;
+ priv->state_11h.is_11h_active = false;
+}
+
+inline int mwifiex_is_11h_active(struct mwifiex_private *priv)
+{
+ return priv->state_11h.is_11h_active;
+}
/* This function appends 11h info to a buffer while joining an
* infrastructure BSS
*/
@@ -39,7 +49,7 @@ mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer,
return;
radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
- sband = priv->wdev->wiphy->bands[radio_type];
+ sband = priv->wdev.wiphy->bands[radio_type];
cap = (struct mwifiex_ie_types_pwr_capability *)*buffer;
cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY);
@@ -69,10 +79,14 @@ mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer,
}
/* Enable or disable the 11h extensions in the firmware */
-static int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag)
+int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag)
{
u32 enable = flag;
+ /* enable master mode radar detection on AP interface */
+ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && enable)
+ enable |= MWIFIEX_MASTER_RADAR_DET_MASK;
+
return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
HostCmd_ACT_GEN_SET, DOT11H_I, &enable, true);
}
@@ -91,11 +105,191 @@ void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
* bit
*/
mwifiex_11h_activate(priv, true);
+ priv->state_11h.is_11h_active = true;
bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_SPECTRUM_MGMT;
mwifiex_11h_process_infra_join(priv, buffer, bss_desc);
} else {
/* Deactivate 11h functions in the firmware */
mwifiex_11h_activate(priv, false);
+ priv->state_11h.is_11h_active = false;
bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT;
}
}
+
+/* This is DFS CAC work queue function.
+ * This delayed work emits CAC finished event for cfg80211 if
+ * CAC was started earlier.
+ */
+void mwifiex_dfs_cac_work_queue(struct work_struct *work)
+{
+ struct cfg80211_chan_def chandef;
+ struct delayed_work *delayed_work =
+ container_of(work, struct delayed_work, work);
+ struct mwifiex_private *priv =
+ container_of(delayed_work, struct mwifiex_private,
+ dfs_cac_work);
+
+ if (WARN_ON(!priv))
+ return;
+
+ chandef = priv->dfs_chandef;
+ if (priv->wdev.cac_started) {
+ dev_dbg(priv->adapter->dev,
+ "CAC timer finished; No radar detected\n");
+ cfg80211_cac_event(priv->netdev, &chandef,
+ NL80211_RADAR_CAC_FINISHED,
+ GFP_KERNEL);
+ }
+}
+
+/* This function prepares channel report request command to FW for
+ * starting radar detection.
+ */
+int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ void *data_buf)
+{
+ struct host_cmd_ds_chan_rpt_req *cr_req = &cmd->params.chan_rpt_req;
+ struct mwifiex_radar_params *radar_params = (void *)data_buf;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_CHAN_REPORT_REQUEST);
+ cmd->size = cpu_to_le16(S_DS_GEN);
+ le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_chan_rpt_req));
+
+ cr_req->chan_desc.start_freq = cpu_to_le16(MWIFIEX_A_BAND_START_FREQ);
+ cr_req->chan_desc.chan_num = radar_params->chandef->chan->hw_value;
+ cr_req->chan_desc.chan_width = radar_params->chandef->width;
+ cr_req->msec_dwell_time = cpu_to_le32(radar_params->cac_time_ms);
+
+ dev_dbg(priv->adapter->dev,
+ "11h: issuing DFS Radar check for channel=%d\n",
+ radar_params->chandef->chan->hw_value);
+
+ return 0;
+}
+
+/* This function is to abort ongoing CAC upon stopping AP operations
+ * or during unload.
+ */
+void mwifiex_abort_cac(struct mwifiex_private *priv)
+{
+ if (priv->wdev.cac_started) {
+ dev_dbg(priv->adapter->dev,
+ "Aborting delayed work for CAC.\n");
+ cancel_delayed_work_sync(&priv->dfs_cac_work);
+ cfg80211_cac_event(priv->netdev, &priv->dfs_chandef,
+ NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
+ }
+}
+
+/* This function handles channel report event from FW during CAC period.
+ * If radar is detected during CAC, driver indicates the same to cfg80211
+ * and also cancels ongoing delayed work.
+ */
+int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv,
+ struct sk_buff *skb)
+{
+ struct host_cmd_ds_chan_rpt_event *rpt_event;
+ struct mwifiex_ie_types_chan_rpt_data *rpt;
+ u8 *evt_buf;
+ u16 event_len, tlv_len;
+
+ rpt_event = (void *)(skb->data + sizeof(u32));
+ event_len = skb->len - (sizeof(struct host_cmd_ds_chan_rpt_event)+
+ sizeof(u32));
+
+ if (le32_to_cpu(rpt_event->result) != HostCmd_RESULT_OK) {
+ dev_err(priv->adapter->dev, "Error in channel report event\n");
+ return -1;
+ }
+
+ evt_buf = (void *)&rpt_event->tlvbuf;
+
+ while (event_len >= sizeof(struct mwifiex_ie_types_header)) {
+ rpt = (void *)&rpt_event->tlvbuf;
+ tlv_len = le16_to_cpu(rpt->header.len);
+
+ switch (le16_to_cpu(rpt->header.type)) {
+ case TLV_TYPE_CHANRPT_11H_BASIC:
+ if (rpt->map.radar) {
+ dev_notice(priv->adapter->dev,
+ "RADAR Detected on channel %d!\n",
+ priv->dfs_chandef.chan->hw_value);
+ cancel_delayed_work_sync(&priv->dfs_cac_work);
+ cfg80211_cac_event(priv->netdev,
+ &priv->dfs_chandef,
+ NL80211_RADAR_DETECTED,
+ GFP_KERNEL);
+ }
+ break;
+ default:
+ break;
+ }
+
+ evt_buf += (tlv_len + sizeof(rpt->header));
+ event_len -= (tlv_len + sizeof(rpt->header));
+ }
+
+ return 0;
+}
+
+/* Handler for radar detected event from FW.*/
+int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
+ struct sk_buff *skb)
+{
+ struct mwifiex_radar_det_event *rdr_event;
+
+ rdr_event = (void *)(skb->data + sizeof(u32));
+
+ if (le32_to_cpu(rdr_event->passed)) {
+ dev_notice(priv->adapter->dev,
+ "radar detected; indicating kernel\n");
+ cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef,
+ GFP_KERNEL);
+ dev_dbg(priv->adapter->dev, "regdomain: %d\n",
+ rdr_event->reg_domain);
+ dev_dbg(priv->adapter->dev, "radar detection type: %d\n",
+ rdr_event->det_type);
+ } else {
+ dev_dbg(priv->adapter->dev, "false radar detection event!\n");
+ }
+
+ return 0;
+}
+
+/* This is work queue function for channel switch handling.
+ * This function takes care of updating new channel definitin to
+ * bss config structure, restart AP and indicate channel switch success
+ * to cfg80211.
+ */
+void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work)
+{
+ struct mwifiex_uap_bss_param *bss_cfg;
+ struct delayed_work *delayed_work =
+ container_of(work, struct delayed_work, work);
+ struct mwifiex_private *priv =
+ container_of(delayed_work, struct mwifiex_private,
+ dfs_chan_sw_work);
+
+ if (WARN_ON(!priv))
+ return;
+
+ bss_cfg = &priv->bss_cfg;
+ if (!bss_cfg->beacon_period) {
+ dev_err(priv->adapter->dev,
+ "channel switch: AP already stopped\n");
+ return;
+ }
+
+ mwifiex_uap_set_channel(bss_cfg, priv->dfs_chandef);
+
+ if (mwifiex_config_start_uap(priv, bss_cfg)) {
+ dev_dbg(priv->adapter->dev,
+ "Failed to start AP after channel switch\n");
+ return;
+ }
+
+ dev_notice(priv->adapter->dev,
+ "indicating channel switch completion to kernel\n");
+ cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef);
+}
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index 9d4786e7ddff..543148d27b01 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -39,7 +39,7 @@ int mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type,
{
uint16_t ht_ext_cap = le16_to_cpu(ht_cap->extended_ht_cap_info);
struct ieee80211_supported_band *sband =
- priv->wdev->wiphy->bands[radio_type];
+ priv->wdev.wiphy->bands[radio_type];
if (WARN_ON_ONCE(!sband)) {
dev_err(priv->adapter->dev, "Invalid radio type!\n");
@@ -314,7 +314,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
return ret_len;
radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
- sband = priv->wdev->wiphy->bands[radio_type];
+ sband = priv->wdev.wiphy->bands[radio_type];
if (bss_desc->bcn_ht_cap) {
ht_cap = (struct mwifiex_ie_types_htcap *) *buffer;
@@ -558,10 +558,10 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
spin_lock_irqsave(&priv->sta_list_spinlock, flags);
sta_ptr = mwifiex_get_sta_entry(priv, peer_mac);
if (!sta_ptr) {
+ spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
dev_warn(priv->adapter->dev,
"BA setup with unknown TDLS peer %pM!\n",
peer_mac);
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
return -1;
}
if (sta_ptr->is_11ac_enabled)
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index f33dc81c5228..a2e8817b56d8 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -45,7 +45,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
- priv->wdev->iftype, 0, false);
+ priv->wdev.iftype, 0, false);
while (!skb_queue_empty(&list)) {
rx_skb = __skb_dequeue(&list);
@@ -353,9 +353,6 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
spin_lock_irqsave(&priv->sta_list_spinlock, flags);
if (mwifiex_queuing_ra_based(priv)) {
- dev_dbg(priv->adapter->dev,
- "info: AP/ADHOC:last_seq=%d start_win=%d\n",
- last_seq, new_node->start_win);
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
node = mwifiex_get_sta_entry(priv, ta);
if (node)
@@ -370,6 +367,9 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
}
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ dev_dbg(priv->adapter->dev, "info: last_seq=%d start_win=%d\n",
+ last_seq, new_node->start_win);
+
if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
last_seq >= new_node->start_win) {
new_node->start_win = last_seq + 1;
@@ -466,10 +466,10 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
sta_ptr = mwifiex_get_sta_entry(priv,
cmd_addba_req->peer_mac_addr);
if (!sta_ptr) {
+ spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
dev_warn(priv->adapter->dev,
"BA setup with unknown TDLS peer %pM!\n",
cmd_addba_req->peer_mac_addr);
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
return -1;
}
if (sta_ptr->is_11ac_enabled)
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 93ab36fc9f93..41c8e25df954 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -590,77 +590,62 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
struct mwifiex_private *priv;
struct mwifiex_uap_bss_param *bss_cfg;
- int ret, bss_started, i;
-
- for (i = 0; i < adapter->priv_num; i++) {
- priv = adapter->priv[i];
-
- switch (priv->bss_role) {
- case MWIFIEX_BSS_ROLE_UAP:
- bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param),
- GFP_KERNEL);
- if (!bss_cfg)
- return -ENOMEM;
-
- mwifiex_set_sys_config_invalid_data(bss_cfg);
-
- if (changed & WIPHY_PARAM_RTS_THRESHOLD)
- bss_cfg->rts_threshold = wiphy->rts_threshold;
- if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
- bss_cfg->frag_threshold = wiphy->frag_threshold;
- if (changed & WIPHY_PARAM_RETRY_LONG)
- bss_cfg->retry_limit = wiphy->retry_long;
-
- bss_started = priv->bss_started;
-
- ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
- HostCmd_ACT_GEN_SET, 0,
- NULL, true);
- if (ret) {
- wiphy_err(wiphy, "Failed to stop the BSS\n");
- kfree(bss_cfg);
- return ret;
- }
+ int ret;
- ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
- HostCmd_ACT_GEN_SET,
- UAP_BSS_PARAMS_I, bss_cfg,
- false);
+ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
- kfree(bss_cfg);
+ switch (priv->bss_role) {
+ case MWIFIEX_BSS_ROLE_UAP:
+ if (priv->bss_started) {
+ dev_err(adapter->dev,
+ "cannot change wiphy params when bss started");
+ return -EINVAL;
+ }
- if (ret) {
- wiphy_err(wiphy, "Failed to set bss config\n");
- return ret;
- }
+ bss_cfg = kzalloc(sizeof(*bss_cfg), GFP_KERNEL);
+ if (!bss_cfg)
+ return -ENOMEM;
- if (!bss_started)
- break;
+ mwifiex_set_sys_config_invalid_data(bss_cfg);
- ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
- HostCmd_ACT_GEN_SET, 0,
- NULL, false);
- if (ret) {
- wiphy_err(wiphy, "Failed to start BSS\n");
- return ret;
- }
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD)
+ bss_cfg->rts_threshold = wiphy->rts_threshold;
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
+ bss_cfg->frag_threshold = wiphy->frag_threshold;
+ if (changed & WIPHY_PARAM_RETRY_LONG)
+ bss_cfg->retry_limit = wiphy->retry_long;
+
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
+ HostCmd_ACT_GEN_SET,
+ UAP_BSS_PARAMS_I, bss_cfg,
+ false);
+
+ kfree(bss_cfg);
+ if (ret) {
+ wiphy_err(wiphy, "Failed to set wiphy phy params\n");
+ return ret;
+ }
+ break;
- break;
case MWIFIEX_BSS_ROLE_STA:
- if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
- ret = mwifiex_set_rts(priv,
- wiphy->rts_threshold);
- if (ret)
- return ret;
- }
- if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
- ret = mwifiex_set_frag(priv,
- wiphy->frag_threshold);
- if (ret)
- return ret;
- }
- break;
+ if (priv->media_connected) {
+ dev_err(adapter->dev,
+ "cannot change wiphy params when connected");
+ return -EINVAL;
+ }
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ ret = mwifiex_set_rts(priv,
+ wiphy->rts_threshold);
+ if (ret)
+ return ret;
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ ret = mwifiex_set_frag(priv,
+ wiphy->frag_threshold);
+ if (ret)
+ return ret;
}
+ break;
}
return 0;
@@ -671,9 +656,6 @@ mwifiex_cfg80211_deinit_p2p(struct mwifiex_private *priv)
{
u16 mode = P2P_MODE_DISABLE;
- if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA)
- mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_STA);
-
if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG,
HostCmd_ACT_GEN_SET, 0, &mode, true))
return -1;
@@ -730,12 +712,249 @@ mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv)
HostCmd_ACT_GEN_SET, 0, &mode, true))
return -1;
- if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP)
- mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_UAP);
+ return 0;
+}
+
+static int mwifiex_deinit_priv_params(struct mwifiex_private *priv)
+{
+ priv->mgmt_frame_mask = 0;
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->mgmt_frame_mask, false)) {
+ dev_warn(priv->adapter->dev,
+ "could not unregister mgmt frame rx\n");
+ return -1;
+ }
+
+ mwifiex_deauthenticate(priv, NULL);
+ mwifiex_free_priv(priv);
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
+ priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
+
+ return 0;
+}
+
+static int
+mwifiex_init_new_priv_params(struct mwifiex_private *priv,
+ struct net_device *dev,
+ enum nl80211_iftype type)
+{
+ mwifiex_init_priv(priv);
+
+ priv->bss_mode = type;
+ priv->wdev.iftype = type;
+
+ mwifiex_init_priv_params(priv, priv->netdev);
+ priv->bss_started = 0;
+
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ priv->bss_role = MWIFIEX_BSS_ROLE_STA;
+ priv->bss_type = MWIFIEX_BSS_TYPE_STA;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ priv->bss_role = MWIFIEX_BSS_ROLE_STA;
+ priv->bss_type = MWIFIEX_BSS_TYPE_P2P;
+ break;
+ case NL80211_IFTYPE_AP:
+ priv->bss_type = MWIFIEX_BSS_TYPE_UAP;
+ priv->bss_role = MWIFIEX_BSS_ROLE_UAP;
+ break;
+ default:
+ dev_err(priv->adapter->dev,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int
+mwifiex_change_vif_to_p2p(struct net_device *dev,
+ enum nl80211_iftype curr_iftype,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct mwifiex_private *priv;
+ struct mwifiex_adapter *adapter;
+
+ priv = mwifiex_netdev_get_priv(dev);
+
+ if (!priv)
+ return -1;
+
+ adapter = priv->adapter;
+
+ if (adapter->curr_iface_comb.p2p_intf ==
+ adapter->iface_limit.p2p_intf) {
+ dev_err(adapter->dev,
+ "cannot create multiple P2P ifaces\n");
+ return -1;
+ }
+
+ dev_dbg(priv->adapter->dev, "%s: changing role to p2p\n", dev->name);
+
+ if (mwifiex_deinit_priv_params(priv))
+ return -1;
+ if (mwifiex_init_new_priv_params(priv, dev, type))
+ return -1;
+
+ switch (type) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ if (mwifiex_cfg80211_init_p2p_client(priv))
+ return -EFAULT;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ if (mwifiex_cfg80211_init_p2p_go(priv))
+ return -EFAULT;
+ break;
+ default:
+ dev_err(priv->adapter->dev,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
+ return -EOPNOTSUPP;
+ }
+
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL, true))
+ return -1;
+
+ if (mwifiex_sta_init_cmd(priv, false, false))
+ return -1;
+
+ switch (curr_iftype) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ adapter->curr_iface_comb.sta_intf--;
+ break;
+ case NL80211_IFTYPE_AP:
+ adapter->curr_iface_comb.uap_intf--;
+ break;
+ default:
+ break;
+ }
+
+ adapter->curr_iface_comb.p2p_intf++;
+ dev->ieee80211_ptr->iftype = type;
+
+ return 0;
+}
+
+static int
+mwifiex_change_vif_to_sta_adhoc(struct net_device *dev,
+ enum nl80211_iftype curr_iftype,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct mwifiex_private *priv;
+ struct mwifiex_adapter *adapter;
+
+ priv = mwifiex_netdev_get_priv(dev);
+
+ if (!priv)
+ return -1;
+
+ adapter = priv->adapter;
+
+ if ((curr_iftype != NL80211_IFTYPE_P2P_CLIENT &&
+ curr_iftype != NL80211_IFTYPE_P2P_GO) &&
+ (adapter->curr_iface_comb.sta_intf ==
+ adapter->iface_limit.sta_intf)) {
+ dev_err(adapter->dev,
+ "cannot create multiple station/adhoc ifaces\n");
+ return -1;
+ }
+
+ if (type == NL80211_IFTYPE_STATION)
+ dev_notice(adapter->dev,
+ "%s: changing role to station\n", dev->name);
+ else
+ dev_notice(adapter->dev,
+ "%s: changing role to adhoc\n", dev->name);
+
+ if (mwifiex_deinit_priv_params(priv))
+ return -1;
+ if (mwifiex_init_new_priv_params(priv, dev, type))
+ return -1;
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL, true))
+ return -1;
+ if (mwifiex_sta_init_cmd(priv, false, false))
+ return -1;
+
+ switch (curr_iftype) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ adapter->curr_iface_comb.p2p_intf--;
+ break;
+ case NL80211_IFTYPE_AP:
+ adapter->curr_iface_comb.uap_intf--;
+ break;
+ default:
+ break;
+ }
+ adapter->curr_iface_comb.sta_intf++;
+ dev->ieee80211_ptr->iftype = type;
return 0;
}
+static int
+mwifiex_change_vif_to_ap(struct net_device *dev,
+ enum nl80211_iftype curr_iftype,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct mwifiex_private *priv;
+ struct mwifiex_adapter *adapter;
+
+ priv = mwifiex_netdev_get_priv(dev);
+
+ if (!priv)
+ return -1;
+
+ adapter = priv->adapter;
+
+ if (adapter->curr_iface_comb.uap_intf ==
+ adapter->iface_limit.uap_intf) {
+ dev_err(adapter->dev,
+ "cannot create multiple AP ifaces\n");
+ return -1;
+ }
+
+ dev_notice(adapter->dev, "%s: changing role to AP\n", dev->name);
+
+ if (mwifiex_deinit_priv_params(priv))
+ return -1;
+ if (mwifiex_init_new_priv_params(priv, dev, type))
+ return -1;
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL, true))
+ return -1;
+ if (mwifiex_sta_init_cmd(priv, false, false))
+ return -1;
+
+ switch (curr_iftype) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ adapter->curr_iface_comb.p2p_intf--;
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ adapter->curr_iface_comb.sta_intf--;
+ break;
+ default:
+ break;
+ }
+
+ adapter->curr_iface_comb.uap_intf++;
+ dev->ieee80211_ptr->iftype = type;
+ return 0;
+}
/*
* CFG802.11 operation handler to change interface type.
*/
@@ -745,19 +964,32 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
- int ret;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ enum nl80211_iftype curr_iftype = dev->ieee80211_ptr->iftype;
- switch (dev->ieee80211_ptr->iftype) {
+ switch (curr_iftype) {
case NL80211_IFTYPE_ADHOC:
switch (type) {
case NL80211_IFTYPE_STATION:
- break;
+ priv->bss_mode = type;
+ priv->sec_info.authentication_mode =
+ NL80211_AUTHTYPE_OPEN_SYSTEM;
+ dev->ieee80211_ptr->iftype = type;
+ mwifiex_deauthenticate(priv, NULL);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL,
+ true);
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ return mwifiex_change_vif_to_p2p(dev, curr_iftype,
+ type, flags, params);
+ case NL80211_IFTYPE_AP:
+ return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
+ flags, params);
case NL80211_IFTYPE_UNSPECIFIED:
wiphy_warn(wiphy, "%s: kept type as IBSS\n", dev->name);
case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */
return 0;
- case NL80211_IFTYPE_AP:
default:
wiphy_err(wiphy, "%s: changing to %d not supported\n",
dev->name, type);
@@ -767,22 +999,25 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
case NL80211_IFTYPE_STATION:
switch (type) {
case NL80211_IFTYPE_ADHOC:
- break;
- case NL80211_IFTYPE_P2P_CLIENT:
- if (mwifiex_cfg80211_init_p2p_client(priv))
- return -EFAULT;
+ priv->bss_mode = type;
+ priv->sec_info.authentication_mode =
+ NL80211_AUTHTYPE_OPEN_SYSTEM;
dev->ieee80211_ptr->iftype = type;
- return 0;
+ mwifiex_deauthenticate(priv, NULL);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL,
+ true);
+ case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
- if (mwifiex_cfg80211_init_p2p_go(priv))
- return -EFAULT;
- dev->ieee80211_ptr->iftype = type;
- return 0;
+ return mwifiex_change_vif_to_p2p(dev, curr_iftype,
+ type, flags, params);
+ case NL80211_IFTYPE_AP:
+ return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
+ flags, params);
case NL80211_IFTYPE_UNSPECIFIED:
wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name);
case NL80211_IFTYPE_STATION: /* This shouldn't happen */
return 0;
- case NL80211_IFTYPE_AP:
default:
wiphy_err(wiphy, "%s: changing to %d not supported\n",
dev->name, type);
@@ -791,12 +1026,20 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
break;
case NL80211_IFTYPE_AP:
switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_STATION:
+ return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype,
+ type, flags,
+ params);
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ return mwifiex_change_vif_to_p2p(dev, curr_iftype,
+ type, flags, params);
case NL80211_IFTYPE_UNSPECIFIED:
wiphy_warn(wiphy, "%s: kept type as AP\n", dev->name);
case NL80211_IFTYPE_AP: /* This shouldn't happen */
return 0;
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_STATION:
default:
wiphy_err(wiphy, "%s: changing to %d not supported\n",
dev->name, type);
@@ -807,11 +1050,30 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
case NL80211_IFTYPE_P2P_GO:
switch (type) {
case NL80211_IFTYPE_STATION:
- if (mwifiex_cfg80211_deinit_p2p(priv))
+ if (mwifiex_cfg80211_init_p2p_client(priv))
return -EFAULT;
dev->ieee80211_ptr->iftype = type;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ if (mwifiex_cfg80211_deinit_p2p(priv))
+ return -EFAULT;
+ return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype,
+ type, flags,
+ params);
+ break;
+ case NL80211_IFTYPE_AP:
+ if (mwifiex_cfg80211_deinit_p2p(priv))
+ return -EFAULT;
+ return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
+ flags, params);
+ case NL80211_IFTYPE_UNSPECIFIED:
+ wiphy_warn(wiphy, "%s: kept type as P2P\n", dev->name);
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
return 0;
default:
+ wiphy_err(wiphy, "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
break;
@@ -821,16 +1083,8 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
return -EOPNOTSUPP;
}
- dev->ieee80211_ptr->iftype = type;
- priv->bss_mode = type;
- mwifiex_deauthenticate(priv, NULL);
-
- priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
-
- ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
- HostCmd_ACT_GEN_SET, 0, NULL, true);
- return ret;
+ return 0;
}
static void
@@ -856,16 +1110,16 @@ mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo,
/* HT or VHT */
switch (tx_htinfo & (BIT(3) | BIT(2))) {
case 0:
- /* This will be 20MHz */
+ rate->bw = RATE_INFO_BW_20;
break;
case (BIT(2)):
- rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ rate->bw = RATE_INFO_BW_40;
break;
case (BIT(3)):
- rate->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
+ rate->bw = RATE_INFO_BW_80;
break;
case (BIT(3) | BIT(2)):
- rate->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
+ rate->bw = RATE_INFO_BW_160;
break;
}
@@ -885,8 +1139,9 @@ mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo,
if ((tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) {
rate->mcs = priv->tx_rate;
rate->flags |= RATE_INFO_FLAGS_MCS;
+ rate->bw = RATE_INFO_BW_20;
if (tx_htinfo & BIT(1))
- rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ rate->bw = RATE_INFO_BW_40;
if (tx_htinfo & BIT(2))
rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
}
@@ -910,10 +1165,10 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
{
u32 rate;
- sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
- STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS |
- STATION_INFO_TX_BITRATE |
- STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
+ sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) | BIT(NL80211_STA_INFO_TX_BYTES) |
+ BIT(NL80211_STA_INFO_RX_PACKETS) | BIT(NL80211_STA_INFO_TX_PACKETS) |
+ BIT(NL80211_STA_INFO_TX_BITRATE) |
+ BIT(NL80211_STA_INFO_SIGNAL) | BIT(NL80211_STA_INFO_SIGNAL_AVG);
/* Get signal information from the firmware */
if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
@@ -944,7 +1199,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
sinfo->txrate.legacy = rate * 5;
if (priv->bss_mode == NL80211_IFTYPE_STATION) {
- sinfo->filled |= STATION_INFO_BSS_PARAM;
+ sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
sinfo->bss_param.flags = 0;
if (priv->curr_bss_params.bss_descriptor.cap_info_bitmap &
WLAN_CAPABILITY_SHORT_PREAMBLE)
@@ -1037,10 +1292,11 @@ mwifiex_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
survey->channel = ieee80211_get_channel(wiphy,
ieee80211_channel_to_frequency(pchan_stats[idx].chan_num, band));
survey->filled = SURVEY_INFO_NOISE_DBM |
- SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY;
+ SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY;
survey->noise = pchan_stats[idx].noise;
- survey->channel_time = pchan_stats[idx].cca_scan_dur;
- survey->channel_time_busy = pchan_stats[idx].cca_busy_dur;
+ survey->time = pchan_stats[idx].cca_scan_dur;
+ survey->time_busy = pchan_stats[idx].cca_busy_dur;
return 0;
}
@@ -1395,10 +1651,13 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ mwifiex_abort_cac(priv);
+
if (mwifiex_del_mgmt_ies(priv))
wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
priv->ap_11n_enabled = 0;
+ memset(&priv->bss_cfg, 0, sizeof(priv->bss_cfg));
if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL, true)) {
@@ -1420,12 +1679,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
{
struct mwifiex_uap_bss_param *bss_cfg;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- u8 config_bands = 0;
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP)
return -1;
- if (mwifiex_set_mgmt_ies(priv, &params->beacon))
- return -1;
bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
if (!bss_cfg)
@@ -1442,6 +1698,11 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len);
bss_cfg->ssid.ssid_len = params->ssid_len;
}
+ if (params->inactivity_timeout > 0) {
+ /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */
+ bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout;
+ bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout;
+ }
switch (params->hidden_ssid) {
case NL80211_HIDDEN_SSID_NOT_IN_USE:
@@ -1457,33 +1718,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
return -EINVAL;
}
- bss_cfg->channel = ieee80211_frequency_to_channel(
- params->chandef.chan->center_freq);
-
- /* Set appropriate bands */
- if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) {
- bss_cfg->band_cfg = BAND_CONFIG_BG;
- config_bands = BAND_B | BAND_G;
-
- if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
- config_bands |= BAND_GN;
- } else {
- bss_cfg->band_cfg = BAND_CONFIG_A;
- config_bands = BAND_A;
-
- if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
- config_bands |= BAND_AN;
-
- if (params->chandef.width > NL80211_CHAN_WIDTH_40)
- config_bands |= BAND_AAC;
- }
-
- if (!((config_bands | priv->adapter->fw_bands) &
- ~priv->adapter->fw_bands))
- priv->adapter->config_bands = config_bands;
-
+ mwifiex_uap_set_channel(bss_cfg, params->chandef);
mwifiex_set_uap_rates(bss_cfg, params);
- mwifiex_send_domain_info_cmd_fw(wiphy);
if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
kfree(bss_cfg);
@@ -1506,45 +1742,29 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
mwifiex_set_wmm_params(priv, bss_cfg, params);
- if (params->inactivity_timeout > 0) {
- /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */
- bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout;
- bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout;
+ if (mwifiex_is_11h_active(priv) &&
+ !cfg80211_chandef_dfs_required(wiphy, &params->chandef,
+ priv->bss_mode)) {
+ dev_dbg(priv->adapter->dev, "Disable 11h extensions in FW\n");
+ if (mwifiex_11h_activate(priv, false)) {
+ dev_err(priv->adapter->dev,
+ "Failed to disable 11h extensions!!");
+ return -1;
+ }
+ priv->state_11h.is_11h_active = true;
}
- if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
- HostCmd_ACT_GEN_SET, 0, NULL, true)) {
- wiphy_err(wiphy, "Failed to stop the BSS\n");
+ if (mwifiex_config_start_uap(priv, bss_cfg)) {
+ wiphy_err(wiphy, "Failed to start AP\n");
kfree(bss_cfg);
return -1;
}
- if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
- HostCmd_ACT_GEN_SET,
- UAP_BSS_PARAMS_I, bss_cfg, false)) {
- wiphy_err(wiphy, "Failed to set the SSID\n");
- kfree(bss_cfg);
+ if (mwifiex_set_mgmt_ies(priv, &params->beacon))
return -1;
- }
+ memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg));
kfree(bss_cfg);
-
- if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
- HostCmd_ACT_GEN_SET, 0, NULL, false)) {
- wiphy_err(wiphy, "Failed to start the BSS\n");
- return -1;
- }
-
- if (priv->sec_info.wep_enabled)
- priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
- else
- priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
-
- if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
- HostCmd_ACT_GEN_SET, 0,
- &priv->curr_pkt_filter, true))
- return -1;
-
return 0;
}
@@ -1603,15 +1823,15 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
- chan = __ieee80211_get_channel(priv->wdev->wiphy,
+ chan = __ieee80211_get_channel(priv->wdev.wiphy,
ieee80211_channel_to_frequency(bss_info.bss_chan,
band));
- bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
+ bss = cfg80211_inform_bss(priv->wdev.wiphy, chan,
CFG80211_BSS_FTYPE_UNKNOWN,
bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
0, ie_buf, ie_len, 0, GFP_KERNEL);
- cfg80211_put_bss(priv->wdev->wiphy, bss);
+ cfg80211_put_bss(priv->wdev.wiphy, bss);
memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
return 0;
@@ -1732,12 +1952,12 @@ done:
/* Find the BSS we want using available scan results */
if (mode == NL80211_IFTYPE_ADHOC)
- bss = cfg80211_get_bss(priv->wdev->wiphy, channel,
+ bss = cfg80211_get_bss(priv->wdev.wiphy, channel,
bssid, ssid, ssid_len,
WLAN_CAPABILITY_IBSS,
WLAN_CAPABILITY_IBSS);
else
- bss = cfg80211_get_bss(priv->wdev->wiphy, channel,
+ bss = cfg80211_get_bss(priv->wdev.wiphy, channel,
bssid, ssid, ssid_len,
WLAN_CAPABILITY_ESS,
WLAN_CAPABILITY_ESS);
@@ -1784,6 +2004,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ struct mwifiex_adapter *adapter = priv->adapter;
int ret;
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) {
@@ -1793,11 +2014,18 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
return -EINVAL;
}
- if (priv->wdev && priv->wdev->current_bss) {
+ if (priv->wdev.current_bss) {
wiphy_warn(wiphy, "%s: already connected\n", dev->name);
return -EALREADY;
}
+ if (adapter->surprise_removed || adapter->is_cmd_timedout) {
+ wiphy_err(wiphy,
+ "%s: Ignore connection. Card removed or FW in bad state\n",
+ dev->name);
+ return -EFAULT;
+ }
+
wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n",
(char *) sme->ssid, sme->bssid);
@@ -1844,7 +2072,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
static int mwifiex_set_ibss_params(struct mwifiex_private *priv,
struct cfg80211_ibss_params *params)
{
- struct wiphy *wiphy = priv->wdev->wiphy;
+ struct wiphy *wiphy = priv->wdev.wiphy;
struct mwifiex_adapter *adapter = priv->adapter;
int index = 0, i;
u8 config_bands = 0;
@@ -2169,6 +2397,7 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
}
+#define MWIFIEX_MAX_WQ_LEN 30
/*
* create a new virtual interface with the given name
*/
@@ -2182,7 +2411,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
struct mwifiex_private *priv;
struct net_device *dev;
void *mdev_priv;
- struct wireless_dev *wdev;
+ char dfs_cac_str[MWIFIEX_MAX_WQ_LEN], dfs_chsw_str[MWIFIEX_MAX_WQ_LEN];
if (!adapter)
return ERR_PTR(-EFAULT);
@@ -2191,20 +2420,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
- priv = adapter->priv[MWIFIEX_BSS_TYPE_STA];
- if (priv->bss_mode) {
+ if (adapter->curr_iface_comb.sta_intf ==
+ adapter->iface_limit.sta_intf) {
wiphy_err(wiphy,
"cannot create multiple sta/adhoc ifaces\n");
return ERR_PTR(-EINVAL);
}
- wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
- if (!wdev)
- return ERR_PTR(-ENOMEM);
+ priv = mwifiex_get_unused_priv(adapter);
+ if (!priv) {
+ wiphy_err(wiphy,
+ "could not get free private struct\n");
+ return ERR_PTR(-EFAULT);
+ }
- wdev->wiphy = wiphy;
- priv->wdev = wdev;
- wdev->iftype = NL80211_IFTYPE_STATION;
+ priv->wdev.wiphy = wiphy;
+ priv->wdev.iftype = NL80211_IFTYPE_STATION;
if (type == NL80211_IFTYPE_UNSPECIFIED)
priv->bss_mode = NL80211_IFTYPE_STATION;
@@ -2219,20 +2450,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
break;
case NL80211_IFTYPE_AP:
- priv = adapter->priv[MWIFIEX_BSS_TYPE_UAP];
-
- if (priv->bss_mode) {
- wiphy_err(wiphy, "Can't create multiple AP interfaces");
+ if (adapter->curr_iface_comb.uap_intf ==
+ adapter->iface_limit.uap_intf) {
+ wiphy_err(wiphy,
+ "cannot create multiple AP ifaces\n");
return ERR_PTR(-EINVAL);
}
- wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
- if (!wdev)
- return ERR_PTR(-ENOMEM);
+ priv = mwifiex_get_unused_priv(adapter);
+ if (!priv) {
+ wiphy_err(wiphy,
+ "could not get free private struct\n");
+ return ERR_PTR(-EFAULT);
+ }
- priv->wdev = wdev;
- wdev->wiphy = wiphy;
- wdev->iftype = NL80211_IFTYPE_AP;
+ priv->wdev.wiphy = wiphy;
+ priv->wdev.iftype = NL80211_IFTYPE_AP;
priv->bss_type = MWIFIEX_BSS_TYPE_UAP;
priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
@@ -2244,24 +2477,25 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
break;
case NL80211_IFTYPE_P2P_CLIENT:
- priv = adapter->priv[MWIFIEX_BSS_TYPE_P2P];
-
- if (priv->bss_mode) {
- wiphy_err(wiphy, "Can't create multiple P2P ifaces");
+ if (adapter->curr_iface_comb.p2p_intf ==
+ adapter->iface_limit.p2p_intf) {
+ wiphy_err(wiphy,
+ "cannot create multiple P2P ifaces\n");
return ERR_PTR(-EINVAL);
}
- wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
- if (!wdev)
- return ERR_PTR(-ENOMEM);
-
- priv->wdev = wdev;
- wdev->wiphy = wiphy;
+ priv = mwifiex_get_unused_priv(adapter);
+ if (!priv) {
+ wiphy_err(wiphy,
+ "could not get free private struct\n");
+ return ERR_PTR(-EFAULT);
+ }
+ priv->wdev.wiphy = wiphy;
/* At start-up, wpa_supplicant tries to change the interface
* to NL80211_IFTYPE_STATION if it is not managed mode.
*/
- wdev->iftype = NL80211_IFTYPE_P2P_CLIENT;
+ priv->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT;
priv->bss_mode = NL80211_IFTYPE_P2P_CLIENT;
/* Setting bss_type to P2P tells firmware that this interface
@@ -2277,8 +2511,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
priv->bss_num = 0;
if (mwifiex_cfg80211_init_p2p_client(priv)) {
- wdev = ERR_PTR(-EFAULT);
- goto done;
+ memset(&priv->wdev, 0, sizeof(priv->wdev));
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
+ return ERR_PTR(-EFAULT);
}
break;
@@ -2292,9 +2527,10 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
IEEE80211_NUM_ACS, 1);
if (!dev) {
wiphy_err(wiphy, "no memory available for netdevice\n");
+ memset(&priv->wdev, 0, sizeof(priv->wdev));
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
- wdev = ERR_PTR(-ENOMEM);
- goto done;
+ return ERR_PTR(-ENOMEM);
}
mwifiex_init_priv_params(priv, dev);
@@ -2314,7 +2550,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
&wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap, priv);
dev_net_set(dev, wiphy_net(wiphy));
- dev->ieee80211_ptr = priv->wdev;
+ dev->ieee80211_ptr = &priv->wdev;
dev->ieee80211_ptr->iftype = priv->bss_mode;
memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
SET_NETDEV_DEV(dev, wiphy_dev(wiphy));
@@ -2335,10 +2571,47 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
free_netdev(dev);
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
priv->netdev = NULL;
- wdev = ERR_PTR(-EFAULT);
- goto done;
+ memset(&priv->wdev, 0, sizeof(priv->wdev));
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
+ return ERR_PTR(-EFAULT);
+ }
+
+ strcpy(dfs_cac_str, "MWIFIEX_DFS_CAC");
+ strcat(dfs_cac_str, name);
+ priv->dfs_cac_workqueue = alloc_workqueue(dfs_cac_str,
+ WQ_HIGHPRI |
+ WQ_MEM_RECLAIM |
+ WQ_UNBOUND, 1);
+ if (!priv->dfs_cac_workqueue) {
+ wiphy_err(wiphy, "cannot register virtual network device\n");
+ free_netdev(dev);
+ priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->netdev = NULL;
+ memset(&priv->wdev, 0, sizeof(priv->wdev));
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
+ return ERR_PTR(-ENOMEM);
+ }
+
+ INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue);
+
+ strcpy(dfs_chsw_str, "MWIFIEX_DFS_CHSW");
+ strcat(dfs_chsw_str, name);
+ priv->dfs_chan_sw_workqueue = alloc_workqueue(dfs_chsw_str,
+ WQ_HIGHPRI | WQ_UNBOUND |
+ WQ_MEM_RECLAIM, 1);
+ if (!priv->dfs_chan_sw_workqueue) {
+ wiphy_err(wiphy, "cannot register virtual network device\n");
+ free_netdev(dev);
+ priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->netdev = NULL;
+ memset(&priv->wdev, 0, sizeof(priv->wdev));
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
+ return ERR_PTR(-ENOMEM);
}
+ INIT_DELAYED_WORK(&priv->dfs_chan_sw_work,
+ mwifiex_dfs_chan_sw_work_queue);
+
sema_init(&priv->async_sem, 1);
dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
@@ -2347,13 +2620,24 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
mwifiex_dev_debugfs_init(priv);
#endif
-done:
- if (IS_ERR(wdev)) {
- kfree(priv->wdev);
- priv->wdev = NULL;
+ switch (type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ adapter->curr_iface_comb.sta_intf++;
+ break;
+ case NL80211_IFTYPE_AP:
+ adapter->curr_iface_comb.uap_intf++;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ adapter->curr_iface_comb.p2p_intf++;
+ break;
+ default:
+ wiphy_err(wiphy, "type not supported\n");
+ return ERR_PTR(-EINVAL);
}
- return wdev;
+ return &priv->wdev;
}
EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);
@@ -2363,12 +2647,13 @@ EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);
int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
+ struct mwifiex_adapter *adapter = priv->adapter;
#ifdef CONFIG_DEBUG_FS
mwifiex_dev_debugfs_remove(priv);
#endif
- mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
+ mwifiex_stop_net_dev_queue(priv->netdev, adapter);
if (netif_carrier_ok(priv->netdev))
netif_carrier_off(priv->netdev);
@@ -2376,14 +2661,42 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
if (wdev->netdev->reg_state == NETREG_REGISTERED)
unregister_netdevice(wdev->netdev);
+ if (priv->dfs_cac_workqueue) {
+ flush_workqueue(priv->dfs_cac_workqueue);
+ destroy_workqueue(priv->dfs_cac_workqueue);
+ priv->dfs_cac_workqueue = NULL;
+ }
+
+ if (priv->dfs_chan_sw_workqueue) {
+ flush_workqueue(priv->dfs_chan_sw_workqueue);
+ destroy_workqueue(priv->dfs_chan_sw_workqueue);
+ priv->dfs_chan_sw_workqueue = NULL;
+ }
/* Clear the priv in adapter */
priv->netdev->ieee80211_ptr = NULL;
priv->netdev = NULL;
- kfree(wdev);
- priv->wdev = NULL;
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
priv->media_connected = false;
+ switch (priv->bss_mode) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ adapter->curr_iface_comb.sta_intf++;
+ break;
+ case NL80211_IFTYPE_AP:
+ adapter->curr_iface_comb.uap_intf++;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ adapter->curr_iface_comb.p2p_intf++;
+ break;
+ default:
+ dev_err(adapter->dev, "del_virtual_intf: type not supported\n");
+ break;
+ }
+
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA ||
@@ -2838,6 +3151,102 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev,
}
static int
+mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_csa_settings *params)
+{
+ struct ieee_types_header *chsw_ie;
+ struct ieee80211_channel_sw_ie *channel_sw;
+ int chsw_msec;
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+ if (priv->adapter->scan_processing) {
+ dev_err(priv->adapter->dev,
+ "radar detection: scan in process...\n");
+ return -EBUSY;
+ }
+
+ if (priv->wdev.cac_started)
+ return -EBUSY;
+
+ if (cfg80211_chandef_identical(&params->chandef,
+ &priv->dfs_chandef))
+ return -EINVAL;
+
+ chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH,
+ params->beacon_csa.tail,
+ params->beacon_csa.tail_len);
+ if (!chsw_ie) {
+ dev_err(priv->adapter->dev,
+ "Could not parse channel switch announcement IE\n");
+ return -EINVAL;
+ }
+
+ channel_sw = (void *)(chsw_ie + 1);
+ if (channel_sw->mode) {
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
+ }
+
+ if (mwifiex_del_mgmt_ies(priv))
+ wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
+
+ if (mwifiex_set_mgmt_ies(priv, &params->beacon_csa)) {
+ wiphy_err(wiphy, "%s: setting mgmt ies failed\n", __func__);
+ return -EFAULT;
+ }
+
+ memcpy(&priv->dfs_chandef, &params->chandef, sizeof(priv->dfs_chandef));
+ memcpy(&priv->beacon_after, &params->beacon_after,
+ sizeof(priv->beacon_after));
+
+ chsw_msec = max(channel_sw->count * priv->bss_cfg.beacon_period, 100);
+ queue_delayed_work(priv->dfs_chan_sw_workqueue, &priv->dfs_chan_sw_work,
+ msecs_to_jiffies(chsw_msec));
+ return 0;
+}
+
+static int
+mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_chan_def *chandef,
+ u32 cac_time_ms)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ struct mwifiex_radar_params radar_params;
+
+ if (priv->adapter->scan_processing) {
+ dev_err(priv->adapter->dev,
+ "radar detection: scan already in process...\n");
+ return -EBUSY;
+ }
+
+ if (!mwifiex_is_11h_active(priv)) {
+ dev_dbg(priv->adapter->dev, "Enable 11h extensions in FW\n");
+ if (mwifiex_11h_activate(priv, true)) {
+ dev_err(priv->adapter->dev,
+ "Failed to activate 11h extensions!!");
+ return -1;
+ }
+ priv->state_11h.is_11h_active = true;
+ }
+
+ memset(&radar_params, 0, sizeof(struct mwifiex_radar_params));
+ radar_params.chandef = chandef;
+ radar_params.cac_time_ms = cac_time_ms;
+
+ memcpy(&priv->dfs_chandef, chandef, sizeof(priv->dfs_chandef));
+
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST,
+ HostCmd_ACT_GEN_SET, 0, &radar_params, true))
+ return -1;
+
+ queue_delayed_work(priv->dfs_cac_workqueue, &priv->dfs_cac_work,
+ msecs_to_jiffies(cac_time_ms));
+ return 0;
+}
+
+static int
mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev,
const u8 *mac,
struct station_parameters *params)
@@ -2901,6 +3310,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.tdls_oper = mwifiex_cfg80211_tdls_oper,
.add_station = mwifiex_cfg80211_add_station,
.change_station = mwifiex_cfg80211_change_station,
+ .start_radar_detection = mwifiex_cfg80211_start_radar_detection,
+ .channel_switch = mwifiex_cfg80211_channel_switch,
};
#ifdef CONFIG_PM
@@ -2999,12 +3410,13 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->cipher_suites = mwifiex_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
- memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
+ ether_addr_copy(wiphy->perm_addr, adapter->perm_addr);
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
WIPHY_FLAG_AP_UAPSD |
- WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+ WIPHY_FLAG_HAS_CHANNEL_SWITCH;
if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
index f494fc7eeb62..e9df8826f124 100644
--- a/drivers/net/wireless/mwifiex/cfp.c
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -322,9 +322,9 @@ mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq)
return cfp;
if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
- sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
+ sband = priv->wdev.wiphy->bands[IEEE80211_BAND_2GHZ];
else
- sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
+ sband = priv->wdev.wiphy->bands[IEEE80211_BAND_5GHZ];
if (!sband) {
dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d\n",
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 946a2f7a172f..c5a14ff7eb82 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -315,22 +315,19 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
return -1;
}
- if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY))
- == MWIFIEX_BSS_ROLE_STA) {
- if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl))
- /* Response is not needed for sleep
- confirm command */
- adapter->ps_state = PS_STATE_SLEEP;
- else
- adapter->ps_state = PS_STATE_SLEEP_CFM;
-
- if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl) &&
- (adapter->is_hs_configured &&
- !adapter->sleep_period.period)) {
- adapter->pm_wakeup_card_req = true;
- mwifiex_hs_activated_event(mwifiex_get_priv
- (adapter, MWIFIEX_BSS_ROLE_STA), true);
- }
+
+ if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl))
+ /* Response is not needed for sleep confirm command */
+ adapter->ps_state = PS_STATE_SLEEP;
+ else
+ adapter->ps_state = PS_STATE_SLEEP_CFM;
+
+ if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl) &&
+ (adapter->is_hs_configured &&
+ !adapter->sleep_period.period)) {
+ adapter->pm_wakeup_card_req = true;
+ mwifiex_hs_activated_event(mwifiex_get_priv
+ (adapter, MWIFIEX_BSS_ROLE_ANY), true);
}
return ret;
@@ -450,6 +447,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
EVENT_GET_BSS_TYPE(eventcause));
if (!priv)
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+
/* Clear BSS_NO_BITS from event */
eventcause &= EVENT_ID_MASK;
adapter->event_cause = eventcause;
@@ -462,12 +460,6 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
}
dev_dbg(adapter->dev, "EVENT: cause: %#x\n", eventcause);
- if (eventcause == EVENT_PS_SLEEP || eventcause == EVENT_PS_AWAKE) {
- /* Handle PS_SLEEP/AWAKE events on STA */
- priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
- if (!priv)
- priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
- }
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
ret = mwifiex_process_uap_event(priv);
@@ -1582,9 +1574,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
le16_to_cpu(hw_spec->hw_if_version),
le16_to_cpu(hw_spec->version));
- if (priv->curr_addr[0] == 0xff)
- memmove(priv->curr_addr, hw_spec->permanent_addr, ETH_ALEN);
-
+ ether_addr_copy(priv->adapter->perm_addr, hw_spec->permanent_addr);
adapter->region_code = le16_to_cpu(hw_spec->region_code);
for (i = 0; i < MWIFIEX_MAX_REGION_CODE; i++)
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index 7aa988e1dc7a..88d0eade6bb1 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -104,6 +104,12 @@
/* Rate index for OFDM 0 */
#define MWIFIEX_RATE_INDEX_OFDM0 4
+#define MWIFIEX_MAX_STA_NUM 1
+#define MWIFIEX_MAX_UAP_NUM 1
+#define MWIFIEX_MAX_P2P_NUM 1
+
+#define MWIFIEX_A_BAND_START_FREQ 5000
+
enum mwifiex_bss_type {
MWIFIEX_BSS_TYPE_STA = 0,
MWIFIEX_BSS_TYPE_UAP = 1,
@@ -232,4 +238,19 @@ struct mwifiex_histogram_data {
atomic_t num_samples;
};
+struct mwifiex_iface_comb {
+ u8 sta_intf;
+ u8 uap_intf;
+ u8 p2p_intf;
+};
+
+struct mwifiex_radar_params {
+ struct cfg80211_chan_def *chandef;
+ u32 cac_time_ms;
+} __packed;
+
+struct mwifiex_11h_intf_state {
+ bool is_11h_enabled;
+ bool is_11h_active;
+} __packed;
#endif /* !_MWIFIEX_DECL_H_ */
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 15ad776ae08e..df553e86a0ad 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -158,6 +158,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84)
#define TLV_TYPE_BSS_SCAN_RSP (PROPRIETARY_TLV_BASE_ID + 86)
#define TLV_TYPE_BSS_SCAN_INFO (PROPRIETARY_TLV_BASE_ID + 87)
+#define TLV_TYPE_CHANRPT_11H_BASIC (PROPRIETARY_TLV_BASE_ID + 91)
#define TLV_TYPE_UAP_RETRY_LIMIT (PROPRIETARY_TLV_BASE_ID + 93)
#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94)
#define TLV_TYPE_UAP_MGMT_FRAME (PROPRIETARY_TLV_BASE_ID + 104)
@@ -336,6 +337,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
#define HostCmd_CMD_11N_DELBA 0x00d0
#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9
+#define HostCmd_CMD_CHAN_REPORT_REQUEST 0x00dd
#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df
#define HostCmd_CMD_TXPWR_CFG 0x00d1
#define HostCmd_CMD_TX_RATE_CFG 0x00d6
@@ -493,6 +495,8 @@ enum P2P_MODES {
#define EVENT_HOSTWAKE_STAIE 0x0000004d
#define EVENT_CHANNEL_SWITCH_ANN 0x00000050
#define EVENT_TDLS_GENERIC_EVENT 0x00000052
+#define EVENT_RADAR_DETECTED 0x00000053
+#define EVENT_CHANNEL_REPORT_RDY 0x00000054
#define EVENT_EXT_SCAN_REPORT 0x00000058
#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f
#define EVENT_TX_STATUS_REPORT 0x00000074
@@ -530,6 +534,8 @@ enum P2P_MODES {
#define MWIFIEX_FW_V15 15
+#define MWIFIEX_MASTER_RADAR_DET_MASK BIT(1)
+
struct mwifiex_ie_types_header {
__le16 type;
__le16 len;
@@ -1216,6 +1222,24 @@ struct host_cmd_ds_tdls_oper {
u8 peer_mac[ETH_ALEN];
} __packed;
+struct mwifiex_chan_desc {
+ __le16 start_freq;
+ u8 chan_width;
+ u8 chan_num;
+} __packed;
+
+struct host_cmd_ds_chan_rpt_req {
+ struct mwifiex_chan_desc chan_desc;
+ __le32 msec_dwell_time;
+} __packed;
+
+struct host_cmd_ds_chan_rpt_event {
+ __le32 result;
+ __le64 start_tsf;
+ __le32 duration;
+ u8 tlvbuf[0];
+} __packed;
+
struct mwifiex_fixed_bcn_param {
__le64 timestamp;
__le16 beacon_period;
@@ -1792,6 +1816,39 @@ struct mwifiex_ie_types_rssi_threshold {
u8 evt_freq;
} __packed;
+#define MWIFIEX_DFS_REC_HDR_LEN 8
+#define MWIFIEX_DFS_REC_HDR_NUM 10
+#define MWIFIEX_BIN_COUNTER_LEN 7
+
+struct mwifiex_radar_det_event {
+ __le32 detect_count;
+ u8 reg_domain; /*1=fcc, 2=etsi, 3=mic*/
+ u8 det_type; /*0=none, 1=pw(chirp), 2=pri(radar)*/
+ __le16 pw_chirp_type;
+ u8 pw_chirp_idx;
+ u8 pw_value;
+ u8 pri_radar_type;
+ u8 pri_bincnt;
+ u8 bin_counter[MWIFIEX_BIN_COUNTER_LEN];
+ u8 num_dfs_records;
+ u8 dfs_record_hdr[MWIFIEX_DFS_REC_HDR_NUM][MWIFIEX_DFS_REC_HDR_LEN];
+ __le32 passed;
+} __packed;
+
+struct meas_rpt_map {
+ u8 rssi:3;
+ u8 unmeasured:1;
+ u8 radar:1;
+ u8 unidentified_sig:1;
+ u8 ofdm_preamble:1;
+ u8 bss:1;
+} __packed;
+
+struct mwifiex_ie_types_chan_rpt_data {
+ struct mwifiex_ie_types_header header;
+ struct meas_rpt_map map;
+} __packed;
+
struct host_cmd_ds_802_11_subsc_evt {
__le16 action;
__le16 events;
@@ -1904,6 +1961,7 @@ struct host_cmd_ds_command {
struct host_cmd_11ac_vht_cfg vht_cfg;
struct host_cmd_ds_coalesce_cfg coalesce_cfg;
struct host_cmd_ds_tdls_oper tdls_oper;
+ struct host_cmd_ds_chan_rpt_req chan_rpt_req;
} params;
} __packed;
diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c
index b933794758b7..f3b6ed249403 100644
--- a/drivers/net/wireless/mwifiex/ie.c
+++ b/drivers/net/wireless/mwifiex/ie.c
@@ -317,27 +317,27 @@ done:
return ret;
}
-/* This function parses different IEs-tail IEs, beacon IEs, probe response IEs,
- * association response IEs from cfg80211_ap_settings function and sets these IE
- * to FW.
+/* This function parses head and tail IEs, from cfg80211_beacon_data and sets
+ * these IE to FW.
*/
-int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
- struct cfg80211_beacon_data *info)
+static int mwifiex_uap_set_head_tail_ies(struct mwifiex_private *priv,
+ struct cfg80211_beacon_data *info)
{
struct mwifiex_ie *gen_ie;
- struct ieee_types_header *rsn_ie, *wpa_ie = NULL;
- u16 rsn_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
+ struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL;
+ struct ieee_types_header *chsw_ie = NULL;
+ u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
const u8 *vendor_ie;
- if (info->tail && info->tail_len) {
- gen_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
- if (!gen_ie)
- return -ENOMEM;
- gen_ie->ie_index = cpu_to_le16(rsn_idx);
- gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON |
- MGMT_MASK_PROBE_RESP |
- MGMT_MASK_ASSOC_RESP);
+ gen_ie = kzalloc(sizeof(*gen_ie), GFP_KERNEL);
+ if (!gen_ie)
+ return -ENOMEM;
+ gen_ie->ie_index = cpu_to_le16(gen_idx);
+ gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON |
+ MGMT_MASK_PROBE_RESP |
+ MGMT_MASK_ASSOC_RESP);
+ if (info->tail && info->tail_len) {
rsn_ie = (void *)cfg80211_find_ie(WLAN_EID_RSN,
info->tail, info->tail_len);
if (rsn_ie) {
@@ -358,19 +358,41 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
gen_ie->ie_length = cpu_to_le16(ie_len);
}
- if (rsn_ie || wpa_ie) {
- if (mwifiex_update_uap_custom_ie(priv, gen_ie, &rsn_idx,
- NULL, NULL,
- NULL, NULL)) {
- kfree(gen_ie);
- return -1;
- }
- priv->rsn_idx = rsn_idx;
+ chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH,
+ info->tail, info->tail_len);
+ if (chsw_ie) {
+ memcpy(gen_ie->ie_buffer + ie_len,
+ chsw_ie, chsw_ie->len + 2);
+ ie_len += chsw_ie->len + 2;
+ gen_ie->ie_length = cpu_to_le16(ie_len);
}
+ }
- kfree(gen_ie);
+ if (rsn_ie || wpa_ie || chsw_ie) {
+ if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL,
+ NULL, NULL, NULL)) {
+ kfree(gen_ie);
+ return -1;
+ }
+ priv->gen_idx = gen_idx;
}
+ kfree(gen_ie);
+ return 0;
+}
+
+/* This function parses different IEs-head & tail IEs, beacon IEs,
+ * probe response IEs, association response IEs from cfg80211_ap_settings
+ * function and sets these IE to FW.
+ */
+int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
+ struct cfg80211_beacon_data *info)
+{
+ int ret;
+
+ ret = mwifiex_uap_set_head_tail_ies(priv, info);
+ return ret;
+
return mwifiex_set_mgmt_beacon_data_ies(priv, info);
}
@@ -378,25 +400,25 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
int mwifiex_del_mgmt_ies(struct mwifiex_private *priv)
{
struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
- struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL;
+ struct mwifiex_ie *ar_ie = NULL, *gen_ie = NULL;
int ret = 0;
- if (priv->rsn_idx != MWIFIEX_AUTO_IDX_MASK) {
- rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
- if (!rsn_ie)
+ if (priv->gen_idx != MWIFIEX_AUTO_IDX_MASK) {
+ gen_ie = kmalloc(sizeof(*gen_ie), GFP_KERNEL);
+ if (!gen_ie)
return -ENOMEM;
- rsn_ie->ie_index = cpu_to_le16(priv->rsn_idx);
- rsn_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
- rsn_ie->ie_length = 0;
- if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &priv->rsn_idx,
+ gen_ie->ie_index = cpu_to_le16(priv->gen_idx);
+ gen_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
+ gen_ie->ie_length = 0;
+ if (mwifiex_update_uap_custom_ie(priv, gen_ie, &priv->gen_idx,
NULL, &priv->proberesp_idx,
NULL, &priv->assocresp_idx)) {
ret = -1;
goto done;
}
- priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK;
+ priv->gen_idx = MWIFIEX_AUTO_IDX_MASK;
}
if (priv->beacon_idx != MWIFIEX_AUTO_IDX_MASK) {
@@ -440,7 +462,6 @@ done:
kfree(beacon_ie);
kfree(pr_ie);
kfree(ar_ie);
- kfree(rsn_ie);
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index b115e0f94dd7..b77ba743e1c4 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -152,6 +152,8 @@ int mwifiex_init_priv(struct mwifiex_private *priv)
priv->check_tdls_tx = false;
memcpy(priv->tos_to_tid_inv, tos_to_tid_inv, MAX_NUM_TID);
+ mwifiex_init_11h_params(priv);
+
return mwifiex_add_bss_prio_tbl(priv);
}
@@ -294,9 +296,13 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
adapter->arp_filter_size = 0;
adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
- adapter->ext_scan = true;
+ adapter->ext_scan = false;
adapter->key_api_major_ver = 0;
adapter->key_api_minor_ver = 0;
+ memset(adapter->perm_addr, 0xff, ETH_ALEN);
+ adapter->iface_limit.sta_intf = MWIFIEX_MAX_STA_NUM;
+ adapter->iface_limit.uap_intf = MWIFIEX_MAX_UAP_NUM;
+ adapter->iface_limit.p2p_intf = MWIFIEX_MAX_P2P_NUM;
setup_timer(&adapter->wakeup_timer, wakeup_timer_fn,
(unsigned long)adapter);
@@ -551,7 +557,8 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter)
for (i = 0; i < adapter->priv_num; i++) {
if (adapter->priv[i]) {
- ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta);
+ ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta,
+ true);
if (ret == -1)
return -1;
@@ -676,6 +683,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
priv = adapter->priv[i];
mwifiex_clean_auto_tdls(priv);
+ mwifiex_abort_cac(priv);
mwifiex_clean_txrx(priv);
mwifiex_delete_bss_prio_tbl(priv);
}
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index d235adb82c94..7e74b4fccddd 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -562,7 +562,8 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
static int
mwifiex_open(struct net_device *dev)
{
- netif_tx_start_all_queues(dev);
+ netif_carrier_off(dev);
+
return 0;
}
@@ -960,21 +961,21 @@ static const struct net_device_ops mwifiex_netdev_ops = {
* In addition, the CFG80211 work queue is also created.
*/
void mwifiex_init_priv_params(struct mwifiex_private *priv,
- struct net_device *dev)
+ struct net_device *dev)
{
dev->netdev_ops = &mwifiex_netdev_ops;
dev->destructor = free_netdev;
/* Initialize private structure */
priv->current_key_index = 0;
priv->media_connected = false;
- memset(&priv->nick_name, 0, sizeof(priv->nick_name));
memset(priv->mgmt_ie, 0,
sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX);
priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK;
priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK;
priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK;
- priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK;
+ priv->gen_idx = MWIFIEX_AUTO_IDX_MASK;
priv->num_tx_timeout = 0;
+ ether_addr_copy(priv->curr_addr, priv->adapter->perm_addr);
memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA ||
@@ -1203,8 +1204,9 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
continue;
rtnl_lock();
- if (priv->wdev && priv->netdev)
- mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev);
+ if (priv->netdev &&
+ priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED)
+ mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev);
rtnl_unlock();
}
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 55273eefb785..f0a6af179af0 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -547,13 +547,12 @@ struct mwifiex_private {
u32 curr_bcn_size;
/* spin lock for beacon buffer */
spinlock_t curr_bcn_buf_lock;
- struct wireless_dev *wdev;
+ struct wireless_dev wdev;
struct mwifiex_chan_freq_power cfp;
char version_str[128];
#ifdef CONFIG_DEBUG_FS
struct dentry *dfs_dev_dir;
#endif
- u8 nick_name[16];
u16 current_key_index;
struct semaphore async_sem;
struct cfg80211_scan_request *scan_request;
@@ -568,7 +567,7 @@ struct mwifiex_private {
u16 beacon_idx;
u16 proberesp_idx;
u16 assocresp_idx;
- u16 rsn_idx;
+ u16 gen_idx;
u8 ap_11n_enabled;
u8 ap_11ac_enabled;
u32 mgmt_frame_mask;
@@ -578,6 +577,7 @@ struct mwifiex_private {
unsigned long csa_expire_time;
u8 del_list_idx;
bool hs2_enabled;
+ struct mwifiex_uap_bss_param bss_cfg;
struct station_parameters *sta_params;
struct sk_buff_head tdls_txq;
u8 check_tdls_tx;
@@ -588,6 +588,14 @@ struct mwifiex_private {
spinlock_t ack_status_lock;
/** rx histogram data */
struct mwifiex_histogram_data *hist_data;
+ struct cfg80211_chan_def dfs_chandef;
+ struct workqueue_struct *dfs_cac_workqueue;
+ struct delayed_work dfs_cac_work;
+ struct timer_list dfs_chan_switch_timer;
+ struct workqueue_struct *dfs_chan_sw_workqueue;
+ struct delayed_work dfs_chan_sw_work;
+ struct cfg80211_beacon_data beacon_after;
+ struct mwifiex_11h_intf_state state_11h;
};
enum mwifiex_ba_status {
@@ -731,6 +739,8 @@ struct mwifiex_if_ops {
struct mwifiex_adapter {
u8 iface_type;
+ struct mwifiex_iface_comb iface_limit;
+ struct mwifiex_iface_comb curr_iface_comb;
struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
u8 priv_num;
const struct firmware *firmware;
@@ -738,6 +748,7 @@ struct mwifiex_adapter {
int winner;
struct device *dev;
struct wiphy *wiphy;
+ u8 perm_addr[ETH_ALEN];
bool surprise_removed;
u32 fw_release_number;
u16 init_wait_q_woken;
@@ -751,6 +762,8 @@ struct mwifiex_adapter {
struct work_struct main_work;
struct workqueue_struct *rx_workqueue;
struct work_struct rx_work;
+ struct workqueue_struct *dfs_workqueue;
+ struct work_struct dfs_work;
bool rx_work_enabled;
bool rx_processing;
bool delay_main_work;
@@ -989,7 +1002,7 @@ void mwifiex_wmm_del_peer_ra_list(struct mwifiex_private *priv,
const u8 *ra_addr);
void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb);
void *mwifiex_process_uap_txpd(struct mwifiex_private *, struct sk_buff *skb);
-int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta);
+int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta, bool init);
int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
struct mwifiex_scan_cmd_config *scan_cfg);
void mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
@@ -1150,6 +1163,25 @@ mwifiex_get_priv(struct mwifiex_adapter *adapter,
}
/*
+ * This function returns the first available unused private structure pointer.
+ */
+static inline struct mwifiex_private *
+mwifiex_get_unused_priv(struct mwifiex_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ if (adapter->priv[i]->bss_mode ==
+ NL80211_IFTYPE_UNSPECIFIED)
+ break;
+ }
+ }
+
+ return ((i < adapter->priv_num) ? adapter->priv[i] : NULL);
+}
+
+/*
* This function returns the driver private structure of a network device.
*/
static inline struct mwifiex_private *
@@ -1240,8 +1272,6 @@ int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
struct ieee80211_channel *chan,
unsigned int duration);
-int mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role);
-
int mwifiex_get_stats_info(struct mwifiex_private *priv,
struct mwifiex_ds_get_stats *log);
@@ -1301,9 +1331,17 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
struct cfg80211_beacon_data *data);
int mwifiex_del_mgmt_ies(struct mwifiex_private *priv);
u8 *mwifiex_11d_code_2_region(u8 code);
+void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_chan_def chandef);
+int mwifiex_config_start_uap(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg);
void mwifiex_uap_del_sta_data(struct mwifiex_private *priv,
struct mwifiex_sta_node *node);
+void mwifiex_init_11h_params(struct mwifiex_private *priv);
+int mwifiex_is_11h_active(struct mwifiex_private *priv);
+int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag);
+
void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
struct mwifiex_bssdescriptor *bss_desc);
int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv);
@@ -1352,6 +1390,11 @@ void mwifiex_check_auto_tdls(unsigned long context);
void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac);
void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv);
void mwifiex_clean_auto_tdls(struct mwifiex_private *priv);
+int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ void *data_buf);
+int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv,
+ struct sk_buff *skb);
void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
void *event_body);
@@ -1359,6 +1402,11 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
struct sk_buff *
mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
struct sk_buff *skb, u8 flag, u64 *cookie);
+void mwifiex_dfs_cac_work_queue(struct work_struct *work);
+void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work);
+void mwifiex_abort_cac(struct mwifiex_private *priv);
+int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
+ struct sk_buff *skb);
void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr,
s8 nflr);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index a460b0e6a151..a5828da59365 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -204,6 +204,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
card->pcie.blksz_fw_dl = data->blksz_fw_dl;
card->pcie.tx_buf_size = data->tx_buf_size;
card->pcie.supports_fw_dump = data->supports_fw_dump;
+ card->pcie.can_ext_scan = data->can_ext_scan;
}
if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
@@ -2563,6 +2564,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
adapter->mem_type_mapping_tbl = mem_type_mapping_tbl;
adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl);
strcpy(adapter->fw_name, card->pcie.firmware);
+ adapter->ext_scan = card->pcie.can_ext_scan;
return 0;
}
diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h
index 200e8b0cb582..666d40e9dbc3 100644
--- a/drivers/net/wireless/mwifiex/pcie.h
+++ b/drivers/net/wireless/mwifiex/pcie.h
@@ -206,6 +206,7 @@ struct mwifiex_pcie_device {
u16 blksz_fw_dl;
u16 tx_buf_size;
bool supports_fw_dump;
+ bool can_ext_scan;
};
static const struct mwifiex_pcie_device mwifiex_pcie8766 = {
@@ -214,6 +215,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8766 = {
.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
.tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
.supports_fw_dump = false,
+ .can_ext_scan = true,
};
static const struct mwifiex_pcie_device mwifiex_pcie8897 = {
@@ -222,6 +224,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8897 = {
.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
.tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
.supports_fw_dump = true,
+ .can_ext_scan = true,
};
struct mwifiex_evt_buf_desc {
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 984a7a4fa93b..0ffdb7c5afd2 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -496,10 +496,10 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) {
- if (!priv->wdev->wiphy->bands[band])
+ if (!priv->wdev.wiphy->bands[band])
continue;
- sband = priv->wdev->wiphy->bands[band];
+ sband = priv->wdev.wiphy->bands[band];
for (i = 0; (i < sband->n_channels) ; i++) {
ch = &sband->channels[i];
@@ -1429,6 +1429,12 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
return -EBUSY;
}
+ if (adapter->surprise_removed || adapter->is_cmd_timedout) {
+ dev_err(adapter->dev,
+ "Ignore scan. Card removed or firmware in bad state\n");
+ return -EFAULT;
+ }
+
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->scan_processing = true;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
@@ -1727,10 +1733,10 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
freq = cfp ? cfp->freq : 0;
- chan = ieee80211_get_channel(priv->wdev->wiphy, freq);
+ chan = ieee80211_get_channel(priv->wdev.wiphy, freq);
if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
- bss = cfg80211_inform_bss(priv->wdev->wiphy,
+ bss = cfg80211_inform_bss(priv->wdev.wiphy,
chan, CFG80211_BSS_FTYPE_UNKNOWN,
bssid, timestamp,
cap_info_bitmap, beacon_period,
@@ -1742,7 +1748,7 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
!memcmp(bssid, priv->curr_bss_params.bss_descriptor
.mac_address, ETH_ALEN))
mwifiex_update_curr_bss_params(priv, bss);
- cfg80211_put_bss(priv->wdev->wiphy, bss);
+ cfg80211_put_bss(priv->wdev.wiphy, bss);
}
} else {
dev_dbg(adapter->dev, "missing BSS channel IE\n");
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index a70f103359ea..91e36cda9543 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -107,6 +107,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size;
card->supports_fw_dump = data->supports_fw_dump;
card->auto_tdls = data->auto_tdls;
+ card->can_ext_scan = data->can_ext_scan;
}
sdio_claim_host(func);
@@ -282,6 +283,9 @@ static int mwifiex_sdio_suspend(struct device *dev)
#define SDIO_DEVICE_ID_MARVELL_8897 (0x912d)
/* Device ID for SD8887 */
#define SDIO_DEVICE_ID_MARVELL_8887 (0x9135)
+/* Device ID for SD8801 */
+#define SDIO_DEVICE_ID_MARVELL_8801 (0x9139)
+
/* WLAN IDs */
static const struct sdio_device_id mwifiex_ids[] = {
@@ -295,6 +299,8 @@ static const struct sdio_device_id mwifiex_ids[] = {
.driver_data = (unsigned long) &mwifiex_sdio_sd8897},
{SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887),
.driver_data = (unsigned long)&mwifiex_sdio_sd8887},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8801),
+ .driver_data = (unsigned long)&mwifiex_sdio_sd8801},
{},
};
@@ -1882,6 +1888,7 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
}
adapter->auto_tdls = card->auto_tdls;
+ adapter->ext_scan = card->can_ext_scan;
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
index 895eea054c9e..957cca246618 100644
--- a/drivers/net/wireless/mwifiex/sdio.h
+++ b/drivers/net/wireless/mwifiex/sdio.h
@@ -34,6 +34,7 @@
#define SD8797_DEFAULT_FW_NAME "mrvl/sd8797_uapsta.bin"
#define SD8897_DEFAULT_FW_NAME "mrvl/sd8897_uapsta.bin"
#define SD8887_DEFAULT_FW_NAME "mrvl/sd8887_uapsta.bin"
+#define SD8801_DEFAULT_FW_NAME "mrvl/sd8801_uapsta.bin"
#define BLOCK_MODE 1
#define BYTE_MODE 0
@@ -255,6 +256,7 @@ struct sdio_mmc_card {
u8 *mp_regs;
u8 auto_tdls;
+ bool can_ext_scan;
struct mwifiex_sdio_mpa_tx mpa_tx;
struct mwifiex_sdio_mpa_rx mpa_rx;
@@ -272,6 +274,7 @@ struct mwifiex_sdio_device {
u32 mp_tx_agg_buf_size;
u32 mp_rx_agg_buf_size;
u8 auto_tdls;
+ bool can_ext_scan;
};
static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = {
@@ -416,6 +419,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = {
.mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
.supports_fw_dump = false,
.auto_tdls = false,
+ .can_ext_scan = false,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
@@ -430,6 +434,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
.mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
.supports_fw_dump = false,
.auto_tdls = false,
+ .can_ext_scan = true,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
@@ -444,6 +449,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
.mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
.supports_fw_dump = false,
.auto_tdls = false,
+ .can_ext_scan = true,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
@@ -458,6 +464,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
.mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K,
.supports_fw_dump = true,
.auto_tdls = false,
+ .can_ext_scan = true,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = {
@@ -472,6 +479,22 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = {
.mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K,
.supports_fw_dump = false,
.auto_tdls = true,
+ .can_ext_scan = true,
+};
+
+static const struct mwifiex_sdio_device mwifiex_sdio_sd8801 = {
+ .firmware = SD8801_DEFAULT_FW_NAME,
+ .reg = &mwifiex_reg_sd87xx,
+ .max_ports = 16,
+ .mp_agg_pkt_limit = 8,
+ .supports_sdio_new_mode = false,
+ .has_control_mask = true,
+ .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
+ .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
+ .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
+ .supports_fw_dump = false,
+ .auto_tdls = false,
+ .can_ext_scan = true,
};
/*
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index f7b920d7a95a..f7d204ffd6e9 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -1897,6 +1897,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
case HostCmd_CMD_TDLS_OPER:
ret = mwifiex_cmd_tdls_oper(priv, cmd_ptr, data_buf);
break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr,
+ data_buf);
+ break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd- %#x\n", cmd_no);
@@ -1911,6 +1915,8 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
*
* This is called after firmware download to bring the card to
* working state.
+ * Function is also called during reinitialization of virtual
+ * interfaces.
*
* The following commands are issued sequentially -
* - Set PCI-Express host buffer configuration (PCIE only)
@@ -1925,7 +1931,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
* - Set 11d control
* - Set MAC control (this must be the last command to initialize firmware)
*/
-int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
+int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
{
struct mwifiex_adapter *adapter = priv->adapter;
int ret;
@@ -2059,9 +2065,6 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
"11D: failed to enable 11D\n");
}
- /* set last_init_cmd before sending the command */
- priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG;
-
/* Send cmd to FW to configure 11n specific configuration
* (Short GI, Channel BW, Green field support etc.) for transmit
*/
@@ -2069,7 +2072,11 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_CFG,
HostCmd_ACT_GEN_SET, 0, &tx_cfg, true);
- ret = -EINPROGRESS;
+ if (init) {
+ /* set last_init_cmd before sending the command */
+ priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG;
+ ret = -EINPROGRESS;
+ }
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 65d10a33eab5..5f8da5924666 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -1105,6 +1105,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_UAP_SYS_CONFIG:
break;
case HostCmd_CMD_UAP_BSS_START:
+ adapter->tx_lock_flag = false;
+ adapter->pps_uapsd_mode = false;
+ adapter->delay_null_pkt = false;
priv->bss_started = 1;
break;
case HostCmd_CMD_UAP_BSS_STOP:
@@ -1119,6 +1122,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_TDLS_OPER:
ret = mwifiex_ret_tdls_oper(priv, resp);
break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ break;
default:
dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
resp->command);
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 419e35f1dbf3..80ffe7412496 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -312,8 +312,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
adapter->ps_state = PS_STATE_AWAKE;
adapter->pm_wakeup_card_req = false;
adapter->pm_wakeup_fw_try = false;
- mod_timer(&adapter->wakeup_timer,
- jiffies + (HZ*3));
+ del_timer_sync(&adapter->wakeup_timer);
break;
}
if (!mwifiex_send_null_packet
@@ -487,7 +486,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
case EVENT_REMAIN_ON_CHAN_EXPIRED:
dev_dbg(adapter->dev, "event: Remain on channel expired\n");
- cfg80211_remain_on_channel_expired(priv->wdev,
+ cfg80211_remain_on_channel_expired(&priv->wdev,
priv->roc_cfg.cookie,
&priv->roc_cfg.chan,
GFP_ATOMIC);
@@ -516,6 +515,16 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
mwifiex_parse_tx_status_event(priv, adapter->event_body);
break;
+ case EVENT_CHANNEL_REPORT_RDY:
+ dev_dbg(adapter->dev, "event: Channel Report\n");
+ ret = mwifiex_11h_handle_chanrpt_ready(priv,
+ adapter->event_skb);
+ break;
+ case EVENT_RADAR_DETECTED:
+ dev_dbg(adapter->dev, "event: Radar detected\n");
+ ret = mwifiex_11h_handle_radar_detected(priv,
+ adapter->event_skb);
+ break;
default:
dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
eventcause);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index fb9c5fc83e5d..0599e41e253c 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -219,7 +219,7 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) {
rcu_read_unlock();
- wiphy_dbg(priv->wdev->wiphy,
+ wiphy_dbg(priv->wdev.wiphy,
"11D: skip setting domain info in FW\n");
return 0;
}
@@ -1135,36 +1135,6 @@ mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
return roc_cfg.status;
}
-int
-mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role)
-{
- if (GET_BSS_ROLE(priv) == bss_role) {
- dev_dbg(priv->adapter->dev,
- "info: already in the desired role.\n");
- return 0;
- }
-
- mwifiex_free_priv(priv);
- mwifiex_init_priv(priv);
-
- priv->bss_role = bss_role;
- switch (bss_role) {
- case MWIFIEX_BSS_ROLE_UAP:
- priv->bss_mode = NL80211_IFTYPE_AP;
- break;
- case MWIFIEX_BSS_ROLE_STA:
- case MWIFIEX_BSS_ROLE_ANY:
- default:
- priv->bss_mode = NL80211_IFTYPE_STATION;
- break;
- }
-
- mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
- HostCmd_ACT_GEN_SET, 0, NULL, true);
-
- return mwifiex_sta_init_cmd(priv, false);
-}
-
/*
* Sends IOCTL request to get statistics information.
*
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
index 1debe76017b1..5ce2d9a4f919 100644
--- a/drivers/net/wireless/mwifiex/sta_tx.c
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -183,9 +183,13 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
}
switch (ret) {
case -EBUSY:
- adapter->data_sent = true;
- /* Fall through FAILURE handling */
+ dev_kfree_skb_any(skb);
+ dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n",
+ __func__, ret);
+ adapter->dbg.num_tx_host_to_card_failure++;
+ break;
case -1:
+ adapter->data_sent = false;
dev_kfree_skb_any(skb);
dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n",
__func__, ret);
@@ -198,6 +202,7 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
adapter->tx_lock_flag = true;
break;
case -EINPROGRESS:
+ adapter->tx_lock_flag = true;
break;
default:
break;
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index 6ae133333363..ac93557cbdc9 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -227,7 +227,7 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
/* consumes ack_skb */
skb_complete_wifi_ack(ack_skb, !tx_status->status);
} else {
- cfg80211_mgmt_tx_status(priv->wdev, tx_info->cookie,
+ cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie,
ack_skb->data, ack_skb->len,
!tx_status->status, GFP_ATOMIC);
dev_kfree_skb_any(ack_skb);
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
index 0f347fdefa0a..f5c2af01ba0a 100644
--- a/drivers/net/wireless/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -761,6 +761,11 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
if (mwifiex_cmd_uap_sta_deauth(priv, cmd, data_buf))
return -1;
break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ if (mwifiex_cmd_issue_chan_report_request(priv, cmd_buf,
+ data_buf))
+ return -1;
+ break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd %#x\n", cmd_no);
@@ -769,3 +774,68 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
return 0;
}
+
+void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_chan_def chandef)
+{
+ u8 config_bands = 0;
+
+ bss_cfg->channel = ieee80211_frequency_to_channel(
+ chandef.chan->center_freq);
+
+ /* Set appropriate bands */
+ if (chandef.chan->band == IEEE80211_BAND_2GHZ) {
+ bss_cfg->band_cfg = BAND_CONFIG_BG;
+ config_bands = BAND_B | BAND_G;
+
+ if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
+ config_bands |= BAND_GN;
+ } else {
+ bss_cfg->band_cfg = BAND_CONFIG_A;
+ config_bands = BAND_A;
+
+ if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
+ config_bands |= BAND_AN;
+
+ if (chandef.width > NL80211_CHAN_WIDTH_40)
+ config_bands |= BAND_AAC;
+ }
+}
+
+int mwifiex_config_start_uap(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg)
+{
+ if (mwifiex_del_mgmt_ies(priv))
+ dev_err(priv->adapter->dev, "Failed to delete mgmt IEs!\n");
+
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, NULL, true)) {
+ dev_err(priv->adapter->dev, "Failed to stop the BSS\n");
+ return -1;
+ }
+
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
+ HostCmd_ACT_GEN_SET,
+ UAP_BSS_PARAMS_I, bss_cfg, false)) {
+ dev_err(priv->adapter->dev, "Failed to set the SSID\n");
+ return -1;
+ }
+
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
+ HostCmd_ACT_GEN_SET, 0, NULL, false)) {
+ dev_err(priv->adapter->dev, "Failed to start the BSS\n");
+ return -1;
+ }
+
+ if (priv->sec_info.wep_enabled)
+ priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
+ else
+ priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
+
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->curr_pkt_filter, true))
+ return -1;
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c
index f31086cdf937..f4794cdc36d2 100644
--- a/drivers/net/wireless/mwifiex/uap_event.c
+++ b/drivers/net/wireless/mwifiex/uap_event.c
@@ -68,7 +68,6 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
len = ETH_ALEN;
if (len != -1) {
- sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
sinfo.assoc_req_ies = &event->data[len];
len = (u8 *)sinfo.assoc_req_ies -
(u8 *)&event->frame_control;
@@ -179,6 +178,53 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
dev_dbg(adapter->dev, "event: TX_STATUS Report\n");
mwifiex_parse_tx_status_event(priv, adapter->event_body);
break;
+ case EVENT_PS_SLEEP:
+ dev_dbg(adapter->dev, "info: EVENT: SLEEP\n");
+
+ adapter->ps_state = PS_STATE_PRE_SLEEP;
+
+ mwifiex_check_ps_cond(adapter);
+ break;
+
+ case EVENT_PS_AWAKE:
+ dev_dbg(adapter->dev, "info: EVENT: AWAKE\n");
+ if (!adapter->pps_uapsd_mode &&
+ priv->media_connected && adapter->sleep_period.period) {
+ adapter->pps_uapsd_mode = true;
+ dev_dbg(adapter->dev,
+ "event: PPS/UAPSD mode activated\n");
+ }
+ adapter->tx_lock_flag = false;
+ if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
+ if (mwifiex_check_last_packet_indication(priv)) {
+ if (adapter->data_sent) {
+ adapter->ps_state = PS_STATE_AWAKE;
+ adapter->pm_wakeup_card_req = false;
+ adapter->pm_wakeup_fw_try = false;
+ break;
+ }
+ if (!mwifiex_send_null_packet
+ (priv,
+ MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET |
+ MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET))
+ adapter->ps_state =
+ PS_STATE_SLEEP;
+ return 0;
+ }
+ }
+ adapter->ps_state = PS_STATE_AWAKE;
+ adapter->pm_wakeup_card_req = false;
+ adapter->pm_wakeup_fw_try = false;
+ break;
+
+ case EVENT_CHANNEL_REPORT_RDY:
+ dev_dbg(adapter->dev, "event: Channel Report\n");
+ mwifiex_11h_handle_chanrpt_ready(priv, adapter->event_skb);
+ break;
+ case EVENT_RADAR_DETECTED:
+ dev_dbg(adapter->dev, "event: Radar detected\n");
+ mwifiex_11h_handle_radar_detected(priv, adapter->event_skb);
+ break;
default:
dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
eventcause);
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c
index 6c62995028e6..223873022ffe 100644
--- a/drivers/net/wireless/mwifiex/usb.c
+++ b/drivers/net/wireless/mwifiex/usb.c
@@ -37,6 +37,11 @@ static struct usb_device_id mwifiex_usb_table[] = {
{USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8797_PID_2,
USB_CLASS_VENDOR_SPEC,
USB_SUBCLASS_VENDOR_SPEC, 0xff)},
+ /* 8801 */
+ {USB_DEVICE(USB8XXX_VID, USB8801_PID_1)},
+ {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8801_PID_2,
+ USB_CLASS_VENDOR_SPEC,
+ USB_SUBCLASS_VENDOR_SPEC, 0xff)},
/* 8897 */
{USB_DEVICE(USB8XXX_VID, USB8897_PID_1)},
{USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8897_PID_2,
@@ -361,11 +366,13 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
switch (id_product) {
case USB8766_PID_1:
case USB8797_PID_1:
+ case USB8801_PID_1:
case USB8897_PID_1:
card->usb_boot_state = USB8XXX_FW_DNLD;
break;
case USB8766_PID_2:
case USB8797_PID_2:
+ case USB8801_PID_2:
case USB8897_PID_2:
card->usb_boot_state = USB8XXX_FW_READY;
break;
@@ -792,11 +799,19 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
case USB8897_PID_2:
adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
strcpy(adapter->fw_name, USB8897_DEFAULT_FW_NAME);
+ adapter->ext_scan = true;
break;
case USB8766_PID_1:
case USB8766_PID_2:
adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
strcpy(adapter->fw_name, USB8766_DEFAULT_FW_NAME);
+ adapter->ext_scan = true;
+ break;
+ case USB8801_PID_1:
+ case USB8801_PID_2:
+ adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
+ strcpy(adapter->fw_name, USB8801_DEFAULT_FW_NAME);
+ adapter->ext_scan = false;
break;
case USB8797_PID_1:
case USB8797_PID_2:
@@ -1083,4 +1098,5 @@ MODULE_VERSION(USB_VERSION);
MODULE_LICENSE("GPL v2");
MODULE_FIRMWARE(USB8766_DEFAULT_FW_NAME);
MODULE_FIRMWARE(USB8797_DEFAULT_FW_NAME);
+MODULE_FIRMWARE(USB8801_DEFAULT_FW_NAME);
MODULE_FIRMWARE(USB8897_DEFAULT_FW_NAME);
diff --git a/drivers/net/wireless/mwifiex/usb.h b/drivers/net/wireless/mwifiex/usb.h
index 0ad1bebc3f93..57e1a5736318 100644
--- a/drivers/net/wireless/mwifiex/usb.h
+++ b/drivers/net/wireless/mwifiex/usb.h
@@ -30,6 +30,9 @@
#define USB8797_PID_2 0x2044
#define USB8897_PID_1 0x2045
#define USB8897_PID_2 0x2046
+#define USB8801_PID_1 0x2049
+#define USB8801_PID_2 0x204a
+
#define USB8XXX_FW_DNLD 1
#define USB8XXX_FW_READY 2
@@ -41,6 +44,7 @@
#define USB8766_DEFAULT_FW_NAME "mrvl/usb8766_uapsta.bin"
#define USB8797_DEFAULT_FW_NAME "mrvl/usb8797_uapsta.bin"
+#define USB8801_DEFAULT_FW_NAME "mrvl/usb8801_uapsta.bin"
#define USB8897_DEFAULT_FW_NAME "mrvl/usb8897_uapsta.bin"
#define FW_DNLD_TX_BUF_SIZE 620
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index 707319799942..308550611f22 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -387,7 +387,7 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
pkt_len -= ETH_ALEN + sizeof(pkt_len);
rx_pd->rx_pkt_length = cpu_to_le16(pkt_len);
- cfg80211_rx_mgmt(priv->wdev, priv->roc_cfg.chan.center_freq,
+ cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq,
CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len,
0);
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index ffffd2c5a76e..ef717acec8b7 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -1228,6 +1228,9 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
case -EINPROGRESS:
if (adapter->iface_type != MWIFIEX_PCIE)
adapter->data_sent = false;
+ break;
+ case 0:
+ mwifiex_write_data_complete(adapter, skb, 0, ret);
default:
break;
}
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index b8d1e04aa9b9..f9b1218c761a 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -3098,14 +3098,14 @@ static void mwl8k_update_survey(struct mwl8k_priv *priv,
cca_cnt = ioread32(priv->regs + NOK_CCA_CNT_REG);
cca_cnt /= 1000; /* uSecs to mSecs */
- survey->channel_time_busy = (u64) cca_cnt;
+ survey->time_busy = (u64) cca_cnt;
rx_rdy = ioread32(priv->regs + BBU_RXRDY_CNT_REG);
rx_rdy /= 1000; /* uSecs to mSecs */
- survey->channel_time_rx = (u64) rx_rdy;
+ survey->time_rx = (u64) rx_rdy;
priv->channel_time = jiffies - priv->channel_time;
- survey->channel_time = jiffies_to_msecs(priv->channel_time);
+ survey->time = jiffies_to_msecs(priv->channel_time);
survey->channel = channel;
@@ -3115,9 +3115,9 @@ static void mwl8k_update_survey(struct mwl8k_priv *priv,
survey->noise = nf * -1;
survey->filled = SURVEY_INFO_NOISE_DBM |
- SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_BUSY |
- SURVEY_INFO_CHANNEL_TIME_RX;
+ SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY |
+ SURVEY_INFO_TIME_RX;
}
/*
diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig
index 60698b020851..6d831d4d1b5f 100644
--- a/drivers/net/wireless/orinoco/Kconfig
+++ b/drivers/net/wireless/orinoco/Kconfig
@@ -1,7 +1,8 @@
config HERMES
tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
depends on (PPC_PMAC || PCI || PCMCIA)
- depends on CFG80211 && CFG80211_WEXT
+ depends on CFG80211
+ select CFG80211_WEXT
select WIRELESS_EXT
select WEXT_SPY
select WEXT_PRIV
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 38ec8d19ac29..c410180479e6 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -2342,7 +2342,7 @@ void free_orinocodev(struct orinoco_private *priv)
list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) {
list_del(&sd->list);
- if ((sd->len > 0) && sd->buf)
+ if (sd->len > 0)
kfree(sd->buf);
kfree(sd);
}
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c
index b6bdad632842..74219d59d7e1 100644
--- a/drivers/net/wireless/orinoco/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco/orinoco_pci.c
@@ -94,7 +94,7 @@ static int orinoco_pci_cor_reset(struct orinoco_private *priv)
mdelay(HERMES_PCI_COR_OFFT);
/* The card is ready when it's no longer busy */
- timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000);
+ timeout = jiffies + msecs_to_jiffies(HERMES_PCI_COR_BUSYT);
reg = hermes_read_regn(hw, CMD);
while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
mdelay(1);
diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c
index b8f6e5c431ae..8b045236b6e0 100644
--- a/drivers/net/wireless/orinoco/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco/orinoco_plx.c
@@ -121,7 +121,7 @@ static int orinoco_plx_cor_reset(struct orinoco_private *priv)
mdelay(1);
/* Just in case, wait more until the card is no longer busy */
- timeout = jiffies + (PLX_RESET_TIME * HZ / 1000);
+ timeout = jiffies + msecs_to_jiffies(PLX_RESET_TIME);
reg = hermes_read_regn(hw, CMD);
while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
mdelay(1);
diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c
index 79d0e33b625e..20ce569b8a43 100644
--- a/drivers/net/wireless/orinoco/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco/orinoco_tmd.c
@@ -71,7 +71,7 @@ static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
mdelay(1);
/* Just in case, wait more until the card is no longer busy */
- timeout = jiffies + (TMD_RESET_TIME * HZ / 1000);
+ timeout = jiffies + msecs_to_jiffies(TMD_RESET_TIME);
reg = hermes_read_regn(hw, CMD);
while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
mdelay(1);
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index 0fe67d2da208..2fe713eda7ad 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -196,9 +196,9 @@ static int p54_generate_band(struct ieee80211_hw *dev,
dest->max_power = chan->max_power;
priv->survey[*chan_num].channel = &tmp->channels[j];
priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
- SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_BUSY |
- SURVEY_INFO_CHANNEL_TIME_TX;
+ SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY |
+ SURVEY_INFO_TIME_TX;
dest->hw_value = (*chan_num);
j++;
(*chan_num)++;
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index bc065e8e348b..5367d510b22d 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -220,6 +220,7 @@ int p54_download_eeprom(struct p54_common *priv, void *buf,
struct sk_buff *skb;
size_t eeprom_hdr_size;
int ret = 0;
+ long timeout;
if (priv->fw_var >= 0x509)
eeprom_hdr_size = sizeof(*eeprom_hdr);
@@ -249,9 +250,11 @@ int p54_download_eeprom(struct p54_common *priv, void *buf,
p54_tx(priv, skb);
- if (!wait_for_completion_interruptible_timeout(
- &priv->eeprom_comp, HZ)) {
- wiphy_err(priv->hw->wiphy, "device does not respond!\n");
+ timeout = wait_for_completion_interruptible_timeout(
+ &priv->eeprom_comp, HZ);
+ if (timeout <= 0) {
+ wiphy_err(priv->hw->wiphy,
+ "device does not respond or signal received!\n");
ret = -EBUSY;
}
priv->eeprom = NULL;
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index 97aeff0edb84..b9250d75d253 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -305,9 +305,9 @@ static void p54_reset_stats(struct p54_common *priv)
struct survey_info *info = &priv->survey[chan->hw_value];
/* only reset channel statistics, don't touch .filled, etc. */
- info->channel_time = 0;
- info->channel_time_busy = 0;
- info->channel_time_tx = 0;
+ info->time = 0;
+ info->time_busy = 0;
+ info->time_tx = 0;
}
priv->update_stats = true;
@@ -575,6 +575,8 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
key->hw_key_idx = 0xff;
goto out_unlock;
}
+
+ key->flags |= IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
} else {
slot = key->hw_key_idx;
@@ -634,7 +636,7 @@ static int p54_get_survey(struct ieee80211_hw *dev, int idx,
if (in_use) {
/* test if the reported statistics are valid. */
- if (survey->channel_time != 0) {
+ if (survey->time != 0) {
survey->filled |= SURVEY_INFO_IN_USE;
} else {
/*
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index d4aee64fb5ea..27a49068d32d 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -431,6 +431,7 @@ static int p54p_open(struct ieee80211_hw *dev)
{
struct p54p_priv *priv = dev->priv;
int err;
+ long timeout;
init_completion(&priv->boot_comp);
err = request_irq(priv->pdev->irq, p54p_interrupt,
@@ -468,10 +469,12 @@ static int p54p_open(struct ieee80211_hw *dev)
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
P54P_READ(dev_int);
- if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
+ timeout = wait_for_completion_interruptible_timeout(
+ &priv->boot_comp, HZ);
+ if (timeout <= 0) {
wiphy_err(dev->wiphy, "Cannot boot firmware!\n");
p54p_stop(dev);
- return -ETIMEDOUT;
+ return timeout ? -ERESTARTSYS : -ETIMEDOUT;
}
P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 153c61539ec8..24e5ff9a9272 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -587,13 +587,13 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
if (chan) {
struct survey_info *survey = &priv->survey[chan->hw_value];
survey->noise = clamp(priv->noise, -128, 127);
- survey->channel_time = priv->survey_raw.active;
- survey->channel_time_tx = priv->survey_raw.tx;
- survey->channel_time_busy = priv->survey_raw.tx +
+ survey->time = priv->survey_raw.active;
+ survey->time_tx = priv->survey_raw.tx;
+ survey->time_busy = priv->survey_raw.tx +
priv->survey_raw.cca;
- do_div(survey->channel_time, 1024);
- do_div(survey->channel_time_tx, 1024);
- do_div(survey->channel_time_busy, 1024);
+ do_div(survey->time, 1024);
+ do_div(survey->time_tx, 1024);
+ do_div(survey->time_busy, 1024);
}
tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 1a4facd1fbf3..60d44ce9c017 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2478,7 +2478,7 @@ static void rndis_fill_station_info(struct usbnet *usbdev,
ret = rndis_query_oid(usbdev, RNDIS_OID_GEN_LINK_SPEED, &linkspeed, &len);
if (ret == 0) {
sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000;
- sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
}
len = sizeof(rssi);
@@ -2486,7 +2486,7 @@ static void rndis_fill_station_info(struct usbnet *usbdev,
&rssi, &len);
if (ret == 0) {
sinfo->signal = level_to_qual(le32_to_cpu(rssi));
- sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
}
}
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 81ee481487cf..be2d54f257b1 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -8020,13 +8020,13 @@ int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &busy_ext);
if (idle || busy) {
- survey->filled = SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_BUSY |
- SURVEY_INFO_CHANNEL_TIME_EXT_BUSY;
+ survey->filled = SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY |
+ SURVEY_INFO_TIME_EXT_BUSY;
- survey->channel_time = (idle + busy) / 1000;
- survey->channel_time_busy = busy / 1000;
- survey->channel_time_ext_busy = busy_ext / 1000;
+ survey->time = (idle + busy) / 1000;
+ survey->time_busy = busy / 1000;
+ survey->time_ext_busy = busy_ext / 1000;
}
if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index eb203163ed05..a31a12775f1a 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -1010,6 +1010,16 @@ static int rtl_op_conf_tx(struct ieee80211_hw *hw,
return 0;
}
+static void send_beacon_frame(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
+
+ if (skb)
+ rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, NULL);
+}
+
static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -1040,6 +1050,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
if (rtlpriv->cfg->ops->linked_set_reg)
rtlpriv->cfg->ops->linked_set_reg(hw);
+ send_beacon_frame(hw, vif);
}
}
if ((changed & BSS_CHANGED_BEACON_ENABLED &&
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 846a2e6e34d8..88331d729b0e 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -578,6 +578,13 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
else
entry = (u8 *)(&ring->desc[ring->idx]);
+ if (rtlpriv->cfg->ops->get_available_desc &&
+ rtlpriv->cfg->ops->get_available_desc(hw, prio) <= 1) {
+ RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_DMESG,
+ "no available desc!\n");
+ return;
+ }
+
if (!rtlpriv->cfg->ops->is_tx_desc_closed(hw, prio, ring->idx))
return;
ring->idx = (ring->idx + 1) % ring->entries;
@@ -641,10 +648,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
ieee80211_tx_status_irqsafe(hw, skb);
- if ((ring->entries - skb_queue_len(&ring->queue))
- == 2) {
+ if ((ring->entries - skb_queue_len(&ring->queue)) <= 4) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
"more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%x\n",
prio, ring->idx,
skb_queue_len(&ring->queue));
@@ -786,7 +792,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
rx_remained_cnt =
rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw,
hw_queue);
- if (rx_remained_cnt < 1)
+ if (rx_remained_cnt == 0)
return;
} else { /* rx descriptor */
@@ -834,18 +840,18 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
else
skb_reserve(skb, stats.rx_drvinfo_size +
stats.rx_bufshift);
-
} else {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"skb->end - skb->tail = %d, len is %d\n",
skb->end - skb->tail, len);
- break;
+ dev_kfree_skb_any(skb);
+ goto new_trx_end;
}
/* handle command packet here */
if (rtlpriv->cfg->ops->rx_command_packet &&
rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
dev_kfree_skb_any(skb);
- goto end;
+ goto new_trx_end;
}
/*
@@ -895,6 +901,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
} else {
dev_kfree_skb_any(skb);
}
+new_trx_end:
if (rtlpriv->use_new_trx_flow) {
rtlpci->rx_ring[hw_queue].next_rx_rp += 1;
rtlpci->rx_ring[hw_queue].next_rx_rp %=
@@ -910,7 +917,6 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
rtlpriv->enter_ps = false;
schedule_work(&rtlpriv->works.lps_change_work);
}
-end:
if (rtlpriv->use_new_trx_flow) {
_rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc,
rxring_idx,
@@ -1672,6 +1678,15 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
}
}
+ if (rtlpriv->cfg->ops->get_available_desc &&
+ rtlpriv->cfg->ops->get_available_desc(hw, hw_queue) == 0) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "get_available_desc fail\n");
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
+ flags);
+ return skb->len;
+ }
+
if (ieee80211_is_data_qos(fc)) {
tid = rtl_get_tid(skb);
if (sta) {
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h
index 5e832306dba9..d4567d12e07e 100644
--- a/drivers/net/wireless/rtlwifi/pci.h
+++ b/drivers/net/wireless/rtlwifi/pci.h
@@ -325,4 +325,11 @@ static inline void pci_write32_async(struct rtl_priv *rtlpriv,
writel(val, (u8 __iomem *) rtlpriv->io.pci_mem_start + addr);
}
+static inline u16 calc_fifo_space(u16 rp, u16 wp)
+{
+ if (rp <= wp)
+ return RTL_PCI_MAX_RX_COUNT - 1 + rp - wp;
+ return rp - wp - 1;
+}
+
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index 551321728ae0..fe4b699a12f5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -1000,6 +1000,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
local_save_flags(flags);
local_irq_enable();
+ rtlhal->fw_ready = false;
rtlhal->hw_type = HARDWARE_TYPE_RTL8192CU;
err = _rtl92cu_init_mac(hw);
if (err) {
@@ -1013,6 +1014,8 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
err = 1;
goto exit;
}
+
+ rtlhal->fw_ready = true;
rtlhal->last_hmeboxnum = 0; /* h2c */
_rtl92cu_phy_param_tab_init(hw);
rtl92cu_phy_mac_config(hw);
@@ -1509,6 +1512,7 @@ void rtl92cu_set_beacon_related_registers(struct ieee80211_hw *hw)
/* TODO: Modify later (Find the right parameters)
* NOTE: Fix test chip's bug (about contention windows's randomness) */
if ((mac->opmode == NL80211_IFTYPE_ADHOC) ||
+ (mac->opmode == NL80211_IFTYPE_MESH_POINT) ||
(mac->opmode == NL80211_IFTYPE_AP)) {
rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x50);
rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x50);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
index 280c3da42993..01bcc2d218dc 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
@@ -546,7 +546,7 @@ static bool _rtl92de_llt_table_init(struct ieee80211_hw *hw)
txpktbuf_bndy = 246;
value8 = 0;
value32 = 0x80bf0d29;
- } else if (rtlpriv->rtlhal.macphymode != SINGLEMAC_SINGLEPHY) {
+ } else {
maxPage = 127;
txpktbuf_bndy = 123;
value8 = 0;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
index 45c128b91f7f..c5d4b8013cde 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
@@ -666,7 +666,6 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
struct sk_buff *skb = NULL;
u32 totalpacketlen;
- bool rtstatus;
u8 u1rsvdpageloc[5] = { 0 };
bool b_dlok = false;
@@ -728,10 +727,7 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
memcpy((u8 *)skb_put(skb, totalpacketlen),
&reserved_page_packet, totalpacketlen);
- rtstatus = rtl_cmd_send_packet(hw, skb);
-
- if (rtstatus)
- b_dlok = true;
+ b_dlok = true;
if (b_dlok) {
RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD ,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
index 1a87edca2c3f..b461b3128da5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
@@ -85,29 +85,6 @@ static void _rtl92ee_enable_bcn_sub_func(struct ieee80211_hw *hw)
_rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(1));
}
-static void _rtl92ee_return_beacon_queue_skb(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
- unsigned long flags;
-
- spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
- while (skb_queue_len(&ring->queue)) {
- struct rtl_tx_buffer_desc *entry =
- &ring->buffer_desc[ring->idx];
- struct sk_buff *skb = __skb_dequeue(&ring->queue);
-
- pci_unmap_single(rtlpci->pdev,
- rtlpriv->cfg->ops->get_desc(
- (u8 *)entry, true, HW_DESC_TXBUFF_ADDR),
- skb->len, PCI_DMA_TODEVICE);
- kfree_skb(skb);
- ring->idx = (ring->idx + 1) % ring->entries;
- }
- spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-}
-
static void _rtl92ee_disable_bcn_sub_func(struct ieee80211_hw *hw)
{
_rtl92ee_set_bcn_ctrl_reg(hw, BIT(1), 0);
@@ -403,9 +380,6 @@ static void _rtl92ee_download_rsvd_page(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, REG_DWBCN0_CTRL + 2,
bcnvalid_reg | BIT(0));
- /* Return Beacon TCB */
- _rtl92ee_return_beacon_queue_skb(hw);
-
/* download rsvd page */
rtl92ee_set_fw_rsvdpagepkt(hw, false);
@@ -1163,6 +1137,139 @@ void rtl92ee_enable_hw_security_config(struct ieee80211_hw *hw)
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
}
+static bool _rtl8192ee_check_pcie_dma_hang(struct rtl_priv *rtlpriv)
+{
+ u8 tmp;
+
+ /* write reg 0x350 Bit[26]=1. Enable debug port. */
+ tmp = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3);
+ if (!(tmp & BIT(2))) {
+ rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3,
+ tmp | BIT(2));
+ mdelay(100); /* Suggested by DD Justin_tsai. */
+ }
+
+ /* read reg 0x350 Bit[25] if 1 : RX hang
+ * read reg 0x350 Bit[24] if 1 : TX hang
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3);
+ if ((tmp & BIT(0)) || (tmp & BIT(1))) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "CheckPcieDMAHang8192EE(): true!!\n");
+ return true;
+ }
+ return false;
+}
+
+static void _rtl8192ee_reset_pcie_interface_dma(struct rtl_priv *rtlpriv,
+ bool mac_power_on)
+{
+ u8 tmp;
+ bool release_mac_rx_pause;
+ u8 backup_pcie_dma_pause;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "ResetPcieInterfaceDMA8192EE()\n");
+
+ /* Revise Note: Follow the document "PCIe RX DMA Hang Reset Flow_v03"
+ * released by SD1 Alan.
+ */
+
+ /* 1. disable register write lock
+ * write 0x1C bit[1:0] = 2'h0
+ * write 0xCC bit[2] = 1'b1
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL);
+ tmp &= ~(BIT(1) | BIT(0));
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL, tmp);
+ tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2);
+ tmp |= BIT(2);
+ rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp);
+
+ /* 2. Check and pause TRX DMA
+ * write 0x284 bit[18] = 1'b1
+ * write 0x301 = 0xFF
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+ if (tmp & BIT(2)) {
+ /* Already pause before the function for another reason. */
+ release_mac_rx_pause = false;
+ } else {
+ rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, (tmp | BIT(2)));
+ release_mac_rx_pause = true;
+ }
+
+ backup_pcie_dma_pause = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG + 1);
+ if (backup_pcie_dma_pause != 0xFF)
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xFF);
+
+ if (mac_power_on) {
+ /* 3. reset TRX function
+ * write 0x100 = 0x00
+ */
+ rtl_write_byte(rtlpriv, REG_CR, 0);
+ }
+
+ /* 4. Reset PCIe DMA
+ * write 0x003 bit[0] = 0
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ tmp &= ~(BIT(0));
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp);
+
+ /* 5. Enable PCIe DMA
+ * write 0x003 bit[0] = 1
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ tmp |= BIT(0);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp);
+
+ if (mac_power_on) {
+ /* 6. enable TRX function
+ * write 0x100 = 0xFF
+ */
+ rtl_write_byte(rtlpriv, REG_CR, 0xFF);
+
+ /* We should init LLT & RQPN and
+ * prepare Tx/Rx descrptor address later
+ * because MAC function is reset.
+ */
+ }
+
+ /* 7. Restore PCIe autoload down bit
+ * write 0xF8 bit[17] = 1'b1
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2);
+ tmp |= BIT(1);
+ rtl_write_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2, tmp);
+
+ /* In MAC power on state, BB and RF maybe in ON state,
+ * if we release TRx DMA here
+ * it will cause packets to be started to Tx/Rx,
+ * so we release Tx/Rx DMA later.
+ */
+ if (!mac_power_on) {
+ /* 8. release TRX DMA
+ * write 0x284 bit[18] = 1'b0
+ * write 0x301 = 0x00
+ */
+ if (release_mac_rx_pause) {
+ tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+ rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL,
+ (tmp & (~BIT(2))));
+ }
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1,
+ backup_pcie_dma_pause);
+ }
+
+ /* 9. lock system register
+ * write 0xCC bit[2] = 1'b0
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2);
+ tmp &= ~(BIT(2));
+ rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp);
+}
+
int rtl92ee_hw_init(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1188,6 +1295,13 @@ int rtl92ee_hw_init(struct ieee80211_hw *hw)
rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_92E;
}
+ if (_rtl8192ee_check_pcie_dma_hang(rtlpriv)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "92ee dma hang!\n");
+ _rtl8192ee_reset_pcie_interface_dma(rtlpriv,
+ rtlhal->mac_func_enable);
+ rtlhal->mac_func_enable = false;
+ }
+
rtstatus = _rtl92ee_init_mac(hw);
rtl_write_byte(rtlpriv, 0x577, 0x03);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h
index 3f2a9596e7cd..1eaa1fab550d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h
@@ -77,9 +77,11 @@
#define REG_HIMRE 0x00B8
#define REG_HISRE 0x00BC
+#define REG_PMC_DBG_CTRL2 0x00CC
#define REG_EFUSE_ACCESS 0x00CF
#define REG_HPON_FSM 0x00EC
#define REG_SYS_CFG1 0x00F0
+#define REG_MAC_PHY_CTRL_NORMAL 0x00F8
#define REG_SYS_CFG2 0x00FC
#define REG_CR 0x0100
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c
index 9b5a7d5be121..c31c6bfb536d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c
@@ -113,8 +113,6 @@ int rtl92ee_init_sw_vars(struct ieee80211_hw *hw)
RCR_HTC_LOC_CTRL |
RCR_AMF |
RCR_ACF |
- RCR_ADF |
- RCR_AICV |
RCR_ACRC32 |
RCR_AB |
RCR_AM |
@@ -241,6 +239,7 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = {
.set_desc = rtl92ee_set_desc,
.get_desc = rtl92ee_get_desc,
.is_tx_desc_closed = rtl92ee_is_tx_desc_closed,
+ .get_available_desc = rtl92ee_get_available_desc,
.tx_polling = rtl92ee_tx_polling,
.enable_hw_sec = rtl92ee_enable_hw_security_config,
.set_key = rtl92ee_set_key,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c
index 55d1da5e162b..d39ee67f6113 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c
@@ -354,6 +354,10 @@ bool rtl92ee_rx_query_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr;
u32 phystatus = GET_RX_DESC_PHYST(pdesc);
+ if (GET_RX_STATUS_DESC_RPT_SEL(pdesc) == 0)
+ status->packet_report_type = NORMAL_RX;
+ else
+ status->packet_report_type = C2H_PACKET;
status->length = (u16)GET_RX_DESC_PKT_LEN(pdesc);
status->rx_drvinfo_size = (u8)GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
RX_DRV_INFO_SIZE_UNIT;
@@ -495,14 +499,7 @@ u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, u8 queue_index)
if (!start_rx)
return 0;
- if ((last_read_point > (RX_DESC_NUM_92E / 2)) &&
- (read_point <= (RX_DESC_NUM_92E / 2))) {
- remind_cnt = RX_DESC_NUM_92E - write_point;
- } else {
- remind_cnt = (read_point >= write_point) ?
- (read_point - write_point) :
- (RX_DESC_NUM_92E - write_point + read_point);
- }
+ remind_cnt = calc_fifo_space(read_point, write_point);
if (remind_cnt == 0)
return 0;
@@ -551,6 +548,26 @@ static u16 get_desc_addr_fr_q_idx(u16 queue_index)
return desc_address;
}
+u16 rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 point_diff = 0;
+ u16 current_tx_read_point = 0, current_tx_write_point = 0;
+ u32 tmp_4byte;
+
+ tmp_4byte = rtl_read_dword(rtlpriv,
+ get_desc_addr_fr_q_idx(q_idx));
+ current_tx_read_point = (u16)((tmp_4byte >> 16) & 0x0fff);
+ current_tx_write_point = (u16)((tmp_4byte) & 0x0fff);
+
+ point_diff = calc_fifo_space(current_tx_read_point,
+ current_tx_write_point);
+
+ rtlpci->tx_ring[q_idx].avl_desc = point_diff;
+ return point_diff;
+}
+
void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw,
u8 *tx_bd_desc, u8 *desc, u8 queue_index,
struct sk_buff *skb, dma_addr_t addr)
@@ -1027,8 +1044,7 @@ bool rtl92ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index)
static u8 stop_report_cnt;
struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
- /*checking Read/Write Point each interrupt wastes CPU */
- if (stop_report_cnt > 15 || !rtlpriv->link_info.busytraffic) {
+ {
u16 point_diff = 0;
u16 cur_tx_rp, cur_tx_wp;
u32 tmpu32 = 0;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h
index 48504c25fffb..8f78ac9e6040 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h
@@ -542,6 +542,8 @@
LE_BITS_TO_4BYTE(__pdesc+8, 12, 4)
#define GET_RX_DESC_RX_IS_QOS(__pdesc) \
LE_BITS_TO_4BYTE(__pdesc+8, 16, 1)
+#define GET_RX_STATUS_DESC_RPT_SEL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 28, 1)
#define GET_RX_DESC_RXMCS(__pdesc) \
LE_BITS_TO_4BYTE(__pdesc+12, 0, 7)
@@ -829,6 +831,7 @@ void rtl92ee_rx_check_dma_ok(struct ieee80211_hw *hw, u8 *header_desc,
u8 queue_index);
u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw,
u8 queue_index);
+u16 rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 queue_index);
void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw,
u8 *tx_bd_desc, u8 *desc, u8 queue_index,
struct sk_buff *skb, dma_addr_t addr);
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index b53d9dd7a595..51572912c53d 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -2182,6 +2182,7 @@ struct rtl_hal_ops {
void (*add_wowlan_pattern)(struct ieee80211_hw *hw,
struct rtl_wow_pattern *rtl_pattern,
u8 index);
+ u16 (*get_available_desc)(struct ieee80211_hw *hw, u8 q_idx);
};
struct rtl_intf_ops {
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 0b30a7b4d663..d4ba009ac9aa 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -500,6 +500,7 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
int ret = 0;
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
+ IEEE80211_VIF_SUPPORTS_UAPSD |
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
@@ -1480,9 +1481,7 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
/* unit us */
/* FIXME: find a proper value */
- wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_UAPSD;
+ wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS;
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c
index b924ceadc02c..f28fa3b5029d 100644
--- a/drivers/net/wireless/ti/wlcore/acx.c
+++ b/drivers/net/wireless/ti/wlcore/acx.c
@@ -1725,7 +1725,7 @@ int wl12xx_acx_config_hangover(struct wl1271 *wl)
acx->decrease_delta = conf->decrease_delta;
acx->quiet_time = conf->quiet_time;
acx->increase_time = conf->increase_time;
- acx->window_size = acx->window_size;
+ acx->window_size = conf->window_size;
ret = wl1271_cmd_configure(wl, ACX_CONFIG_HANGOVER, acx,
sizeof(*acx));
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index e90fb781a6a1..1e136993580f 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -1785,8 +1785,10 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
mutex_lock(&wl->mutex);
ret = wl1271_ps_elp_wakeup(wl);
- if (ret < 0)
+ if (ret < 0) {
+ mutex_unlock(&wl->mutex);
return ret;
+ }
wl->wow_enabled = true;
wl12xx_for_each_wlvif(wl, wlvif) {
@@ -2552,6 +2554,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
}
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
+ IEEE80211_VIF_SUPPORTS_UAPSD |
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
@@ -5661,14 +5664,15 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
ieee80211_queue_work(hw, &wlvif->rc_update_work);
}
-static int wlcore_op_get_rssi(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- s8 *rssi_dbm)
+static void wlcore_op_sta_statistics(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct station_info *sinfo)
{
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
- int ret = 0;
+ s8 rssi_dbm;
+ int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi");
@@ -5681,17 +5685,18 @@ static int wlcore_op_get_rssi(struct ieee80211_hw *hw,
if (ret < 0)
goto out_sleep;
- ret = wlcore_acx_average_rssi(wl, wlvif, rssi_dbm);
+ ret = wlcore_acx_average_rssi(wl, wlvif, &rssi_dbm);
if (ret < 0)
goto out_sleep;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
+ sinfo->signal = rssi_dbm;
+
out_sleep:
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
-
- return ret;
}
static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
@@ -5893,7 +5898,7 @@ static const struct ieee80211_ops wl1271_ops = {
.unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx,
.switch_vif_chanctx = wlcore_op_switch_vif_chanctx,
.sta_rc_update = wlcore_op_sta_rc_update,
- .get_rssi = wlcore_op_get_rssi,
+ .sta_statistics = wlcore_op_sta_statistics,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
@@ -6064,7 +6069,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_SUPPORTS_UAPSD |
IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_CONNECTION_MONITOR |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 2fead3820849..1e180c400f17 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -90,25 +90,6 @@ found:
}
#endif /* CONFIG_SSB_PCMCIAHOST */
-#ifdef CONFIG_SSB_SDIOHOST
-struct ssb_bus *ssb_sdio_func_to_bus(struct sdio_func *func)
-{
- struct ssb_bus *bus;
-
- ssb_buses_lock();
- list_for_each_entry(bus, &buses, list) {
- if (bus->bustype == SSB_BUSTYPE_SDIO &&
- bus->host_sdio == func)
- goto found;
- }
- bus = NULL;
-found:
- ssb_buses_unlock();
-
- return bus;
-}
-#endif /* CONFIG_SSB_SDIOHOST */
-
int ssb_for_each_bus_call(unsigned long data,
int (*func)(struct ssb_bus *bus, unsigned long data))
{
diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
index 82a8c06ab347..c5800ae71fcf 100644
--- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
@@ -1091,17 +1091,17 @@ static int cfg80211_rtw_get_station(struct wiphy *wiphy,
goto exit;
}
- sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
sinfo->signal = translate_percentage_to_dbm(padapter->recvpriv.
signal_strength);
- sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
sinfo->txrate.legacy = rtw_get_cur_max_rate(padapter);
- sinfo->filled |= STATION_INFO_RX_PACKETS;
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
sinfo->rx_packets = sta_rx_data_pkts(psta);
- sinfo->filled |= STATION_INFO_TX_PACKETS;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
sinfo->tx_packets = psta->sta_stats.tx_pkts;
}
@@ -2363,7 +2363,7 @@ void rtw_cfg80211_indicate_sta_assoc(struct rtw_adapter *padapter,
ie_offset = offsetof(struct ieee80211_mgmt,
u.reassoc_req.variable);
- sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
+ sinfo.filled = 0;
sinfo.assoc_req_ies = pmgmt_frame + ie_offset;
sinfo.assoc_req_ies_len = frame_len - ie_offset;
cfg80211_new_sta(ndev, hdr->addr2, &sinfo, GFP_ATOMIC);
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 8942dcb44180..7c87aecf4744 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -325,9 +325,9 @@ static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
if (result == 0) {
sinfo->txrate.legacy = quality.txrate.data;
- sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
sinfo->signal = quality.level.data;
- sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
}
return result;
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index eb1c6a47b67f..994739da827f 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -318,6 +318,7 @@ struct bcma_bus {
const struct bcma_host_ops *ops;
enum bcma_hosttype hosttype;
+ bool host_is_pcie2; /* Used for BCMA_HOSTTYPE_PCI only */
union {
/* Pointer to the PCI bus (only for BCMA_HOSTTYPE_PCI) */
struct pci_dev *host_pci;
diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h
index 0333e605ea0d..3f809ae372c4 100644
--- a/include/linux/bcma/bcma_driver_pci.h
+++ b/include/linux/bcma/bcma_driver_pci.h
@@ -223,6 +223,7 @@ struct bcma_drv_pci_host {
struct bcma_drv_pci {
struct bcma_device *core;
+ u8 early_setup_done:1;
u8 setup_done:1;
u8 hostmode:1;
@@ -237,6 +238,7 @@ struct bcma_drv_pci {
#define pcicore_write16(pc, offset, val) bcma_write16((pc)->core, offset, val)
#define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val)
+extern void bcma_core_pci_early_init(struct bcma_drv_pci *pc);
extern void bcma_core_pci_init(struct bcma_drv_pci *pc);
extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
struct bcma_device *core, bool enable);
diff --git a/include/linux/bcma/bcma_regs.h b/include/linux/bcma/bcma_regs.h
index e64ae7bf80a1..ebd5c1fcdea4 100644
--- a/include/linux/bcma/bcma_regs.h
+++ b/include/linux/bcma/bcma_regs.h
@@ -64,6 +64,8 @@
#define BCMA_PCI_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */
#define BCMA_PCI_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */
+#define BCMA_PCIE2_BAR0_WIN2 0x70
+
/* SiliconBackplane Address Map.
* All regions may not exist on all chips.
*/
diff --git a/include/linux/bcma/bcma_soc.h b/include/linux/bcma/bcma_soc.h
index f24d245f8394..1b5fc0c3b1b5 100644
--- a/include/linux/bcma/bcma_soc.h
+++ b/include/linux/bcma/bcma_soc.h
@@ -5,8 +5,6 @@
struct bcma_soc {
struct bcma_bus bus;
- struct bcma_device core_cc;
- struct bcma_device core_mips;
};
int __init bcma_host_soc_register(struct bcma_soc *soc);
diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h
index f7b9100686c3..c0f707ac192b 100644
--- a/include/linux/ssb/ssb_regs.h
+++ b/include/linux/ssb/ssb_regs.h
@@ -173,6 +173,7 @@
#define SSB_SPROMSIZE_BYTES_R123 (SSB_SPROMSIZE_WORDS_R123 * sizeof(u16))
#define SSB_SPROMSIZE_BYTES_R4 (SSB_SPROMSIZE_WORDS_R4 * sizeof(u16))
#define SSB_SPROMSIZE_WORDS_R10 230
+#define SSB_SPROMSIZE_WORDS_R11 234
#define SSB_SPROM_BASE1 0x1000
#define SSB_SPROM_BASE31 0x0800
#define SSB_SPROM_REVISION 0x007E
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 4ebb816241fa..7b44ba0a7632 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -520,37 +520,41 @@ ieee80211_chandef_max_power(struct cfg80211_chan_def *chandef)
*
* @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in
* @SURVEY_INFO_IN_USE: channel is currently being used
- * @SURVEY_INFO_CHANNEL_TIME: channel active time (in ms) was filled in
- * @SURVEY_INFO_CHANNEL_TIME_BUSY: channel busy time was filled in
- * @SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: extension channel busy time was filled in
- * @SURVEY_INFO_CHANNEL_TIME_RX: channel receive time was filled in
- * @SURVEY_INFO_CHANNEL_TIME_TX: channel transmit time was filled in
+ * @SURVEY_INFO_TIME: active time (in ms) was filled in
+ * @SURVEY_INFO_TIME_BUSY: busy time was filled in
+ * @SURVEY_INFO_TIME_EXT_BUSY: extension channel busy time was filled in
+ * @SURVEY_INFO_TIME_RX: receive time was filled in
+ * @SURVEY_INFO_TIME_TX: transmit time was filled in
+ * @SURVEY_INFO_TIME_SCAN: scan time was filled in
*
* Used by the driver to indicate which info in &struct survey_info
* it has filled in during the get_survey().
*/
enum survey_info_flags {
- SURVEY_INFO_NOISE_DBM = 1<<0,
- SURVEY_INFO_IN_USE = 1<<1,
- SURVEY_INFO_CHANNEL_TIME = 1<<2,
- SURVEY_INFO_CHANNEL_TIME_BUSY = 1<<3,
- SURVEY_INFO_CHANNEL_TIME_EXT_BUSY = 1<<4,
- SURVEY_INFO_CHANNEL_TIME_RX = 1<<5,
- SURVEY_INFO_CHANNEL_TIME_TX = 1<<6,
+ SURVEY_INFO_NOISE_DBM = BIT(0),
+ SURVEY_INFO_IN_USE = BIT(1),
+ SURVEY_INFO_TIME = BIT(2),
+ SURVEY_INFO_TIME_BUSY = BIT(3),
+ SURVEY_INFO_TIME_EXT_BUSY = BIT(4),
+ SURVEY_INFO_TIME_RX = BIT(5),
+ SURVEY_INFO_TIME_TX = BIT(6),
+ SURVEY_INFO_TIME_SCAN = BIT(7),
};
/**
* struct survey_info - channel survey response
*
- * @channel: the channel this survey record reports, mandatory
+ * @channel: the channel this survey record reports, may be %NULL for a single
+ * record to report global statistics
* @filled: bitflag of flags from &enum survey_info_flags
* @noise: channel noise in dBm. This and all following fields are
* optional
- * @channel_time: amount of time in ms the radio spent on the channel
- * @channel_time_busy: amount of time the primary channel was sensed busy
- * @channel_time_ext_busy: amount of time the extension channel was sensed busy
- * @channel_time_rx: amount of time the radio spent receiving data
- * @channel_time_tx: amount of time the radio spent transmitting data
+ * @time: amount of time in ms the radio was turn on (on the channel)
+ * @time_busy: amount of time the primary channel was sensed busy
+ * @time_ext_busy: amount of time the extension channel was sensed busy
+ * @time_rx: amount of time the radio spent receiving data
+ * @time_tx: amount of time the radio spent transmitting data
+ * @time_scan: amount of time the radio spent for scanning
*
* Used by dump_survey() to report back per-channel survey information.
*
@@ -559,11 +563,12 @@ enum survey_info_flags {
*/
struct survey_info {
struct ieee80211_channel *channel;
- u64 channel_time;
- u64 channel_time_busy;
- u64 channel_time_ext_busy;
- u64 channel_time_rx;
- u64 channel_time_tx;
+ u64 time;
+ u64 time_busy;
+ u64 time_ext_busy;
+ u64 time_rx;
+ u64 time_tx;
+ u64 time_scan;
u32 filled;
s8 noise;
};
@@ -861,75 +866,6 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
enum cfg80211_station_type statype);
/**
- * enum station_info_flags - station information flags
- *
- * Used by the driver to indicate which info in &struct station_info
- * it has filled in during get_station() or dump_station().
- *
- * @STATION_INFO_INACTIVE_TIME: @inactive_time filled
- * @STATION_INFO_RX_BYTES: @rx_bytes filled
- * @STATION_INFO_TX_BYTES: @tx_bytes filled
- * @STATION_INFO_RX_BYTES64: @rx_bytes filled with 64-bit value
- * @STATION_INFO_TX_BYTES64: @tx_bytes filled with 64-bit value
- * @STATION_INFO_LLID: @llid filled
- * @STATION_INFO_PLID: @plid filled
- * @STATION_INFO_PLINK_STATE: @plink_state filled
- * @STATION_INFO_SIGNAL: @signal filled
- * @STATION_INFO_TX_BITRATE: @txrate fields are filled
- * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
- * @STATION_INFO_RX_PACKETS: @rx_packets filled with 32-bit value
- * @STATION_INFO_TX_PACKETS: @tx_packets filled with 32-bit value
- * @STATION_INFO_TX_RETRIES: @tx_retries filled
- * @STATION_INFO_TX_FAILED: @tx_failed filled
- * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled
- * @STATION_INFO_SIGNAL_AVG: @signal_avg filled
- * @STATION_INFO_RX_BITRATE: @rxrate fields are filled
- * @STATION_INFO_BSS_PARAM: @bss_param filled
- * @STATION_INFO_CONNECTED_TIME: @connected_time filled
- * @STATION_INFO_ASSOC_REQ_IES: @assoc_req_ies filled
- * @STATION_INFO_STA_FLAGS: @sta_flags filled
- * @STATION_INFO_BEACON_LOSS_COUNT: @beacon_loss_count filled
- * @STATION_INFO_T_OFFSET: @t_offset filled
- * @STATION_INFO_LOCAL_PM: @local_pm filled
- * @STATION_INFO_PEER_PM: @peer_pm filled
- * @STATION_INFO_NONPEER_PM: @nonpeer_pm filled
- * @STATION_INFO_CHAIN_SIGNAL: @chain_signal filled
- * @STATION_INFO_CHAIN_SIGNAL_AVG: @chain_signal_avg filled
- * @STATION_INFO_EXPECTED_THROUGHPUT: @expected_throughput filled
- */
-enum station_info_flags {
- STATION_INFO_INACTIVE_TIME = BIT(0),
- STATION_INFO_RX_BYTES = BIT(1),
- STATION_INFO_TX_BYTES = BIT(2),
- STATION_INFO_LLID = BIT(3),
- STATION_INFO_PLID = BIT(4),
- STATION_INFO_PLINK_STATE = BIT(5),
- STATION_INFO_SIGNAL = BIT(6),
- STATION_INFO_TX_BITRATE = BIT(7),
- STATION_INFO_RX_PACKETS = BIT(8),
- STATION_INFO_TX_PACKETS = BIT(9),
- STATION_INFO_TX_RETRIES = BIT(10),
- STATION_INFO_TX_FAILED = BIT(11),
- STATION_INFO_RX_DROP_MISC = BIT(12),
- STATION_INFO_SIGNAL_AVG = BIT(13),
- STATION_INFO_RX_BITRATE = BIT(14),
- STATION_INFO_BSS_PARAM = BIT(15),
- STATION_INFO_CONNECTED_TIME = BIT(16),
- STATION_INFO_ASSOC_REQ_IES = BIT(17),
- STATION_INFO_STA_FLAGS = BIT(18),
- STATION_INFO_BEACON_LOSS_COUNT = BIT(19),
- STATION_INFO_T_OFFSET = BIT(20),
- STATION_INFO_LOCAL_PM = BIT(21),
- STATION_INFO_PEER_PM = BIT(22),
- STATION_INFO_NONPEER_PM = BIT(23),
- STATION_INFO_RX_BYTES64 = BIT(24),
- STATION_INFO_TX_BYTES64 = BIT(25),
- STATION_INFO_CHAIN_SIGNAL = BIT(26),
- STATION_INFO_CHAIN_SIGNAL_AVG = BIT(27),
- STATION_INFO_EXPECTED_THROUGHPUT = BIT(28),
-};
-
-/**
* enum station_info_rate_flags - bitrate info flags
*
* Used by the driver to indicate the specific rate transmission
@@ -937,22 +873,35 @@ enum station_info_flags {
*
* @RATE_INFO_FLAGS_MCS: mcs field filled with HT MCS
* @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS
- * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 MHz width transmission
- * @RATE_INFO_FLAGS_80_MHZ_WIDTH: 80 MHz width transmission
- * @RATE_INFO_FLAGS_80P80_MHZ_WIDTH: 80+80 MHz width transmission
- * @RATE_INFO_FLAGS_160_MHZ_WIDTH: 160 MHz width transmission
* @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
* @RATE_INFO_FLAGS_60G: 60GHz MCS
*/
enum rate_info_flags {
RATE_INFO_FLAGS_MCS = BIT(0),
RATE_INFO_FLAGS_VHT_MCS = BIT(1),
- RATE_INFO_FLAGS_40_MHZ_WIDTH = BIT(2),
- RATE_INFO_FLAGS_80_MHZ_WIDTH = BIT(3),
- RATE_INFO_FLAGS_80P80_MHZ_WIDTH = BIT(4),
- RATE_INFO_FLAGS_160_MHZ_WIDTH = BIT(5),
- RATE_INFO_FLAGS_SHORT_GI = BIT(6),
- RATE_INFO_FLAGS_60G = BIT(7),
+ RATE_INFO_FLAGS_SHORT_GI = BIT(2),
+ RATE_INFO_FLAGS_60G = BIT(3),
+};
+
+/**
+ * enum rate_info_bw - rate bandwidth information
+ *
+ * Used by the driver to indicate the rate bandwidth.
+ *
+ * @RATE_INFO_BW_5: 5 MHz bandwidth
+ * @RATE_INFO_BW_10: 10 MHz bandwidth
+ * @RATE_INFO_BW_20: 20 MHz bandwidth
+ * @RATE_INFO_BW_40: 40 MHz bandwidth
+ * @RATE_INFO_BW_80: 80 MHz bandwidth
+ * @RATE_INFO_BW_160: 160 MHz bandwidth
+ */
+enum rate_info_bw {
+ RATE_INFO_BW_5,
+ RATE_INFO_BW_10,
+ RATE_INFO_BW_20,
+ RATE_INFO_BW_40,
+ RATE_INFO_BW_80,
+ RATE_INFO_BW_160,
};
/**
@@ -964,12 +913,14 @@ enum rate_info_flags {
* @mcs: mcs index if struct describes a 802.11n bitrate
* @legacy: bitrate in 100kbit/s for 802.11abg
* @nss: number of streams (VHT only)
+ * @bw: bandwidth (from &enum rate_info_bw)
*/
struct rate_info {
u8 flags;
u8 mcs;
u16 legacy;
u8 nss;
+ u8 bw;
};
/**
@@ -1003,6 +954,24 @@ struct sta_bss_parameters {
u16 beacon_interval;
};
+/**
+ * struct cfg80211_tid_stats - per-TID statistics
+ * @filled: bitmap of flags using the bits of &enum nl80211_tid_stats to
+ * indicate the relevant values in this struct are filled
+ * @rx_msdu: number of received MSDUs
+ * @tx_msdu: number of (attempted) transmitted MSDUs
+ * @tx_msdu_retries: number of retries (not counting the first) for
+ * transmitted MSDUs
+ * @tx_msdu_failed: number of failed transmitted MSDUs
+ */
+struct cfg80211_tid_stats {
+ u32 filled;
+ u64 rx_msdu;
+ u64 tx_msdu;
+ u64 tx_msdu_retries;
+ u64 tx_msdu_failed;
+};
+
#define IEEE80211_MAX_CHAINS 4
/**
@@ -1010,11 +979,12 @@ struct sta_bss_parameters {
*
* Station information filled by driver for get_station() and dump_station.
*
- * @filled: bitflag of flags from &enum station_info_flags
+ * @filled: bitflag of flags using the bits of &enum nl80211_sta_info to
+ * indicate the relevant values in this struct for them
* @connected_time: time(in secs) since a station is last connected
* @inactive_time: time since last station activity (tx/rx) in milliseconds
- * @rx_bytes: bytes received from this station
- * @tx_bytes: bytes transmitted to this station
+ * @rx_bytes: bytes (size of MPDUs) received from this station
+ * @tx_bytes: bytes (size of MPDUs) transmitted to this station
* @llid: mesh local link id
* @plid: mesh peer link id
* @plink_state: mesh peer link state
@@ -1027,10 +997,10 @@ struct sta_bss_parameters {
* @chain_signal_avg: per-chain signal strength average in dBm
* @txrate: current unicast bitrate from this station
* @rxrate: current unicast bitrate to this station
- * @rx_packets: packets received from this station
- * @tx_packets: packets transmitted to this station
- * @tx_retries: cumulative retry counts
- * @tx_failed: number of failed transmissions (retries exceeded, no ACK)
+ * @rx_packets: packets (MSDUs & MMPDUs) received from this station
+ * @tx_packets: packets (MSDUs & MMPDUs) transmitted to this station
+ * @tx_retries: cumulative retry counts (MPDUs)
+ * @tx_failed: number of failed transmissions (MPDUs) (retries exceeded, no ACK)
* @rx_dropped_misc: Dropped for un-specified reason.
* @bss_param: current BSS parameters
* @generation: generation number for nl80211 dumps.
@@ -1050,6 +1020,11 @@ struct sta_bss_parameters {
* @nonpeer_pm: non-peer mesh STA power save mode
* @expected_throughput: expected throughput in kbps (including 802.11 headers)
* towards this station.
+ * @rx_beacon: number of beacons received from this peer
+ * @rx_beacon_signal_avg: signal strength average (in dBm) for beacons received
+ * from this peer
+ * @pertid: per-TID statistics, see &struct cfg80211_tid_stats, using the last
+ * (IEEE80211_NUM_TIDS) index for MSDUs not encapsulated in QoS-MPDUs.
*/
struct station_info {
u32 filled;
@@ -1090,10 +1065,9 @@ struct station_info {
u32 expected_throughput;
- /*
- * Note: Add a new enum station_info_flags value for each new field and
- * use it to check which fields are initialized.
- */
+ u64 rx_beacon;
+ u8 rx_beacon_signal_avg;
+ struct cfg80211_tid_stats pertid[IEEE80211_NUM_TIDS + 1];
};
/**
@@ -1516,6 +1490,9 @@ struct cfg80211_match_set {
* @mac_addr_mask: MAC address mask used with randomisation, bits that
* are 0 in the mask should be randomised, bits that are 1 should
* be taken from the @mac_addr
+ * @rcu_head: RCU callback used to free the struct
+ * @owner_nlportid: netlink portid of owner (if this should is a request
+ * owned by a particular socket)
*/
struct cfg80211_sched_scan_request {
struct cfg80211_ssid *ssids;
@@ -1537,6 +1514,8 @@ struct cfg80211_sched_scan_request {
struct wiphy *wiphy;
struct net_device *dev;
unsigned long scan_start;
+ struct rcu_head rcu_head;
+ u32 owner_nlportid;
/* keep last */
struct ieee80211_channel *channels[0];
@@ -3011,6 +2990,8 @@ struct wiphy_vendor_command {
* @regulatory_flags: wiphy regulatory flags, see
* &enum ieee80211_regulatory_flags
* @features: features advertised to nl80211, see &enum nl80211_feature_flags.
+ * @ext_features: extended features advertised to nl80211, see
+ * &enum nl80211_ext_feature_index.
* @bss_priv_size: each BSS struct has private data allocated with it,
* this variable determines its size
* @max_scan_ssids: maximum number of SSIDs the device can scan for in
@@ -3120,6 +3101,7 @@ struct wiphy {
u16 max_acl_mac_addrs;
u32 flags, regulatory_flags, features;
+ u8 ext_features[DIV_ROUND_UP(NUM_NL80211_EXT_FEATURES, 8)];
u32 ap_sme_capa;
@@ -3808,6 +3790,34 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
/**
+ * regulatory_set_wiphy_regd - set regdom info for self managed drivers
+ * @wiphy: the wireless device we want to process the regulatory domain on
+ * @rd: the regulatory domain informatoin to use for this wiphy
+ *
+ * Set the regulatory domain information for self-managed wiphys, only they
+ * may use this function. See %REGULATORY_WIPHY_SELF_MANAGED for more
+ * information.
+ *
+ * Return: 0 on success. -EINVAL, -EPERM
+ */
+int regulatory_set_wiphy_regd(struct wiphy *wiphy,
+ struct ieee80211_regdomain *rd);
+
+/**
+ * regulatory_set_wiphy_regd_sync_rtnl - set regdom for self-managed drivers
+ * @wiphy: the wireless device we want to process the regulatory domain on
+ * @rd: the regulatory domain information to use for this wiphy
+ *
+ * This functions requires the RTNL to be held and applies the new regdomain
+ * synchronously to this wiphy. For more details see
+ * regulatory_set_wiphy_regd().
+ *
+ * Return: 0 on success. -EINVAL, -EPERM
+ */
+int regulatory_set_wiphy_regd_sync_rtnl(struct wiphy *wiphy,
+ struct ieee80211_regdomain *rd);
+
+/**
* wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
* @wiphy: the wireless device we want to process the regulatory domain on
* @regd: the custom regulatory domain to use for this wiphy
@@ -4565,13 +4575,27 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
struct station_info *sinfo, gfp_t gfp);
/**
+ * cfg80211_del_sta_sinfo - notify userspace about deletion of a station
+ * @dev: the netdev
+ * @mac_addr: the station's address
+ * @sinfo: the station information/statistics
+ * @gfp: allocation flags
+ */
+void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr,
+ struct station_info *sinfo, gfp_t gfp);
+
+/**
* cfg80211_del_sta - notify userspace about deletion of a station
*
* @dev: the netdev
* @mac_addr: the station's address
* @gfp: allocation flags
*/
-void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp);
+static inline void cfg80211_del_sta(struct net_device *dev,
+ const u8 *mac_addr, gfp_t gfp)
+{
+ cfg80211_del_sta_sinfo(dev, mac_addr, NULL, gfp);
+}
/**
* cfg80211_conn_failed - connection request failed notification
@@ -5033,6 +5057,42 @@ void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev,
*/
void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy);
+/**
+ * wiphy_ext_feature_set - set the extended feature flag
+ *
+ * @wiphy: the wiphy to modify.
+ * @ftidx: extended feature bit index.
+ *
+ * The extended features are flagged in multiple bytes (see
+ * &struct wiphy.@ext_features)
+ */
+static inline void wiphy_ext_feature_set(struct wiphy *wiphy,
+ enum nl80211_ext_feature_index ftidx)
+{
+ u8 *ft_byte;
+
+ ft_byte = &wiphy->ext_features[ftidx / 8];
+ *ft_byte |= BIT(ftidx % 8);
+}
+
+/**
+ * wiphy_ext_feature_isset - check the extended feature flag
+ *
+ * @wiphy: the wiphy to modify.
+ * @ftidx: extended feature bit index.
+ *
+ * The extended features are flagged in multiple bytes (see
+ * &struct wiphy.@ext_features)
+ */
+static inline bool
+wiphy_ext_feature_isset(struct wiphy *wiphy,
+ enum nl80211_ext_feature_index ftidx)
+{
+ u8 ft_byte;
+
+ ft_byte = wiphy->ext_features[ftidx / 8];
+ return (ft_byte & BIT(ftidx % 8)) != 0;
+}
/* ethtool helper */
void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 58d719ddaa60..275ee56152ad 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -505,8 +505,11 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_CTL_DONTFRAG: Don't fragment this packet even if it
* would be fragmented by size (this is optional, only used for
* monitor injection).
- * @IEEE80211_TX_CTL_PS_RESPONSE: This frame is a response to a poll
- * frame (PS-Poll or uAPSD).
+ * @IEEE80211_TX_STAT_NOACK_TRANSMITTED: A frame that was marked with
+ * IEEE80211_TX_CTL_NO_ACK has been successfully transmitted without
+ * any errors (like issues specific to the driver/HW).
+ * This flag must not be set for frames that don't request no-ack
+ * behaviour with IEEE80211_TX_CTL_NO_ACK.
*
* Note: If you have to add new flags to the enumeration, then don't
* forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -542,7 +545,7 @@ enum mac80211_tx_info_flags {
IEEE80211_TX_STATUS_EOSP = BIT(28),
IEEE80211_TX_CTL_USE_MINRATE = BIT(29),
IEEE80211_TX_CTL_DONTFRAG = BIT(30),
- IEEE80211_TX_CTL_PS_RESPONSE = BIT(31),
+ IEEE80211_TX_STAT_NOACK_TRANSMITTED = BIT(31),
};
#define IEEE80211_TX_CTL_STBC_SHIFT 23
@@ -552,11 +555,14 @@ enum mac80211_tx_info_flags {
*
* @IEEE80211_TX_CTRL_PORT_CTRL_PROTO: this frame is a port control
* protocol frame (e.g. EAP)
+ * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
+ * frame (PS-Poll or uAPSD).
*
* These flags are used in tx_info->control.flags.
*/
enum mac80211_tx_control_flags {
IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
+ IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
};
/*
@@ -925,15 +931,13 @@ enum mac80211_rx_flags {
* These flags are used with the @vht_flag member of
* &struct ieee80211_rx_status.
* @RX_VHT_FLAG_80MHZ: 80 MHz was used
- * @RX_VHT_FLAG_80P80MHZ: 80+80 MHz was used
* @RX_VHT_FLAG_160MHZ: 160 MHz was used
* @RX_VHT_FLAG_BF: packet was beamformed
*/
enum mac80211_rx_vht_flags {
RX_VHT_FLAG_80MHZ = BIT(0),
- RX_VHT_FLAG_80P80MHZ = BIT(1),
- RX_VHT_FLAG_160MHZ = BIT(2),
- RX_VHT_FLAG_BF = BIT(3),
+ RX_VHT_FLAG_160MHZ = BIT(1),
+ RX_VHT_FLAG_BF = BIT(2),
};
/**
@@ -1181,10 +1185,15 @@ struct ieee80211_channel_switch {
* monitoring on this virtual interface -- i.e. it can monitor
* connection quality related parameters, such as the RSSI level and
* provide notifications if configured trigger levels are reached.
+ * @IEEE80211_VIF_SUPPORTS_UAPSD: The device can do U-APSD for this
+ * interface. This flag should be set during interface addition,
+ * but may be set/cleared as late as authentication to an AP. It is
+ * only valid for managed/station mode interfaces.
*/
enum ieee80211_vif_flags {
IEEE80211_VIF_BEACON_FILTER = BIT(0),
IEEE80211_VIF_SUPPORTS_CQM_RSSI = BIT(1),
+ IEEE80211_VIF_SUPPORTS_UAPSD = BIT(2),
};
/**
@@ -1296,6 +1305,9 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
* @IEEE80211_KEY_FLAG_GENERATE_IV_MGMT: This flag should be set by the
* driver for a CCMP key to indicate that is requires IV generation
* only for managment frames (MFP).
+ * @IEEE80211_KEY_FLAG_RESERVE_TAILROOM: This flag should be set by the
+ * driver for a key to indicate that sufficient tailroom must always
+ * be reserved for ICV or MIC, even when HW encryption is enabled.
*/
enum ieee80211_key_flags {
IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0),
@@ -1305,6 +1317,7 @@ enum ieee80211_key_flags {
IEEE80211_KEY_FLAG_SW_MGMT_TX = BIT(4),
IEEE80211_KEY_FLAG_PUT_IV_SPACE = BIT(5),
IEEE80211_KEY_FLAG_RX_MGMT = BIT(6),
+ IEEE80211_KEY_FLAG_RESERVE_TAILROOM = BIT(7),
};
/**
@@ -1583,11 +1596,6 @@ struct ieee80211_tx_control {
* @IEEE80211_HW_MFP_CAPABLE:
* Hardware supports management frame protection (MFP, IEEE 802.11w).
*
- * @IEEE80211_HW_SUPPORTS_UAPSD:
- * Hardware supports Unscheduled Automatic Power Save Delivery
- * (U-APSD) in managed mode. The mode is configured with
- * conf_tx() operation.
- *
* @IEEE80211_HW_REPORTS_TX_ACK_STATUS:
* Hardware can provide ack status reports of Tx frames to
* the stack.
@@ -1673,8 +1681,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_MFP_CAPABLE = 1<<13,
IEEE80211_HW_WANT_MONITOR_VIF = 1<<14,
IEEE80211_HW_NO_AUTO_VIF = 1<<15,
- /* free slot */
- IEEE80211_HW_SUPPORTS_UAPSD = 1<<17,
+ /* free slots */
IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18,
IEEE80211_HW_CONNECTION_MONITOR = 1<<19,
IEEE80211_HW_QUEUE_CONTROL = 1<<20,
@@ -2026,7 +2033,7 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
* enabled whenever user has enabled powersave.
*
* Driver informs U-APSD client support by enabling
- * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the
+ * %IEEE80211_VIF_SUPPORTS_UAPSD flag. The mode is configured through the
* uapsd parameter in conf_tx() operation. Hardware needs to send the QoS
* Nullfunc frames and stay awake until the service period has ended. To
* utilize U-APSD, dynamic powersave is disabled for voip AC and all frames
@@ -2699,6 +2706,14 @@ enum ieee80211_reconfig_type {
* is only used if the configured rate control algorithm actually uses
* the new rate table API, and is therefore optional. Must be atomic.
*
+ * @sta_statistics: Get statistics for this station. For example with beacon
+ * filtering, the statistics kept by mac80211 might not be accurate, so
+ * let the driver pre-fill the statistics. The driver can fill most of
+ * the values (indicating which by setting the filled bitmap), but not
+ * all of them make sense - see the source for which ones are possible.
+ * Statistics that the driver doesn't fill will be filled by mac80211.
+ * The callback can sleep.
+ *
* @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
* bursting) for a hardware TX queue.
* Returns a negative error code on failure.
@@ -2859,9 +2874,6 @@ enum ieee80211_reconfig_type {
* @get_et_strings: Ethtool API to get a set of strings to describe stats
* and perhaps other supported types of ethtool data-sets.
*
- * @get_rssi: Get current signal strength in dBm, the function is optional
- * and can sleep.
- *
* @mgd_prepare_tx: Prepare for transmitting a management frame for association
* before associated. In multi-channel scenarios, a virtual interface is
* bound to a channel before it is associated, but as it isn't associated
@@ -3062,6 +3074,10 @@ struct ieee80211_ops {
void (*sta_rate_tbl_update)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
+ void (*sta_statistics)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct station_info *sinfo);
int (*conf_tx)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 ac,
const struct ieee80211_tx_queue_params *params);
@@ -3129,8 +3145,6 @@ struct ieee80211_ops {
void (*get_et_strings)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u32 sset, u8 *data);
- int (*get_rssi)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, s8 *rssi_dbm);
void (*mgd_prepare_tx)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index b776d72d84be..ebc5a2ed8631 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -147,6 +147,24 @@ struct regulatory_request {
* NL80211_IFTYPE_P2P_CLIENT, NL80211_IFTYPE_P2P_GO,
* NL80211_IFTYPE_P2P_DEVICE. The flag will be set by default if a device
* includes any modes unsupported for enforcement checking.
+ * @REGULATORY_WIPHY_SELF_MANAGED: for devices that employ wiphy-specific
+ * regdom management. These devices will ignore all regdom changes not
+ * originating from their own wiphy.
+ * A self-managed wiphys only employs regulatory information obtained from
+ * the FW and driver and does not use other cfg80211 sources like
+ * beacon-hints, country-code IEs and hints from other devices on the same
+ * system. Conversely, a self-managed wiphy does not share its regulatory
+ * hints with other devices in the system. If a system contains several
+ * devices, one or more of which are self-managed, there might be
+ * contradictory regulatory settings between them. Usage of flag is
+ * generally discouraged. Only use it if the FW/driver is incompatible
+ * with non-locally originated hints.
+ * This flag is incompatible with the flags: %REGULATORY_CUSTOM_REG,
+ * %REGULATORY_STRICT_REG, %REGULATORY_COUNTRY_IE_FOLLOW_POWER,
+ * %REGULATORY_COUNTRY_IE_IGNORE and %REGULATORY_DISABLE_BEACON_HINTS.
+ * Mixing any of the above flags with this flag will result in a failure
+ * to register the wiphy. This flag implies
+ * %REGULATORY_DISABLE_BEACON_HINTS and %REGULATORY_COUNTRY_IE_IGNORE.
*/
enum ieee80211_regulatory_flags {
REGULATORY_CUSTOM_REG = BIT(0),
@@ -156,6 +174,7 @@ enum ieee80211_regulatory_flags {
REGULATORY_COUNTRY_IE_IGNORE = BIT(4),
REGULATORY_ENABLE_RELAX_NO_IR = BIT(5),
REGULATORY_IGNORE_STALE_KICKOFF = BIT(6),
+ REGULATORY_WIPHY_SELF_MANAGED = BIT(7),
};
struct ieee80211_freq_range {
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index b37bd5a1cb82..f52797a90816 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -29,6 +29,13 @@
#define NL80211_GENL_NAME "nl80211"
+#define NL80211_MULTICAST_GROUP_CONFIG "config"
+#define NL80211_MULTICAST_GROUP_SCAN "scan"
+#define NL80211_MULTICAST_GROUP_REG "regulatory"
+#define NL80211_MULTICAST_GROUP_MLME "mlme"
+#define NL80211_MULTICAST_GROUP_VENDOR "vendor"
+#define NL80211_MULTICAST_GROUP_TESTMODE "testmode"
+
/**
* DOC: Station handling
*
@@ -252,7 +259,18 @@
* %NL80211_ATTR_IFINDEX.
*
* @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set
- * regulatory domain.
+ * regulatory domain. If %NL80211_ATTR_WIPHY is specified and the device
+ * has a private regulatory domain, it will be returned. Otherwise, the
+ * global regdomain will be returned.
+ * A device will have a private regulatory domain if it uses the
+ * regulatory_hint() API. Even when a private regdomain is used the channel
+ * information will still be mended according to further hints from
+ * the regulatory core to help with compliance. A dump version of this API
+ * is now available which will returns the global regdomain as well as
+ * all private regdomains of present wiphys (for those that have it).
+ * If a wiphy is self-managed (%NL80211_ATTR_WIPHY_SELF_MANAGED_REG), then
+ * its private regdomain is the only valid one for it. The regulatory
+ * core is not used to help with compliance in this case.
* @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
* after being queried by the kernel. CRDA replies by sending a regulatory
* domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
@@ -774,6 +792,10 @@
* peer given by %NL80211_ATTR_MAC. Both peers must be on the base channel
* when this command completes.
*
+ * @NL80211_CMD_WIPHY_REG_CHANGE: Similar to %NL80211_CMD_REG_CHANGE, but used
+ * as an event to indicate changes for devices with wiphy-specific regdom
+ * management.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -958,6 +980,8 @@ enum nl80211_commands {
NL80211_CMD_TDLS_CHANNEL_SWITCH,
NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
+ NL80211_CMD_WIPHY_REG_CHANGE,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1655,6 +1679,9 @@ enum nl80211_commands {
* @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
* creation then the new interface will be owned by the netlink socket
* that created it and will be destroyed when the socket is closed.
+ * If set during scheduled scan start then the new scan req will be
+ * owned by the netlink socket that created it and the scheduled scan will
+ * be stopped when the socket is closed.
*
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
* the TDLS link initiator.
@@ -1688,6 +1715,26 @@ enum nl80211_commands {
*
* @NL80211_ATTR_MAC_MASK: MAC address mask
*
+ * @NL80211_ATTR_WIPHY_SELF_MANAGED_REG: flag attribute indicating this device
+ * is self-managing its regulatory information and any regulatory domain
+ * obtained from it is coming from the device's wiphy and not the global
+ * cfg80211 regdomain.
+ *
+ * @NL80211_ATTR_EXT_FEATURES: extended feature flags contained in a byte
+ * array. The feature flags are identified by their bit index (see &enum
+ * nl80211_ext_feature_index). The bit index is ordered starting at the
+ * least-significant bit of the first byte in the array, ie. bit index 0
+ * is located at bit 0 of byte 0. bit index 25 would be located at bit 1
+ * of byte 3 (u8 array).
+ *
+ * @NL80211_ATTR_SURVEY_RADIO_STATS: Request overall radio statistics to be
+ * returned along with other survey data. If set, @NL80211_CMD_GET_SURVEY
+ * may return a survey entry without a channel indicating global radio
+ * statistics (only some values are valid and make sense.)
+ * For devices that don't return such an entry even then, the information
+ * should be contained in the result as the sum of the respective counters
+ * over all channels.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2045,6 +2092,12 @@ enum nl80211_attrs {
NL80211_ATTR_MAC_MASK,
+ NL80211_ATTR_WIPHY_SELF_MANAGED_REG,
+
+ NL80211_ATTR_EXT_FEATURES,
+
+ NL80211_ATTR_SURVEY_RADIO_STATS,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -2085,7 +2138,7 @@ enum nl80211_attrs {
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_HT_RATES 77
-#define NL80211_MAX_SUPP_REG_RULES 32
+#define NL80211_MAX_SUPP_REG_RULES 64
#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
@@ -2225,8 +2278,15 @@ struct nl80211_sta_flag_update {
* @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8)
* @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8)
* @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate
- * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate
+ * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: unused - 80+80 is treated the
+ * same as 160 for purposes of the bitrates
* @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate
+ * @NL80211_RATE_INFO_10_MHZ_WIDTH: 10 MHz width - note that this is
+ * a legacy rate and will be reported as the actual bitrate, i.e.
+ * half the base (20 MHz) rate
+ * @NL80211_RATE_INFO_5_MHZ_WIDTH: 5 MHz width - note that this is
+ * a legacy rate and will be reported as the actual bitrate, i.e.
+ * a quarter of the base (20 MHz) rate
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
enum nl80211_rate_info {
@@ -2241,6 +2301,8 @@ enum nl80211_rate_info {
NL80211_RATE_INFO_80_MHZ_WIDTH,
NL80211_RATE_INFO_80P80_MHZ_WIDTH,
NL80211_RATE_INFO_160_MHZ_WIDTH,
+ NL80211_RATE_INFO_10_MHZ_WIDTH,
+ NL80211_RATE_INFO_5_MHZ_WIDTH,
/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
@@ -2285,18 +2347,24 @@ enum nl80211_sta_bss_param {
*
* @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
* @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
- * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
- * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
- * @NL80211_STA_INFO_RX_BYTES64: total received bytes (u64, from this station)
- * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (u64, to this station)
+ * @NL80211_STA_INFO_RX_BYTES: total received bytes (MPDU length)
+ * (u32, from this station)
+ * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (MPDU length)
+ * (u32, to this station)
+ * @NL80211_STA_INFO_RX_BYTES64: total received bytes (MPDU length)
+ * (u64, from this station)
+ * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (MPDU length)
+ * (u64, to this station)
* @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
* @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
* containing info as possible, see &enum nl80211_rate_info
- * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
- * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
- * station)
- * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
- * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
+ * @NL80211_STA_INFO_RX_PACKETS: total received packet (MSDUs and MMPDUs)
+ * (u32, from this station)
+ * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (MSDUs and MMPDUs)
+ * (u32, to this station)
+ * @NL80211_STA_INFO_TX_RETRIES: total retries (MPDUs) (u32, to this station)
+ * @NL80211_STA_INFO_TX_FAILED: total failed packets (MPDUs)
+ * (u32, to this station)
* @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm)
* @NL80211_STA_INFO_LLID: the station's mesh LLID
* @NL80211_STA_INFO_PLID: the station's mesh PLID
@@ -2320,6 +2388,16 @@ enum nl80211_sta_bss_param {
* Same format as NL80211_STA_INFO_CHAIN_SIGNAL.
* @NL80211_STA_EXPECTED_THROUGHPUT: expected throughput considering also the
* 802.11 header (u32, kbps)
+ * @NL80211_STA_INFO_RX_DROP_MISC: RX packets dropped for unspecified reasons
+ * (u64)
+ * @NL80211_STA_INFO_BEACON_RX: number of beacons received from this peer (u64)
+ * @NL80211_STA_INFO_BEACON_SIGNAL_AVG: signal strength average
+ * for beacons only (u8, dBm)
+ * @NL80211_STA_INFO_TID_STATS: per-TID statistics (see &enum nl80211_tid_stats)
+ * This is a nested attribute where each the inner attribute number is the
+ * TID+1 and the special TID 16 (i.e. value 17) is used for non-QoS frames;
+ * each one of those is again nested with &enum nl80211_tid_stats
+ * attributes carrying the actual values.
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -2352,6 +2430,10 @@ enum nl80211_sta_info {
NL80211_STA_INFO_CHAIN_SIGNAL,
NL80211_STA_INFO_CHAIN_SIGNAL_AVG,
NL80211_STA_INFO_EXPECTED_THROUGHPUT,
+ NL80211_STA_INFO_RX_DROP_MISC,
+ NL80211_STA_INFO_BEACON_RX,
+ NL80211_STA_INFO_BEACON_SIGNAL_AVG,
+ NL80211_STA_INFO_TID_STATS,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -2359,6 +2441,31 @@ enum nl80211_sta_info {
};
/**
+ * enum nl80211_tid_stats - per TID statistics attributes
+ * @__NL80211_TID_STATS_INVALID: attribute number 0 is reserved
+ * @NL80211_TID_STATS_RX_MSDU: number of MSDUs received (u64)
+ * @NL80211_TID_STATS_TX_MSDU: number of MSDUs transmitted (or
+ * attempted to transmit; u64)
+ * @NL80211_TID_STATS_TX_MSDU_RETRIES: number of retries for
+ * transmitted MSDUs (not counting the first attempt; u64)
+ * @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted
+ * MSDUs (u64)
+ * @NUM_NL80211_TID_STATS: number of attributes here
+ * @NL80211_TID_STATS_MAX: highest numbered attribute here
+ */
+enum nl80211_tid_stats {
+ __NL80211_TID_STATS_INVALID,
+ NL80211_TID_STATS_RX_MSDU,
+ NL80211_TID_STATS_TX_MSDU,
+ NL80211_TID_STATS_TX_MSDU_RETRIES,
+ NL80211_TID_STATS_TX_MSDU_FAILED,
+
+ /* keep last */
+ NUM_NL80211_TID_STATS,
+ NL80211_TID_STATS_MAX = NUM_NL80211_TID_STATS - 1
+};
+
+/**
* enum nl80211_mpath_flags - nl80211 mesh path flags
*
* @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
@@ -2772,16 +2879,18 @@ enum nl80211_user_reg_hint_type {
* @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
* @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
* @NL80211_SURVEY_INFO_IN_USE: channel is currently being used
- * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio
- * spent on this channel
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary
+ * @NL80211_SURVEY_INFO_TIME: amount of time (in ms) that the radio
+ * was turned on (on channel or globally)
+ * @NL80211_SURVEY_INFO_TIME_BUSY: amount of the time the primary
* channel was sensed busy (either due to activity or energy detect)
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension
+ * @NL80211_SURVEY_INFO_TIME_EXT_BUSY: amount of time the extension
* channel was sensed busy
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent
- * receiving data
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent
- * transmitting data
+ * @NL80211_SURVEY_INFO_TIME_RX: amount of time the radio spent
+ * receiving data (on channel or globally)
+ * @NL80211_SURVEY_INFO_TIME_TX: amount of time the radio spent
+ * transmitting data (on channel or globally)
+ * @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan
+ * (on this channel or globally)
* @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
* currently defined
* @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
@@ -2791,17 +2900,25 @@ enum nl80211_survey_info {
NL80211_SURVEY_INFO_FREQUENCY,
NL80211_SURVEY_INFO_NOISE,
NL80211_SURVEY_INFO_IN_USE,
- NL80211_SURVEY_INFO_CHANNEL_TIME,
- NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
- NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
- NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
- NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
+ NL80211_SURVEY_INFO_TIME,
+ NL80211_SURVEY_INFO_TIME_BUSY,
+ NL80211_SURVEY_INFO_TIME_EXT_BUSY,
+ NL80211_SURVEY_INFO_TIME_RX,
+ NL80211_SURVEY_INFO_TIME_TX,
+ NL80211_SURVEY_INFO_TIME_SCAN,
/* keep last */
__NL80211_SURVEY_INFO_AFTER_LAST,
NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1
};
+/* keep old names for compatibility */
+#define NL80211_SURVEY_INFO_CHANNEL_TIME NL80211_SURVEY_INFO_TIME
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY NL80211_SURVEY_INFO_TIME_BUSY
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY NL80211_SURVEY_INFO_TIME_EXT_BUSY
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_RX NL80211_SURVEY_INFO_TIME_RX
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_TX NL80211_SURVEY_INFO_TIME_TX
+
/**
* enum nl80211_mntr_flags - monitor configuration flags
*
@@ -3238,6 +3355,9 @@ enum nl80211_bss {
/**
* enum nl80211_bss_status - BSS "status"
* @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS.
+ * Note that this is no longer used since cfg80211 no longer
+ * keeps track of whether or not authentication was done with
+ * a given BSS.
* @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS.
* @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS.
*
@@ -3623,7 +3743,9 @@ struct nl80211_pattern_support {
* same attributes used with @NL80211_CMD_START_SCHED_SCAN. It
* specifies how the scan is performed (e.g. the interval and the
* channels to scan) as well as the scan results that will
- * trigger a wake (i.e. the matchsets).
+ * trigger a wake (i.e. the matchsets). This attribute is also
+ * sent in a response to @NL80211_CMD_GET_WIPHY, indicating the
+ * number of match sets supported by the driver (u32).
* @NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS: nested attribute
* containing an array with information about what triggered the
* wake up. If no elements are present in the array, it means
@@ -4194,6 +4316,19 @@ enum nl80211_feature_flags {
};
/**
+ * enum nl80211_ext_feature_index - bit index of extended features.
+ *
+ * @NUM_NL80211_EXT_FEATURES: number of extended features.
+ * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
+ */
+enum nl80211_ext_feature_index {
+
+ /* add new features before the definition below */
+ NUM_NL80211_EXT_FEATURES,
+ MAX_NL80211_EXT_FEATURES = NUM_NL80211_EXT_FEATURES - 1
+};
+
+/**
* enum nl80211_probe_resp_offload_support_attr - optional supported
* protocols for probe-response offloading by the driver/FW.
* To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute.
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index e75d5c53e97b..ff090ef1ea2c 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -428,11 +428,13 @@ void sta_set_rate_info_tx(struct sta_info *sta,
rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
}
if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
- rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
- if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
- rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
- if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
- rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
+ rinfo->bw = RATE_INFO_BW_40;
+ else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_80;
+ else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_160;
+ else
+ rinfo->bw = RATE_INFO_BW_20;
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
}
@@ -459,16 +461,21 @@ void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
}
- if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
- rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI)
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
- if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_80MHZ)
- rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
- if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_80P80MHZ)
- rinfo->flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH;
- if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_160MHZ)
- rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
+
+ if (sta->last_rx_rate_flag & RX_FLAG_5MHZ)
+ rinfo->bw = RATE_INFO_BW_5;
+ else if (sta->last_rx_rate_flag & RX_FLAG_10MHZ)
+ rinfo->bw = RATE_INFO_BW_10;
+ else if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
+ rinfo->bw = RATE_INFO_BW_40;
+ else if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_80MHZ)
+ rinfo->bw = RATE_INFO_BW_80;
+ else if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_160MHZ)
+ rinfo->bw = RATE_INFO_BW_160;
+ else
+ rinfo->bw = RATE_INFO_BW_20;
}
static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
@@ -678,7 +685,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
BSS_CHANGED_BEACON_ENABLED |
BSS_CHANGED_BEACON |
BSS_CHANGED_SSID |
- BSS_CHANGED_P2P_PS;
+ BSS_CHANGED_P2P_PS |
+ BSS_CHANGED_TXPOWER;
int err;
old = sdata_dereference(sdata->u.ap.beacon, sdata);
@@ -2556,7 +2564,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
/* if there's one pending or we're scanning, queue this one */
if (!list_empty(&local->roc_list) ||
- local->scanning || local->radar_detect_enabled)
+ local->scanning || ieee80211_is_radar_required(local))
goto out_check_combine;
/* if not HW assist, just queue & schedule work */
@@ -3664,7 +3672,7 @@ static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev,
* queues.
*/
synchronize_net();
- ieee80211_flush_queues(local, sdata);
+ ieee80211_flush_queues(local, sdata, false);
/* restore the normal QoS parameters
* (unconditionally to avoid races)
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index da1c12c34487..35b11e11e0c4 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -388,7 +388,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
return NULL;
}
-static bool ieee80211_is_radar_required(struct ieee80211_local *local)
+bool ieee80211_is_radar_required(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
@@ -406,6 +406,34 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local)
return false;
}
+static bool
+ieee80211_chanctx_radar_required(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx)
+{
+ struct ieee80211_chanctx_conf *conf = &ctx->conf;
+ struct ieee80211_sub_if_data *sdata;
+ bool required = false;
+
+ lockdep_assert_held(&local->chanctx_mtx);
+ lockdep_assert_held(&local->mtx);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (!ieee80211_sdata_running(sdata))
+ continue;
+ if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
+ continue;
+ if (!sdata->radar_required)
+ continue;
+
+ required = true;
+ break;
+ }
+ rcu_read_unlock();
+
+ return required;
+}
+
static struct ieee80211_chanctx *
ieee80211_alloc_chanctx(struct ieee80211_local *local,
const struct cfg80211_chan_def *chandef,
@@ -425,7 +453,7 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local,
ctx->conf.rx_chains_static = 1;
ctx->conf.rx_chains_dynamic = 1;
ctx->mode = mode;
- ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
+ ctx->conf.radar_enabled = false;
ieee80211_recalc_chanctx_min_def(local, ctx);
return ctx;
@@ -567,16 +595,15 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
bool radar_enabled;
lockdep_assert_held(&local->chanctx_mtx);
- /* for setting local->radar_detect_enabled */
+ /* for ieee80211_is_radar_required */
lockdep_assert_held(&local->mtx);
- radar_enabled = ieee80211_is_radar_required(local);
+ radar_enabled = ieee80211_chanctx_radar_required(local, chanctx);
if (radar_enabled == chanctx->conf.radar_enabled)
return;
chanctx->conf.radar_enabled = radar_enabled;
- local->radar_detect_enabled = chanctx->conf.radar_enabled;
if (!local->use_chanctx) {
local->hw.conf.radar_enabled = chanctx->conf.radar_enabled;
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 54a189f0393e..eeb0bbd69d98 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -303,8 +303,6 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf,
sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n");
if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE)
sf += scnprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n");
- if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
- sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n");
if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
sf += scnprintf(buf + sf, mxln - sf,
"REPORTS_TX_ACK_STATUS\n");
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 2ebc9ead9695..fdeda17b8dd2 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -639,6 +639,21 @@ static inline void drv_sta_rate_tbl_update(struct ieee80211_local *local,
trace_drv_return_void(local);
}
+static inline void drv_sta_statistics(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta,
+ struct station_info *sinfo)
+{
+ sdata = get_bss_sdata(sdata);
+ if (!check_sdata_in_driver(sdata))
+ return;
+
+ trace_drv_sta_statistics(local, sdata, sta);
+ if (local->ops->sta_statistics)
+ local->ops->sta_statistics(&local->hw, &sdata->vif, sta, sinfo);
+ trace_drv_return_void(local);
+}
+
static inline int drv_conf_tx(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, u16 ac,
const struct ieee80211_tx_queue_params *params)
@@ -966,21 +981,6 @@ drv_allow_buffered_frames(struct ieee80211_local *local,
trace_drv_return_void(local);
}
-static inline int drv_get_rssi(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- struct ieee80211_sta *sta,
- s8 *rssi_dbm)
-{
- int ret;
-
- might_sleep();
-
- ret = local->ops->get_rssi(&local->hw, &sdata->vif, sta, rssi_dbm);
- trace_drv_get_rssi(local, sta, *rssi_dbm, ret);
-
- return ret;
-}
-
static inline void drv_mgd_prepare_tx(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c
index ebfc8091557b..52bcea6ad9e8 100644
--- a/net/mac80211/ethtool.c
+++ b/net/mac80211/ethtool.c
@@ -117,16 +117,16 @@ static void ieee80211_get_stats(struct net_device *dev,
data[i++] = sta->sta_state;
- if (sinfo.filled & STATION_INFO_TX_BITRATE)
+ if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE))
data[i] = 100000 *
cfg80211_calculate_bitrate(&sinfo.txrate);
i++;
- if (sinfo.filled & STATION_INFO_RX_BITRATE)
+ if (sinfo.filled & BIT(NL80211_STA_INFO_RX_BITRATE))
data[i] = 100000 *
cfg80211_calculate_bitrate(&sinfo.rxrate);
i++;
- if (sinfo.filled & STATION_INFO_SIGNAL_AVG)
+ if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))
data[i] = (u8)sinfo.signal_avg;
i++;
} else {
@@ -175,24 +175,24 @@ do_survey:
data[i++] = (u8)survey.noise;
else
data[i++] = -1LL;
- if (survey.filled & SURVEY_INFO_CHANNEL_TIME)
- data[i++] = survey.channel_time;
+ if (survey.filled & SURVEY_INFO_TIME)
+ data[i++] = survey.time;
else
data[i++] = -1LL;
- if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY)
- data[i++] = survey.channel_time_busy;
+ if (survey.filled & SURVEY_INFO_TIME_BUSY)
+ data[i++] = survey.time_busy;
else
data[i++] = -1LL;
- if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY)
- data[i++] = survey.channel_time_ext_busy;
+ if (survey.filled & SURVEY_INFO_TIME_EXT_BUSY)
+ data[i++] = survey.time_ext_busy;
else
data[i++] = -1LL;
- if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX)
- data[i++] = survey.channel_time_rx;
+ if (survey.filled & SURVEY_INFO_TIME_RX)
+ data[i++] = survey.time_rx;
else
data[i++] = -1LL;
- if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX)
- data[i++] = survey.channel_time_tx;
+ if (survey.filled & SURVEY_INFO_TIME_TX)
+ data[i++] = survey.time_tx;
else
data[i++] = -1LL;
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 509bc157ce55..b606b53a49a7 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -1069,9 +1069,16 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
}
if (sta && rates_updated) {
- drv_sta_rc_update(local, sdata, &sta->sta,
- IEEE80211_RC_SUPP_RATES_CHANGED);
+ u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
+ u8 rx_nss = sta->sta.rx_nss;
+
+ /* Force rx_nss recalculation */
+ sta->sta.rx_nss = 0;
rate_control_rate_init(sta);
+ if (sta->sta.rx_nss != rx_nss)
+ changed |= IEEE80211_RC_NSS_CHANGED;
+
+ drv_sta_rc_update(local, sdata, &sta->sta, changed);
}
rcu_read_unlock();
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index cc6e964d9837..156ea79e0157 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1168,8 +1168,6 @@ struct ieee80211_local {
/* wowlan is enabled -- don't reconfig on resume */
bool wowlan;
- /* DFS/radar detection is enabled */
- bool radar_detect_enabled;
struct work_struct radar_detected_work;
/* number of RX chains the hardware has */
@@ -1704,6 +1702,7 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband,
const struct ieee80211_vht_cap *vht_cap_ie,
struct sta_info *sta);
+enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta);
enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta);
void ieee80211_sta_set_rx_nss(struct sta_info *sta);
u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
@@ -1881,10 +1880,10 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
void ieee80211_add_pending_skbs(struct ieee80211_local *local,
struct sk_buff_head *skbs);
void ieee80211_flush_queues(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata);
+ struct ieee80211_sub_if_data *sdata, bool drop);
void __ieee80211_flush_queues(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int queues);
+ unsigned int queues, bool drop);
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg, u16 status,
@@ -1981,6 +1980,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx);
void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx);
+bool ieee80211_is_radar_required(struct ieee80211_local *local);
void ieee80211_dfs_cac_timer(unsigned long data);
void ieee80211_dfs_cac_timer_work(struct work_struct *work);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 417355390873..677422e11e07 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -93,7 +93,7 @@ static u32 __ieee80211_idle_on(struct ieee80211_local *local)
if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
return 0;
- ieee80211_flush_queues(local, NULL);
+ ieee80211_flush_queues(local, NULL, false);
local->hw.conf.flags |= IEEE80211_CONF_IDLE;
return IEEE80211_CONF_CHANGE_IDLE;
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 0bb7038121ac..f8d9f0ee59bf 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -140,7 +140,8 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
if (!ret) {
key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
- if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
+ if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+ (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
sdata->crypto_tx_tailroom_needed_cnt--;
WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
@@ -188,7 +189,8 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
sta = key->sta;
sdata = key->sdata;
- if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
+ if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+ (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
increment_tailroom_need_count(sdata);
ret = drv_set_key(key->local, DISABLE_KEY, sdata,
@@ -884,7 +886,8 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf)
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
- if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
+ if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+ (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
increment_tailroom_need_count(key->sdata);
}
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 6ab99da38db9..d9ce33663c73 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -916,10 +916,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
}
}
- WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
- && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK),
- "U-APSD not supported with HW_PS_NULLFUNC_STACK\n");
-
/*
* Calculate scan IE length -- we need this to alloc
* memory and to subtract from the driver limit. It
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index b488e1859b18..fa94ca15ba95 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -523,6 +523,13 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
sdata->u.mesh.mshcfg.auto_open_plinks &&
rssi_threshold_check(sdata, sta))
changed = mesh_plink_open(sta);
+ else if (sta->plink_state == NL80211_PLINK_LISTEN &&
+ (sdata->u.mesh.user_mpm ||
+ sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED))
+ cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
+ elems->ie_start,
+ elems->total_len,
+ GFP_ATOMIC);
ieee80211_mps_frame_release(sta, elems);
out:
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 2c36c4765f47..1875181ebd94 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -157,14 +157,18 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct cfg80211_chan_def vht_chandef;
+ struct ieee80211_sta_ht_cap sta_ht_cap;
u32 ht_cfreq, ret;
+ memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
+ ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
+
chandef->chan = channel;
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
chandef->center_freq1 = channel->center_freq;
chandef->center_freq2 = 0;
- if (!ht_cap || !ht_oper || !sband->ht_cap.ht_supported) {
+ if (!ht_cap || !ht_oper || !sta_ht_cap.ht_supported) {
ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
goto out;
}
@@ -198,7 +202,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
}
/* check 40 MHz support, if we have it */
- if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+ if (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
chandef->width = NL80211_CHAN_WIDTH_40;
@@ -1054,8 +1058,6 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
sdata->csa_block_tx = false;
}
- cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef);
-
sdata->vif.csa_active = false;
ifmgd->csa_waiting_bcn = false;
@@ -1067,6 +1069,8 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
&ifmgd->csa_connection_drop_work);
return;
}
+
+ cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef);
}
void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
@@ -1284,8 +1288,11 @@ ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata,
country_ie_len -= 3;
}
- if (have_chan_pwr)
+ if (have_chan_pwr && pwr_constr_elem)
*pwr_reduction = *pwr_constr_elem;
+ else
+ *pwr_reduction = 0;
+
return have_chan_pwr;
}
@@ -1314,10 +1321,11 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
int chan_pwr = 0, pwr_reduction_80211h = 0;
int pwr_level_cisco, pwr_level_80211h;
int new_ap_level;
+ __le16 capab = mgmt->u.probe_resp.capab_info;
- if (country_ie && pwr_constr_ie &&
- mgmt->u.probe_resp.capab_info &
- cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) {
+ if (country_ie &&
+ (capab & cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT) ||
+ capab & cpu_to_le16(WLAN_CAPABILITY_RADIO_MEASURE))) {
has_80211h_pwr = ieee80211_find_80211h_pwr_constr(
sdata, channel, country_ie, country_ie_len,
pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h);
@@ -1596,7 +1604,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
} else {
ieee80211_send_nullfunc(local, sdata, 1);
/* Flush to get the tx status of nullfunc frame */
- ieee80211_flush_queues(local, sdata);
+ ieee80211_flush_queues(local, sdata, false);
}
}
@@ -2003,18 +2011,23 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
/* disable per-vif ps */
ieee80211_recalc_ps_vif(sdata);
- /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */
+ /*
+ * drop any frame before deauth/disassoc, this can be data or
+ * management frame. Since we are disconnecting, we should not
+ * insist sending these frames which can take time and delay
+ * the disconnection and possible the roaming.
+ */
if (tx)
- ieee80211_flush_queues(local, sdata);
+ ieee80211_flush_queues(local, sdata, true);
/* deauthenticate/disassociate now */
if (tx || frame_buf)
ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype,
reason, tx, frame_buf);
- /* flush out frame */
+ /* flush out frame - make sure the deauth was actually sent */
if (tx)
- ieee80211_flush_queues(local, sdata);
+ ieee80211_flush_queues(local, sdata, false);
/* clear bssid only after building the needed mgmt frames */
memset(ifmgd->bssid, 0, ETH_ALEN);
@@ -2440,6 +2453,12 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
sdata_assert_lock(sdata);
if (!assoc) {
+ /*
+ * we are not authenticated yet, the only timer that could be
+ * running is the timeout for the authentication response which
+ * which is not relevant anymore.
+ */
+ del_timer_sync(&sdata->u.mgd.timer);
sta_info_destroy_addr(sdata, auth_data->bss->bssid);
memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
@@ -2747,6 +2766,12 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
sdata_assert_lock(sdata);
if (!assoc) {
+ /*
+ * we are not associated yet, the only timer that could be
+ * running is the timeout for the association response which
+ * which is not relevant anymore.
+ */
+ del_timer_sync(&sdata->u.mgd.timer);
sta_info_destroy_addr(sdata, assoc_data->bss->bssid);
memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
@@ -4197,9 +4222,13 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_bss *bss = (void *)cbss->priv;
struct sta_info *new_sta = NULL;
- bool have_sta = false;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_sta_ht_cap sta_ht_cap;
+ bool have_sta = false, is_override = false;
int err;
+ sband = local->hw.wiphy->bands[cbss->channel->band];
+
if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data))
return -EINVAL;
@@ -4214,25 +4243,32 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
if (!new_sta)
return -ENOMEM;
}
+
+ memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
+ ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
+
+ is_override = (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) !=
+ (sband->ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40);
+
+ if (new_sta || is_override) {
+ err = ieee80211_prep_channel(sdata, cbss);
+ if (err) {
+ if (new_sta)
+ sta_info_free(local, new_sta);
+ return -EINVAL;
+ }
+ }
+
if (new_sta) {
u32 rates = 0, basic_rates = 0;
bool have_higher_than_11mbit;
int min_rate = INT_MAX, min_rate_index = -1;
struct ieee80211_chanctx_conf *chanctx_conf;
- struct ieee80211_supported_band *sband;
const struct cfg80211_bss_ies *ies;
- int shift;
+ int shift = ieee80211_vif_get_shift(&sdata->vif);
u32 rate_flags;
- sband = local->hw.wiphy->bands[cbss->channel->band];
-
- err = ieee80211_prep_channel(sdata, cbss);
- if (err) {
- sta_info_free(local, new_sta);
- return -EINVAL;
- }
- shift = ieee80211_vif_get_shift(&sdata->vif);
-
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
@@ -4668,8 +4704,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
rcu_read_unlock();
+ if (WARN((sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD) &&
+ (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK),
+ "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"))
+ sdata->vif.driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
+
if (bss->wmm_used && bss->uapsd_supported &&
- (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
+ (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD)) {
assoc_data->uapsd = true;
ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED;
} else {
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index ff20b2ebdb30..683f0e3cb124 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -121,7 +121,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL,
false);
- ieee80211_flush_queues(local, NULL);
+ ieee80211_flush_queues(local, NULL, false);
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
@@ -398,7 +398,7 @@ void ieee80211_sw_roc_work(struct work_struct *work)
ieee80211_roc_notify_destroy(roc, !roc->abort);
if (started && !on_channel) {
- ieee80211_flush_queues(local, NULL);
+ ieee80211_flush_queues(local, NULL, false);
local->tmp_channel = NULL;
ieee80211_hw_config(local, 0);
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 4c5192e0d66c..8c8c67819072 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -41,7 +41,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
/* flush out all packets */
synchronize_net();
- ieee80211_flush_queues(local, NULL);
+ ieee80211_flush_queues(local, NULL, true);
local->quiescing = true;
/* make quiescing visible to timers everywhere */
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index d51f6b1c549b..7c86a002df95 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -263,12 +263,12 @@ static inline unsigned int
minstrel_get_retry_count(struct minstrel_rate *mr,
struct ieee80211_tx_info *info)
{
- unsigned int retry = mr->adjusted_retry_count;
+ u8 retry = mr->adjusted_retry_count;
if (info->control.use_rts)
- retry = max(2U, min(mr->stats.retry_count_rtscts, retry));
+ retry = max_t(u8, 2, min(mr->stats.retry_count_rtscts, retry));
else if (info->control.use_cts_prot)
- retry = max(2U, min(mr->retry_count_cts, retry));
+ retry = max_t(u8, 2, min(mr->retry_count_cts, retry));
return retry;
}
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index 97eca86a4af0..410efe620c57 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -33,8 +33,8 @@ minstrel_ewma(int old, int new, int weight)
struct minstrel_rate_stats {
/* current / last sampling period attempts/success counters */
- unsigned int attempts, last_attempts;
- unsigned int success, last_success;
+ u16 attempts, last_attempts;
+ u16 success, last_success;
/* total attempts/success counters */
u64 att_hist, succ_hist;
@@ -46,8 +46,8 @@ struct minstrel_rate_stats {
unsigned int cur_prob, probability;
/* maximum retry counts */
- unsigned int retry_count;
- unsigned int retry_count_rtscts;
+ u8 retry_count;
+ u8 retry_count_rtscts;
u8 sample_skipped;
bool retry_updated;
@@ -55,14 +55,15 @@ struct minstrel_rate_stats {
struct minstrel_rate {
int bitrate;
- int rix;
+
+ s8 rix;
+ u8 retry_count_cts;
+ u8 adjusted_retry_count;
unsigned int perfect_tx_time;
unsigned int ack_time;
int sample_limit;
- unsigned int retry_count_cts;
- unsigned int adjusted_retry_count;
struct minstrel_rate_stats stats;
};
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 683b10f46505..3d79d498e7f6 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -361,9 +361,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
u16 known = local->hw.radiotap_vht_details;
rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT);
- /* known field - how to handle 80+80? */
- if (status->vht_flag & RX_VHT_FLAG_80P80MHZ)
- known &= ~IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;
put_unaligned_le16(known, pos);
pos += 2;
/* flags */
@@ -378,8 +375,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
/* bandwidth */
if (status->vht_flag & RX_VHT_FLAG_80MHZ)
*pos++ = 4;
- else if (status->vht_flag & RX_VHT_FLAG_80P80MHZ)
- *pos++ = 0; /* marked not known above */
else if (status->vht_flag & RX_VHT_FLAG_160MHZ)
*pos++ = 11;
else if (status->flag & RX_FLAG_40MHZ)
@@ -2314,6 +2309,15 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
return RX_DROP_MONITOR;
+ if (rx->sta) {
+ /* The security index has the same property as needed
+ * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
+ * for non-QoS-data frames. Here we know it's a data
+ * frame, so count MSDUs.
+ */
+ rx->sta->rx_msdu[rx->security_idx]++;
+ }
+
/*
* Send unexpected-4addr-frame event to hostapd. For older versions,
* also drop the frame to cooked monitor interfaces.
@@ -2598,7 +2602,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: {
struct ieee80211_supported_band *sband;
u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth;
- enum ieee80211_sta_rx_bandwidth new_bw;
+ enum ieee80211_sta_rx_bandwidth max_bw, new_bw;
/* If it doesn't support 40 MHz it can't change ... */
if (!(rx->sta->sta.ht_cap.cap &
@@ -2606,13 +2610,18 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
goto handled;
if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ)
- new_bw = IEEE80211_STA_RX_BW_20;
+ max_bw = IEEE80211_STA_RX_BW_20;
else
- new_bw = ieee80211_sta_cur_vht_bw(rx->sta);
+ max_bw = ieee80211_sta_cap_rx_bw(rx->sta);
+
+ /* set cur_max_bandwidth and recalc sta bw */
+ rx->sta->cur_max_bandwidth = max_bw;
+ new_bw = ieee80211_sta_cur_vht_bw(rx->sta);
if (rx->sta->sta.bandwidth == new_bw)
goto handled;
+ rx->sta->sta.bandwidth = new_bw;
sband = rx->local->hw.wiphy->bands[status->band];
rate_control_rate_update(local, sband, rx->sta,
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index ae842678b629..7807fa42ed3f 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -416,7 +416,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local,
ieee80211_offchannel_stop_vifs(local);
/* ensure nullfunc is transmitted before leaving operating channel */
- ieee80211_flush_queues(local, NULL);
+ ieee80211_flush_queues(local, NULL, false);
ieee80211_configure_filter(local);
@@ -432,7 +432,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local,
static bool ieee80211_can_scan(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
- if (local->radar_detect_enabled)
+ if (ieee80211_is_radar_required(local))
return false;
if (!list_empty(&local->roc_list))
@@ -505,7 +505,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
lockdep_assert_held(&local->mtx);
- if (local->scan_req)
+ if (local->scan_req || ieee80211_is_radar_required(local))
return -EBUSY;
if (!ieee80211_can_scan(local, sdata)) {
@@ -805,7 +805,7 @@ static void ieee80211_scan_state_resume(struct ieee80211_local *local,
ieee80211_offchannel_stop_vifs(local);
if (local->ops->flush) {
- ieee80211_flush_queues(local, NULL);
+ ieee80211_flush_queues(local, NULL, false);
*next_delay = 0;
} else
*next_delay = HZ / 10;
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index efeba56c913b..06e6ac8cc693 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -34,19 +34,15 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
struct cfg80211_chan_def new_vht_chandef = {};
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
- const struct ieee80211_ht_operation *ht_oper;
int secondary_channel_offset = -1;
sec_chan_offs = elems->sec_chan_offs;
wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
- ht_oper = elems->ht_operation;
if (sta_flags & (IEEE80211_STA_DISABLE_HT |
IEEE80211_STA_DISABLE_40MHZ)) {
sec_chan_offs = NULL;
wide_bw_chansw_ie = NULL;
- /* only used for bandwidth here */
- ht_oper = NULL;
}
if (sta_flags & IEEE80211_STA_DISABLE_VHT)
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index a42f5b2b024d..79383ef0c264 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -116,7 +116,6 @@ static void __cleanup_single_sta(struct sta_info *sta)
clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
atomic_dec(&ps->num_sta_ps);
- sta_info_recalc_tim(sta);
}
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
@@ -625,7 +624,7 @@ static unsigned long ieee80211_tids_for_ac(int ac)
}
}
-void sta_info_recalc_tim(struct sta_info *sta)
+static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending)
{
struct ieee80211_local *local = sta->local;
struct ps_data *ps;
@@ -667,6 +666,9 @@ void sta_info_recalc_tim(struct sta_info *sta)
if (ignore_for_tim == BIT(IEEE80211_NUM_ACS) - 1)
ignore_for_tim = 0;
+ if (ignore_pending)
+ ignore_for_tim = BIT(IEEE80211_NUM_ACS) - 1;
+
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
unsigned long tids;
@@ -695,7 +697,7 @@ void sta_info_recalc_tim(struct sta_info *sta)
else
__bss_tim_clear(ps->tim, id);
- if (local->ops->set_tim) {
+ if (local->ops->set_tim && !WARN_ON(sta->dead)) {
local->tim_in_locked_section = true;
drv_set_tim(local, &sta->sta, indicate_tim);
local->tim_in_locked_section = false;
@@ -705,6 +707,11 @@ out_unlock:
spin_unlock_bh(&local->tim_lock);
}
+void sta_info_recalc_tim(struct sta_info *sta)
+{
+ __sta_info_recalc_tim(sta, false);
+}
+
static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb)
{
struct ieee80211_tx_info *info;
@@ -874,6 +881,7 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct station_info sinfo = {};
int ret;
/*
@@ -887,6 +895,9 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
/* now keys can no longer be reached */
ieee80211_free_sta_keys(local, sta);
+ /* disable TIM bit - last chance to tell driver */
+ __sta_info_recalc_tim(sta, true);
+
sta->dead = true;
local->num_sta--;
@@ -908,7 +919,8 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr);
- cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL);
+ sta_set_sinfo(sta, &sinfo);
+ cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
rate_control_remove_sta_debugfs(sta);
ieee80211_sta_debugfs_remove(sta);
@@ -1243,10 +1255,11 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
* ends the poll/service period.
*/
info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER |
- IEEE80211_TX_CTL_PS_RESPONSE |
IEEE80211_TX_STATUS_EOSP |
IEEE80211_TX_CTL_REQ_TX_STATUS;
+ info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE;
+
if (call_driver)
drv_allow_buffered_frames(local, sta, BIT(tid), 1,
reason, false);
@@ -1395,8 +1408,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
* STA may still remain is PS mode after this frame
* exchange.
*/
- info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER |
- IEEE80211_TX_CTL_PS_RESPONSE;
+ info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+ info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE;
/*
* Use MoreData flag to indicate whether there are
@@ -1743,7 +1756,6 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
struct ieee80211_local *local = sdata->local;
struct rate_control_ref *ref = NULL;
struct timespec uptime;
- u64 packets = 0;
u32 thr = 0;
int i, ac;
@@ -1752,49 +1764,76 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->generation = sdata->local->sta_generation;
- sinfo->filled = STATION_INFO_INACTIVE_TIME |
- STATION_INFO_RX_BYTES64 |
- STATION_INFO_TX_BYTES64 |
- STATION_INFO_RX_PACKETS |
- STATION_INFO_TX_PACKETS |
- STATION_INFO_TX_RETRIES |
- STATION_INFO_TX_FAILED |
- STATION_INFO_TX_BITRATE |
- STATION_INFO_RX_BITRATE |
- STATION_INFO_RX_DROP_MISC |
- STATION_INFO_BSS_PARAM |
- STATION_INFO_CONNECTED_TIME |
- STATION_INFO_STA_FLAGS |
- STATION_INFO_BEACON_LOSS_COUNT;
+ drv_sta_statistics(local, sdata, &sta->sta, sinfo);
+
+ sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME) |
+ BIT(NL80211_STA_INFO_STA_FLAGS) |
+ BIT(NL80211_STA_INFO_BSS_PARAM) |
+ BIT(NL80211_STA_INFO_CONNECTED_TIME) |
+ BIT(NL80211_STA_INFO_RX_DROP_MISC) |
+ BIT(NL80211_STA_INFO_BEACON_LOSS);
ktime_get_ts(&uptime);
sinfo->connected_time = uptime.tv_sec - sta->last_connected;
-
sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
- sinfo->tx_bytes = 0;
- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
- sinfo->tx_bytes += sta->tx_bytes[ac];
- packets += sta->tx_packets[ac];
+
+ if (!(sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES64) |
+ BIT(NL80211_STA_INFO_TX_BYTES)))) {
+ sinfo->tx_bytes = 0;
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ sinfo->tx_bytes += sta->tx_bytes[ac];
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64);
+ }
+
+ if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_PACKETS))) {
+ sinfo->tx_packets = 0;
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ sinfo->tx_packets += sta->tx_packets[ac];
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
+ }
+
+ if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) |
+ BIT(NL80211_STA_INFO_RX_BYTES)))) {
+ sinfo->rx_bytes = sta->rx_bytes;
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
+ }
+
+ if (!(sinfo->filled & BIT(NL80211_STA_INFO_RX_PACKETS))) {
+ sinfo->rx_packets = sta->rx_packets;
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
+ }
+
+ if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_RETRIES))) {
+ sinfo->tx_retries = sta->tx_retry_count;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_RETRIES);
}
- sinfo->tx_packets = packets;
- sinfo->rx_bytes = sta->rx_bytes;
- sinfo->rx_packets = sta->rx_packets;
- sinfo->tx_retries = sta->tx_retry_count;
- sinfo->tx_failed = sta->tx_retry_failed;
+
+ if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_FAILED))) {
+ sinfo->tx_failed = sta->tx_retry_failed;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
+ }
+
sinfo->rx_dropped_misc = sta->rx_dropped;
sinfo->beacon_loss_count = sta->beacon_loss_count;
if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
(sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
- sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
- if (!local->ops->get_rssi ||
- drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal))
+ if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL))) {
sinfo->signal = (s8)sta->last_signal;
- sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
+ }
+
+ if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))) {
+ sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
+ }
}
- if (sta->chains) {
- sinfo->filled |= STATION_INFO_CHAIN_SIGNAL |
- STATION_INFO_CHAIN_SIGNAL_AVG;
+
+ if (sta->chains &&
+ !(sinfo->filled & (BIT(NL80211_STA_INFO_CHAIN_SIGNAL) |
+ BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL) |
+ BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
sinfo->chains = sta->chains;
for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
@@ -1804,23 +1843,61 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
}
}
- sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
- sta_set_rate_info_rx(sta, &sinfo->rxrate);
+ if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE))) {
+ sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
+ }
+
+ if (!(sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE))) {
+ sta_set_rate_info_rx(sta, &sinfo->rxrate);
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
+ }
+
+ sinfo->filled |= BIT(NL80211_STA_INFO_TID_STATS);
+ for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) {
+ struct cfg80211_tid_stats *tidstats = &sinfo->pertid[i];
+
+ if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) {
+ tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU);
+ tidstats->rx_msdu = sta->rx_msdu[i];
+ }
+
+ if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) {
+ tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU);
+ tidstats->tx_msdu = sta->tx_msdu[i];
+ }
+
+ if (!(tidstats->filled &
+ BIT(NL80211_TID_STATS_TX_MSDU_RETRIES)) &&
+ local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
+ tidstats->filled |=
+ BIT(NL80211_TID_STATS_TX_MSDU_RETRIES);
+ tidstats->tx_msdu_retries = sta->tx_msdu_retries[i];
+ }
+
+ if (!(tidstats->filled &
+ BIT(NL80211_TID_STATS_TX_MSDU_FAILED)) &&
+ local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
+ tidstats->filled |=
+ BIT(NL80211_TID_STATS_TX_MSDU_FAILED);
+ tidstats->tx_msdu_failed = sta->tx_msdu_failed[i];
+ }
+ }
if (ieee80211_vif_is_mesh(&sdata->vif)) {
#ifdef CONFIG_MAC80211_MESH
- sinfo->filled |= STATION_INFO_LLID |
- STATION_INFO_PLID |
- STATION_INFO_PLINK_STATE |
- STATION_INFO_LOCAL_PM |
- STATION_INFO_PEER_PM |
- STATION_INFO_NONPEER_PM;
+ sinfo->filled |= BIT(NL80211_STA_INFO_LLID) |
+ BIT(NL80211_STA_INFO_PLID) |
+ BIT(NL80211_STA_INFO_PLINK_STATE) |
+ BIT(NL80211_STA_INFO_LOCAL_PM) |
+ BIT(NL80211_STA_INFO_PEER_PM) |
+ BIT(NL80211_STA_INFO_NONPEER_PM);
sinfo->llid = sta->llid;
sinfo->plid = sta->plid;
sinfo->plink_state = sta->plink_state;
if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
- sinfo->filled |= STATION_INFO_T_OFFSET;
+ sinfo->filled |= BIT(NL80211_STA_INFO_T_OFFSET);
sinfo->t_offset = sta->t_offset;
}
sinfo->local_pm = sta->local_pm;
@@ -1869,7 +1946,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
thr = drv_get_expected_throughput(local, &sta->sta);
if (thr != 0) {
- sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT;
+ sinfo->filled |= BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT);
sinfo->expected_throughput = thr;
}
}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 4f052bb2a5ad..925e68fe64c7 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -346,6 +346,14 @@ struct ieee80211_tx_latency_stat {
* @cipher_scheme: optional cipher scheme for this station
* @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed
* @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED)
+ * @tx_msdu: MSDUs transmitted to this station, using IEEE80211_NUM_TID
+ * entry for non-QoS frames
+ * @tx_msdu_retries: MSDU retries for transmissions to to this station,
+ * using IEEE80211_NUM_TID entry for non-QoS frames
+ * @tx_msdu_failed: MSDU failures for transmissions to to this station,
+ * using IEEE80211_NUM_TID entry for non-QoS frames
+ * @rx_msdu: MSDUs received from this station, using IEEE80211_NUM_TID
+ * entry for non-QoS frames
*/
struct sta_info {
/* General information, mostly static */
@@ -416,6 +424,10 @@ struct sta_info {
u32 last_rx_rate_vht_flag;
u8 last_rx_rate_vht_nss;
u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
+ u64 tx_msdu[IEEE80211_NUM_TIDS + 1];
+ u64 tx_msdu_retries[IEEE80211_NUM_TIDS + 1];
+ u64 tx_msdu_failed[IEEE80211_NUM_TIDS + 1];
+ u64 rx_msdu[IEEE80211_NUM_TIDS + 1];
/*
* Aggregation information, locked with lock.
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index bb146f377ee4..e679b7c9b160 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -664,13 +664,15 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
struct ieee80211_supported_band *sband;
int retry_count;
int rates_idx;
- bool acked;
+ bool acked, noack_success;
rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
sband = hw->wiphy->bands[info->band];
acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
+ noack_success = !!(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED);
+
if (pubsta) {
struct sta_info *sta;
@@ -696,7 +698,7 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
rate_control_tx_status_noskb(local, sband, sta, info);
}
- if (acked) {
+ if (acked || noack_success) {
local->dot11TransmittedFrameCount++;
if (!pubsta)
local->dot11MulticastTransmittedFrameCount++;
@@ -728,6 +730,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_bar *bar;
int rtap_len;
int shift = 0;
+ int tid = IEEE80211_NUM_TIDS;
rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
@@ -771,7 +774,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
(ieee80211_is_data_qos(fc))) {
- u16 tid, ssn;
+ u16 ssn;
u8 *qc;
qc = ieee80211_get_qos_ctl(hdr);
@@ -780,10 +783,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
& IEEE80211_SCTL_SEQ);
ieee80211_send_bar(&sta->sdata->vif, hdr->addr1,
tid, ssn);
+ } else if (ieee80211_is_data_qos(fc)) {
+ u8 *qc = ieee80211_get_qos_ctl(hdr);
+
+ tid = qc[0] & 0xf;
}
if (!acked && ieee80211_is_back_req(fc)) {
- u16 tid, control;
+ u16 control;
/*
* BAR failed, store the last SSN and retry sending
@@ -811,6 +818,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
if (!acked)
sta->tx_retry_failed++;
sta->tx_retry_count += retry_count;
+
+ if (ieee80211_is_data_present(fc)) {
+ if (!acked)
+ sta->tx_msdu_failed[tid]++;
+ sta->tx_msdu_retries[tid] += retry_count;
+ }
}
rate_control_tx_status(local, sband, sta, skb);
@@ -856,10 +869,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
* Fragments are passed to low-level drivers as separate skbs, so these
* are actually fragments, not frames. Update frame counters only for
* the first fragment of the frame. */
- if (info->flags & IEEE80211_TX_STAT_ACK) {
+ if ((info->flags & IEEE80211_TX_STAT_ACK) ||
+ (info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED)) {
if (ieee80211_is_first_frag(hdr->seq_ctrl)) {
local->dot11TransmittedFrameCount++;
- if (is_multicast_ether_addr(hdr->addr1))
+ if (is_multicast_ether_addr(ieee80211_get_DA(hdr)))
local->dot11MulticastTransmittedFrameCount++;
if (retry_count > 0)
local->dot11RetryCount++;
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index 55ddd77b865d..917088dfd696 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -68,17 +68,24 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata,
ch = ieee80211_get_channel(sdata->local->hw.wiphy, i);
if (ch) {
/* we will be active on the channel */
- u32 flags = IEEE80211_CHAN_DISABLED |
- IEEE80211_CHAN_NO_IR;
cfg80211_chandef_create(&chandef, ch,
- NL80211_CHAN_HT20);
- if (cfg80211_chandef_usable(sdata->local->hw.wiphy,
- &chandef, flags)) {
+ NL80211_CHAN_NO_HT);
+ if (cfg80211_reg_can_beacon(sdata->local->hw.wiphy,
+ &chandef,
+ sdata->wdev.iftype)) {
ch_cnt++;
+ /*
+ * check if the next channel is also part of
+ * this allowed range
+ */
continue;
}
}
+ /*
+ * we've reached the end of a range, with allowed channels
+ * found
+ */
if (ch_cnt) {
u8 *pos = skb_put(skb, 2);
*pos++ = ieee80211_frequency_to_channel(subband_start);
@@ -89,6 +96,15 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata,
}
}
+ /* all channels in the requested range are allowed - add them here */
+ if (ch_cnt) {
+ u8 *pos = skb_put(skb, 2);
+ *pos++ = ieee80211_frequency_to_channel(subband_start);
+ *pos++ = ch_cnt;
+
+ subband_cnt++;
+ }
+
return subband_cnt;
}
@@ -912,7 +928,7 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
rcu_read_unlock();
}
- ieee80211_flush_queues(local, sdata);
+ ieee80211_flush_queues(local, sdata, false);
ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code,
dialog_token, status_code,
@@ -952,7 +968,7 @@ ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev,
*/
ieee80211_stop_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN);
- ieee80211_flush_queues(local, sdata);
+ ieee80211_flush_queues(local, sdata, false);
ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code,
dialog_token, status_code,
@@ -1098,7 +1114,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
*/
tasklet_kill(&local->tx_pending_tasklet);
/* flush a potentially queued teardown packet */
- ieee80211_flush_queues(local, sdata);
+ ieee80211_flush_queues(local, sdata, false);
ret = sta_info_destroy_addr(sdata, peer);
break;
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 8e461a02c6a8..263a9561eb26 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -825,6 +825,13 @@ DECLARE_EVENT_CLASS(sta_event,
)
);
+DEFINE_EVENT(sta_event, drv_sta_statistics,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta),
+ TP_ARGS(local, sdata, sta)
+);
+
DEFINE_EVENT(sta_event, drv_sta_add,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
@@ -1329,32 +1336,6 @@ DEFINE_EVENT(release_evt, drv_allow_buffered_frames,
TP_ARGS(local, sta, tids, num_frames, reason, more_data)
);
-TRACE_EVENT(drv_get_rssi,
- TP_PROTO(struct ieee80211_local *local, struct ieee80211_sta *sta,
- s8 rssi, int ret),
-
- TP_ARGS(local, sta, rssi, ret),
-
- TP_STRUCT__entry(
- LOCAL_ENTRY
- STA_ENTRY
- __field(s8, rssi)
- __field(int, ret)
- ),
-
- TP_fast_assign(
- LOCAL_ASSIGN;
- STA_ASSIGN;
- __entry->rssi = rssi;
- __entry->ret = ret;
- ),
-
- TP_printk(
- LOCAL_PR_FMT STA_PR_FMT " rssi:%d ret:%d",
- LOCAL_PR_ARG, STA_PR_ARG, __entry->rssi, __entry->ret
- )
-);
-
DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata),
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 058686a721a1..02ed6f60629a 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -815,6 +815,8 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
/* for pure STA mode without beacons, we can do it */
hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number);
tx->sdata->sequence_number += 0x10;
+ if (tx->sta)
+ tx->sta->tx_msdu[IEEE80211_NUM_TIDS]++;
return TX_CONTINUE;
}
@@ -831,6 +833,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
qc = ieee80211_get_qos_ctl(hdr);
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
seq = &tx->sta->tid_seq[tid];
+ tx->sta->tx_msdu[tid]++;
hdr->seq_ctrl = cpu_to_le16(*seq);
@@ -3152,7 +3155,7 @@ int ieee80211_reserve_tid(struct ieee80211_sta *pubsta, u8 tid)
}
queues = BIT(sdata->vif.hw_queue[ieee802_1d_to_ac[tid]]);
- __ieee80211_flush_queues(local, sdata, queues);
+ __ieee80211_flush_queues(local, sdata, queues, false);
sta->reserved_tid = tid;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 974ebe70f5b0..fbd37d43dfce 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -578,7 +578,7 @@ ieee80211_get_vif_queues(struct ieee80211_local *local,
void __ieee80211_flush_queues(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- unsigned int queues)
+ unsigned int queues, bool drop)
{
if (!local->ops->flush)
return;
@@ -594,7 +594,7 @@ void __ieee80211_flush_queues(struct ieee80211_local *local,
IEEE80211_QUEUE_STOP_REASON_FLUSH,
false);
- drv_flush(local, sdata, queues, false);
+ drv_flush(local, sdata, queues, drop);
ieee80211_wake_queues_by_reason(&local->hw, queues,
IEEE80211_QUEUE_STOP_REASON_FLUSH,
@@ -602,9 +602,9 @@ void __ieee80211_flush_queues(struct ieee80211_local *local,
}
void ieee80211_flush_queues(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata)
+ struct ieee80211_sub_if_data *sdata, bool drop)
{
- __ieee80211_flush_queues(local, sdata, 0);
+ __ieee80211_flush_queues(local, sdata, 0, drop);
}
void ieee80211_stop_vif_queues(struct ieee80211_local *local,
@@ -1470,10 +1470,12 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
/* Check if any channel in this sband supports at least 80 MHz */
for (i = 0; i < sband->n_channels; i++) {
- if (!(sband->channels[i].flags & IEEE80211_CHAN_NO_80MHZ)) {
- have_80mhz = true;
- break;
- }
+ if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED |
+ IEEE80211_CHAN_NO_80MHZ))
+ continue;
+
+ have_80mhz = true;
+ break;
}
if (sband->vht_cap.vht_supported && have_80mhz) {
@@ -1735,6 +1737,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
struct cfg80211_sched_scan_request *sched_scan_req;
bool sched_scan_stopped = false;
+ /* nothing to do if HW shouldn't run */
+ if (!local->open_count)
+ goto wake_up;
+
#ifdef CONFIG_PM
if (local->suspended)
local->resuming = true;
@@ -1756,9 +1762,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
reconfig_due_to_wowlan = true;
}
#endif
- /* everything else happens only if HW was up & running */
- if (!local->open_count)
- goto wake_up;
/*
* Upon resume hardware can sometimes be goofy due to
@@ -2042,7 +2045,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
* If this is for hw restart things are still running.
* We may want to change that later, however.
*/
- if (!local->suspended || reconfig_due_to_wowlan)
+ if (local->open_count && (!local->suspended || reconfig_due_to_wowlan))
drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART);
if (!local->suspended)
@@ -2054,7 +2057,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mb();
local->resuming = false;
- if (!reconfig_due_to_wowlan)
+ if (local->open_count && !reconfig_due_to_wowlan)
drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND);
list_for_each_entry(sdata, &local->interfaces, list) {
@@ -2538,7 +2541,9 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
ri.mcs = status->rate_idx;
ri.flags |= RATE_INFO_FLAGS_MCS;
if (status->flag & RX_FLAG_40MHZ)
- ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ ri.bw = RATE_INFO_BW_40;
+ else
+ ri.bw = RATE_INFO_BW_20;
if (status->flag & RX_FLAG_SHORT_GI)
ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
} else if (status->flag & RX_FLAG_VHT) {
@@ -2546,13 +2551,13 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
ri.mcs = status->rate_idx;
ri.nss = status->vht_nss;
if (status->flag & RX_FLAG_40MHZ)
- ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
- if (status->vht_flag & RX_VHT_FLAG_80MHZ)
- ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
- if (status->vht_flag & RX_VHT_FLAG_80P80MHZ)
- ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH;
- if (status->vht_flag & RX_VHT_FLAG_160MHZ)
- ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
+ ri.bw = RATE_INFO_BW_40;
+ else if (status->vht_flag & RX_VHT_FLAG_80MHZ)
+ ri.bw = RATE_INFO_BW_80;
+ else if (status->vht_flag & RX_VHT_FLAG_160MHZ)
+ ri.bw = RATE_INFO_BW_160;
+ else
+ ri.bw = RATE_INFO_BW_20;
if (status->flag & RX_FLAG_SHORT_GI)
ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
} else {
@@ -2560,10 +2565,15 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
int shift = 0;
int bitrate;
- if (status->flag & RX_FLAG_10MHZ)
+ if (status->flag & RX_FLAG_10MHZ) {
shift = 1;
- if (status->flag & RX_FLAG_5MHZ)
+ ri.bw = RATE_INFO_BW_10;
+ } else if (status->flag & RX_FLAG_5MHZ) {
shift = 2;
+ ri.bw = RATE_INFO_BW_5;
+ } else {
+ ri.bw = RATE_INFO_BW_20;
+ }
sband = local->hw.wiphy->bands[status->band];
bitrate = sband->bitrates[status->rate_idx].bitrate;
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index bc9e8fc48785..85f9596da07b 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -269,51 +269,54 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
}
-enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
+enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta)
{
- struct ieee80211_sub_if_data *sdata = sta->sdata;
- u32 cap = sta->sta.vht_cap.cap;
- enum ieee80211_sta_rx_bandwidth bw;
+ struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap;
+ u32 cap_width;
- if (!sta->sta.vht_cap.vht_supported) {
- bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
- IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
- goto check_max;
- }
+ if (!vht_cap->vht_supported)
+ return sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
+ IEEE80211_STA_RX_BW_40 :
+ IEEE80211_STA_RX_BW_20;
- switch (sdata->vif.bss_conf.chandef.width) {
- default:
- WARN_ON_ONCE(1);
- /* fall through */
+ cap_width = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+
+ if (cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ||
+ cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
+ return IEEE80211_STA_RX_BW_160;
+
+ return IEEE80211_STA_RX_BW_80;
+}
+
+static enum ieee80211_sta_rx_bandwidth
+ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width)
+{
+ switch (width) {
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_20:
- bw = IEEE80211_STA_RX_BW_20;
- break;
+ return IEEE80211_STA_RX_BW_20;
case NL80211_CHAN_WIDTH_40:
- bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
- IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
- break;
+ return IEEE80211_STA_RX_BW_40;
+ case NL80211_CHAN_WIDTH_80:
+ return IEEE80211_STA_RX_BW_80;
case NL80211_CHAN_WIDTH_160:
- if ((cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) ==
- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) {
- bw = IEEE80211_STA_RX_BW_160;
- break;
- }
- /* fall through */
case NL80211_CHAN_WIDTH_80P80:
- if ((cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) ==
- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
- bw = IEEE80211_STA_RX_BW_160;
- break;
- }
- /* fall through */
- case NL80211_CHAN_WIDTH_80:
- bw = IEEE80211_STA_RX_BW_80;
+ return IEEE80211_STA_RX_BW_160;
+ default:
+ WARN_ON_ONCE(1);
+ return IEEE80211_STA_RX_BW_20;
}
+}
+
+enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ enum ieee80211_sta_rx_bandwidth bw;
+
+ bw = ieee80211_chan_width_to_rx_bw(sdata->vif.bss_conf.chandef.width);
+ bw = min(bw, ieee80211_sta_cap_rx_bw(sta));
+ bw = min(bw, sta->cur_max_bandwidth);
- check_max:
- if (bw > sta->cur_max_bandwidth)
- bw = sta->cur_max_bandwidth;
return bw;
}
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 53dda7728f86..3af0ecf1cc16 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -320,6 +320,20 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work)
rtnl_unlock();
}
+static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
+{
+ struct cfg80211_registered_device *rdev;
+
+ rdev = container_of(work, struct cfg80211_registered_device,
+ sched_scan_stop_wk);
+
+ rtnl_lock();
+
+ __cfg80211_stop_sched_scan(rdev, false);
+
+ rtnl_unlock();
+}
+
/* exported functions */
struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -406,6 +420,7 @@ use_default_name:
INIT_LIST_HEAD(&rdev->destroy_list);
spin_lock_init(&rdev->destroy_list_lock);
INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
+ INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk);
#ifdef CONFIG_CFG80211_DEFAULT_PS
rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -560,6 +575,14 @@ int wiphy_register(struct wiphy *wiphy)
BIT(NL80211_IFTYPE_MONITOR)))
wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF;
+ if (WARN_ON((wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) &&
+ (wiphy->regulatory_flags &
+ (REGULATORY_CUSTOM_REG |
+ REGULATORY_STRICT_REG |
+ REGULATORY_COUNTRY_IE_FOLLOW_POWER |
+ REGULATORY_COUNTRY_IE_IGNORE))))
+ return -EINVAL;
+
if (WARN_ON(wiphy->coalesce &&
(!wiphy->coalesce->n_rules ||
!wiphy->coalesce->n_patterns) &&
@@ -778,6 +801,7 @@ void wiphy_unregister(struct wiphy *wiphy)
flush_work(&rdev->event_work);
cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
flush_work(&rdev->destroy_work);
+ flush_work(&rdev->sched_scan_stop_wk);
#ifdef CONFIG_PM
if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
@@ -858,6 +882,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev)
{
struct net_device *dev = wdev->netdev;
+ struct cfg80211_sched_scan_request *sched_scan_req;
ASSERT_RTNL();
ASSERT_WDEV_LOCK(wdev);
@@ -868,7 +893,8 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
- if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev)
+ sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
+ if (sched_scan_req && dev == sched_scan_req->dev)
__cfg80211_stop_sched_scan(rdev, false);
#ifdef CONFIG_CFG80211_WEXT
@@ -943,6 +969,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev;
+ struct cfg80211_sched_scan_request *sched_scan_req;
if (!wdev)
return NOTIFY_DONE;
@@ -1007,8 +1034,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
___cfg80211_scan_done(rdev, false);
}
- if (WARN_ON(rdev->sched_scan_req &&
- rdev->sched_scan_req->dev == wdev->netdev)) {
+ sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
+ if (WARN_ON(sched_scan_req &&
+ sched_scan_req->dev == wdev->netdev)) {
__cfg80211_stop_sched_scan(rdev, false);
}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index faa5b1609aae..801cd49c5a0c 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -36,6 +36,13 @@ struct cfg80211_registered_device {
* the country on the country IE changed. */
char country_ie_alpha2[2];
+ /*
+ * the driver requests the regulatory core to set this regulatory
+ * domain as the wiphy's. Only used for %REGULATORY_WIPHY_SELF_MANAGED
+ * devices using the regulatory_set_wiphy_regd() API
+ */
+ const struct ieee80211_regdomain *requested_regd;
+
/* If a Country IE has been received this tells us the environment
* which its telling us its in. This defaults to ENVIRON_ANY */
enum environment_cap env;
@@ -63,7 +70,7 @@ struct cfg80211_registered_device {
u32 bss_generation;
struct cfg80211_scan_request *scan_req; /* protected by RTNL */
struct sk_buff *scan_msg;
- struct cfg80211_sched_scan_request *sched_scan_req;
+ struct cfg80211_sched_scan_request __rcu *sched_scan_req;
unsigned long suspend_at;
struct work_struct scan_done_wk;
struct work_struct sched_scan_results_wk;
@@ -84,6 +91,8 @@ struct cfg80211_registered_device {
struct list_head destroy_list;
struct work_struct destroy_work;
+ struct work_struct sched_scan_stop_wk;
+
/* must be last because of the way we do wiphy_priv(),
* and it should at least be aligned to NETDEV_ALIGN */
struct wiphy wiphy __aligned(NETDEV_ALIGN);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 7ca4b5133123..c5661c5ad8f3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -59,13 +59,13 @@ enum nl80211_multicast_groups {
};
static const struct genl_multicast_group nl80211_mcgrps[] = {
- [NL80211_MCGRP_CONFIG] = { .name = "config", },
- [NL80211_MCGRP_SCAN] = { .name = "scan", },
- [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", },
- [NL80211_MCGRP_MLME] = { .name = "mlme", },
- [NL80211_MCGRP_VENDOR] = { .name = "vendor", },
+ [NL80211_MCGRP_CONFIG] = { .name = NL80211_MULTICAST_GROUP_CONFIG },
+ [NL80211_MCGRP_SCAN] = { .name = NL80211_MULTICAST_GROUP_SCAN },
+ [NL80211_MCGRP_REGULATORY] = { .name = NL80211_MULTICAST_GROUP_REG },
+ [NL80211_MCGRP_MLME] = { .name = NL80211_MULTICAST_GROUP_MLME },
+ [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR },
#ifdef CONFIG_NL80211_TESTMODE
- [NL80211_MCGRP_TESTMODE] = { .name = "testmode", }
+ [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE }
#endif
};
@@ -396,6 +396,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
[NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
[NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN },
+ [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
};
/* policy for the key attributes */
@@ -1087,6 +1088,11 @@ static int nl80211_send_wowlan(struct sk_buff *msg,
return -ENOBUFS;
}
+ if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) &&
+ nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT,
+ rdev->wiphy.wowlan->max_nd_match_sets))
+ return -ENOBUFS;
+
if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
return -ENOBUFS;
@@ -1701,6 +1707,15 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
rdev->wiphy.max_num_csa_counters))
goto nla_put_failure;
+ if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
+ nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
+ goto nla_put_failure;
+
+ if (nla_put(msg, NL80211_ATTR_EXT_FEATURES,
+ sizeof(rdev->wiphy.ext_features),
+ rdev->wiphy.ext_features))
+ goto nla_put_failure;
+
/* done */
state->split_start = 0;
break;
@@ -3563,6 +3578,7 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
struct nlattr *rate;
u32 bitrate;
u16 bitrate_compat;
+ enum nl80211_attrs rate_flg;
rate = nla_nest_start(msg, attr);
if (!rate)
@@ -3579,12 +3595,36 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
return false;
+ switch (info->bw) {
+ case RATE_INFO_BW_5:
+ rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH;
+ break;
+ case RATE_INFO_BW_10:
+ rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH;
+ break;
+ default:
+ WARN_ON(1);
+ /* fall through */
+ case RATE_INFO_BW_20:
+ rate_flg = 0;
+ break;
+ case RATE_INFO_BW_40:
+ rate_flg = NL80211_RATE_INFO_40_MHZ_WIDTH;
+ break;
+ case RATE_INFO_BW_80:
+ rate_flg = NL80211_RATE_INFO_80_MHZ_WIDTH;
+ break;
+ case RATE_INFO_BW_160:
+ rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
+ break;
+ }
+
+ if (rate_flg && nla_put_flag(msg, rate_flg))
+ return false;
+
if (info->flags & RATE_INFO_FLAGS_MCS) {
if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
return false;
- if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
- nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
- return false;
if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
return false;
@@ -3593,18 +3633,6 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
return false;
if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
return false;
- if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
- nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
- return false;
- if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH &&
- nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH))
- return false;
- if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH &&
- nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH))
- return false;
- if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH &&
- nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH))
- return false;
if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
return false;
@@ -3640,8 +3668,8 @@ static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
return true;
}
-static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
- int flags,
+static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
+ u32 seq, int flags,
struct cfg80211_registered_device *rdev,
struct net_device *dev,
const u8 *mac_addr, struct station_info *sinfo)
@@ -3649,7 +3677,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
void *hdr;
struct nlattr *sinfoattr, *bss_param;
- hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_STATION);
+ hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
if (!hdr)
return -1;
@@ -3661,115 +3689,77 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
if (!sinfoattr)
goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_CONNECTED_TIME) &&
- nla_put_u32(msg, NL80211_STA_INFO_CONNECTED_TIME,
- sinfo->connected_time))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_INACTIVE_TIME) &&
- nla_put_u32(msg, NL80211_STA_INFO_INACTIVE_TIME,
- sinfo->inactive_time))
- goto nla_put_failure;
- if ((sinfo->filled & (STATION_INFO_RX_BYTES |
- STATION_INFO_RX_BYTES64)) &&
+
+#define PUT_SINFO(attr, memb, type) do { \
+ if (sinfo->filled & BIT(NL80211_STA_INFO_ ## attr) && \
+ nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
+ sinfo->memb)) \
+ goto nla_put_failure; \
+ } while (0)
+
+ PUT_SINFO(CONNECTED_TIME, connected_time, u32);
+ PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
+
+ if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) |
+ BIT(NL80211_STA_INFO_RX_BYTES64)) &&
nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
(u32)sinfo->rx_bytes))
goto nla_put_failure;
- if ((sinfo->filled & (STATION_INFO_TX_BYTES |
- STATION_INFO_TX_BYTES64)) &&
+
+ if (sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES) |
+ BIT(NL80211_STA_INFO_TX_BYTES64)) &&
nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
(u32)sinfo->tx_bytes))
goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_RX_BYTES64) &&
- nla_put_u64(msg, NL80211_STA_INFO_RX_BYTES64,
- sinfo->rx_bytes))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_TX_BYTES64) &&
- nla_put_u64(msg, NL80211_STA_INFO_TX_BYTES64,
- sinfo->tx_bytes))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_LLID) &&
- nla_put_u16(msg, NL80211_STA_INFO_LLID, sinfo->llid))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_PLID) &&
- nla_put_u16(msg, NL80211_STA_INFO_PLID, sinfo->plid))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_PLINK_STATE) &&
- nla_put_u8(msg, NL80211_STA_INFO_PLINK_STATE,
- sinfo->plink_state))
- goto nla_put_failure;
+
+ PUT_SINFO(RX_BYTES64, rx_bytes, u64);
+ PUT_SINFO(TX_BYTES64, tx_bytes, u64);
+ PUT_SINFO(LLID, llid, u16);
+ PUT_SINFO(PLID, plid, u16);
+ PUT_SINFO(PLINK_STATE, plink_state, u8);
+
switch (rdev->wiphy.signal_type) {
case CFG80211_SIGNAL_TYPE_MBM:
- if ((sinfo->filled & STATION_INFO_SIGNAL) &&
- nla_put_u8(msg, NL80211_STA_INFO_SIGNAL,
- sinfo->signal))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_SIGNAL_AVG) &&
- nla_put_u8(msg, NL80211_STA_INFO_SIGNAL_AVG,
- sinfo->signal_avg))
- goto nla_put_failure;
+ PUT_SINFO(SIGNAL, signal, u8);
+ PUT_SINFO(SIGNAL_AVG, signal_avg, u8);
break;
default:
break;
}
- if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL) {
+ if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL)) {
if (!nl80211_put_signal(msg, sinfo->chains,
sinfo->chain_signal,
NL80211_STA_INFO_CHAIN_SIGNAL))
goto nla_put_failure;
}
- if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL_AVG) {
+ if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
if (!nl80211_put_signal(msg, sinfo->chains,
sinfo->chain_signal_avg,
NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
goto nla_put_failure;
}
- if (sinfo->filled & STATION_INFO_TX_BITRATE) {
+ if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
NL80211_STA_INFO_TX_BITRATE))
goto nla_put_failure;
}
- if (sinfo->filled & STATION_INFO_RX_BITRATE) {
+ if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) {
if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
NL80211_STA_INFO_RX_BITRATE))
goto nla_put_failure;
}
- if ((sinfo->filled & STATION_INFO_RX_PACKETS) &&
- nla_put_u32(msg, NL80211_STA_INFO_RX_PACKETS,
- sinfo->rx_packets))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_TX_PACKETS) &&
- nla_put_u32(msg, NL80211_STA_INFO_TX_PACKETS,
- sinfo->tx_packets))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_TX_RETRIES) &&
- nla_put_u32(msg, NL80211_STA_INFO_TX_RETRIES,
- sinfo->tx_retries))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_TX_FAILED) &&
- nla_put_u32(msg, NL80211_STA_INFO_TX_FAILED,
- sinfo->tx_failed))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_EXPECTED_THROUGHPUT) &&
- nla_put_u32(msg, NL80211_STA_INFO_EXPECTED_THROUGHPUT,
- sinfo->expected_throughput))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) &&
- nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS,
- sinfo->beacon_loss_count))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_LOCAL_PM) &&
- nla_put_u32(msg, NL80211_STA_INFO_LOCAL_PM,
- sinfo->local_pm))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_PEER_PM) &&
- nla_put_u32(msg, NL80211_STA_INFO_PEER_PM,
- sinfo->peer_pm))
- goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_NONPEER_PM) &&
- nla_put_u32(msg, NL80211_STA_INFO_NONPEER_PM,
- sinfo->nonpeer_pm))
- goto nla_put_failure;
- if (sinfo->filled & STATION_INFO_BSS_PARAM) {
+
+ PUT_SINFO(RX_PACKETS, rx_packets, u32);
+ PUT_SINFO(TX_PACKETS, tx_packets, u32);
+ PUT_SINFO(TX_RETRIES, tx_retries, u32);
+ PUT_SINFO(TX_FAILED, tx_failed, u32);
+ PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32);
+ PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32);
+ PUT_SINFO(LOCAL_PM, local_pm, u32);
+ PUT_SINFO(PEER_PM, peer_pm, u32);
+ PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
+
+ if (sinfo->filled & BIT(NL80211_STA_INFO_BSS_PARAM)) {
bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
if (!bss_param)
goto nla_put_failure;
@@ -3788,18 +3778,62 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
nla_nest_end(msg, bss_param);
}
- if ((sinfo->filled & STATION_INFO_STA_FLAGS) &&
+ if ((sinfo->filled & BIT(NL80211_STA_INFO_STA_FLAGS)) &&
nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
sizeof(struct nl80211_sta_flag_update),
&sinfo->sta_flags))
goto nla_put_failure;
- if ((sinfo->filled & STATION_INFO_T_OFFSET) &&
- nla_put_u64(msg, NL80211_STA_INFO_T_OFFSET,
- sinfo->t_offset))
- goto nla_put_failure;
+
+ PUT_SINFO(T_OFFSET, t_offset, u64);
+ PUT_SINFO(RX_DROP_MISC, rx_dropped_misc, u64);
+ PUT_SINFO(BEACON_RX, rx_beacon, u64);
+ PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
+
+#undef PUT_SINFO
+
+ if (sinfo->filled & BIT(NL80211_STA_INFO_TID_STATS)) {
+ struct nlattr *tidsattr;
+ int tid;
+
+ tidsattr = nla_nest_start(msg, NL80211_STA_INFO_TID_STATS);
+ if (!tidsattr)
+ goto nla_put_failure;
+
+ for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
+ struct cfg80211_tid_stats *tidstats;
+ struct nlattr *tidattr;
+
+ tidstats = &sinfo->pertid[tid];
+
+ if (!tidstats->filled)
+ continue;
+
+ tidattr = nla_nest_start(msg, tid + 1);
+ if (!tidattr)
+ goto nla_put_failure;
+
+#define PUT_TIDVAL(attr, memb, type) do { \
+ if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \
+ nla_put_ ## type(msg, NL80211_TID_STATS_ ## attr, \
+ tidstats->memb)) \
+ goto nla_put_failure; \
+ } while (0)
+
+ PUT_TIDVAL(RX_MSDU, rx_msdu, u64);
+ PUT_TIDVAL(TX_MSDU, tx_msdu, u64);
+ PUT_TIDVAL(TX_MSDU_RETRIES, tx_msdu_retries, u64);
+ PUT_TIDVAL(TX_MSDU_FAILED, tx_msdu_failed, u64);
+
+#undef PUT_TIDVAL
+ nla_nest_end(msg, tidattr);
+ }
+
+ nla_nest_end(msg, tidsattr);
+ }
+
nla_nest_end(msg, sinfoattr);
- if ((sinfo->filled & STATION_INFO_ASSOC_REQ_IES) &&
+ if (sinfo->assoc_req_ies_len &&
nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
sinfo->assoc_req_ies))
goto nla_put_failure;
@@ -3844,7 +3878,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
if (err)
goto out_err;
- if (nl80211_send_station(skb,
+ if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
rdev, wdev->netdev, mac_addr,
@@ -3891,7 +3925,8 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
if (!msg)
return -ENOMEM;
- if (nl80211_send_station(msg, info->snd_portid, info->snd_seq, 0,
+ if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION,
+ info->snd_portid, info->snd_seq, 0,
rdev, dev, mac_addr, &sinfo) < 0) {
nlmsg_free(msg);
return -ENOBUFS;
@@ -5327,42 +5362,20 @@ static int nl80211_update_mesh_config(struct sk_buff *skb,
return err;
}
-static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom,
+ struct sk_buff *msg)
{
- const struct ieee80211_regdomain *regdom;
- struct sk_buff *msg;
- void *hdr = NULL;
struct nlattr *nl_reg_rules;
unsigned int i;
- if (!cfg80211_regdomain)
- return -EINVAL;
-
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!msg)
- return -ENOBUFS;
-
- hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
- NL80211_CMD_GET_REG);
- if (!hdr)
- goto put_failure;
-
- if (reg_last_request_cell_base() &&
- nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
- NL80211_USER_REG_HINT_CELL_BASE))
- goto nla_put_failure;
-
- rcu_read_lock();
- regdom = rcu_dereference(cfg80211_regdomain);
-
if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
(regdom->dfs_region &&
nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
- goto nla_put_failure_rcu;
+ goto nla_put_failure;
nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
if (!nl_reg_rules)
- goto nla_put_failure_rcu;
+ goto nla_put_failure;
for (i = 0; i < regdom->n_reg_rules; i++) {
struct nlattr *nl_reg_rule;
@@ -5377,7 +5390,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
nl_reg_rule = nla_nest_start(msg, i);
if (!nl_reg_rule)
- goto nla_put_failure_rcu;
+ goto nla_put_failure;
max_bandwidth_khz = freq_range->max_bandwidth_khz;
if (!max_bandwidth_khz)
@@ -5398,13 +5411,74 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
power_rule->max_eirp) ||
nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
reg_rule->dfs_cac_ms))
- goto nla_put_failure_rcu;
+ goto nla_put_failure;
nla_nest_end(msg, nl_reg_rule);
}
- rcu_read_unlock();
nla_nest_end(msg, nl_reg_rules);
+ return 0;
+
+nla_put_failure:
+ return -EMSGSIZE;
+}
+
+static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
+{
+ const struct ieee80211_regdomain *regdom = NULL;
+ struct cfg80211_registered_device *rdev;
+ struct wiphy *wiphy = NULL;
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOBUFS;
+
+ hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
+ NL80211_CMD_GET_REG);
+ if (!hdr)
+ goto put_failure;
+
+ if (info->attrs[NL80211_ATTR_WIPHY]) {
+ bool self_managed;
+
+ rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
+ if (IS_ERR(rdev)) {
+ nlmsg_free(msg);
+ return PTR_ERR(rdev);
+ }
+
+ wiphy = &rdev->wiphy;
+ self_managed = wiphy->regulatory_flags &
+ REGULATORY_WIPHY_SELF_MANAGED;
+ regdom = get_wiphy_regdom(wiphy);
+
+ /* a self-managed-reg device must have a private regdom */
+ if (WARN_ON(!regdom && self_managed)) {
+ nlmsg_free(msg);
+ return -EINVAL;
+ }
+
+ if (regdom &&
+ nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
+ goto nla_put_failure;
+ }
+
+ if (!wiphy && reg_last_request_cell_base() &&
+ nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
+ NL80211_USER_REG_HINT_CELL_BASE))
+ goto nla_put_failure;
+
+ rcu_read_lock();
+
+ if (!regdom)
+ regdom = rcu_dereference(cfg80211_regdomain);
+
+ if (nl80211_put_regdom(regdom, msg))
+ goto nla_put_failure_rcu;
+
+ rcu_read_unlock();
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
@@ -5418,6 +5492,83 @@ put_failure:
return -EMSGSIZE;
}
+static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
+ u32 seq, int flags, struct wiphy *wiphy,
+ const struct ieee80211_regdomain *regdom)
+{
+ void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
+ NL80211_CMD_GET_REG);
+
+ if (!hdr)
+ return -1;
+
+ genl_dump_check_consistent(cb, hdr, &nl80211_fam);
+
+ if (nl80211_put_regdom(regdom, msg))
+ goto nla_put_failure;
+
+ if (!wiphy && reg_last_request_cell_base() &&
+ nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
+ NL80211_USER_REG_HINT_CELL_BASE))
+ goto nla_put_failure;
+
+ if (wiphy &&
+ nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
+ goto nla_put_failure;
+
+ if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
+ nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
+ goto nla_put_failure;
+
+ return genlmsg_end(msg, hdr);
+
+nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
+}
+
+static int nl80211_get_reg_dump(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ const struct ieee80211_regdomain *regdom = NULL;
+ struct cfg80211_registered_device *rdev;
+ int err, reg_idx, start = cb->args[2];
+
+ rtnl_lock();
+
+ if (cfg80211_regdomain && start == 0) {
+ err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
+ NLM_F_MULTI, NULL,
+ rtnl_dereference(cfg80211_regdomain));
+ if (err < 0)
+ goto out_err;
+ }
+
+ /* the global regdom is idx 0 */
+ reg_idx = 1;
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ regdom = get_wiphy_regdom(&rdev->wiphy);
+ if (!regdom)
+ continue;
+
+ if (++reg_idx <= start)
+ continue;
+
+ err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
+ NLM_F_MULTI, &rdev->wiphy, regdom);
+ if (err < 0) {
+ reg_idx--;
+ break;
+ }
+ }
+
+ cb->args[2] = reg_idx;
+ err = skb->len;
+out_err:
+ rtnl_unlock();
+ return err;
+}
+
static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
@@ -6069,6 +6220,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_sched_scan_request *sched_scan_req;
int err;
if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
@@ -6078,27 +6230,32 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
if (rdev->sched_scan_req)
return -EINPROGRESS;
- rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
- info->attrs);
- err = PTR_ERR_OR_ZERO(rdev->sched_scan_req);
+ sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
+ info->attrs);
+
+ err = PTR_ERR_OR_ZERO(sched_scan_req);
if (err)
goto out_err;
- err = rdev_sched_scan_start(rdev, dev, rdev->sched_scan_req);
+ err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
if (err)
goto out_free;
- rdev->sched_scan_req->dev = dev;
- rdev->sched_scan_req->wiphy = &rdev->wiphy;
+ sched_scan_req->dev = dev;
+ sched_scan_req->wiphy = &rdev->wiphy;
+
+ if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
+ sched_scan_req->owner_nlportid = info->snd_portid;
+
+ rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
nl80211_send_sched_scan(rdev, dev,
NL80211_CMD_START_SCHED_SCAN);
return 0;
out_free:
- kfree(rdev->sched_scan_req);
+ kfree(sched_scan_req);
out_err:
- rdev->sched_scan_req = NULL;
return err;
}
@@ -6481,12 +6638,17 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
}
static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
- int flags, struct net_device *dev,
- struct survey_info *survey)
+ int flags, struct net_device *dev,
+ bool allow_radio_stats,
+ struct survey_info *survey)
{
void *hdr;
struct nlattr *infoattr;
+ /* skip radio stats if userspace didn't request them */
+ if (!survey->channel && !allow_radio_stats)
+ return 0;
+
hdr = nl80211hdr_put(msg, portid, seq, flags,
NL80211_CMD_NEW_SURVEY_RESULTS);
if (!hdr)
@@ -6499,7 +6661,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
if (!infoattr)
goto nla_put_failure;
- if (nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
+ if (survey->channel &&
+ nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
survey->channel->center_freq))
goto nla_put_failure;
@@ -6509,25 +6672,29 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
if ((survey->filled & SURVEY_INFO_IN_USE) &&
nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE))
goto nla_put_failure;
- if ((survey->filled & SURVEY_INFO_CHANNEL_TIME) &&
- nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME,
- survey->channel_time))
+ if ((survey->filled & SURVEY_INFO_TIME) &&
+ nla_put_u64(msg, NL80211_SURVEY_INFO_TIME,
+ survey->time))
+ goto nla_put_failure;
+ if ((survey->filled & SURVEY_INFO_TIME_BUSY) &&
+ nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_BUSY,
+ survey->time_busy))
goto nla_put_failure;
- if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY) &&
- nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
- survey->channel_time_busy))
+ if ((survey->filled & SURVEY_INFO_TIME_EXT_BUSY) &&
+ nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY,
+ survey->time_ext_busy))
goto nla_put_failure;
- if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) &&
- nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
- survey->channel_time_ext_busy))
+ if ((survey->filled & SURVEY_INFO_TIME_RX) &&
+ nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_RX,
+ survey->time_rx))
goto nla_put_failure;
- if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_RX) &&
- nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
- survey->channel_time_rx))
+ if ((survey->filled & SURVEY_INFO_TIME_TX) &&
+ nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_TX,
+ survey->time_tx))
goto nla_put_failure;
- if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_TX) &&
- nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
- survey->channel_time_tx))
+ if ((survey->filled & SURVEY_INFO_TIME_SCAN) &&
+ nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_SCAN,
+ survey->time_scan))
goto nla_put_failure;
nla_nest_end(msg, infoattr);
@@ -6539,19 +6706,22 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
return -EMSGSIZE;
}
-static int nl80211_dump_survey(struct sk_buff *skb,
- struct netlink_callback *cb)
+static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
{
struct survey_info survey;
struct cfg80211_registered_device *rdev;
struct wireless_dev *wdev;
int survey_idx = cb->args[2];
int res;
+ bool radio_stats;
res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
if (res)
return res;
+ /* prepare_wdev_dump parsed the attributes */
+ radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
+
if (!wdev->netdev) {
res = -EINVAL;
goto out_err;
@@ -6569,13 +6739,9 @@ static int nl80211_dump_survey(struct sk_buff *skb,
if (res)
goto out_err;
- /* Survey without a channel doesn't make sense */
- if (!survey.channel) {
- res = -EINVAL;
- goto out;
- }
-
- if (survey.channel->flags & IEEE80211_CHAN_DISABLED) {
+ /* don't send disabled channels, but do send non-channel data */
+ if (survey.channel &&
+ survey.channel->flags & IEEE80211_CHAN_DISABLED) {
survey_idx++;
continue;
}
@@ -6583,7 +6749,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
if (nl80211_send_survey(skb,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
- wdev->netdev, &survey) < 0)
+ wdev->netdev, radio_stats, &survey) < 0)
goto out;
survey_idx++;
}
@@ -8599,6 +8765,48 @@ static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
return 0;
}
+static int nl80211_send_wowlan_nd(struct sk_buff *msg,
+ struct cfg80211_sched_scan_request *req)
+{
+ struct nlattr *nd, *freqs, *matches, *match;
+ int i;
+
+ if (!req)
+ return 0;
+
+ nd = nla_nest_start(msg, NL80211_WOWLAN_TRIG_NET_DETECT);
+ if (!nd)
+ return -ENOBUFS;
+
+ if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, req->interval))
+ return -ENOBUFS;
+
+ freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
+ if (!freqs)
+ return -ENOBUFS;
+
+ for (i = 0; i < req->n_channels; i++)
+ nla_put_u32(msg, i, req->channels[i]->center_freq);
+
+ nla_nest_end(msg, freqs);
+
+ if (req->n_match_sets) {
+ matches = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
+ for (i = 0; i < req->n_match_sets; i++) {
+ match = nla_nest_start(msg, i);
+ nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
+ req->match_sets[i].ssid.ssid_len,
+ req->match_sets[i].ssid.ssid);
+ nla_nest_end(msg, match);
+ }
+ nla_nest_end(msg, matches);
+ }
+
+ nla_nest_end(msg, nd);
+
+ return 0;
+}
+
static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -8656,6 +8864,11 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
rdev->wiphy.wowlan_config->tcp))
goto nla_put_failure;
+ if (nl80211_send_wowlan_nd(
+ msg,
+ rdev->wiphy.wowlan_config->nd_config))
+ goto nla_put_failure;
+
nla_nest_end(msg, nl_wowlan);
}
@@ -10225,7 +10438,8 @@ static const struct genl_ops nl80211_ops[] = {
},
{
.cmd = NL80211_CMD_GET_REG,
- .doit = nl80211_get_reg,
+ .doit = nl80211_get_reg_do,
+ .dumpit = nl80211_get_reg_dump,
.policy = nl80211_policy,
.internal_flags = NL80211_FLAG_NEED_RTNL,
/* can be retrieved by unprivileged users */
@@ -10939,25 +11153,9 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
NL80211_MCGRP_SCAN, GFP_KERNEL);
}
-/*
- * This can happen on global regulatory changes or device specific settings
- * based on custom world regulatory domains.
- */
-void nl80211_send_reg_change_event(struct regulatory_request *request)
+static bool nl80211_reg_change_event_fill(struct sk_buff *msg,
+ struct regulatory_request *request)
{
- struct sk_buff *msg;
- void *hdr;
-
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!msg)
- return;
-
- hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE);
- if (!hdr) {
- nlmsg_free(msg);
- return;
- }
-
/* Userspace can always count this one always being set */
if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
goto nla_put_failure;
@@ -10983,8 +11181,46 @@ void nl80211_send_reg_change_event(struct regulatory_request *request)
goto nla_put_failure;
}
- if (request->wiphy_idx != WIPHY_IDX_INVALID &&
- nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
+ if (request->wiphy_idx != WIPHY_IDX_INVALID) {
+ struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx);
+
+ if (wiphy &&
+ nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
+ goto nla_put_failure;
+
+ if (wiphy &&
+ wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
+ nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
+ goto nla_put_failure;
+ }
+
+ return true;
+
+nla_put_failure:
+ return false;
+}
+
+/*
+ * This can happen on global regulatory changes or device specific settings
+ * based on custom regulatory domains.
+ */
+void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
+ struct regulatory_request *request)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ if (nl80211_reg_change_event_fill(msg, request) == false)
goto nla_put_failure;
genlmsg_end(msg, hdr);
@@ -11523,7 +11759,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
if (!msg)
return;
- if (nl80211_send_station(msg, 0, 0, 0,
+ if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0,
rdev, dev, mac_addr, sinfo) < 0) {
nlmsg_free(msg);
return;
@@ -11534,12 +11770,16 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
}
EXPORT_SYMBOL(cfg80211_new_sta);
-void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
+void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr,
+ struct station_info *sinfo, gfp_t gfp)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct sk_buff *msg;
- void *hdr;
+ struct station_info empty_sinfo = {};
+
+ if (!sinfo)
+ sinfo = &empty_sinfo;
trace_cfg80211_del_sta(dev, mac_addr);
@@ -11547,27 +11787,16 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
if (!msg)
return;
- hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_STATION);
- if (!hdr) {
+ if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0,
+ rdev, dev, mac_addr, sinfo) < 0) {
nlmsg_free(msg);
return;
}
- if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
- nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
- goto nla_put_failure;
-
- genlmsg_end(msg, hdr);
-
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
NL80211_MCGRP_MLME, gfp);
- return;
-
- nla_put_failure:
- genlmsg_cancel(msg, hdr);
- nlmsg_free(msg);
}
-EXPORT_SYMBOL(cfg80211_del_sta);
+EXPORT_SYMBOL(cfg80211_del_sta_sinfo);
void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
enum nl80211_connect_failed_reason reason,
@@ -12471,6 +12700,13 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
bool schedule_destroy_work = false;
+ bool schedule_scan_stop = false;
+ struct cfg80211_sched_scan_request *sched_scan_req =
+ rcu_dereference(rdev->sched_scan_req);
+
+ if (sched_scan_req && notify->portid &&
+ sched_scan_req->owner_nlportid == notify->portid)
+ schedule_scan_stop = true;
list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) {
cfg80211_mlme_unregister_socket(wdev, notify->portid);
@@ -12501,6 +12737,12 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
spin_unlock(&rdev->destroy_list_lock);
schedule_work(&rdev->destroy_work);
}
+ } else if (schedule_scan_stop) {
+ sched_scan_req->owner_nlportid = 0;
+
+ if (rdev->ops->sched_scan_stop &&
+ rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
+ schedule_work(&rdev->sched_scan_stop_wk);
}
}
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 7ad70d6f0cc6..84d4edf1d545 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -17,7 +17,21 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u32 cmd);
void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
struct net_device *netdev);
-void nl80211_send_reg_change_event(struct regulatory_request *request);
+void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
+ struct regulatory_request *request);
+
+static inline void
+nl80211_send_reg_change_event(struct regulatory_request *request)
+{
+ nl80211_common_reg_change_event(NL80211_CMD_REG_CHANGE, request);
+}
+
+static inline void
+nl80211_send_wiphy_reg_change_event(struct regulatory_request *request)
+{
+ nl80211_common_reg_change_event(NL80211_CMD_WIPHY_REG_CHANGE, request);
+}
+
void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
const u8 *buf, size_t len, gfp_t gfp);
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 7b8309840d4e..886cc7cb5566 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -109,7 +109,7 @@ static struct regulatory_request core_request_world = {
* protected by RTNL (and can be accessed with RCU protection)
*/
static struct regulatory_request __rcu *last_request =
- (void __rcu *)&core_request_world;
+ (void __force __rcu *)&core_request_world;
/* To trigger userspace events */
static struct platform_device *reg_pdev;
@@ -142,7 +142,7 @@ static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
return rtnl_dereference(cfg80211_regdomain);
}
-static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy)
+const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy)
{
return rtnl_dereference(wiphy->regd);
}
@@ -1307,6 +1307,9 @@ static bool ignore_reg_update(struct wiphy *wiphy,
{
struct regulatory_request *lr = get_last_request();
+ if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+ return true;
+
if (!lr) {
REG_DBG_PRINT("Ignoring regulatory request set by %s "
"since last_request is not set\n",
@@ -1683,8 +1686,12 @@ static void handle_channel_custom(struct wiphy *wiphy,
if (IS_ERR(reg_rule)) {
REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n",
chan->center_freq);
- chan->orig_flags |= IEEE80211_CHAN_DISABLED;
- chan->flags = chan->orig_flags;
+ if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
+ chan->flags |= IEEE80211_CHAN_DISABLED;
+ } else {
+ chan->orig_flags |= IEEE80211_CHAN_DISABLED;
+ chan->flags = chan->orig_flags;
+ }
return;
}
@@ -1709,7 +1716,13 @@ static void handle_channel_custom(struct wiphy *wiphy,
chan->dfs_state = NL80211_DFS_USABLE;
chan->beacon_found = false;
- chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;
+
+ if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+ chan->flags = chan->orig_flags | bw_flags |
+ map_regdom_flags(reg_rule->flags);
+ else
+ chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;
+
chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain);
chan->max_reg_power = chan->max_power =
(int) MBM_TO_DBM(power_rule->max_eirp);
@@ -2095,6 +2108,26 @@ out_free:
reg_free_request(reg_request);
}
+static bool reg_only_self_managed_wiphys(void)
+{
+ struct cfg80211_registered_device *rdev;
+ struct wiphy *wiphy;
+ bool self_managed_found = false;
+
+ ASSERT_RTNL();
+
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ wiphy = &rdev->wiphy;
+ if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+ self_managed_found = true;
+ else
+ return false;
+ }
+
+ /* make sure at least one self-managed wiphy exists */
+ return self_managed_found;
+}
+
/*
* Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_*
* Regulatory hints come on a first come first serve basis and we
@@ -2126,6 +2159,11 @@ static void reg_process_pending_hints(void)
spin_unlock(&reg_requests_lock);
+ if (reg_only_self_managed_wiphys()) {
+ reg_free_request(reg_request);
+ return;
+ }
+
reg_process_hint(reg_request);
}
@@ -2153,11 +2191,52 @@ static void reg_process_pending_beacon_hints(void)
spin_unlock_bh(&reg_pending_beacons_lock);
}
+static void reg_process_self_managed_hints(void)
+{
+ struct cfg80211_registered_device *rdev;
+ struct wiphy *wiphy;
+ const struct ieee80211_regdomain *tmp;
+ const struct ieee80211_regdomain *regd;
+ enum ieee80211_band band;
+ struct regulatory_request request = {};
+
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ wiphy = &rdev->wiphy;
+
+ spin_lock(&reg_requests_lock);
+ regd = rdev->requested_regd;
+ rdev->requested_regd = NULL;
+ spin_unlock(&reg_requests_lock);
+
+ if (regd == NULL)
+ continue;
+
+ tmp = get_wiphy_regdom(wiphy);
+ rcu_assign_pointer(wiphy->regd, regd);
+ rcu_free_regdom(tmp);
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+ handle_band_custom(wiphy, wiphy->bands[band], regd);
+
+ reg_process_ht_flags(wiphy);
+
+ request.wiphy_idx = get_wiphy_idx(wiphy);
+ request.alpha2[0] = regd->alpha2[0];
+ request.alpha2[1] = regd->alpha2[1];
+ request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
+
+ nl80211_send_wiphy_reg_change_event(&request);
+ }
+
+ reg_check_channels();
+}
+
static void reg_todo(struct work_struct *work)
{
rtnl_lock();
reg_process_pending_hints();
reg_process_pending_beacon_hints();
+ reg_process_self_managed_hints();
rtnl_unlock();
}
@@ -2438,6 +2517,8 @@ static void restore_regulatory_settings(bool reset_user)
world_alpha2[1] = cfg80211_world_regdom->alpha2[1];
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+ continue;
if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG)
restore_custom_reg_settings(&rdev->wiphy);
}
@@ -2841,10 +2922,79 @@ int set_regdom(const struct ieee80211_regdomain *rd)
return 0;
}
+static int __regulatory_set_wiphy_regd(struct wiphy *wiphy,
+ struct ieee80211_regdomain *rd)
+{
+ const struct ieee80211_regdomain *regd;
+ const struct ieee80211_regdomain *prev_regd;
+ struct cfg80211_registered_device *rdev;
+
+ if (WARN_ON(!wiphy || !rd))
+ return -EINVAL;
+
+ if (WARN(!(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED),
+ "wiphy should have REGULATORY_WIPHY_SELF_MANAGED\n"))
+ return -EPERM;
+
+ if (WARN(!is_valid_rd(rd), "Invalid regulatory domain detected\n")) {
+ print_regdomain_info(rd);
+ return -EINVAL;
+ }
+
+ regd = reg_copy_regd(rd);
+ if (IS_ERR(regd))
+ return PTR_ERR(regd);
+
+ rdev = wiphy_to_rdev(wiphy);
+
+ spin_lock(&reg_requests_lock);
+ prev_regd = rdev->requested_regd;
+ rdev->requested_regd = regd;
+ spin_unlock(&reg_requests_lock);
+
+ kfree(prev_regd);
+ return 0;
+}
+
+int regulatory_set_wiphy_regd(struct wiphy *wiphy,
+ struct ieee80211_regdomain *rd)
+{
+ int ret = __regulatory_set_wiphy_regd(wiphy, rd);
+
+ if (ret)
+ return ret;
+
+ schedule_work(&reg_work);
+ return 0;
+}
+EXPORT_SYMBOL(regulatory_set_wiphy_regd);
+
+int regulatory_set_wiphy_regd_sync_rtnl(struct wiphy *wiphy,
+ struct ieee80211_regdomain *rd)
+{
+ int ret;
+
+ ASSERT_RTNL();
+
+ ret = __regulatory_set_wiphy_regd(wiphy, rd);
+ if (ret)
+ return ret;
+
+ /* process the request immediately */
+ reg_process_self_managed_hints();
+ return 0;
+}
+EXPORT_SYMBOL(regulatory_set_wiphy_regd_sync_rtnl);
+
void wiphy_regulatory_register(struct wiphy *wiphy)
{
struct regulatory_request *lr;
+ /* self-managed devices ignore external hints */
+ if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+ wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS |
+ REGULATORY_COUNTRY_IE_IGNORE;
+
if (!reg_dev_ignore_cell_hint(wiphy))
reg_num_devs_support_basehint++;
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index 5e48031ccb9a..4b45d6e61d24 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -38,6 +38,7 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
const struct ieee80211_reg_rule *rule);
bool reg_last_request_cell_base(void);
+const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy);
/**
* regulatory_hint_found_beacon - hints a beacon was found on a channel
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index bda39f149810..c705c3e2b751 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -257,7 +257,7 @@ void __cfg80211_sched_scan_results(struct work_struct *wk)
rtnl_lock();
- request = rdev->sched_scan_req;
+ request = rtnl_dereference(rdev->sched_scan_req);
/* we don't have sched_scan_req anymore if the scan is stopping */
if (request) {
@@ -279,7 +279,8 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy)
{
trace_cfg80211_sched_scan_results(wiphy);
/* ignore if we're not scanning */
- if (wiphy_to_rdev(wiphy)->sched_scan_req)
+
+ if (rcu_access_pointer(wiphy_to_rdev(wiphy)->sched_scan_req))
queue_work(cfg80211_wq,
&wiphy_to_rdev(wiphy)->sched_scan_results_wk);
}
@@ -308,6 +309,7 @@ EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
bool driver_initiated)
{
+ struct cfg80211_sched_scan_request *sched_scan_req;
struct net_device *dev;
ASSERT_RTNL();
@@ -315,7 +317,8 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
if (!rdev->sched_scan_req)
return -ENOENT;
- dev = rdev->sched_scan_req->dev;
+ sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
+ dev = sched_scan_req->dev;
if (!driver_initiated) {
int err = rdev_sched_scan_stop(rdev, dev);
@@ -325,8 +328,8 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);
- kfree(rdev->sched_scan_req);
- rdev->sched_scan_req = NULL;
+ RCU_INIT_POINTER(rdev->sched_scan_req, NULL);
+ kfree_rcu(sched_scan_req, rcu_head);
return 0;
}
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index ad38910f7036..b17b3692f8c2 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1604,11 +1604,12 @@ TRACE_EVENT(rdev_return_int_survey_info,
WIPHY_ENTRY
CHAN_ENTRY
__field(int, ret)
- __field(u64, channel_time)
- __field(u64, channel_time_busy)
- __field(u64, channel_time_ext_busy)
- __field(u64, channel_time_rx)
- __field(u64, channel_time_tx)
+ __field(u64, time)
+ __field(u64, time_busy)
+ __field(u64, time_ext_busy)
+ __field(u64, time_rx)
+ __field(u64, time_tx)
+ __field(u64, time_scan)
__field(u32, filled)
__field(s8, noise)
),
@@ -1616,22 +1617,24 @@ TRACE_EVENT(rdev_return_int_survey_info,
WIPHY_ASSIGN;
CHAN_ASSIGN(info->channel);
__entry->ret = ret;
- __entry->channel_time = info->channel_time;
- __entry->channel_time_busy = info->channel_time_busy;
- __entry->channel_time_ext_busy = info->channel_time_ext_busy;
- __entry->channel_time_rx = info->channel_time_rx;
- __entry->channel_time_tx = info->channel_time_tx;
+ __entry->time = info->time;
+ __entry->time_busy = info->time_busy;
+ __entry->time_ext_busy = info->time_ext_busy;
+ __entry->time_rx = info->time_rx;
+ __entry->time_tx = info->time_tx;
+ __entry->time_scan = info->time_scan;
__entry->filled = info->filled;
__entry->noise = info->noise;
),
TP_printk(WIPHY_PR_FMT ", returned: %d, " CHAN_PR_FMT
", channel time: %llu, channel time busy: %llu, "
"channel time extension busy: %llu, channel time rx: %llu, "
- "channel time tx: %llu, filled: %u, noise: %d",
+ "channel time tx: %llu, scan time: %llu, filled: %u, noise: %d",
WIPHY_PR_ARG, __entry->ret, CHAN_PR_ARG,
- __entry->channel_time, __entry->channel_time_busy,
- __entry->channel_time_ext_busy, __entry->channel_time_rx,
- __entry->channel_time_tx, __entry->filled, __entry->noise)
+ __entry->time, __entry->time_busy,
+ __entry->time_ext_busy, __entry->time_rx,
+ __entry->time_tx, __entry->time_scan,
+ __entry->filled, __entry->noise)
);
TRACE_EVENT(rdev_tdls_oper,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index d0ac795445b7..3535e8ade48f 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1073,10 +1073,24 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
if (WARN_ON_ONCE(rate->mcs > 9))
return 0;
- idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH |
- RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 :
- rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 :
- rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0;
+ switch (rate->bw) {
+ case RATE_INFO_BW_160:
+ idx = 3;
+ break;
+ case RATE_INFO_BW_80:
+ idx = 2;
+ break;
+ case RATE_INFO_BW_40:
+ idx = 1;
+ break;
+ case RATE_INFO_BW_5:
+ case RATE_INFO_BW_10:
+ default:
+ WARN_ON(1);
+ /* fall through */
+ case RATE_INFO_BW_20:
+ idx = 0;
+ }
bitrate = base[idx][rate->mcs];
bitrate *= rate->nss;
@@ -1107,8 +1121,7 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate)
modulation = rate->mcs & 7;
streams = (rate->mcs >> 3) + 1;
- bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ?
- 13500000 : 6500000;
+ bitrate = (rate->bw == RATE_INFO_BW_40) ? 13500000 : 6500000;
if (modulation < 4)
bitrate *= (modulation + 1);
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 0f47948c572f..5b24d39d7903 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -1300,7 +1300,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev,
if (err)
return err;
- if (!(sinfo.filled & STATION_INFO_TX_BITRATE))
+ if (!(sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)))
return -EOPNOTSUPP;
rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate);
@@ -1340,7 +1340,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
switch (rdev->wiphy.signal_type) {
case CFG80211_SIGNAL_TYPE_MBM:
- if (sinfo.filled & STATION_INFO_SIGNAL) {
+ if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL)) {
int sig = sinfo.signal;
wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
@@ -1354,7 +1354,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
break;
}
case CFG80211_SIGNAL_TYPE_UNSPEC:
- if (sinfo.filled & STATION_INFO_SIGNAL) {
+ if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL)) {
wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
wstats.qual.level = sinfo.signal;
@@ -1367,9 +1367,9 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
}
wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
- if (sinfo.filled & STATION_INFO_RX_DROP_MISC)
+ if (sinfo.filled & BIT(NL80211_STA_INFO_RX_DROP_MISC))
wstats.discard.misc = sinfo.rx_dropped_misc;
- if (sinfo.filled & STATION_INFO_TX_FAILED)
+ if (sinfo.filled & BIT(NL80211_STA_INFO_TX_FAILED))
wstats.discard.retries = sinfo.tx_failed;
return &wstats;