summaryrefslogtreecommitdiff
path: root/drivers/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/adm8211.c35
-rw-r--r--drivers/net/wireless/at76c50x-usb.c4
-rw-r--r--drivers/net/wireless/at76c50x-usb.h2
-rw-r--r--drivers/net/wireless/ath/ar5523/ar5523.c9
-rw-r--r--drivers/net/wireless/ath/ath.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/Makefile4
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c182
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h65
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c127
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.c50
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.c98
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h132
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c208
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c34
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.c21
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h59
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c2840
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.h29
-rw-r--r--drivers/net/wireless/ath/ath10k/p2p.c156
-rw-r--r--drivers/net/wireless/ath/ath10k/p2p.h28
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c362
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h95
-rw-r--r--drivers/net/wireless/ath/ath10k/rx_desc.h22
-rw-r--r--drivers/net/wireless/ath/ath10k/spectral.c5
-rw-r--r--drivers/net/wireless/ath/ath10k/thermal.c134
-rw-r--r--drivers/net/wireless/ath/ath10k/thermal.h10
-rw-r--r--drivers/net/wireless/ath/ath10k/trace.h22
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c9
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-ops.h194
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c582
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h168
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c312
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h229
-rw-r--r--drivers/net/wireless/ath/ath10k/wow.c321
-rw-r--r--drivers/net/wireless/ath/ath10k/wow.h40
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h1
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c12
-rw-r--r--drivers/net/wireless/ath/ath5k/led.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c16
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c4
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c155
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_phy.c144
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.c740
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.h35
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h8
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c19
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c25
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c20
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c24
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c5
-rw-r--r--drivers/net/wireless/ath/carl9170/fw.c5
-rw-r--r--drivers/net/wireless/ath/carl9170/led.c2
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c27
-rw-r--r--drivers/net/wireless/ath/carl9170/usb.c5
-rw-r--r--drivers/net/wireless/ath/dfs_pattern_detector.c72
-rw-r--r--drivers/net/wireless/ath/dfs_pattern_detector.h4
-rw-r--r--drivers/net/wireless/ath/dfs_pri_detector.c4
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c12
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c4
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile1
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c174
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c115
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c33
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c8
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c105
-rw-r--r--drivers/net/wireless/ath/wil6210/pmc.c375
-rw-r--r--drivers/net/wireless/ath/wil6210/pmc.h27
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c50
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h24
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h33
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.c14
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.h3
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c75
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h50
-rw-r--r--drivers/net/wireless/b43/main.c16
-rw-r--r--drivers/net/wireless/b43legacy/main.c13
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c37
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c521
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/chip.c1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/commonring.c37
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/commonring.h3
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/core.c4
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/debug.c50
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/feature.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/feature.h8
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/firmware.c251
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/firmware.h6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/flowring.c5
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/flowring.h4
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h79
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c44
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/of.c11
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.c203
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/pcie.c200
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio.c17
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c9
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c12
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.c2
-rw-r--r--drivers/net/wireless/brcm80211/include/brcm_hw_ids.h3
-rw-r--r--drivers/net/wireless/cw1200/main.c16
-rw-r--r--drivers/net/wireless/cw1200/sta.c10
-rw-r--r--drivers/net/wireless/iwlegacy/3945-mac.c10
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c16
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig13
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile1
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c33
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-7000.c41
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-8000.c71
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-config.h45
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h15
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h107
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.c34
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.c113
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h22
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex.c103
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex_legacy.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c44
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c21
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h91
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h63
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c23
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c446
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h162
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c16
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c43
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c47
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c1418
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.c33
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tt.c40
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c35
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/utils.c2
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c17
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h57
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/rx.c415
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c145
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c25
-rw-r--r--drivers/net/wireless/libertas/cfg.c13
-rw-r--r--drivers/net/wireless/libertas/cfg.h3
-rw-r--r--drivers/net/wireless/libertas/cmd.h3
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c13
-rw-r--r--drivers/net/wireless/libertas_tf/main.c9
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c77
-rw-r--r--drivers/net/wireless/mediatek/Kconfig10
-rw-r--r--drivers/net/wireless/mediatek/Makefile1
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/Kconfig6
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/Makefile9
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/core.c78
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/debugfs.c172
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/dma.c505
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/dma.h127
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/eeprom.c418
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/eeprom.h151
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/init.c628
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/initvals.h164
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/initvals_phy.h291
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mac.c573
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mac.h178
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/main.c413
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mcu.c534
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mcu.h94
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mt7601u.h390
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/phy.c1251
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/regs.h636
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/trace.c21
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/trace.h400
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/tx.c319
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/usb.c367
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/usb.h77
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/util.c42
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/util.h77
-rw-r--r--drivers/net/wireless/mwifiex/11h.c72
-rw-r--r--drivers/net/wireless/mwifiex/11n.c128
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.c7
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c136
-rw-r--r--drivers/net/wireless/mwifiex/Kconfig2
-rw-r--r--drivers/net/wireless/mwifiex/README6
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c592
-rw-r--r--drivers/net/wireless/mwifiex/cfp.c50
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c368
-rw-r--r--drivers/net/wireless/mwifiex/debugfs.c165
-rw-r--r--drivers/net/wireless/mwifiex/decl.h7
-rw-r--r--drivers/net/wireless/mwifiex/ethtool.c97
-rw-r--r--drivers/net/wireless/mwifiex/fw.h71
-rw-r--r--drivers/net/wireless/mwifiex/ie.c102
-rw-r--r--drivers/net/wireless/mwifiex/init.c54
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h7
-rw-r--r--drivers/net/wireless/mwifiex/join.c254
-rw-r--r--drivers/net/wireless/mwifiex/main.c224
-rw-r--r--drivers/net/wireless/mwifiex/main.h96
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c589
-rw-r--r--drivers/net/wireless/mwifiex/scan.c377
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c458
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c159
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c223
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c194
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c147
-rw-r--r--drivers/net/wireless/mwifiex/sta_rx.c13
-rw-r--r--drivers/net/wireless/mwifiex/sta_tx.c18
-rw-r--r--drivers/net/wireless/mwifiex/tdls.c86
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c51
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c75
-rw-r--r--drivers/net/wireless/mwifiex/uap_event.c112
-rw-r--r--drivers/net/wireless/mwifiex/uap_txrx.c54
-rw-r--r--drivers/net/wireless/mwifiex/usb.c141
-rw-r--r--drivers/net/wireless/mwifiex/util.c84
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c107
-rw-r--r--drivers/net/wireless/mwl8k.c11
-rw-r--r--drivers/net/wireless/p54/fwio.c3
-rw-r--r--drivers/net/wireless/p54/led.c2
-rw-r--r--drivers/net/wireless/p54/main.c18
-rw-r--r--drivers/net/wireless/ray_cs.c2
-rw-r--r--drivers/net/wireless/rndis_wlan.c8
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mac80211.c7
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c13
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h10
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c92
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h5
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800soc.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c22
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c13
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c13
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/dev.c9
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/dev.c6
-rw-r--r--drivers/net/wireless/rtlwifi/Kconfig2
-rw-r--r--drivers/net/wireless/rtlwifi/base.c22
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c7
-rw-r--r--drivers/net/wireless/rtlwifi/core.h3
-rw-r--r--drivers/net/wireless/rtlwifi/regd.c42
-rw-r--r--drivers/net/wireless/rtlwifi/regd.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/dm.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/hw.c20
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/hw.c54
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/mac.c17
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/mac.h5
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/phy.c28
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/rf.c22
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/trx.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/dm.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/fw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/hw.c21
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/dm.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/hw.c13
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/dm.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/fw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/hw.c21
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8821ae/dm.c14
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8821ae/hw.c24
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h1
-rw-r--r--drivers/net/wireless/ti/wl1251/acx.c3
-rw-r--r--drivers/net/wireless/ti/wl1251/main.c12
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c71
-rw-r--r--drivers/net/wireless/ti/wl18xx/reg.h1
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c54
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c12
282 files changed, 21856 insertions, 6808 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 16604bdf5197..a63ab2e83105 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -277,6 +277,7 @@ source "drivers/net/wireless/libertas/Kconfig"
source "drivers/net/wireless/orinoco/Kconfig"
source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/rt2x00/Kconfig"
+source "drivers/net/wireless/mediatek/Kconfig"
source "drivers/net/wireless/rtlwifi/Kconfig"
source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 0c8891686718..6b9e729dd8ac 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -45,6 +45,8 @@ obj-$(CONFIG_IWLWIFI) += iwlwifi/
obj-$(CONFIG_IWLEGACY) += iwlegacy/
obj-$(CONFIG_RT2X00) += rt2x00/
+obj-$(CONFIG_WL_MEDIATEK) += mediatek/
+
obj-$(CONFIG_P54_COMMON) += p54/
obj-$(CONFIG_ATH_CARDS) += ath/
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index f07a61899545..15f057ed41ad 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -1098,14 +1098,18 @@ static void adm8211_hw_init(struct ieee80211_hw *dev)
pci_read_config_byte(priv->pdev, PCI_CACHE_LINE_SIZE, &cline);
switch (cline) {
- case 0x8: reg |= (0x1 << 14);
- break;
- case 0x16: reg |= (0x2 << 14);
- break;
- case 0x32: reg |= (0x3 << 14);
- break;
- default: reg |= (0x0 << 14);
- break;
+ case 0x8:
+ reg |= (0x1 << 14);
+ break;
+ case 0x10:
+ reg |= (0x2 << 14);
+ break;
+ case 0x20:
+ reg |= (0x3 << 14);
+ break;
+ default:
+ reg |= (0x0 << 14);
+ break;
}
}
@@ -1353,12 +1357,7 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
new_flags = 0;
- if (*total_flags & FIF_PROMISC_IN_BSS) {
- new_flags |= FIF_PROMISC_IN_BSS;
- priv->nar |= ADM8211_NAR_PR;
- priv->nar &= ~ADM8211_NAR_MM;
- mc_filter[1] = mc_filter[0] = ~0;
- } else if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) {
+ if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) {
new_flags |= FIF_ALLMULTI;
priv->nar &= ~ADM8211_NAR_PR;
priv->nar |= ADM8211_NAR_MM;
@@ -1374,9 +1373,9 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
ADM8211_CSR_READ(NAR);
if (priv->nar & ADM8211_NAR_PR)
- dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
+ ieee80211_hw_set(dev, RX_INCLUDES_FCS);
else
- dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+ __clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, dev->flags);
if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
adm8211_set_bssid(dev, bcast);
@@ -1862,8 +1861,8 @@ static int adm8211_probe(struct pci_dev *pdev,
SET_IEEE80211_PERM_ADDR(dev, perm_addr);
dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
- /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
- dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
+ /* dev->flags = RX_INCLUDES_FCS in promisc mode */
+ ieee80211_hw_set(dev, SIGNAL_UNSPEC);
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
dev->max_signal = 100; /* FIXME: find better value */
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 49219c508963..dab25136214a 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -2360,8 +2360,8 @@ static int at76_init_new_device(struct at76_priv *priv,
priv->hw->wiphy->max_scan_ie_len = 0;
priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band;
- priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_UNSPEC;
+ ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(priv->hw, SIGNAL_UNSPEC);
priv->hw->max_signal = 100;
SET_IEEE80211_DEV(priv->hw, &interface->dev);
diff --git a/drivers/net/wireless/at76c50x-usb.h b/drivers/net/wireless/at76c50x-usb.h
index 55090a38ac95..ae03271f878e 100644
--- a/drivers/net/wireless/at76c50x-usb.h
+++ b/drivers/net/wireless/at76c50x-usb.h
@@ -447,7 +447,7 @@ struct at76_priv {
int mac80211_registered;
};
-#define AT76_SUPPORTED_FILTERS FIF_PROMISC_IN_BSS
+#define AT76_SUPPORTED_FILTERS 0
#define SCAN_POLL_INTERVAL (HZ / 4)
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c
index 5147ebe4cd05..3b343c63aa52 100644
--- a/drivers/net/wireless/ath/ar5523/ar5523.c
+++ b/drivers/net/wireless/ath/ar5523/ar5523.c
@@ -1319,8 +1319,7 @@ out_unlock:
}
-#define AR5523_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+#define AR5523_SUPPORTED_FILTERS (FIF_ALLMULTI | \
FIF_FCSFAIL | \
FIF_OTHER_BSS)
@@ -1683,9 +1682,9 @@ static int ar5523_probe(struct usb_interface *intf,
(id->driver_info & AR5523_FLAG_ABG) ? '5' : '2');
ar->vif = NULL;
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_HAS_RATE_CONTROL;
+ ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
hw->extra_tx_headroom = sizeof(struct ar5523_tx_desc) +
sizeof(struct ar5523_chunk);
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 7e9481099a8e..65ef483ebf50 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -251,6 +251,7 @@ void ath_printk(const char *level, const struct ath_common *common,
* @ATH_DBG_DFS: radar datection
* @ATH_DBG_WOW: Wake on Wireless
* @ATH_DBG_DYNACK: dynack handling
+ * @ATH_DBG_SPECTRAL_SCAN: FFT spectral scan
* @ATH_DBG_ANY: enable all debugging
*
* The debug level is used to control the amount and type of debugging output
@@ -280,6 +281,7 @@ enum ATH_DEBUG {
ATH_DBG_WOW = 0x00020000,
ATH_DBG_CHAN_CTX = 0x00040000,
ATH_DBG_DYNACK = 0x00080000,
+ ATH_DBG_SPECTRAL_SCAN = 0x00100000,
ATH_DBG_ANY = 0xffffffff
};
diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index f4dbb3e93bf8..9729e6941635 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -10,13 +10,15 @@ ath10k_core-y += mac.o \
wmi.o \
wmi-tlv.o \
bmi.o \
- hw.o
+ hw.o \
+ p2p.o
ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o
ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
ath10k_core-$(CONFIG_THERMAL) += thermal.o
ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o
+ath10k_core-$(CONFIG_PM) += wow.o
obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
ath10k_pci-y += pci.o \
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index c0e454bb6a8d..59496a90ad5e 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -48,6 +48,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.name = "qca988x hw2.0",
.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
+ .has_shifted_cc_wraparound = true,
.fw = {
.dir = QCA988X_HW_2_0_FW_DIR,
.fw = QCA988X_HW_2_0_FW_FILE,
@@ -387,7 +388,9 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
- if (!skip_otp && result != 0) {
+ if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
+ ar->fw_features))
+ && result != 0) {
ath10k_err(ar, "otp calibration failed: %d", result);
return -EINVAL;
}
@@ -482,31 +485,79 @@ static int ath10k_fetch_cal_file(struct ath10k *ar)
return 0;
}
-static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
+static int ath10k_core_fetch_spec_board_file(struct ath10k *ar)
{
- int ret = 0;
+ char filename[100];
- if (ar->hw_params.fw.fw == NULL) {
- ath10k_err(ar, "firmware file not defined\n");
- return -EINVAL;
- }
+ scnprintf(filename, sizeof(filename), "board-%s-%s.bin",
+ ath10k_bus_str(ar->hif.bus), ar->spec_board_id);
+
+ ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, filename);
+ if (IS_ERR(ar->board))
+ return PTR_ERR(ar->board);
+
+ ar->board_data = ar->board->data;
+ ar->board_len = ar->board->size;
+ ar->spec_board_loaded = true;
- if (ar->hw_params.fw.board == NULL) {
- ath10k_err(ar, "board data file not defined");
+ return 0;
+}
+
+static int ath10k_core_fetch_generic_board_file(struct ath10k *ar)
+{
+ if (!ar->hw_params.fw.board) {
+ ath10k_err(ar, "failed to find board file fw entry\n");
return -EINVAL;
}
ar->board = ath10k_fetch_fw_file(ar,
ar->hw_params.fw.dir,
ar->hw_params.fw.board);
- if (IS_ERR(ar->board)) {
- ret = PTR_ERR(ar->board);
- ath10k_err(ar, "could not fetch board data (%d)\n", ret);
- goto err;
- }
+ if (IS_ERR(ar->board))
+ return PTR_ERR(ar->board);
ar->board_data = ar->board->data;
ar->board_len = ar->board->size;
+ ar->spec_board_loaded = false;
+
+ return 0;
+}
+
+static int ath10k_core_fetch_board_file(struct ath10k *ar)
+{
+ int ret;
+
+ if (strlen(ar->spec_board_id) > 0) {
+ ret = ath10k_core_fetch_spec_board_file(ar);
+ if (ret) {
+ ath10k_info(ar, "failed to load spec board file, falling back to generic: %d\n",
+ ret);
+ goto generic;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found specific board file for %s\n",
+ ar->spec_board_id);
+ return 0;
+ }
+
+generic:
+ ret = ath10k_core_fetch_generic_board_file(ar);
+ if (ret) {
+ ath10k_err(ar, "failed to fetch generic board data: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
+{
+ int ret = 0;
+
+ if (ar->hw_params.fw.fw == NULL) {
+ ath10k_err(ar, "firmware file not defined\n");
+ return -EINVAL;
+ }
ar->firmware = ath10k_fetch_fw_file(ar,
ar->hw_params.fw.dir,
@@ -675,6 +726,17 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie wmi op version %d\n",
ar->wmi.op_version);
break;
+ case ATH10K_FW_IE_HTT_OP_VERSION:
+ if (ie_len != sizeof(u32))
+ break;
+
+ version = (__le32 *)data;
+
+ ar->htt.op_version = le32_to_cpup(version);
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie htt op version %d\n",
+ ar->htt.op_version);
+ break;
default:
ath10k_warn(ar, "Unknown FW IE: %u\n",
le32_to_cpu(hdr->id));
@@ -695,27 +757,6 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
goto err;
}
- /* now fetch the board file */
- if (ar->hw_params.fw.board == NULL) {
- ath10k_err(ar, "board data file not defined");
- ret = -EINVAL;
- goto err;
- }
-
- ar->board = ath10k_fetch_fw_file(ar,
- ar->hw_params.fw.dir,
- ar->hw_params.fw.board);
- if (IS_ERR(ar->board)) {
- ret = PTR_ERR(ar->board);
- ath10k_err(ar, "could not fetch board data '%s/%s' (%d)\n",
- ar->hw_params.fw.dir, ar->hw_params.fw.board,
- ret);
- goto err;
- }
-
- ar->board_data = ar->board->data;
- ar->board_len = ar->board->size;
-
return 0;
err:
@@ -730,6 +771,19 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
/* calibration file is optional, don't check for any errors */
ath10k_fetch_cal_file(ar);
+ ret = ath10k_core_fetch_board_file(ar);
+ if (ret) {
+ ath10k_err(ar, "failed to fetch board file: %d\n", ret);
+ return ret;
+ }
+
+ ar->fw_api = 5;
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+
+ ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API5_FILE);
+ if (ret == 0)
+ goto success;
+
ar->fw_api = 4;
ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
@@ -958,6 +1012,8 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
ar->max_num_stations = TARGET_NUM_STATIONS;
ar->max_num_vdevs = TARGET_NUM_VDEVS;
ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC;
+ ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV |
+ WMI_STAT_PEER;
break;
case ATH10K_FW_WMI_OP_VERSION_10_1:
case ATH10K_FW_WMI_OP_VERSION_10_2:
@@ -966,12 +1022,17 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
ar->max_num_stations = TARGET_10X_NUM_STATIONS;
ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
+ ar->fw_stats_req_mask = WMI_STAT_PEER;
break;
case ATH10K_FW_WMI_OP_VERSION_TLV:
ar->max_num_peers = TARGET_TLV_NUM_PEERS;
ar->max_num_stations = TARGET_TLV_NUM_STATIONS;
ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS;
+ ar->max_num_tdls_vdevs = TARGET_TLV_NUM_TDLS_VDEVS;
ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC;
+ ar->wow.max_num_patterns = TARGET_TLV_NUM_WOW_PATTERNS;
+ ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV |
+ WMI_STAT_PEER;
break;
case ATH10K_FW_WMI_OP_VERSION_UNSET:
case ATH10K_FW_WMI_OP_VERSION_MAX:
@@ -979,6 +1040,29 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
return -EINVAL;
}
+ /* Backwards compatibility for firmwares without
+ * ATH10K_FW_IE_HTT_OP_VERSION.
+ */
+ if (ar->htt.op_version == ATH10K_FW_HTT_OP_VERSION_UNSET) {
+ switch (ar->wmi.op_version) {
+ case ATH10K_FW_WMI_OP_VERSION_MAIN:
+ ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_MAIN;
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_10_1:
+ case ATH10K_FW_WMI_OP_VERSION_10_2:
+ case ATH10K_FW_WMI_OP_VERSION_10_2_4:
+ ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_10_1;
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_TLV:
+ ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_TLV;
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_UNSET:
+ case ATH10K_FW_WMI_OP_VERSION_MAX:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ }
+
return 0;
}
@@ -1001,6 +1085,22 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
if (status)
goto err;
+ /* Some of of qca988x solutions are having global reset issue
+ * during target initialization. Bypassing PLL setting before
+ * downloading firmware and letting the SoC run on REF_CLK is
+ * fixing the problem. Corresponding firmware change is also needed
+ * to set the clock source once the target is initialized.
+ */
+ if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT,
+ ar->fw_features)) {
+ status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1);
+ if (status) {
+ ath10k_err(ar, "could not write to skip_clock_init: %d\n",
+ status);
+ goto err;
+ }
+ }
+
status = ath10k_download_fw(ar, mode);
if (status)
goto err;
@@ -1080,9 +1180,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
status = ath10k_wmi_wait_for_service_ready(ar);
- if (status <= 0) {
+ if (status) {
ath10k_warn(ar, "wmi service ready event not received");
- status = -ETIMEDOUT;
goto err_hif_stop;
}
}
@@ -1098,9 +1197,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
}
status = ath10k_wmi_wait_for_unified_ready(ar);
- if (status <= 0) {
+ if (status) {
ath10k_err(ar, "wmi unified ready event not received\n");
- status = -ETIMEDOUT;
goto err_hif_stop;
}
@@ -1151,6 +1249,7 @@ EXPORT_SYMBOL(ath10k_core_start);
int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)
{
int ret;
+ unsigned long time_left;
reinit_completion(&ar->target_suspend);
@@ -1160,9 +1259,9 @@ int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)
return ret;
}
- ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
+ time_left = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
- if (ret == 0) {
+ if (!time_left) {
ath10k_warn(ar, "suspend timed out - target pause event never came\n");
return -ETIMEDOUT;
}
@@ -1386,6 +1485,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
init_completion(&ar->scan.completed);
init_completion(&ar->scan.on_channel);
init_completion(&ar->target_suspend);
+ init_completion(&ar->wow.wakeup_completed);
init_completion(&ar->install_key_done);
init_completion(&ar->vdev_setup_done);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index f65310c3ba5f..78094f23c9dd 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -35,6 +35,7 @@
#include "../dfs_pattern_detector.h"
#include "spectral.h"
#include "thermal.h"
+#include "wow.h"
#define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -43,15 +44,16 @@
#define ATH10K_SCAN_ID 0
#define WMI_READY_TIMEOUT (5 * HZ)
#define ATH10K_FLUSH_TIMEOUT_HZ (5*HZ)
-#define ATH10K_NUM_CHANS 38
+#define ATH10K_CONNECTION_LOSS_HZ (3*HZ)
+#define ATH10K_NUM_CHANS 39
/* Antenna noise floor */
#define ATH10K_DEFAULT_NOISE_FLOOR -95
#define ATH10K_MAX_NUM_MGMT_PENDING 128
-/* number of failed packets */
-#define ATH10K_KICKOUT_THRESHOLD 50
+/* number of failed packets (20 packets with 16 sw reties each) */
+#define ATH10K_KICKOUT_THRESHOLD (20 * 16)
/*
* Use insanely high numbers to make sure that the firmware implementation
@@ -82,6 +84,8 @@ struct ath10k_skb_cb {
dma_addr_t paddr;
u8 eid;
u8 vdev_id;
+ enum ath10k_hw_txrx_mode txmode;
+ bool is_protected;
struct {
u8 tid;
@@ -301,6 +305,7 @@ struct ath10k_vif {
enum ath10k_beacon_state beacon_state;
void *beacon_buf;
dma_addr_t beacon_paddr;
+ unsigned long tx_paused; /* arbitrary values defined by target */
struct ath10k *ar;
struct ieee80211_vif *vif;
@@ -334,13 +339,13 @@ struct ath10k_vif {
} ap;
} u;
- u8 fixed_rate;
- u8 fixed_nss;
- u8 force_sgi;
bool use_cts_prot;
int num_legacy_stations;
int txpower;
struct wmi_wmm_params_all_arg wmm_params;
+ struct work_struct ap_csa_work;
+ struct delayed_work connection_loss_work;
+ struct cfg80211_bitrate_mask bitrate_mask;
};
struct ath10k_vif_iter {
@@ -440,6 +445,23 @@ enum ath10k_fw_features {
*/
ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT = 5,
+ /* Some firmware revisions have an incomplete WoWLAN implementation
+ * despite WMI service bit being advertised. This feature flag is used
+ * to distinguish whether WoWLAN is really supported or not.
+ */
+ ATH10K_FW_FEATURE_WOWLAN_SUPPORT = 6,
+
+ /* Don't trust error code from otp.bin */
+ ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
+
+ /* Some firmware revisions pad 4th hw address to 4 byte boundary making
+ * it 8 bytes long in Native Wifi Rx decap.
+ */
+ ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING,
+
+ /* Firmware supports bypassing PLL setting on init. */
+ ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9,
+
/* keep last */
ATH10K_FW_FEATURE_COUNT,
};
@@ -498,6 +520,11 @@ static inline const char *ath10k_scan_state_str(enum ath10k_scan_state state)
return "unknown";
}
+enum ath10k_tx_pause_reason {
+ ATH10K_TX_PAUSE_Q_FULL,
+ ATH10K_TX_PAUSE_MAX,
+};
+
struct ath10k {
struct ath_common ath_common;
struct ieee80211_hw *hw;
@@ -511,12 +538,15 @@ struct ath10k {
u32 fw_version_minor;
u16 fw_version_release;
u16 fw_version_build;
+ u32 fw_stats_req_mask;
u32 phy_capability;
u32 hw_min_tx_power;
u32 hw_max_tx_power;
u32 ht_cap_info;
u32 vht_cap_info;
u32 num_rf_chains;
+ /* protected by conf_mutex */
+ bool ani_enabled;
DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
@@ -541,6 +571,13 @@ struct ath10k {
u32 patch_load_addr;
int uart_pin;
+ /* This is true if given HW chip has a quirky Cycle Counter
+ * wraparound which resets to 0x7fffffff instead of 0. All
+ * other CC related counters (e.g. Rx Clear Count) are divided
+ * by 2 so they never wraparound themselves.
+ */
+ bool has_shifted_cc_wraparound;
+
struct ath10k_hw_params_fw {
const char *dir;
const char *fw;
@@ -565,6 +602,9 @@ struct ath10k {
const struct firmware *cal_file;
+ char spec_board_id[100];
+ bool spec_board_loaded;
+
int fw_api;
enum ath10k_cal_mode cal_mode;
@@ -593,6 +633,7 @@ struct ath10k {
struct cfg80211_chan_def chandef;
unsigned long long free_vdev_map;
+ struct ath10k_vif *monitor_arvif;
bool monitor;
int monitor_vdev_id;
bool monitor_started;
@@ -633,6 +674,7 @@ struct ath10k {
int max_num_peers;
int max_num_stations;
int max_num_vdevs;
+ int max_num_tdls_vdevs;
struct work_struct offchan_tx_work;
struct sk_buff_head offchan_tx_queue;
@@ -653,8 +695,18 @@ struct ath10k {
u32 survey_last_cycle_count;
struct survey_info survey[ATH10K_NUM_CHANS];
+ /* Channel info events are expected to come in pairs without and with
+ * COMPLETE flag set respectively for each channel visit during scan.
+ *
+ * However there are deviations from this rule. This flag is used to
+ * avoid reporting garbage data.
+ */
+ bool ch_info_can_report_survey;
+
struct dfs_pattern_detector *dfs_detector;
+ unsigned long tx_paused; /* see ATH10K_TX_PAUSE_ */
+
#ifdef CONFIG_ATH10K_DEBUGFS
struct ath10k_debug debug;
#endif
@@ -686,6 +738,7 @@ struct ath10k {
} stats;
struct ath10k_thermal thermal;
+ struct ath10k_wow wow;
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 301081db1ef6..8fa606a9c4dd 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -124,10 +124,14 @@ EXPORT_SYMBOL(ath10k_info);
void ath10k_print_driver_info(struct ath10k *ar)
{
- ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n",
+ ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n",
ar->hw_params.name,
ar->target_version,
ar->chip_id,
+ (strlen(ar->spec_board_id) > 0 ? ", " : ""),
+ ar->spec_board_id,
+ (strlen(ar->spec_board_id) > 0 && !ar->spec_board_loaded
+ ? " fallback" : ""),
ar->hw->wiphy->fw_version,
ar->fw_api,
ar->htt.target_version_major,
@@ -380,12 +384,12 @@ unlock:
static int ath10k_debug_fw_stats_request(struct ath10k *ar)
{
- unsigned long timeout;
+ unsigned long timeout, time_left;
int ret;
lockdep_assert_held(&ar->conf_mutex);
- timeout = jiffies + msecs_to_jiffies(1*HZ);
+ timeout = jiffies + msecs_to_jiffies(1 * HZ);
ath10k_debug_fw_stats_reset(ar);
@@ -395,18 +399,16 @@ static int ath10k_debug_fw_stats_request(struct ath10k *ar)
reinit_completion(&ar->debug.fw_stats_complete);
- ret = ath10k_wmi_request_stats(ar,
- WMI_STAT_PDEV |
- WMI_STAT_VDEV |
- WMI_STAT_PEER);
+ ret = ath10k_wmi_request_stats(ar, ar->fw_stats_req_mask);
if (ret) {
ath10k_warn(ar, "could not request stats (%d)\n", ret);
return ret;
}
- ret = wait_for_completion_timeout(&ar->debug.fw_stats_complete,
- 1*HZ);
- if (ret == 0)
+ time_left =
+ wait_for_completion_timeout(&ar->debug.fw_stats_complete,
+ 1 * HZ);
+ if (!time_left)
return -ETIMEDOUT;
spin_lock_bh(&ar->data_lock);
@@ -1708,6 +1710,61 @@ static int ath10k_debug_cal_data_release(struct inode *inode,
return 0;
}
+static ssize_t ath10k_write_ani_enable(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ int ret;
+ u8 enable;
+
+ if (kstrtou8_from_user(user_buf, count, 0, &enable))
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->ani_enabled == enable) {
+ ret = count;
+ goto exit;
+ }
+
+ ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->ani_enable,
+ enable);
+ if (ret) {
+ ath10k_warn(ar, "ani_enable failed from debugfs: %d\n", ret);
+ goto exit;
+ }
+ ar->ani_enabled = enable;
+
+ ret = count;
+
+exit:
+ mutex_unlock(&ar->conf_mutex);
+
+ return ret;
+}
+
+static ssize_t ath10k_read_ani_enable(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ int len = 0;
+ char buf[32];
+
+ len = scnprintf(buf, sizeof(buf) - len, "%d\n",
+ ar->ani_enabled);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_ani_enable = {
+ .read = ath10k_read_ani_enable,
+ .write = ath10k_write_ani_enable,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static const struct file_operations fops_cal_data = {
.open = ath10k_debug_cal_data_open,
.read = ath10k_debug_cal_data_read,
@@ -1991,6 +2048,50 @@ static const struct file_operations fops_pktlog_filter = {
.open = simple_open
};
+static ssize_t ath10k_write_quiet_period(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ u32 period;
+
+ if (kstrtouint_from_user(ubuf, count, 0, &period))
+ return -EINVAL;
+
+ if (period < ATH10K_QUIET_PERIOD_MIN) {
+ ath10k_warn(ar, "Quiet period %u can not be lesser than 25ms\n",
+ period);
+ return -EINVAL;
+ }
+ mutex_lock(&ar->conf_mutex);
+ ar->thermal.quiet_period = period;
+ ath10k_thermal_set_throttling(ar);
+ mutex_unlock(&ar->conf_mutex);
+
+ return count;
+}
+
+static ssize_t ath10k_read_quiet_period(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[32];
+ struct ath10k *ar = file->private_data;
+ int len = 0;
+
+ mutex_lock(&ar->conf_mutex);
+ len = scnprintf(buf, sizeof(buf) - len, "%d\n",
+ ar->thermal.quiet_period);
+ mutex_unlock(&ar->conf_mutex);
+
+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_quiet_period = {
+ .read = ath10k_read_quiet_period,
+ .write = ath10k_write_quiet_period,
+ .open = simple_open
+};
+
int ath10k_debug_create(struct ath10k *ar)
{
ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data));
@@ -2068,6 +2169,9 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_cal_data);
+ debugfs_create_file("ani_enable", S_IRUSR | S_IWUSR,
+ ar->debug.debugfs_phy, ar, &fops_ani_enable);
+
debugfs_create_file("nf_cal_period", S_IRUSR | S_IWUSR,
ar->debug.debugfs_phy, ar, &fops_nf_cal_period);
@@ -2088,6 +2192,9 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("pktlog_filter", S_IRUGO | S_IWUSR,
ar->debug.debugfs_phy, ar, &fops_pktlog_filter);
+ debugfs_create_file("quiet_period", S_IRUGO | S_IWUSR,
+ ar->debug.debugfs_phy, ar, &fops_quiet_period);
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index a12b8323f9f1..53bd6a19eab6 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -36,6 +36,7 @@ enum ath10k_debug_mask {
ATH10K_DBG_REGULATORY = 0x00000800,
ATH10K_DBG_TESTMODE = 0x00001000,
ATH10K_DBG_WMI_PRINT = 0x00002000,
+ ATH10K_DBG_PCI_PS = 0x00004000,
ATH10K_DBG_ANY = 0xffffffff,
};
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 2fd9e180272b..85bfa2acb801 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -86,21 +86,6 @@ static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
ep->ep_ops.ep_tx_complete(ep->htc->ar, skb);
}
-/* assumes tx_lock is held */
-static bool ath10k_htc_ep_need_credit_update(struct ath10k_htc_ep *ep)
-{
- struct ath10k *ar = ep->htc->ar;
-
- if (!ep->tx_credit_flow_enabled)
- return false;
- if (ep->tx_credits >= ep->tx_credits_per_max_message)
- return false;
-
- ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n",
- ep->eid);
- return true;
-}
-
static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
struct sk_buff *skb)
{
@@ -111,13 +96,10 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
hdr->eid = ep->eid;
hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr));
hdr->flags = 0;
+ hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE;
spin_lock_bh(&ep->htc->tx_lock);
hdr->seq_no = ep->seq_no++;
-
- if (ath10k_htc_ep_need_credit_update(ep))
- hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE;
-
spin_unlock_bh(&ep->htc->tx_lock);
}
@@ -414,7 +396,8 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
struct ath10k_htc_msg *msg = (struct ath10k_htc_msg *)skb->data;
switch (__le16_to_cpu(msg->hdr.message_id)) {
- default:
+ case ATH10K_HTC_MSG_READY_ID:
+ case ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID:
/* handle HTC control message */
if (completion_done(&htc->ctl_resp)) {
/*
@@ -438,6 +421,10 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
break;
case ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE:
htc->htc_ops.target_send_suspend_complete(ar);
+ break;
+ default:
+ ath10k_warn(ar, "ignoring unsolicited htc ep0 event\n");
+ break;
}
goto out;
}
@@ -548,6 +535,7 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
{
struct ath10k *ar = htc->ar;
int i, status = 0;
+ unsigned long time_left;
struct ath10k_htc_svc_conn_req conn_req;
struct ath10k_htc_svc_conn_resp conn_resp;
struct ath10k_htc_msg *msg;
@@ -555,9 +543,9 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
u16 credit_count;
u16 credit_size;
- status = wait_for_completion_timeout(&htc->ctl_resp,
- ATH10K_HTC_WAIT_TIMEOUT_HZ);
- if (status == 0) {
+ time_left = wait_for_completion_timeout(&htc->ctl_resp,
+ ATH10K_HTC_WAIT_TIMEOUT_HZ);
+ if (!time_left) {
/* Workaround: In some cases the PCI HIF doesn't
* receive interrupt for the control response message
* even if the buffer was completed. It is suspected
@@ -569,10 +557,11 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
for (i = 0; i < CE_COUNT; i++)
ath10k_hif_send_complete_check(htc->ar, i, 1);
- status = wait_for_completion_timeout(&htc->ctl_resp,
- ATH10K_HTC_WAIT_TIMEOUT_HZ);
+ time_left =
+ wait_for_completion_timeout(&htc->ctl_resp,
+ ATH10K_HTC_WAIT_TIMEOUT_HZ);
- if (status == 0)
+ if (!time_left)
status = -ETIMEDOUT;
}
@@ -646,6 +635,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
struct sk_buff *skb;
unsigned int max_msg_size = 0;
int length, status;
+ unsigned long time_left;
bool disable_credit_flow_ctrl = false;
u16 message_id, service_id, flags = 0;
u8 tx_alloc = 0;
@@ -701,10 +691,10 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
}
/* wait for response */
- status = wait_for_completion_timeout(&htc->ctl_resp,
- ATH10K_HTC_CONN_SVC_TIMEOUT_HZ);
- if (status == 0) {
- ath10k_err(ar, "Service connect timeout: %d\n", status);
+ time_left = wait_for_completion_timeout(&htc->ctl_resp,
+ ATH10K_HTC_CONN_SVC_TIMEOUT_HZ);
+ if (!time_left) {
+ ath10k_err(ar, "Service connect timeout\n");
return -ETIMEDOUT;
}
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 4f59ab923e48..6da6ef26143a 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -22,6 +22,86 @@
#include "core.h"
#include "debug.h"
+static const enum htt_t2h_msg_type htt_main_t2h_msg_types[] = {
+ [HTT_MAIN_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH,
+ [HTT_MAIN_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP,
+ [HTT_MAIN_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA,
+ [HTT_MAIN_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG,
+ [HTT_MAIN_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_TX_INSPECT_IND] =
+ HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] =
+ HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
+ [HTT_MAIN_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND] =
+ HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_PN_IND] = HTT_T2H_MSG_TYPE_RX_PN_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND] =
+ HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND,
+ [HTT_MAIN_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,
+};
+
+static const enum htt_t2h_msg_type htt_10x_t2h_msg_types[] = {
+ [HTT_10X_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
+ [HTT_10X_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND,
+ [HTT_10X_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH,
+ [HTT_10X_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP,
+ [HTT_10X_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP,
+ [HTT_10X_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA,
+ [HTT_10X_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA,
+ [HTT_10X_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND,
+ [HTT_10X_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG,
+ [HTT_10X_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF,
+ [HTT_10X_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND,
+ [HTT_10X_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND,
+ [HTT_10X_T2H_MSG_TYPE_RC_UPDATE_IND] = HTT_T2H_MSG_TYPE_RC_UPDATE_IND,
+ [HTT_10X_T2H_MSG_TYPE_TX_INSPECT_IND] = HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
+ [HTT_10X_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,
+ [HTT_10X_T2H_MSG_TYPE_CHAN_CHANGE] = HTT_T2H_MSG_TYPE_CHAN_CHANGE,
+ [HTT_10X_T2H_MSG_TYPE_AGGR_CONF] = HTT_T2H_MSG_TYPE_AGGR_CONF,
+ [HTT_10X_T2H_MSG_TYPE_STATS_NOUPLOAD] = HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
+ [HTT_10X_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] =
+ HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
+};
+
+static const enum htt_t2h_msg_type htt_tlv_t2h_msg_types[] = {
+ [HTT_TLV_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
+ [HTT_TLV_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND,
+ [HTT_TLV_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH,
+ [HTT_TLV_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP,
+ [HTT_TLV_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP,
+ [HTT_TLV_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA,
+ [HTT_TLV_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA,
+ [HTT_TLV_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND,
+ [HTT_TLV_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG,
+ [HTT_TLV_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF,
+ [HTT_TLV_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND,
+ [HTT_TLV_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND,
+ [HTT_TLV_T2H_MSG_TYPE_RC_UPDATE_IND] = HTT_T2H_MSG_TYPE_RC_UPDATE_IND,
+ [HTT_TLV_T2H_MSG_TYPE_TX_INSPECT_IND] = HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
+ [HTT_TLV_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] =
+ HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
+ [HTT_TLV_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND] =
+ HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
+ [HTT_TLV_T2H_MSG_TYPE_RX_PN_IND] = HTT_T2H_MSG_TYPE_RX_PN_IND,
+ [HTT_TLV_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND] =
+ HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND,
+ [HTT_TLV_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND] =
+ HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND,
+ [HTT_TLV_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE] =
+ HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE,
+ [HTT_TLV_T2H_MSG_TYPE_CHAN_CHANGE] = HTT_T2H_MSG_TYPE_CHAN_CHANGE,
+ [HTT_TLV_T2H_MSG_TYPE_RX_OFLD_PKT_ERR] =
+ HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR,
+ [HTT_TLV_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,
+};
+
int ath10k_htt_connect(struct ath10k_htt *htt)
{
struct ath10k_htc_svc_conn_req conn_req;
@@ -66,6 +146,24 @@ int ath10k_htt_init(struct ath10k *ar)
8 + /* llc snap */
2; /* ip4 dscp or ip6 priority */
+ switch (ar->htt.op_version) {
+ case ATH10K_FW_HTT_OP_VERSION_10_1:
+ ar->htt.t2h_msg_types = htt_10x_t2h_msg_types;
+ ar->htt.t2h_msg_types_max = HTT_10X_T2H_NUM_MSGS;
+ break;
+ case ATH10K_FW_HTT_OP_VERSION_TLV:
+ ar->htt.t2h_msg_types = htt_tlv_t2h_msg_types;
+ ar->htt.t2h_msg_types_max = HTT_TLV_T2H_NUM_MSGS;
+ break;
+ case ATH10K_FW_HTT_OP_VERSION_MAIN:
+ ar->htt.t2h_msg_types = htt_main_t2h_msg_types;
+ ar->htt.t2h_msg_types_max = HTT_MAIN_T2H_NUM_MSGS;
+ break;
+ case ATH10K_FW_HTT_OP_VERSION_MAX:
+ case ATH10K_FW_HTT_OP_VERSION_UNSET:
+ WARN_ON(1);
+ return -EINVAL;
+ }
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 874bf44ff7a2..7e8a0d835663 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -25,7 +25,9 @@
#include <net/mac80211.h>
#include "htc.h"
+#include "hw.h"
#include "rx_desc.h"
+#include "hw.h"
enum htt_dbg_stats_type {
HTT_DBG_STATS_WAL_PDEV_TXRX = 1 << 0,
@@ -271,35 +273,108 @@ enum htt_mgmt_tx_status {
/*=== target -> host messages ===============================================*/
-enum htt_t2h_msg_type {
- HTT_T2H_MSG_TYPE_VERSION_CONF = 0x0,
- HTT_T2H_MSG_TYPE_RX_IND = 0x1,
- HTT_T2H_MSG_TYPE_RX_FLUSH = 0x2,
- HTT_T2H_MSG_TYPE_PEER_MAP = 0x3,
- HTT_T2H_MSG_TYPE_PEER_UNMAP = 0x4,
- HTT_T2H_MSG_TYPE_RX_ADDBA = 0x5,
- HTT_T2H_MSG_TYPE_RX_DELBA = 0x6,
- HTT_T2H_MSG_TYPE_TX_COMPL_IND = 0x7,
- HTT_T2H_MSG_TYPE_PKTLOG = 0x8,
- HTT_T2H_MSG_TYPE_STATS_CONF = 0x9,
- HTT_T2H_MSG_TYPE_RX_FRAG_IND = 0xa,
- HTT_T2H_MSG_TYPE_SEC_IND = 0xb,
- HTT_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc,
- HTT_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
- HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION = 0xe,
- HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf,
- HTT_T2H_MSG_TYPE_RX_PN_IND = 0x10,
- HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11,
- HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND = 0x12,
+enum htt_main_t2h_msg_type {
+ HTT_MAIN_T2H_MSG_TYPE_VERSION_CONF = 0x0,
+ HTT_MAIN_T2H_MSG_TYPE_RX_IND = 0x1,
+ HTT_MAIN_T2H_MSG_TYPE_RX_FLUSH = 0x2,
+ HTT_MAIN_T2H_MSG_TYPE_PEER_MAP = 0x3,
+ HTT_MAIN_T2H_MSG_TYPE_PEER_UNMAP = 0x4,
+ HTT_MAIN_T2H_MSG_TYPE_RX_ADDBA = 0x5,
+ HTT_MAIN_T2H_MSG_TYPE_RX_DELBA = 0x6,
+ HTT_MAIN_T2H_MSG_TYPE_TX_COMPL_IND = 0x7,
+ HTT_MAIN_T2H_MSG_TYPE_PKTLOG = 0x8,
+ HTT_MAIN_T2H_MSG_TYPE_STATS_CONF = 0x9,
+ HTT_MAIN_T2H_MSG_TYPE_RX_FRAG_IND = 0xa,
+ HTT_MAIN_T2H_MSG_TYPE_SEC_IND = 0xb,
+ HTT_MAIN_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
+ HTT_MAIN_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0xe,
+ HTT_MAIN_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf,
+ HTT_MAIN_T2H_MSG_TYPE_RX_PN_IND = 0x10,
+ HTT_MAIN_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11,
+ HTT_MAIN_T2H_MSG_TYPE_TEST,
+ /* keep this last */
+ HTT_MAIN_T2H_NUM_MSGS
+};
+
+enum htt_10x_t2h_msg_type {
+ HTT_10X_T2H_MSG_TYPE_VERSION_CONF = 0x0,
+ HTT_10X_T2H_MSG_TYPE_RX_IND = 0x1,
+ HTT_10X_T2H_MSG_TYPE_RX_FLUSH = 0x2,
+ HTT_10X_T2H_MSG_TYPE_PEER_MAP = 0x3,
+ HTT_10X_T2H_MSG_TYPE_PEER_UNMAP = 0x4,
+ HTT_10X_T2H_MSG_TYPE_RX_ADDBA = 0x5,
+ HTT_10X_T2H_MSG_TYPE_RX_DELBA = 0x6,
+ HTT_10X_T2H_MSG_TYPE_TX_COMPL_IND = 0x7,
+ HTT_10X_T2H_MSG_TYPE_PKTLOG = 0x8,
+ HTT_10X_T2H_MSG_TYPE_STATS_CONF = 0x9,
+ HTT_10X_T2H_MSG_TYPE_RX_FRAG_IND = 0xa,
+ HTT_10X_T2H_MSG_TYPE_SEC_IND = 0xb,
+ HTT_10X_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc,
+ HTT_10X_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
+ HTT_10X_T2H_MSG_TYPE_TEST = 0xe,
+ HTT_10X_T2H_MSG_TYPE_CHAN_CHANGE = 0xf,
+ HTT_10X_T2H_MSG_TYPE_AGGR_CONF = 0x11,
+ HTT_10X_T2H_MSG_TYPE_STATS_NOUPLOAD = 0x12,
+ HTT_10X_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0x13,
+ /* keep this last */
+ HTT_10X_T2H_NUM_MSGS
+};
+
+enum htt_tlv_t2h_msg_type {
+ HTT_TLV_T2H_MSG_TYPE_VERSION_CONF = 0x0,
+ HTT_TLV_T2H_MSG_TYPE_RX_IND = 0x1,
+ HTT_TLV_T2H_MSG_TYPE_RX_FLUSH = 0x2,
+ HTT_TLV_T2H_MSG_TYPE_PEER_MAP = 0x3,
+ HTT_TLV_T2H_MSG_TYPE_PEER_UNMAP = 0x4,
+ HTT_TLV_T2H_MSG_TYPE_RX_ADDBA = 0x5,
+ HTT_TLV_T2H_MSG_TYPE_RX_DELBA = 0x6,
+ HTT_TLV_T2H_MSG_TYPE_TX_COMPL_IND = 0x7,
+ HTT_TLV_T2H_MSG_TYPE_PKTLOG = 0x8,
+ HTT_TLV_T2H_MSG_TYPE_STATS_CONF = 0x9,
+ HTT_TLV_T2H_MSG_TYPE_RX_FRAG_IND = 0xa,
+ HTT_TLV_T2H_MSG_TYPE_SEC_IND = 0xb,
+ HTT_TLV_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc, /* deprecated */
+ HTT_TLV_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
+ HTT_TLV_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0xe,
+ HTT_TLV_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf,
+ HTT_TLV_T2H_MSG_TYPE_RX_PN_IND = 0x10,
+ HTT_TLV_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11,
+ HTT_TLV_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND = 0x12,
/* 0x13 reservd */
- HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE = 0x14,
+ HTT_TLV_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE = 0x14,
+ HTT_TLV_T2H_MSG_TYPE_CHAN_CHANGE = 0x15,
+ HTT_TLV_T2H_MSG_TYPE_RX_OFLD_PKT_ERR = 0x16,
+ HTT_TLV_T2H_MSG_TYPE_TEST,
+ /* keep this last */
+ HTT_TLV_T2H_NUM_MSGS
+};
- /* FIXME: Do not depend on this event id. Numbering of this event id is
- * broken across different firmware revisions and HTT version fails to
- * indicate this.
- */
+enum htt_t2h_msg_type {
+ HTT_T2H_MSG_TYPE_VERSION_CONF,
+ HTT_T2H_MSG_TYPE_RX_IND,
+ HTT_T2H_MSG_TYPE_RX_FLUSH,
+ HTT_T2H_MSG_TYPE_PEER_MAP,
+ HTT_T2H_MSG_TYPE_PEER_UNMAP,
+ HTT_T2H_MSG_TYPE_RX_ADDBA,
+ HTT_T2H_MSG_TYPE_RX_DELBA,
+ HTT_T2H_MSG_TYPE_TX_COMPL_IND,
+ HTT_T2H_MSG_TYPE_PKTLOG,
+ HTT_T2H_MSG_TYPE_STATS_CONF,
+ HTT_T2H_MSG_TYPE_RX_FRAG_IND,
+ HTT_T2H_MSG_TYPE_SEC_IND,
+ HTT_T2H_MSG_TYPE_RC_UPDATE_IND,
+ HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
+ HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
+ HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
+ HTT_T2H_MSG_TYPE_RX_PN_IND,
+ HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND,
+ HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND,
+ HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE,
+ HTT_T2H_MSG_TYPE_CHAN_CHANGE,
+ HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR,
+ HTT_T2H_MSG_TYPE_AGGR_CONF,
+ HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
HTT_T2H_MSG_TYPE_TEST,
-
/* keep this last */
HTT_T2H_NUM_MSGS
};
@@ -1222,6 +1297,7 @@ struct htt_tx_done {
u32 msdu_id;
bool discard;
bool no_ack;
+ bool success;
};
struct htt_peer_map_event {
@@ -1248,6 +1324,10 @@ struct ath10k_htt {
u8 target_version_major;
u8 target_version_minor;
struct completion target_version_received;
+ enum ath10k_fw_htt_op_version op_version;
+
+ const enum htt_t2h_msg_type *t2h_msg_types;
+ u32 t2h_msg_types_max;
struct {
/*
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 01a2b384f358..89eb16b30fc4 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -637,58 +637,21 @@ static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar,
return 0;
}
-struct rfc1042_hdr {
- u8 llc_dsap;
- u8 llc_ssap;
- u8 llc_ctrl;
- u8 snap_oui[3];
- __be16 snap_type;
-} __packed;
-
struct amsdu_subframe_hdr {
u8 dst[ETH_ALEN];
u8 src[ETH_ALEN];
__be16 len;
} __packed;
-static const u8 rx_legacy_rate_idx[] = {
- 3, /* 0x00 - 11Mbps */
- 2, /* 0x01 - 5.5Mbps */
- 1, /* 0x02 - 2Mbps */
- 0, /* 0x03 - 1Mbps */
- 3, /* 0x04 - 11Mbps */
- 2, /* 0x05 - 5.5Mbps */
- 1, /* 0x06 - 2Mbps */
- 0, /* 0x07 - 1Mbps */
- 10, /* 0x08 - 48Mbps */
- 8, /* 0x09 - 24Mbps */
- 6, /* 0x0A - 12Mbps */
- 4, /* 0x0B - 6Mbps */
- 11, /* 0x0C - 54Mbps */
- 9, /* 0x0D - 36Mbps */
- 7, /* 0x0E - 18Mbps */
- 5, /* 0x0F - 9Mbps */
-};
-
static void ath10k_htt_rx_h_rates(struct ath10k *ar,
struct ieee80211_rx_status *status,
struct htt_rx_desc *rxd)
{
- enum ieee80211_band band;
- u8 cck, rate, rate_idx, bw, sgi, mcs, nss;
+ struct ieee80211_supported_band *sband;
+ u8 cck, rate, bw, sgi, mcs, nss;
u8 preamble = 0;
u32 info1, info2, info3;
- /* Band value can't be set as undefined but freq can be 0 - use that to
- * determine whether band is provided.
- *
- * FIXME: Perhaps this can go away if CCK rate reporting is a little
- * reworked?
- */
- if (!status->freq)
- return;
-
- band = status->band;
info1 = __le32_to_cpu(rxd->ppdu_start.info1);
info2 = __le32_to_cpu(rxd->ppdu_start.info2);
info3 = __le32_to_cpu(rxd->ppdu_start.info3);
@@ -697,31 +660,18 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
switch (preamble) {
case HTT_RX_LEGACY:
+ /* To get legacy rate index band is required. Since band can't
+ * be undefined check if freq is non-zero.
+ */
+ if (!status->freq)
+ return;
+
cck = info1 & RX_PPDU_START_INFO1_L_SIG_RATE_SELECT;
rate = MS(info1, RX_PPDU_START_INFO1_L_SIG_RATE);
- rate_idx = 0;
-
- if (rate < 0x08 || rate > 0x0F)
- break;
-
- switch (band) {
- case IEEE80211_BAND_2GHZ:
- if (cck)
- rate &= ~BIT(3);
- rate_idx = rx_legacy_rate_idx[rate];
- break;
- case IEEE80211_BAND_5GHZ:
- rate_idx = rx_legacy_rate_idx[rate];
- /* We are using same rate table registering
- HW - ath10k_rates[]. In case of 5GHz skip
- CCK rates, so -4 here */
- rate_idx -= 4;
- break;
- default:
- break;
- }
+ rate &= ~RX_PPDU_START_RATE_FLAG;
- status->rate_idx = rate_idx;
+ sband = &ar->mac.sbands[status->band];
+ status->rate_idx = ath10k_mac_hw_rate_to_idx(sband, rate);
break;
case HTT_RX_HT:
case HTT_RX_HT_WITH_TXBF:
@@ -773,8 +723,87 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
}
}
+static struct ieee80211_channel *
+ath10k_htt_rx_h_peer_channel(struct ath10k *ar, struct htt_rx_desc *rxd)
+{
+ struct ath10k_peer *peer;
+ struct ath10k_vif *arvif;
+ struct cfg80211_chan_def def;
+ u16 peer_id;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ if (!rxd)
+ return NULL;
+
+ if (rxd->attention.flags &
+ __cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID))
+ return NULL;
+
+ if (!(rxd->msdu_end.info0 &
+ __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)))
+ return NULL;
+
+ peer_id = MS(__le32_to_cpu(rxd->mpdu_start.info0),
+ RX_MPDU_START_INFO0_PEER_IDX);
+
+ peer = ath10k_peer_find_by_id(ar, peer_id);
+ if (!peer)
+ return NULL;
+
+ arvif = ath10k_get_arvif(ar, peer->vdev_id);
+ if (WARN_ON_ONCE(!arvif))
+ return NULL;
+
+ if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def)))
+ return NULL;
+
+ return def.chan;
+}
+
+static struct ieee80211_channel *
+ath10k_htt_rx_h_vdev_channel(struct ath10k *ar, u32 vdev_id)
+{
+ struct ath10k_vif *arvif;
+ struct cfg80211_chan_def def;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ if (arvif->vdev_id == vdev_id &&
+ ath10k_mac_vif_chan(arvif->vif, &def) == 0)
+ return def.chan;
+ }
+
+ return NULL;
+}
+
+static void
+ath10k_htt_rx_h_any_chan_iter(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *conf,
+ void *data)
+{
+ struct cfg80211_chan_def *def = data;
+
+ *def = conf->def;
+}
+
+static struct ieee80211_channel *
+ath10k_htt_rx_h_any_channel(struct ath10k *ar)
+{
+ struct cfg80211_chan_def def = {};
+
+ ieee80211_iter_chan_contexts_atomic(ar->hw,
+ ath10k_htt_rx_h_any_chan_iter,
+ &def);
+
+ return def.chan;
+}
+
static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
- struct ieee80211_rx_status *status)
+ struct ieee80211_rx_status *status,
+ struct htt_rx_desc *rxd,
+ u32 vdev_id)
{
struct ieee80211_channel *ch;
@@ -782,6 +811,12 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
ch = ar->scan_channel;
if (!ch)
ch = ar->rx_channel;
+ if (!ch)
+ ch = ath10k_htt_rx_h_peer_channel(ar, rxd);
+ if (!ch)
+ ch = ath10k_htt_rx_h_vdev_channel(ar, vdev_id);
+ if (!ch)
+ ch = ath10k_htt_rx_h_any_channel(ar);
spin_unlock_bh(&ar->data_lock);
if (!ch)
@@ -819,7 +854,8 @@ static void ath10k_htt_rx_h_mactime(struct ath10k *ar,
static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
struct sk_buff_head *amsdu,
- struct ieee80211_rx_status *status)
+ struct ieee80211_rx_status *status,
+ u32 vdev_id)
{
struct sk_buff *first;
struct htt_rx_desc *rxd;
@@ -851,7 +887,7 @@ static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
status->flag |= RX_FLAG_NO_SIGNAL_VAL;
ath10k_htt_rx_h_signal(ar, status, rxd);
- ath10k_htt_rx_h_channel(ar, status);
+ ath10k_htt_rx_h_channel(ar, status, rxd, vdev_id);
ath10k_htt_rx_h_rates(ar, status, rxd);
}
@@ -929,10 +965,16 @@ static void ath10k_process_rx(struct ath10k *ar,
ieee80211_rx(ar->hw, skb);
}
-static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr)
+static int ath10k_htt_rx_nwifi_hdrlen(struct ath10k *ar,
+ struct ieee80211_hdr *hdr)
{
- /* nwifi header is padded to 4 bytes. this fixes 4addr rx */
- return round_up(ieee80211_hdrlen(hdr->frame_control), 4);
+ int len = ieee80211_hdrlen(hdr->frame_control);
+
+ if (!test_bit(ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING,
+ ar->fw_features))
+ len = round_up(len, 4);
+
+ return len;
}
static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar,
@@ -1031,7 +1073,7 @@ static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
/* pull decapped header and copy SA & DA */
hdr = (struct ieee80211_hdr *)msdu->data;
- hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
+ hdr_len = ath10k_htt_rx_nwifi_hdrlen(ar, hdr);
ether_addr_copy(da, ieee80211_get_DA(hdr));
ether_addr_copy(sa, ieee80211_get_SA(hdr));
skb_pull(msdu, hdr_len);
@@ -1522,7 +1564,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
break;
}
- ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status);
+ ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
@@ -1569,7 +1611,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
return;
}
- ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status);
+ ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
@@ -1598,6 +1640,7 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
tx_done.no_ack = true;
break;
case HTT_DATA_TX_STATUS_OK:
+ tx_done.success = true;
break;
case HTT_DATA_TX_STATUS_DISCARD:
case HTT_DATA_TX_STATUS_POSTPONE:
@@ -1796,7 +1839,7 @@ static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
status->flag |= RX_FLAG_NO_SIGNAL_VAL;
ath10k_htt_rx_h_rx_offload_prot(status, msdu);
- ath10k_htt_rx_h_channel(ar, status);
+ ath10k_htt_rx_h_channel(ar, status, NULL, rx->vdev_id);
ath10k_process_rx(ar, status, msdu);
}
}
@@ -1869,7 +1912,7 @@ static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
* better to report something than nothing though. This
* should still give an idea about rx rate to the user.
*/
- ath10k_htt_rx_h_ppdu(ar, &amsdu, status);
+ ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
ath10k_htt_rx_h_filter(ar, &amsdu, status);
ath10k_htt_rx_h_mpdu(ar, &amsdu, status);
ath10k_htt_rx_h_deliver(ar, &amsdu, status);
@@ -1892,6 +1935,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
{
struct ath10k_htt *htt = &ar->htt;
struct htt_resp *resp = (struct htt_resp *)skb->data;
+ enum htt_t2h_msg_type type;
/* confirm alignment */
if (!IS_ALIGNED((unsigned long)skb->data, 4))
@@ -1899,7 +1943,16 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
resp->hdr.msg_type);
- switch (resp->hdr.msg_type) {
+
+ if (resp->hdr.msg_type >= ar->htt.t2h_msg_types_max) {
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, unsupported msg_type: 0x%0X\n max: 0x%0X",
+ resp->hdr.msg_type, ar->htt.t2h_msg_types_max);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ type = ar->htt.t2h_msg_types[resp->hdr.msg_type];
+
+ switch (type) {
case HTT_T2H_MSG_TYPE_VERSION_CONF: {
htt->target_version_major = resp->ver_resp.major;
htt->target_version_minor = resp->ver_resp.minor;
@@ -1937,6 +1990,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
switch (status) {
case HTT_MGMT_TX_STATUS_OK:
+ tx_done.success = true;
break;
case HTT_MGMT_TX_STATUS_RETRY:
tx_done.no_ack = true;
@@ -1976,7 +2030,6 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
case HTT_T2H_MSG_TYPE_TEST:
- /* FIX THIS */
break;
case HTT_T2H_MSG_TYPE_STATS_CONF:
trace_ath10k_htt_stats(ar, skb->data, skb->len);
@@ -2018,11 +2071,8 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
return;
}
case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
- /* FIXME: This WMI-TLV event is overlapping with 10.2
- * CHAN_CHANGE - both being 0xF. Neither is being used in
- * practice so no immediate action is necessary. Nevertheless
- * HTT may need an abstraction layer like WMI has one day.
- */
+ break;
+ case HTT_T2H_MSG_TYPE_CHAN_CHANGE:
break;
default:
ath10k_warn(ar, "htt event (%d) not handled\n",
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index cbd2bc9e6202..a60ef7d1d5fc 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -26,7 +26,7 @@ void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
{
htt->num_pending_tx--;
if (htt->num_pending_tx == htt->max_num_pending_tx - 1)
- ieee80211_wake_queues(htt->ar->hw);
+ ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
}
static void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
@@ -49,7 +49,7 @@ static int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
htt->num_pending_tx++;
if (htt->num_pending_tx == htt->max_num_pending_tx)
- ieee80211_stop_queues(htt->ar->hw);
+ ath10k_mac_tx_lock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
exit:
spin_unlock_bh(&htt->tx_lock);
@@ -420,9 +420,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
int res;
u8 flags0 = 0;
u16 msdu_id, flags1 = 0;
- dma_addr_t paddr;
- u32 frags_paddr;
- bool use_frags;
+ dma_addr_t paddr = 0;
+ u32 frags_paddr = 0;
res = ath10k_htt_tx_inc_pending(htt);
if (res)
@@ -440,12 +439,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
prefetch_len = min(htt->prefetch_len, msdu->len);
prefetch_len = roundup(prefetch_len, 4);
- /* Since HTT 3.0 there is no separate mgmt tx command. However in case
- * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
- * fragment list host driver specifies directly frame pointer. */
- use_frags = htt->target_version_major < 3 ||
- !ieee80211_is_mgmt(hdr->frame_control);
-
skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC,
&paddr);
if (!skb_cb->htt.txbuf) {
@@ -466,7 +459,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
if (res)
goto err_free_txbuf;
- if (likely(use_frags)) {
+ switch (skb_cb->txmode) {
+ case ATH10K_HW_TXRX_RAW:
+ case ATH10K_HW_TXRX_NATIVE_WIFI:
+ flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
+ /* pass through */
+ case ATH10K_HW_TXRX_ETHERNET:
frags = skb_cb->htt.txbuf->frags;
frags[0].paddr = __cpu_to_le32(skb_cb->paddr);
@@ -474,15 +472,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
frags[1].paddr = 0;
frags[1].len = 0;
- flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
- HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+ flags0 |= SM(skb_cb->txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
frags_paddr = skb_cb->htt.txbuf_paddr;
- } else {
+ break;
+ case ATH10K_HW_TXRX_MGMT:
flags0 |= SM(ATH10K_HW_TXRX_MGMT,
HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+ flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
frags_paddr = skb_cb->paddr;
+ break;
}
/* Normally all commands go through HTC which manages tx credits for
@@ -508,11 +508,9 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
prefetch_len);
skb_cb->htt.txbuf->htc_hdr.flags = 0;
- if (!ieee80211_has_protected(hdr->frame_control))
+ if (!skb_cb->is_protected)
flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
- flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
-
flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID);
if (msdu->ip_summed == CHECKSUM_PARTIAL) {
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index 839a8791fb9e..5997f00afe3b 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -15,6 +15,7 @@
*/
#include <linux/types.h>
+#include "core.h"
#include "hw.h"
const struct ath10k_hw_regs qca988x_regs = {
@@ -56,3 +57,23 @@ const struct ath10k_hw_regs qca6174_regs = {
.soc_chip_id_address = 0x000f0,
.scratch_3_address = 0x0028,
};
+
+void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
+ u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev)
+{
+ u32 cc_fix = 0;
+
+ survey->filled |= SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY;
+
+ if (ar->hw_params.has_shifted_cc_wraparound && cc < cc_prev) {
+ cc_fix = 0x7fffffff;
+ survey->filled &= ~SURVEY_INFO_TIME_BUSY;
+ }
+
+ cc -= cc_prev - cc_fix;
+ rcc -= rcc_prev;
+
+ survey->time = CCNT_TO_MSEC(cc);
+ survey->time_busy = CCNT_TO_MSEC(rcc);
+}
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 460771fcfe9e..85cca29375fe 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -78,6 +78,9 @@ enum qca6174_chip_id_rev {
/* added support for ATH10K_FW_IE_WMI_OP_VERSION */
#define ATH10K_FW_API4_FILE "firmware-4.bin"
+/* HTT id conflict fix for management frames over HTT */
+#define ATH10K_FW_API5_FILE "firmware-5.bin"
+
#define ATH10K_FW_UTF_FILE "utf.bin"
/* includes also the null byte */
@@ -104,6 +107,11 @@ enum ath10k_fw_ie_type {
* FW API 4 and above.
*/
ATH10K_FW_IE_WMI_OP_VERSION = 5,
+
+ /* HTT "operations" interface version, 32 bit value. Supported from
+ * FW API 5 and above.
+ */
+ ATH10K_FW_IE_HTT_OP_VERSION = 6,
};
enum ath10k_fw_wmi_op_version {
@@ -119,6 +127,20 @@ enum ath10k_fw_wmi_op_version {
ATH10K_FW_WMI_OP_VERSION_MAX,
};
+enum ath10k_fw_htt_op_version {
+ ATH10K_FW_HTT_OP_VERSION_UNSET = 0,
+
+ ATH10K_FW_HTT_OP_VERSION_MAIN = 1,
+
+ /* also used in 10.2 and 10.2.4 branches */
+ ATH10K_FW_HTT_OP_VERSION_10_1 = 2,
+
+ ATH10K_FW_HTT_OP_VERSION_TLV = 3,
+
+ /* keep last */
+ ATH10K_FW_HTT_OP_VERSION_MAX,
+};
+
enum ath10k_hw_rev {
ATH10K_HW_QCA988X,
ATH10K_HW_QCA6174,
@@ -147,6 +169,9 @@ struct ath10k_hw_regs {
extern const struct ath10k_hw_regs qca988x_regs;
extern const struct ath10k_hw_regs qca6174_regs;
+void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
+ u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev);
+
#define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X)
#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174)
@@ -180,6 +205,27 @@ struct ath10k_pktlog_hdr {
u8 payload[0];
} __packed;
+enum ath10k_hw_rate_ofdm {
+ ATH10K_HW_RATE_OFDM_48M = 0,
+ ATH10K_HW_RATE_OFDM_24M,
+ ATH10K_HW_RATE_OFDM_12M,
+ ATH10K_HW_RATE_OFDM_6M,
+ ATH10K_HW_RATE_OFDM_54M,
+ ATH10K_HW_RATE_OFDM_36M,
+ ATH10K_HW_RATE_OFDM_18M,
+ ATH10K_HW_RATE_OFDM_9M,
+};
+
+enum ath10k_hw_rate_cck {
+ ATH10K_HW_RATE_CCK_LP_11M = 0,
+ ATH10K_HW_RATE_CCK_LP_5_5M,
+ ATH10K_HW_RATE_CCK_LP_2M,
+ ATH10K_HW_RATE_CCK_LP_1M,
+ ATH10K_HW_RATE_CCK_SP_11M,
+ ATH10K_HW_RATE_CCK_SP_5_5M,
+ ATH10K_HW_RATE_CCK_SP_2M,
+};
+
/* Target specific defines for MAIN firmware */
#define TARGET_NUM_VDEVS 8
#define TARGET_NUM_PEER_AST 2
@@ -223,7 +269,7 @@ struct ath10k_pktlog_hdr {
#define TARGET_10X_NUM_WDS_ENTRIES 32
#define TARGET_10X_DMA_BURST_SIZE 0
#define TARGET_10X_MAC_AGGR_DELIM 0
-#define TARGET_10X_AST_SKID_LIMIT 16
+#define TARGET_10X_AST_SKID_LIMIT 128
#define TARGET_10X_NUM_STATIONS 128
#define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \
(TARGET_10X_NUM_VDEVS))
@@ -256,13 +302,13 @@ struct ath10k_pktlog_hdr {
#define TARGET_10_2_DMA_BURST_SIZE 1
/* Target specific defines for WMI-TLV firmware */
-#define TARGET_TLV_NUM_VDEVS 3
+#define TARGET_TLV_NUM_VDEVS 4
#define TARGET_TLV_NUM_STATIONS 32
-#define TARGET_TLV_NUM_PEERS ((TARGET_TLV_NUM_STATIONS) + \
- (TARGET_TLV_NUM_VDEVS) + \
- 2)
+#define TARGET_TLV_NUM_PEERS 35
+#define TARGET_TLV_NUM_TDLS_VDEVS 1
#define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2)
#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
+#define TARGET_TLV_NUM_WOW_PATTERNS 22
/* Number of Copy Engines supported */
#define CE_COUNT 8
@@ -406,6 +452,9 @@ struct ath10k_pktlog_hdr {
#define SCRATCH_3_ADDRESS ar->regs->scratch_3_address
#define CPU_INTR_ADDRESS 0x0010
+/* Cycle counters are running at 88MHz */
+#define CCNT_TO_MSEC(x) ((x) / 88000)
+
/* Firmware indications to the Host via SCRATCH_3 register. */
#define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS)
#define FW_IND_EVENT_PENDING 1
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 973485bd4121..218b6af63447 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -28,7 +28,131 @@
#include "txrx.h"
#include "testmode.h"
#include "wmi.h"
+#include "wmi-tlv.h"
#include "wmi-ops.h"
+#include "wow.h"
+
+/*********/
+/* Rates */
+/*********/
+
+static struct ieee80211_rate ath10k_rates[] = {
+ { .bitrate = 10,
+ .hw_value = ATH10K_HW_RATE_CCK_LP_1M },
+ { .bitrate = 20,
+ .hw_value = ATH10K_HW_RATE_CCK_LP_2M,
+ .hw_value_short = ATH10K_HW_RATE_CCK_SP_2M,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55,
+ .hw_value = ATH10K_HW_RATE_CCK_LP_5_5M,
+ .hw_value_short = ATH10K_HW_RATE_CCK_SP_5_5M,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110,
+ .hw_value = ATH10K_HW_RATE_CCK_LP_11M,
+ .hw_value_short = ATH10K_HW_RATE_CCK_SP_11M,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+
+ { .bitrate = 60, .hw_value = ATH10K_HW_RATE_OFDM_6M },
+ { .bitrate = 90, .hw_value = ATH10K_HW_RATE_OFDM_9M },
+ { .bitrate = 120, .hw_value = ATH10K_HW_RATE_OFDM_12M },
+ { .bitrate = 180, .hw_value = ATH10K_HW_RATE_OFDM_18M },
+ { .bitrate = 240, .hw_value = ATH10K_HW_RATE_OFDM_24M },
+ { .bitrate = 360, .hw_value = ATH10K_HW_RATE_OFDM_36M },
+ { .bitrate = 480, .hw_value = ATH10K_HW_RATE_OFDM_48M },
+ { .bitrate = 540, .hw_value = ATH10K_HW_RATE_OFDM_54M },
+};
+
+#define ATH10K_MAC_FIRST_OFDM_RATE_IDX 4
+
+#define ath10k_a_rates (ath10k_rates + ATH10K_MAC_FIRST_OFDM_RATE_IDX)
+#define ath10k_a_rates_size (ARRAY_SIZE(ath10k_rates) - \
+ ATH10K_MAC_FIRST_OFDM_RATE_IDX)
+#define ath10k_g_rates (ath10k_rates + 0)
+#define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates))
+
+static bool ath10k_mac_bitrate_is_cck(int bitrate)
+{
+ switch (bitrate) {
+ case 10:
+ case 20:
+ case 55:
+ case 110:
+ return true;
+ }
+
+ return false;
+}
+
+static u8 ath10k_mac_bitrate_to_rate(int bitrate)
+{
+ return DIV_ROUND_UP(bitrate, 5) |
+ (ath10k_mac_bitrate_is_cck(bitrate) ? BIT(7) : 0);
+}
+
+u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
+ u8 hw_rate)
+{
+ const struct ieee80211_rate *rate;
+ int i;
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ rate = &sband->bitrates[i];
+
+ if (rate->hw_value == hw_rate)
+ return i;
+ else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE &&
+ rate->hw_value_short == hw_rate)
+ return i;
+ }
+
+ return 0;
+}
+
+u8 ath10k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
+ u32 bitrate)
+{
+ int i;
+
+ for (i = 0; i < sband->n_bitrates; i++)
+ if (sband->bitrates[i].bitrate == bitrate)
+ return i;
+
+ return 0;
+}
+
+static int ath10k_mac_get_max_vht_mcs_map(u16 mcs_map, int nss)
+{
+ switch ((mcs_map >> (2 * nss)) & 0x3) {
+ case IEEE80211_VHT_MCS_SUPPORT_0_7: return BIT(8) - 1;
+ case IEEE80211_VHT_MCS_SUPPORT_0_8: return BIT(9) - 1;
+ case IEEE80211_VHT_MCS_SUPPORT_0_9: return BIT(10) - 1;
+ }
+ return 0;
+}
+
+static u32
+ath10k_mac_max_ht_nss(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
+{
+ int nss;
+
+ for (nss = IEEE80211_HT_MCS_MASK_LEN - 1; nss >= 0; nss--)
+ if (ht_mcs_mask[nss])
+ return nss + 1;
+
+ return 1;
+}
+
+static u32
+ath10k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
+{
+ int nss;
+
+ for (nss = NL80211_VHT_NSS_MAX - 1; nss >= 0; nss--)
+ if (vht_mcs_mask[nss])
+ return nss + 1;
+
+ return 1;
+}
/**********/
/* Crypto */
@@ -37,7 +161,7 @@
static int ath10k_send_key(struct ath10k_vif *arvif,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd,
- const u8 *macaddr, bool def_idx)
+ const u8 *macaddr, u32 flags)
{
struct ath10k *ar = arvif->ar;
struct wmi_vdev_install_key_arg arg = {
@@ -45,16 +169,12 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
.key_idx = key->keyidx,
.key_len = key->keylen,
.key_data = key->key,
+ .key_flags = flags,
.macaddr = macaddr,
};
lockdep_assert_held(&arvif->ar->conf_mutex);
- if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
- arg.key_flags = WMI_KEY_PAIRWISE;
- else
- arg.key_flags = WMI_KEY_GROUP;
-
switch (key->cipher) {
case WLAN_CIPHER_SUITE_CCMP:
arg.key_cipher = WMI_CIPHER_AES_CCM;
@@ -68,17 +188,10 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
arg.key_cipher = WMI_CIPHER_WEP;
- /* AP/IBSS mode requires self-key to be groupwise
- * Otherwise pairwise key must be set */
- if (memcmp(macaddr, arvif->vif->addr, ETH_ALEN))
- arg.key_flags = WMI_KEY_PAIRWISE;
-
- if (def_idx)
- arg.key_flags |= WMI_KEY_TX_USAGE;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
- /* this one needs to be done in software */
- return 1;
+ WARN_ON(1);
+ return -EINVAL;
default:
ath10k_warn(ar, "cipher %d is not supported\n", key->cipher);
return -EOPNOTSUPP;
@@ -95,21 +208,22 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
static int ath10k_install_key(struct ath10k_vif *arvif,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd,
- const u8 *macaddr, bool def_idx)
+ const u8 *macaddr, u32 flags)
{
struct ath10k *ar = arvif->ar;
int ret;
+ unsigned long time_left;
lockdep_assert_held(&ar->conf_mutex);
reinit_completion(&ar->install_key_done);
- ret = ath10k_send_key(arvif, key, cmd, macaddr, def_idx);
+ ret = ath10k_send_key(arvif, key, cmd, macaddr, flags);
if (ret)
return ret;
- ret = wait_for_completion_timeout(&ar->install_key_done, 3*HZ);
- if (ret == 0)
+ time_left = wait_for_completion_timeout(&ar->install_key_done, 3 * HZ);
+ if (time_left == 0)
return -ETIMEDOUT;
return 0;
@@ -122,7 +236,7 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
struct ath10k_peer *peer;
int ret;
int i;
- bool def_idx;
+ u32 flags;
lockdep_assert_held(&ar->conf_mutex);
@@ -136,14 +250,20 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
for (i = 0; i < ARRAY_SIZE(arvif->wep_keys); i++) {
if (arvif->wep_keys[i] == NULL)
continue;
- /* set TX_USAGE flag for default key id */
- if (arvif->def_wep_key_idx == i)
- def_idx = true;
- else
- def_idx = false;
+
+ flags = 0;
+ flags |= WMI_KEY_PAIRWISE;
+
+ ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY,
+ addr, flags);
+ if (ret)
+ return ret;
+
+ flags = 0;
+ flags |= WMI_KEY_GROUP;
ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY,
- addr, def_idx);
+ addr, flags);
if (ret)
return ret;
@@ -152,6 +272,27 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
spin_unlock_bh(&ar->data_lock);
}
+ /* In some cases (notably with static WEP IBSS with multiple keys)
+ * multicast Tx becomes broken. Both pairwise and groupwise keys are
+ * installed already. Using WMI_KEY_TX_USAGE in different combinations
+ * didn't seem help. Using def_keyid vdev parameter seems to be
+ * effective so use that.
+ *
+ * FIXME: Revisit. Perhaps this can be done in a less hacky way.
+ */
+ if (arvif->def_wep_key_idx == -1)
+ return 0;
+
+ ret = ath10k_wmi_vdev_set_param(arvif->ar,
+ arvif->vdev_id,
+ arvif->ar->wmi.vdev_param->def_keyid,
+ arvif->def_wep_key_idx);
+ if (ret) {
+ ath10k_warn(ar, "failed to re-set def wpa key idxon vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
return 0;
}
@@ -163,6 +304,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
int first_errno = 0;
int ret;
int i;
+ u32 flags = 0;
lockdep_assert_held(&ar->conf_mutex);
@@ -179,7 +321,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
/* key flags are not required to delete the key */
ret = ath10k_install_key(arvif, peer->keys[i],
- DISABLE_KEY, addr, false);
+ DISABLE_KEY, addr, flags);
if (ret && first_errno == 0)
first_errno = ret;
@@ -229,6 +371,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
int first_errno = 0;
int ret;
int i;
+ u32 flags = 0;
lockdep_assert_held(&ar->conf_mutex);
@@ -254,7 +397,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
if (i == ARRAY_SIZE(peer->keys))
break;
/* key flags are not required to delete the key */
- ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, false);
+ ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, flags);
if (ret && first_errno == 0)
first_errno = ret;
@@ -266,6 +409,39 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
return first_errno;
}
+static int ath10k_mac_vif_update_wep_key(struct ath10k_vif *arvif,
+ struct ieee80211_key_conf *key)
+{
+ struct ath10k *ar = arvif->ar;
+ struct ath10k_peer *peer;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ list_for_each_entry(peer, &ar->peers, list) {
+ if (!memcmp(peer->addr, arvif->vif->addr, ETH_ALEN))
+ continue;
+
+ if (!memcmp(peer->addr, arvif->bssid, ETH_ALEN))
+ continue;
+
+ if (peer->keys[key->keyidx] == key)
+ continue;
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vif vdev %i update key %i needs update\n",
+ arvif->vdev_id, key->keyidx);
+
+ ret = ath10k_install_peer_wep_keys(arvif, peer->addr);
+ if (ret) {
+ ath10k_warn(ar, "failed to update wep keys on vdev %i for peer %pM: %d\n",
+ arvif->vdev_id, peer->addr, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
/*********************/
/* General utilities */
/*********************/
@@ -364,7 +540,56 @@ static u8 ath10k_parse_mpdudensity(u8 mpdudensity)
}
}
-static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
+int ath10k_mac_vif_chan(struct ieee80211_vif *vif,
+ struct cfg80211_chan_def *def)
+{
+ struct ieee80211_chanctx_conf *conf;
+
+ rcu_read_lock();
+ conf = rcu_dereference(vif->chanctx_conf);
+ if (!conf) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+
+ *def = conf->def;
+ rcu_read_unlock();
+
+ return 0;
+}
+
+static void ath10k_mac_num_chanctxs_iter(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *conf,
+ void *data)
+{
+ int *num = data;
+
+ (*num)++;
+}
+
+static int ath10k_mac_num_chanctxs(struct ath10k *ar)
+{
+ int num = 0;
+
+ ieee80211_iter_chan_contexts_atomic(ar->hw,
+ ath10k_mac_num_chanctxs_iter,
+ &num);
+
+ return num;
+}
+
+static void
+ath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *conf,
+ void *data)
+{
+ struct cfg80211_chan_def **def = data;
+
+ *def = &conf->def;
+}
+
+static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr,
+ enum wmi_peer_type peer_type)
{
int ret;
@@ -373,7 +598,7 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
if (ar->num_peers >= ar->max_num_peers)
return -ENOBUFS;
- ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
+ ret = ath10k_wmi_peer_create(ar, vdev_id, addr, peer_type);
if (ret) {
ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n",
addr, vdev_id, ret);
@@ -517,6 +742,38 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
ar->num_stations = 0;
}
+static int ath10k_mac_tdls_peer_update(struct ath10k *ar, u32 vdev_id,
+ struct ieee80211_sta *sta,
+ enum wmi_tdls_peer_state state)
+{
+ int ret;
+ struct wmi_tdls_peer_update_cmd_arg arg = {};
+ struct wmi_tdls_peer_capab_arg cap = {};
+ struct wmi_channel_arg chan_arg = {};
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ arg.vdev_id = vdev_id;
+ arg.peer_state = state;
+ ether_addr_copy(arg.addr, sta->addr);
+
+ cap.peer_max_sp = sta->max_sp;
+ cap.peer_uapsd_queues = sta->uapsd_queues;
+
+ if (state == WMI_TDLS_PEER_STATE_CONNECTED &&
+ !sta->tdls_initiator)
+ cap.is_peer_responder = 1;
+
+ ret = ath10k_wmi_tdls_peer_update(ar, &arg, &cap, &chan_arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to update tdls peer %pM on vdev %i: %i\n",
+ arg.addr, vdev_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/************************/
/* Interface management */
/************************/
@@ -561,16 +818,16 @@ static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
{
- int ret;
+ unsigned long time_left;
lockdep_assert_held(&ar->conf_mutex);
if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
return -ESHUTDOWN;
- ret = wait_for_completion_timeout(&ar->vdev_setup_done,
- ATH10K_VDEV_SETUP_TIMEOUT_HZ);
- if (ret == 0)
+ time_left = wait_for_completion_timeout(&ar->vdev_setup_done,
+ ATH10K_VDEV_SETUP_TIMEOUT_HZ);
+ if (time_left == 0)
return -ETIMEDOUT;
return 0;
@@ -578,13 +835,21 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
{
- struct cfg80211_chan_def *chandef = &ar->chandef;
+ struct cfg80211_chan_def *chandef = NULL;
struct ieee80211_channel *channel = chandef->chan;
struct wmi_vdev_start_request_arg arg = {};
int ret = 0;
lockdep_assert_held(&ar->conf_mutex);
+ ieee80211_iter_chan_contexts_atomic(ar->hw,
+ ath10k_mac_get_any_chandef_iter,
+ &chandef);
+ if (WARN_ON_ONCE(!chandef))
+ return -ENOENT;
+
+ channel = chandef->chan;
+
arg.vdev_id = vdev_id;
arg.channel.freq = channel->center_freq;
arg.channel.band_center_freq1 = chandef->center_freq1;
@@ -766,27 +1031,78 @@ static int ath10k_monitor_stop(struct ath10k *ar)
return 0;
}
+static bool ath10k_mac_monitor_vdev_is_needed(struct ath10k *ar)
+{
+ int num_ctx;
+
+ /* At least one chanctx is required to derive a channel to start
+ * monitor vdev on.
+ */
+ num_ctx = ath10k_mac_num_chanctxs(ar);
+ if (num_ctx == 0)
+ return false;
+
+ /* If there's already an existing special monitor interface then don't
+ * bother creating another monitor vdev.
+ */
+ if (ar->monitor_arvif)
+ return false;
+
+ return ar->monitor ||
+ test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+}
+
+static bool ath10k_mac_monitor_vdev_is_allowed(struct ath10k *ar)
+{
+ int num_ctx;
+
+ num_ctx = ath10k_mac_num_chanctxs(ar);
+
+ /* FIXME: Current interface combinations and cfg80211/mac80211 code
+ * shouldn't allow this but make sure to prevent handling the following
+ * case anyway since multi-channel DFS hasn't been tested at all.
+ */
+ if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags) && num_ctx > 1)
+ return false;
+
+ return true;
+}
+
static int ath10k_monitor_recalc(struct ath10k *ar)
{
- bool should_start;
+ bool needed;
+ bool allowed;
+ int ret;
lockdep_assert_held(&ar->conf_mutex);
- should_start = ar->monitor ||
- ar->filter_flags & FIF_PROMISC_IN_BSS ||
- test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+ needed = ath10k_mac_monitor_vdev_is_needed(ar);
+ allowed = ath10k_mac_monitor_vdev_is_allowed(ar);
ath10k_dbg(ar, ATH10K_DBG_MAC,
- "mac monitor recalc started? %d should? %d\n",
- ar->monitor_started, should_start);
+ "mac monitor recalc started? %d needed? %d allowed? %d\n",
+ ar->monitor_started, needed, allowed);
+
+ if (WARN_ON(needed && !allowed)) {
+ if (ar->monitor_started) {
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopping disallowed monitor\n");
- if (should_start == ar->monitor_started)
+ ret = ath10k_monitor_stop(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to stop disallowed monitor: %d\n", ret);
+ /* not serious */
+ }
+
+ return -EPERM;
+ }
+
+ if (needed == ar->monitor_started)
return 0;
- if (should_start)
+ if (needed)
return ath10k_monitor_start(ar);
-
- return ath10k_monitor_stop(ar);
+ else
+ return ath10k_monitor_stop(ar);
}
static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
@@ -798,12 +1114,14 @@ static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
vdev_param = ar->wmi.vdev_param->enable_rtscts;
- if (arvif->use_cts_prot || arvif->num_legacy_stations > 0)
- rts_cts |= SM(WMI_RTSCTS_ENABLED, WMI_RTSCTS_SET);
+ rts_cts |= SM(WMI_RTSCTS_ENABLED, WMI_RTSCTS_SET);
if (arvif->num_legacy_stations > 0)
rts_cts |= SM(WMI_RTSCTS_ACROSS_SW_RETRIES,
WMI_RTSCTS_PROFILE);
+ else
+ rts_cts |= SM(WMI_RTSCTS_FOR_SECOND_RATESERIES,
+ WMI_RTSCTS_PROFILE);
return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
rts_cts);
@@ -846,6 +1164,27 @@ static int ath10k_stop_cac(struct ath10k *ar)
return 0;
}
+static void ath10k_mac_has_radar_iter(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *conf,
+ void *data)
+{
+ bool *ret = data;
+
+ if (!*ret && conf->radar_enabled)
+ *ret = true;
+}
+
+static bool ath10k_mac_has_radar_enabled(struct ath10k *ar)
+{
+ bool has_radar = false;
+
+ ieee80211_iter_chan_contexts_atomic(ar->hw,
+ ath10k_mac_has_radar_iter,
+ &has_radar);
+
+ return has_radar;
+}
+
static void ath10k_recalc_radar_detection(struct ath10k *ar)
{
int ret;
@@ -854,7 +1193,7 @@ static void ath10k_recalc_radar_detection(struct ath10k *ar)
ath10k_stop_cac(ar);
- if (!ar->radar_enabled)
+ if (!ath10k_mac_has_radar_enabled(ar))
return;
if (ar->num_started_vdevs > 0)
@@ -872,10 +1211,44 @@ static void ath10k_recalc_radar_detection(struct ath10k *ar)
}
}
-static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart)
+static int ath10k_vdev_stop(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ reinit_completion(&ar->vdev_setup_done);
+
+ ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
+ if (ret) {
+ ath10k_warn(ar, "failed to stop WMI vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ ret = ath10k_vdev_setup_sync(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to syncronise setup for vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ WARN_ON(ar->num_started_vdevs == 0);
+
+ if (ar->num_started_vdevs != 0) {
+ ar->num_started_vdevs--;
+ ath10k_recalc_radar_detection(ar);
+ }
+
+ return ret;
+}
+
+static int ath10k_vdev_start_restart(struct ath10k_vif *arvif,
+ const struct cfg80211_chan_def *chandef,
+ bool restart)
{
struct ath10k *ar = arvif->ar;
- struct cfg80211_chan_def *chandef = &ar->chandef;
struct wmi_vdev_start_request_arg arg = {};
int ret = 0;
@@ -939,47 +1312,16 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart)
return ret;
}
-static int ath10k_vdev_start(struct ath10k_vif *arvif)
+static int ath10k_vdev_start(struct ath10k_vif *arvif,
+ const struct cfg80211_chan_def *def)
{
- return ath10k_vdev_start_restart(arvif, false);
+ return ath10k_vdev_start_restart(arvif, def, false);
}
-static int ath10k_vdev_restart(struct ath10k_vif *arvif)
-{
- return ath10k_vdev_start_restart(arvif, true);
-}
-
-static int ath10k_vdev_stop(struct ath10k_vif *arvif)
+static int ath10k_vdev_restart(struct ath10k_vif *arvif,
+ const struct cfg80211_chan_def *def)
{
- struct ath10k *ar = arvif->ar;
- int ret;
-
- lockdep_assert_held(&ar->conf_mutex);
-
- reinit_completion(&ar->vdev_setup_done);
-
- ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
- if (ret) {
- ath10k_warn(ar, "failed to stop WMI vdev %i: %d\n",
- arvif->vdev_id, ret);
- return ret;
- }
-
- ret = ath10k_vdev_setup_sync(ar);
- if (ret) {
- ath10k_warn(ar, "failed to synchronize setup for vdev %i stop: %d\n",
- arvif->vdev_id, ret);
- return ret;
- }
-
- WARN_ON(ar->num_started_vdevs == 0);
-
- if (ar->num_started_vdevs != 0) {
- ar->num_started_vdevs--;
- ath10k_recalc_radar_detection(ar);
- }
-
- return ret;
+ return ath10k_vdev_start_restart(arvif, def, true);
}
static int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif,
@@ -1056,6 +1398,10 @@ static int ath10k_mac_setup_bcn_tmpl(struct ath10k_vif *arvif)
if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
return 0;
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
+ arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
+ return 0;
+
bcn = ieee80211_beacon_get_template(hw, vif, &offs);
if (!bcn) {
ath10k_warn(ar, "failed to get beacon template from mac80211\n");
@@ -1101,6 +1447,9 @@ static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif)
if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
return 0;
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
+ return 0;
+
prb = ieee80211_proberesp_get(hw, vif);
if (!prb) {
ath10k_warn(ar, "failed to get probe resp template from mac80211\n");
@@ -1119,6 +1468,80 @@ static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif)
return 0;
}
+static int ath10k_mac_vif_fix_hidden_ssid(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ struct cfg80211_chan_def def;
+ int ret;
+
+ /* When originally vdev is started during assign_vif_chanctx() some
+ * information is missing, notably SSID. Firmware revisions with beacon
+ * offloading require the SSID to be provided during vdev (re)start to
+ * handle hidden SSID properly.
+ *
+ * Vdev restart must be done after vdev has been both started and
+ * upped. Otherwise some firmware revisions (at least 10.2) fail to
+ * deliver vdev restart response event causing timeouts during vdev
+ * syncing in ath10k.
+ *
+ * Note: The vdev down/up and template reinstallation could be skipped
+ * since only wmi-tlv firmware are known to have beacon offload and
+ * wmi-tlv doesn't seem to misbehave like 10.2 wrt vdev restart
+ * response delivery. It's probably more robust to keep it as is.
+ */
+ if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
+ return 0;
+
+ if (WARN_ON(!arvif->is_started))
+ return -EINVAL;
+
+ if (WARN_ON(!arvif->is_up))
+ return -EINVAL;
+
+ if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def)))
+ return -EINVAL;
+
+ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+ if (ret) {
+ ath10k_warn(ar, "failed to bring down ap vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ /* Vdev down reset beacon & presp templates. Reinstall them. Otherwise
+ * firmware will crash upon vdev up.
+ */
+
+ ret = ath10k_mac_setup_bcn_tmpl(arvif);
+ if (ret) {
+ ath10k_warn(ar, "failed to update beacon template: %d\n", ret);
+ return ret;
+ }
+
+ ret = ath10k_mac_setup_prb_tmpl(arvif);
+ if (ret) {
+ ath10k_warn(ar, "failed to update presp template: %d\n", ret);
+ return ret;
+ }
+
+ ret = ath10k_vdev_restart(arvif, &def);
+ if (ret) {
+ ath10k_warn(ar, "failed to restart ap vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
+ arvif->bssid);
+ if (ret) {
+ ath10k_warn(ar, "failed to bring up ap vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static void ath10k_control_beaconing(struct ath10k_vif *arvif,
struct ieee80211_bss_conf *info)
{
@@ -1128,9 +1551,11 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
lockdep_assert_held(&arvif->ar->conf_mutex);
if (!info->enable_beacon) {
- ath10k_vdev_stop(arvif);
+ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+ if (ret)
+ ath10k_warn(ar, "failed to down vdev_id %i: %d\n",
+ arvif->vdev_id, ret);
- arvif->is_started = false;
arvif->is_up = false;
spin_lock_bh(&arvif->ar->data_lock);
@@ -1142,10 +1567,6 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
arvif->tx_seq_no = 0x1000;
- ret = ath10k_vdev_start(arvif);
- if (ret)
- return;
-
arvif->aid = 0;
ether_addr_copy(arvif->bssid, info->bssid);
@@ -1154,13 +1575,18 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
if (ret) {
ath10k_warn(ar, "failed to bring up vdev %d: %i\n",
arvif->vdev_id, ret);
- ath10k_vdev_stop(arvif);
return;
}
- arvif->is_started = true;
arvif->is_up = true;
+ ret = ath10k_mac_vif_fix_hidden_ssid(arvif);
+ if (ret) {
+ ath10k_warn(ar, "failed to fix hidden ssid for vdev %i, expect trouble: %d\n",
+ arvif->vdev_id, ret);
+ return;
+ }
+
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
}
@@ -1175,11 +1601,6 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
lockdep_assert_held(&arvif->ar->conf_mutex);
if (!info->ibss_joined) {
- ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer);
- if (ret)
- ath10k_warn(ar, "failed to delete IBSS self peer %pM for vdev %d: %d\n",
- self_peer, arvif->vdev_id, ret);
-
if (is_zero_ether_addr(arvif->bssid))
return;
@@ -1188,13 +1609,6 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
return;
}
- ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer);
- if (ret) {
- ath10k_warn(ar, "failed to create IBSS self peer %pM for vdev %d: %d\n",
- self_peer, arvif->vdev_id, ret);
- return;
- }
-
vdev_param = arvif->ar->wmi.vdev_param->atim_window;
ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param,
ATH10K_DEFAULT_ATIM);
@@ -1294,7 +1708,14 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
enable_ps = false;
}
- if (enable_ps) {
+ if (!arvif->is_started) {
+ /* mac80211 can update vif powersave state while disconnected.
+ * Firmware doesn't behave nicely and consumes more power than
+ * necessary if PS is disabled on a non-started vdev. Hence
+ * force-enable PS for non-running vdevs.
+ */
+ psmode = WMI_STA_PS_MODE_ENABLED;
+ } else if (enable_ps) {
psmode = WMI_STA_PS_MODE_ENABLED;
param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
@@ -1361,6 +1782,123 @@ static int ath10k_mac_vif_disable_keepalive(struct ath10k_vif *arvif)
return 0;
}
+static void ath10k_mac_vif_ap_csa_count_down(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ struct ieee80211_vif *vif = arvif->vif;
+ int ret;
+
+ lockdep_assert_held(&arvif->ar->conf_mutex);
+
+ if (WARN_ON(!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)))
+ return;
+
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
+ return;
+
+ if (!vif->csa_active)
+ return;
+
+ if (!arvif->is_up)
+ return;
+
+ if (!ieee80211_csa_is_complete(vif)) {
+ ieee80211_csa_update_counter(vif);
+
+ ret = ath10k_mac_setup_bcn_tmpl(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n",
+ ret);
+
+ ret = ath10k_mac_setup_prb_tmpl(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
+ ret);
+ } else {
+ ieee80211_csa_finish(vif);
+ }
+}
+
+static void ath10k_mac_vif_ap_csa_work(struct work_struct *work)
+{
+ struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
+ ap_csa_work);
+ struct ath10k *ar = arvif->ar;
+
+ mutex_lock(&ar->conf_mutex);
+ ath10k_mac_vif_ap_csa_count_down(arvif);
+ mutex_unlock(&ar->conf_mutex);
+}
+
+static void ath10k_mac_handle_beacon_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct sk_buff *skb = data;
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
+ if (vif->type != NL80211_IFTYPE_STATION)
+ return;
+
+ if (!ether_addr_equal(mgmt->bssid, vif->bss_conf.bssid))
+ return;
+
+ cancel_delayed_work(&arvif->connection_loss_work);
+}
+
+void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb)
+{
+ ieee80211_iterate_active_interfaces_atomic(ar->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ ath10k_mac_handle_beacon_iter,
+ skb);
+}
+
+static void ath10k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ u32 *vdev_id = data;
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct ath10k *ar = arvif->ar;
+ struct ieee80211_hw *hw = ar->hw;
+
+ if (arvif->vdev_id != *vdev_id)
+ return;
+
+ if (!arvif->is_up)
+ return;
+
+ ieee80211_beacon_loss(vif);
+
+ /* Firmware doesn't report beacon loss events repeatedly. If AP probe
+ * (done by mac80211) succeeds but beacons do not resume then it
+ * doesn't make sense to continue operation. Queue connection loss work
+ * which can be cancelled when beacon is received.
+ */
+ ieee80211_queue_delayed_work(hw, &arvif->connection_loss_work,
+ ATH10K_CONNECTION_LOSS_HZ);
+}
+
+void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id)
+{
+ ieee80211_iterate_active_interfaces_atomic(ar->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ ath10k_mac_handle_beacon_miss_iter,
+ &vdev_id);
+}
+
+static void ath10k_mac_vif_sta_connection_loss_work(struct work_struct *work)
+{
+ struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
+ connection_loss_work.work);
+ struct ieee80211_vif *vif = arvif->vif;
+
+ if (!arvif->is_up)
+ return;
+
+ ieee80211_connection_loss(vif);
+}
+
/**********************/
/* Station management */
/**********************/
@@ -1388,12 +1926,18 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
struct wmi_peer_assoc_complete_arg *arg)
{
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ u32 aid;
lockdep_assert_held(&ar->conf_mutex);
+ if (vif->type == NL80211_IFTYPE_STATION)
+ aid = vif->bss_conf.aid;
+ else
+ aid = sta->aid;
+
ether_addr_copy(arg->addr, sta->addr);
arg->vdev_id = arvif->vdev_id;
- arg->peer_aid = sta->aid;
+ arg->peer_aid = aid;
arg->peer_flags |= WMI_PEER_AUTH;
arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif);
arg->peer_num_spatial_streams = 1;
@@ -1405,15 +1949,18 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
struct wmi_peer_assoc_complete_arg *arg)
{
struct ieee80211_bss_conf *info = &vif->bss_conf;
+ struct cfg80211_chan_def def;
struct cfg80211_bss *bss;
const u8 *rsnie = NULL;
const u8 *wpaie = NULL;
lockdep_assert_held(&ar->conf_mutex);
- bss = cfg80211_get_bss(ar->hw->wiphy, ar->hw->conf.chandef.chan,
- info->bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY,
- IEEE80211_PRIVACY_ANY);
+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
+ return;
+
+ bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, NULL, 0,
+ IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
if (bss) {
const struct cfg80211_bss_ies *ies;
@@ -1443,19 +1990,29 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
}
static void ath10k_peer_assoc_h_rates(struct ath10k *ar,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct wmi_peer_assoc_complete_arg *arg)
{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct wmi_rate_set_arg *rateset = &arg->peer_legacy_rates;
+ struct cfg80211_chan_def def;
const struct ieee80211_supported_band *sband;
const struct ieee80211_rate *rates;
+ enum ieee80211_band band;
u32 ratemask;
+ u8 rate;
int i;
lockdep_assert_held(&ar->conf_mutex);
- sband = ar->hw->wiphy->bands[ar->hw->conf.chandef.chan->band];
- ratemask = sta->supp_rates[ar->hw->conf.chandef.chan->band];
+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
+ return;
+
+ band = def.chan->band;
+ sband = ar->hw->wiphy->bands[band];
+ ratemask = sta->supp_rates[band];
+ ratemask &= arvif->bitrate_mask.control[band].legacy;
rates = sband->bitrates;
rateset->num_rates = 0;
@@ -1464,24 +2021,66 @@ static void ath10k_peer_assoc_h_rates(struct ath10k *ar,
if (!(ratemask & 1))
continue;
- rateset->rates[rateset->num_rates] = rates->hw_value;
+ rate = ath10k_mac_bitrate_to_rate(rates->bitrate);
+ rateset->rates[rateset->num_rates] = rate;
rateset->num_rates++;
}
}
+static bool
+ath10k_peer_assoc_h_ht_masked(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
+{
+ int nss;
+
+ for (nss = 0; nss < IEEE80211_HT_MCS_MASK_LEN; nss++)
+ if (ht_mcs_mask[nss])
+ return false;
+
+ return true;
+}
+
+static bool
+ath10k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
+{
+ int nss;
+
+ for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++)
+ if (vht_mcs_mask[nss])
+ return false;
+
+ return true;
+}
+
static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct wmi_peer_assoc_complete_arg *arg)
{
const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
- int i, n;
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct cfg80211_chan_def def;
+ enum ieee80211_band band;
+ const u8 *ht_mcs_mask;
+ const u16 *vht_mcs_mask;
+ int i, n, max_nss;
u32 stbc;
lockdep_assert_held(&ar->conf_mutex);
+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
+ return;
+
if (!ht_cap->ht_supported)
return;
+ band = def.chan->band;
+ ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
+ vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
+
+ if (ath10k_peer_assoc_h_ht_masked(ht_mcs_mask) &&
+ ath10k_peer_assoc_h_vht_masked(vht_mcs_mask))
+ return;
+
arg->peer_flags |= WMI_PEER_HT;
arg->peer_max_mpdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
ht_cap->ampdu_factor)) - 1;
@@ -1500,11 +2099,13 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
arg->peer_rate_caps |= WMI_RC_CW40_FLAG;
}
- if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
- arg->peer_rate_caps |= WMI_RC_SGI_FLAG;
+ if (arvif->bitrate_mask.control[band].gi != NL80211_TXRATE_FORCE_LGI) {
+ if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
+ arg->peer_rate_caps |= WMI_RC_SGI_FLAG;
- if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40)
- arg->peer_rate_caps |= WMI_RC_SGI_FLAG;
+ if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40)
+ arg->peer_rate_caps |= WMI_RC_SGI_FLAG;
+ }
if (ht_cap->cap & IEEE80211_HT_CAP_TX_STBC) {
arg->peer_rate_caps |= WMI_RC_TX_STBC_FLAG;
@@ -1524,9 +2125,12 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
else if (ht_cap->mcs.rx_mask[1])
arg->peer_rate_caps |= WMI_RC_DS_FLAG;
- for (i = 0, n = 0; i < IEEE80211_HT_MCS_MASK_LEN*8; i++)
- if (ht_cap->mcs.rx_mask[i/8] & (1 << i%8))
+ for (i = 0, n = 0, max_nss = 0; i < IEEE80211_HT_MCS_MASK_LEN * 8; i++)
+ if ((ht_cap->mcs.rx_mask[i / 8] & BIT(i % 8)) &&
+ (ht_mcs_mask[i / 8] & BIT(i % 8))) {
+ max_nss = (i / 8) + 1;
arg->peer_ht_rates.rates[n++] = i;
+ }
/*
* This is a workaround for HT-enabled STAs which break the spec
@@ -1543,7 +2147,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
arg->peer_ht_rates.rates[i] = i;
} else {
arg->peer_ht_rates.num_rates = n;
- arg->peer_num_spatial_streams = sta->rx_nss;
+ arg->peer_num_spatial_streams = max_nss;
}
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
@@ -1619,19 +2223,84 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
return 0;
}
+static u16
+ath10k_peer_assoc_h_vht_limit(u16 tx_mcs_set,
+ const u16 vht_mcs_limit[NL80211_VHT_NSS_MAX])
+{
+ int idx_limit;
+ int nss;
+ u16 mcs_map;
+ u16 mcs;
+
+ for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
+ mcs_map = ath10k_mac_get_max_vht_mcs_map(tx_mcs_set, nss) &
+ vht_mcs_limit[nss];
+
+ if (mcs_map)
+ idx_limit = fls(mcs_map) - 1;
+ else
+ idx_limit = -1;
+
+ switch (idx_limit) {
+ case 0: /* fall through */
+ case 1: /* fall through */
+ case 2: /* fall through */
+ case 3: /* fall through */
+ case 4: /* fall through */
+ case 5: /* fall through */
+ case 6: /* fall through */
+ default:
+ /* see ath10k_mac_can_set_bitrate_mask() */
+ WARN_ON(1);
+ /* fall through */
+ case -1:
+ mcs = IEEE80211_VHT_MCS_NOT_SUPPORTED;
+ break;
+ case 7:
+ mcs = IEEE80211_VHT_MCS_SUPPORT_0_7;
+ break;
+ case 8:
+ mcs = IEEE80211_VHT_MCS_SUPPORT_0_8;
+ break;
+ case 9:
+ mcs = IEEE80211_VHT_MCS_SUPPORT_0_9;
+ break;
+ }
+
+ tx_mcs_set &= ~(0x3 << (nss * 2));
+ tx_mcs_set |= mcs << (nss * 2);
+ }
+
+ return tx_mcs_set;
+}
+
static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct wmi_peer_assoc_complete_arg *arg)
{
const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct cfg80211_chan_def def;
+ enum ieee80211_band band;
+ const u16 *vht_mcs_mask;
u8 ampdu_factor;
+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
+ return;
+
if (!vht_cap->vht_supported)
return;
+ band = def.chan->band;
+ vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
+
+ if (ath10k_peer_assoc_h_vht_masked(vht_mcs_mask))
+ return;
+
arg->peer_flags |= WMI_PEER_VHT;
- if (ar->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
+ if (def.chan->band == IEEE80211_BAND_2GHZ)
arg->peer_flags |= WMI_PEER_VHT_2G;
arg->peer_vht_caps = vht_cap->cap;
@@ -1657,8 +2326,8 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
__le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map);
arg->peer_vht_rates.tx_max_rate =
__le16_to_cpu(vht_cap->vht_mcs.tx_highest);
- arg->peer_vht_rates.tx_mcs_set =
- __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
+ arg->peer_vht_rates.tx_mcs_set = ath10k_peer_assoc_h_vht_limit(
+ __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
sta->addr, arg->peer_max_mpdu, arg->peer_flags);
@@ -1697,10 +2366,10 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
sta->addr, !!(arg->peer_flags & WMI_PEER_QOS));
}
-static bool ath10k_mac_sta_has_11g_rates(struct ieee80211_sta *sta)
+static bool ath10k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta)
{
- /* First 4 rates in ath10k_rates are CCK (11b) rates. */
- return sta->supp_rates[IEEE80211_BAND_2GHZ] >> 4;
+ return sta->supp_rates[IEEE80211_BAND_2GHZ] >>
+ ATH10K_MAC_FIRST_OFDM_RATE_IDX;
}
static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
@@ -1708,21 +2377,35 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
struct ieee80211_sta *sta,
struct wmi_peer_assoc_complete_arg *arg)
{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct cfg80211_chan_def def;
+ enum ieee80211_band band;
+ const u8 *ht_mcs_mask;
+ const u16 *vht_mcs_mask;
enum wmi_phy_mode phymode = MODE_UNKNOWN;
- switch (ar->hw->conf.chandef.chan->band) {
+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
+ return;
+
+ band = def.chan->band;
+ ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
+ vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
+
+ switch (band) {
case IEEE80211_BAND_2GHZ:
- if (sta->vht_cap.vht_supported) {
+ if (sta->vht_cap.vht_supported &&
+ !ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) {
if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
phymode = MODE_11AC_VHT40;
else
phymode = MODE_11AC_VHT20;
- } else if (sta->ht_cap.ht_supported) {
+ } else if (sta->ht_cap.ht_supported &&
+ !ath10k_peer_assoc_h_ht_masked(ht_mcs_mask)) {
if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
phymode = MODE_11NG_HT40;
else
phymode = MODE_11NG_HT20;
- } else if (ath10k_mac_sta_has_11g_rates(sta)) {
+ } else if (ath10k_mac_sta_has_ofdm_only(sta)) {
phymode = MODE_11G;
} else {
phymode = MODE_11B;
@@ -1733,15 +2416,17 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
/*
* Check VHT first.
*/
- if (sta->vht_cap.vht_supported) {
+ if (sta->vht_cap.vht_supported &&
+ !ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) {
if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
phymode = MODE_11AC_VHT80;
else if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
phymode = MODE_11AC_VHT40;
else if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
phymode = MODE_11AC_VHT20;
- } else if (sta->ht_cap.ht_supported) {
- if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
+ } else if (sta->ht_cap.ht_supported &&
+ !ath10k_peer_assoc_h_ht_masked(ht_mcs_mask)) {
+ if (sta->bandwidth >= IEEE80211_STA_RX_BW_40)
phymode = MODE_11NA_HT40;
else
phymode = MODE_11NA_HT20;
@@ -1772,9 +2457,9 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
ath10k_peer_assoc_h_basic(ar, vif, sta, arg);
ath10k_peer_assoc_h_crypto(ar, vif, arg);
- ath10k_peer_assoc_h_rates(ar, sta, arg);
- ath10k_peer_assoc_h_ht(ar, sta, arg);
- ath10k_peer_assoc_h_vht(ar, sta, arg);
+ ath10k_peer_assoc_h_rates(ar, vif, sta, arg);
+ ath10k_peer_assoc_h_ht(ar, vif, sta, arg);
+ ath10k_peer_assoc_h_vht(ar, vif, sta, arg);
ath10k_peer_assoc_h_qos(ar, vif, sta, arg);
ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
@@ -1993,6 +2678,8 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
}
arvif->is_up = false;
+
+ cancel_delayed_work_sync(&arvif->connection_loss_work);
}
static int ath10k_station_assoc(struct ath10k *ar,
@@ -2013,7 +2700,6 @@ static int ath10k_station_assoc(struct ath10k *ar,
return ret;
}
- peer_arg.peer_reassoc = reassoc;
ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
if (ret) {
ath10k_warn(ar, "failed to run peer assoc for STA %pM vdev %i: %d\n",
@@ -2274,6 +2960,149 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
/* TX handlers */
/***************/
+void ath10k_mac_tx_lock(struct ath10k *ar, int reason)
+{
+ lockdep_assert_held(&ar->htt.tx_lock);
+
+ WARN_ON(reason >= ATH10K_TX_PAUSE_MAX);
+ ar->tx_paused |= BIT(reason);
+ ieee80211_stop_queues(ar->hw);
+}
+
+static void ath10k_mac_tx_unlock_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct ath10k *ar = data;
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
+ if (arvif->tx_paused)
+ return;
+
+ ieee80211_wake_queue(ar->hw, arvif->vdev_id);
+}
+
+void ath10k_mac_tx_unlock(struct ath10k *ar, int reason)
+{
+ lockdep_assert_held(&ar->htt.tx_lock);
+
+ WARN_ON(reason >= ATH10K_TX_PAUSE_MAX);
+ ar->tx_paused &= ~BIT(reason);
+
+ if (ar->tx_paused)
+ return;
+
+ ieee80211_iterate_active_interfaces_atomic(ar->hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ ath10k_mac_tx_unlock_iter,
+ ar);
+}
+
+void ath10k_mac_vif_tx_lock(struct ath10k_vif *arvif, int reason)
+{
+ struct ath10k *ar = arvif->ar;
+
+ lockdep_assert_held(&ar->htt.tx_lock);
+
+ WARN_ON(reason >= BITS_PER_LONG);
+ arvif->tx_paused |= BIT(reason);
+ ieee80211_stop_queue(ar->hw, arvif->vdev_id);
+}
+
+void ath10k_mac_vif_tx_unlock(struct ath10k_vif *arvif, int reason)
+{
+ struct ath10k *ar = arvif->ar;
+
+ lockdep_assert_held(&ar->htt.tx_lock);
+
+ WARN_ON(reason >= BITS_PER_LONG);
+ arvif->tx_paused &= ~BIT(reason);
+
+ if (ar->tx_paused)
+ return;
+
+ if (arvif->tx_paused)
+ return;
+
+ ieee80211_wake_queue(ar->hw, arvif->vdev_id);
+}
+
+static void ath10k_mac_vif_handle_tx_pause(struct ath10k_vif *arvif,
+ enum wmi_tlv_tx_pause_id pause_id,
+ enum wmi_tlv_tx_pause_action action)
+{
+ struct ath10k *ar = arvif->ar;
+
+ lockdep_assert_held(&ar->htt.tx_lock);
+
+ switch (pause_id) {
+ case WMI_TLV_TX_PAUSE_ID_MCC:
+ case WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA:
+ case WMI_TLV_TX_PAUSE_ID_P2P_GO_PS:
+ case WMI_TLV_TX_PAUSE_ID_AP_PS:
+ case WMI_TLV_TX_PAUSE_ID_IBSS_PS:
+ switch (action) {
+ case WMI_TLV_TX_PAUSE_ACTION_STOP:
+ ath10k_mac_vif_tx_lock(arvif, pause_id);
+ break;
+ case WMI_TLV_TX_PAUSE_ACTION_WAKE:
+ ath10k_mac_vif_tx_unlock(arvif, pause_id);
+ break;
+ default:
+ ath10k_warn(ar, "received unknown tx pause action %d on vdev %i, ignoring\n",
+ action, arvif->vdev_id);
+ break;
+ }
+ break;
+ case WMI_TLV_TX_PAUSE_ID_AP_PEER_PS:
+ case WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD:
+ case WMI_TLV_TX_PAUSE_ID_STA_ADD_BA:
+ case WMI_TLV_TX_PAUSE_ID_HOST:
+ default:
+ /* FIXME: Some pause_ids aren't vdev specific. Instead they
+ * target peer_id and tid. Implementing these could improve
+ * traffic scheduling fairness across multiple connected
+ * stations in AP/IBSS modes.
+ */
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac ignoring unsupported tx pause vdev %i id %d\n",
+ arvif->vdev_id, pause_id);
+ break;
+ }
+}
+
+struct ath10k_mac_tx_pause {
+ u32 vdev_id;
+ enum wmi_tlv_tx_pause_id pause_id;
+ enum wmi_tlv_tx_pause_action action;
+};
+
+static void ath10k_mac_handle_tx_pause_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct ath10k_mac_tx_pause *arg = data;
+
+ ath10k_mac_vif_handle_tx_pause(arvif, arg->pause_id, arg->action);
+}
+
+void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id,
+ enum wmi_tlv_tx_pause_id pause_id,
+ enum wmi_tlv_tx_pause_action action)
+{
+ struct ath10k_mac_tx_pause arg = {
+ .vdev_id = vdev_id,
+ .pause_id = pause_id,
+ .action = action,
+ };
+
+ spin_lock_bh(&ar->htt.tx_lock);
+ ieee80211_iterate_active_interfaces_atomic(ar->hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ ath10k_mac_handle_tx_pause_iter,
+ &arg);
+ spin_unlock_bh(&ar->htt.tx_lock);
+}
+
static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr)
{
if (ieee80211_is_mgmt(hdr->frame_control))
@@ -2300,6 +3129,52 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif)
return 0;
}
+static enum ath10k_hw_txrx_mode
+ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, struct sk_buff *skb)
+{
+ const struct ieee80211_hdr *hdr = (void *)skb->data;
+ __le16 fc = hdr->frame_control;
+
+ if (!vif || vif->type == NL80211_IFTYPE_MONITOR)
+ return ATH10K_HW_TXRX_RAW;
+
+ if (ieee80211_is_mgmt(fc))
+ return ATH10K_HW_TXRX_MGMT;
+
+ /* Workaround:
+ *
+ * NullFunc frames are mostly used to ping if a client or AP are still
+ * reachable and responsive. This implies tx status reports must be
+ * accurate - otherwise either mac80211 or userspace (e.g. hostapd) can
+ * come to a conclusion that the other end disappeared and tear down
+ * BSS connection or it can never disconnect from BSS/client (which is
+ * the case).
+ *
+ * Firmware with HTT older than 3.0 delivers incorrect tx status for
+ * NullFunc frames to driver. However there's a HTT Mgmt Tx command
+ * which seems to deliver correct tx reports for NullFunc frames. The
+ * downside of using it is it ignores client powersave state so it can
+ * end up disconnecting sleeping clients in AP mode. It should fix STA
+ * mode though because AP don't sleep.
+ */
+ if (ar->htt.target_version_major < 3 &&
+ (ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) &&
+ !test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, ar->fw_features))
+ return ATH10K_HW_TXRX_MGMT;
+
+ /* Workaround:
+ *
+ * Some wmi-tlv firmwares for qca6174 have broken Tx key selection for
+ * NativeWifi txmode - it selects AP key instead of peer key. It seems
+ * to work with Ethernet txmode so use it.
+ */
+ if (ieee80211_is_data_present(fc) && sta && sta->tdls)
+ return ATH10K_HW_TXRX_ETHERNET;
+
+ return ATH10K_HW_TXRX_NATIVE_WIFI;
+}
+
/* HTT Tx uses Native Wifi tx mode which expects 802.11 frames without QoS
* Control in the header.
*/
@@ -2317,16 +3192,42 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb)
skb->data, (void *)qos_ctl - (void *)skb->data);
skb_pull(skb, IEEE80211_QOS_CTL_LEN);
- /* Fw/Hw generates a corrupted QoS Control Field for QoS NullFunc
- * frames. Powersave is handled by the fw/hw so QoS NyllFunc frames are
- * used only for CQM purposes (e.g. hostapd station keepalive ping) so
- * it is safe to downgrade to NullFunc.
+ /* Some firmware revisions don't handle sending QoS NullFunc well.
+ * These frames are mainly used for CQM purposes so it doesn't really
+ * matter whether QoS NullFunc or NullFunc are sent.
*/
hdr = (void *)skb->data;
- if (ieee80211_is_qos_nullfunc(hdr->frame_control)) {
- hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
+ if (ieee80211_is_qos_nullfunc(hdr->frame_control))
cb->htt.tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
- }
+
+ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
+}
+
+static void ath10k_tx_h_8023(struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr;
+ struct rfc1042_hdr *rfc1042;
+ struct ethhdr *eth;
+ size_t hdrlen;
+ u8 da[ETH_ALEN];
+ u8 sa[ETH_ALEN];
+ __be16 type;
+
+ hdr = (void *)skb->data;
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ rfc1042 = (void *)skb->data + hdrlen;
+
+ ether_addr_copy(da, ieee80211_get_DA(hdr));
+ ether_addr_copy(sa, ieee80211_get_SA(hdr));
+ type = rfc1042->snap_type;
+
+ skb_pull(skb, hdrlen + sizeof(*rfc1042));
+ skb_push(skb, sizeof(*eth));
+
+ eth = (void *)skb->data;
+ ether_addr_copy(eth->h_dest, da);
+ ether_addr_copy(eth->h_source, sa);
+ eth->h_proto = type;
}
static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
@@ -2365,45 +3266,51 @@ static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
ar->htt.target_version_minor >= 4);
}
-static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb)
{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct sk_buff_head *q = &ar->wmi_mgmt_tx_queue;
int ret = 0;
- if (ar->htt.target_version_major >= 3) {
- /* Since HTT 3.0 there is no separate mgmt tx command */
- ret = ath10k_htt_tx(&ar->htt, skb);
- goto exit;
+ spin_lock_bh(&ar->data_lock);
+
+ if (skb_queue_len(q) == ATH10K_MAX_NUM_MGMT_PENDING) {
+ ath10k_warn(ar, "wmi mgmt tx queue is full\n");
+ ret = -ENOSPC;
+ goto unlock;
}
- if (ieee80211_is_mgmt(hdr->frame_control)) {
- if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
- ar->fw_features)) {
- if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >=
- ATH10K_MAX_NUM_MGMT_PENDING) {
- ath10k_warn(ar, "reached WMI management transmit queue limit\n");
- ret = -EBUSY;
- goto exit;
- }
+ __skb_queue_tail(q, skb);
+ ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
- skb_queue_tail(&ar->wmi_mgmt_tx_queue, skb);
- ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
- } else {
- ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
- }
- } else if (!test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
- ar->fw_features) &&
- ieee80211_is_nullfunc(hdr->frame_control)) {
- /* FW does not report tx status properly for NullFunc frames
- * unless they are sent through mgmt tx path. mac80211 sends
- * those frames when it detects link/beacon loss and depends
- * on the tx status to be correct. */
- ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
- } else {
- ret = ath10k_htt_tx(&ar->htt, skb);
+unlock:
+ spin_unlock_bh(&ar->data_lock);
+
+ return ret;
+}
+
+static void ath10k_mac_tx(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
+ struct ath10k_htt *htt = &ar->htt;
+ int ret = 0;
+
+ switch (cb->txmode) {
+ case ATH10K_HW_TXRX_RAW:
+ case ATH10K_HW_TXRX_NATIVE_WIFI:
+ case ATH10K_HW_TXRX_ETHERNET:
+ ret = ath10k_htt_tx(htt, skb);
+ break;
+ case ATH10K_HW_TXRX_MGMT:
+ if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
+ ar->fw_features))
+ ret = ath10k_mac_tx_wmi_mgmt(ar, skb);
+ else if (ar->htt.target_version_major >= 3)
+ ret = ath10k_htt_tx(htt, skb);
+ else
+ ret = ath10k_htt_mgmt_tx(htt, skb);
+ break;
}
-exit:
if (ret) {
ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
ret);
@@ -2433,6 +3340,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
const u8 *peer_addr;
int vdev_id;
int ret;
+ unsigned long time_left;
/* FW requirement: We must create a peer before FW will send out
* an offchannel frame. Otherwise the frame will be stuck and
@@ -2465,7 +3373,8 @@ void ath10k_offchan_tx_work(struct work_struct *work)
peer_addr, vdev_id);
if (!peer) {
- ret = ath10k_peer_create(ar, vdev_id, peer_addr);
+ ret = ath10k_peer_create(ar, vdev_id, peer_addr,
+ WMI_PEER_TYPE_DEFAULT);
if (ret)
ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n",
peer_addr, vdev_id, ret);
@@ -2476,11 +3385,11 @@ void ath10k_offchan_tx_work(struct work_struct *work)
ar->offchan_tx_skb = skb;
spin_unlock_bh(&ar->data_lock);
- ath10k_tx_htt(ar, skb);
+ ath10k_mac_tx(ar, skb);
- ret = wait_for_completion_timeout(&ar->offchan_tx_completed,
- 3 * HZ);
- if (ret == 0)
+ time_left =
+ wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ);
+ if (time_left == 0)
ath10k_warn(ar, "timed out waiting for offchannel skb %p\n",
skb);
@@ -2700,21 +3609,38 @@ static void ath10k_tx(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
+ struct ieee80211_sta *sta = control->sta;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ __le16 fc = hdr->frame_control;
/* We should disable CCK RATE due to P2P */
if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
ATH10K_SKB_CB(skb)->htt.is_offchan = false;
+ ATH10K_SKB_CB(skb)->htt.freq = 0;
ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);
+ ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, sta, skb);
+ ATH10K_SKB_CB(skb)->is_protected = ieee80211_has_protected(fc);
- /* it makes no sense to process injected frames like that */
- if (vif && vif->type != NL80211_IFTYPE_MONITOR) {
+ switch (ATH10K_SKB_CB(skb)->txmode) {
+ case ATH10K_HW_TXRX_MGMT:
+ case ATH10K_HW_TXRX_NATIVE_WIFI:
ath10k_tx_h_nwifi(hw, skb);
ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb);
ath10k_tx_h_seq_no(vif, skb);
+ break;
+ case ATH10K_HW_TXRX_ETHERNET:
+ ath10k_tx_h_8023(skb);
+ break;
+ case ATH10K_HW_TXRX_RAW:
+ /* FIXME: Packet injection isn't implemented. It should be
+ * doable with firmware 10.2 on qca988x.
+ */
+ WARN_ON_ONCE(1);
+ ieee80211_free_txskb(hw, skb);
+ return;
}
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
@@ -2736,7 +3662,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
}
}
- ath10k_tx_htt(ar, skb);
+ ath10k_mac_tx(ar, skb);
}
/* Must not be called with conf_mutex held as workers can use that also. */
@@ -2761,11 +3687,13 @@ void ath10k_halt(struct ath10k *ar)
clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
ar->filter_flags = 0;
ar->monitor = false;
+ ar->monitor_arvif = NULL;
if (ar->monitor_started)
ath10k_monitor_stop(ar);
ar->monitor_started = false;
+ ar->tx_paused = 0;
ath10k_scan_finish(ar);
ath10k_peer_cleanup_all(ar);
@@ -2859,6 +3787,7 @@ static int ath10k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
static int ath10k_start(struct ieee80211_hw *hw)
{
struct ath10k *ar = hw->priv;
+ u32 burst_enable;
int ret = 0;
/*
@@ -2913,6 +3842,24 @@ static int ath10k_start(struct ieee80211_hw *hw)
goto err_core_stop;
}
+ if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) {
+ ret = ath10k_wmi_adaptive_qcs(ar, true);
+ if (ret) {
+ ath10k_warn(ar, "failed to enable adaptive qcs: %d\n",
+ ret);
+ goto err_core_stop;
+ }
+ }
+
+ if (test_bit(WMI_SERVICE_BURST, ar->wmi.svc_map)) {
+ burst_enable = ar->wmi.pdev_param->burst_enable;
+ ret = ath10k_wmi_pdev_set_param(ar, burst_enable, 0);
+ if (ret) {
+ ath10k_warn(ar, "failed to disable burst: %d\n", ret);
+ goto err_core_stop;
+ }
+ }
+
if (ar->cfg_tx_chainmask)
__ath10k_set_antenna(ar, ar->cfg_tx_chainmask,
ar->cfg_rx_chainmask);
@@ -2934,10 +3881,21 @@ static int ath10k_start(struct ieee80211_hw *hw)
goto err_core_stop;
}
+ ret = ath10k_wmi_pdev_set_param(ar,
+ ar->wmi.pdev_param->ani_enable, 1);
+ if (ret) {
+ ath10k_warn(ar, "failed to enable ani by default: %d\n",
+ ret);
+ goto err_core_stop;
+ }
+
+ ar->ani_enabled = true;
+
ar->num_started_vdevs = 0;
ath10k_regd_update(ar);
ath10k_spectral_start(ar);
+ ath10k_thermal_set_throttling(ar);
mutex_unlock(&ar->conf_mutex);
return 0;
@@ -2991,97 +3949,6 @@ static int ath10k_config_ps(struct ath10k *ar)
return ret;
}
-static const char *chandef_get_width(enum nl80211_chan_width width)
-{
- switch (width) {
- case NL80211_CHAN_WIDTH_20_NOHT:
- return "20 (noht)";
- case NL80211_CHAN_WIDTH_20:
- return "20";
- case NL80211_CHAN_WIDTH_40:
- return "40";
- case NL80211_CHAN_WIDTH_80:
- return "80";
- case NL80211_CHAN_WIDTH_80P80:
- return "80+80";
- case NL80211_CHAN_WIDTH_160:
- return "160";
- case NL80211_CHAN_WIDTH_5:
- return "5";
- case NL80211_CHAN_WIDTH_10:
- return "10";
- }
- return "?";
-}
-
-static void ath10k_config_chan(struct ath10k *ar)
-{
- struct ath10k_vif *arvif;
- int ret;
-
- lockdep_assert_held(&ar->conf_mutex);
-
- ath10k_dbg(ar, ATH10K_DBG_MAC,
- "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n",
- ar->chandef.chan->center_freq,
- ar->chandef.center_freq1,
- ar->chandef.center_freq2,
- chandef_get_width(ar->chandef.width));
-
- /* First stop monitor interface. Some FW versions crash if there's a
- * lone monitor interface. */
- if (ar->monitor_started)
- ath10k_monitor_stop(ar);
-
- list_for_each_entry(arvif, &ar->arvifs, list) {
- if (!arvif->is_started)
- continue;
-
- if (!arvif->is_up)
- continue;
-
- if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
- continue;
-
- ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
- if (ret) {
- ath10k_warn(ar, "failed to down vdev %d: %d\n",
- arvif->vdev_id, ret);
- continue;
- }
- }
-
- /* all vdevs are downed now - attempt to restart and re-up them */
-
- list_for_each_entry(arvif, &ar->arvifs, list) {
- if (!arvif->is_started)
- continue;
-
- if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
- continue;
-
- ret = ath10k_vdev_restart(arvif);
- if (ret) {
- ath10k_warn(ar, "failed to restart vdev %d: %d\n",
- arvif->vdev_id, ret);
- continue;
- }
-
- if (!arvif->is_up)
- continue;
-
- ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
- arvif->bssid);
- if (ret) {
- ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
- arvif->vdev_id, ret);
- continue;
- }
- }
-
- ath10k_monitor_recalc(ar);
-}
-
static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower)
{
int ret;
@@ -3147,26 +4014,6 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&ar->conf_mutex);
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- ath10k_dbg(ar, ATH10K_DBG_MAC,
- "mac config channel %dMHz flags 0x%x radar %d\n",
- conf->chandef.chan->center_freq,
- conf->chandef.chan->flags,
- conf->radar_enabled);
-
- spin_lock_bh(&ar->data_lock);
- ar->rx_channel = conf->chandef.chan;
- spin_unlock_bh(&ar->data_lock);
-
- ar->radar_enabled = conf->radar_enabled;
- ath10k_recalc_radar_detection(ar);
-
- if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) {
- ar->chandef = conf->chandef;
- ath10k_config_chan(ar);
- }
- }
-
if (changed & IEEE80211_CONF_CHANGE_PS)
ath10k_config_ps(ar);
@@ -3208,6 +4055,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
int ret = 0;
u32 value;
int bit;
+ int i;
u32 vdev_param;
vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
@@ -3220,6 +4068,17 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
arvif->vif = vif;
INIT_LIST_HEAD(&arvif->list);
+ INIT_WORK(&arvif->ap_csa_work, ath10k_mac_vif_ap_csa_work);
+ INIT_DELAYED_WORK(&arvif->connection_loss_work,
+ ath10k_mac_vif_sta_connection_loss_work);
+
+ for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) {
+ arvif->bitrate_mask.control[i].legacy = 0xffffffff;
+ memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff,
+ sizeof(arvif->bitrate_mask.control[i].ht_mcs));
+ memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff,
+ sizeof(arvif->bitrate_mask.control[i].vht_mcs));
+ }
if (ar->free_vdev_map == 0) {
ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n");
@@ -3262,6 +4121,15 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
break;
}
+ /* Using vdev_id as queue number will make it very easy to do per-vif
+ * tx queue locking. This shouldn't wrap due to interface combinations
+ * but do a modulo for correctness sake and prevent using offchannel tx
+ * queues for regular vif tx.
+ */
+ vif->cab_queue = arvif->vdev_id % (IEEE80211_MAX_QUEUES - 1);
+ for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++)
+ vif->hw_queue[i] = arvif->vdev_id % (IEEE80211_MAX_QUEUES - 1);
+
/* Some firmware revisions don't wait for beacon tx completion before
* sending another SWBA event. This could lead to hardware using old
* (freed) beacon data in some cases, e.g. tx credit starvation
@@ -3343,14 +4211,18 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
}
}
- if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
- ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
+ arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
+ ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr,
+ WMI_PEER_TYPE_DEFAULT);
if (ret) {
- ath10k_warn(ar, "failed to create vdev %i peer for AP: %d\n",
+ ath10k_warn(ar, "failed to create vdev %i peer for AP/IBSS: %d\n",
arvif->vdev_id, ret);
goto err_vdev_delete;
}
+ }
+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath10k_mac_set_kickout(arvif);
if (ret) {
ath10k_warn(ar, "failed to set vdev %i kickout parameters: %d\n",
@@ -3406,11 +4278,21 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
goto err_peer_delete;
}
+ if (vif->type == NL80211_IFTYPE_MONITOR) {
+ ar->monitor_arvif = arvif;
+ ret = ath10k_monitor_recalc(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to recalc monitor: %d\n", ret);
+ goto err_peer_delete;
+ }
+ }
+
mutex_unlock(&ar->conf_mutex);
return 0;
err_peer_delete:
- if (arvif->vdev_type == WMI_VDEV_TYPE_AP)
+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
+ arvif->vdev_type == WMI_VDEV_TYPE_IBSS)
ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr);
err_vdev_delete:
@@ -3430,6 +4312,14 @@ err:
return ret;
}
+static void ath10k_mac_vif_tx_unlock_all(struct ath10k_vif *arvif)
+{
+ int i;
+
+ for (i = 0; i < BITS_PER_LONG; i++)
+ ath10k_mac_vif_tx_unlock(arvif, i);
+}
+
static void ath10k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -3437,6 +4327,9 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
int ret;
+ cancel_work_sync(&arvif->ap_csa_work);
+ cancel_delayed_work_sync(&arvif->connection_loss_work);
+
mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
@@ -3451,11 +4344,12 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ar->free_vdev_map |= 1LL << arvif->vdev_id;
list_del(&arvif->list);
- if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
+ arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
ret = ath10k_wmi_peer_delete(arvif->ar, arvif->vdev_id,
vif->addr);
if (ret)
- ath10k_warn(ar, "failed to submit AP self-peer removal on vdev %i: %d\n",
+ ath10k_warn(ar, "failed to submit AP/IBSS self-peer removal on vdev %i: %d\n",
arvif->vdev_id, ret);
kfree(arvif->u.ap.noa_data);
@@ -3472,7 +4366,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
/* Some firmware revisions don't notify host about self-peer removal
* until after associated vdev is deleted.
*/
- if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
+ arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
ret = ath10k_wait_for_peer_deleted(ar, arvif->vdev_id,
vif->addr);
if (ret)
@@ -3486,6 +4381,17 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ath10k_peer_cleanup(ar, arvif->vdev_id);
+ if (vif->type == NL80211_IFTYPE_MONITOR) {
+ ar->monitor_arvif = NULL;
+ ret = ath10k_monitor_recalc(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to recalc monitor: %d\n", ret);
+ }
+
+ spin_lock_bh(&ar->htt.tx_lock);
+ ath10k_mac_vif_tx_unlock_all(arvif);
+ spin_unlock_bh(&ar->htt.tx_lock);
+
mutex_unlock(&ar->conf_mutex);
}
@@ -3493,8 +4399,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
* FIXME: Has to be verified.
*/
#define SUPPORTED_FILTERS \
- (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+ (FIF_ALLMULTI | \
FIF_CONTROL | \
FIF_PSPOLL | \
FIF_OTHER_BSS | \
@@ -3615,6 +4520,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
if (ret)
ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
arvif->vdev_id, ret);
+
+ vdev_param = ar->wmi.vdev_param->protection_mode;
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
+ info->use_cts_prot ? 1 : 0);
+ if (ret)
+ ath10k_warn(ar, "failed to set protection mode %d on vdev %i: %d\n",
+ info->use_cts_prot, arvif->vdev_id, ret);
}
if (changed & BSS_CHANGED_ERP_SLOT) {
@@ -3791,10 +4703,14 @@ static void ath10k_set_key_h_def_keyidx(struct ath10k *ar,
* frames with multi-vif APs. This is not required for main firmware
* branch (e.g. 636).
*
- * FIXME: This has been tested only in AP. It remains unknown if this
- * is required for multi-vif STA interfaces on 10.1 */
+ * This is also needed for 636 fw for IBSS-RSN to work more reliably.
+ *
+ * FIXME: It remains unknown if this is required for multi-vif STA
+ * interfaces on 10.1.
+ */
- if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
+ arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
return;
if (key->cipher == WLAN_CIPHER_SUITE_WEP40)
@@ -3826,8 +4742,14 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
const u8 *peer_addr;
bool is_wep = key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
key->cipher == WLAN_CIPHER_SUITE_WEP104;
- bool def_idx = false;
int ret = 0;
+ int ret2;
+ u32 flags = 0;
+ u32 flags2;
+
+ /* this one needs to be done in software */
+ if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+ return 1;
if (key->keyidx > WMI_MAX_KEY_INDEX)
return -ENOSPC;
@@ -3843,6 +4765,13 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key->hw_key_idx = key->keyidx;
+ if (is_wep) {
+ if (cmd == SET_KEY)
+ arvif->wep_keys[key->keyidx] = key;
+ else
+ arvif->wep_keys[key->keyidx] = NULL;
+ }
+
/* the peer should not disappear in mid-way (unless FW goes awry) since
* we already hold conf_mutex. we just make sure its there now. */
spin_lock_bh(&ar->data_lock);
@@ -3862,30 +4791,61 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
}
}
- if (is_wep) {
- if (cmd == SET_KEY)
- arvif->wep_keys[key->keyidx] = key;
- else
- arvif->wep_keys[key->keyidx] = NULL;
+ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+ flags |= WMI_KEY_PAIRWISE;
+ else
+ flags |= WMI_KEY_GROUP;
+ if (is_wep) {
if (cmd == DISABLE_KEY)
ath10k_clear_vdev_key(arvif, key);
- }
- /* set TX_USAGE flag for all the keys incase of dot1x-WEP. For
- * static WEP, do not set this flag for the keys whose key id
- * is greater than default key id.
- */
- if (arvif->def_wep_key_idx == -1)
- def_idx = true;
+ /* When WEP keys are uploaded it's possible that there are
+ * stations associated already (e.g. when merging) without any
+ * keys. Static WEP needs an explicit per-peer key upload.
+ */
+ if (vif->type == NL80211_IFTYPE_ADHOC &&
+ cmd == SET_KEY)
+ ath10k_mac_vif_update_wep_key(arvif, key);
+
+ /* 802.1x never sets the def_wep_key_idx so each set_key()
+ * call changes default tx key.
+ *
+ * Static WEP sets def_wep_key_idx via .set_default_unicast_key
+ * after first set_key().
+ */
+ if (cmd == SET_KEY && arvif->def_wep_key_idx == -1)
+ flags |= WMI_KEY_TX_USAGE;
+ }
- ret = ath10k_install_key(arvif, key, cmd, peer_addr, def_idx);
+ ret = ath10k_install_key(arvif, key, cmd, peer_addr, flags);
if (ret) {
ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n",
arvif->vdev_id, peer_addr, ret);
goto exit;
}
+ /* mac80211 sets static WEP keys as groupwise while firmware requires
+ * them to be installed twice as both pairwise and groupwise.
+ */
+ if (is_wep && !sta && vif->type == NL80211_IFTYPE_STATION) {
+ flags2 = flags;
+ flags2 &= ~WMI_KEY_GROUP;
+ flags2 |= WMI_KEY_PAIRWISE;
+
+ ret = ath10k_install_key(arvif, key, cmd, peer_addr, flags2);
+ if (ret) {
+ ath10k_warn(ar, "failed to install (ucast) key for vdev %i peer %pM: %d\n",
+ arvif->vdev_id, peer_addr, ret);
+ ret2 = ath10k_install_key(arvif, key, DISABLE_KEY,
+ peer_addr, flags);
+ if (ret2)
+ ath10k_warn(ar, "failed to disable (mcast) key for vdev %i peer %pM: %d\n",
+ arvif->vdev_id, peer_addr, ret2);
+ goto exit;
+ }
+ }
+
ath10k_set_key_h_def_keyidx(ar, arvif, cmd, key);
spin_lock_bh(&ar->data_lock);
@@ -3933,6 +4893,7 @@ static void ath10k_set_default_unicast_key(struct ieee80211_hw *hw,
}
arvif->def_wep_key_idx = keyidx;
+
unlock:
mutex_unlock(&arvif->ar->conf_mutex);
}
@@ -3943,6 +4904,10 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
struct ath10k_vif *arvif;
struct ath10k_sta *arsta;
struct ieee80211_sta *sta;
+ struct cfg80211_chan_def def;
+ enum ieee80211_band band;
+ const u8 *ht_mcs_mask;
+ const u16 *vht_mcs_mask;
u32 changed, bw, nss, smps;
int err;
@@ -3951,6 +4916,13 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
arvif = arsta->arvif;
ar = arvif->ar;
+ if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def)))
+ return;
+
+ band = def.chan->band;
+ ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
+ vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
+
spin_lock_bh(&ar->data_lock);
changed = arsta->changed;
@@ -3964,6 +4936,10 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
mutex_lock(&ar->conf_mutex);
+ nss = max_t(u32, 1, nss);
+ nss = min(nss, max(ath10k_mac_max_ht_nss(ht_mcs_mask),
+ ath10k_mac_max_vht_nss(vht_mcs_mask)));
+
if (changed & IEEE80211_RC_BW_CHANGED) {
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
sta->addr, bw);
@@ -4011,14 +4987,14 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
mutex_unlock(&ar->conf_mutex);
}
-static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif)
+static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif,
+ struct ieee80211_sta *sta)
{
struct ath10k *ar = arvif->ar;
lockdep_assert_held(&ar->conf_mutex);
- if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
- arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
+ if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
return 0;
if (ar->num_stations >= ar->max_num_stations)
@@ -4029,19 +5005,72 @@ static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif)
return 0;
}
-static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif)
+static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif,
+ struct ieee80211_sta *sta)
{
struct ath10k *ar = arvif->ar;
lockdep_assert_held(&ar->conf_mutex);
- if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
- arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
+ if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
return;
ar->num_stations--;
}
+struct ath10k_mac_tdls_iter_data {
+ u32 num_tdls_stations;
+ struct ieee80211_vif *curr_vif;
+};
+
+static void ath10k_mac_tdls_vif_stations_count_iter(void *data,
+ struct ieee80211_sta *sta)
+{
+ struct ath10k_mac_tdls_iter_data *iter_data = data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ieee80211_vif *sta_vif = arsta->arvif->vif;
+
+ if (sta->tdls && sta_vif == iter_data->curr_vif)
+ iter_data->num_tdls_stations++;
+}
+
+static int ath10k_mac_tdls_vif_stations_count(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct ath10k_mac_tdls_iter_data data = {};
+
+ data.curr_vif = vif;
+
+ ieee80211_iterate_stations_atomic(hw,
+ ath10k_mac_tdls_vif_stations_count_iter,
+ &data);
+ return data.num_tdls_stations;
+}
+
+static void ath10k_mac_tdls_vifs_count_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ int *num_tdls_vifs = data;
+
+ if (vif->type != NL80211_IFTYPE_STATION)
+ return;
+
+ if (ath10k_mac_tdls_vif_stations_count(arvif->ar->hw, vif) > 0)
+ (*num_tdls_vifs)++;
+}
+
+static int ath10k_mac_tdls_vifs_count(struct ieee80211_hw *hw)
+{
+ int num_tdls_vifs = 0;
+
+ ieee80211_iterate_active_interfaces_atomic(hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ ath10k_mac_tdls_vifs_count_iter,
+ &num_tdls_vifs);
+ return num_tdls_vifs;
+}
+
static int ath10k_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -4072,41 +5101,80 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
/*
* New station addition.
*/
+ enum wmi_peer_type peer_type = WMI_PEER_TYPE_DEFAULT;
+ u32 num_tdls_stations;
+ u32 num_tdls_vifs;
+
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n",
arvif->vdev_id, sta->addr,
ar->num_stations + 1, ar->max_num_stations,
ar->num_peers + 1, ar->max_num_peers);
- ret = ath10k_mac_inc_num_stations(arvif);
+ ret = ath10k_mac_inc_num_stations(arvif, sta);
if (ret) {
ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n",
ar->max_num_stations);
goto exit;
}
- ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
+ if (sta->tdls)
+ peer_type = WMI_PEER_TYPE_TDLS;
+
+ ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr,
+ peer_type);
if (ret) {
ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
sta->addr, arvif->vdev_id, ret);
- ath10k_mac_dec_num_stations(arvif);
+ ath10k_mac_dec_num_stations(arvif, sta);
+ goto exit;
+ }
+
+ if (!sta->tdls)
+ goto exit;
+
+ num_tdls_stations = ath10k_mac_tdls_vif_stations_count(hw, vif);
+ num_tdls_vifs = ath10k_mac_tdls_vifs_count(hw);
+
+ if (num_tdls_vifs >= ar->max_num_tdls_vdevs &&
+ num_tdls_stations == 0) {
+ ath10k_warn(ar, "vdev %i exceeded maximum number of tdls vdevs %i\n",
+ arvif->vdev_id, ar->max_num_tdls_vdevs);
+ ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
+ ath10k_mac_dec_num_stations(arvif, sta);
+ ret = -ENOBUFS;
goto exit;
}
- if (vif->type == NL80211_IFTYPE_STATION) {
- WARN_ON(arvif->is_started);
+ if (num_tdls_stations == 0) {
+ /* This is the first tdls peer in current vif */
+ enum wmi_tdls_state state = WMI_TDLS_ENABLE_ACTIVE;
- ret = ath10k_vdev_start(arvif);
+ ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id,
+ state);
if (ret) {
- ath10k_warn(ar, "failed to start vdev %i: %d\n",
+ ath10k_warn(ar, "failed to update fw tdls state on vdev %i: %i\n",
arvif->vdev_id, ret);
- WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id,
- sta->addr));
- ath10k_mac_dec_num_stations(arvif);
+ ath10k_peer_delete(ar, arvif->vdev_id,
+ sta->addr);
+ ath10k_mac_dec_num_stations(arvif, sta);
goto exit;
}
+ }
- arvif->is_started = true;
+ ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta,
+ WMI_TDLS_PEER_STATE_PEERING);
+ if (ret) {
+ ath10k_warn(ar,
+ "failed to update tdls peer %pM for vdev %d when adding a new sta: %i\n",
+ sta->addr, arvif->vdev_id, ret);
+ ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
+ ath10k_mac_dec_num_stations(arvif, sta);
+
+ if (num_tdls_stations != 0)
+ goto exit;
+ ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id,
+ WMI_TDLS_DISABLE);
}
} else if ((old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST)) {
@@ -4117,23 +5185,26 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
"mac vdev %d peer delete %pM (sta gone)\n",
arvif->vdev_id, sta->addr);
- if (vif->type == NL80211_IFTYPE_STATION) {
- WARN_ON(!arvif->is_started);
-
- ret = ath10k_vdev_stop(arvif);
- if (ret)
- ath10k_warn(ar, "failed to stop vdev %i: %d\n",
- arvif->vdev_id, ret);
-
- arvif->is_started = false;
- }
-
ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
if (ret)
ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
sta->addr, arvif->vdev_id, ret);
- ath10k_mac_dec_num_stations(arvif);
+ ath10k_mac_dec_num_stations(arvif, sta);
+
+ if (!sta->tdls)
+ goto exit;
+
+ if (ath10k_mac_tdls_vif_stations_count(hw, vif))
+ goto exit;
+
+ /* This was the last tdls peer in current vif */
+ ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id,
+ WMI_TDLS_DISABLE);
+ if (ret) {
+ ath10k_warn(ar, "failed to update fw tdls state on vdev %i: %i\n",
+ arvif->vdev_id, ret);
+ }
} else if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC &&
(vif->type == NL80211_IFTYPE_AP ||
@@ -4149,9 +5220,30 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
} else if (old_state == IEEE80211_STA_ASSOC &&
- new_state == IEEE80211_STA_AUTH &&
- (vif->type == NL80211_IFTYPE_AP ||
- vif->type == NL80211_IFTYPE_ADHOC)) {
+ new_state == IEEE80211_STA_AUTHORIZED &&
+ sta->tdls) {
+ /*
+ * Tdls station authorized.
+ */
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac tdls sta %pM authorized\n",
+ sta->addr);
+
+ ret = ath10k_station_assoc(ar, vif, sta, false);
+ if (ret) {
+ ath10k_warn(ar, "failed to associate tdls station %pM for vdev %i: %i\n",
+ sta->addr, arvif->vdev_id, ret);
+ goto exit;
+ }
+
+ ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta,
+ WMI_TDLS_PEER_STATE_CONNECTED);
+ if (ret)
+ ath10k_warn(ar, "failed to update tdls peer %pM for vdev %i: %i\n",
+ sta->addr, arvif->vdev_id, ret);
+ } else if (old_state == IEEE80211_STA_ASSOC &&
+ new_state == IEEE80211_STA_AUTH &&
+ (vif->type == NL80211_IFTYPE_AP ||
+ vif->type == NL80211_IFTYPE_ADHOC)) {
/*
* Disassociation.
*/
@@ -4356,6 +5448,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct wmi_start_scan_arg arg;
int ret = 0;
+ u32 scan_time_msec;
mutex_lock(&ar->conf_mutex);
@@ -4382,7 +5475,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
if (ret)
goto exit;
- duration = max(duration, WMI_SCAN_CHAN_MIN_TIME_MSEC);
+ scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2;
memset(&arg, 0, sizeof(arg));
ath10k_wmi_start_scan_init(ar, &arg);
@@ -4390,11 +5483,12 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
arg.scan_id = ATH10K_SCAN_ID;
arg.n_channels = 1;
arg.channels[0] = chan->center_freq;
- arg.dwell_time_active = duration;
- arg.dwell_time_passive = duration;
- arg.max_scan_time = 2 * duration;
+ arg.dwell_time_active = scan_time_msec;
+ arg.dwell_time_passive = scan_time_msec;
+ arg.max_scan_time = scan_time_msec;
arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE;
arg.scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ;
+ arg.burst_duration_ms = duration;
ret = ath10k_start_scan(ar, &arg);
if (ret) {
@@ -4417,6 +5511,9 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
goto exit;
}
+ ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
+ msecs_to_jiffies(duration));
+
ret = 0;
exit:
mutex_unlock(&ar->conf_mutex);
@@ -4512,70 +5609,6 @@ static int ath10k_tx_last_beacon(struct ieee80211_hw *hw)
return 1;
}
-#ifdef CONFIG_PM
-static int ath10k_suspend(struct ieee80211_hw *hw,
- struct cfg80211_wowlan *wowlan)
-{
- struct ath10k *ar = hw->priv;
- int ret;
-
- mutex_lock(&ar->conf_mutex);
-
- ret = ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND);
- if (ret) {
- if (ret == -ETIMEDOUT)
- goto resume;
- ret = 1;
- goto exit;
- }
-
- ret = ath10k_hif_suspend(ar);
- if (ret) {
- ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
- goto resume;
- }
-
- ret = 0;
- goto exit;
-resume:
- ret = ath10k_wmi_pdev_resume_target(ar);
- if (ret)
- ath10k_warn(ar, "failed to resume target: %d\n", ret);
-
- ret = 1;
-exit:
- mutex_unlock(&ar->conf_mutex);
- return ret;
-}
-
-static int ath10k_resume(struct ieee80211_hw *hw)
-{
- struct ath10k *ar = hw->priv;
- int ret;
-
- mutex_lock(&ar->conf_mutex);
-
- ret = ath10k_hif_resume(ar);
- if (ret) {
- ath10k_warn(ar, "failed to resume hif: %d\n", ret);
- ret = 1;
- goto exit;
- }
-
- ret = ath10k_wmi_pdev_resume_target(ar);
- if (ret) {
- ath10k_warn(ar, "failed to resume target: %d\n", ret);
- ret = 1;
- goto exit;
- }
-
- ret = 0;
-exit:
- mutex_unlock(&ar->conf_mutex);
- return ret;
-}
-#endif
-
static void ath10k_reconfig_complete(struct ieee80211_hw *hw,
enum ieee80211_reconfig_type reconfig_type)
{
@@ -4635,343 +5668,286 @@ exit:
return ret;
}
-/* Helper table for legacy fixed_rate/bitrate_mask */
-static const u8 cck_ofdm_rate[] = {
- /* CCK */
- 3, /* 1Mbps */
- 2, /* 2Mbps */
- 1, /* 5.5Mbps */
- 0, /* 11Mbps */
- /* OFDM */
- 3, /* 6Mbps */
- 7, /* 9Mbps */
- 2, /* 12Mbps */
- 6, /* 18Mbps */
- 1, /* 24Mbps */
- 5, /* 36Mbps */
- 0, /* 48Mbps */
- 4, /* 54Mbps */
-};
-
-/* Check if only one bit set */
-static int ath10k_check_single_mask(u32 mask)
-{
- int bit;
-
- bit = ffs(mask);
- if (!bit)
- return 0;
-
- mask &= ~BIT(bit - 1);
- if (mask)
- return 2;
-
- return 1;
-}
-
static bool
-ath10k_default_bitrate_mask(struct ath10k *ar,
- enum ieee80211_band band,
- const struct cfg80211_bitrate_mask *mask)
+ath10k_mac_bitrate_mask_has_single_rate(struct ath10k *ar,
+ enum ieee80211_band band,
+ const struct cfg80211_bitrate_mask *mask)
{
- u32 legacy = 0x00ff;
- u8 ht = 0xff, i;
- u16 vht = 0x3ff;
- u16 nrf = ar->num_rf_chains;
-
- if (ar->cfg_tx_chainmask)
- nrf = get_nss_from_chainmask(ar->cfg_tx_chainmask);
-
- switch (band) {
- case IEEE80211_BAND_2GHZ:
- legacy = 0x00fff;
- vht = 0;
- break;
- case IEEE80211_BAND_5GHZ:
- break;
- default:
- return false;
- }
+ int num_rates = 0;
+ int i;
- if (mask->control[band].legacy != legacy)
- return false;
+ num_rates += hweight32(mask->control[band].legacy);
- for (i = 0; i < nrf; i++)
- if (mask->control[band].ht_mcs[i] != ht)
- return false;
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++)
+ num_rates += hweight8(mask->control[band].ht_mcs[i]);
- for (i = 0; i < nrf; i++)
- if (mask->control[band].vht_mcs[i] != vht)
- return false;
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++)
+ num_rates += hweight16(mask->control[band].vht_mcs[i]);
- return true;
+ return num_rates == 1;
}
static bool
-ath10k_bitrate_mask_nss(const struct cfg80211_bitrate_mask *mask,
- enum ieee80211_band band,
- u8 *fixed_nss)
-{
- int ht_nss = 0, vht_nss = 0, i;
+ath10k_mac_bitrate_mask_get_single_nss(struct ath10k *ar,
+ enum ieee80211_band band,
+ const struct cfg80211_bitrate_mask *mask,
+ int *nss)
+{
+ struct ieee80211_supported_band *sband = &ar->mac.sbands[band];
+ u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
+ u8 ht_nss_mask = 0;
+ u8 vht_nss_mask = 0;
+ int i;
- /* check legacy */
- if (ath10k_check_single_mask(mask->control[band].legacy))
+ if (mask->control[band].legacy)
return false;
- /* check HT */
- for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
- if (mask->control[band].ht_mcs[i] == 0xff)
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) {
+ if (mask->control[band].ht_mcs[i] == 0)
continue;
- else if (mask->control[band].ht_mcs[i] == 0x00)
- break;
-
- return false;
+ else if (mask->control[band].ht_mcs[i] ==
+ sband->ht_cap.mcs.rx_mask[i])
+ ht_nss_mask |= BIT(i);
+ else
+ return false;
}
- ht_nss = i;
-
- /* check VHT */
- for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
- if (mask->control[band].vht_mcs[i] == 0x03ff)
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
+ if (mask->control[band].vht_mcs[i] == 0)
continue;
- else if (mask->control[band].vht_mcs[i] == 0x0000)
- break;
-
- return false;
+ else if (mask->control[band].vht_mcs[i] ==
+ ath10k_mac_get_max_vht_mcs_map(vht_mcs_map, i))
+ vht_nss_mask |= BIT(i);
+ else
+ return false;
}
- vht_nss = i;
-
- if (ht_nss > 0 && vht_nss > 0)
- return false;
-
- if (ht_nss)
- *fixed_nss = ht_nss;
- else if (vht_nss)
- *fixed_nss = vht_nss;
- else
- return false;
-
- return true;
-}
-
-static bool
-ath10k_bitrate_mask_correct(const struct cfg80211_bitrate_mask *mask,
- enum ieee80211_band band,
- enum wmi_rate_preamble *preamble)
-{
- int legacy = 0, ht = 0, vht = 0, i;
-
- *preamble = WMI_RATE_PREAMBLE_OFDM;
-
- /* check legacy */
- legacy = ath10k_check_single_mask(mask->control[band].legacy);
- if (legacy > 1)
- return false;
-
- /* check HT */
- for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
- ht += ath10k_check_single_mask(mask->control[band].ht_mcs[i]);
- if (ht > 1)
+ if (ht_nss_mask != vht_nss_mask)
return false;
- /* check VHT */
- for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
- vht += ath10k_check_single_mask(mask->control[band].vht_mcs[i]);
- if (vht > 1)
+ if (ht_nss_mask == 0)
return false;
- /* Currently we support only one fixed_rate */
- if ((legacy + ht + vht) != 1)
+ if (BIT(fls(ht_nss_mask)) - 1 != ht_nss_mask)
return false;
- if (ht)
- *preamble = WMI_RATE_PREAMBLE_HT;
- else if (vht)
- *preamble = WMI_RATE_PREAMBLE_VHT;
+ *nss = fls(ht_nss_mask);
return true;
}
-static bool
-ath10k_bitrate_mask_rate(struct ath10k *ar,
- const struct cfg80211_bitrate_mask *mask,
- enum ieee80211_band band,
- u8 *fixed_rate,
- u8 *fixed_nss)
+static int
+ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
+ enum ieee80211_band band,
+ const struct cfg80211_bitrate_mask *mask,
+ u8 *rate, u8 *nss)
{
- u8 rate = 0, pream = 0, nss = 0, i;
- enum wmi_rate_preamble preamble;
-
- /* Check if single rate correct */
- if (!ath10k_bitrate_mask_correct(mask, band, &preamble))
- return false;
-
- pream = preamble;
-
- switch (preamble) {
- case WMI_RATE_PREAMBLE_CCK:
- case WMI_RATE_PREAMBLE_OFDM:
- i = ffs(mask->control[band].legacy) - 1;
-
- if (band == IEEE80211_BAND_2GHZ && i < 4)
- pream = WMI_RATE_PREAMBLE_CCK;
-
- if (band == IEEE80211_BAND_5GHZ)
- i += 4;
-
- if (i >= ARRAY_SIZE(cck_ofdm_rate))
- return false;
+ struct ieee80211_supported_band *sband = &ar->mac.sbands[band];
+ int rate_idx;
+ int i;
+ u16 bitrate;
+ u8 preamble;
+ u8 hw_rate;
- rate = cck_ofdm_rate[i];
- break;
- case WMI_RATE_PREAMBLE_HT:
- for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
- if (mask->control[band].ht_mcs[i])
- break;
+ if (hweight32(mask->control[band].legacy) == 1) {
+ rate_idx = ffs(mask->control[band].legacy) - 1;
- if (i == IEEE80211_HT_MCS_MASK_LEN)
- return false;
+ hw_rate = sband->bitrates[rate_idx].hw_value;
+ bitrate = sband->bitrates[rate_idx].bitrate;
- rate = ffs(mask->control[band].ht_mcs[i]) - 1;
- nss = i;
- break;
- case WMI_RATE_PREAMBLE_VHT:
- for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
- if (mask->control[band].vht_mcs[i])
- break;
+ if (ath10k_mac_bitrate_is_cck(bitrate))
+ preamble = WMI_RATE_PREAMBLE_CCK;
+ else
+ preamble = WMI_RATE_PREAMBLE_OFDM;
- if (i == NL80211_VHT_NSS_MAX)
- return false;
+ *nss = 1;
+ *rate = preamble << 6 |
+ (*nss - 1) << 4 |
+ hw_rate << 0;
- rate = ffs(mask->control[band].vht_mcs[i]) - 1;
- nss = i;
- break;
+ return 0;
}
- *fixed_nss = nss + 1;
- nss <<= 4;
- pream <<= 6;
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) {
+ if (hweight8(mask->control[band].ht_mcs[i]) == 1) {
+ *nss = i + 1;
+ *rate = WMI_RATE_PREAMBLE_HT << 6 |
+ (*nss - 1) << 4 |
+ (ffs(mask->control[band].ht_mcs[i]) - 1);
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
- pream, nss, rate);
+ return 0;
+ }
+ }
- *fixed_rate = pream | nss | rate;
+ for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
+ if (hweight16(mask->control[band].vht_mcs[i]) == 1) {
+ *nss = i + 1;
+ *rate = WMI_RATE_PREAMBLE_VHT << 6 |
+ (*nss - 1) << 4 |
+ (ffs(mask->control[band].vht_mcs[i]) - 1);
- return true;
-}
-
-static bool ath10k_get_fixed_rate_nss(struct ath10k *ar,
- const struct cfg80211_bitrate_mask *mask,
- enum ieee80211_band band,
- u8 *fixed_rate,
- u8 *fixed_nss)
-{
- /* First check full NSS mask, if we can simply limit NSS */
- if (ath10k_bitrate_mask_nss(mask, band, fixed_nss))
- return true;
+ return 0;
+ }
+ }
- /* Next Check single rate is set */
- return ath10k_bitrate_mask_rate(ar, mask, band, fixed_rate, fixed_nss);
+ return -EINVAL;
}
-static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
- u8 fixed_rate,
- u8 fixed_nss,
- u8 force_sgi)
+static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
+ u8 rate, u8 nss, u8 sgi)
{
struct ath10k *ar = arvif->ar;
u32 vdev_param;
- int ret = 0;
-
- mutex_lock(&ar->conf_mutex);
-
- if (arvif->fixed_rate == fixed_rate &&
- arvif->fixed_nss == fixed_nss &&
- arvif->force_sgi == force_sgi)
- goto exit;
+ int ret;
- if (fixed_rate == WMI_FIXED_RATE_NONE)
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
+ lockdep_assert_held(&ar->conf_mutex);
- if (force_sgi)
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac force sgi\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02hhx nss %hhu sgi %hhu\n",
+ arvif->vdev_id, rate, nss, sgi);
vdev_param = ar->wmi.vdev_param->fixed_rate;
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
- vdev_param, fixed_rate);
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, rate);
if (ret) {
ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n",
- fixed_rate, ret);
- ret = -EINVAL;
- goto exit;
+ rate, ret);
+ return ret;
}
- arvif->fixed_rate = fixed_rate;
-
vdev_param = ar->wmi.vdev_param->nss;
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
- vdev_param, fixed_nss);
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, nss);
+ if (ret) {
+ ath10k_warn(ar, "failed to set nss param %d: %d\n", nss, ret);
+ return ret;
+ }
+ vdev_param = ar->wmi.vdev_param->sgi;
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, sgi);
if (ret) {
- ath10k_warn(ar, "failed to set fixed nss param %d: %d\n",
- fixed_nss, ret);
- ret = -EINVAL;
- goto exit;
+ ath10k_warn(ar, "failed to set sgi param %d: %d\n", sgi, ret);
+ return ret;
}
- arvif->fixed_nss = fixed_nss;
+ return 0;
+}
- vdev_param = ar->wmi.vdev_param->sgi;
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
- force_sgi);
+static bool
+ath10k_mac_can_set_bitrate_mask(struct ath10k *ar,
+ enum ieee80211_band band,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ int i;
+ u16 vht_mcs;
- if (ret) {
- ath10k_warn(ar, "failed to set sgi param %d: %d\n",
- force_sgi, ret);
- ret = -EINVAL;
- goto exit;
+ /* Due to firmware limitation in WMI_PEER_ASSOC_CMDID it is impossible
+ * to express all VHT MCS rate masks. Effectively only the following
+ * ranges can be used: none, 0-7, 0-8 and 0-9.
+ */
+ for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
+ vht_mcs = mask->control[band].vht_mcs[i];
+
+ switch (vht_mcs) {
+ case 0:
+ case BIT(8) - 1:
+ case BIT(9) - 1:
+ case BIT(10) - 1:
+ break;
+ default:
+ ath10k_warn(ar, "refusing bitrate mask with missing 0-7 VHT MCS rates\n");
+ return false;
+ }
}
- arvif->force_sgi = force_sgi;
+ return true;
+}
-exit:
- mutex_unlock(&ar->conf_mutex);
- return ret;
+static void ath10k_mac_set_bitrate_mask_iter(void *data,
+ struct ieee80211_sta *sta)
+{
+ struct ath10k_vif *arvif = data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k *ar = arvif->ar;
+
+ if (arsta->arvif != arvif)
+ return;
+
+ spin_lock_bh(&ar->data_lock);
+ arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
+ spin_unlock_bh(&ar->data_lock);
+
+ ieee80211_queue_work(ar->hw, &arsta->update_wk);
}
-static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- const struct cfg80211_bitrate_mask *mask)
+static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const struct cfg80211_bitrate_mask *mask)
{
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct cfg80211_chan_def def;
struct ath10k *ar = arvif->ar;
- enum ieee80211_band band = ar->hw->conf.chandef.chan->band;
- u8 fixed_rate = WMI_FIXED_RATE_NONE;
- u8 fixed_nss = ar->num_rf_chains;
- u8 force_sgi;
+ enum ieee80211_band band;
+ const u8 *ht_mcs_mask;
+ const u16 *vht_mcs_mask;
+ u8 rate;
+ u8 nss;
+ u8 sgi;
+ int single_nss;
+ int ret;
- if (ar->cfg_tx_chainmask)
- fixed_nss = get_nss_from_chainmask(ar->cfg_tx_chainmask);
+ if (ath10k_mac_vif_chan(vif, &def))
+ return -EPERM;
+
+ band = def.chan->band;
+ ht_mcs_mask = mask->control[band].ht_mcs;
+ vht_mcs_mask = mask->control[band].vht_mcs;
- force_sgi = mask->control[band].gi;
- if (force_sgi == NL80211_TXRATE_FORCE_LGI)
+ sgi = mask->control[band].gi;
+ if (sgi == NL80211_TXRATE_FORCE_LGI)
return -EINVAL;
- if (!ath10k_default_bitrate_mask(ar, band, mask)) {
- if (!ath10k_get_fixed_rate_nss(ar, mask, band,
- &fixed_rate,
- &fixed_nss))
+ if (ath10k_mac_bitrate_mask_has_single_rate(ar, band, mask)) {
+ ret = ath10k_mac_bitrate_mask_get_single_rate(ar, band, mask,
+ &rate, &nss);
+ if (ret) {
+ ath10k_warn(ar, "failed to get single rate for vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+ } else if (ath10k_mac_bitrate_mask_get_single_nss(ar, band, mask,
+ &single_nss)) {
+ rate = WMI_FIXED_RATE_NONE;
+ nss = single_nss;
+ } else {
+ rate = WMI_FIXED_RATE_NONE;
+ nss = min(ar->num_rf_chains,
+ max(ath10k_mac_max_ht_nss(ht_mcs_mask),
+ ath10k_mac_max_vht_nss(vht_mcs_mask)));
+
+ if (!ath10k_mac_can_set_bitrate_mask(ar, band, mask))
return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ arvif->bitrate_mask = *mask;
+ ieee80211_iterate_stations_atomic(ar->hw,
+ ath10k_mac_set_bitrate_mask_iter,
+ arvif);
+
+ mutex_unlock(&ar->conf_mutex);
}
- if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) {
- ath10k_warn(ar, "failed to force SGI usage for default rate settings\n");
- return -EINVAL;
+ mutex_lock(&ar->conf_mutex);
+
+ ret = ath10k_mac_set_fixed_rate_params(arvif, rate, nss, sgi);
+ if (ret) {
+ ath10k_warn(ar, "failed to set fixed rate params on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ goto exit;
}
- return ath10k_set_fixed_rate_param(arvif, fixed_rate,
- fixed_nss, force_sgi);
+exit:
+ mutex_unlock(&ar->conf_mutex);
+
+ return ret;
}
static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
@@ -5090,6 +6066,317 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw,
return -EINVAL;
}
+static void
+ath10k_mac_update_rx_channel(struct ath10k *ar,
+ struct ieee80211_chanctx_conf *ctx,
+ struct ieee80211_vif_chanctx_switch *vifs,
+ int n_vifs)
+{
+ struct cfg80211_chan_def *def = NULL;
+
+ /* Both locks are required because ar->rx_channel is modified. This
+ * allows readers to hold either lock.
+ */
+ lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_held(&ar->data_lock);
+
+ WARN_ON(ctx && vifs);
+ WARN_ON(vifs && n_vifs != 1);
+
+ /* FIXME: Sort of an optimization and a workaround. Peers and vifs are
+ * on a linked list now. Doing a lookup peer -> vif -> chanctx for each
+ * ppdu on Rx may reduce performance on low-end systems. It should be
+ * possible to make tables/hashmaps to speed the lookup up (be vary of
+ * cpu data cache lines though regarding sizes) but to keep the initial
+ * implementation simple and less intrusive fallback to the slow lookup
+ * only for multi-channel cases. Single-channel cases will remain to
+ * use the old channel derival and thus performance should not be
+ * affected much.
+ */
+ rcu_read_lock();
+ if (!ctx && ath10k_mac_num_chanctxs(ar) == 1) {
+ ieee80211_iter_chan_contexts_atomic(ar->hw,
+ ath10k_mac_get_any_chandef_iter,
+ &def);
+
+ if (vifs)
+ def = &vifs[0].new_ctx->def;
+
+ ar->rx_channel = def->chan;
+ } else if (ctx && ath10k_mac_num_chanctxs(ar) == 0) {
+ ar->rx_channel = ctx->def.chan;
+ } else {
+ ar->rx_channel = NULL;
+ }
+ rcu_read_unlock();
+}
+
+static int
+ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct ath10k *ar = hw->priv;
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx add freq %hu width %d ptr %p\n",
+ ctx->def.chan->center_freq, ctx->def.width, ctx);
+
+ mutex_lock(&ar->conf_mutex);
+
+ spin_lock_bh(&ar->data_lock);
+ ath10k_mac_update_rx_channel(ar, ctx, NULL, 0);
+ spin_unlock_bh(&ar->data_lock);
+
+ ath10k_recalc_radar_detection(ar);
+ ath10k_monitor_recalc(ar);
+
+ mutex_unlock(&ar->conf_mutex);
+
+ return 0;
+}
+
+static void
+ath10k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct ath10k *ar = hw->priv;
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx remove freq %hu width %d ptr %p\n",
+ ctx->def.chan->center_freq, ctx->def.width, ctx);
+
+ mutex_lock(&ar->conf_mutex);
+
+ spin_lock_bh(&ar->data_lock);
+ ath10k_mac_update_rx_channel(ar, NULL, NULL, 0);
+ spin_unlock_bh(&ar->data_lock);
+
+ ath10k_recalc_radar_detection(ar);
+ ath10k_monitor_recalc(ar);
+
+ mutex_unlock(&ar->conf_mutex);
+}
+
+static void
+ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx,
+ u32 changed)
+{
+ struct ath10k *ar = hw->priv;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx change freq %hu width %d ptr %p changed %x\n",
+ ctx->def.chan->center_freq, ctx->def.width, ctx, changed);
+
+ /* This shouldn't really happen because channel switching should use
+ * switch_vif_chanctx().
+ */
+ if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL))
+ goto unlock;
+
+ ath10k_recalc_radar_detection(ar);
+
+ /* FIXME: How to configure Rx chains properly? */
+
+ /* No other actions are actually necessary. Firmware maintains channel
+ * definitions per vdev internally and there's no host-side channel
+ * context abstraction to configure, e.g. channel width.
+ */
+
+unlock:
+ mutex_unlock(&ar->conf_mutex);
+}
+
+static int
+ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct ath10k *ar = hw->priv;
+ struct ath10k_vif *arvif = (void *)vif->drv_priv;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx assign ptr %p vdev_id %i\n",
+ ctx, arvif->vdev_id);
+
+ if (WARN_ON(arvif->is_started)) {
+ mutex_unlock(&ar->conf_mutex);
+ return -EBUSY;
+ }
+
+ ret = ath10k_vdev_start(arvif, &ctx->def);
+ if (ret) {
+ ath10k_warn(ar, "failed to start vdev %i addr %pM on freq %d: %d\n",
+ arvif->vdev_id, vif->addr,
+ ctx->def.chan->center_freq, ret);
+ goto err;
+ }
+
+ arvif->is_started = true;
+
+ if (vif->type == NL80211_IFTYPE_MONITOR) {
+ ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, 0, vif->addr);
+ if (ret) {
+ ath10k_warn(ar, "failed to up monitor vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ goto err_stop;
+ }
+
+ arvif->is_up = true;
+ }
+
+ mutex_unlock(&ar->conf_mutex);
+ return 0;
+
+err_stop:
+ ath10k_vdev_stop(arvif);
+ arvif->is_started = false;
+
+err:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static void
+ath10k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct ath10k *ar = hw->priv;
+ struct ath10k_vif *arvif = (void *)vif->drv_priv;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx unassign ptr %p vdev_id %i\n",
+ ctx, arvif->vdev_id);
+
+ WARN_ON(!arvif->is_started);
+
+ if (vif->type == NL80211_IFTYPE_MONITOR) {
+ WARN_ON(!arvif->is_up);
+
+ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+ if (ret)
+ ath10k_warn(ar, "failed to down monitor vdev %i: %d\n",
+ arvif->vdev_id, ret);
+
+ arvif->is_up = false;
+ }
+
+ ret = ath10k_vdev_stop(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to stop vdev %i: %d\n",
+ arvif->vdev_id, ret);
+
+ arvif->is_started = false;
+
+ mutex_unlock(&ar->conf_mutex);
+}
+
+static int
+ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif_chanctx_switch *vifs,
+ int n_vifs,
+ enum ieee80211_chanctx_switch_mode mode)
+{
+ struct ath10k *ar = hw->priv;
+ struct ath10k_vif *arvif;
+ int ret;
+ int i;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx switch n_vifs %d mode %d\n",
+ n_vifs, mode);
+
+ /* First stop monitor interface. Some FW versions crash if there's a
+ * lone monitor interface.
+ */
+ if (ar->monitor_started)
+ ath10k_monitor_stop(ar);
+
+ for (i = 0; i < n_vifs; i++) {
+ arvif = ath10k_vif_to_arvif(vifs[i].vif);
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
+ "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n",
+ arvif->vdev_id,
+ vifs[i].old_ctx->def.chan->center_freq,
+ vifs[i].new_ctx->def.chan->center_freq,
+ vifs[i].old_ctx->def.width,
+ vifs[i].new_ctx->def.width);
+
+ if (WARN_ON(!arvif->is_started))
+ continue;
+
+ if (WARN_ON(!arvif->is_up))
+ continue;
+
+ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+ if (ret) {
+ ath10k_warn(ar, "failed to down vdev %d: %d\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
+ }
+
+ /* All relevant vdevs are downed and associated channel resources
+ * should be available for the channel switch now.
+ */
+
+ spin_lock_bh(&ar->data_lock);
+ ath10k_mac_update_rx_channel(ar, NULL, vifs, n_vifs);
+ spin_unlock_bh(&ar->data_lock);
+
+ for (i = 0; i < n_vifs; i++) {
+ arvif = ath10k_vif_to_arvif(vifs[i].vif);
+
+ if (WARN_ON(!arvif->is_started))
+ continue;
+
+ if (WARN_ON(!arvif->is_up))
+ continue;
+
+ ret = ath10k_mac_setup_bcn_tmpl(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n",
+ ret);
+
+ ret = ath10k_mac_setup_prb_tmpl(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
+ ret);
+
+ ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def);
+ if (ret) {
+ ath10k_warn(ar, "failed to restart vdev %d: %d\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
+
+ ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
+ arvif->bssid);
+ if (ret) {
+ ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
+ }
+
+ ath10k_monitor_recalc(ar);
+
+ mutex_unlock(&ar->conf_mutex);
+ return 0;
+}
+
static const struct ieee80211_ops ath10k_ops = {
.tx = ath10k_tx,
.start = ath10k_start,
@@ -5114,31 +6401,31 @@ static const struct ieee80211_ops ath10k_ops = {
.get_antenna = ath10k_get_antenna,
.reconfig_complete = ath10k_reconfig_complete,
.get_survey = ath10k_get_survey,
- .set_bitrate_mask = ath10k_set_bitrate_mask,
+ .set_bitrate_mask = ath10k_mac_op_set_bitrate_mask,
.sta_rc_update = ath10k_sta_rc_update,
.get_tsf = ath10k_get_tsf,
.ampdu_action = ath10k_ampdu_action,
.get_et_sset_count = ath10k_debug_get_et_sset_count,
.get_et_stats = ath10k_debug_get_et_stats,
.get_et_strings = ath10k_debug_get_et_strings,
+ .add_chanctx = ath10k_mac_op_add_chanctx,
+ .remove_chanctx = ath10k_mac_op_remove_chanctx,
+ .change_chanctx = ath10k_mac_op_change_chanctx,
+ .assign_vif_chanctx = ath10k_mac_op_assign_vif_chanctx,
+ .unassign_vif_chanctx = ath10k_mac_op_unassign_vif_chanctx,
+ .switch_vif_chanctx = ath10k_mac_op_switch_vif_chanctx,
CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
#ifdef CONFIG_PM
- .suspend = ath10k_suspend,
- .resume = ath10k_resume,
+ .suspend = ath10k_wow_op_suspend,
+ .resume = ath10k_wow_op_resume,
#endif
#ifdef CONFIG_MAC80211_DEBUGFS
.sta_add_debugfs = ath10k_sta_add_debugfs,
#endif
};
-#define RATETAB_ENT(_rate, _rateid, _flags) { \
- .bitrate = (_rate), \
- .flags = (_flags), \
- .hw_value = (_rateid), \
-}
-
#define CHAN2G(_channel, _freq, _flags) { \
.band = IEEE80211_BAND_2GHZ, \
.hw_value = (_channel), \
@@ -5194,6 +6481,7 @@ static const struct ieee80211_channel ath10k_5ghz_channels[] = {
CHAN5G(132, 5660, 0),
CHAN5G(136, 5680, 0),
CHAN5G(140, 5700, 0),
+ CHAN5G(144, 5720, 0),
CHAN5G(149, 5745, 0),
CHAN5G(153, 5765, 0),
CHAN5G(157, 5785, 0),
@@ -5201,31 +6489,6 @@ static const struct ieee80211_channel ath10k_5ghz_channels[] = {
CHAN5G(165, 5825, 0),
};
-/* Note: Be careful if you re-order these. There is code which depends on this
- * ordering.
- */
-static struct ieee80211_rate ath10k_rates[] = {
- /* CCK */
- RATETAB_ENT(10, 0x82, 0),
- RATETAB_ENT(20, 0x84, 0),
- RATETAB_ENT(55, 0x8b, 0),
- RATETAB_ENT(110, 0x96, 0),
- /* OFDM */
- RATETAB_ENT(60, 0x0c, 0),
- RATETAB_ENT(90, 0x12, 0),
- RATETAB_ENT(120, 0x18, 0),
- RATETAB_ENT(180, 0x24, 0),
- RATETAB_ENT(240, 0x30, 0),
- RATETAB_ENT(360, 0x48, 0),
- RATETAB_ENT(480, 0x60, 0),
- RATETAB_ENT(540, 0x6c, 0),
-};
-
-#define ath10k_a_rates (ath10k_rates + 4)
-#define ath10k_a_rates_size (ARRAY_SIZE(ath10k_rates) - 4)
-#define ath10k_g_rates (ath10k_rates + 0)
-#define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates))
-
struct ath10k *ath10k_mac_create(size_t priv_size)
{
struct ieee80211_hw *hw;
@@ -5299,15 +6562,92 @@ static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = {
},
};
+static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = {
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
+ },
+};
+
+static const struct ieee80211_iface_limit ath10k_tlv_if_limit_ibss[] = {
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_ADHOC),
+ },
+};
+
+/* FIXME: This is not thouroughly tested. These combinations may over- or
+ * underestimate hw/fw capabilities.
+ */
+static struct ieee80211_iface_combination ath10k_tlv_if_comb[] = {
+ {
+ .limits = ath10k_tlv_if_limit,
+ .num_different_channels = 1,
+ .max_interfaces = 3,
+ .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit),
+ },
+ {
+ .limits = ath10k_tlv_if_limit_ibss,
+ .num_different_channels = 1,
+ .max_interfaces = 2,
+ .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit_ibss),
+ },
+};
+
+static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = {
+ {
+ .limits = ath10k_tlv_if_limit,
+ .num_different_channels = 2,
+ .max_interfaces = 3,
+ .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit),
+ },
+ {
+ .limits = ath10k_tlv_if_limit_ibss,
+ .num_different_channels = 1,
+ .max_interfaces = 2,
+ .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit_ibss),
+ },
+};
+
static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
{
struct ieee80211_sta_vht_cap vht_cap = {0};
u16 mcs_map;
+ u32 val;
int i;
vht_cap.vht_supported = 1;
vht_cap.cap = ar->vht_cap_info;
+ if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) {
+ val = ar->num_rf_chains - 1;
+ val <<= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
+ val &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
+
+ vht_cap.cap |= val;
+ }
+
+ if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
+ val = ar->num_rf_chains - 1;
+ val <<= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
+ val &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
+
+ vht_cap.cap |= val;
+ }
+
mcs_map = 0;
for (i = 0; i < 8; i++) {
if (i < ar->num_rf_chains)
@@ -5438,6 +6778,10 @@ int ath10k_mac_register(struct ath10k *ar)
ht_cap = ath10k_get_ht_cap(ar);
vht_cap = ath10k_create_vht_cap(ar);
+ BUILD_BUG_ON((ARRAY_SIZE(ath10k_2ghz_channels) +
+ ARRAY_SIZE(ath10k_5ghz_channels)) !=
+ ATH10K_NUM_CHANS);
+
if (ar->phy_capability & WHAL_WLAN_11G_CAPABILITY) {
channels = kmemdup(ath10k_2ghz_channels,
sizeof(ath10k_2ghz_channels),
@@ -5492,24 +6836,31 @@ int ath10k_mac_register(struct ath10k *ar)
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO);
- ar->hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_HAS_RATE_CONTROL |
- IEEE80211_HW_AP_LINK_PS |
- IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_SW_CRYPTO_CONTROL;
+ ieee80211_hw_set(ar->hw, SIGNAL_DBM);
+ ieee80211_hw_set(ar->hw, SUPPORTS_PS);
+ ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(ar->hw, MFP_CAPABLE);
+ ieee80211_hw_set(ar->hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(ar->hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(ar->hw, AP_LINK_PS);
+ ieee80211_hw_set(ar->hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL);
+ ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT);
+ ieee80211_hw_set(ar->hw, CONNECTION_MONITOR);
+ ieee80211_hw_set(ar->hw, SUPPORTS_PER_STA_GTK);
+ ieee80211_hw_set(ar->hw, WANT_MONITOR_VIF);
+ ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA);
+ ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
+ ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS;
if (ar->ht_cap_info & WMI_HT_CAP_ENABLED) {
- ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
- ar->hw->flags |= IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
+ ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW);
}
ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID;
@@ -5533,6 +6884,9 @@ int ath10k_mac_register(struct ath10k *ar)
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
}
+ if (test_bit(WMI_SERVICE_TDLS, ar->wmi.svc_map))
+ ar->hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
ar->hw->wiphy->max_remain_on_channel_duration = 5000;
@@ -5540,20 +6894,46 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
+ ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations;
+
+ ret = ath10k_wow_init(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to init wow: %d\n", ret);
+ goto err_free;
+ }
+
/*
* on LL hardware queues are managed entirely by the FW
* so we only advertise to mac we can do the queues thing
*/
- ar->hw->queues = 4;
+ ar->hw->queues = IEEE80211_MAX_QUEUES;
+
+ /* vdev_ids are used as hw queue numbers. Make sure offchan tx queue is
+ * something that vdev_ids can't reach so that we don't stop the queue
+ * accidentally.
+ */
+ ar->hw->offchannel_tx_hw_queue = IEEE80211_MAX_QUEUES - 1;
switch (ar->wmi.op_version) {
case ATH10K_FW_WMI_OP_VERSION_MAIN:
- case ATH10K_FW_WMI_OP_VERSION_TLV:
ar->hw->wiphy->iface_combinations = ath10k_if_comb;
ar->hw->wiphy->n_iface_combinations =
ARRAY_SIZE(ath10k_if_comb);
ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
break;
+ case ATH10K_FW_WMI_OP_VERSION_TLV:
+ if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) {
+ ar->hw->wiphy->iface_combinations =
+ ath10k_tlv_qcs_if_comb;
+ ar->hw->wiphy->n_iface_combinations =
+ ARRAY_SIZE(ath10k_tlv_qcs_if_comb);
+ } else {
+ ar->hw->wiphy->iface_combinations = ath10k_tlv_if_comb;
+ ar->hw->wiphy->n_iface_combinations =
+ ARRAY_SIZE(ath10k_tlv_if_comb);
+ }
+ ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+ break;
case ATH10K_FW_WMI_OP_VERSION_10_1:
case ATH10K_FW_WMI_OP_VERSION_10_2:
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
index 68296117d203..b291f063705c 100644
--- a/drivers/net/wireless/ath/ath10k/mac.h
+++ b/drivers/net/wireless/ath/ath10k/mac.h
@@ -23,11 +23,22 @@
#define WEP_KEYID_SHIFT 6
+enum wmi_tlv_tx_pause_id;
+enum wmi_tlv_tx_pause_action;
+
struct ath10k_generic_iter {
struct ath10k *ar;
int ret;
};
+struct rfc1042_hdr {
+ u8 llc_dsap;
+ u8 llc_ssap;
+ u8 llc_ctrl;
+ u8 snap_oui[3];
+ __be16 snap_type;
+} __packed;
+
struct ath10k *ath10k_mac_create(size_t priv_size);
void ath10k_mac_destroy(struct ath10k *ar);
int ath10k_mac_register(struct ath10k *ar);
@@ -45,6 +56,24 @@ void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
void ath10k_drain_tx(struct ath10k *ar);
bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
u8 keyidx);
+int ath10k_mac_vif_chan(struct ieee80211_vif *vif,
+ struct cfg80211_chan_def *def);
+
+void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id);
+void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id,
+ enum wmi_tlv_tx_pause_id pause_id,
+ enum wmi_tlv_tx_pause_action action);
+
+u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
+ u8 hw_rate);
+u8 ath10k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
+ u32 bitrate);
+
+void ath10k_mac_tx_lock(struct ath10k *ar, int reason);
+void ath10k_mac_tx_unlock(struct ath10k *ar, int reason);
+void ath10k_mac_vif_tx_lock(struct ath10k_vif *arvif, int reason);
+void ath10k_mac_vif_tx_unlock(struct ath10k_vif *arvif, int reason);
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
{
diff --git a/drivers/net/wireless/ath/ath10k/p2p.c b/drivers/net/wireless/ath/ath10k/p2p.c
new file mode 100644
index 000000000000..c0b6ffaf3ec1
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/p2p.c
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+#include "core.h"
+#include "wmi.h"
+#include "mac.h"
+#include "p2p.h"
+
+static void ath10k_p2p_noa_ie_fill(u8 *data, size_t len,
+ const struct wmi_p2p_noa_info *noa)
+{
+ struct ieee80211_p2p_noa_attr *noa_attr;
+ u8 ctwindow_oppps = noa->ctwindow_oppps;
+ u8 ctwindow = ctwindow_oppps >> WMI_P2P_OPPPS_CTWINDOW_OFFSET;
+ bool oppps = !!(ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT);
+ __le16 *noa_attr_len;
+ u16 attr_len;
+ u8 noa_descriptors = noa->num_descriptors;
+ int i;
+
+ /* P2P IE */
+ data[0] = WLAN_EID_VENDOR_SPECIFIC;
+ data[1] = len - 2;
+ data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
+ data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
+ data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
+ data[5] = WLAN_OUI_TYPE_WFA_P2P;
+
+ /* NOA ATTR */
+ data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE;
+ noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */
+ noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9];
+
+ noa_attr->index = noa->index;
+ noa_attr->oppps_ctwindow = ctwindow;
+ if (oppps)
+ noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT;
+
+ for (i = 0; i < noa_descriptors; i++) {
+ noa_attr->desc[i].count =
+ __le32_to_cpu(noa->descriptors[i].type_count);
+ noa_attr->desc[i].duration = noa->descriptors[i].duration;
+ noa_attr->desc[i].interval = noa->descriptors[i].interval;
+ noa_attr->desc[i].start_time = noa->descriptors[i].start_time;
+ }
+
+ attr_len = 2; /* index + oppps_ctwindow */
+ attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
+ *noa_attr_len = __cpu_to_le16(attr_len);
+}
+
+static size_t ath10k_p2p_noa_ie_len_compute(const struct wmi_p2p_noa_info *noa)
+{
+ size_t len = 0;
+
+ if (!noa->num_descriptors &&
+ !(noa->ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT))
+ return 0;
+
+ len += 1 + 1 + 4; /* EID + len + OUI */
+ len += 1 + 2; /* noa attr + attr len */
+ len += 1 + 1; /* index + oppps_ctwindow */
+ len += noa->num_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
+
+ return len;
+}
+
+static void ath10k_p2p_noa_ie_assign(struct ath10k_vif *arvif, void *ie,
+ size_t len)
+{
+ struct ath10k *ar = arvif->ar;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ kfree(arvif->u.ap.noa_data);
+
+ arvif->u.ap.noa_data = ie;
+ arvif->u.ap.noa_len = len;
+}
+
+static void __ath10k_p2p_noa_update(struct ath10k_vif *arvif,
+ const struct wmi_p2p_noa_info *noa)
+{
+ struct ath10k *ar = arvif->ar;
+ void *ie;
+ size_t len;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ ath10k_p2p_noa_ie_assign(arvif, NULL, 0);
+
+ len = ath10k_p2p_noa_ie_len_compute(noa);
+ if (!len)
+ return;
+
+ ie = kmalloc(len, GFP_ATOMIC);
+ if (!ie)
+ return;
+
+ ath10k_p2p_noa_ie_fill(ie, len, noa);
+ ath10k_p2p_noa_ie_assign(arvif, ie, len);
+}
+
+void ath10k_p2p_noa_update(struct ath10k_vif *arvif,
+ const struct wmi_p2p_noa_info *noa)
+{
+ struct ath10k *ar = arvif->ar;
+
+ spin_lock_bh(&ar->data_lock);
+ __ath10k_p2p_noa_update(arvif, noa);
+ spin_unlock_bh(&ar->data_lock);
+}
+
+struct ath10k_p2p_noa_arg {
+ u32 vdev_id;
+ const struct wmi_p2p_noa_info *noa;
+};
+
+static void ath10k_p2p_noa_update_vdev_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct ath10k_p2p_noa_arg *arg = data;
+
+ if (arvif->vdev_id != arg->vdev_id)
+ return;
+
+ ath10k_p2p_noa_update(arvif, arg->noa);
+}
+
+void ath10k_p2p_noa_update_by_vdev_id(struct ath10k *ar, u32 vdev_id,
+ const struct wmi_p2p_noa_info *noa)
+{
+ struct ath10k_p2p_noa_arg arg = {
+ .vdev_id = vdev_id,
+ .noa = noa,
+ };
+
+ ieee80211_iterate_active_interfaces_atomic(ar->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ ath10k_p2p_noa_update_vdev_iter,
+ &arg);
+}
diff --git a/drivers/net/wireless/ath/ath10k/p2p.h b/drivers/net/wireless/ath/ath10k/p2p.h
new file mode 100644
index 000000000000..7be616e2e121
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/p2p.h
@@ -0,0 +1,28 @@
+/*
+ * 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 _P2P_H
+#define _P2P_H
+
+struct ath10k_vif;
+struct wmi_p2p_noa_info;
+
+void ath10k_p2p_noa_update(struct ath10k_vif *arvif,
+ const struct wmi_p2p_noa_info *noa);
+void ath10k_p2p_noa_update_by_vdev_id(struct ath10k *ar, u32 vdev_id,
+ const struct wmi_p2p_noa_info *noa);
+
+#endif
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 7681237fe298..ea656e011a96 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -113,7 +113,7 @@ static const struct ce_attr host_ce_config_wlan[] = {
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
- .dest_nentries = 32,
+ .dest_nentries = 128,
},
/* CE3: host->target WMI */
@@ -183,7 +183,7 @@ static const struct ce_pipe_config target_ce_config_wlan[] = {
{
.pipenum = __cpu_to_le32(2),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
- .nentries = __cpu_to_le32(32),
+ .nentries = __cpu_to_le32(64),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
@@ -330,6 +330,205 @@ static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
},
};
+static bool ath10k_pci_is_awake(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ u32 val = ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
+ RTC_STATE_ADDRESS);
+
+ return RTC_STATE_V_GET(val) == RTC_STATE_V_ON;
+}
+
+static void __ath10k_pci_wake(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+ lockdep_assert_held(&ar_pci->ps_lock);
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps wake reg refcount %lu awake %d\n",
+ ar_pci->ps_wake_refcount, ar_pci->ps_awake);
+
+ iowrite32(PCIE_SOC_WAKE_V_MASK,
+ ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
+ PCIE_SOC_WAKE_ADDRESS);
+}
+
+static void __ath10k_pci_sleep(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+ lockdep_assert_held(&ar_pci->ps_lock);
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps sleep reg refcount %lu awake %d\n",
+ ar_pci->ps_wake_refcount, ar_pci->ps_awake);
+
+ iowrite32(PCIE_SOC_WAKE_RESET,
+ ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS +
+ PCIE_SOC_WAKE_ADDRESS);
+ ar_pci->ps_awake = false;
+}
+
+static int ath10k_pci_wake_wait(struct ath10k *ar)
+{
+ int tot_delay = 0;
+ int curr_delay = 5;
+
+ while (tot_delay < PCIE_WAKE_TIMEOUT) {
+ if (ath10k_pci_is_awake(ar))
+ return 0;
+
+ udelay(curr_delay);
+ tot_delay += curr_delay;
+
+ if (curr_delay < 50)
+ curr_delay += 5;
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int ath10k_pci_wake(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&ar_pci->ps_lock, flags);
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps wake refcount %lu awake %d\n",
+ ar_pci->ps_wake_refcount, ar_pci->ps_awake);
+
+ /* This function can be called very frequently. To avoid excessive
+ * CPU stalls for MMIO reads use a cache var to hold the device state.
+ */
+ if (!ar_pci->ps_awake) {
+ __ath10k_pci_wake(ar);
+
+ ret = ath10k_pci_wake_wait(ar);
+ if (ret == 0)
+ ar_pci->ps_awake = true;
+ }
+
+ if (ret == 0) {
+ ar_pci->ps_wake_refcount++;
+ WARN_ON(ar_pci->ps_wake_refcount == 0);
+ }
+
+ spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
+
+ return ret;
+}
+
+static void ath10k_pci_sleep(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ar_pci->ps_lock, flags);
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps sleep refcount %lu awake %d\n",
+ ar_pci->ps_wake_refcount, ar_pci->ps_awake);
+
+ if (WARN_ON(ar_pci->ps_wake_refcount == 0))
+ goto skip;
+
+ ar_pci->ps_wake_refcount--;
+
+ mod_timer(&ar_pci->ps_timer, jiffies +
+ msecs_to_jiffies(ATH10K_PCI_SLEEP_GRACE_PERIOD_MSEC));
+
+skip:
+ spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
+}
+
+static void ath10k_pci_ps_timer(unsigned long ptr)
+{
+ struct ath10k *ar = (void *)ptr;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ar_pci->ps_lock, flags);
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps timer refcount %lu awake %d\n",
+ ar_pci->ps_wake_refcount, ar_pci->ps_awake);
+
+ if (ar_pci->ps_wake_refcount > 0)
+ goto skip;
+
+ __ath10k_pci_sleep(ar);
+
+skip:
+ spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
+}
+
+static void ath10k_pci_sleep_sync(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ unsigned long flags;
+
+ del_timer_sync(&ar_pci->ps_timer);
+
+ spin_lock_irqsave(&ar_pci->ps_lock, flags);
+ WARN_ON(ar_pci->ps_wake_refcount > 0);
+ __ath10k_pci_sleep(ar);
+ spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
+}
+
+void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ int ret;
+
+ ret = ath10k_pci_wake(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to wake target for write32 of 0x%08x at 0x%08x: %d\n",
+ value, offset, ret);
+ return;
+ }
+
+ iowrite32(value, ar_pci->mem + offset);
+ ath10k_pci_sleep(ar);
+}
+
+u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ u32 val;
+ int ret;
+
+ ret = ath10k_pci_wake(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to wake target for read32 at 0x%08x: %d\n",
+ offset, ret);
+ return 0xffffffff;
+ }
+
+ val = ioread32(ar_pci->mem + offset);
+ ath10k_pci_sleep(ar);
+
+ return val;
+}
+
+u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr)
+{
+ return ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + addr);
+}
+
+void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val)
+{
+ ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val);
+}
+
+u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
+{
+ return ath10k_pci_read32(ar, PCIE_LOCAL_BASE_ADDRESS + addr);
+}
+
+void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
+{
+ ath10k_pci_write32(ar, PCIE_LOCAL_BASE_ADDRESS + addr, val);
+}
+
static bool ath10k_pci_irq_pending(struct ath10k *ar)
{
u32 cause;
@@ -793,45 +992,6 @@ static int ath10k_pci_diag_write32(struct ath10k *ar, u32 address, u32 value)
return ath10k_pci_diag_write_mem(ar, address, &val, sizeof(val));
}
-static bool ath10k_pci_is_awake(struct ath10k *ar)
-{
- u32 val = ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS);
-
- return RTC_STATE_V_GET(val) == RTC_STATE_V_ON;
-}
-
-static int ath10k_pci_wake_wait(struct ath10k *ar)
-{
- int tot_delay = 0;
- int curr_delay = 5;
-
- while (tot_delay < PCIE_WAKE_TIMEOUT) {
- if (ath10k_pci_is_awake(ar))
- return 0;
-
- udelay(curr_delay);
- tot_delay += curr_delay;
-
- if (curr_delay < 50)
- curr_delay += 5;
- }
-
- return -ETIMEDOUT;
-}
-
-static int ath10k_pci_wake(struct ath10k *ar)
-{
- ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
- PCIE_SOC_WAKE_V_MASK);
- return ath10k_pci_wake_wait(ar);
-}
-
-static void ath10k_pci_sleep(struct ath10k *ar)
-{
- ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
- PCIE_SOC_WAKE_RESET);
-}
-
/* Called by lower (CE) layer when a send to Target completes. */
static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
{
@@ -1212,11 +1372,15 @@ static void ath10k_pci_irq_enable(struct ath10k *ar)
static int ath10k_pci_hif_start(struct ath10k *ar)
{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
ath10k_pci_irq_enable(ar);
ath10k_pci_rx_post(ar);
+ pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL,
+ ar_pci->link_ctl);
+
return 0;
}
@@ -1260,7 +1424,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
struct ath10k_ce_ring *ce_ring;
struct ce_desc *ce_desc;
struct sk_buff *skb;
- unsigned int id;
int i;
ar = pci_pipe->hif_ce_state;
@@ -1284,8 +1447,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
continue;
ce_ring->per_transfer_context[i] = NULL;
- id = MS(__le16_to_cpu(ce_desc[i].flags),
- CE_DESC_FLAGS_META_DATA);
ar_pci->msg_callbacks_current.tx_completion(ar, skb);
}
@@ -1329,6 +1490,9 @@ static void ath10k_pci_flush(struct ath10k *ar)
static void ath10k_pci_hif_stop(struct ath10k *ar)
{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ unsigned long flags;
+
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
/* Most likely the device has HTT Rx ring configured. The only way to
@@ -1347,6 +1511,10 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_irq_disable(ar);
ath10k_pci_irq_sync(ar);
ath10k_pci_flush(ar);
+
+ spin_lock_irqsave(&ar_pci->ps_lock, flags);
+ WARN_ON(ar_pci->ps_wake_refcount > 0);
+ spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
}
static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
@@ -1524,12 +1692,11 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) {
case QCA6174_HW_1_0_CHIP_ID_REV:
case QCA6174_HW_1_1_CHIP_ID_REV:
+ case QCA6174_HW_2_1_CHIP_ID_REV:
+ case QCA6174_HW_2_2_CHIP_ID_REV:
return 3;
case QCA6174_HW_1_3_CHIP_ID_REV:
return 2;
- case QCA6174_HW_2_1_CHIP_ID_REV:
- case QCA6174_HW_2_2_CHIP_ID_REV:
- return 6;
case QCA6174_HW_3_0_CHIP_ID_REV:
case QCA6174_HW_3_1_CHIP_ID_REV:
case QCA6174_HW_3_2_CHIP_ID_REV:
@@ -1967,15 +2134,15 @@ static int ath10k_pci_chip_reset(struct ath10k *ar)
static int ath10k_pci_hif_power_up(struct ath10k *ar)
{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ret;
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n");
- ret = ath10k_pci_wake(ar);
- if (ret) {
- ath10k_err(ar, "failed to wake up target: %d\n", ret);
- return ret;
- }
+ pcie_capability_read_word(ar_pci->pdev, PCI_EXP_LNKCTL,
+ &ar_pci->link_ctl);
+ pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL,
+ ar_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
/*
* Bring the target up cleanly.
@@ -2023,7 +2190,6 @@ err_ce:
ath10k_pci_ce_deinit(ar);
err_sleep:
- ath10k_pci_sleep(ar);
return ret;
}
@@ -2034,28 +2200,18 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
/* Currently hif_power_up performs effectively a reset and hif_stop
* resets the chip as well so there's no point in resetting here.
*/
-
- ath10k_pci_sleep(ar);
}
#ifdef CONFIG_PM
-#define ATH10K_PCI_PM_CONTROL 0x44
-
static int ath10k_pci_hif_suspend(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct pci_dev *pdev = ar_pci->pdev;
- u32 val;
-
- pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val);
-
- if ((val & 0x000000ff) != 0x3) {
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL,
- (val & 0xffffff00) | 0x03);
- }
+ /* The grace timer can still be counting down and ar->ps_awake be true.
+ * It is known that the device may be asleep after resuming regardless
+ * of the SoC powersave state before suspending. Hence make sure the
+ * device is asleep before proceeding.
+ */
+ ath10k_pci_sleep_sync(ar);
return 0;
}
@@ -2066,22 +2222,14 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
struct pci_dev *pdev = ar_pci->pdev;
u32 val;
- pci_read_config_dword(pdev, ATH10K_PCI_PM_CONTROL, &val);
-
- if ((val & 0x000000ff) != 0) {
- pci_restore_state(pdev);
- pci_write_config_dword(pdev, ATH10K_PCI_PM_CONTROL,
- val & 0xffffff00);
- /*
- * Suspend/Resume resets the PCI configuration space,
- * so we have to re-disable the RETRY_TIMEOUT register (0x41)
- * to keep PCI Tx retries from interfering with C3 CPU state
- */
- pci_read_config_dword(pdev, 0x40, &val);
-
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
- }
+ /* Suspend/Resume resets the PCI configuration space, so we have to
+ * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+ * from interfering with C3 CPU state. pci_restore_state won't help
+ * here since it only restores the first 64 bytes pci config header.
+ */
+ pci_read_config_dword(pdev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
return 0;
}
@@ -2497,7 +2645,6 @@ static int ath10k_pci_claim(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct pci_dev *pdev = ar_pci->pdev;
- u32 lcr_val;
int ret;
pci_set_drvdata(pdev, ar);
@@ -2531,10 +2678,6 @@ static int ath10k_pci_claim(struct ath10k *ar)
pci_set_master(pdev);
- /* Workaround: Disable ASPM */
- pci_read_config_dword(pdev, 0x80, &lcr_val);
- pci_write_config_dword(pdev, 0x80, (lcr_val & 0xffffff00));
-
/* Arrange for access to Target SoC registers. */
ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0);
if (!ar_pci->mem) {
@@ -2621,9 +2764,19 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
ar_pci->dev = &pdev->dev;
ar_pci->ar = ar;
+ if (pdev->subsystem_vendor || pdev->subsystem_device)
+ scnprintf(ar->spec_board_id, sizeof(ar->spec_board_id),
+ "%04x:%04x:%04x:%04x",
+ pdev->vendor, pdev->device,
+ pdev->subsystem_vendor, pdev->subsystem_device);
+
spin_lock_init(&ar_pci->ce_lock);
+ spin_lock_init(&ar_pci->ps_lock);
+
setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
(unsigned long)ar);
+ setup_timer(&ar_pci->ps_timer, ath10k_pci_ps_timer,
+ (unsigned long)ar);
ret = ath10k_pci_claim(ar);
if (ret) {
@@ -2631,12 +2784,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_core_destroy;
}
- ret = ath10k_pci_wake(ar);
- if (ret) {
- ath10k_err(ar, "failed to wake up: %d\n", ret);
- goto err_release;
- }
-
ret = ath10k_pci_alloc_pipes(ar);
if (ret) {
ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
@@ -2678,11 +2825,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) {
ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
pdev->device, chip_id);
- goto err_sleep;
+ goto err_free_irq;
}
- ath10k_pci_sleep(ar);
-
ret = ath10k_core_register(ar, chip_id);
if (ret) {
ath10k_err(ar, "failed to register driver core: %d\n", ret);
@@ -2702,9 +2847,7 @@ err_free_pipes:
ath10k_pci_free_pipes(ar);
err_sleep:
- ath10k_pci_sleep(ar);
-
-err_release:
+ ath10k_pci_sleep_sync(ar);
ath10k_pci_release(ar);
err_core_destroy:
@@ -2734,6 +2877,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
ath10k_pci_deinit_irq(ar);
ath10k_pci_ce_deinit(ar);
ath10k_pci_free_pipes(ar);
+ ath10k_pci_sleep_sync(ar);
ath10k_pci_release(ar);
ath10k_core_destroy(ar);
}
@@ -2770,7 +2914,21 @@ module_exit(ath10k_pci_exit);
MODULE_AUTHOR("Qualcomm Atheros");
MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
MODULE_LICENSE("Dual BSD/GPL");
+
+/* QCA988x 2.0 firmware files */
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API2_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API4_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API5_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
+
+/* QCA6174 2.1 firmware files */
+MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE);
+MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API5_FILE);
+MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" QCA6174_HW_2_1_BOARD_DATA_FILE);
+
+/* QCA6174 3.1 firmware files */
+MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE);
+MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE);
+MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE);
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index bddf54320160..d7696ddc03c4 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -185,6 +185,41 @@ struct ath10k_pci {
/* Map CE id to ce_state */
struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
struct timer_list rx_post_retry;
+
+ /* Due to HW quirks it is recommended to disable ASPM during device
+ * bootup. To do that the original PCI-E Link Control is stored before
+ * device bootup is executed and re-programmed later.
+ */
+ u16 link_ctl;
+
+ /* Protects ps_awake and ps_wake_refcount */
+ spinlock_t ps_lock;
+
+ /* The device has a special powersave-oriented register. When device is
+ * considered asleep it drains less power and driver is forbidden from
+ * accessing most MMIO registers. If host were to access them without
+ * waking up the device might scribble over host memory or return
+ * 0xdeadbeef readouts.
+ */
+ unsigned long ps_wake_refcount;
+
+ /* Waking up takes some time (up to 2ms in some cases) so it can be bad
+ * for latency. To mitigate this the device isn't immediately allowed
+ * to sleep after all references are undone - instead there's a grace
+ * period after which the powersave register is updated unless some
+ * activity to/from device happened in the meantime.
+ *
+ * Also see comments on ATH10K_PCI_SLEEP_GRACE_PERIOD_MSEC.
+ */
+ struct timer_list ps_timer;
+
+ /* MMIO registers are used to communicate with the device. With
+ * intensive traffic accessing powersave register would be a bit
+ * wasteful overhead and would needlessly stall CPU. It is far more
+ * efficient to rely on a variable in RAM and update it only upon
+ * powersave register state changes.
+ */
+ bool ps_awake;
};
static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
@@ -209,61 +244,25 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
* for this device; but that's not guaranteed.
*/
#define TARG_CPU_SPACE_TO_CE_SPACE(ar, pci_addr, addr) \
- (((ioread32((pci_addr)+(SOC_CORE_BASE_ADDRESS| \
+ (((ath10k_pci_read32(ar, (SOC_CORE_BASE_ADDRESS | \
CORE_CTRL_ADDRESS)) & 0x7ff) << 21) | \
0x100000 | ((addr) & 0xfffff))
/* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
#define DIAG_ACCESS_CE_TIMEOUT_MS 10
-/* Target exposes its registers for direct access. However before host can
- * access them it needs to make sure the target is awake (ath10k_pci_wake,
- * ath10k_pci_wake_wait, ath10k_pci_is_awake). Once target is awake it won't go
- * to sleep unless host tells it to (ath10k_pci_sleep).
- *
- * If host tries to access target registers without waking it up it can
- * scribble over host memory.
- *
- * If target is asleep waking it up may take up to even 2ms.
- */
-
-static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
- u32 value)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- iowrite32(value, ar_pci->mem + offset);
-}
-
-static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- return ioread32(ar_pci->mem + offset);
-}
-
-static inline u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr)
-{
- return ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + addr);
-}
-
-static inline void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val)
-{
- ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val);
-}
-
-static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
-}
+void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value);
+void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val);
+void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val);
-static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+u32 ath10k_pci_read32(struct ath10k *ar, u32 offset);
+u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr);
+u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr);
- iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
-}
+/* QCA6174 is known to have Tx/Rx issues when SOC_WAKE register is poked too
+ * frequently. To avoid this put SoC to sleep after a very conservative grace
+ * period. Adjust with great care.
+ */
+#define ATH10K_PCI_SLEEP_GRACE_PERIOD_MSEC 60
#endif /* _PCI_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h
index e9cc7787bf5f..492b5a5af434 100644
--- a/drivers/net/wireless/ath/ath10k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath10k/rx_desc.h
@@ -661,6 +661,28 @@ struct rx_msdu_end {
#define RX_PPDU_START_INFO5_SERVICE_MASK 0x0000ffff
#define RX_PPDU_START_INFO5_SERVICE_LSB 0
+/* No idea what this flag means. It seems to be always set in rate. */
+#define RX_PPDU_START_RATE_FLAG BIT(3)
+
+enum rx_ppdu_start_rate {
+ RX_PPDU_START_RATE_OFDM_48M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_48M,
+ RX_PPDU_START_RATE_OFDM_24M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_24M,
+ RX_PPDU_START_RATE_OFDM_12M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_12M,
+ RX_PPDU_START_RATE_OFDM_6M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_6M,
+ RX_PPDU_START_RATE_OFDM_54M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_54M,
+ RX_PPDU_START_RATE_OFDM_36M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_36M,
+ RX_PPDU_START_RATE_OFDM_18M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_18M,
+ RX_PPDU_START_RATE_OFDM_9M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_OFDM_9M,
+
+ RX_PPDU_START_RATE_CCK_LP_11M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_11M,
+ RX_PPDU_START_RATE_CCK_LP_5_5M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_5_5M,
+ RX_PPDU_START_RATE_CCK_LP_2M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_2M,
+ RX_PPDU_START_RATE_CCK_LP_1M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_LP_1M,
+ RX_PPDU_START_RATE_CCK_SP_11M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_11M,
+ RX_PPDU_START_RATE_CCK_SP_5_5M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_5_5M,
+ RX_PPDU_START_RATE_CCK_SP_2M = RX_PPDU_START_RATE_FLAG | ATH10K_HW_RATE_CCK_SP_2M,
+};
+
struct rx_ppdu_start {
struct {
u8 pri20_mhz;
diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c
index d22addf6118b..8dcd424aa502 100644
--- a/drivers/net/wireless/ath/ath10k/spectral.c
+++ b/drivers/net/wireless/ath/ath10k/spectral.c
@@ -519,9 +519,12 @@ int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
int ath10k_spectral_create(struct ath10k *ar)
{
+ /* The buffer size covers whole channels in dual bands up to 128 bins.
+ * Scan with bigger than 128 bins needs to be run on single band each.
+ */
ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan",
ar->debug.debugfs_phy,
- 1024, 256,
+ 1140, 2500,
&rfs_spec_scan_cb, NULL);
debugfs_create_file("spectral_scan_ctl",
S_IRUSR | S_IWUSR,
diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c
index aede750809fe..1a899d70dc5d 100644
--- a/drivers/net/wireless/ath/ath10k/thermal.c
+++ b/drivers/net/wireless/ath/ath10k/thermal.c
@@ -23,102 +23,50 @@
#include "debug.h"
#include "wmi-ops.h"
-static int ath10k_thermal_get_active_vifs(struct ath10k *ar,
- enum wmi_vdev_type type)
+static int
+ath10k_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
{
- struct ath10k_vif *arvif;
- int count = 0;
-
- lockdep_assert_held(&ar->conf_mutex);
-
- list_for_each_entry(arvif, &ar->arvifs, list) {
- if (!arvif->is_started)
- continue;
-
- if (!arvif->is_up)
- continue;
-
- if (arvif->vdev_type != type)
- continue;
-
- count++;
- }
- return count;
-}
-
-static int ath10k_thermal_get_max_dutycycle(struct thermal_cooling_device *cdev,
- unsigned long *state)
-{
- *state = ATH10K_QUIET_DUTY_CYCLE_MAX;
+ *state = ATH10K_THERMAL_THROTTLE_MAX;
return 0;
}
-static int ath10k_thermal_get_cur_dutycycle(struct thermal_cooling_device *cdev,
- unsigned long *state)
+static int
+ath10k_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
{
struct ath10k *ar = cdev->devdata;
mutex_lock(&ar->conf_mutex);
- *state = ar->thermal.duty_cycle;
+ *state = ar->thermal.throttle_state;
mutex_unlock(&ar->conf_mutex);
return 0;
}
-static int ath10k_thermal_set_cur_dutycycle(struct thermal_cooling_device *cdev,
- unsigned long duty_cycle)
+static int
+ath10k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long throttle_state)
{
struct ath10k *ar = cdev->devdata;
- u32 period, duration, enabled;
- int num_bss, ret = 0;
- mutex_lock(&ar->conf_mutex);
- if (ar->state != ATH10K_STATE_ON) {
- ret = -ENETDOWN;
- goto out;
- }
-
- if (duty_cycle > ATH10K_QUIET_DUTY_CYCLE_MAX) {
- ath10k_warn(ar, "duty cycle %ld is exceeding the limit %d\n",
- duty_cycle, ATH10K_QUIET_DUTY_CYCLE_MAX);
- ret = -EINVAL;
- goto out;
- }
- /* TODO: Right now, thermal mitigation is handled only for single/multi
- * vif AP mode. Since quiet param is not validated in STA mode, it needs
- * to be investigated further to handle multi STA and multi-vif (AP+STA)
- * mode properly.
- */
- num_bss = ath10k_thermal_get_active_vifs(ar, WMI_VDEV_TYPE_AP);
- if (!num_bss) {
- ath10k_warn(ar, "no active AP interfaces\n");
- ret = -ENETDOWN;
- goto out;
- }
- period = max(ATH10K_QUIET_PERIOD_MIN,
- (ATH10K_QUIET_PERIOD_DEFAULT / num_bss));
- duration = (period * duty_cycle) / 100;
- enabled = duration ? 1 : 0;
-
- ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration,
- ATH10K_QUIET_START_OFFSET,
- enabled);
- if (ret) {
- ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",
- period, duration, enabled, ret);
- goto out;
+ if (throttle_state > ATH10K_THERMAL_THROTTLE_MAX) {
+ ath10k_warn(ar, "throttle state %ld is exceeding the limit %d\n",
+ throttle_state, ATH10K_THERMAL_THROTTLE_MAX);
+ return -EINVAL;
}
- ar->thermal.duty_cycle = duty_cycle;
-out:
+ mutex_lock(&ar->conf_mutex);
+ ar->thermal.throttle_state = throttle_state;
+ ath10k_thermal_set_throttling(ar);
mutex_unlock(&ar->conf_mutex);
- return ret;
+ return 0;
}
static struct thermal_cooling_device_ops ath10k_thermal_ops = {
- .get_max_state = ath10k_thermal_get_max_dutycycle,
- .get_cur_state = ath10k_thermal_get_cur_dutycycle,
- .set_cur_state = ath10k_thermal_set_cur_dutycycle,
+ .get_max_state = ath10k_thermal_get_max_throttle_state,
+ .get_cur_state = ath10k_thermal_get_cur_throttle_state,
+ .set_cur_state = ath10k_thermal_set_cur_throttle_state,
};
static ssize_t ath10k_thermal_show_temp(struct device *dev,
@@ -127,6 +75,7 @@ static ssize_t ath10k_thermal_show_temp(struct device *dev,
{
struct ath10k *ar = dev_get_drvdata(dev);
int ret, temperature;
+ unsigned long time_left;
mutex_lock(&ar->conf_mutex);
@@ -148,9 +97,9 @@ static ssize_t ath10k_thermal_show_temp(struct device *dev,
goto out;
}
- ret = wait_for_completion_timeout(&ar->thermal.wmi_sync,
- ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
- if (ret == 0) {
+ time_left = wait_for_completion_timeout(&ar->thermal.wmi_sync,
+ ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
+ if (!time_left) {
ath10k_warn(ar, "failed to synchronize thermal read\n");
ret = -ETIMEDOUT;
goto out;
@@ -184,6 +133,32 @@ static struct attribute *ath10k_hwmon_attrs[] = {
};
ATTRIBUTE_GROUPS(ath10k_hwmon);
+void ath10k_thermal_set_throttling(struct ath10k *ar)
+{
+ u32 period, duration, enabled;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ if (!ar->wmi.ops->gen_pdev_set_quiet_mode)
+ return;
+
+ if (ar->state != ATH10K_STATE_ON)
+ return;
+
+ period = ar->thermal.quiet_period;
+ duration = (period * ar->thermal.throttle_state) / 100;
+ enabled = duration ? 1 : 0;
+
+ ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration,
+ ATH10K_QUIET_START_OFFSET,
+ enabled);
+ if (ret) {
+ ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",
+ period, duration, enabled, ret);
+ }
+}
+
int ath10k_thermal_register(struct ath10k *ar)
{
struct thermal_cooling_device *cdev;
@@ -202,11 +177,12 @@ int ath10k_thermal_register(struct ath10k *ar)
ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj,
"cooling_device");
if (ret) {
- ath10k_err(ar, "failed to create thermal symlink\n");
+ ath10k_err(ar, "failed to create cooling device symlink\n");
goto err_cooling_destroy;
}
ar->thermal.cdev = cdev;
+ ar->thermal.quiet_period = ATH10K_QUIET_PERIOD_DEFAULT;
/* Do not register hwmon device when temperature reading is not
* supported by firmware
@@ -231,7 +207,7 @@ int ath10k_thermal_register(struct ath10k *ar)
return 0;
err_remove_link:
- sysfs_remove_link(&ar->dev->kobj, "thermal_sensor");
+ sysfs_remove_link(&ar->dev->kobj, "cooling_device");
err_cooling_destroy:
thermal_cooling_device_unregister(cdev);
return ret;
diff --git a/drivers/net/wireless/ath/ath10k/thermal.h b/drivers/net/wireless/ath/ath10k/thermal.h
index bccc17ae0fde..b610ea5caae8 100644
--- a/drivers/net/wireless/ath/ath10k/thermal.h
+++ b/drivers/net/wireless/ath/ath10k/thermal.h
@@ -19,16 +19,17 @@
#define ATH10K_QUIET_PERIOD_DEFAULT 100
#define ATH10K_QUIET_PERIOD_MIN 25
#define ATH10K_QUIET_START_OFFSET 10
-#define ATH10K_QUIET_DUTY_CYCLE_MAX 70
#define ATH10K_HWMON_NAME_LEN 15
#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5*HZ)
+#define ATH10K_THERMAL_THROTTLE_MAX 100
struct ath10k_thermal {
struct thermal_cooling_device *cdev;
struct completion wmi_sync;
/* protected by conf_mutex */
- u32 duty_cycle;
+ u32 throttle_state;
+ u32 quiet_period;
/* temperature value in Celcius degree
* protected by data_lock
*/
@@ -39,6 +40,7 @@ struct ath10k_thermal {
int ath10k_thermal_register(struct ath10k *ar);
void ath10k_thermal_unregister(struct ath10k *ar);
void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature);
+void ath10k_thermal_set_throttling(struct ath10k *ar);
#else
static inline int ath10k_thermal_register(struct ath10k *ar)
{
@@ -54,5 +56,9 @@ static inline void ath10k_thermal_event_temperature(struct ath10k *ar,
{
}
+static inline void ath10k_thermal_set_throttling(struct ath10k *ar)
+{
+}
+
#endif
#endif /* _THERMAL_ */
diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h
index 5407887380ab..71bdb368813d 100644
--- a/drivers/net/wireless/ath/ath10k/trace.h
+++ b/drivers/net/wireless/ath/ath10k/trace.h
@@ -21,11 +21,16 @@
#include "core.h"
#if !defined(_TRACE_H_)
-static inline u32 ath10k_frm_hdr_len(const void *buf)
+static inline u32 ath10k_frm_hdr_len(const void *buf, size_t len)
{
const struct ieee80211_hdr *hdr = buf;
- return ieee80211_hdrlen(hdr->frame_control);
+ /* In some rare cases (e.g. fcs error) device reports frame buffer
+ * shorter than what frame header implies (e.g. len = 0). The buffer
+ * can still be accessed so do a simple min() to guarantee caller
+ * doesn't get value greater than len.
+ */
+ return min_t(u32, len, ieee80211_hdrlen(hdr->frame_control));
}
#endif
@@ -46,7 +51,7 @@ static inline void trace_ ## name(proto) {}
#undef TRACE_SYSTEM
#define TRACE_SYSTEM ath10k
-#define ATH10K_MSG_MAX 200
+#define ATH10K_MSG_MAX 400
DECLARE_EVENT_CLASS(ath10k_log_event,
TP_PROTO(struct ath10k *ar, struct va_format *vaf),
@@ -360,13 +365,13 @@ DECLARE_EVENT_CLASS(ath10k_hdr_event,
__string(device, dev_name(ar->dev))
__string(driver, dev_driver_string(ar->dev))
__field(size_t, len)
- __dynamic_array(u8, data, ath10k_frm_hdr_len(data))
+ __dynamic_array(u8, data, ath10k_frm_hdr_len(data, len))
),
TP_fast_assign(
__assign_str(device, dev_name(ar->dev));
__assign_str(driver, dev_driver_string(ar->dev));
- __entry->len = ath10k_frm_hdr_len(data);
+ __entry->len = ath10k_frm_hdr_len(data, len);
memcpy(__get_dynamic_array(data), data, __entry->len);
),
@@ -387,15 +392,16 @@ DECLARE_EVENT_CLASS(ath10k_payload_event,
__string(device, dev_name(ar->dev))
__string(driver, dev_driver_string(ar->dev))
__field(size_t, len)
- __dynamic_array(u8, payload, (len - ath10k_frm_hdr_len(data)))
+ __dynamic_array(u8, payload, (len -
+ ath10k_frm_hdr_len(data, len)))
),
TP_fast_assign(
__assign_str(device, dev_name(ar->dev));
__assign_str(driver, dev_driver_string(ar->dev));
- __entry->len = len - ath10k_frm_hdr_len(data);
+ __entry->len = len - ath10k_frm_hdr_len(data, len);
memcpy(__get_dynamic_array(payload),
- data + ath10k_frm_hdr_len(data), __entry->len);
+ data + ath10k_frm_hdr_len(data, len), __entry->len);
),
TP_printk(
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index 3f00cec8aef5..826500bb2b1b 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -55,8 +55,10 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
lockdep_assert_held(&htt->tx_lock);
- ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
- tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack);
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
+ "htt tx completion msdu_id %u discard %d no_ack %d success %d\n",
+ tx_done->msdu_id, !!tx_done->discard,
+ !!tx_done->no_ack, !!tx_done->success);
if (tx_done->msdu_id >= htt->max_num_pending_tx) {
ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n",
@@ -97,6 +99,9 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
if (tx_done->no_ack)
info->flags &= ~IEEE80211_TX_STAT_ACK;
+ if (tx_done->success && (info->flags & IEEE80211_TX_CTL_NO_ACK))
+ info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+
ieee80211_tx_status(htt->ar->hw, msdu);
/* we do not own the msdu anymore */
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index c8b64e7a6089..47fe2e756bec 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -45,6 +45,10 @@ struct wmi_ops {
struct wmi_rdy_ev_arg *arg);
int (*pull_fw_stats)(struct ath10k *ar, struct sk_buff *skb,
struct ath10k_fw_stats *stats);
+ int (*pull_roam_ev)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_roam_ev_arg *arg);
+ int (*pull_wow_event)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_wow_ev_arg *arg);
struct sk_buff *(*gen_pdev_suspend)(struct ath10k *ar, u32 suspend_opt);
struct sk_buff *(*gen_pdev_resume)(struct ath10k *ar);
@@ -81,7 +85,8 @@ struct wmi_ops {
struct sk_buff *(*gen_vdev_wmm_conf)(struct ath10k *ar, u32 vdev_id,
const struct wmi_wmm_params_all_arg *arg);
struct sk_buff *(*gen_peer_create)(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN]);
+ const u8 peer_addr[ETH_ALEN],
+ enum wmi_peer_type peer_type);
struct sk_buff *(*gen_peer_delete)(struct ath10k *ar, u32 vdev_id,
const u8 peer_addr[ETH_ALEN]);
struct sk_buff *(*gen_peer_flush)(struct ath10k *ar, u32 vdev_id,
@@ -148,6 +153,27 @@ struct wmi_ops {
u32 num_ac);
struct sk_buff *(*gen_sta_keepalive)(struct ath10k *ar,
const struct wmi_sta_keepalive_arg *arg);
+ struct sk_buff *(*gen_wow_enable)(struct ath10k *ar);
+ struct sk_buff *(*gen_wow_add_wakeup_event)(struct ath10k *ar, u32 vdev_id,
+ enum wmi_wow_wakeup_event event,
+ u32 enable);
+ struct sk_buff *(*gen_wow_host_wakeup_ind)(struct ath10k *ar);
+ struct sk_buff *(*gen_wow_add_pattern)(struct ath10k *ar, u32 vdev_id,
+ u32 pattern_id,
+ const u8 *pattern,
+ const u8 *mask,
+ int pattern_len,
+ int pattern_offset);
+ struct sk_buff *(*gen_wow_del_pattern)(struct ath10k *ar, u32 vdev_id,
+ u32 pattern_id);
+ struct sk_buff *(*gen_update_fw_tdls_state)(struct ath10k *ar,
+ u32 vdev_id,
+ enum wmi_tdls_state state);
+ struct sk_buff *(*gen_tdls_peer_update)(struct ath10k *ar,
+ const struct wmi_tdls_peer_update_cmd_arg *arg,
+ const struct wmi_tdls_peer_capab_arg *cap,
+ const struct wmi_channel_arg *chan);
+ struct sk_buff *(*gen_adaptive_qcs)(struct ath10k *ar, bool enable);
};
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
@@ -274,6 +300,26 @@ ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
}
static inline int
+ath10k_wmi_pull_roam_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_roam_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_roam_ev)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_roam_ev(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_wow_event(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_wow_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_wow_event)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_wow_event(ar, skb, arg);
+}
+
+static inline int
ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
@@ -624,14 +670,15 @@ ath10k_wmi_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id,
static inline int
ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN])
+ const u8 peer_addr[ETH_ALEN],
+ enum wmi_peer_type peer_type)
{
struct sk_buff *skb;
if (!ar->wmi.ops->gen_peer_create)
return -EOPNOTSUPP;
- skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr);
+ skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr, peer_type);
if (IS_ERR(skb))
return PTR_ERR(skb);
@@ -1060,4 +1107,145 @@ ath10k_wmi_sta_keepalive(struct ath10k *ar,
return ath10k_wmi_cmd_send(ar, skb, cmd_id);
}
+static inline int
+ath10k_wmi_wow_enable(struct ath10k *ar)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_wow_enable)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_wow_enable(ar);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->wow_enable_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_wow_add_wakeup_event(struct ath10k *ar, u32 vdev_id,
+ enum wmi_wow_wakeup_event event,
+ u32 enable)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_wow_add_wakeup_event)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_wow_add_wakeup_event(ar, vdev_id, event, enable);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->wow_enable_disable_wake_event_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_wow_host_wakeup_ind(struct ath10k *ar)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_wow_host_wakeup_ind)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_wow_host_wakeup_ind(ar);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->wow_hostwakeup_from_sleep_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_wow_add_pattern(struct ath10k *ar, u32 vdev_id, u32 pattern_id,
+ const u8 *pattern, const u8 *mask,
+ int pattern_len, int pattern_offset)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_wow_add_pattern)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_wow_add_pattern(ar, vdev_id, pattern_id,
+ pattern, mask, pattern_len,
+ pattern_offset);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->wow_add_wake_pattern_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_wow_del_pattern(struct ath10k *ar, u32 vdev_id, u32 pattern_id)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_wow_del_pattern)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_wow_del_pattern(ar, vdev_id, pattern_id);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->wow_del_wake_pattern_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id,
+ enum wmi_tdls_state state)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_update_fw_tdls_state)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_update_fw_tdls_state(ar, vdev_id, state);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->tdls_set_state_cmdid);
+}
+
+static inline int
+ath10k_wmi_tdls_peer_update(struct ath10k *ar,
+ const struct wmi_tdls_peer_update_cmd_arg *arg,
+ const struct wmi_tdls_peer_capab_arg *cap,
+ const struct wmi_channel_arg *chan)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_tdls_peer_update)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_tdls_peer_update(ar, arg, cap, chan);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->tdls_peer_update_cmdid);
+}
+
+static inline int
+ath10k_wmi_adaptive_qcs(struct ath10k *ar, bool enable)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_adaptive_qcs)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_adaptive_qcs(ar, enable);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->adaptive_qcs_cmdid);
+}
+
#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index ee0c5f602e29..8fdba3865c96 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -16,10 +16,13 @@
*/
#include "core.h"
#include "debug.h"
+#include "mac.h"
#include "hw.h"
+#include "mac.h"
#include "wmi.h"
#include "wmi-ops.h"
#include "wmi-tlv.h"
+#include "p2p.h"
/***************/
/* TLV helpers */
@@ -31,9 +34,9 @@ struct wmi_tlv_policy {
static const struct wmi_tlv_policy wmi_tlv_policies[] = {
[WMI_TLV_TAG_ARRAY_BYTE]
- = { .min_len = sizeof(u8) },
+ = { .min_len = 0 },
[WMI_TLV_TAG_ARRAY_UINT32]
- = { .min_len = sizeof(u32) },
+ = { .min_len = 0 },
[WMI_TLV_TAG_STRUCT_SCAN_EVENT]
= { .min_len = sizeof(struct wmi_scan_event) },
[WMI_TLV_TAG_STRUCT_MGMT_RX_HDR]
@@ -62,6 +65,14 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = {
= { .min_len = sizeof(struct wmi_tlv_bcn_tx_status_ev) },
[WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT]
= { .min_len = sizeof(struct wmi_tlv_diag_data_ev) },
+ [WMI_TLV_TAG_STRUCT_P2P_NOA_EVENT]
+ = { .min_len = sizeof(struct wmi_tlv_p2p_noa_ev) },
+ [WMI_TLV_TAG_STRUCT_ROAM_EVENT]
+ = { .min_len = sizeof(struct wmi_tlv_roam_ev) },
+ [WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO]
+ = { .min_len = sizeof(struct wmi_tlv_wow_event_info) },
+ [WMI_TLV_TAG_STRUCT_TX_PAUSE_EVENT]
+ = { .min_len = sizeof(struct wmi_tlv_tx_pause_ev) },
};
static int
@@ -168,6 +179,7 @@ static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar,
{
const void **tb;
const struct wmi_tlv_bcn_tx_status_ev *ev;
+ struct ath10k_vif *arvif;
u32 vdev_id, tx_status;
int ret;
@@ -201,6 +213,10 @@ static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar,
break;
}
+ arvif = ath10k_get_arvif(ar, vdev_id);
+ if (arvif && arvif->is_up && arvif->vif->csa_active)
+ ieee80211_queue_work(ar->hw, &arvif->ap_csa_work);
+
kfree(tb);
return 0;
}
@@ -296,6 +312,83 @@ static int ath10k_wmi_tlv_event_diag(struct ath10k *ar,
return 0;
}
+static int ath10k_wmi_tlv_event_p2p_noa(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ const void **tb;
+ const struct wmi_tlv_p2p_noa_ev *ev;
+ const struct wmi_p2p_noa_info *noa;
+ int ret, vdev_id;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_P2P_NOA_EVENT];
+ noa = tb[WMI_TLV_TAG_STRUCT_P2P_NOA_INFO];
+
+ if (!ev || !noa) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ vdev_id = __le32_to_cpu(ev->vdev_id);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi tlv p2p noa vdev_id %i descriptors %hhu\n",
+ vdev_id, noa->num_descriptors);
+
+ ath10k_p2p_noa_update_by_vdev_id(ar, vdev_id, noa);
+ kfree(tb);
+ return 0;
+}
+
+static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ const void **tb;
+ const struct wmi_tlv_tx_pause_ev *ev;
+ int ret, vdev_id;
+ u32 pause_id, action, vdev_map, peer_id, tid_map;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_TX_PAUSE_EVENT];
+ if (!ev) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ pause_id = __le32_to_cpu(ev->pause_id);
+ action = __le32_to_cpu(ev->action);
+ vdev_map = __le32_to_cpu(ev->vdev_map);
+ peer_id = __le32_to_cpu(ev->peer_id);
+ tid_map = __le32_to_cpu(ev->tid_map);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi tlv tx pause pause_id %u action %u vdev_map 0x%08x peer_id %u tid_map 0x%08x\n",
+ pause_id, action, vdev_map, peer_id, tid_map);
+
+ for (vdev_id = 0; vdev_map; vdev_id++) {
+ if (!(vdev_map & BIT(vdev_id)))
+ continue;
+
+ vdev_map &= ~BIT(vdev_id);
+ ath10k_mac_handle_tx_pause(ar, vdev_id, pause_id, action);
+ }
+
+ kfree(tb);
+ return 0;
+}
+
/***********/
/* TLV ops */
/***********/
@@ -309,7 +402,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
- return;
+ goto out;
trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
@@ -417,11 +510,18 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_TLV_DIAG_EVENTID:
ath10k_wmi_tlv_event_diag(ar, skb);
break;
+ case WMI_TLV_P2P_NOA_EVENTID:
+ ath10k_wmi_tlv_event_p2p_noa(ar, skb);
+ break;
+ case WMI_TLV_TX_PAUSE_EVENTID:
+ ath10k_wmi_tlv_event_tx_pause(ar, skb);
+ break;
default:
ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
}
+out:
dev_kfree_skb(skb);
}
@@ -1012,6 +1112,65 @@ static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar,
return 0;
}
+static int ath10k_wmi_tlv_op_pull_roam_ev(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct wmi_roam_ev_arg *arg)
+{
+ const void **tb;
+ const struct wmi_tlv_roam_ev *ev;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_ROAM_EVENT];
+ if (!ev) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ arg->vdev_id = ev->vdev_id;
+ arg->reason = ev->reason;
+ arg->rssi = ev->rssi;
+
+ kfree(tb);
+ return 0;
+}
+
+static int
+ath10k_wmi_tlv_op_pull_wow_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_wow_ev_arg *arg)
+{
+ const void **tb;
+ const struct wmi_tlv_wow_event_info *ev;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO];
+ if (!ev) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ arg->vdev_id = __le32_to_cpu(ev->vdev_id);
+ arg->flag = __le32_to_cpu(ev->flag);
+ arg->wake_reason = __le32_to_cpu(ev->wake_reason);
+ arg->data_len = __le32_to_cpu(ev->data_len);
+
+ kfree(tb);
+ return 0;
+}
+
static struct sk_buff *
ath10k_wmi_tlv_op_gen_pdev_suspend(struct ath10k *ar, u32 opt)
{
@@ -1160,8 +1319,8 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS);
if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) {
- cfg->num_offload_peers = __cpu_to_le32(3);
- cfg->num_offload_reorder_bufs = __cpu_to_le32(3);
+ cfg->num_offload_peers = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
+ cfg->num_offload_reorder_bufs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
} else {
cfg->num_offload_peers = __cpu_to_le32(0);
cfg->num_offload_reorder_bufs = __cpu_to_le32(0);
@@ -1178,8 +1337,8 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
cfg->rx_timeout_pri[3] = __cpu_to_le32(0x28);
cfg->rx_decap_mode = __cpu_to_le32(1);
cfg->scan_max_pending_reqs = __cpu_to_le32(4);
- cfg->bmiss_offload_max_vdev = __cpu_to_le32(3);
- cfg->roam_offload_max_vdev = __cpu_to_le32(3);
+ cfg->bmiss_offload_max_vdev = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
+ cfg->roam_offload_max_vdev = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
cfg->roam_offload_max_ap_profiles = __cpu_to_le32(8);
cfg->num_mcast_groups = __cpu_to_le32(0);
cfg->num_mcast_table_elems = __cpu_to_le32(0);
@@ -1193,11 +1352,11 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
cfg->gtk_offload_max_vdev = __cpu_to_le32(2);
cfg->num_msdu_desc = __cpu_to_le32(TARGET_TLV_NUM_MSDU_DESC);
cfg->max_frag_entries = __cpu_to_le32(2);
- cfg->num_tdls_vdevs = __cpu_to_le32(1);
+ cfg->num_tdls_vdevs = __cpu_to_le32(TARGET_TLV_NUM_TDLS_VDEVS);
cfg->num_tdls_conn_table_entries = __cpu_to_le32(0x20);
cfg->beacon_tx_offload_max_vdev = __cpu_to_le32(2);
cfg->num_multicast_filter_entries = __cpu_to_le32(5);
- cfg->num_wow_filters = __cpu_to_le32(0x16);
+ cfg->num_wow_filters = __cpu_to_le32(ar->wow.max_num_patterns);
cfg->num_keep_alive_pattern = __cpu_to_le32(6);
cfg->keep_alive_pattern_size = __cpu_to_le32(0);
cfg->max_tdls_concurrent_sleep_sta = __cpu_to_le32(1);
@@ -1248,7 +1407,7 @@ ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar,
cmd = (void *)tlv->value;
ath10k_wmi_put_start_scan_common(&cmd->common, arg);
- cmd->burst_duration_ms = __cpu_to_le32(0);
+ cmd->burst_duration_ms = __cpu_to_le32(arg->burst_duration_ms);
cmd->num_channels = __cpu_to_le32(arg->n_channels);
cmd->num_ssids = __cpu_to_le32(arg->n_ssids);
cmd->num_bssids = __cpu_to_le32(arg->n_bssids);
@@ -1408,8 +1567,6 @@ ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar,
void *ptr;
u32 flags = 0;
- if (WARN_ON(arg->ssid && arg->ssid_len == 0))
- return ERR_PTR(-EINVAL);
if (WARN_ON(arg->hidden_ssid && !arg->ssid))
return ERR_PTR(-EINVAL);
if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))
@@ -1782,7 +1939,8 @@ ath10k_wmi_tlv_op_gen_sta_keepalive(struct ath10k *ar,
static struct sk_buff *
ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN])
+ const u8 peer_addr[ETH_ALEN],
+ enum wmi_peer_type peer_type)
{
struct wmi_tlv_peer_create_cmd *cmd;
struct wmi_tlv *tlv;
@@ -1797,7 +1955,7 @@ ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
tlv->len = __cpu_to_le16(sizeof(*cmd));
cmd = (void *)tlv->value;
cmd->vdev_id = __cpu_to_le32(vdev_id);
- cmd->peer_type = __cpu_to_le32(WMI_TLV_PEER_TYPE_DEFAULT); /* FIXME */
+ cmd->peer_type = __cpu_to_le32(peer_type);
ether_addr_copy(cmd->peer_addr.addr, peer_addr);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer create\n");
@@ -2027,7 +2185,7 @@ ath10k_wmi_tlv_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac,
if (!mac)
return ERR_PTR(-EINVAL);
- skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
if (!skb)
return ERR_PTR(-ENOMEM);
@@ -2485,6 +2643,387 @@ ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id,
return skb;
}
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id,
+ enum wmi_tdls_state state)
+{
+ struct wmi_tdls_set_state_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ void *ptr;
+ size_t len;
+ /* Set to options from wmi_tlv_tdls_options,
+ * for now none of them are enabled.
+ */
+ u32 options = 0;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_SET_STATE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->state = __cpu_to_le32(state);
+ cmd->notification_interval_ms = __cpu_to_le32(5000);
+ cmd->tx_discovery_threshold = __cpu_to_le32(100);
+ cmd->tx_teardown_threshold = __cpu_to_le32(5);
+ cmd->rssi_teardown_threshold = __cpu_to_le32(-75);
+ cmd->rssi_delta = __cpu_to_le32(-20);
+ cmd->tdls_options = __cpu_to_le32(options);
+ cmd->tdls_peer_traffic_ind_window = __cpu_to_le32(2);
+ cmd->tdls_peer_traffic_response_timeout_ms = __cpu_to_le32(5000);
+ cmd->tdls_puapsd_mask = __cpu_to_le32(0xf);
+ cmd->tdls_puapsd_inactivity_time_ms = __cpu_to_le32(0);
+ cmd->tdls_puapsd_rx_frame_threshold = __cpu_to_le32(10);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv update fw tdls state %d for vdev %i\n",
+ state, vdev_id);
+ return skb;
+}
+
+static u32 ath10k_wmi_tlv_prepare_peer_qos(u8 uapsd_queues, u8 sp)
+{
+ u32 peer_qos = 0;
+
+ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
+ peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VO;
+ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
+ peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_VI;
+ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
+ peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BK;
+ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
+ peer_qos |= WMI_TLV_TDLS_PEER_QOS_AC_BE;
+
+ peer_qos |= SM(sp, WMI_TLV_TDLS_PEER_SP);
+
+ return peer_qos;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_tdls_peer_update(struct ath10k *ar,
+ const struct wmi_tdls_peer_update_cmd_arg *arg,
+ const struct wmi_tdls_peer_capab_arg *cap,
+ const struct wmi_channel_arg *chan_arg)
+{
+ struct wmi_tdls_peer_update_cmd *cmd;
+ struct wmi_tdls_peer_capab *peer_cap;
+ struct wmi_channel *chan;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ u32 peer_qos;
+ void *ptr;
+ int len;
+ int i;
+
+ len = sizeof(*tlv) + sizeof(*cmd) +
+ sizeof(*tlv) + sizeof(*peer_cap) +
+ sizeof(*tlv) + cap->peer_chan_len * sizeof(*chan);
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_PEER_UPDATE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+ ether_addr_copy(cmd->peer_macaddr.addr, arg->addr);
+ cmd->peer_state = __cpu_to_le32(arg->peer_state);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_TDLS_PEER_CAPABILITIES);
+ tlv->len = __cpu_to_le16(sizeof(*peer_cap));
+ peer_cap = (void *)tlv->value;
+ peer_qos = ath10k_wmi_tlv_prepare_peer_qos(cap->peer_uapsd_queues,
+ cap->peer_max_sp);
+ peer_cap->peer_qos = __cpu_to_le32(peer_qos);
+ peer_cap->buff_sta_support = __cpu_to_le32(cap->buff_sta_support);
+ peer_cap->off_chan_support = __cpu_to_le32(cap->off_chan_support);
+ peer_cap->peer_curr_operclass = __cpu_to_le32(cap->peer_curr_operclass);
+ peer_cap->self_curr_operclass = __cpu_to_le32(cap->self_curr_operclass);
+ peer_cap->peer_chan_len = __cpu_to_le32(cap->peer_chan_len);
+ peer_cap->peer_operclass_len = __cpu_to_le32(cap->peer_operclass_len);
+
+ for (i = 0; i < WMI_TDLS_MAX_SUPP_OPER_CLASSES; i++)
+ peer_cap->peer_operclass[i] = cap->peer_operclass[i];
+
+ peer_cap->is_peer_responder = __cpu_to_le32(cap->is_peer_responder);
+ peer_cap->pref_offchan_num = __cpu_to_le32(cap->pref_offchan_num);
+ peer_cap->pref_offchan_bw = __cpu_to_le32(cap->pref_offchan_bw);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*peer_cap);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(cap->peer_chan_len * sizeof(*chan));
+
+ ptr += sizeof(*tlv);
+
+ for (i = 0; i < cap->peer_chan_len; i++) {
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
+ tlv->len = __cpu_to_le16(sizeof(*chan));
+ chan = (void *)tlv->value;
+ ath10k_wmi_put_wmi_channel(chan, &chan_arg[i]);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*chan);
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi tlv tdls peer update vdev %i state %d n_chans %u\n",
+ arg->vdev_id, arg->peer_state, cap->peer_chan_len);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_wow_enable(struct ath10k *ar)
+{
+ struct wmi_tlv_wow_enable_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (struct wmi_tlv *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WOW_ENABLE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ cmd->enable = __cpu_to_le32(1);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv wow enable\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_wow_add_wakeup_event(struct ath10k *ar,
+ u32 vdev_id,
+ enum wmi_wow_wakeup_event event,
+ u32 enable)
+{
+ struct wmi_tlv_wow_add_del_event_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (struct wmi_tlv *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WOW_ADD_DEL_EVT_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->is_add = __cpu_to_le32(enable);
+ cmd->event_bitmap = __cpu_to_le32(1 << event);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv wow add wakeup event %s enable %d vdev_id %d\n",
+ wow_wakeup_event(event), enable, vdev_id);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_gen_wow_host_wakeup_ind(struct ath10k *ar)
+{
+ struct wmi_tlv_wow_host_wakeup_ind *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (struct wmi_tlv *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WOW_HOSTWAKEUP_FROM_SLEEP_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv wow host wakeup ind\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_wow_add_pattern(struct ath10k *ar, u32 vdev_id,
+ u32 pattern_id, const u8 *pattern,
+ const u8 *bitmask, int pattern_len,
+ int pattern_offset)
+{
+ struct wmi_tlv_wow_add_pattern_cmd *cmd;
+ struct wmi_tlv_wow_bitmap_pattern *bitmap;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ void *ptr;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd) +
+ sizeof(*tlv) + /* array struct */
+ sizeof(*tlv) + sizeof(*bitmap) + /* bitmap */
+ sizeof(*tlv) + /* empty ipv4 sync */
+ sizeof(*tlv) + /* empty ipv6 sync */
+ sizeof(*tlv) + /* empty magic */
+ sizeof(*tlv) + /* empty info timeout */
+ sizeof(*tlv) + sizeof(u32); /* ratelimit interval */
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ /* cmd */
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WOW_ADD_PATTERN_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->pattern_id = __cpu_to_le32(pattern_id);
+ cmd->pattern_type = __cpu_to_le32(WOW_BITMAP_PATTERN);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ /* bitmap */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(sizeof(*tlv) + sizeof(*bitmap));
+
+ ptr += sizeof(*tlv);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WOW_BITMAP_PATTERN_T);
+ tlv->len = __cpu_to_le16(sizeof(*bitmap));
+ bitmap = (void *)tlv->value;
+
+ memcpy(bitmap->patternbuf, pattern, pattern_len);
+ memcpy(bitmap->bitmaskbuf, bitmask, pattern_len);
+ bitmap->pattern_offset = __cpu_to_le32(pattern_offset);
+ bitmap->pattern_len = __cpu_to_le32(pattern_len);
+ bitmap->bitmask_len = __cpu_to_le32(pattern_len);
+ bitmap->pattern_id = __cpu_to_le32(pattern_id);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*bitmap);
+
+ /* ipv4 sync */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(0);
+
+ ptr += sizeof(*tlv);
+
+ /* ipv6 sync */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(0);
+
+ ptr += sizeof(*tlv);
+
+ /* magic */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(0);
+
+ ptr += sizeof(*tlv);
+
+ /* pattern info timeout */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32);
+ tlv->len = __cpu_to_le16(0);
+
+ ptr += sizeof(*tlv);
+
+ /* ratelimit interval */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32);
+ tlv->len = __cpu_to_le16(sizeof(u32));
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv wow add pattern vdev_id %d pattern_id %d, pattern_offset %d\n",
+ vdev_id, pattern_id, pattern_offset);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_wow_del_pattern(struct ath10k *ar, u32 vdev_id,
+ u32 pattern_id)
+{
+ struct wmi_tlv_wow_del_pattern_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (struct wmi_tlv *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WOW_DEL_PATTERN_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->pattern_id = __cpu_to_le32(pattern_id);
+ cmd->pattern_type = __cpu_to_le32(WOW_BITMAP_PATTERN);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv wow del pattern vdev_id %d pattern_id %d\n",
+ vdev_id, pattern_id);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_adaptive_qcs(struct ath10k *ar, bool enable)
+{
+ struct wmi_tlv_adaptive_qcs *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ void *ptr;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_RESMGR_ADAPTIVE_OCS_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->enable = __cpu_to_le32(enable ? 1 : 0);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv adaptive qcs %d\n", enable);
+ return skb;
+}
+
/****************/
/* TLV mappings */
/****************/
@@ -2609,6 +3148,9 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = {
.gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID,
.pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED,
.vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID,
+ .tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID,
+ .tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_CMDID,
+ .adaptive_qcs_cmdid = WMI_TLV_RESMGR_ADAPTIVE_OCS_CMDID,
};
static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = {
@@ -2736,6 +3278,8 @@ static const struct wmi_ops wmi_tlv_ops = {
.pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev,
.pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev,
.pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats,
+ .pull_roam_ev = ath10k_wmi_tlv_op_pull_roam_ev,
+ .pull_wow_event = ath10k_wmi_tlv_op_pull_wow_ev,
.gen_pdev_suspend = ath10k_wmi_tlv_op_gen_pdev_suspend,
.gen_pdev_resume = ath10k_wmi_tlv_op_gen_pdev_resume,
@@ -2781,6 +3325,14 @@ static const struct wmi_ops wmi_tlv_ops = {
.gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie,
.gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd,
.gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive,
+ .gen_wow_enable = ath10k_wmi_tlv_op_gen_wow_enable,
+ .gen_wow_add_wakeup_event = ath10k_wmi_tlv_op_gen_wow_add_wakeup_event,
+ .gen_wow_host_wakeup_ind = ath10k_wmi_tlv_gen_wow_host_wakeup_ind,
+ .gen_wow_add_pattern = ath10k_wmi_tlv_op_gen_wow_add_pattern,
+ .gen_wow_del_pattern = ath10k_wmi_tlv_op_gen_wow_del_pattern,
+ .gen_update_fw_tdls_state = ath10k_wmi_tlv_op_gen_update_fw_tdls_state,
+ .gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update,
+ .gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs,
};
/************/
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index a6c8280cc4b1..ad655c44afdb 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -1454,6 +1454,174 @@ struct wmi_tlv_stats_ev {
__le32 num_chan_stats;
} __packed;
+struct wmi_tlv_p2p_noa_ev {
+ __le32 vdev_id;
+} __packed;
+
+struct wmi_tlv_roam_ev {
+ __le32 vdev_id;
+ __le32 reason;
+ __le32 rssi;
+} __packed;
+
+struct wmi_tlv_wow_add_del_event_cmd {
+ __le32 vdev_id;
+ __le32 is_add;
+ __le32 event_bitmap;
+} __packed;
+
+struct wmi_tlv_wow_enable_cmd {
+ __le32 enable;
+} __packed;
+
+struct wmi_tlv_wow_host_wakeup_ind {
+ __le32 reserved;
+} __packed;
+
+struct wmi_tlv_wow_event_info {
+ __le32 vdev_id;
+ __le32 flag;
+ __le32 wake_reason;
+ __le32 data_len;
+} __packed;
+
+enum wmi_tlv_pattern_type {
+ WOW_PATTERN_MIN = 0,
+ WOW_BITMAP_PATTERN = WOW_PATTERN_MIN,
+ WOW_IPV4_SYNC_PATTERN,
+ WOW_IPV6_SYNC_PATTERN,
+ WOW_WILD_CARD_PATTERN,
+ WOW_TIMER_PATTERN,
+ WOW_MAGIC_PATTERN,
+ WOW_IPV6_RA_PATTERN,
+ WOW_IOAC_PKT_PATTERN,
+ WOW_IOAC_TMR_PATTERN,
+ WOW_PATTERN_MAX
+};
+
+#define WOW_DEFAULT_BITMAP_PATTERN_SIZE 148
+#define WOW_DEFAULT_BITMASK_SIZE 148
+
+struct wmi_tlv_wow_bitmap_pattern {
+ u8 patternbuf[WOW_DEFAULT_BITMAP_PATTERN_SIZE];
+ u8 bitmaskbuf[WOW_DEFAULT_BITMASK_SIZE];
+ __le32 pattern_offset;
+ __le32 pattern_len;
+ __le32 bitmask_len;
+ __le32 pattern_id;
+} __packed;
+
+struct wmi_tlv_wow_add_pattern_cmd {
+ __le32 vdev_id;
+ __le32 pattern_id;
+ __le32 pattern_type;
+} __packed;
+
+struct wmi_tlv_wow_del_pattern_cmd {
+ __le32 vdev_id;
+ __le32 pattern_id;
+ __le32 pattern_type;
+} __packed;
+
+/* TDLS Options */
+enum wmi_tlv_tdls_options {
+ WMI_TLV_TDLS_OFFCHAN_EN = BIT(0),
+ WMI_TLV_TDLS_BUFFER_STA_EN = BIT(1),
+ WMI_TLV_TDLS_SLEEP_STA_EN = BIT(2),
+};
+
+struct wmi_tdls_set_state_cmd {
+ __le32 vdev_id;
+ __le32 state;
+ __le32 notification_interval_ms;
+ __le32 tx_discovery_threshold;
+ __le32 tx_teardown_threshold;
+ __le32 rssi_teardown_threshold;
+ __le32 rssi_delta;
+ __le32 tdls_options;
+ __le32 tdls_peer_traffic_ind_window;
+ __le32 tdls_peer_traffic_response_timeout_ms;
+ __le32 tdls_puapsd_mask;
+ __le32 tdls_puapsd_inactivity_time_ms;
+ __le32 tdls_puapsd_rx_frame_threshold;
+} __packed;
+
+struct wmi_tdls_peer_update_cmd {
+ __le32 vdev_id;
+ struct wmi_mac_addr peer_macaddr;
+ __le32 peer_state;
+} __packed;
+
+enum {
+ WMI_TLV_TDLS_PEER_QOS_AC_VO = BIT(0),
+ WMI_TLV_TDLS_PEER_QOS_AC_VI = BIT(1),
+ WMI_TLV_TDLS_PEER_QOS_AC_BK = BIT(2),
+ WMI_TLV_TDLS_PEER_QOS_AC_BE = BIT(3),
+};
+
+#define WMI_TLV_TDLS_PEER_SP_MASK 0x60
+#define WMI_TLV_TDLS_PEER_SP_LSB 5
+
+struct wmi_tdls_peer_capab {
+ __le32 peer_qos;
+ __le32 buff_sta_support;
+ __le32 off_chan_support;
+ __le32 peer_curr_operclass;
+ __le32 self_curr_operclass;
+ __le32 peer_chan_len;
+ __le32 peer_operclass_len;
+ u8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES];
+ __le32 is_peer_responder;
+ __le32 pref_offchan_num;
+ __le32 pref_offchan_bw;
+} __packed;
+
+struct wmi_tlv_adaptive_qcs {
+ __le32 enable;
+} __packed;
+
+/**
+ * wmi_tlv_tx_pause_id - firmware tx queue pause reason types
+ *
+ * @WMI_TLV_TX_PAUSE_ID_MCC: used for by multi-channel firmware scheduler.
+ * Only vdev_map is valid.
+ * @WMI_TLV_TX_PAUSE_ID_AP_PEER_PS: peer in AP mode is asleep.
+ * Only peer_id is valid.
+ * @WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD: Only peer_id and tid_map are valid.
+ * @WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA: Only vdev_map is valid.
+ * @WMI_TLV_TX_PAUSE_ID_P2P_GO_PS: Only vdev_map is valid.
+ * @WMI_TLV_TX_PAUSE_ID_STA_ADD_BA: Only peer_id and tid_map are valid.
+ * @WMI_TLV_TX_PAUSE_ID_AP_PS: When all peers are asleep in AP mode. Only
+ * vdev_map is valid.
+ * @WMI_TLV_TX_PAUSE_ID_IBSS_PS: When all peers are asleep in IBSS mode. Only
+ * vdev_map is valid.
+ * @WMI_TLV_TX_PAUSE_ID_HOST: Host itself requested tx pause.
+ */
+enum wmi_tlv_tx_pause_id {
+ WMI_TLV_TX_PAUSE_ID_MCC = 1,
+ WMI_TLV_TX_PAUSE_ID_AP_PEER_PS = 2,
+ WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD = 3,
+ WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA = 4,
+ WMI_TLV_TX_PAUSE_ID_P2P_GO_PS = 5,
+ WMI_TLV_TX_PAUSE_ID_STA_ADD_BA = 6,
+ WMI_TLV_TX_PAUSE_ID_AP_PS = 7,
+ WMI_TLV_TX_PAUSE_ID_IBSS_PS = 8,
+ WMI_TLV_TX_PAUSE_ID_HOST = 21,
+};
+
+enum wmi_tlv_tx_pause_action {
+ WMI_TLV_TX_PAUSE_ACTION_STOP,
+ WMI_TLV_TX_PAUSE_ACTION_WAKE,
+};
+
+struct wmi_tlv_tx_pause_ev {
+ __le32 pause_id;
+ __le32 action;
+ __le32 vdev_map;
+ __le32 peer_id;
+ __le32 tid_map;
+} __packed;
+
void ath10k_wmi_tlv_attach(struct ath10k *ar);
#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c7ea77edce24..6c046c244705 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -26,6 +26,8 @@
#include "mac.h"
#include "testmode.h"
#include "wmi-ops.h"
+#include "p2p.h"
+#include "hw.h"
/* MAIN WMI cmd track */
static struct wmi_cmd_map wmi_cmd_map = {
@@ -884,20 +886,24 @@ void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
{
- int ret;
+ unsigned long time_left;
- ret = wait_for_completion_timeout(&ar->wmi.service_ready,
- WMI_SERVICE_READY_TIMEOUT_HZ);
- return ret;
+ time_left = wait_for_completion_timeout(&ar->wmi.service_ready,
+ WMI_SERVICE_READY_TIMEOUT_HZ);
+ if (!time_left)
+ return -ETIMEDOUT;
+ return 0;
}
int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar)
{
- int ret;
+ unsigned long time_left;
- ret = wait_for_completion_timeout(&ar->wmi.unified_ready,
- WMI_UNIFIED_READY_TIMEOUT_HZ);
- return ret;
+ time_left = wait_for_completion_timeout(&ar->wmi.unified_ready,
+ WMI_UNIFIED_READY_TIMEOUT_HZ);
+ if (!time_left)
+ return -ETIMEDOUT;
+ return 0;
}
struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len)
@@ -1351,63 +1357,6 @@ static inline enum ieee80211_band phy_mode_to_band(u32 phy_mode)
return band;
}
-static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band)
-{
- u8 rate_idx = 0;
-
- /* rate in Kbps */
- switch (rate) {
- case 1000:
- rate_idx = 0;
- break;
- case 2000:
- rate_idx = 1;
- break;
- case 5500:
- rate_idx = 2;
- break;
- case 11000:
- rate_idx = 3;
- break;
- case 6000:
- rate_idx = 4;
- break;
- case 9000:
- rate_idx = 5;
- break;
- case 12000:
- rate_idx = 6;
- break;
- case 18000:
- rate_idx = 7;
- break;
- case 24000:
- rate_idx = 8;
- break;
- case 36000:
- rate_idx = 9;
- break;
- case 48000:
- rate_idx = 10;
- break;
- case 54000:
- rate_idx = 11;
- break;
- default:
- break;
- }
-
- if (band == IEEE80211_BAND_5GHZ) {
- if (rate_idx > 3)
- /* Omit CCK rates */
- rate_idx -= 4;
- else
- rate_idx = 0;
- }
-
- return rate_idx;
-}
-
/* If keys are configured, HW decrypts all frames
* with protected bit set. Mark such frames as decrypted.
*/
@@ -1489,6 +1438,7 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
struct wmi_mgmt_rx_ev_arg arg = {};
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr;
+ struct ieee80211_supported_band *sband;
u32 rx_status;
u32 channel;
u32 phy_mode;
@@ -1501,6 +1451,7 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
ret = ath10k_wmi_pull_mgmt_rx(ar, skb, &arg);
if (ret) {
ath10k_warn(ar, "failed to parse mgmt rx event: %d\n", ret);
+ dev_kfree_skb(skb);
return ret;
}
@@ -1559,9 +1510,11 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
if (phy_mode == MODE_11B && status->band == IEEE80211_BAND_5GHZ)
ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
+ sband = &ar->mac.sbands[status->band];
+
status->freq = ieee80211_channel_to_frequency(channel, status->band);
status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR;
- status->rate_idx = get_rate_idx(rate, status->band);
+ status->rate_idx = ath10k_mac_bitrate_to_idx(sband, rate / 100);
hdr = (struct ieee80211_hdr *)skb->data;
fc = le16_to_cpu(hdr->frame_control);
@@ -1585,6 +1538,9 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
}
}
+ if (ieee80211_is_beacon(hdr->frame_control))
+ ath10k_mac_handle_beacon(ar, skb);
+
ath10k_dbg(ar, ATH10K_DBG_MGMT,
"event mgmt rx skb %p len %d ftype %02x stype %02x\n",
skb, skb->len,
@@ -1682,20 +1638,22 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
}
if (cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) {
- /* During scanning chan info is reported twice for each
- * visited channel. The reported cycle count is global
- * and per-channel cycle count must be calculated */
-
- cycle_count -= ar->survey_last_cycle_count;
- rx_clear_count -= ar->survey_last_rx_clear_count;
-
- survey = &ar->survey[idx];
- 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_TIME |
- SURVEY_INFO_TIME_RX |
- SURVEY_INFO_NOISE_DBM;
+ if (ar->ch_info_can_report_survey) {
+ survey = &ar->survey[idx];
+ survey->noise = noise_floor;
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+
+ ath10k_hw_fill_survey_time(ar,
+ survey,
+ cycle_count,
+ rx_clear_count,
+ ar->survey_last_cycle_count,
+ ar->survey_last_rx_clear_count);
+ }
+
+ ar->ch_info_can_report_survey = false;
+ } else {
+ ar->ch_info_can_report_survey = true;
}
ar->survey_last_rx_clear_count = rx_clear_count;
@@ -2276,109 +2234,25 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
tim->bitmap_ctrl, pvm_len);
}
-static void ath10k_p2p_fill_noa_ie(u8 *data, u32 len,
- const struct wmi_p2p_noa_info *noa)
-{
- struct ieee80211_p2p_noa_attr *noa_attr;
- u8 ctwindow_oppps = noa->ctwindow_oppps;
- u8 ctwindow = ctwindow_oppps >> WMI_P2P_OPPPS_CTWINDOW_OFFSET;
- bool oppps = !!(ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT);
- __le16 *noa_attr_len;
- u16 attr_len;
- u8 noa_descriptors = noa->num_descriptors;
- int i;
-
- /* P2P IE */
- data[0] = WLAN_EID_VENDOR_SPECIFIC;
- data[1] = len - 2;
- data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
- data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
- data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
- data[5] = WLAN_OUI_TYPE_WFA_P2P;
-
- /* NOA ATTR */
- data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE;
- noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */
- noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9];
-
- noa_attr->index = noa->index;
- noa_attr->oppps_ctwindow = ctwindow;
- if (oppps)
- noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT;
-
- for (i = 0; i < noa_descriptors; i++) {
- noa_attr->desc[i].count =
- __le32_to_cpu(noa->descriptors[i].type_count);
- noa_attr->desc[i].duration = noa->descriptors[i].duration;
- noa_attr->desc[i].interval = noa->descriptors[i].interval;
- noa_attr->desc[i].start_time = noa->descriptors[i].start_time;
- }
-
- attr_len = 2; /* index + oppps_ctwindow */
- attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
- *noa_attr_len = __cpu_to_le16(attr_len);
-}
-
-static u32 ath10k_p2p_calc_noa_ie_len(const struct wmi_p2p_noa_info *noa)
-{
- u32 len = 0;
- u8 noa_descriptors = noa->num_descriptors;
- u8 opp_ps_info = noa->ctwindow_oppps;
- bool opps_enabled = !!(opp_ps_info & WMI_P2P_OPPPS_ENABLE_BIT);
-
- if (!noa_descriptors && !opps_enabled)
- return len;
-
- len += 1 + 1 + 4; /* EID + len + OUI */
- len += 1 + 2; /* noa attr + attr len */
- len += 1 + 1; /* index + oppps_ctwindow */
- len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
-
- return len;
-}
-
static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif,
struct sk_buff *bcn,
const struct wmi_p2p_noa_info *noa)
{
- u8 *new_data, *old_data = arvif->u.ap.noa_data;
- u32 new_len;
-
if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
return;
ath10k_dbg(ar, ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
- if (noa->changed & WMI_P2P_NOA_CHANGED_BIT) {
- new_len = ath10k_p2p_calc_noa_ie_len(noa);
- if (!new_len)
- goto cleanup;
-
- new_data = kmalloc(new_len, GFP_ATOMIC);
- if (!new_data)
- goto cleanup;
-
- ath10k_p2p_fill_noa_ie(new_data, new_len, noa);
- spin_lock_bh(&ar->data_lock);
- arvif->u.ap.noa_data = new_data;
- arvif->u.ap.noa_len = new_len;
- spin_unlock_bh(&ar->data_lock);
- kfree(old_data);
- }
+ if (noa->changed & WMI_P2P_NOA_CHANGED_BIT)
+ ath10k_p2p_noa_update(arvif, noa);
if (arvif->u.ap.noa_data)
if (!pskb_expand_head(bcn, 0, arvif->u.ap.noa_len, GFP_ATOMIC))
memcpy(skb_put(bcn, arvif->u.ap.noa_len),
arvif->u.ap.noa_data,
arvif->u.ap.noa_len);
- return;
-cleanup:
- spin_lock_bh(&ar->data_lock);
- arvif->u.ap.noa_data = NULL;
- arvif->u.ap.noa_len = 0;
- spin_unlock_bh(&ar->data_lock);
- kfree(old_data);
+ return;
}
static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb,
@@ -2555,6 +2429,7 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
u64 tsf)
{
u32 reg0, reg1, tsf32l;
+ struct ieee80211_channel *ch;
struct pulse_event pe;
u64 tsf64;
u8 rssi, width;
@@ -2583,6 +2458,15 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
if (!ar->dfs_detector)
return;
+ spin_lock_bh(&ar->data_lock);
+ ch = ar->rx_channel;
+ spin_unlock_bh(&ar->data_lock);
+
+ if (!ch) {
+ ath10k_warn(ar, "failed to derive channel for radar pulse, treating as radar\n");
+ goto radar_detected;
+ }
+
/* report event to DFS pattern detector */
tsf32l = __le32_to_cpu(phyerr->tsf_timestamp);
tsf64 = tsf & (~0xFFFFFFFFULL);
@@ -2598,10 +2482,10 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
rssi = 0;
pe.ts = tsf64;
- pe.freq = ar->hw->conf.chandef.chan->center_freq;
+ pe.freq = ch->center_freq;
pe.width = width;
pe.rssi = rssi;
-
+ pe.chirp = (MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP) != 0);
ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n",
pe.freq, pe.width, pe.rssi, pe.ts);
@@ -2614,6 +2498,7 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
return;
}
+radar_detected:
ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n");
ATH10K_DFS_STAT_INC(ar, radar_detected);
@@ -2872,7 +2757,43 @@ void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
{
- ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
+ struct wmi_roam_ev_arg arg = {};
+ int ret;
+ u32 vdev_id;
+ u32 reason;
+ s32 rssi;
+
+ ret = ath10k_wmi_pull_roam_ev(ar, skb, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse roam event: %d\n", ret);
+ return;
+ }
+
+ vdev_id = __le32_to_cpu(arg.vdev_id);
+ reason = __le32_to_cpu(arg.reason);
+ rssi = __le32_to_cpu(arg.rssi);
+ rssi += WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi roam event vdev %u reason 0x%08x rssi %d\n",
+ vdev_id, reason, rssi);
+
+ if (reason >= WMI_ROAM_REASON_MAX)
+ ath10k_warn(ar, "ignoring unknown roam event reason %d on vdev %i\n",
+ reason, vdev_id);
+
+ switch (reason) {
+ case WMI_ROAM_REASON_BEACON_MISS:
+ ath10k_mac_handle_beacon_miss(ar, vdev_id);
+ break;
+ case WMI_ROAM_REASON_BETTER_AP:
+ case WMI_ROAM_REASON_LOW_RSSI:
+ case WMI_ROAM_REASON_SUITABLE_AP_FOUND:
+ case WMI_ROAM_REASON_HO_FAILED:
+ ath10k_warn(ar, "ignoring not implemented roam event reason %d on vdev %i\n",
+ reason, vdev_id);
+ break;
+ }
}
void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb)
@@ -2942,7 +2863,19 @@ void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb)
void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb)
{
- ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
+ struct wmi_wow_ev_arg ev = {};
+ int ret;
+
+ complete(&ar->wow.wakeup_completed);
+
+ ret = ath10k_wmi_pull_wow_event(ar, skb, &ev);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse wow wakeup event: %d\n", ret);
+ return;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wow wakeup host reason %s\n",
+ wow_reason(ev.wake_reason));
}
void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb)
@@ -3231,6 +3164,21 @@ static int ath10k_wmi_op_pull_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
return 0;
}
+static int ath10k_wmi_op_pull_roam_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_roam_ev_arg *arg)
+{
+ struct wmi_roam_ev *ev = (void *)skb->data;
+
+ if (skb->len < sizeof(*ev))
+ return -EPROTO;
+
+ skb_pull(skb, sizeof(*ev));
+ arg->vdev_id = ev->vdev_id;
+ arg->reason = ev->reason;
+
+ return 0;
+}
+
int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_rdy_ev_arg arg = {};
@@ -3275,7 +3223,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
- return;
+ goto out;
trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
@@ -3379,6 +3327,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
break;
}
+out:
dev_kfree_skb(skb);
}
@@ -3392,7 +3341,7 @@ static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
- return;
+ goto out;
trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
@@ -3515,7 +3464,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
- return;
+ goto out;
trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
@@ -3623,6 +3572,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
break;
}
+out:
dev_kfree_skb(skb);
}
@@ -3989,6 +3939,8 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
cmd = (struct wmi_init_cmd_10_2 *)buf->data;
features = WMI_10_2_RX_BATCH_MODE;
+ if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map))
+ features |= WMI_10_2_COEX_GPIO;
cmd->resource_config.feature_mask = __cpu_to_le32(features);
memcpy(&cmd->resource_config.common, &config, sizeof(config));
@@ -4315,8 +4267,6 @@ ath10k_wmi_op_gen_vdev_start(struct ath10k *ar,
const char *cmdname;
u32 flags = 0;
- if (WARN_ON(arg->ssid && arg->ssid_len == 0))
- return ERR_PTR(-EINVAL);
if (WARN_ON(arg->hidden_ssid && !arg->ssid))
return ERR_PTR(-EINVAL);
if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))
@@ -4539,7 +4489,8 @@ ath10k_wmi_op_gen_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id,
static struct sk_buff *
ath10k_wmi_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN])
+ const u8 peer_addr[ETH_ALEN],
+ enum wmi_peer_type peer_type)
{
struct wmi_peer_create_cmd *cmd;
struct sk_buff *skb;
@@ -5223,6 +5174,7 @@ static const struct wmi_ops wmi_ops = {
.pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev,
.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
.pull_fw_stats = ath10k_wmi_main_op_pull_fw_stats,
+ .pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
@@ -5268,6 +5220,7 @@ static const struct wmi_ops wmi_ops = {
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
+ /* .gen_adaptive_qcs not implemented */
};
static const struct wmi_ops wmi_10_1_ops = {
@@ -5290,6 +5243,7 @@ static const struct wmi_ops wmi_10_1_ops = {
.pull_swba = ath10k_wmi_op_pull_swba_ev,
.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
+ .pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
@@ -5330,6 +5284,7 @@ static const struct wmi_ops wmi_10_1_ops = {
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
+ /* .gen_adaptive_qcs not implemented */
};
static const struct wmi_ops wmi_10_2_ops = {
@@ -5353,6 +5308,7 @@ static const struct wmi_ops wmi_10_2_ops = {
.pull_swba = ath10k_wmi_op_pull_swba_ev,
.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
+ .pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
@@ -5413,6 +5369,7 @@ static const struct wmi_ops wmi_10_2_4_ops = {
.pull_swba = ath10k_wmi_op_pull_swba_ev,
.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
+ .pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
.gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
@@ -5452,6 +5409,7 @@ static const struct wmi_ops wmi_10_2_4_ops = {
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
+ /* .gen_adaptive_qcs not implemented */
};
int ath10k_wmi_attach(struct ath10k *ar)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index adf935bf0580..cf44a3d080a3 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -148,6 +148,8 @@ enum wmi_service {
WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
WMI_SERVICE_MDNS_OFFLOAD,
WMI_SERVICE_SAP_AUTH_OFFLOAD,
+ WMI_SERVICE_ATF,
+ WMI_SERVICE_COEX_GPIO,
/* keep last */
WMI_SERVICE_MAX,
@@ -177,6 +179,8 @@ enum wmi_10x_service {
WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
WMI_10X_SERVICE_FORCE_FW_HANG,
WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+ WMI_10X_SERVICE_ATF,
+ WMI_10X_SERVICE_COEX_GPIO,
};
enum wmi_main_service {
@@ -293,6 +297,8 @@ static inline char *wmi_service_name(int service_id)
SVCSTR(WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT);
SVCSTR(WMI_SERVICE_MDNS_OFFLOAD);
SVCSTR(WMI_SERVICE_SAP_AUTH_OFFLOAD);
+ SVCSTR(WMI_SERVICE_ATF);
+ SVCSTR(WMI_SERVICE_COEX_GPIO);
default:
return NULL;
}
@@ -356,6 +362,10 @@ static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out,
WMI_SERVICE_FORCE_FW_HANG, len);
SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, len);
+ SVCMAP(WMI_10X_SERVICE_ATF,
+ WMI_SERVICE_ATF, len);
+ SVCMAP(WMI_10X_SERVICE_COEX_GPIO,
+ WMI_SERVICE_COEX_GPIO, len);
}
static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out,
@@ -552,6 +562,9 @@ struct wmi_cmd_map {
u32 gpio_output_cmdid;
u32 pdev_get_temperature_cmdid;
u32 vdev_set_wmm_params_cmdid;
+ u32 tdls_set_state_cmdid;
+ u32 tdls_peer_update_cmdid;
+ u32 adaptive_qcs_cmdid;
};
/*
@@ -1952,6 +1965,7 @@ struct wmi_resource_config_10x {
enum wmi_10_2_feature_mask {
WMI_10_2_RX_BATCH_MODE = BIT(0),
WMI_10_2_ATF_CONFIG = BIT(1),
+ WMI_10_2_COEX_GPIO = BIT(3),
};
struct wmi_resource_config_10_2 {
@@ -2166,6 +2180,7 @@ struct wmi_start_scan_arg {
u32 max_scan_time;
u32 probe_delay;
u32 scan_ctrl_flags;
+ u32 burst_duration_ms;
u32 ie_len;
u32 n_channels;
@@ -4333,6 +4348,12 @@ struct wmi_peer_create_cmd {
struct wmi_mac_addr peer_macaddr;
} __packed;
+enum wmi_peer_type {
+ WMI_PEER_TYPE_DEFAULT = 0,
+ WMI_PEER_TYPE_BSS = 1,
+ WMI_PEER_TYPE_TDLS = 2,
+};
+
struct wmi_peer_delete_cmd {
__le32 vdev_id;
struct wmi_mac_addr peer_macaddr;
@@ -4645,9 +4666,6 @@ struct wmi_peer_sta_kickout_event {
#define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0)
-/* FIXME: empirically extrapolated */
-#define WMI_CHAN_INFO_MSEC(x) ((x) / 76595)
-
/* Beacon filter wmi command info */
#define BCN_FLT_MAX_SUPPORTED_IES 256
#define BCN_FLT_MAX_ELEMS_IE_LIST (BCN_FLT_MAX_SUPPORTED_IES / 32)
@@ -4769,6 +4787,22 @@ struct wmi_dbglog_cfg_cmd {
__le32 config_valid;
} __packed;
+enum wmi_roam_reason {
+ WMI_ROAM_REASON_BETTER_AP = 1,
+ WMI_ROAM_REASON_BEACON_MISS = 2,
+ WMI_ROAM_REASON_LOW_RSSI = 3,
+ WMI_ROAM_REASON_SUITABLE_AP_FOUND = 4,
+ WMI_ROAM_REASON_HO_FAILED = 5,
+
+ /* keep last */
+ WMI_ROAM_REASON_MAX,
+};
+
+struct wmi_roam_ev {
+ __le32 vdev_id;
+ __le32 reason;
+} __packed;
+
#define ATH10K_FRAGMT_THRESHOLD_MIN 540
#define ATH10K_FRAGMT_THRESHOLD_MAX 2346
@@ -4857,11 +4891,200 @@ struct wmi_rdy_ev_arg {
const u8 *mac_addr;
};
+struct wmi_roam_ev_arg {
+ __le32 vdev_id;
+ __le32 reason;
+ __le32 rssi;
+};
+
struct wmi_pdev_temperature_event {
/* temperature value in Celcius degree */
__le32 temperature;
} __packed;
+/* WOW structures */
+enum wmi_wow_wakeup_event {
+ WOW_BMISS_EVENT = 0,
+ WOW_BETTER_AP_EVENT,
+ WOW_DEAUTH_RECVD_EVENT,
+ WOW_MAGIC_PKT_RECVD_EVENT,
+ WOW_GTK_ERR_EVENT,
+ WOW_FOURWAY_HSHAKE_EVENT,
+ WOW_EAPOL_RECVD_EVENT,
+ WOW_NLO_DETECTED_EVENT,
+ WOW_DISASSOC_RECVD_EVENT,
+ WOW_PATTERN_MATCH_EVENT,
+ WOW_CSA_IE_EVENT,
+ WOW_PROBE_REQ_WPS_IE_EVENT,
+ WOW_AUTH_REQ_EVENT,
+ WOW_ASSOC_REQ_EVENT,
+ WOW_HTT_EVENT,
+ WOW_RA_MATCH_EVENT,
+ WOW_HOST_AUTO_SHUTDOWN_EVENT,
+ WOW_IOAC_MAGIC_EVENT,
+ WOW_IOAC_SHORT_EVENT,
+ WOW_IOAC_EXTEND_EVENT,
+ WOW_IOAC_TIMER_EVENT,
+ WOW_DFS_PHYERR_RADAR_EVENT,
+ WOW_BEACON_EVENT,
+ WOW_CLIENT_KICKOUT_EVENT,
+ WOW_EVENT_MAX,
+};
+
+#define C2S(x) case x: return #x
+
+static inline const char *wow_wakeup_event(enum wmi_wow_wakeup_event ev)
+{
+ switch (ev) {
+ C2S(WOW_BMISS_EVENT);
+ C2S(WOW_BETTER_AP_EVENT);
+ C2S(WOW_DEAUTH_RECVD_EVENT);
+ C2S(WOW_MAGIC_PKT_RECVD_EVENT);
+ C2S(WOW_GTK_ERR_EVENT);
+ C2S(WOW_FOURWAY_HSHAKE_EVENT);
+ C2S(WOW_EAPOL_RECVD_EVENT);
+ C2S(WOW_NLO_DETECTED_EVENT);
+ C2S(WOW_DISASSOC_RECVD_EVENT);
+ C2S(WOW_PATTERN_MATCH_EVENT);
+ C2S(WOW_CSA_IE_EVENT);
+ C2S(WOW_PROBE_REQ_WPS_IE_EVENT);
+ C2S(WOW_AUTH_REQ_EVENT);
+ C2S(WOW_ASSOC_REQ_EVENT);
+ C2S(WOW_HTT_EVENT);
+ C2S(WOW_RA_MATCH_EVENT);
+ C2S(WOW_HOST_AUTO_SHUTDOWN_EVENT);
+ C2S(WOW_IOAC_MAGIC_EVENT);
+ C2S(WOW_IOAC_SHORT_EVENT);
+ C2S(WOW_IOAC_EXTEND_EVENT);
+ C2S(WOW_IOAC_TIMER_EVENT);
+ C2S(WOW_DFS_PHYERR_RADAR_EVENT);
+ C2S(WOW_BEACON_EVENT);
+ C2S(WOW_CLIENT_KICKOUT_EVENT);
+ C2S(WOW_EVENT_MAX);
+ default:
+ return NULL;
+ }
+}
+
+enum wmi_wow_wake_reason {
+ WOW_REASON_UNSPECIFIED = -1,
+ WOW_REASON_NLOD = 0,
+ WOW_REASON_AP_ASSOC_LOST,
+ WOW_REASON_LOW_RSSI,
+ WOW_REASON_DEAUTH_RECVD,
+ WOW_REASON_DISASSOC_RECVD,
+ WOW_REASON_GTK_HS_ERR,
+ WOW_REASON_EAP_REQ,
+ WOW_REASON_FOURWAY_HS_RECV,
+ WOW_REASON_TIMER_INTR_RECV,
+ WOW_REASON_PATTERN_MATCH_FOUND,
+ WOW_REASON_RECV_MAGIC_PATTERN,
+ WOW_REASON_P2P_DISC,
+ WOW_REASON_WLAN_HB,
+ WOW_REASON_CSA_EVENT,
+ WOW_REASON_PROBE_REQ_WPS_IE_RECV,
+ WOW_REASON_AUTH_REQ_RECV,
+ WOW_REASON_ASSOC_REQ_RECV,
+ WOW_REASON_HTT_EVENT,
+ WOW_REASON_RA_MATCH,
+ WOW_REASON_HOST_AUTO_SHUTDOWN,
+ WOW_REASON_IOAC_MAGIC_EVENT,
+ WOW_REASON_IOAC_SHORT_EVENT,
+ WOW_REASON_IOAC_EXTEND_EVENT,
+ WOW_REASON_IOAC_TIMER_EVENT,
+ WOW_REASON_ROAM_HO,
+ WOW_REASON_DFS_PHYERR_RADADR_EVENT,
+ WOW_REASON_BEACON_RECV,
+ WOW_REASON_CLIENT_KICKOUT_EVENT,
+ WOW_REASON_DEBUG_TEST = 0xFF,
+};
+
+static inline const char *wow_reason(enum wmi_wow_wake_reason reason)
+{
+ switch (reason) {
+ C2S(WOW_REASON_UNSPECIFIED);
+ C2S(WOW_REASON_NLOD);
+ C2S(WOW_REASON_AP_ASSOC_LOST);
+ C2S(WOW_REASON_LOW_RSSI);
+ C2S(WOW_REASON_DEAUTH_RECVD);
+ C2S(WOW_REASON_DISASSOC_RECVD);
+ C2S(WOW_REASON_GTK_HS_ERR);
+ C2S(WOW_REASON_EAP_REQ);
+ C2S(WOW_REASON_FOURWAY_HS_RECV);
+ C2S(WOW_REASON_TIMER_INTR_RECV);
+ C2S(WOW_REASON_PATTERN_MATCH_FOUND);
+ C2S(WOW_REASON_RECV_MAGIC_PATTERN);
+ C2S(WOW_REASON_P2P_DISC);
+ C2S(WOW_REASON_WLAN_HB);
+ C2S(WOW_REASON_CSA_EVENT);
+ C2S(WOW_REASON_PROBE_REQ_WPS_IE_RECV);
+ C2S(WOW_REASON_AUTH_REQ_RECV);
+ C2S(WOW_REASON_ASSOC_REQ_RECV);
+ C2S(WOW_REASON_HTT_EVENT);
+ C2S(WOW_REASON_RA_MATCH);
+ C2S(WOW_REASON_HOST_AUTO_SHUTDOWN);
+ C2S(WOW_REASON_IOAC_MAGIC_EVENT);
+ C2S(WOW_REASON_IOAC_SHORT_EVENT);
+ C2S(WOW_REASON_IOAC_EXTEND_EVENT);
+ C2S(WOW_REASON_IOAC_TIMER_EVENT);
+ C2S(WOW_REASON_ROAM_HO);
+ C2S(WOW_REASON_DFS_PHYERR_RADADR_EVENT);
+ C2S(WOW_REASON_BEACON_RECV);
+ C2S(WOW_REASON_CLIENT_KICKOUT_EVENT);
+ C2S(WOW_REASON_DEBUG_TEST);
+ default:
+ return NULL;
+ }
+}
+
+#undef C2S
+
+struct wmi_wow_ev_arg {
+ u32 vdev_id;
+ u32 flag;
+ enum wmi_wow_wake_reason wake_reason;
+ u32 data_len;
+};
+
+#define WOW_MIN_PATTERN_SIZE 1
+#define WOW_MAX_PATTERN_SIZE 148
+#define WOW_MAX_PKT_OFFSET 128
+
+enum wmi_tdls_state {
+ WMI_TDLS_DISABLE,
+ WMI_TDLS_ENABLE_PASSIVE,
+ WMI_TDLS_ENABLE_ACTIVE,
+};
+
+enum wmi_tdls_peer_state {
+ WMI_TDLS_PEER_STATE_PEERING,
+ WMI_TDLS_PEER_STATE_CONNECTED,
+ WMI_TDLS_PEER_STATE_TEARDOWN,
+};
+
+struct wmi_tdls_peer_update_cmd_arg {
+ u32 vdev_id;
+ enum wmi_tdls_peer_state peer_state;
+ u8 addr[ETH_ALEN];
+};
+
+#define WMI_TDLS_MAX_SUPP_OPER_CLASSES 32
+
+struct wmi_tdls_peer_capab_arg {
+ u8 peer_uapsd_queues;
+ u8 peer_max_sp;
+ u32 buff_sta_support;
+ u32 off_chan_support;
+ u32 peer_curr_operclass;
+ u32 self_curr_operclass;
+ u32 peer_chan_len;
+ u32 peer_operclass_len;
+ u8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES];
+ u32 is_peer_responder;
+ u32 pref_offchan_num;
+ u32 pref_offchan_bw;
+};
+
struct ath10k;
struct ath10k_vif;
struct ath10k_fw_stats_pdev;
diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c
new file mode 100644
index 000000000000..a68d8fd853a3
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/wow.c
@@ -0,0 +1,321 @@
+/*
+ * 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.
+ */
+
+#include "mac.h"
+
+#include <net/mac80211.h>
+#include "hif.h"
+#include "core.h"
+#include "debug.h"
+#include "wmi.h"
+#include "wmi-ops.h"
+
+static const struct wiphy_wowlan_support ath10k_wowlan_support = {
+ .flags = WIPHY_WOWLAN_DISCONNECT |
+ WIPHY_WOWLAN_MAGIC_PKT,
+ .pattern_min_len = WOW_MIN_PATTERN_SIZE,
+ .pattern_max_len = WOW_MAX_PATTERN_SIZE,
+ .max_pkt_offset = WOW_MAX_PKT_OFFSET,
+};
+
+static int ath10k_wow_vif_cleanup(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ int i, ret;
+
+ for (i = 0; i < WOW_EVENT_MAX; i++) {
+ ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 0);
+ if (ret) {
+ ath10k_warn(ar, "failed to issue wow wakeup for event %s on vdev %i: %d\n",
+ wow_wakeup_event(i), arvif->vdev_id, ret);
+ return ret;
+ }
+ }
+
+ for (i = 0; i < ar->wow.max_num_patterns; i++) {
+ ret = ath10k_wmi_wow_del_pattern(ar, arvif->vdev_id, i);
+ if (ret) {
+ ath10k_warn(ar, "failed to delete wow pattern %d for vdev %i: %d\n",
+ i, arvif->vdev_id, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ath10k_wow_cleanup(struct ath10k *ar)
+{
+ struct ath10k_vif *arvif;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ ret = ath10k_wow_vif_cleanup(arvif);
+ if (ret) {
+ ath10k_warn(ar, "failed to clean wow wakeups on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif,
+ struct cfg80211_wowlan *wowlan)
+{
+ int ret, i;
+ unsigned long wow_mask = 0;
+ struct ath10k *ar = arvif->ar;
+ const struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
+ int pattern_id = 0;
+
+ /* Setup requested WOW features */
+ switch (arvif->vdev_type) {
+ case WMI_VDEV_TYPE_IBSS:
+ __set_bit(WOW_BEACON_EVENT, &wow_mask);
+ /* fall through */
+ case WMI_VDEV_TYPE_AP:
+ __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
+ __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
+ __set_bit(WOW_PROBE_REQ_WPS_IE_EVENT, &wow_mask);
+ __set_bit(WOW_AUTH_REQ_EVENT, &wow_mask);
+ __set_bit(WOW_ASSOC_REQ_EVENT, &wow_mask);
+ __set_bit(WOW_HTT_EVENT, &wow_mask);
+ __set_bit(WOW_RA_MATCH_EVENT, &wow_mask);
+ break;
+ case WMI_VDEV_TYPE_STA:
+ if (wowlan->disconnect) {
+ __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
+ __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
+ __set_bit(WOW_BMISS_EVENT, &wow_mask);
+ __set_bit(WOW_CSA_IE_EVENT, &wow_mask);
+ }
+
+ if (wowlan->magic_pkt)
+ __set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask);
+ break;
+ default:
+ break;
+ }
+
+ for (i = 0; i < wowlan->n_patterns; i++) {
+ u8 bitmask[WOW_MAX_PATTERN_SIZE] = {};
+ int j;
+
+ if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE)
+ continue;
+
+ /* convert bytemask to bitmask */
+ for (j = 0; j < patterns[i].pattern_len; j++)
+ if (patterns[i].mask[j / 8] & BIT(j % 8))
+ bitmask[j] = 0xff;
+
+ ret = ath10k_wmi_wow_add_pattern(ar, arvif->vdev_id,
+ pattern_id,
+ patterns[i].pattern,
+ bitmask,
+ patterns[i].pattern_len,
+ patterns[i].pkt_offset);
+ if (ret) {
+ ath10k_warn(ar, "failed to add pattern %i to vdev %i: %d\n",
+ pattern_id,
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ pattern_id++;
+ __set_bit(WOW_PATTERN_MATCH_EVENT, &wow_mask);
+ }
+
+ for (i = 0; i < WOW_EVENT_MAX; i++) {
+ if (!test_bit(i, &wow_mask))
+ continue;
+ ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 1);
+ if (ret) {
+ ath10k_warn(ar, "failed to enable wakeup event %s on vdev %i: %d\n",
+ wow_wakeup_event(i), arvif->vdev_id, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ath10k_wow_set_wakeups(struct ath10k *ar,
+ struct cfg80211_wowlan *wowlan)
+{
+ struct ath10k_vif *arvif;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ ret = ath10k_vif_wow_set_wakeups(arvif, wowlan);
+ if (ret) {
+ ath10k_warn(ar, "failed to set wow wakeups on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ath10k_wow_enable(struct ath10k *ar)
+{
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ reinit_completion(&ar->target_suspend);
+
+ ret = ath10k_wmi_wow_enable(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to issue wow enable: %d\n", ret);
+ return ret;
+ }
+
+ ret = wait_for_completion_timeout(&ar->target_suspend, 3 * HZ);
+ if (ret == 0) {
+ ath10k_warn(ar, "timed out while waiting for suspend completion\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int ath10k_wow_wakeup(struct ath10k *ar)
+{
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ reinit_completion(&ar->wow.wakeup_completed);
+
+ ret = ath10k_wmi_wow_host_wakeup_ind(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to send wow wakeup indication: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = wait_for_completion_timeout(&ar->wow.wakeup_completed, 3 * HZ);
+ if (ret == 0) {
+ ath10k_warn(ar, "timed out while waiting for wow wakeup completion\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
+ struct cfg80211_wowlan *wowlan)
+{
+ struct ath10k *ar = hw->priv;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
+ ar->fw_features))) {
+ ret = 1;
+ goto exit;
+ }
+
+ ret = ath10k_wow_cleanup(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to clear wow wakeup events: %d\n",
+ ret);
+ goto exit;
+ }
+
+ ret = ath10k_wow_set_wakeups(ar, wowlan);
+ if (ret) {
+ ath10k_warn(ar, "failed to set wow wakeup events: %d\n",
+ ret);
+ goto cleanup;
+ }
+
+ ret = ath10k_wow_enable(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to start wow: %d\n", ret);
+ goto cleanup;
+ }
+
+ ret = ath10k_hif_suspend(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
+ goto wakeup;
+ }
+
+ goto exit;
+
+wakeup:
+ ath10k_wow_wakeup(ar);
+
+cleanup:
+ ath10k_wow_cleanup(ar);
+
+exit:
+ mutex_unlock(&ar->conf_mutex);
+ return ret ? 1 : 0;
+}
+
+int ath10k_wow_op_resume(struct ieee80211_hw *hw)
+{
+ struct ath10k *ar = hw->priv;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
+ ar->fw_features))) {
+ ret = 1;
+ goto exit;
+ }
+
+ ret = ath10k_hif_resume(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to resume hif: %d\n", ret);
+ goto exit;
+ }
+
+ ret = ath10k_wow_wakeup(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret);
+
+exit:
+ mutex_unlock(&ar->conf_mutex);
+ return ret ? 1 : 0;
+}
+
+int ath10k_wow_init(struct ath10k *ar)
+{
+ if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, ar->fw_features))
+ return 0;
+
+ if (WARN_ON(!test_bit(WMI_SERVICE_WOW, ar->wmi.svc_map)))
+ return -EINVAL;
+
+ ar->wow.wowlan_support = ath10k_wowlan_support;
+ ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns;
+ ar->hw->wiphy->wowlan = &ar->wow.wowlan_support;
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ath/ath10k/wow.h b/drivers/net/wireless/ath/ath10k/wow.h
new file mode 100644
index 000000000000..abbb04b6d1bd
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/wow.h
@@ -0,0 +1,40 @@
+/*
+ * 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 _WOW_H_
+#define _WOW_H_
+
+struct ath10k_wow {
+ u32 max_num_patterns;
+ struct completion wakeup_completed;
+ struct wiphy_wowlan_support wowlan_support;
+};
+
+#ifdef CONFIG_PM
+
+int ath10k_wow_init(struct ath10k *ar);
+int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
+ struct cfg80211_wowlan *wowlan);
+int ath10k_wow_op_resume(struct ieee80211_hw *hw);
+
+#else
+
+static inline int ath10k_wow_init(struct ath10k *ar)
+{
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+#endif /* _WOW_H_ */
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 7ca0d6f930fd..e22b0e778927 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -1280,7 +1280,6 @@ struct ath5k_hw {
DECLARE_BITMAP(status, 4);
#define ATH_STAT_INVALID 0 /* disable hardware accesses */
-#define ATH_STAT_PROMISC 1
#define ATH_STAT_LEDSOFT 2 /* enable LED gpio status */
#define ATH_STAT_STARTED 3 /* opened & irqs enabled */
#define ATH_STAT_RESET 4 /* hw reset */
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index a6131825c9f6..23552f43d125 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -2537,12 +2537,12 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
/* Initialize driver private data */
SET_IEEE80211_DEV(hw, ah->dev);
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SUPPORTS_RC_TABLE;
+ ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index ca4b7ccd697f..803030fd17d3 100644
--- a/drivers/net/wireless/ath/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -124,7 +124,7 @@ ath5k_led_brightness_set(struct led_classdev *led_dev,
static int
ath5k_register_led(struct ath5k_hw *ah, struct ath5k_led *led,
- const char *name, char *trigger)
+ const char *name, const char *trigger)
{
int err;
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 3b4a6463d87a..dc44cfef7517 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -369,7 +369,7 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
unsigned int *new_flags, u64 multicast)
{
#define SUPPORTED_FIF_FLAGS \
- (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \
+ (FIF_ALLMULTI | FIF_FCSFAIL | \
FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
FIF_BCN_PRBRESP_PROMISC)
@@ -393,16 +393,6 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
(AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
AR5K_RX_FILTER_MCAST);
- if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
- if (*new_flags & FIF_PROMISC_IN_BSS)
- __set_bit(ATH_STAT_PROMISC, ah->status);
- else
- __clear_bit(ATH_STAT_PROMISC, ah->status);
- }
-
- if (test_bit(ATH_STAT_PROMISC, ah->status))
- rfilt |= AR5K_RX_FILTER_PROM;
-
/* Note, AR5K_RX_FILTER_MCAST is already enabled */
if (*new_flags & FIF_ALLMULTI) {
mfilt[0] = ~0;
@@ -418,8 +408,7 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (ah->nvifs > 1))
rfilt |= AR5K_RX_FILTER_BEACON;
- /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
- * set we should only pass on control frames for this
+ /* FIF_CONTROL doc says we should only pass on control frames for this
* station. This needs testing. I believe right now this
* enables *all* control frames, which is OK.. but
* but we should see if we can improve on granularity */
@@ -809,7 +798,6 @@ const struct ieee80211_ops ath5k_hw_ops = {
.sw_scan_start = ath5k_sw_scan_start,
.sw_scan_complete = ath5k_sw_scan_complete,
.get_stats = ath5k_get_stats,
- /* .get_tkip_seq = not implemented */
/* .set_frag_threshold = not implemented */
/* .set_rts_threshold = not implemented */
/* .sta_add = not implemented */
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index cce4625a53ad..a511ef3614b9 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -889,7 +889,7 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
GFP_KERNEL);
} else if (vif->sme_state == SME_CONNECTED) {
cfg80211_disconnected(vif->ndev, proto_reason,
- NULL, 0, GFP_KERNEL);
+ NULL, 0, false, GFP_KERNEL);
}
vif->sme_state = SME_DISCONNECTED;
@@ -3467,7 +3467,7 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
GFP_KERNEL);
break;
case SME_CONNECTED:
- cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
+ cfg80211_disconnected(vif->ndev, 0, NULL, 0, true, GFP_KERNEL);
break;
}
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 19f88b4a24fb..05d25a94c781 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1527,8 +1527,8 @@ struct wmi_connect_event {
__le32 nw_type;
} sta;
struct {
- u8 phymode;
u8 aid;
+ u8 phymode;
u8 mac_addr[ETH_ALEN];
u8 auth;
u8 keymgmt;
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index 6c23d279525f..8f8793004b9f 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -254,86 +254,25 @@ static int ar5008_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
return 0;
}
-/**
- * ar5008_hw_spur_mitigate - convert baseband spur frequency for external radios
- * @ah: atheros hardware structure
- * @chan:
- *
- * For non single-chip solutions. Converts to baseband spur frequency given the
- * input channel frequency and compute register settings below.
- */
-static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
- struct ath9k_channel *chan)
+void ar5008_hw_cmn_spur_mitigate(struct ath_hw *ah,
+ struct ath9k_channel *chan, int bin)
{
- int bb_spur = AR_NO_SPUR;
- int bin, cur_bin;
- int spur_freq_sd;
- int spur_delta_phase;
- int denominator;
+ int cur_bin;
int upper, lower, cur_vit_mask;
- int tmp, new;
int i;
- static int pilot_mask_reg[4] = {
+ int8_t mask_m[123];
+ int8_t mask_p[123];
+ int8_t mask_amt;
+ int tmp_mask;
+ static const int pilot_mask_reg[4] = {
AR_PHY_TIMING7, AR_PHY_TIMING8,
AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
};
- static int chan_mask_reg[4] = {
+ static const int chan_mask_reg[4] = {
AR_PHY_TIMING9, AR_PHY_TIMING10,
AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
};
- static int inc[4] = { 0, 100, 0, 0 };
-
- int8_t mask_m[123];
- int8_t mask_p[123];
- int8_t mask_amt;
- int tmp_mask;
- int cur_bb_spur;
- bool is2GHz = IS_CHAN_2GHZ(chan);
-
- memset(&mask_m, 0, sizeof(int8_t) * 123);
- memset(&mask_p, 0, sizeof(int8_t) * 123);
-
- for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
- cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
- if (AR_NO_SPUR == cur_bb_spur)
- break;
- cur_bb_spur = cur_bb_spur - (chan->channel * 10);
- if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) {
- bb_spur = cur_bb_spur;
- break;
- }
- }
-
- if (AR_NO_SPUR == bb_spur)
- return;
-
- bin = bb_spur * 32;
-
- tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
- new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
- AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
- AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
- AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
-
- REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new);
-
- new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
- AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
- AR_PHY_SPUR_REG_MASK_RATE_SELECT |
- AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
- SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
- REG_WRITE(ah, AR_PHY_SPUR_REG, new);
-
- spur_delta_phase = ((bb_spur * 524288) / 100) &
- AR_PHY_TIMING11_SPUR_DELTA_PHASE;
-
- denominator = IS_CHAN_2GHZ(chan) ? 440 : 400;
- spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff;
-
- new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
- SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
- SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
- REG_WRITE(ah, AR_PHY_TIMING11, new);
+ static const int inc[4] = { 0, 100, 0, 0 };
cur_bin = -6000;
upper = bin + 100;
@@ -343,6 +282,7 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
int pilot_mask = 0;
int chan_mask = 0;
int bp = 0;
+
for (bp = 0; bp < 30; bp++) {
if ((cur_bin > lower) && (cur_bin < upper)) {
pilot_mask = pilot_mask | 0x1 << bp;
@@ -361,7 +301,6 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
for (i = 0; i < 123; i++) {
if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
-
/* workaround for gcc bug #37014 */
volatile int tmp_v = abs(cur_vit_mask - bin);
@@ -467,6 +406,78 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
}
/**
+ * ar5008_hw_spur_mitigate - convert baseband spur frequency for external radios
+ * @ah: atheros hardware structure
+ * @chan:
+ *
+ * For non single-chip solutions. Converts to baseband spur frequency given the
+ * input channel frequency and compute register settings below.
+ */
+static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ int bb_spur = AR_NO_SPUR;
+ int bin;
+ int spur_freq_sd;
+ int spur_delta_phase;
+ int denominator;
+ int tmp, new;
+ int i;
+
+ int8_t mask_m[123];
+ int8_t mask_p[123];
+ int cur_bb_spur;
+ bool is2GHz = IS_CHAN_2GHZ(chan);
+
+ memset(&mask_m, 0, sizeof(int8_t) * 123);
+ memset(&mask_p, 0, sizeof(int8_t) * 123);
+
+ for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+ cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
+ if (AR_NO_SPUR == cur_bb_spur)
+ break;
+ cur_bb_spur = cur_bb_spur - (chan->channel * 10);
+ if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) {
+ bb_spur = cur_bb_spur;
+ break;
+ }
+ }
+
+ if (AR_NO_SPUR == bb_spur)
+ return;
+
+ bin = bb_spur * 32;
+
+ tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
+ new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
+ AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
+ AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
+ AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
+
+ REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new);
+
+ new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
+ AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
+ AR_PHY_SPUR_REG_MASK_RATE_SELECT |
+ AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
+ SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
+ REG_WRITE(ah, AR_PHY_SPUR_REG, new);
+
+ spur_delta_phase = ((bb_spur * 524288) / 100) &
+ AR_PHY_TIMING11_SPUR_DELTA_PHASE;
+
+ denominator = IS_CHAN_2GHZ(chan) ? 440 : 400;
+ spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff;
+
+ new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
+ SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
+ SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
+ REG_WRITE(ah, AR_PHY_TIMING11, new);
+
+ ar5008_hw_cmn_spur_mitigate(ah, chan, bin);
+}
+
+/**
* ar5008_hw_rf_alloc_ext_banks - allocates banks for external radio programming
* @ah: atheros hardware structure
*
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index fc08162b5820..db6624527d99 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -169,29 +169,17 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
{
int bb_spur = AR_NO_SPUR;
int freq;
- int bin, cur_bin;
+ int bin;
int bb_spur_off, spur_subchannel_sd;
int spur_freq_sd;
int spur_delta_phase;
int denominator;
- int upper, lower, cur_vit_mask;
int tmp, newVal;
int i;
- static const int pilot_mask_reg[4] = {
- AR_PHY_TIMING7, AR_PHY_TIMING8,
- AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
- };
- static const int chan_mask_reg[4] = {
- AR_PHY_TIMING9, AR_PHY_TIMING10,
- AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
- };
- static const int inc[4] = { 0, 100, 0, 0 };
struct chan_centers centers;
int8_t mask_m[123];
int8_t mask_p[123];
- int8_t mask_amt;
- int tmp_mask;
int cur_bb_spur;
bool is2GHz = IS_CHAN_2GHZ(chan);
@@ -288,135 +276,7 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S;
REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal);
- cur_bin = -6000;
- upper = bin + 100;
- lower = bin - 100;
-
- for (i = 0; i < 4; i++) {
- int pilot_mask = 0;
- int chan_mask = 0;
- int bp = 0;
- for (bp = 0; bp < 30; bp++) {
- if ((cur_bin > lower) && (cur_bin < upper)) {
- pilot_mask = pilot_mask | 0x1 << bp;
- chan_mask = chan_mask | 0x1 << bp;
- }
- cur_bin += 100;
- }
- cur_bin += inc[i];
- REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
- REG_WRITE(ah, chan_mask_reg[i], chan_mask);
- }
-
- cur_vit_mask = 6100;
- upper = bin + 120;
- lower = bin - 120;
-
- for (i = 0; i < 123; i++) {
- if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
-
- /* workaround for gcc bug #37014 */
- volatile int tmp_v = abs(cur_vit_mask - bin);
-
- if (tmp_v < 75)
- mask_amt = 1;
- else
- mask_amt = 0;
- if (cur_vit_mask < 0)
- mask_m[abs(cur_vit_mask / 100)] = mask_amt;
- else
- mask_p[cur_vit_mask / 100] = mask_amt;
- }
- cur_vit_mask -= 100;
- }
-
- tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
- | (mask_m[48] << 26) | (mask_m[49] << 24)
- | (mask_m[50] << 22) | (mask_m[51] << 20)
- | (mask_m[52] << 18) | (mask_m[53] << 16)
- | (mask_m[54] << 14) | (mask_m[55] << 12)
- | (mask_m[56] << 10) | (mask_m[57] << 8)
- | (mask_m[58] << 6) | (mask_m[59] << 4)
- | (mask_m[60] << 2) | (mask_m[61] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
- REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
-
- tmp_mask = (mask_m[31] << 28)
- | (mask_m[32] << 26) | (mask_m[33] << 24)
- | (mask_m[34] << 22) | (mask_m[35] << 20)
- | (mask_m[36] << 18) | (mask_m[37] << 16)
- | (mask_m[48] << 14) | (mask_m[39] << 12)
- | (mask_m[40] << 10) | (mask_m[41] << 8)
- | (mask_m[42] << 6) | (mask_m[43] << 4)
- | (mask_m[44] << 2) | (mask_m[45] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
-
- tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
- | (mask_m[18] << 26) | (mask_m[18] << 24)
- | (mask_m[20] << 22) | (mask_m[20] << 20)
- | (mask_m[22] << 18) | (mask_m[22] << 16)
- | (mask_m[24] << 14) | (mask_m[24] << 12)
- | (mask_m[25] << 10) | (mask_m[26] << 8)
- | (mask_m[27] << 6) | (mask_m[28] << 4)
- | (mask_m[29] << 2) | (mask_m[30] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
-
- tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
- | (mask_m[2] << 26) | (mask_m[3] << 24)
- | (mask_m[4] << 22) | (mask_m[5] << 20)
- | (mask_m[6] << 18) | (mask_m[7] << 16)
- | (mask_m[8] << 14) | (mask_m[9] << 12)
- | (mask_m[10] << 10) | (mask_m[11] << 8)
- | (mask_m[12] << 6) | (mask_m[13] << 4)
- | (mask_m[14] << 2) | (mask_m[15] << 0);
- REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
-
- tmp_mask = (mask_p[15] << 28)
- | (mask_p[14] << 26) | (mask_p[13] << 24)
- | (mask_p[12] << 22) | (mask_p[11] << 20)
- | (mask_p[10] << 18) | (mask_p[9] << 16)
- | (mask_p[8] << 14) | (mask_p[7] << 12)
- | (mask_p[6] << 10) | (mask_p[5] << 8)
- | (mask_p[4] << 6) | (mask_p[3] << 4)
- | (mask_p[2] << 2) | (mask_p[1] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
-
- tmp_mask = (mask_p[30] << 28)
- | (mask_p[29] << 26) | (mask_p[28] << 24)
- | (mask_p[27] << 22) | (mask_p[26] << 20)
- | (mask_p[25] << 18) | (mask_p[24] << 16)
- | (mask_p[23] << 14) | (mask_p[22] << 12)
- | (mask_p[21] << 10) | (mask_p[20] << 8)
- | (mask_p[19] << 6) | (mask_p[18] << 4)
- | (mask_p[17] << 2) | (mask_p[16] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
-
- tmp_mask = (mask_p[45] << 28)
- | (mask_p[44] << 26) | (mask_p[43] << 24)
- | (mask_p[42] << 22) | (mask_p[41] << 20)
- | (mask_p[40] << 18) | (mask_p[39] << 16)
- | (mask_p[38] << 14) | (mask_p[37] << 12)
- | (mask_p[36] << 10) | (mask_p[35] << 8)
- | (mask_p[34] << 6) | (mask_p[33] << 4)
- | (mask_p[32] << 2) | (mask_p[31] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
-
- tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
- | (mask_p[59] << 26) | (mask_p[58] << 24)
- | (mask_p[57] << 22) | (mask_p[56] << 20)
- | (mask_p[55] << 18) | (mask_p[54] << 16)
- | (mask_p[53] << 14) | (mask_p[52] << 12)
- | (mask_p[51] << 10) | (mask_p[50] << 8)
- | (mask_p[49] << 6) | (mask_p[48] << 4)
- | (mask_p[47] << 2) | (mask_p[46] << 0);
- REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
- REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
+ ar5008_hw_cmn_spur_mitigate(ah, chan, bin);
REGWRITE_BUFFER_FLUSH(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 5cee231cca1f..a8762711ad74 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -15,6 +15,7 @@
*/
#include <linux/relay.h>
+#include <linux/random.h>
#include "ath9k.h"
static s8 fix_rssi_inv_only(u8 rssi_val)
@@ -36,21 +37,480 @@ static void ath_debug_send_fft_sample(struct ath_spec_scan_priv *spec_priv,
relay_write(spec_priv->rfs_chan_spec_scan, fft_sample_tlv, length);
}
+typedef int (ath_cmn_fft_idx_validator) (u8 *sample_end, int bytes_read);
+
+static int
+ath_cmn_max_idx_verify_ht20_fft(u8 *sample_end, int bytes_read)
+{
+ struct ath_ht20_mag_info *mag_info;
+ u8 *sample;
+ u16 max_magnitude;
+ u8 max_index;
+ u8 max_exp;
+
+ /* Sanity check so that we don't read outside the read
+ * buffer
+ */
+ if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN - 1)
+ return -1;
+
+ mag_info = (struct ath_ht20_mag_info *) (sample_end -
+ sizeof(struct ath_ht20_mag_info) + 1);
+
+ sample = sample_end - SPECTRAL_HT20_SAMPLE_LEN + 1;
+
+ max_index = spectral_max_index(mag_info->all_bins,
+ SPECTRAL_HT20_NUM_BINS);
+ max_magnitude = spectral_max_magnitude(mag_info->all_bins);
+
+ max_exp = mag_info->max_exp & 0xf;
+
+ /* Don't try to read something outside the read buffer
+ * in case of a missing byte (so bins[0] will be outside
+ * the read buffer)
+ */
+ if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN && max_index < 1)
+ return -1;
+
+ if (sample[max_index] != (max_magnitude >> max_exp))
+ return -1;
+ else
+ return 0;
+}
+
+static int
+ath_cmn_max_idx_verify_ht20_40_fft(u8 *sample_end, int bytes_read)
+{
+ struct ath_ht20_40_mag_info *mag_info;
+ u8 *sample;
+ u16 lower_mag, upper_mag;
+ u8 lower_max_index, upper_max_index;
+ u8 max_exp;
+ int dc_pos = SPECTRAL_HT20_40_NUM_BINS / 2;
+
+ /* Sanity check so that we don't read outside the read
+ * buffer
+ */
+ if (bytes_read < SPECTRAL_HT20_40_SAMPLE_LEN - 1)
+ return -1;
+
+ mag_info = (struct ath_ht20_40_mag_info *) (sample_end -
+ sizeof(struct ath_ht20_40_mag_info) + 1);
+
+ sample = sample_end - SPECTRAL_HT20_40_SAMPLE_LEN + 1;
+
+ lower_mag = spectral_max_magnitude(mag_info->lower_bins);
+ lower_max_index = spectral_max_index(mag_info->lower_bins,
+ SPECTRAL_HT20_40_NUM_BINS);
+
+ upper_mag = spectral_max_magnitude(mag_info->upper_bins);
+ upper_max_index = spectral_max_index(mag_info->upper_bins,
+ SPECTRAL_HT20_40_NUM_BINS);
+
+ max_exp = mag_info->max_exp & 0xf;
+
+ /* Don't try to read something outside the read buffer
+ * in case of a missing byte (so bins[0] will be outside
+ * the read buffer)
+ */
+ if (bytes_read < SPECTRAL_HT20_40_SAMPLE_LEN &&
+ ((upper_max_index < 1) || (lower_max_index < 1)))
+ return -1;
+
+ /* Some time hardware messes up the index and adds
+ * the index of the middle point (dc_pos). Try to fix it.
+ */
+ if ((upper_max_index - dc_pos > 0) &&
+ (sample[upper_max_index] == (upper_mag >> max_exp)))
+ upper_max_index -= dc_pos;
+
+ if ((lower_max_index - dc_pos > 0) &&
+ (sample[lower_max_index - dc_pos] == (lower_mag >> max_exp)))
+ lower_max_index -= dc_pos;
+
+ if ((sample[upper_max_index + dc_pos] != (upper_mag >> max_exp)) ||
+ (sample[lower_max_index] != (lower_mag >> max_exp)))
+ return -1;
+ else
+ return 0;
+}
+
+typedef int (ath_cmn_fft_sample_handler) (struct ath_rx_status *rs,
+ struct ath_spec_scan_priv *spec_priv,
+ u8 *sample_buf, u64 tsf, u16 freq, int chan_type);
+
+static int
+ath_cmn_process_ht20_fft(struct ath_rx_status *rs,
+ struct ath_spec_scan_priv *spec_priv,
+ u8 *sample_buf,
+ u64 tsf, u16 freq, int chan_type)
+{
+ struct fft_sample_ht20 fft_sample_20;
+ struct ath_common *common = ath9k_hw_common(spec_priv->ah);
+ struct ath_hw *ah = spec_priv->ah;
+ struct ath_ht20_mag_info *mag_info;
+ struct fft_sample_tlv *tlv;
+ int i = 0;
+ int ret = 0;
+ int dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
+ u16 magnitude, tmp_mag, length;
+ u8 max_index, bitmap_w, max_exp;
+
+ length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv);
+ fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20;
+ fft_sample_20.tlv.length = __cpu_to_be16(length);
+ fft_sample_20.freq = __cpu_to_be16(freq);
+ fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
+ fft_sample_20.noise = ah->noise;
+
+ mag_info = (struct ath_ht20_mag_info *) (sample_buf +
+ SPECTRAL_HT20_NUM_BINS);
+
+ magnitude = spectral_max_magnitude(mag_info->all_bins);
+ fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
+
+ max_index = spectral_max_index(mag_info->all_bins,
+ SPECTRAL_HT20_NUM_BINS);
+ fft_sample_20.max_index = max_index;
+
+ bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
+ fft_sample_20.bitmap_weight = bitmap_w;
+
+ max_exp = mag_info->max_exp & 0xf;
+ fft_sample_20.max_exp = max_exp;
+
+ fft_sample_20.tsf = __cpu_to_be64(tsf);
+
+ memcpy(fft_sample_20.data, sample_buf, SPECTRAL_HT20_NUM_BINS);
+
+ ath_dbg(common, SPECTRAL_SCAN, "FFT HT20 frame: max mag 0x%X,"
+ "max_mag_idx %i\n",
+ magnitude >> max_exp,
+ max_index);
+
+ if (fft_sample_20.data[max_index] != (magnitude >> max_exp)) {
+ ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n");
+ ret = -1;
+ }
+
+ /* DC value (value in the middle) is the blind spot of the spectral
+ * sample and invalid, interpolate it.
+ */
+ fft_sample_20.data[dc_pos] = (fft_sample_20.data[dc_pos + 1] +
+ fft_sample_20.data[dc_pos - 1]) / 2;
+
+ /* Check if the maximum magnitude is indeed maximum,
+ * also if the maximum value was at dc_pos, calculate
+ * a new one (since value at dc_pos is invalid).
+ */
+ if (max_index == dc_pos) {
+ tmp_mag = 0;
+ for (i = 0; i < dc_pos; i++) {
+ if (fft_sample_20.data[i] > tmp_mag) {
+ tmp_mag = fft_sample_20.data[i];
+ fft_sample_20.max_index = i;
+ }
+ }
+
+ magnitude = tmp_mag << max_exp;
+ fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
+
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Calculated new lower max 0x%X at %i\n",
+ tmp_mag, fft_sample_20.max_index);
+ } else
+ for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++) {
+ if (fft_sample_20.data[i] == (magnitude >> max_exp))
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Got max: 0x%X at index %i\n",
+ fft_sample_20.data[i], i);
+
+ if (fft_sample_20.data[i] > (magnitude >> max_exp)) {
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Got bin %i greater than max: 0x%X\n",
+ i, fft_sample_20.data[i]);
+ ret = -1;
+ }
+ }
+
+ if (ret < 0)
+ return ret;
+
+ tlv = (struct fft_sample_tlv *)&fft_sample_20;
+
+ ath_debug_send_fft_sample(spec_priv, tlv);
+
+ return 0;
+}
+
+static int
+ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs,
+ struct ath_spec_scan_priv *spec_priv,
+ u8 *sample_buf,
+ u64 tsf, u16 freq, int chan_type)
+{
+ struct fft_sample_ht20_40 fft_sample_40;
+ struct ath_common *common = ath9k_hw_common(spec_priv->ah);
+ struct ath_hw *ah = spec_priv->ah;
+ struct ath9k_hw_cal_data *caldata = ah->caldata;
+ struct ath_ht20_40_mag_info *mag_info;
+ struct fft_sample_tlv *tlv;
+ int dc_pos = SPECTRAL_HT20_40_NUM_BINS / 2;
+ int i = 0;
+ int ret = 0;
+ s16 ext_nf;
+ u16 lower_mag, upper_mag, tmp_mag, length;
+ s8 lower_rssi, upper_rssi;
+ u8 lower_max_index, upper_max_index;
+ u8 lower_bitmap_w, upper_bitmap_w, max_exp;
+
+ if (caldata)
+ ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
+ caldata->nfCalHist[3].privNF);
+ else
+ ext_nf = ATH_DEFAULT_NOISE_FLOOR;
+
+ length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv);
+ fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40;
+ fft_sample_40.tlv.length = __cpu_to_be16(length);
+ fft_sample_40.freq = __cpu_to_be16(freq);
+ fft_sample_40.channel_type = chan_type;
+
+ if (chan_type == NL80211_CHAN_HT40PLUS) {
+ lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
+ upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
+
+ fft_sample_40.lower_noise = ah->noise;
+ fft_sample_40.upper_noise = ext_nf;
+ } else {
+ lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
+ upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
+
+ fft_sample_40.lower_noise = ext_nf;
+ fft_sample_40.upper_noise = ah->noise;
+ }
+
+ fft_sample_40.lower_rssi = lower_rssi;
+ fft_sample_40.upper_rssi = upper_rssi;
+
+ mag_info = (struct ath_ht20_40_mag_info *) (sample_buf +
+ SPECTRAL_HT20_40_NUM_BINS);
+
+ lower_mag = spectral_max_magnitude(mag_info->lower_bins);
+ fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
+
+ upper_mag = spectral_max_magnitude(mag_info->upper_bins);
+ fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
+
+ lower_max_index = spectral_max_index(mag_info->lower_bins,
+ SPECTRAL_HT20_40_NUM_BINS);
+ fft_sample_40.lower_max_index = lower_max_index;
+
+ upper_max_index = spectral_max_index(mag_info->upper_bins,
+ SPECTRAL_HT20_40_NUM_BINS);
+ fft_sample_40.upper_max_index = upper_max_index;
+
+ lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins);
+ fft_sample_40.lower_bitmap_weight = lower_bitmap_w;
+
+ upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
+ fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
+
+ max_exp = mag_info->max_exp & 0xf;
+ fft_sample_40.max_exp = max_exp;
+
+ fft_sample_40.tsf = __cpu_to_be64(tsf);
+
+ memcpy(fft_sample_40.data, sample_buf, SPECTRAL_HT20_40_NUM_BINS);
+
+ ath_dbg(common, SPECTRAL_SCAN, "FFT HT20/40 frame: lower mag 0x%X,"
+ "lower_mag_idx %i, upper mag 0x%X,"
+ "upper_mag_idx %i\n",
+ lower_mag >> max_exp,
+ lower_max_index,
+ upper_mag >> max_exp,
+ upper_max_index);
+
+ /* Some time hardware messes up the index and adds
+ * the index of the middle point (dc_pos). Try to fix it.
+ */
+ if ((upper_max_index - dc_pos > 0) &&
+ (fft_sample_40.data[upper_max_index] == (upper_mag >> max_exp))) {
+ upper_max_index -= dc_pos;
+ fft_sample_40.upper_max_index = upper_max_index;
+ }
+
+ if ((lower_max_index - dc_pos > 0) &&
+ (fft_sample_40.data[lower_max_index - dc_pos] ==
+ (lower_mag >> max_exp))) {
+ lower_max_index -= dc_pos;
+ fft_sample_40.lower_max_index = lower_max_index;
+ }
+
+ /* Check if we got the expected magnitude values at
+ * the expected bins
+ */
+ if ((fft_sample_40.data[upper_max_index + dc_pos]
+ != (upper_mag >> max_exp)) ||
+ (fft_sample_40.data[lower_max_index]
+ != (lower_mag >> max_exp))) {
+ ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n");
+ ret = -1;
+ }
+
+ /* DC value (value in the middle) is the blind spot of the spectral
+ * sample and invalid, interpolate it.
+ */
+ fft_sample_40.data[dc_pos] = (fft_sample_40.data[dc_pos + 1] +
+ fft_sample_40.data[dc_pos - 1]) / 2;
+
+ /* Check if the maximum magnitudes are indeed maximum,
+ * also if the maximum value was at dc_pos, calculate
+ * a new one (since value at dc_pos is invalid).
+ */
+ if (lower_max_index == dc_pos) {
+ tmp_mag = 0;
+ for (i = 0; i < dc_pos; i++) {
+ if (fft_sample_40.data[i] > tmp_mag) {
+ tmp_mag = fft_sample_40.data[i];
+ fft_sample_40.lower_max_index = i;
+ }
+ }
+
+ lower_mag = tmp_mag << max_exp;
+ fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
+
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Calculated new lower max 0x%X at %i\n",
+ tmp_mag, fft_sample_40.lower_max_index);
+ } else
+ for (i = 0; i < dc_pos; i++) {
+ if (fft_sample_40.data[i] == (lower_mag >> max_exp))
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Got lower mag: 0x%X at index %i\n",
+ fft_sample_40.data[i], i);
+
+ if (fft_sample_40.data[i] > (lower_mag >> max_exp)) {
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Got lower bin %i higher than max: 0x%X\n",
+ i, fft_sample_40.data[i]);
+ ret = -1;
+ }
+ }
+
+ if (upper_max_index == dc_pos) {
+ tmp_mag = 0;
+ for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) {
+ if (fft_sample_40.data[i] > tmp_mag) {
+ tmp_mag = fft_sample_40.data[i];
+ fft_sample_40.upper_max_index = i;
+ }
+ }
+ upper_mag = tmp_mag << max_exp;
+ fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
+
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Calculated new upper max 0x%X at %i\n",
+ tmp_mag, i);
+ } else
+ for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) {
+ if (fft_sample_40.data[i] == (upper_mag >> max_exp))
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Got upper mag: 0x%X at index %i\n",
+ fft_sample_40.data[i], i);
+
+ if (fft_sample_40.data[i] > (upper_mag >> max_exp)) {
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Got upper bin %i higher than max: 0x%X\n",
+ i, fft_sample_40.data[i]);
+
+ ret = -1;
+ }
+ }
+
+ if (ret < 0)
+ return ret;
+
+ tlv = (struct fft_sample_tlv *)&fft_sample_40;
+
+ ath_debug_send_fft_sample(spec_priv, tlv);
+
+ return 0;
+}
+
+static inline void
+ath_cmn_copy_fft_frame(u8 *in, u8 *out, int sample_len, int sample_bytes)
+{
+ switch (sample_bytes - sample_len) {
+ case -1:
+ /* First byte missing */
+ memcpy(&out[1], in,
+ sample_len - 1);
+ break;
+ case 0:
+ /* Length correct, nothing to do. */
+ memcpy(out, in, sample_len);
+ break;
+ case 1:
+ /* MAC added 2 extra bytes AND first byte
+ * is missing.
+ */
+ memcpy(&out[1], in, 30);
+ out[31] = in[31];
+ memcpy(&out[32], &in[33],
+ sample_len - 32);
+ break;
+ case 2:
+ /* MAC added 2 extra bytes at bin 30 and 32,
+ * remove them.
+ */
+ memcpy(out, in, 30);
+ out[30] = in[31];
+ memcpy(&out[31], &in[33],
+ sample_len - 31);
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv)
+{
+ int i = 0;
+ int ret = 0;
+ struct rchan *rc = spec_priv->rfs_chan_spec_scan;
+
+ for_each_online_cpu(i)
+ ret += relay_buf_full(rc->buf[i]);
+
+ i = num_online_cpus();
+
+ if (ret == i)
+ return 1;
+ else
+ return 0;
+}
+
/* returns 1 if this was a spectral frame, even if not handled. */
int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_hdr *hdr,
struct ath_rx_status *rs, u64 tsf)
{
+ u8 sample_buf[SPECTRAL_SAMPLE_MAX_LEN] = {0};
struct ath_hw *ah = spec_priv->ah;
struct ath_common *common = ath9k_hw_common(spec_priv->ah);
- u8 num_bins, *bins, *vdata = (u8 *)hdr;
- struct fft_sample_ht20 fft_sample_20;
- struct fft_sample_ht20_40 fft_sample_40;
- struct fft_sample_tlv *tlv;
+ u8 num_bins, *vdata = (u8 *)hdr;
struct ath_radar_info *radar_info;
int len = rs->rs_datalen;
- int dc_pos;
- u16 fft_len, length, freq = ah->curchan->chan->center_freq;
+ int i;
+ int got_slen = 0;
+ u8 *sample_start;
+ int sample_bytes = 0;
+ int ret = 0;
+ u16 fft_len, sample_len, freq = ah->curchan->chan->center_freq;
enum nl80211_channel_type chan_type;
+ ath_cmn_fft_idx_validator *fft_idx_validator;
+ ath_cmn_fft_sample_handler *fft_handler;
/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
* via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
@@ -68,140 +528,170 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
return 0;
+ /* Output buffers are full, no need to process anything
+ * since there is no space to put the result anyway
+ */
+ ret = ath_cmn_is_fft_buf_full(spec_priv);
+ if (ret == 1) {
+ ath_dbg(common, SPECTRAL_SCAN, "FFT report ignored, no space "
+ "left on output buffers\n");
+ return 1;
+ }
+
chan_type = cfg80211_get_chandef_type(&common->hw->conf.chandef);
if ((chan_type == NL80211_CHAN_HT40MINUS) ||
(chan_type == NL80211_CHAN_HT40PLUS)) {
fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
+ sample_len = SPECTRAL_HT20_40_SAMPLE_LEN;
num_bins = SPECTRAL_HT20_40_NUM_BINS;
- bins = (u8 *)fft_sample_40.data;
+ fft_idx_validator = &ath_cmn_max_idx_verify_ht20_40_fft;
+ fft_handler = &ath_cmn_process_ht20_40_fft;
} else {
fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN;
+ sample_len = SPECTRAL_HT20_SAMPLE_LEN;
num_bins = SPECTRAL_HT20_NUM_BINS;
- bins = (u8 *)fft_sample_20.data;
- }
-
- /* Variation in the data length is possible and will be fixed later */
- if ((len > fft_len + 2) || (len < fft_len - 1))
- return 1;
-
- switch (len - fft_len) {
- case 0:
- /* length correct, nothing to do. */
- memcpy(bins, vdata, num_bins);
- break;
- case -1:
- /* first byte missing, duplicate it. */
- memcpy(&bins[1], vdata, num_bins - 1);
- bins[0] = vdata[0];
- break;
- case 2:
- /* MAC added 2 extra bytes at bin 30 and 32, remove them. */
- memcpy(bins, vdata, 30);
- bins[30] = vdata[31];
- memcpy(&bins[31], &vdata[33], num_bins - 31);
- break;
- case 1:
- /* MAC added 2 extra bytes AND first byte is missing. */
- bins[0] = vdata[0];
- memcpy(&bins[1], vdata, 30);
- bins[31] = vdata[31];
- memcpy(&bins[32], &vdata[33], num_bins - 32);
- break;
- default:
- return 1;
+ fft_idx_validator = ath_cmn_max_idx_verify_ht20_fft;
+ fft_handler = &ath_cmn_process_ht20_fft;
}
- /* DC value (value in the middle) is the blind spot of the spectral
- * sample and invalid, interpolate it.
- */
- dc_pos = num_bins / 2;
- bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
-
- if ((chan_type == NL80211_CHAN_HT40MINUS) ||
- (chan_type == NL80211_CHAN_HT40PLUS)) {
- s8 lower_rssi, upper_rssi;
- s16 ext_nf;
- u8 lower_max_index, upper_max_index;
- u8 lower_bitmap_w, upper_bitmap_w;
- u16 lower_mag, upper_mag;
- struct ath9k_hw_cal_data *caldata = ah->caldata;
- struct ath_ht20_40_mag_info *mag_info;
-
- if (caldata)
- ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
- caldata->nfCalHist[3].privNF);
- else
- ext_nf = ATH_DEFAULT_NOISE_FLOOR;
-
- length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv);
- fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40;
- fft_sample_40.tlv.length = __cpu_to_be16(length);
- fft_sample_40.freq = __cpu_to_be16(freq);
- fft_sample_40.channel_type = chan_type;
-
- if (chan_type == NL80211_CHAN_HT40PLUS) {
- lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
- upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
-
- fft_sample_40.lower_noise = ah->noise;
- fft_sample_40.upper_noise = ext_nf;
- } else {
- lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
- upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
-
- fft_sample_40.lower_noise = ext_nf;
- fft_sample_40.upper_noise = ah->noise;
+ ath_dbg(common, SPECTRAL_SCAN, "Got radar dump bw_info: 0x%X,"
+ "len: %i fft_len: %i\n",
+ radar_info->pulse_bw_info,
+ len,
+ fft_len);
+ sample_start = vdata;
+ for (i = 0; i < len - 2; i++) {
+ sample_bytes++;
+
+ /* Only a single sample received, no need to look
+ * for the sample's end, do the correction based
+ * on the packet's length instead. Note that hw
+ * will always put the radar_info structure on
+ * the end.
+ */
+ if (len <= fft_len + 2) {
+ sample_bytes = len - sizeof(struct ath_radar_info);
+ got_slen = 1;
}
- fft_sample_40.lower_rssi = lower_rssi;
- fft_sample_40.upper_rssi = upper_rssi;
-
- mag_info = ((struct ath_ht20_40_mag_info *)radar_info) - 1;
- lower_mag = spectral_max_magnitude(mag_info->lower_bins);
- upper_mag = spectral_max_magnitude(mag_info->upper_bins);
- fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
- fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
- lower_max_index = spectral_max_index(mag_info->lower_bins);
- upper_max_index = spectral_max_index(mag_info->upper_bins);
- fft_sample_40.lower_max_index = lower_max_index;
- fft_sample_40.upper_max_index = upper_max_index;
- lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins);
- upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
- fft_sample_40.lower_bitmap_weight = lower_bitmap_w;
- fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
- fft_sample_40.max_exp = mag_info->max_exp & 0xf;
- fft_sample_40.tsf = __cpu_to_be64(tsf);
-
- tlv = (struct fft_sample_tlv *)&fft_sample_40;
- } else {
- u8 max_index, bitmap_w;
- u16 magnitude;
- struct ath_ht20_mag_info *mag_info;
-
- length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv);
- fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20;
- fft_sample_20.tlv.length = __cpu_to_be16(length);
- fft_sample_20.freq = __cpu_to_be16(freq);
-
- fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
- fft_sample_20.noise = ah->noise;
-
- mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
- magnitude = spectral_max_magnitude(mag_info->all_bins);
- fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
- max_index = spectral_max_index(mag_info->all_bins);
- fft_sample_20.max_index = max_index;
- bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
- fft_sample_20.bitmap_weight = bitmap_w;
- fft_sample_20.max_exp = mag_info->max_exp & 0xf;
-
- fft_sample_20.tsf = __cpu_to_be64(tsf);
+ /* Search for the end of the FFT frame between
+ * sample_len - 1 and sample_len + 2. exp_max is 3
+ * bits long and it's the only value on the last
+ * byte of the frame so since it'll be smaller than
+ * the next byte (the first bin of the next sample)
+ * 90% of the time, we can use it as a separator.
+ */
+ if (vdata[i] <= 0x7 && sample_bytes >= sample_len - 1) {
+
+ /* Got a frame length within boundaries, there are
+ * four scenarios here:
+ *
+ * a) sample_len -> We got the correct length
+ * b) sample_len + 2 -> 2 bytes added around bin[31]
+ * c) sample_len - 1 -> The first byte is missing
+ * d) sample_len + 1 -> b + c at the same time
+ *
+ * When MAC adds 2 extra bytes, bin[31] and bin[32]
+ * have the same value, so we can use that for further
+ * verification in cases b and d.
+ */
+
+ /* Did we go too far ? If so we couldn't determine
+ * this sample's boundaries, discard any further
+ * data
+ */
+ if ((sample_bytes > sample_len + 2) ||
+ ((sample_bytes > sample_len) &&
+ (sample_start[31] != sample_start[32])))
+ break;
+
+ /* See if we got a valid frame by checking the
+ * consistency of mag_info fields. This is to
+ * prevent from "fixing" a correct frame.
+ * Failure is non-fatal, later frames may
+ * be valid.
+ */
+ if (!fft_idx_validator(&vdata[i], i)) {
+ ath_dbg(common, SPECTRAL_SCAN,
+ "Found valid fft frame at %i\n", i);
+ got_slen = 1;
+ }
+
+ /* We expect 1 - 2 more bytes */
+ else if ((sample_start[31] == sample_start[32]) &&
+ (sample_bytes >= sample_len) &&
+ (sample_bytes < sample_len + 2) &&
+ (vdata[i + 1] <= 0x7))
+ continue;
+
+ /* Try to distinguish cases a and c */
+ else if ((sample_bytes == sample_len - 1) &&
+ (vdata[i + 1] <= 0x7))
+ continue;
+
+ got_slen = 1;
+ }
- tlv = (struct fft_sample_tlv *)&fft_sample_20;
+ if (got_slen) {
+ ath_dbg(common, SPECTRAL_SCAN, "FFT frame len: %i\n",
+ sample_bytes);
+
+ /* Only try to fix a frame if it's the only one
+ * on the report, else just skip it.
+ */
+ if (sample_bytes != sample_len && len <= fft_len + 2) {
+ ath_cmn_copy_fft_frame(sample_start,
+ sample_buf, sample_len,
+ sample_bytes);
+
+ fft_handler(rs, spec_priv, sample_buf,
+ tsf, freq, chan_type);
+
+ memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
+
+ /* Mix the received bins to the /dev/random
+ * pool
+ */
+ add_device_randomness(sample_buf, num_bins);
+ }
+
+ /* Process a normal frame */
+ if (sample_bytes == sample_len) {
+ ret = fft_handler(rs, spec_priv, sample_start,
+ tsf, freq, chan_type);
+
+ /* Mix the received bins to the /dev/random
+ * pool
+ */
+ add_device_randomness(sample_start, num_bins);
+ }
+
+ /* Short report processed, break out of the
+ * loop.
+ */
+ if (len <= fft_len + 2)
+ break;
+
+ sample_start = &vdata[i + 1];
+
+ /* -1 to grab sample_len -1, -2 since
+ * they 'll get increased by one. In case
+ * of failure try to recover by going byte
+ * by byte instead.
+ */
+ if (ret == 0) {
+ i += num_bins - 2;
+ sample_bytes = num_bins - 2;
+ }
+ got_slen = 0;
+ }
}
- ath_debug_send_fft_sample(spec_priv, tlv);
-
+ i -= num_bins - 2;
+ if (len - i != sizeof(struct ath_radar_info))
+ ath_dbg(common, SPECTRAL_SCAN, "FFT report truncated"
+ "(bytes left: %i)\n",
+ len - i);
return 1;
}
EXPORT_SYMBOL(ath_cmn_process_fft);
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.h b/drivers/net/wireless/ath/ath9k/common-spectral.h
index 82d9dd29652c..998743be9c67 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.h
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.h
@@ -66,6 +66,8 @@ struct ath_ht20_fft_packet {
} __packed;
#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ath_ht20_fft_packet))
+#define SPECTRAL_HT20_SAMPLE_LEN (sizeof(struct ath_ht20_mag_info) +\
+ SPECTRAL_HT20_NUM_BINS)
/* Dynamic 20/40 mode:
*
@@ -101,6 +103,10 @@ struct ath_spec_scan_priv {
};
#define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet))
+#define SPECTRAL_HT20_40_SAMPLE_LEN (sizeof(struct ath_ht20_40_mag_info) +\
+ SPECTRAL_HT20_40_NUM_BINS)
+
+#define SPECTRAL_SAMPLE_MAX_LEN SPECTRAL_HT20_40_SAMPLE_LEN
/* grabs the max magnitude from the all/upper/lower bins */
static inline u16 spectral_max_magnitude(u8 *bins)
@@ -111,17 +117,32 @@ static inline u16 spectral_max_magnitude(u8 *bins)
}
/* return the max magnitude from the all/upper/lower bins */
-static inline u8 spectral_max_index(u8 *bins)
+static inline u8 spectral_max_index(u8 *bins, int num_bins)
{
s8 m = (bins[2] & 0xfc) >> 2;
-
- /* TODO: this still doesn't always report the right values ... */
- if (m > 32)
+ u8 zero_idx = num_bins / 2;
+
+ /* It's a 5 bit signed int, remove its sign and use one's
+ * complement interpretation to add the sign back to the 8
+ * bit int
+ */
+ if (m & 0x20) {
+ m &= ~0x20;
m |= 0xe0;
- else
- m &= ~0xe0;
+ }
+
+ /* Bring the zero point to the beginning
+ * instead of the middle so that we can use
+ * it for array lookup and that we don't deal
+ * with negative values later
+ */
+ m += zero_idx;
+
+ /* Sanity check to make sure index is within bounds */
+ if (m < 0 || m > num_bins - 1)
+ m = 0;
- return m + 29;
+ return m;
}
/* return the bitmap weight from the all/upper/lower bins */
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index e82a0d4ce23f..16dff4b89a86 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -440,9 +440,9 @@ static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv)
}
#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
-#define OP_BT_PRIORITY_DETECTED BIT(3)
-#define OP_BT_SCAN BIT(4)
-#define OP_TSF_RESET BIT(6)
+#define OP_BT_PRIORITY_DETECTED 3
+#define OP_BT_SCAN 4
+#define OP_TSF_RESET 6
enum htc_op_flags {
HTC_FWFLAG_NO_RMW,
@@ -531,6 +531,7 @@ struct ath9k_htc_priv {
struct ath9k_debug debug;
#endif
struct mutex mutex;
+ struct ieee80211_vif *csa_vif;
};
static inline void ath_read_cachesize(struct ath_common *common, int *csz)
@@ -584,6 +585,7 @@ void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv);
void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event);
void ath9k_tx_failed_tasklet(unsigned long data);
void ath9k_htc_tx_cleanup_timer(unsigned long data);
+bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv);
int ath9k_rx_init(struct ath9k_htc_priv *priv);
void ath9k_rx_cleanup(struct ath9k_htc_priv *priv);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index e8b6ec3c1dbb..e6bcb4c90fa0 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -257,6 +257,8 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
}
spin_unlock_bh(&priv->beacon_lock);
+
+ ath9k_htc_csa_is_finished(priv);
}
static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv,
@@ -503,3 +505,20 @@ void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv)
return;
}
}
+
+bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv)
+{
+ struct ieee80211_vif *vif;
+
+ vif = priv->csa_vif;
+ if (!vif || !vif->csa_active)
+ return false;
+
+ if (!ieee80211_csa_is_complete(vif))
+ return false;
+
+ ieee80211_csa_finish(vif);
+
+ priv->csa_vif = NULL;
+ return true;
+}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index d7beefe60683..39eaf9b6e9b4 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -594,7 +594,7 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
priv->spec_priv.ah = priv->ah;
priv->spec_priv.spec_config.enabled = 0;
- priv->spec_priv.spec_config.short_repeat = false;
+ priv->spec_priv.spec_config.short_repeat = true;
priv->spec_priv.spec_config.count = 8;
priv->spec_priv.spec_config.endless = false;
priv->spec_priv.spec_config.period = 0x12;
@@ -717,18 +717,18 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
struct ath_common *common = ath9k_hw_common(priv->ah);
struct base_eep_header *pBase;
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_HAS_RATE_CONTROL |
- IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_PS_NULLFUNC_STACK |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
if (ath9k_ps_enable)
- hw->flags |= IEEE80211_HW_SUPPORTS_PS;
+ ieee80211_hw_set(hw, SUPPORTS_PS);
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
@@ -744,7 +744,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN |
- WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+ WIPHY_FLAG_HAS_CHANNEL_SWITCH;
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 564923c0df87..dab1323dfec7 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1134,6 +1134,9 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
priv->nvifs--;
priv->vif_slot &= ~(1 << avp->index);
+ if (priv->csa_vif == vif)
+ priv->csa_vif = NULL;
+
ath9k_htc_remove_station(priv, vif, NULL);
DEC_VIF(priv, vif->type);
@@ -1238,8 +1241,7 @@ out:
}
#define SUPPORTED_FILTERS \
- (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+ (FIF_ALLMULTI | \
FIF_CONTROL | \
FIF_PSPOLL | \
FIF_OTHER_BSS | \
@@ -1842,6 +1844,19 @@ static int ath9k_htc_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant,
return 0;
}
+static void ath9k_htc_channel_switch_beacon(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_chan_def *chandef)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+
+ /* mac80211 does not support CSA in multi-if cases (yet) */
+ if (WARN_ON(priv->csa_vif))
+ return;
+
+ priv->csa_vif = vif;
+}
+
struct ieee80211_ops ath9k_htc_ops = {
.tx = ath9k_htc_tx,
.start = ath9k_htc_start,
@@ -1868,6 +1883,7 @@ struct ieee80211_ops ath9k_htc_ops = {
.set_bitrate_mask = ath9k_htc_set_bitrate_mask,
.get_stats = ath9k_htc_get_stats,
.get_antenna = ath9k_htc_get_antenna,
+ .channel_switch_beacon = ath9k_htc_channel_switch_beacon,
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
.get_et_sset_count = ath9k_htc_get_et_sset_count,
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index a0f58e2aa553..cc9648f844ae 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -872,14 +872,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
if (priv->rxfilter & FIF_PROBE_REQ)
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
- /*
- * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
- * mode interface or when in monitor mode. AP mode does not need this
- * since it receives all in-BSS frames anyway.
- */
- if (((ah->opmode != NL80211_IFTYPE_AP) &&
- (priv->rxfilter & FIF_PROMISC_IN_BSS)) ||
- ah->is_monitoring)
+ if (ah->is_monitoring)
rfilt |= ATH9K_RX_FILTER_PROM;
if (priv->rxfilter & FIF_CONTROL)
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index c1d2d0340feb..e8454db17634 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -1119,6 +1119,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_cmn_spur_mitigate(struct ath_hw *ah,
+ struct ath9k_channel *chan, int bin);
void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array,
struct ath9k_channel *chan, int ht40_delta);
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index f8d11efa7b0f..eff0e5325e6a 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -796,7 +796,7 @@ static void ath9k_set_mcc_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
if (!ath9k_is_chanctx_enabled())
return;
- hw->flags |= IEEE80211_HW_QUEUE_CONTROL;
+ ieee80211_hw_set(hw, QUEUE_CONTROL);
hw->queues = ATH9K_NUM_TX_QUEUES;
hw->offchannel_tx_hw_queue = hw->queues - 1;
hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS);
@@ -818,20 +818,20 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_PS_NULLFUNC_STACK |
- IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SUPPORTS_RC_TABLE |
- IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
+ ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
+ ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
if (ath9k_ps_enable)
- hw->flags |= IEEE80211_HW_SUPPORTS_PS;
+ ieee80211_hw_set(hw, SUPPORTS_PS);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
- hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
if (AR_SREV_9280_20_OR_LATER(ah))
hw->radiotap_mcs_details |=
@@ -839,7 +839,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
}
if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt)
- hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+ ieee80211_hw_set(hw, MFP_CAPABLE);
hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index b0badef71ce7..cfd45cb8ccfc 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -216,11 +216,13 @@ static bool ath_prepare_reset(struct ath_softc *sc)
ath_stop_ani(sc);
ath9k_hw_disable_interrupts(ah);
- if (!ath_drain_all_txq(sc))
- ret = false;
-
- if (!ath_stoprecv(sc))
- ret = false;
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ ret &= ath_stoprecv(sc);
+ ret &= ath_drain_all_txq(sc);
+ } else {
+ ret &= ath_drain_all_txq(sc);
+ ret &= ath_stoprecv(sc);
+ }
return ret;
}
@@ -1442,8 +1444,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
#define SUPPORTED_FILTERS \
- (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+ (FIF_ALLMULTI | \
FIF_CONTROL | \
FIF_PSPOLL | \
FIF_OTHER_BSS | \
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 6fb40ef86fd6..6c75fb1ab77d 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -392,11 +392,6 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (sc->cur_chan->rxfilter & FIF_PROBE_REQ)
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
- /*
- * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
- * mode interface or when in monitor mode. AP mode does not need this
- * since it receives all in-BSS frames anyway.
- */
if (sc->sc_ah->is_monitoring)
rfilt |= ATH9K_RX_FILTER_PROM;
diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c
index 47d5c2e910ad..88045f93a76c 100644
--- a/drivers/net/wireless/ath/carl9170/fw.c
+++ b/drivers/net/wireless/ath/carl9170/fw.c
@@ -286,7 +286,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
}
if (SUPP(CARL9170FW_PSM) && SUPP(CARL9170FW_FIXED_5GHZ_PSM))
- ar->hw->flags |= IEEE80211_HW_SUPPORTS_PS;
+ ieee80211_hw_set(ar->hw, SUPPORTS_PS);
if (!SUPP(CARL9170FW_USB_INIT_FIRMWARE)) {
dev_err(&ar->udev->dev, "firmware does not provide "
@@ -310,8 +310,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
if (SUPP(CARL9170FW_RX_FILTER)) {
ar->fw.rx_filter = true;
ar->rx_filter_caps = FIF_FCSFAIL | FIF_PLCPFAIL |
- FIF_CONTROL | FIF_PSPOLL | FIF_OTHER_BSS |
- FIF_PROMISC_IN_BSS;
+ FIF_CONTROL | FIF_PSPOLL | FIF_OTHER_BSS;
}
if (SUPP(CARL9170FW_HW_COUNTERS))
diff --git a/drivers/net/wireless/ath/carl9170/led.c b/drivers/net/wireless/ath/carl9170/led.c
index 78dadc797558..2c74425f5059 100644
--- a/drivers/net/wireless/ath/carl9170/led.c
+++ b/drivers/net/wireless/ath/carl9170/led.c
@@ -122,7 +122,7 @@ static void carl9170_led_set_brightness(struct led_classdev *led,
}
static int carl9170_led_register_led(struct ar9170 *ar, int i, char *name,
- char *trigger)
+ const char *trigger)
{
int err;
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index f1455a04cb62..170c209f99b8 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1011,9 +1011,8 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
if (multicast != ar->cur_mc_hash)
WARN_ON(carl9170_update_multicast(ar, multicast));
- if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
- ar->sniffer_enabled = !!(*new_flags &
- (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS));
+ if (changed_flags & FIF_OTHER_BSS) {
+ ar->sniffer_enabled = !!(*new_flags & FIF_OTHER_BSS);
WARN_ON(carl9170_set_operating_mode(ar));
}
@@ -1033,7 +1032,7 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
if (!(*new_flags & FIF_PSPOLL))
rx_filter |= CARL9170_RX_FILTER_CTL_PSPOLL;
- if (!(*new_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))) {
+ if (!(*new_flags & FIF_OTHER_BSS)) {
rx_filter |= CARL9170_RX_FILTER_OTHER_RA;
rx_filter |= CARL9170_RX_FILTER_DECRY_FAIL;
}
@@ -1845,22 +1844,22 @@ void *carl9170_alloc(size_t priv_size)
/* firmware decides which modes we support */
hw->wiphy->interface_modes = 0;
- hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK |
- IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
- IEEE80211_HW_SUPPORTS_RC_TABLE |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
+ ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
if (!modparam_noht) {
/*
* see the comment above, why we allow the user
* to disable HT by a module parameter.
*/
- hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
}
hw->extra_tx_headroom = sizeof(struct _carl9170_tx_superframe);
diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c
index c9f93310c0d6..76842e6ca38e 100644
--- a/drivers/net/wireless/ath/carl9170/usb.c
+++ b/drivers/net/wireless/ath/carl9170/usb.c
@@ -651,6 +651,7 @@ int carl9170_exec_cmd(struct ar9170 *ar, const enum carl9170_cmd_oids cmd,
unsigned int plen, void *payload, unsigned int outlen, void *out)
{
int err = -ENOMEM;
+ unsigned long time_left;
if (!IS_ACCEPTING_CMD(ar))
return -EIO;
@@ -672,8 +673,8 @@ int carl9170_exec_cmd(struct ar9170 *ar, const enum carl9170_cmd_oids cmd,
err = __carl9170_exec_cmd(ar, &ar->cmd, false);
if (!(cmd & CARL9170_CMD_ASYNC_FLAG)) {
- err = wait_for_completion_timeout(&ar->cmd_wait, HZ);
- if (err == 0) {
+ time_left = wait_for_completion_timeout(&ar->cmd_wait, HZ);
+ if (time_left == 0) {
err = -ETIMEDOUT;
goto err_unbuf;
}
diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c
index c657ca26a71a..656ce42b339a 100644
--- a/drivers/net/wireless/ath/dfs_pattern_detector.c
+++ b/drivers/net/wireless/ath/dfs_pattern_detector.c
@@ -41,30 +41,31 @@ struct radar_types {
/* percentage on ppb threshold to trigger detection */
#define MIN_PPB_THRESH 50
-#define PPB_THRESH(PPB) ((PPB * MIN_PPB_THRESH + 50) / 100)
+#define PPB_THRESH_RATE(PPB, RATE) ((PPB * RATE + 100 - RATE) / 100)
+#define PPB_THRESH(PPB) PPB_THRESH_RATE(PPB, MIN_PPB_THRESH)
#define PRF2PRI(PRF) ((1000000 + PRF / 2) / PRF)
/* percentage of pulse width tolerance */
#define WIDTH_TOLERANCE 5
#define WIDTH_LOWER(X) ((X*(100-WIDTH_TOLERANCE)+50)/100)
#define WIDTH_UPPER(X) ((X*(100+WIDTH_TOLERANCE)+50)/100)
-#define ETSI_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB) \
+#define ETSI_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB, CHIRP) \
{ \
ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \
(PRF2PRI(PMAX) - PRI_TOLERANCE), \
(PRF2PRI(PMIN) * PRF + PRI_TOLERANCE), PRF, PPB * PRF, \
- PPB_THRESH(PPB), PRI_TOLERANCE, \
+ PPB_THRESH(PPB), PRI_TOLERANCE, CHIRP \
}
/* radar types as defined by ETSI EN-301-893 v1.5.1 */
static const struct radar_detector_specs etsi_radar_ref_types_v15[] = {
- ETSI_PATTERN(0, 0, 1, 700, 700, 1, 18),
- ETSI_PATTERN(1, 0, 5, 200, 1000, 1, 10),
- ETSI_PATTERN(2, 0, 15, 200, 1600, 1, 15),
- ETSI_PATTERN(3, 0, 15, 2300, 4000, 1, 25),
- ETSI_PATTERN(4, 20, 30, 2000, 4000, 1, 20),
- ETSI_PATTERN(5, 0, 2, 300, 400, 3, 10),
- ETSI_PATTERN(6, 0, 2, 400, 1200, 3, 15),
+ ETSI_PATTERN(0, 0, 1, 700, 700, 1, 18, false),
+ ETSI_PATTERN(1, 0, 5, 200, 1000, 1, 10, false),
+ ETSI_PATTERN(2, 0, 15, 200, 1600, 1, 15, false),
+ ETSI_PATTERN(3, 0, 15, 2300, 4000, 1, 25, false),
+ ETSI_PATTERN(4, 20, 30, 2000, 4000, 1, 20, false),
+ ETSI_PATTERN(5, 0, 2, 300, 400, 3, 10, false),
+ ETSI_PATTERN(6, 0, 2, 400, 1200, 3, 15, false),
};
static const struct radar_types etsi_radar_types_v15 = {
@@ -73,21 +74,30 @@ static const struct radar_types etsi_radar_types_v15 = {
.radar_types = etsi_radar_ref_types_v15,
};
-#define FCC_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB) \
+#define FCC_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB, CHIRP) \
{ \
ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \
PMIN - PRI_TOLERANCE, \
PMAX * PRF + PRI_TOLERANCE, PRF, PPB * PRF, \
- PPB_THRESH(PPB), PRI_TOLERANCE, \
+ PPB_THRESH(PPB), PRI_TOLERANCE, CHIRP \
}
+/* radar types released on August 14, 2014
+ * type 1 PRI values randomly selected within the range of 518 and 3066.
+ * divide it to 3 groups is good enough for both of radar detection and
+ * avoiding false detection based on practical test results
+ * collected for more than a year.
+ */
static const struct radar_detector_specs fcc_radar_ref_types[] = {
- FCC_PATTERN(0, 0, 1, 1428, 1428, 1, 18),
- FCC_PATTERN(1, 0, 5, 150, 230, 1, 23),
- FCC_PATTERN(2, 6, 10, 200, 500, 1, 16),
- FCC_PATTERN(3, 11, 20, 200, 500, 1, 12),
- FCC_PATTERN(4, 50, 100, 1000, 2000, 1, 1),
- FCC_PATTERN(5, 0, 1, 333, 333, 1, 9),
+ FCC_PATTERN(0, 0, 1, 1428, 1428, 1, 18, false),
+ FCC_PATTERN(101, 0, 1, 518, 938, 1, 57, false),
+ FCC_PATTERN(102, 0, 1, 938, 2000, 1, 27, false),
+ FCC_PATTERN(103, 0, 1, 2000, 3066, 1, 18, false),
+ FCC_PATTERN(2, 0, 5, 150, 230, 1, 23, false),
+ FCC_PATTERN(3, 6, 10, 200, 500, 1, 16, false),
+ FCC_PATTERN(4, 11, 20, 200, 500, 1, 12, false),
+ FCC_PATTERN(5, 50, 100, 1000, 2000, 1, 1, true),
+ FCC_PATTERN(6, 0, 1, 333, 333, 1, 9, false),
};
static const struct radar_types fcc_radar_types = {
@@ -96,17 +106,23 @@ static const struct radar_types fcc_radar_types = {
.radar_types = fcc_radar_ref_types,
};
-#define JP_PATTERN FCC_PATTERN
+#define JP_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB, RATE, CHIRP) \
+{ \
+ ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \
+ PMIN - PRI_TOLERANCE, \
+ PMAX * PRF + PRI_TOLERANCE, PRF, PPB * PRF, \
+ PPB_THRESH_RATE(PPB, RATE), PRI_TOLERANCE, CHIRP \
+}
static const struct radar_detector_specs jp_radar_ref_types[] = {
- JP_PATTERN(0, 0, 1, 1428, 1428, 1, 18),
- JP_PATTERN(1, 2, 3, 3846, 3846, 1, 18),
- JP_PATTERN(2, 0, 1, 1388, 1388, 1, 18),
- JP_PATTERN(3, 1, 2, 4000, 4000, 1, 18),
- JP_PATTERN(4, 0, 5, 150, 230, 1, 23),
- JP_PATTERN(5, 6, 10, 200, 500, 1, 16),
- JP_PATTERN(6, 11, 20, 200, 500, 1, 12),
- JP_PATTERN(7, 50, 100, 1000, 2000, 1, 20),
- JP_PATTERN(5, 0, 1, 333, 333, 1, 9),
+ JP_PATTERN(0, 0, 1, 1428, 1428, 1, 18, 29, false),
+ JP_PATTERN(1, 2, 3, 3846, 3846, 1, 18, 29, false),
+ JP_PATTERN(2, 0, 1, 1388, 1388, 1, 18, 50, false),
+ JP_PATTERN(3, 1, 2, 4000, 4000, 1, 18, 50, false),
+ JP_PATTERN(4, 0, 5, 150, 230, 1, 23, 50, false),
+ JP_PATTERN(5, 6, 10, 200, 500, 1, 16, 50, false),
+ JP_PATTERN(6, 11, 20, 200, 500, 1, 12, 50, false),
+ JP_PATTERN(7, 50, 100, 1000, 2000, 1, 20, 50, false),
+ JP_PATTERN(5, 0, 1, 333, 333, 1, 9, 50, false),
};
static const struct radar_types jp_radar_types = {
diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.h b/drivers/net/wireless/ath/dfs_pattern_detector.h
index dde2652b787c..25a43d632f90 100644
--- a/drivers/net/wireless/ath/dfs_pattern_detector.h
+++ b/drivers/net/wireless/ath/dfs_pattern_detector.h
@@ -40,12 +40,14 @@ struct ath_dfs_pool_stats {
* @freq: channel frequency in MHz
* @width: pulse duration in us
* @rssi: rssi of radar event
+ * @chirp: chirp detected in pulse
*/
struct pulse_event {
u64 ts;
u16 freq;
u8 width;
u8 rssi;
+ bool chirp;
};
/**
@@ -59,6 +61,7 @@ struct pulse_event {
* @ppb: pulses per bursts for this type
* @ppb_thresh: number of pulses required to trigger detection
* @max_pri_tolerance: pulse time stamp tolerance on both sides [us]
+ * @chirp: chirp required for the radar pattern
*/
struct radar_detector_specs {
u8 type_id;
@@ -70,6 +73,7 @@ struct radar_detector_specs {
u8 ppb;
u8 ppb_thresh;
u8 max_pri_tolerance;
+ bool chirp;
};
/**
diff --git a/drivers/net/wireless/ath/dfs_pri_detector.c b/drivers/net/wireless/ath/dfs_pri_detector.c
index 43b608178884..1b5ad1965607 100644
--- a/drivers/net/wireless/ath/dfs_pri_detector.c
+++ b/drivers/net/wireless/ath/dfs_pri_detector.c
@@ -390,6 +390,10 @@ static struct pri_sequence *pri_detector_add_pulse(struct pri_detector *de,
if ((ts - de->last_ts) < rs->max_pri_tolerance)
/* if delta to last pulse is too short, don't use this pulse */
return NULL;
+ /* radar detector spec needs chirp, but not detected */
+ if (rs->chirp && rs->chirp != event->chirp)
+ return NULL;
+
de->last_ts = ts;
max_updated_seq = pseq_handler_add_to_existing_seqs(de, ts);
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 0783d2ed8238..900e72a089d8 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -944,12 +944,12 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
WLAN_CIPHER_SUITE_CCMP,
};
- wcn->hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_HAS_RATE_CONTROL |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_CONNECTION_MONITOR |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_TIMING_BEACON_ONLY;
+ ieee80211_hw_set(wcn->hw, TIMING_BEACON_ONLY);
+ ieee80211_hw_set(wcn->hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(wcn->hw, CONNECTION_MONITOR);
+ ieee80211_hw_set(wcn->hw, SUPPORTS_PS);
+ ieee80211_hw_set(wcn->hw, SIGNAL_DBM);
+ ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL);
wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index dbd894428be6..c9263e1c75d4 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -216,9 +216,7 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
memcpy(&sta_params->bssid, vif->addr, ETH_ALEN);
sta_params->encrypt_type = priv_vif->encrypt_type;
- sta_params->short_preamble_supported =
- !(WCN36XX_FLAGS(wcn) &
- IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE);
+ sta_params->short_preamble_supported = true;
sta_params->rifs_mode = 0;
sta_params->rmf = 0;
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index caa717bf52f3..050506f842e9 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -12,6 +12,7 @@ wil6210-y += debug.o
wil6210-y += rx_reorder.o
wil6210-y += ioctl.o
wil6210-y += fw.o
+wil6210-y += pmc.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
wil6210-y += wil_platform.o
wil6210-y += ethtool.o
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index b97172667bc7..c79cfe02ec80 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -289,6 +289,26 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
}
wil_dbg_misc(wil, "Start scan_request 0x%p\n", request);
+ wil_dbg_misc(wil, "SSID count: %d", request->n_ssids);
+
+ for (i = 0; i < request->n_ssids; i++) {
+ wil_dbg_misc(wil, "SSID[%d]", i);
+ print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
+ request->ssids[i].ssid,
+ request->ssids[i].ssid_len);
+ }
+
+ if (request->n_ssids)
+ rc = wmi_set_ssid(wil, request->ssids[0].ssid_len,
+ request->ssids[0].ssid);
+ else
+ rc = wmi_set_ssid(wil, 0, NULL);
+
+ if (rc) {
+ wil_err(wil, "set SSID for scan request failed: %d\n", rc);
+ return rc;
+ }
+
wil->scan_request = request;
mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO);
@@ -402,11 +422,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
rsn_eid = sme->ie ?
cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
NULL;
-
- if (sme->privacy && !rsn_eid) {
- wil_err(wil, "Missing RSN IE for secure connection\n");
- return -EINVAL;
- }
+ if (sme->privacy && !rsn_eid)
+ wil_info(wil, "WSC connection\n");
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
sme->ssid, sme->ssid_len,
@@ -425,10 +442,17 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
wil->privacy = sme->privacy;
if (wil->privacy) {
- /* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */
- rc = wmi_del_cipher_key(wil, 0, bss->bssid);
+ /* For secure assoc, remove old keys */
+ rc = wmi_del_cipher_key(wil, 0, bss->bssid,
+ WMI_KEY_USE_PAIRWISE);
+ if (rc) {
+ wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n");
+ goto out;
+ }
+ rc = wmi_del_cipher_key(wil, 0, bss->bssid,
+ WMI_KEY_USE_RX_GROUP);
if (rc) {
- wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
+ wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n");
goto out;
}
}
@@ -458,11 +482,18 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
goto out;
}
if (wil->privacy) {
- conn.dot11_auth_mode = WMI_AUTH11_SHARED;
- conn.auth_mode = WMI_AUTH_WPA2_PSK;
- conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
- conn.pairwise_crypto_len = 16;
- } else {
+ if (rsn_eid) { /* regular secure connection */
+ conn.dot11_auth_mode = WMI_AUTH11_SHARED;
+ conn.auth_mode = WMI_AUTH_WPA2_PSK;
+ conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
+ conn.pairwise_crypto_len = 16;
+ conn.group_crypto_type = WMI_CRYPT_AES_GCMP;
+ conn.group_crypto_len = 16;
+ } else { /* WSC */
+ conn.dot11_auth_mode = WMI_AUTH11_WSC;
+ conn.auth_mode = WMI_AUTH_NONE;
+ }
+ } else { /* insecure connection */
conn.dot11_auth_mode = WMI_AUTH11_OPEN;
conn.auth_mode = WMI_AUTH_NONE;
}
@@ -507,6 +538,8 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
int rc;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ wil_dbg_misc(wil, "%s(reason=%d)\n", __func__, reason_code);
+
rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
return rc;
@@ -561,6 +594,39 @@ static int wil_cfg80211_set_channel(struct wiphy *wiphy,
return 0;
}
+static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil,
+ bool pairwise)
+{
+ struct wireless_dev *wdev = wil->wdev;
+ enum wmi_key_usage rc;
+ static const char * const key_usage_str[] = {
+ [WMI_KEY_USE_PAIRWISE] = "WMI_KEY_USE_PAIRWISE",
+ [WMI_KEY_USE_RX_GROUP] = "WMI_KEY_USE_RX_GROUP",
+ [WMI_KEY_USE_TX_GROUP] = "WMI_KEY_USE_TX_GROUP",
+ };
+
+ if (pairwise) {
+ rc = WMI_KEY_USE_PAIRWISE;
+ } else {
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_STATION:
+ rc = WMI_KEY_USE_RX_GROUP;
+ break;
+ case NL80211_IFTYPE_AP:
+ rc = WMI_KEY_USE_TX_GROUP;
+ break;
+ default:
+ /* TODO: Rx GTK or Tx GTK? */
+ wil_err(wil, "Can't determine GTK type\n");
+ rc = WMI_KEY_USE_RX_GROUP;
+ break;
+ }
+ }
+ wil_dbg_misc(wil, "%s() -> %s\n", __func__, key_usage_str[rc]);
+
+ return rc;
+}
+
static int wil_cfg80211_add_key(struct wiphy *wiphy,
struct net_device *ndev,
u8 key_index, bool pairwise,
@@ -568,13 +634,13 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
struct key_params *params)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
- /* group key is not used */
- if (!pairwise)
- return 0;
+ wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
+ pairwise ? "PTK" : "GTK");
- return wmi_add_cipher_key(wil, key_index, mac_addr,
- params->key_len, params->key);
+ return wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len,
+ params->key, key_usage);
}
static int wil_cfg80211_del_key(struct wiphy *wiphy,
@@ -583,12 +649,12 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy,
const u8 *mac_addr)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
- /* group key is not used */
- if (!pairwise)
- return 0;
+ wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
+ pairwise ? "PTK" : "GTK");
- return wmi_del_cipher_key(wil, key_index, mac_addr);
+ return wmi_del_cipher_key(wil, key_index, mac_addr, key_usage);
}
/* Need to be present or wiphy_new() will WARN */
@@ -661,11 +727,6 @@ static int wil_fix_bcon(struct wil6210_priv *wil,
if (bcon->probe_resp_len <= hlen)
return 0;
- if (!bcon->proberesp_ies) {
- bcon->proberesp_ies = f->u.probe_resp.variable;
- bcon->proberesp_ies_len = bcon->probe_resp_len - hlen;
- rc = 1;
- }
if (!bcon->assocresp_ies) {
bcon->assocresp_ies = f->u.probe_resp.variable;
bcon->assocresp_ies_len = bcon->probe_resp_len - hlen;
@@ -680,9 +741,19 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
struct cfg80211_beacon_data *bcon)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp;
+ size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ const u8 *pr_ies = NULL;
+ size_t pr_ies_len = 0;
int rc;
wil_dbg_misc(wil, "%s()\n", __func__);
+ wil_print_bcon_data(bcon);
+
+ if (bcon->probe_resp_len > hlen) {
+ pr_ies = f->u.probe_resp.variable;
+ pr_ies_len = bcon->probe_resp_len - hlen;
+ }
if (wil_fix_bcon(wil, bcon)) {
wil_dbg_misc(wil, "Fixed bcon\n");
@@ -695,9 +766,7 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
* wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
* bcon->beacon_ies);
*/
- rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
- bcon->proberesp_ies_len,
- bcon->proberesp_ies);
+ rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies);
if (rc) {
wil_err(wil, "set_ie(PROBE_RESP) failed\n");
return rc;
@@ -725,6 +794,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
struct cfg80211_beacon_data *bcon = &info->beacon;
struct cfg80211_crypto_settings *crypto = &info->crypto;
u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
+ struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp;
+ size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ const u8 *pr_ies = NULL;
+ size_t pr_ies_len = 0;
+ u8 hidden_ssid;
wil_dbg_misc(wil, "%s()\n", __func__);
@@ -737,6 +811,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
channel->center_freq, info->privacy ? "secure" : "open");
wil_dbg_misc(wil, "Privacy: %d auth_type %d\n",
info->privacy, info->auth_type);
+ wil_dbg_misc(wil, "Hidden SSID mode: %d\n",
+ info->hidden_ssid);
wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval,
info->dtim_period);
print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
@@ -744,6 +820,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
wil_print_bcon_data(bcon);
wil_print_crypto(wil, crypto);
+ if (bcon->probe_resp_len > hlen) {
+ pr_ies = f->u.probe_resp.variable;
+ pr_ies_len = bcon->probe_resp_len - hlen;
+ }
+
if (wil_fix_bcon(wil, bcon)) {
wil_dbg_misc(wil, "Fixed bcon\n");
wil_print_bcon_data(bcon);
@@ -771,17 +852,34 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
* wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
* bcon->beacon_ies);
*/
- wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len,
- bcon->proberesp_ies);
+ wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies);
wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
bcon->assocresp_ies);
wil->privacy = info->privacy;
+ switch (info->hidden_ssid) {
+ case NL80211_HIDDEN_SSID_NOT_IN_USE:
+ hidden_ssid = WMI_HIDDEN_SSID_DISABLED;
+ break;
+
+ case NL80211_HIDDEN_SSID_ZERO_LEN:
+ hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY;
+ break;
+
+ case NL80211_HIDDEN_SSID_ZERO_CONTENTS:
+ hidden_ssid = WMI_HIDDEN_SSID_CLEAR;
+ break;
+
+ default:
+ rc = -EOPNOTSUPP;
+ goto out;
+ }
+
netif_carrier_on(ndev);
rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype,
- channel->hw_value);
+ channel->hw_value, hidden_ssid);
if (rc)
goto err_pcp_start;
@@ -814,13 +912,9 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
wmi_pcp_stop(wil);
__wil_down(wil);
- __wil_up(wil);
mutex_unlock(&wil->mutex);
- /* some functions above might fail (e.g. __wil_up). Nevertheless, we
- * return success because AP has stopped
- */
return 0;
}
@@ -830,6 +924,9 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy,
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ wil_dbg_misc(wil, "%s(%pM, reason=%d)\n", __func__, params->mac,
+ params->reason_code);
+
mutex_lock(&wil->mutex);
wil6210_disconnect(wil, params->mac, params->reason_code, false);
mutex_unlock(&wil->mutex);
@@ -967,8 +1064,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
static void wil_wiphy_init(struct wiphy *wiphy)
{
- /* TODO: set real value */
- wiphy->max_scan_ssids = 10;
+ wiphy->max_scan_ssids = 1;
wiphy->max_scan_ie_len = WMI_MAX_IE_LEN;
wiphy->max_num_pmkids = 0 /* TODO: */;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index bbc22d88f78f..75219a1b8805 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.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
@@ -24,6 +24,7 @@
#include "wil6210.h"
#include "wmi.h"
#include "txrx.h"
+#include "pmc.h"
/* Nasty hack. Better have per device instances */
static u32 mem_addr;
@@ -123,15 +124,17 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
if (cid < WIL6210_MAX_CID)
seq_printf(s,
- "\n%pM CID %d TID %d BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
+ "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
wil->sta[cid].addr, cid, tid,
+ txdata->dot1x_open ? "+" : "-",
txdata->agg_wsize,
txdata->agg_timeout,
txdata->agg_amsdu ? "+" : "-",
used, avail, sidle);
else
seq_printf(s,
- "\nBroadcast [%3d|%3d] idle %s\n",
+ "\nBroadcast 1x%s [%3d|%3d] idle %s\n",
+ txdata->dot1x_open ? "+" : "-",
used, avail, sidle);
wil_print_vring(s, wil, name, vring, '_', 'H');
@@ -702,6 +705,89 @@ static const struct file_operations fops_back = {
.open = simple_open,
};
+/* pmc control, write:
+ * - "alloc <num descriptors> <descriptor_size>" to allocate PMC
+ * - "free" to release memory allocated for PMC
+ */
+static ssize_t wil_write_pmccfg(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[9];
+ int num_descs, desc_size;
+
+ 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", cmd, &num_descs, &desc_size);
+ kfree(kbuf);
+
+ if (rc < 0)
+ return rc;
+
+ if (rc < 1) {
+ wil_err(wil, "pmccfg: no params given\n");
+ return -EINVAL;
+ }
+
+ if (0 == strcmp(cmd, "alloc")) {
+ if (rc != 3) {
+ wil_err(wil, "pmccfg: alloc requires 2 params\n");
+ return -EINVAL;
+ }
+ wil_pmc_alloc(wil, num_descs, desc_size);
+ } else if (0 == strcmp(cmd, "free")) {
+ if (rc != 1) {
+ wil_err(wil, "pmccfg: free does not have any params\n");
+ return -EINVAL;
+ }
+ wil_pmc_free(wil, true);
+ } else {
+ wil_err(wil, "pmccfg: Unrecognized command \"%s\"\n", cmd);
+ return -EINVAL;
+ }
+
+ return len;
+}
+
+static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wil6210_priv *wil = file->private_data;
+ char text[256];
+ char help[] = "pmc control, write:\n"
+ " - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n"
+ " - \"free\" to free memory allocated for pmc\n";
+
+ sprintf(text, "Last command status: %d\n\n%s",
+ wil_pmc_last_cmd_status(wil),
+ help);
+
+ return simple_read_from_buffer(user_buf, count, ppos, text,
+ strlen(text) + 1);
+}
+
+static const struct file_operations fops_pmccfg = {
+ .read = wil_read_pmccfg,
+ .write = wil_write_pmccfg,
+ .open = simple_open,
+};
+
+static const struct file_operations fops_pmcdata = {
+ .open = simple_open,
+ .read = wil_pmc_read,
+ .llseek = wil_pmc_llseek,
+};
+
/*---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,
@@ -1111,8 +1197,7 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
status = "connected";
break;
}
- seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
- (p->data_port_open ? " data_port_open" : ""));
+ seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
if (p->status == wil_sta_connected) {
rc = wil_cid_fill_sinfo(wil, i, &sinfo);
@@ -1275,7 +1360,7 @@ 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;
+ int i, tid, mcs;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i];
@@ -1292,8 +1377,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
status = "connected";
break;
}
- seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
- (p->data_port_open ? " data_port_open" : ""));
+ seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
if (p->status == wil_sta_connected) {
spin_lock_bh(&p->tid_rx_lock);
@@ -1306,6 +1390,12 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
}
}
spin_unlock_bh(&p->tid_rx_lock);
+ seq_puts(s, "Rx/MCS:");
+ for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
+ mcs++)
+ seq_printf(s, " %lld",
+ p->stats.rx_per_mcs[mcs]);
+ seq_puts(s, "\n");
}
}
@@ -1363,6 +1453,8 @@ static const struct {
{"tx_mgmt", S_IWUSR, &fops_txmgmt},
{"wmi_send", S_IWUSR, &fops_wmi},
{"back", S_IRUGO | S_IWUSR, &fops_back},
+ {"pmccfg", S_IRUGO | S_IWUSR, &fops_pmccfg},
+ {"pmcdata", S_IRUGO, &fops_pmcdata},
{"temp", S_IRUGO, &fops_temp},
{"freq", S_IRUGO, &fops_freq},
{"link", S_IRUGO, &fops_link},
@@ -1440,6 +1532,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
if (IS_ERR_OR_NULL(dbg))
return -ENODEV;
+ wil_pmc_init(wil);
+
wil6210_debugfs_init_files(wil, dbg);
wil6210_debugfs_init_isr(wil, dbg);
wil6210_debugfs_init_blobs(wil, dbg);
@@ -1459,4 +1553,9 @@ void wil6210_debugfs_remove(struct wil6210_priv *wil)
{
debugfs_remove_recursive(wil->debug);
wil->debug = NULL;
+
+ /* free pmc memory without sending command to fw, as it will
+ * be reset on the way down anyway
+ */
+ wil_pmc_free(wil, false);
}
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index c2a238426425..b9febab89167 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -25,6 +25,10 @@
#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
+bool debug_fw; /* = false; */
+module_param(debug_fw, bool, S_IRUGO);
+MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
+
bool no_fw_recovery;
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");
@@ -96,6 +100,8 @@ module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, S_IRUGO);
MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order");
module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, S_IRUGO);
MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order");
+module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, S_IRUGO);
+MODULE_PARM_DESC(bcast_ring_order, " Bcast ring order; size = 1 << order");
#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
@@ -146,7 +152,6 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
sta->status);
- sta->data_port_open = false;
if (sta->status != wil_sta_unused) {
if (!from_event)
wmi_disconnect_sta(wil, sta->addr, reason_code);
@@ -224,7 +229,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
if (test_bit(wil_status_fwconnected, wil->status)) {
clear_bit(wil_status_fwconnected, wil->status);
cfg80211_disconnected(ndev, reason_code,
- NULL, 0, GFP_KERNEL);
+ NULL, 0, false, GFP_KERNEL);
} else if (test_bit(wil_status_fwconnecting, wil->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
@@ -373,9 +378,10 @@ int wil_bcast_init(struct wil6210_priv *wil)
if (ri < 0)
return ri;
+ wil->bcast_vring = ri;
rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order);
- if (rc == 0)
- wil->bcast_vring = ri;
+ if (rc)
+ wil->bcast_vring = -1;
return rc;
}
@@ -547,7 +553,7 @@ static inline void wil_release_cpu(struct wil6210_priv *wil)
static int wil_target_reset(struct wil6210_priv *wil)
{
int delay = 0;
- u32 x;
+ u32 x, x1 = 0;
wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name);
@@ -602,12 +608,16 @@ static int wil_target_reset(struct wil6210_priv *wil)
do {
msleep(RST_DELAY);
x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready));
+ if (x1 != x) {
+ wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x);
+ x1 = x;
+ }
if (delay++ > RST_COUNT) {
wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
x);
return -ETIME;
}
- } while (!(x & BIT_BL_READY));
+ } while (x != BIT_BL_READY);
C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
@@ -686,6 +696,17 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
WARN_ON(!mutex_is_locked(&wil->mutex));
WARN_ON(test_bit(wil_status_napi_en, wil->status));
+ if (debug_fw) {
+ static const u8 mac[ETH_ALEN] = {
+ 0x00, 0xde, 0xad, 0x12, 0x34, 0x56,
+ };
+ struct net_device *ndev = wil_to_ndev(wil);
+
+ ether_addr_copy(ndev->perm_addr, mac);
+ ether_addr_copy(ndev->dev_addr, ndev->perm_addr);
+ return 0;
+ }
+
cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
wil_bcast_fini(wil);
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index f2f7ea29558e..8ef18ace110f 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -24,6 +24,11 @@ static int wil_open(struct net_device *ndev)
wil_dbg_misc(wil, "%s()\n", __func__);
+ if (debug_fw) {
+ wil_err(wil, "%s() while in debug_fw mode\n", __func__);
+ return -EINVAL;
+ }
+
return wil_up(wil);
}
@@ -127,7 +132,7 @@ static void wil_dev_setup(struct net_device *dev)
dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT;
}
-void *wil_if_alloc(struct device *dev, void __iomem *csr)
+void *wil_if_alloc(struct device *dev)
{
struct net_device *ndev;
struct wireless_dev *wdev;
@@ -142,7 +147,6 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
}
wil = wdev_to_wil(wdev);
- wil->csr = csr;
wil->wdev = wdev;
wil_dbg_misc(wil, "%s()\n", __func__);
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 109986114abf..aa3ecc607ca3 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -27,10 +27,6 @@ MODULE_PARM_DESC(use_msi,
" Use MSI interrupt: "
"0 - don't, 1 - (default) - single, or 3");
-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)
{
@@ -133,8 +129,6 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
mutex_lock(&wil->mutex);
rc = wil_reset(wil, false);
mutex_unlock(&wil->mutex);
- if (debug_fw)
- rc = 0;
if (rc)
goto release_irq;
@@ -169,7 +163,6 @@ 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;
int rc;
/* check HW */
@@ -184,9 +177,28 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENODEV;
}
+ wil = wil_if_alloc(dev);
+ if (IS_ERR(wil)) {
+ rc = (int)PTR_ERR(wil);
+ dev_err(dev, "wil_if_alloc failed: %d\n", rc);
+ return rc;
+ }
+ wil->pdev = pdev;
+ pci_set_drvdata(pdev, wil);
+ /* rollback to if_free */
+
+ wil->platform_handle =
+ wil_platform_init(&pdev->dev, &wil->platform_ops);
+ if (!wil->platform_handle) {
+ rc = -ENODEV;
+ wil_err(wil, "wil_platform_init failed\n");
+ goto if_free;
+ }
+ /* rollback to err_plat */
+
rc = pci_enable_device(pdev);
if (rc) {
- dev_err(&pdev->dev,
+ wil_err(wil,
"pci_enable_device failed, retry with MSI only\n");
/* Work around for platforms that can't allocate IRQ:
* retry with MSI only
@@ -194,47 +206,37 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pdev->msi_enabled = 1;
rc = pci_enable_device(pdev);
}
- if (rc)
- return -ENODEV;
+ if (rc) {
+ wil_err(wil,
+ "pci_enable_device failed, even with MSI only\n");
+ goto err_plat;
+ }
/* rollback to err_disable_pdev */
rc = pci_request_region(pdev, 0, WIL_NAME);
if (rc) {
- dev_err(&pdev->dev, "pci_request_region failed\n");
+ wil_err(wil, "pci_request_region failed\n");
goto err_disable_pdev;
}
/* rollback to err_release_reg */
- csr = pci_ioremap_bar(pdev, 0);
- if (!csr) {
- dev_err(&pdev->dev, "pci_ioremap_bar failed\n");
+ wil->csr = pci_ioremap_bar(pdev, 0);
+ if (!wil->csr) {
+ wil_err(wil, "pci_ioremap_bar failed\n");
rc = -ENODEV;
goto err_release_reg;
}
/* rollback to err_iounmap */
- dev_info(&pdev->dev, "CSR at %pR -> 0x%p\n", &pdev->resource[0], csr);
-
- wil = wil_if_alloc(dev, csr);
- if (IS_ERR(wil)) {
- rc = (int)PTR_ERR(wil);
- dev_err(dev, "wil_if_alloc failed: %d\n", rc);
- goto err_iounmap;
- }
- /* rollback to if_free */
+ wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr);
- pci_set_drvdata(pdev, wil);
- wil->pdev = pdev;
wil_set_capabilities(wil);
wil6210_clear_irq(wil);
- wil->platform_handle =
- wil_platform_init(&pdev->dev, &wil->platform_ops);
-
/* FW should raise IRQ when ready */
rc = wil_if_pcie_enable(wil);
if (rc) {
wil_err(wil, "Enable device failed\n");
- goto if_free;
+ goto err_iounmap;
}
/* rollback to bus_disable */
@@ -249,18 +251,19 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
- bus_disable:
+bus_disable:
wil_if_pcie_disable(wil);
- if_free:
+err_iounmap:
+ pci_iounmap(pdev, wil->csr);
+err_release_reg:
+ pci_release_region(pdev, 0);
+err_disable_pdev:
+ pci_disable_device(pdev);
+err_plat:
if (wil->platform_ops.uninit)
wil->platform_ops.uninit(wil->platform_handle);
+if_free:
wil_if_free(wil);
- err_iounmap:
- pci_iounmap(pdev, csr);
- err_release_reg:
- pci_release_region(pdev, 0);
- err_disable_pdev:
- pci_disable_device(pdev);
return rc;
}
@@ -275,12 +278,12 @@ static void wil_pcie_remove(struct pci_dev *pdev)
wil6210_debugfs_remove(wil);
wil_if_remove(wil);
wil_if_pcie_disable(wil);
- if (wil->platform_ops.uninit)
- wil->platform_ops.uninit(wil->platform_handle);
- wil_if_free(wil);
pci_iounmap(pdev, csr);
pci_release_region(pdev, 0);
pci_disable_device(pdev);
+ if (wil->platform_ops.uninit)
+ wil->platform_ops.uninit(wil->platform_handle);
+ wil_if_free(wil);
}
static const struct pci_device_id wil6210_pcie_ids[] = {
@@ -297,7 +300,27 @@ static struct pci_driver wil6210_driver = {
.name = WIL_NAME,
};
-module_pci_driver(wil6210_driver);
+static int __init wil6210_driver_init(void)
+{
+ int rc;
+
+ rc = wil_platform_modinit();
+ if (rc)
+ return rc;
+
+ rc = pci_register_driver(&wil6210_driver);
+ if (rc)
+ wil_platform_modexit();
+ return rc;
+}
+module_init(wil6210_driver_init);
+
+static void __exit wil6210_driver_exit(void)
+{
+ pci_unregister_driver(&wil6210_driver);
+ wil_platform_modexit();
+}
+module_exit(wil6210_driver_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>");
diff --git a/drivers/net/wireless/ath/wil6210/pmc.c b/drivers/net/wireless/ath/wil6210/pmc.c
new file mode 100644
index 000000000000..8a8cdc61b25b
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/pmc.c
@@ -0,0 +1,375 @@
+/*
+ * 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
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include "wmi.h"
+#include "wil6210.h"
+#include "txrx.h"
+#include "pmc.h"
+
+struct desc_alloc_info {
+ dma_addr_t pa;
+ void *va;
+};
+
+static int wil_is_pmc_allocated(struct pmc_ctx *pmc)
+{
+ return !!pmc->pring_va;
+}
+
+void wil_pmc_init(struct wil6210_priv *wil)
+{
+ memset(&wil->pmc, 0, sizeof(struct pmc_ctx));
+ mutex_init(&wil->pmc.lock);
+}
+
+/**
+ * Allocate the physical ring (p-ring) and the required
+ * number of descriptors of required size.
+ * Initialize the descriptors as required by pmc dma.
+ * The descriptors' buffers dwords are initialized to hold
+ * dword's serial number in the lsw and reserved value
+ * PCM_DATA_INVALID_DW_VAL in the msw.
+ */
+void wil_pmc_alloc(struct wil6210_priv *wil,
+ int num_descriptors,
+ int descriptor_size)
+{
+ u32 i;
+ struct pmc_ctx *pmc = &wil->pmc;
+ struct device *dev = wil_to_dev(wil);
+ struct wmi_pmc_cmd pmc_cmd = {0};
+
+ mutex_lock(&pmc->lock);
+
+ if (wil_is_pmc_allocated(pmc)) {
+ /* sanity check */
+ wil_err(wil, "%s: ERROR pmc is already allocated\n", __func__);
+ goto no_release_err;
+ }
+
+ pmc->num_descriptors = num_descriptors;
+ pmc->descriptor_size = descriptor_size;
+
+ wil_dbg_misc(wil, "%s: %d descriptors x %d bytes each\n",
+ __func__, num_descriptors, descriptor_size);
+
+ /* allocate descriptors info list in pmc context*/
+ pmc->descriptors = kcalloc(num_descriptors,
+ sizeof(struct desc_alloc_info),
+ GFP_KERNEL);
+ if (!pmc->descriptors) {
+ wil_err(wil, "%s: ERROR allocating pmc skb list\n", __func__);
+ goto no_release_err;
+ }
+
+ wil_dbg_misc(wil,
+ "%s: allocated descriptors info list %p\n",
+ __func__, pmc->descriptors);
+
+ /* Allocate pring buffer and descriptors.
+ * vring->va should be aligned on its size rounded up to power of 2
+ * This is granted by the dma_alloc_coherent
+ */
+ pmc->pring_va = dma_alloc_coherent(dev,
+ sizeof(struct vring_tx_desc) * num_descriptors,
+ &pmc->pring_pa,
+ GFP_KERNEL);
+
+ wil_dbg_misc(wil,
+ "%s: allocated pring %p => %pad. %zd x %d = total %zd bytes\n",
+ __func__,
+ pmc->pring_va, &pmc->pring_pa,
+ sizeof(struct vring_tx_desc),
+ num_descriptors,
+ sizeof(struct vring_tx_desc) * num_descriptors);
+
+ if (!pmc->pring_va) {
+ wil_err(wil, "%s: ERROR allocating pmc pring\n", __func__);
+ goto release_pmc_skb_list;
+ }
+
+ /* initially, all descriptors are SW owned
+ * For Tx, Rx, and PMC, ownership bit is at the same location, thus
+ * we can use any
+ */
+ for (i = 0; i < num_descriptors; i++) {
+ struct vring_tx_desc *_d = &pmc->pring_va[i];
+ struct vring_tx_desc dd, *d = &dd;
+ int j = 0;
+
+ pmc->descriptors[i].va = dma_alloc_coherent(dev,
+ descriptor_size,
+ &pmc->descriptors[i].pa,
+ GFP_KERNEL);
+
+ if (unlikely(!pmc->descriptors[i].va)) {
+ wil_err(wil,
+ "%s: ERROR allocating pmc descriptor %d",
+ __func__, i);
+ goto release_pmc_skbs;
+ }
+
+ for (j = 0; j < descriptor_size / sizeof(u32); j++) {
+ u32 *p = (u32 *)pmc->descriptors[i].va + j;
+ *p = PCM_DATA_INVALID_DW_VAL | j;
+ }
+
+ /* configure dma descriptor */
+ d->dma.addr.addr_low =
+ cpu_to_le32(lower_32_bits(pmc->descriptors[i].pa));
+ d->dma.addr.addr_high =
+ cpu_to_le16((u16)upper_32_bits(pmc->descriptors[i].pa));
+ d->dma.status = 0; /* 0 = HW_OWNED */
+ d->dma.length = cpu_to_le16(descriptor_size);
+ d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT;
+ *_d = *d;
+ }
+
+ wil_dbg_misc(wil, "%s: allocated successfully\n", __func__);
+
+ pmc_cmd.op = WMI_PMC_ALLOCATE;
+ pmc_cmd.ring_size = cpu_to_le16(pmc->num_descriptors);
+ pmc_cmd.mem_base = cpu_to_le64(pmc->pring_pa);
+
+ wil_dbg_misc(wil, "%s: send WMI_PMC_CMD with ALLOCATE op\n", __func__);
+ pmc->last_cmd_status = wmi_send(wil,
+ WMI_PMC_CMDID,
+ &pmc_cmd,
+ sizeof(pmc_cmd));
+ if (pmc->last_cmd_status) {
+ wil_err(wil,
+ "%s: WMI_PMC_CMD with ALLOCATE op failed with status %d",
+ __func__, pmc->last_cmd_status);
+ goto release_pmc_skbs;
+ }
+
+ mutex_unlock(&pmc->lock);
+
+ return;
+
+release_pmc_skbs:
+ wil_err(wil, "%s: exit on error: Releasing skbs...\n", __func__);
+ for (i = 0; pmc->descriptors[i].va && i < num_descriptors; i++) {
+ dma_free_coherent(dev,
+ descriptor_size,
+ pmc->descriptors[i].va,
+ pmc->descriptors[i].pa);
+
+ pmc->descriptors[i].va = NULL;
+ }
+ wil_err(wil, "%s: exit on error: Releasing pring...\n", __func__);
+
+ dma_free_coherent(dev,
+ sizeof(struct vring_tx_desc) * num_descriptors,
+ pmc->pring_va,
+ pmc->pring_pa);
+
+ pmc->pring_va = NULL;
+
+release_pmc_skb_list:
+ wil_err(wil, "%s: exit on error: Releasing descriptors info list...\n",
+ __func__);
+ kfree(pmc->descriptors);
+ pmc->descriptors = NULL;
+
+no_release_err:
+ pmc->last_cmd_status = -ENOMEM;
+ mutex_unlock(&pmc->lock);
+}
+
+/**
+ * Traverse the p-ring and release all buffers.
+ * At the end release the p-ring memory
+ */
+void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd)
+{
+ struct pmc_ctx *pmc = &wil->pmc;
+ struct device *dev = wil_to_dev(wil);
+ struct wmi_pmc_cmd pmc_cmd = {0};
+
+ mutex_lock(&pmc->lock);
+
+ pmc->last_cmd_status = 0;
+
+ if (!wil_is_pmc_allocated(pmc)) {
+ wil_dbg_misc(wil, "%s: Error, can't free - not allocated\n",
+ __func__);
+ pmc->last_cmd_status = -EPERM;
+ mutex_unlock(&pmc->lock);
+ return;
+ }
+
+ if (send_pmc_cmd) {
+ wil_dbg_misc(wil, "%s: send WMI_PMC_CMD with RELEASE op\n",
+ __func__);
+ pmc_cmd.op = WMI_PMC_RELEASE;
+ pmc->last_cmd_status =
+ wmi_send(wil, WMI_PMC_CMDID, &pmc_cmd,
+ sizeof(pmc_cmd));
+ if (pmc->last_cmd_status) {
+ wil_err(wil,
+ "%s WMI_PMC_CMD with RELEASE op failed, status %d",
+ __func__, pmc->last_cmd_status);
+ /* There's nothing we can do with this error.
+ * Normally, it should never occur.
+ * Continue to freeing all memory allocated for pmc.
+ */
+ }
+ }
+
+ if (pmc->pring_va) {
+ size_t buf_size = sizeof(struct vring_tx_desc) *
+ pmc->num_descriptors;
+
+ wil_dbg_misc(wil, "%s: free pring va %p\n",
+ __func__, pmc->pring_va);
+ dma_free_coherent(dev, buf_size, pmc->pring_va, pmc->pring_pa);
+
+ pmc->pring_va = NULL;
+ } else {
+ pmc->last_cmd_status = -ENOENT;
+ }
+
+ if (pmc->descriptors) {
+ int i;
+
+ for (i = 0;
+ pmc->descriptors[i].va && i < pmc->num_descriptors; i++) {
+ dma_free_coherent(dev,
+ pmc->descriptor_size,
+ pmc->descriptors[i].va,
+ pmc->descriptors[i].pa);
+ pmc->descriptors[i].va = NULL;
+ }
+ wil_dbg_misc(wil, "%s: free descriptor info %d/%d\n",
+ __func__, i, pmc->num_descriptors);
+ wil_dbg_misc(wil,
+ "%s: free pmc descriptors info list %p\n",
+ __func__, pmc->descriptors);
+ kfree(pmc->descriptors);
+ pmc->descriptors = NULL;
+ } else {
+ pmc->last_cmd_status = -ENOENT;
+ }
+
+ mutex_unlock(&pmc->lock);
+}
+
+/**
+ * Status of the last operation requested via debugfs: alloc/free/read.
+ * 0 - success or negative errno
+ */
+int wil_pmc_last_cmd_status(struct wil6210_priv *wil)
+{
+ wil_dbg_misc(wil, "%s: status %d\n", __func__,
+ wil->pmc.last_cmd_status);
+
+ return wil->pmc.last_cmd_status;
+}
+
+/**
+ * Read from required position up to the end of current descriptor,
+ * depends on descriptor size configured during alloc request.
+ */
+ssize_t wil_pmc_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *f_pos)
+{
+ struct wil6210_priv *wil = filp->private_data;
+ struct pmc_ctx *pmc = &wil->pmc;
+ size_t retval = 0;
+ unsigned long long idx;
+ loff_t offset;
+ size_t pmc_size = pmc->descriptor_size * pmc->num_descriptors;
+
+ mutex_lock(&pmc->lock);
+
+ if (!wil_is_pmc_allocated(pmc)) {
+ wil_err(wil, "%s: error, pmc is not allocated!\n", __func__);
+ pmc->last_cmd_status = -EPERM;
+ mutex_unlock(&pmc->lock);
+ return -EPERM;
+ }
+
+ wil_dbg_misc(wil,
+ "%s: size %u, pos %lld\n",
+ __func__, (unsigned)count, *f_pos);
+
+ pmc->last_cmd_status = 0;
+
+ idx = *f_pos;
+ do_div(idx, pmc->descriptor_size);
+ offset = *f_pos - (idx * pmc->descriptor_size);
+
+ if (*f_pos >= pmc_size) {
+ wil_dbg_misc(wil, "%s: reached end of pmc buf: %lld >= %u\n",
+ __func__, *f_pos, (unsigned)pmc_size);
+ pmc->last_cmd_status = -ERANGE;
+ goto out;
+ }
+
+ wil_dbg_misc(wil,
+ "%s: read from pos %lld (descriptor %llu, offset %llu) %zu bytes\n",
+ __func__, *f_pos, idx, offset, count);
+
+ /* if no errors, return the copied byte count */
+ retval = simple_read_from_buffer(buf,
+ count,
+ &offset,
+ pmc->descriptors[idx].va,
+ pmc->descriptor_size);
+ *f_pos += retval;
+out:
+ mutex_unlock(&pmc->lock);
+
+ return retval;
+}
+
+loff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence)
+{
+ loff_t newpos;
+ struct wil6210_priv *wil = filp->private_data;
+ struct pmc_ctx *pmc = &wil->pmc;
+ size_t pmc_size = pmc->descriptor_size * pmc->num_descriptors;
+
+ switch (whence) {
+ case 0: /* SEEK_SET */
+ newpos = off;
+ break;
+
+ case 1: /* SEEK_CUR */
+ newpos = filp->f_pos + off;
+ break;
+
+ case 2: /* SEEK_END */
+ newpos = pmc_size;
+ break;
+
+ default: /* can't happen */
+ return -EINVAL;
+ }
+
+ if (newpos < 0)
+ return -EINVAL;
+ if (newpos > pmc_size)
+ newpos = pmc_size;
+
+ filp->f_pos = newpos;
+
+ return newpos;
+}
diff --git a/drivers/net/wireless/ath/wil6210/pmc.h b/drivers/net/wireless/ath/wil6210/pmc.h
new file mode 100644
index 000000000000..bebc8d52e1e6
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/pmc.h
@@ -0,0 +1,27 @@
+/*
+ * 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
+ * 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/types.h>
+
+#define PCM_DATA_INVALID_DW_VAL (0xB0BA0000)
+
+void wil_pmc_init(struct wil6210_priv *wil);
+void wil_pmc_alloc(struct wil6210_priv *wil,
+ int num_descriptors, int descriptor_size);
+void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd);
+int wil_pmc_last_cmd_status(struct wil6210_priv *wil);
+ssize_t wil_pmc_read(struct file *, char __user *, size_t, loff_t *);
+loff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index e8bd512d81a9..aa20af86e1d6 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.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
@@ -236,7 +236,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
return -ENOMEM;
}
- d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT;
+ d->dma.d0 = RX_DMA_D0_CMD_DMA_RT | RX_DMA_D0_CMD_DMA_IT;
wil_desc_addr_set(&d->dma.addr, pa);
/* ip_length don't care */
/* b11 don't care */
@@ -427,6 +427,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
cid = wil_rxdesc_cid(d);
stats = &wil->sta[cid].stats;
stats->last_mcs_rx = wil_rxdesc_mcs(d);
+ if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs))
+ stats->rx_per_mcs[stats->last_mcs_rx]++;
/* use radiotap header only if required */
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
@@ -724,6 +726,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
+ if (!wil->privacy)
+ txdata->dot1x_open = true;
rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
if (rc)
@@ -738,11 +742,13 @@ 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))
+ if (txdata->dot1x_open && (agg_wsize >= 0))
wil_addba_tx_request(wil, id, agg_wsize);
return 0;
out_free:
+ txdata->dot1x_open = false;
+ txdata->enabled = 0;
wil_vring_free(wil, vring, 1);
out:
@@ -792,6 +798,8 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
+ if (!wil->privacy)
+ txdata->dot1x_open = true;
rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, &cmd, sizeof(cmd),
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
if (rc)
@@ -809,6 +817,8 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
return 0;
out_free:
+ txdata->enabled = 0;
+ txdata->dot1x_open = false;
wil_vring_free(wil, vring, 1);
out:
@@ -828,6 +838,7 @@ 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->dot1x_open = false;
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 */
@@ -848,12 +859,11 @@ static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
if (cid < 0)
return NULL;
- if (!wil->sta[cid].data_port_open &&
- (skb->protocol != cpu_to_be16(ETH_P_PAE)))
- return NULL;
-
/* TODO: fix for multiple TID */
for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
+ if (!wil->vring_tx_data[i].dot1x_open &&
+ (skb->protocol != cpu_to_be16(ETH_P_PAE)))
+ continue;
if (wil->vring2cid_tid[i][0] == cid) {
struct vring *v = &wil->vring_tx[i];
@@ -883,7 +893,7 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
/* 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
+ * find 1-st vring eligible for this skb and use it.
*/
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
v = &wil->vring_tx[i];
@@ -894,9 +904,9 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
if (cid >= WIL6210_MAX_CID) /* skip BCAST */
continue;
- if (!wil->sta[cid].data_port_open &&
+ if (!wil->vring_tx_data[i].dot1x_open &&
(skb->protocol != cpu_to_be16(ETH_P_PAE)))
- break;
+ continue;
wil_dbg_txrx(wil, "Tx -> ring %d\n", i);
@@ -918,7 +928,6 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
* in all cases override dest address to unicast peer's address
* Use old strategy when new is not supported yet:
* - for PBSS
- * - for secure link
*/
static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
struct sk_buff *skb)
@@ -931,6 +940,9 @@ static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
v = &wil->vring_tx[i];
if (!v->va)
return NULL;
+ if (!wil->vring_tx_data[i].dot1x_open &&
+ (skb->protocol != cpu_to_be16(ETH_P_PAE)))
+ return NULL;
return v;
}
@@ -963,7 +975,8 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
cid = wil->vring2cid_tid[i][0];
if (cid >= WIL6210_MAX_CID) /* skip BCAST */
continue;
- if (!wil->sta[cid].data_port_open)
+ if (!wil->vring_tx_data[i].dot1x_open &&
+ (skb->protocol != cpu_to_be16(ETH_P_PAE)))
continue;
/* don't Tx back to source when re-routing Rx->Tx at the AP */
@@ -989,7 +1002,8 @@ found:
cid = wil->vring2cid_tid[i][0];
if (cid >= WIL6210_MAX_CID) /* skip BCAST */
continue;
- if (!wil->sta[cid].data_port_open)
+ if (!wil->vring_tx_data[i].dot1x_open &&
+ (skb->protocol != cpu_to_be16(ETH_P_PAE)))
continue;
if (0 == memcmp(wil->sta[cid].addr, src, ETH_ALEN))
@@ -1016,9 +1030,6 @@ static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil,
if (wdev->iftype != NL80211_IFTYPE_AP)
return wil_find_tx_bcast_2(wil, skb);
- if (wil->privacy)
- return wil_find_tx_bcast_2(wil, skb);
-
return wil_find_tx_bcast_1(wil, skb);
}
@@ -1144,13 +1155,8 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
wil_tx_desc_map(d, pa, len, vring_index);
if (unlikely(mcast)) {
d->mac.d[0] |= BIT(MAC_CFG_DESC_TX_0_MCS_EN_POS); /* MCS 0 */
- if (unlikely(len > WIL_BCAST_MCS0_LIMIT)) {
- /* set MCS 1 */
+ if (unlikely(len > WIL_BCAST_MCS0_LIMIT)) /* set MCS 1 */
d->mac.d[0] |= (1 << MAC_CFG_DESC_TX_0_MCS_INDEX_POS);
- /* packet mode 2 */
- d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_PKT_MODE_EN_POS) |
- (2 << MAC_CFG_DESC_TX_1_PKT_MODE_POS);
- }
}
/* Process TCP/UDP checksum offloading */
if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) {
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index d90c8aa20c15..0c4638487c74 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -384,19 +384,27 @@ struct vring_rx_mac {
* [word 7] length
*/
-#define RX_DMA_D0_CMD_DMA_IT BIT(10)
-
-/* Error field, offload bits */
-#define RX_DMA_ERROR_L3_ERR BIT(4)
-#define RX_DMA_ERROR_L4_ERR BIT(5)
+#define RX_DMA_D0_CMD_DMA_EOP BIT(8)
+#define RX_DMA_D0_CMD_DMA_RT BIT(9) /* always 1 */
+#define RX_DMA_D0_CMD_DMA_IT BIT(10) /* interrupt */
+
+/* Error field */
+#define RX_DMA_ERROR_FCS BIT(0)
+#define RX_DMA_ERROR_MIC BIT(1)
+#define RX_DMA_ERROR_KEY BIT(2) /* Key missing */
+#define RX_DMA_ERROR_REPLAY BIT(3)
+#define RX_DMA_ERROR_L3_ERR BIT(4)
+#define RX_DMA_ERROR_L4_ERR BIT(5)
/* Status field */
-#define RX_DMA_STATUS_DU BIT(0)
-#define RX_DMA_STATUS_ERROR BIT(2)
-
+#define RX_DMA_STATUS_DU BIT(0)
+#define RX_DMA_STATUS_EOP BIT(1)
+#define RX_DMA_STATUS_ERROR BIT(2)
+#define RX_DMA_STATUS_MI BIT(3) /* MAC Interrupt is asserted */
#define RX_DMA_STATUS_L3I BIT(4)
#define RX_DMA_STATUS_L4I BIT(5)
#define RX_DMA_STATUS_PHY_INFO BIT(6)
+#define RX_DMA_STATUS_FFM BIT(7) /* EtherType Flex Filter Match */
struct vring_rx_dma {
u32 d0;
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 4310972c9e16..275355d46a36 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -21,6 +21,7 @@
#include <linux/wireless.h>
#include <net/cfg80211.h>
#include <linux/timex.h>
+#include <linux/types.h>
#include "wil_platform.h"
extern bool no_fw_recovery;
@@ -29,10 +30,11 @@ extern unsigned short rx_ring_overflow_thrsh;
extern int agg_wsize;
extern u32 vring_idle_trsh;
extern bool rx_align_2;
+extern bool debug_fw;
#define WIL_NAME "wil6210"
#define WIL_FW_NAME "wil6210.fw" /* code */
-#define WIL_FW2_NAME "wil6210.board" /* board & radio parameters */
+#define WIL_FW2_NAME "wil6210.brd" /* board & radio parameters */
#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
@@ -279,7 +281,7 @@ struct fw_map {
};
/* array size should be in sync with actual definition in the wmi.c */
-extern const struct fw_map fw_mapping[7];
+extern const struct fw_map fw_mapping[8];
/**
* mk_cidxtid - construct @cidxtid field
@@ -396,6 +398,7 @@ struct vring {
* Additional data for Tx Vring
*/
struct vring_tx_data {
+ bool dot1x_open;
int enabled;
cycles_t idle, last_idle, begin;
u8 agg_wsize; /* agreed aggregation window, 0 - no agg */
@@ -461,6 +464,7 @@ enum wil_sta_status {
};
#define WIL_STA_TID_NUM (16)
+#define WIL_MCS_MAX (12) /* Maximum MCS supported */
struct wil_net_stats {
unsigned long rx_packets;
@@ -470,6 +474,7 @@ struct wil_net_stats {
unsigned long tx_errors;
unsigned long rx_dropped;
u16 last_mcs_rx;
+ u64 rx_per_mcs[WIL_MCS_MAX + 1];
};
/**
@@ -484,7 +489,6 @@ struct wil_sta_info {
u8 addr[ETH_ALEN];
enum wil_sta_status status;
struct wil_net_stats stats;
- bool data_port_open; /* can send any data, not only EAPOL */
/* Rx BACK */
struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
spinlock_t tid_rx_lock; /* guarding tid_rx array */
@@ -526,6 +530,17 @@ struct wil_probe_client_req {
u8 cid;
};
+struct pmc_ctx {
+ /* alloc, free, and read operations must own the lock */
+ struct mutex lock;
+ struct vring_tx_desc *pring_va;
+ dma_addr_t pring_pa;
+ struct desc_alloc_info *descriptors;
+ int last_cmd_status;
+ int num_descriptors;
+ int descriptor_size;
+};
+
struct wil6210_priv {
struct pci_dev *pdev;
int n_msi;
@@ -610,6 +625,8 @@ struct wil6210_priv {
void *platform_handle;
struct wil_platform_ops platform_ops;
+
+ struct pmc_ctx pmc;
};
#define wil_to_wiphy(i) (i->wdev->wiphy)
@@ -669,7 +686,7 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
size_t count);
-void *wil_if_alloc(struct device *dev, void __iomem *csr);
+void *wil_if_alloc(struct device *dev);
void wil_if_free(struct wil6210_priv *wil);
int wil_if_add(struct wil6210_priv *wil);
void wil_if_remove(struct wil6210_priv *wil);
@@ -701,9 +718,10 @@ int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid);
int wmi_set_channel(struct wil6210_priv *wil, int channel);
int wmi_get_channel(struct wil6210_priv *wil, int *channel);
int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
- const void *mac_addr);
+ const void *mac_addr, int key_usage);
int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
- const void *mac_addr, int key_len, const void *key);
+ const void *mac_addr, int key_len, const void *key,
+ int key_usage);
int wmi_echo(struct wil6210_priv *wil);
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
@@ -746,7 +764,8 @@ struct wireless_dev *wil_cfg80211_init(struct device *dev);
void wil_wdev_free(struct wil6210_priv *wil);
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
-int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
+int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
+ u8 chan, u8 hidden_ssid);
int wmi_pcp_stop(struct wil6210_priv *wil);
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
u16 reason_code, bool from_event);
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c
index 976a071ba74e..de15f1422fe9 100644
--- a/drivers/net/wireless/ath/wil6210/wil_platform.c
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.c
@@ -17,6 +17,15 @@
#include "linux/device.h"
#include "wil_platform.h"
+int __init wil_platform_modinit(void)
+{
+ return 0;
+}
+
+void wil_platform_modexit(void)
+{
+}
+
/**
* wil_platform_init() - wil6210 platform module init
*
@@ -26,10 +35,11 @@
*/
void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops)
{
- void *handle = NULL;
+ void *handle = ops; /* to return some non-NULL for 'void' impl. */
if (!ops) {
- dev_err(dev, "Invalid parameter. Cannot init platform module\n");
+ dev_err(dev,
+ "Invalid parameter. Cannot init platform module\n");
return NULL;
}
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h
index 158c73b049a9..d7fa19b7886d 100644
--- a/drivers/net/wireless/ath/wil6210/wil_platform.h
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.h
@@ -31,4 +31,7 @@ struct wil_platform_ops {
void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops);
+int __init wil_platform_modinit(void);
+void wil_platform_modexit(void);
+
#endif /* __WIL_PLATFORM_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 9fe2085be2c5..c759759afbb2 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.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
@@ -85,6 +85,7 @@ const struct fw_map fw_mapping[] = {
{0x880000, 0x88a000, 0x880000, "rgf"}, /* various RGF 40k */
{0x88a000, 0x88b000, 0x88a000, "AGC_tbl"}, /* AGC table 4k */
{0x88b000, 0x88c000, 0x88b000, "rgf_ext"}, /* Pcie_ext_rgf 4k */
+ {0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext"}, /* mac_ext_rgf 512b */
{0x8c0000, 0x949000, 0x8c0000, "upper"}, /* upper area 548k */
/*
* 920000..930000 ucode code RAM
@@ -543,55 +544,22 @@ 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)
+static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len)
{
- struct vring_tx_data *t;
- int i;
+ struct wmi_vring_en_event *evt = d;
+ u8 vri = evt->vring_index;
- 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_dbg_wmi(wil, "Enable vring %d\n", vri);
- wil_addba_tx_request(wil, i, wsize);
- }
-}
-
-static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
-{
- struct wmi_data_port_open_event *evt = d;
- u8 cid = evt->cid;
-
- wil_dbg_wmi(wil, "Link UP for CID %d\n", cid);
-
- if (cid >= ARRAY_SIZE(wil->sta)) {
- wil_err(wil, "Link UP for invalid CID %d\n", cid);
+ if (vri >= ARRAY_SIZE(wil->vring_tx)) {
+ wil_err(wil, "Enable for invalid vring %d\n", vri);
return;
}
-
- wil->sta[cid].data_port_open = true;
- 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)
-{
- struct net_device *ndev = wil_to_ndev(wil);
- struct wmi_wbe_link_down_event *evt = d;
- u8 cid = evt->cid;
-
- wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n",
- cid, le32_to_cpu(evt->reason));
-
- if (cid >= ARRAY_SIZE(wil->sta)) {
- wil_err(wil, "Link DOWN for invalid CID %d\n", cid);
+ wil->vring_tx_data[vri].dot1x_open = true;
+ if (vri == wil->bcast_vring) /* no BA for bcast */
return;
- }
-
- wil->sta[cid].data_port_open = false;
- netif_carrier_off(ndev);
+ if (agg_wsize >= 0)
+ wil_addba_tx_request(wil, vri, agg_wsize);
}
static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
@@ -695,11 +663,10 @@ static const struct {
{WMI_CONNECT_EVENTID, wmi_evt_connect},
{WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
{WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
- {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},
+ {WMI_VRING_EN_EVENTID, wmi_evt_vring_en},
};
/*
@@ -844,7 +811,7 @@ int wmi_echo(struct wil6210_priv *wil)
};
return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
- WMI_ECHO_RSP_EVENTID, NULL, 0, 20);
+ WMI_ECHO_RSP_EVENTID, NULL, 0, 50);
}
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
@@ -858,7 +825,8 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
}
-int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
+int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
+ u8 chan, u8 hidden_ssid)
{
int rc;
@@ -868,6 +836,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
.disable_sec_offload = 1,
.channel = chan - 1,
.pcp_max_assoc_sta = max_assoc_sta,
+ .hidden_ssid = hidden_ssid,
};
struct {
struct wil6210_mbox_hdr_wmi wmi;
@@ -985,7 +954,7 @@ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel)
}
int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
- const void *mac_addr)
+ const void *mac_addr, int key_usage)
{
struct wmi_delete_cipher_key_cmd cmd = {
.key_index = key_index,
@@ -998,11 +967,12 @@ int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
}
int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
- const void *mac_addr, int key_len, const void *key)
+ const void *mac_addr, int key_len, const void *key,
+ int key_usage)
{
struct wmi_add_cipher_key_cmd cmd = {
.key_index = key_index,
- .key_usage = WMI_KEY_USE_PAIRWISE,
+ .key_usage = key_usage,
.key_len = key_len,
};
@@ -1238,7 +1208,8 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
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);
+ WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply),
+ 100);
if (rc)
return rc;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index b29055315350..6e90e78f1554 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
* Copyright (c) 2006-2012 Wilocity .
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -253,8 +253,8 @@ struct wmi_set_passphrase_cmd {
*/
enum wmi_key_usage {
WMI_KEY_USE_PAIRWISE = 0,
- WMI_KEY_USE_GROUP = 1,
- WMI_KEY_USE_TX = 2, /* default Tx Key - Static WEP only */
+ WMI_KEY_USE_RX_GROUP = 1,
+ WMI_KEY_USE_TX_GROUP = 2,
};
struct wmi_add_cipher_key_cmd {
@@ -495,10 +495,18 @@ struct wmi_power_mgmt_cfg_cmd {
/*
* WMI_PCP_START_CMDID
*/
+
+enum wmi_hidden_ssid {
+ WMI_HIDDEN_SSID_DISABLED = 0,
+ WMI_HIDDEN_SSID_SEND_EMPTY = 1,
+ WMI_HIDDEN_SSID_CLEAR = 2,
+};
+
struct wmi_pcp_start_cmd {
__le16 bcon_interval;
u8 pcp_max_assoc_sta;
- u8 reserved0[9];
+ u8 hidden_ssid;
+ u8 reserved0[8];
u8 network_type;
u8 channel;
u8 disable_sec_offload;
@@ -836,6 +844,21 @@ struct wmi_temp_sense_cmd {
} __packed;
/*
+ * WMI_PMC_CMDID
+ */
+enum wmi_pmc_op_e {
+ WMI_PMC_ALLOCATE = 0,
+ WMI_PMC_RELEASE = 1,
+};
+
+struct wmi_pmc_cmd {
+ u8 op; /* enum wmi_pmc_cmd_op_type */
+ u8 reserved;
+ __le16 ring_size;
+ __le64 mem_base;
+} __packed;
+
+/*
* WMI Events
*/
@@ -870,7 +893,7 @@ enum wmi_event_id {
WMI_VRING_CFG_DONE_EVENTID = 0x1821,
WMI_BA_STATUS_EVENTID = 0x1823,
WMI_RCP_ADDBA_REQ_EVENTID = 0x1824,
- WMI_ADDBA_RESP_SENT_EVENTID = 0x1825,
+ WMI_RCP_ADDBA_RESP_SENT_EVENTID = 0x1825,
WMI_DELBA_EVENTID = 0x1826,
WMI_GET_SSID_EVENTID = 0x1828,
WMI_GET_PCP_CHANNEL_EVENTID = 0x182a,
@@ -882,7 +905,7 @@ enum wmi_event_id {
WMI_WRITE_MAC_TXQ_EVENTID = 0x1833,
WMI_WRITE_MAC_XQ_FIELD_EVENTID = 0x1834,
- WMI_BEAFORMING_MGMT_DONE_EVENTID = 0x1836,
+ WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836,
WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837,
WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839,
WMI_RS_MGMT_DONE_EVENTID = 0x1852,
@@ -894,11 +917,12 @@ enum wmi_event_id {
/* Performance monitoring events */
WMI_DATA_PORT_OPEN_EVENTID = 0x1860,
- WMI_WBE_LINKDOWN_EVENTID = 0x1861,
+ WMI_WBE_LINK_DOWN_EVENTID = 0x1861,
WMI_BF_CTRL_DONE_EVENTID = 0x1862,
WMI_NOTIFY_REQ_DONE_EVENTID = 0x1863,
WMI_GET_STATUS_DONE_EVENTID = 0x1864,
+ WMI_VRING_EN_EVENTID = 0x1865,
WMI_UNIT_TEST_EVENTID = 0x1900,
WMI_FLASH_READ_DONE_EVENTID = 0x1902,
@@ -1147,7 +1171,7 @@ struct wmi_vring_cfg_done_event {
} __packed;
/*
- * WMI_ADDBA_RESP_SENT_EVENTID
+ * WMI_RCP_ADDBA_RESP_SENT_EVENTID
*/
struct wmi_rcp_addba_resp_sent_event {
u8 cidxtid;
@@ -1179,7 +1203,7 @@ struct wmi_cfg_rx_chain_done_event {
} __packed;
/*
- * WMI_WBE_LINKDOWN_EVENTID
+ * WMI_WBE_LINK_DOWN_EVENTID
*/
enum wmi_wbe_link_down_event_reason {
WMI_WBE_REASON_USER_REQUEST = 0,
@@ -1202,6 +1226,14 @@ struct wmi_data_port_open_event {
} __packed;
/*
+ * WMI_VRING_EN_EVENTID
+ */
+struct wmi_vring_en_event {
+ u8 vring_index;
+ u8 reserved[3];
+} __packed;
+
+/*
* WMI_GET_PCP_CHANNEL_EVENTID
*/
struct wmi_get_pcp_channel_event {
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index b2f9521fe551..28490702124a 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3131,8 +3131,6 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
ctl |= B43_MACCTL_KEEP_BAD;
if (wl->filter_flags & FIF_PLCPFAIL)
ctl |= B43_MACCTL_KEEP_BADPLCP;
- if (wl->filter_flags & FIF_PROMISC_IN_BSS)
- ctl |= B43_MACCTL_PROMISC;
if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
ctl |= B43_MACCTL_BEACPROMISC;
@@ -4310,16 +4308,14 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw,
goto out_unlock;
}
- *fflags &= FIF_PROMISC_IN_BSS |
- FIF_ALLMULTI |
+ *fflags &= FIF_ALLMULTI |
FIF_FCSFAIL |
FIF_PLCPFAIL |
FIF_CONTROL |
FIF_OTHER_BSS |
FIF_BCN_PRBRESP_PROMISC;
- changed &= FIF_PROMISC_IN_BSS |
- FIF_ALLMULTI |
+ changed &= FIF_ALLMULTI |
FIF_FCSFAIL |
FIF_PLCPFAIL |
FIF_CONTROL |
@@ -5365,6 +5361,10 @@ static void b43_supported_bands(struct b43_wldev *dev, bool *have_2ghz_phy,
*have_5ghz_phy = true;
return;
case 0x4321: /* BCM4306 */
+ /* There are 14e4:4321 PCI devs with 2.4 GHz BCM4321 (N-PHY) */
+ if (dev->phy.type != B43_PHYTYPE_G)
+ break;
+ /* fall through */
case 0x4313: /* BCM4311 */
case 0x431a: /* BCM4318 */
case 0x432a: /* BCM4321 */
@@ -5609,8 +5609,8 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
wl = hw_to_b43_wl(hw);
/* fill hw info */
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_DBM;
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index c77b7f59505c..afc1fb3e38df 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2055,8 +2055,6 @@ static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev)
ctl |= B43legacy_MACCTL_KEEP_BAD;
if (wl->filter_flags & FIF_PLCPFAIL)
ctl |= B43legacy_MACCTL_KEEP_BADPLCP;
- if (wl->filter_flags & FIF_PROMISC_IN_BSS)
- ctl |= B43legacy_MACCTL_PROMISC;
if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
ctl |= B43legacy_MACCTL_BEACPROMISC;
@@ -2922,16 +2920,14 @@ static void b43legacy_op_configure_filter(struct ieee80211_hw *hw,
}
spin_lock_irqsave(&wl->irq_lock, flags);
- *fflags &= FIF_PROMISC_IN_BSS |
- FIF_ALLMULTI |
+ *fflags &= FIF_ALLMULTI |
FIF_FCSFAIL |
FIF_PLCPFAIL |
FIF_CONTROL |
FIF_OTHER_BSS |
FIF_BCN_PRBRESP_PROMISC;
- changed &= FIF_PROMISC_IN_BSS |
- FIF_ALLMULTI |
+ changed &= FIF_ALLMULTI |
FIF_FCSFAIL |
FIF_PLCPFAIL |
FIF_CONTROL |
@@ -3836,8 +3832,9 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
}
/* fill hw info */
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_DBM;
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index 9b508bd3b839..410a6645d316 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -33,6 +33,7 @@
#include <linux/suspend.h>
#include <linux/errno.h>
#include <linux/module.h>
+#include <linux/acpi.h>
#include <net/cfg80211.h>
#include <defs.h>
@@ -987,6 +988,7 @@ static void brcmf_sdiod_freezer_detach(struct brcmf_sdio_dev *sdiodev)
static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
{
+ sdiodev->state = BRCMF_SDIOD_DOWN;
if (sdiodev->bus) {
brcmf_sdio_remove(sdiodev->bus);
sdiodev->bus = NULL;
@@ -1011,6 +1013,14 @@ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
return 0;
}
+static void brcmf_sdiod_host_fixup(struct mmc_host *host)
+{
+ /* runtime-pm powers off the device */
+ pm_runtime_forbid(host->parent);
+ /* avoid removal detection upon resume */
+ host->caps |= MMC_CAP_NONREMOVABLE;
+}
+
static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
{
struct sdio_func *func;
@@ -1076,7 +1086,7 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
ret = -ENODEV;
goto out;
}
- pm_runtime_forbid(host->parent);
+ brcmf_sdiod_host_fixup(host);
out:
if (ret)
brcmf_sdiod_remove(sdiodev);
@@ -1108,12 +1118,25 @@ MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
+static void brcmf_sdiod_acpi_set_power_manageable(struct device *dev,
+ int val)
+{
+#if IS_ENABLED(CONFIG_ACPI)
+ struct acpi_device *adev;
+
+ adev = ACPI_COMPANION(dev);
+ if (adev)
+ adev->flags.power_manageable = 0;
+#endif
+}
+
static int brcmf_ops_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
int err;
struct brcmf_sdio_dev *sdiodev;
struct brcmf_bus *bus_if;
+ struct device *dev;
brcmf_dbg(SDIO, "Enter\n");
brcmf_dbg(SDIO, "Class=%x\n", func->class);
@@ -1121,6 +1144,10 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
brcmf_dbg(SDIO, "Function#: %d\n", func->num);
+ dev = &func->dev;
+ /* prohibit ACPI power management for this device */
+ brcmf_sdiod_acpi_set_power_manageable(dev, 0);
+
/* Consume func num 1 but dont do anything with it. */
if (func->num == 1)
return 0;
@@ -1246,15 +1273,15 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
brcmf_sdiod_freezer_on(sdiodev);
brcmf_sdio_wd_timer(sdiodev->bus, 0);
+ sdio_flags = MMC_PM_KEEP_POWER;
if (sdiodev->wowl_enabled) {
- sdio_flags = MMC_PM_KEEP_POWER;
if (sdiodev->pdata->oob_irq_supported)
enable_irq_wake(sdiodev->pdata->oob_irq_nr);
else
- sdio_flags = MMC_PM_WAKE_SDIO_IRQ;
- if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags))
- brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
+ sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
}
+ if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags))
+ brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
return 0;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
index 8a15ebbce4a3..d86d1f1f1c91 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
@@ -52,8 +52,6 @@
#define BRCMF_PNO_SCAN_COMPLETE 1
#define BRCMF_PNO_SCAN_INCOMPLETE 0
-#define BRCMF_IFACE_MAX_CNT 3
-
#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
#define WPA_OUI_TYPE 1
#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
@@ -129,13 +127,47 @@ static struct ieee80211_rate __wl_rates[] = {
RATETAB_ENT(BRCM_RATE_54M, 0),
};
-#define wl_a_rates (__wl_rates + 4)
-#define wl_a_rates_size 8
#define wl_g_rates (__wl_rates + 0)
-#define wl_g_rates_size 12
+#define wl_g_rates_size ARRAY_SIZE(__wl_rates)
+#define wl_a_rates (__wl_rates + 4)
+#define wl_a_rates_size (wl_g_rates_size - 4)
+
+#define CHAN2G(_channel, _freq) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_channel), \
+ .flags = IEEE80211_CHAN_DISABLED, \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+#define CHAN5G(_channel) { \
+ .band = IEEE80211_BAND_5GHZ, \
+ .center_freq = 5000 + (5 * (_channel)), \
+ .hw_value = (_channel), \
+ .flags = IEEE80211_CHAN_DISABLED, \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+static struct ieee80211_channel __wl_2ghz_channels[] = {
+ CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427),
+ CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447),
+ CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467),
+ CHAN2G(13, 2472), CHAN2G(14, 2484)
+};
+
+static struct ieee80211_channel __wl_5ghz_channels[] = {
+ CHAN5G(34), CHAN5G(36), CHAN5G(38), CHAN5G(40), CHAN5G(42),
+ CHAN5G(44), CHAN5G(46), CHAN5G(48), CHAN5G(52), CHAN5G(56),
+ CHAN5G(60), CHAN5G(64), CHAN5G(100), CHAN5G(104), CHAN5G(108),
+ CHAN5G(112), CHAN5G(116), CHAN5G(120), CHAN5G(124), CHAN5G(128),
+ CHAN5G(132), CHAN5G(136), CHAN5G(140), CHAN5G(144), CHAN5G(149),
+ CHAN5G(153), CHAN5G(157), CHAN5G(161), CHAN5G(165)
+};
/* Band templates duplicated per wiphy. The channel info
- * is filled in after querying the device.
+ * above is added to the band during setup.
*/
static const struct ieee80211_supported_band __wl_band_2ghz = {
.band = IEEE80211_BAND_2GHZ,
@@ -143,7 +175,7 @@ static const struct ieee80211_supported_band __wl_band_2ghz = {
.n_bitrates = wl_g_rates_size,
};
-static const struct ieee80211_supported_band __wl_band_5ghz_a = {
+static const struct ieee80211_supported_band __wl_band_5ghz = {
.band = IEEE80211_BAND_5GHZ,
.bitrates = wl_a_rates,
.n_bitrates = wl_a_rates_size,
@@ -1262,7 +1294,7 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
}
clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
- GFP_KERNEL);
+ true, GFP_KERNEL);
}
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
@@ -1928,7 +1960,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
- cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
+ cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
scbval.val = cpu_to_le32(reason_code);
@@ -2364,27 +2396,80 @@ brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
brcmf_err("set wsec error (%d)\n", err);
}
+static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)
+{
+ struct nl80211_sta_flag_update *sfu;
+
+ brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags);
+ si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
+ sfu = &si->sta_flags;
+ sfu->mask = BIT(NL80211_STA_FLAG_WME) |
+ BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+ BIT(NL80211_STA_FLAG_ASSOCIATED) |
+ BIT(NL80211_STA_FLAG_AUTHORIZED);
+ if (fw_sta_flags & BRCMF_STA_WME)
+ sfu->set |= BIT(NL80211_STA_FLAG_WME);
+ if (fw_sta_flags & BRCMF_STA_AUTHE)
+ sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
+ if (fw_sta_flags & BRCMF_STA_ASSOC)
+ sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
+ if (fw_sta_flags & BRCMF_STA_AUTHO)
+ sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
+}
+
+static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
+{
+ struct {
+ __le32 len;
+ struct brcmf_bss_info_le bss_le;
+ } *buf;
+ u16 capability;
+ int err;
+
+ buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ buf->len = cpu_to_le32(WL_BSS_INFO_MAX);
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf,
+ WL_BSS_INFO_MAX);
+ if (err) {
+ brcmf_err("Failed to get bss info (%d)\n", err);
+ return;
+ }
+ si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
+ si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
+ si->bss_param.dtim_period = buf->bss_le.dtim_period;
+ capability = le16_to_cpu(buf->bss_le.capability);
+ if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT)
+ si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
+ if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
+ if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
+}
+
static s32
brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
const u8 *mac, struct station_info *sinfo)
{
struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
- struct brcmf_scb_val_le scb_val;
- int rssi;
- s32 rate;
s32 err = 0;
- u8 *bssid = profile->bssid;
struct brcmf_sta_info_le sta_info_le;
- u32 beacon_period;
- u32 dtim_period;
+ u32 sta_flags;
+ u32 is_tdls_peer;
brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
if (!check_vif_up(ifp->vif))
return -EIO;
- if (brcmf_is_apmode(ifp->vif)) {
- memcpy(&sta_info_le, mac, ETH_ALEN);
+ memset(&sta_info_le, 0, sizeof(sta_info_le));
+ memcpy(&sta_info_le, mac, ETH_ALEN);
+ err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info",
+ &sta_info_le,
+ sizeof(sta_info_le));
+ is_tdls_peer = !err;
+ if (err) {
err = brcmf_fil_iovar_data_get(ifp, "sta_info",
&sta_info_le,
sizeof(sta_info_le));
@@ -2392,73 +2477,48 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
brcmf_err("GET STA INFO failed, %d\n", err);
goto done;
}
- 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 |= 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",
- sinfo->inactive_time, sinfo->connected_time);
- } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {
- if (memcmp(mac, bssid, ETH_ALEN)) {
- brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
- mac, bssid);
- err = -ENOENT;
- goto done;
- }
- /* Report the current tx rate */
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
- if (err) {
- brcmf_err("Could not get rate (%d)\n", err);
- goto done;
- } else {
+ }
+ brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver));
+ sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
+ sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
+ sta_flags = le32_to_cpu(sta_info_le.flags);
+ brcmf_convert_sta_flags(sta_flags, sinfo);
+ sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+ if (is_tdls_peer)
+ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+ else
+ sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
+ if (sta_flags & BRCMF_STA_ASSOC) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
+ sinfo->connected_time = le32_to_cpu(sta_info_le.in);
+ brcmf_fill_bss_param(ifp, sinfo);
+ }
+ if (sta_flags & BRCMF_STA_SCBSTATS) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
+ sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures);
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
+ sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts);
+ sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts);
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
+ sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts);
+ sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts);
+ if (sinfo->tx_packets) {
sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
- sinfo->txrate.legacy = rate * 5;
- brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
+ sinfo->txrate.legacy = le32_to_cpu(sta_info_le.tx_rate);
+ sinfo->txrate.legacy /= 100;
}
-
- if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
- &ifp->vif->sme_state)) {
- memset(&scb_val, 0, sizeof(scb_val));
- err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
- &scb_val, sizeof(scb_val));
- if (err) {
- brcmf_err("Could not get rssi (%d)\n", err);
- goto done;
- } else {
- rssi = le32_to_cpu(scb_val.val);
- sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
- sinfo->signal = rssi;
- brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
- }
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
- &beacon_period);
- if (err) {
- brcmf_err("Could not get beacon period (%d)\n",
- err);
- goto done;
- } else {
- sinfo->bss_param.beacon_interval =
- beacon_period;
- brcmf_dbg(CONN, "Beacon peroid %d\n",
- beacon_period);
- }
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
- &dtim_period);
- if (err) {
- brcmf_err("Could not get DTIM period (%d)\n",
- err);
- goto done;
- } else {
- sinfo->bss_param.dtim_period = dtim_period;
- brcmf_dbg(CONN, "DTIM peroid %d\n",
- dtim_period);
- }
- sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
+ if (sinfo->rx_packets) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
+ sinfo->rxrate.legacy = le32_to_cpu(sta_info_le.rx_rate);
+ sinfo->rxrate.legacy /= 100;
}
- } else
- err = -EPERM;
+ if (le16_to_cpu(sta_info_le.ver) >= 4) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
+ sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes);
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
+ sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
+ }
+ }
done:
brcmf_dbg(TRACE, "Exit\n");
return err;
@@ -5253,40 +5313,6 @@ dongle_scantime_out:
return err;
}
-/* Filter the list of channels received from firmware counting only
- * the 20MHz channels. The wiphy band data only needs those which get
- * flagged to indicate if they can take part in higher bandwidth.
- */
-static void brcmf_count_20mhz_channels(struct brcmf_cfg80211_info *cfg,
- struct brcmf_chanspec_list *chlist,
- u32 chcnt[])
-{
- u32 total = le32_to_cpu(chlist->count);
- struct brcmu_chan ch;
- int i;
-
- for (i = 0; i < total; i++) {
- ch.chspec = (u16)le32_to_cpu(chlist->element[i]);
- cfg->d11inf.decchspec(&ch);
-
- /* Firmware gives a ordered list. We skip non-20MHz
- * channels is 2G. For 5G we can abort upon reaching
- * a non-20MHz channel in the list.
- */
- if (ch.bw != BRCMU_CHAN_BW_20) {
- if (ch.band == BRCMU_CHAN_BAND_5G)
- break;
- else
- continue;
- }
-
- if (ch.band == BRCMU_CHAN_BAND_2G)
- chcnt[0] += 1;
- else if (ch.band == BRCMU_CHAN_BAND_5G)
- chcnt[1] += 1;
- }
-}
-
static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
struct brcmu_chan *ch)
{
@@ -5322,7 +5348,6 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
u32 i, j;
u32 total;
u32 chaninfo;
- u32 chcnt[2] = { 0, 0 };
u32 index;
pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
@@ -5339,42 +5364,15 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
goto fail_pbuf;
}
- brcmf_count_20mhz_channels(cfg, list, chcnt);
wiphy = cfg_to_wiphy(cfg);
- if (chcnt[0]) {
- band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
- GFP_KERNEL);
- if (band == NULL) {
- err = -ENOMEM;
- goto fail_pbuf;
- }
- band->channels = kcalloc(chcnt[0], sizeof(*channel),
- GFP_KERNEL);
- if (band->channels == NULL) {
- kfree(band);
- err = -ENOMEM;
- goto fail_pbuf;
- }
- band->n_channels = 0;
- wiphy->bands[IEEE80211_BAND_2GHZ] = band;
- }
- if (chcnt[1]) {
- band = kmemdup(&__wl_band_5ghz_a, sizeof(__wl_band_5ghz_a),
- GFP_KERNEL);
- if (band == NULL) {
- err = -ENOMEM;
- goto fail_band2g;
- }
- band->channels = kcalloc(chcnt[1], sizeof(*channel),
- GFP_KERNEL);
- if (band->channels == NULL) {
- kfree(band);
- err = -ENOMEM;
- goto fail_band2g;
- }
- band->n_channels = 0;
- wiphy->bands[IEEE80211_BAND_5GHZ] = band;
- }
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ if (band)
+ for (i = 0; i < band->n_channels; i++)
+ band->channels[i].flags = IEEE80211_CHAN_DISABLED;
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (band)
+ for (i = 0; i < band->n_channels; i++)
+ band->channels[i].flags = IEEE80211_CHAN_DISABLED;
total = le32_to_cpu(list->count);
for (i = 0; i < total; i++) {
@@ -5389,6 +5387,8 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
continue;
}
+ if (!band)
+ continue;
if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
ch.bw == BRCMU_CHAN_BW_40)
continue;
@@ -5416,9 +5416,9 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
} else if (ch.bw == BRCMU_CHAN_BW_40) {
brcmf_update_bw40_channel_flag(&channel[index], &ch);
} else {
- /* disable other bandwidths for now as mentioned
- * order assure they are enabled for subsequent
- * chanspecs.
+ /* enable the channel and disable other bandwidths
+ * for now as mentioned order assure they are enabled
+ * for subsequent chanspecs.
*/
channel[index].flags = IEEE80211_CHAN_NO_HT40 |
IEEE80211_CHAN_NO_80MHZ;
@@ -5437,16 +5437,8 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
IEEE80211_CHAN_NO_IR;
}
}
- if (index == band->n_channels)
- band->n_channels++;
}
- kfree(pbuf);
- return 0;
-fail_band2g:
- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
- kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
- wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
fail_pbuf:
kfree(pbuf);
return err;
@@ -5674,53 +5666,6 @@ static int brcmf_setup_wiphybands(struct wiphy *wiphy)
return 0;
}
-static const struct ieee80211_iface_limit brcmf_iface_limits_mbss[] = {
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC)
- },
- {
- .max = 4,
- .types = BIT(NL80211_IFTYPE_AP)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
- }
-};
-
-static const struct ieee80211_iface_limit brcmf_iface_limits_sbss[] = {
- {
- .max = 2,
- .types = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
- }
-};
-static struct ieee80211_iface_combination brcmf_iface_combos[] = {
- {
- .max_interfaces = BRCMF_IFACE_MAX_CNT,
- .num_different_channels = 1,
- .n_limits = ARRAY_SIZE(brcmf_iface_limits_sbss),
- .limits = brcmf_iface_limits_sbss,
- }
-};
-
static const struct ieee80211_txrx_stypes
brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
[NL80211_IFTYPE_STATION] = {
@@ -5750,6 +5695,67 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
}
};
+static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
+{
+ struct ieee80211_iface_combination *combo = NULL;
+ struct ieee80211_iface_limit *limits = NULL;
+ int i = 0, max_iface_cnt;
+
+ combo = kzalloc(sizeof(*combo), GFP_KERNEL);
+ if (!combo)
+ goto err;
+
+ limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL);
+ if (!limits)
+ goto err;
+
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP);
+
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
+ combo->num_different_channels = 2;
+ else
+ combo->num_different_channels = 1;
+
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
+ limits[i].max = 1;
+ limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+ limits[i].max = 4;
+ limits[i++].types = BIT(NL80211_IFTYPE_AP);
+ max_iface_cnt = 5;
+ } else {
+ limits[i].max = 2;
+ limits[i++].types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP);
+ max_iface_cnt = 2;
+ }
+
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) {
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_DEVICE);
+ limits[i].max = 1;
+ limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO);
+ limits[i].max = 1;
+ limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
+ max_iface_cnt += 2;
+ }
+ combo->max_interfaces = max_iface_cnt;
+ combo->limits = limits;
+ combo->n_limits = i;
+
+ wiphy->iface_combinations = combo;
+ wiphy->n_iface_combinations = 1;
+ return 0;
+
+err:
+ kfree(limits);
+ kfree(combo);
+ return -ENOMEM;
+}
+
static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
{
/* scheduled scan settings */
@@ -5779,28 +5785,19 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)
static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
{
- struct ieee80211_iface_combination ifc_combo;
+ struct ieee80211_supported_band *band;
+ __le32 bandlist[3];
+ u32 n_bands;
+ int err, i;
+
wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
- wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO) |
- BIT(NL80211_IFTYPE_P2P_DEVICE);
- /* need VSDB firmware feature for concurrent channels */
- ifc_combo = brcmf_iface_combos[0];
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
- ifc_combo.num_different_channels = 2;
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
- ifc_combo.n_limits = ARRAY_SIZE(brcmf_iface_limits_mbss),
- ifc_combo.limits = brcmf_iface_limits_mbss;
- }
- wiphy->iface_combinations = kmemdup(&ifc_combo,
- sizeof(ifc_combo),
- GFP_KERNEL);
- wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
+
+ err = brcmf_setup_ifmodes(wiphy, ifp);
+ if (err)
+ return err;
+
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->cipher_suites = __wl_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
@@ -5812,7 +5809,8 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
wiphy->mgmt_stypes = brcmf_txrx_stypes;
wiphy->max_remain_on_channel_duration = 5000;
- brcmf_wiphy_pno_params(wiphy);
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
+ brcmf_wiphy_pno_params(wiphy);
/* vendor commands/events support */
wiphy->vendor_commands = brcmf_vendor_cmds;
@@ -5821,7 +5819,52 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
brcmf_wiphy_wowl_params(wiphy);
- return brcmf_setup_wiphybands(wiphy);
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, &bandlist,
+ sizeof(bandlist));
+ if (err) {
+ brcmf_err("could not obtain band info: err=%d\n", err);
+ return err;
+ }
+ /* first entry in bandlist is number of bands */
+ n_bands = le32_to_cpu(bandlist[0]);
+ for (i = 1; i <= n_bands && i < ARRAY_SIZE(bandlist); i++) {
+ if (bandlist[i] == cpu_to_le32(WLC_BAND_2G)) {
+ band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
+ GFP_KERNEL);
+ if (!band)
+ return -ENOMEM;
+
+ band->channels = kmemdup(&__wl_2ghz_channels,
+ sizeof(__wl_2ghz_channels),
+ GFP_KERNEL);
+ if (!band->channels) {
+ kfree(band);
+ return -ENOMEM;
+ }
+
+ band->n_channels = ARRAY_SIZE(__wl_2ghz_channels);
+ wiphy->bands[IEEE80211_BAND_2GHZ] = band;
+ }
+ if (bandlist[i] == cpu_to_le32(WLC_BAND_5G)) {
+ band = kmemdup(&__wl_band_5ghz, sizeof(__wl_band_5ghz),
+ GFP_KERNEL);
+ if (!band)
+ return -ENOMEM;
+
+ band->channels = kmemdup(&__wl_5ghz_channels,
+ sizeof(__wl_5ghz_channels),
+ GFP_KERNEL);
+ if (!band->channels) {
+ kfree(band);
+ return -ENOMEM;
+ }
+
+ band->n_channels = ARRAY_SIZE(__wl_5ghz_channels);
+ wiphy->bands[IEEE80211_BAND_5GHZ] = band;
+ }
+ }
+ err = brcmf_setup_wiphybands(wiphy);
+ return err;
}
static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
@@ -6007,11 +6050,20 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
memset(&ccreq, 0, sizeof(ccreq));
ccreq.rev = cpu_to_le32(-1);
memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2));
- brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
+ if (brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq))) {
+ brcmf_err("firmware rejected country setting\n");
+ return;
+ }
+ brcmf_setup_wiphybands(wiphy);
}
static void brcmf_free_wiphy(struct wiphy *wiphy)
{
+ if (!wiphy)
+ return;
+
+ if (wiphy->iface_combinations)
+ kfree(wiphy->iface_combinations->limits);
kfree(wiphy->iface_combinations);
if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
@@ -6047,6 +6099,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
brcmf_err("Could not allocate wiphy device\n");
return NULL;
}
+ memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
set_wiphy_dev(wiphy, busdev);
cfg = wiphy_priv(wiphy);
@@ -6154,10 +6207,8 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
if (!cfg)
return;
- WARN_ON(!list_empty(&cfg->vif_list));
- wiphy_unregister(cfg->wiphy);
brcmf_btcoex_detach(cfg);
- brcmf_p2p_detach(&cfg->p2p);
+ wiphy_unregister(cfg->wiphy);
wl_deinit_priv(cfg);
brcmf_free_wiphy(cfg->wiphy);
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
index ab2fac8b2760..288f8314f208 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
@@ -649,6 +649,7 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci)
case BRCM_CC_43567_CHIP_ID:
case BRCM_CC_43569_CHIP_ID:
case BRCM_CC_43570_CHIP_ID:
+ case BRCM_CC_4358_CHIP_ID:
case BRCM_CC_43602_CHIP_ID:
return 0x180000;
default:
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.c b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c
index 77656c711bed..7b0e52195a85 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c
@@ -22,17 +22,6 @@
#include "core.h"
#include "commonring.h"
-
-/* dma flushing needs implementation for mips and arm platforms. Should
- * be put in util. Note, this is not real flushing. It is virtual non
- * cached memory. Only write buffers should have to be drained. Though
- * this may be different depending on platform......
- * SEE ALSO msgbuf.c
- */
-#define brcmf_dma_flush(addr, len)
-#define brcmf_dma_invalidate_cache(addr, len)
-
-
void brcmf_commonring_register_cb(struct brcmf_commonring *commonring,
int (*cr_ring_bell)(void *ctx),
int (*cr_update_rptr)(void *ctx),
@@ -206,14 +195,9 @@ int brcmf_commonring_write_complete(struct brcmf_commonring *commonring)
address = commonring->buf_addr;
address += (commonring->f_ptr * commonring->item_len);
if (commonring->f_ptr > commonring->w_ptr) {
- brcmf_dma_flush(address,
- (commonring->depth - commonring->f_ptr) *
- commonring->item_len);
address = commonring->buf_addr;
commonring->f_ptr = 0;
}
- brcmf_dma_flush(address, (commonring->w_ptr - commonring->f_ptr) *
- commonring->item_len);
commonring->f_ptr = commonring->w_ptr;
@@ -239,8 +223,6 @@ void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring,
void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
u16 *n_items)
{
- void *ret_addr;
-
if (commonring->cr_update_wptr)
commonring->cr_update_wptr(commonring->cr_ctx);
@@ -251,21 +233,18 @@ void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
if (*n_items == 0)
return NULL;
- ret_addr = commonring->buf_addr +
- (commonring->r_ptr * commonring->item_len);
-
- commonring->r_ptr += *n_items;
- if (commonring->r_ptr == commonring->depth)
- commonring->r_ptr = 0;
-
- brcmf_dma_invalidate_cache(ret_addr, *n_ items * commonring->item_len);
-
- return ret_addr;
+ return commonring->buf_addr +
+ (commonring->r_ptr * commonring->item_len);
}
-int brcmf_commonring_read_complete(struct brcmf_commonring *commonring)
+int brcmf_commonring_read_complete(struct brcmf_commonring *commonring,
+ u16 n_items)
{
+ commonring->r_ptr += n_items;
+ if (commonring->r_ptr == commonring->depth)
+ commonring->r_ptr = 0;
+
if (commonring->cr_write_rptr)
return commonring->cr_write_rptr(commonring->cr_ctx);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
index 3d404016a92e..b85033611c8d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
@@ -62,7 +62,8 @@ void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring,
u16 n_items);
void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
u16 *n_items);
-int brcmf_commonring_read_complete(struct brcmf_commonring *commonring);
+int brcmf_commonring_read_complete(struct brcmf_commonring *commonring,
+ u16 n_items);
#define brcmf_commonring_n_items(commonring) (commonring->depth)
#define brcmf_commonring_len_item(commonring) (commonring->item_len)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c
index f8f47dcfa886..fe9d3fbf5fe2 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -867,8 +867,6 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
}
/* unregister will take care of freeing it */
unregister_netdev(ifp->ndev);
- } else {
- kfree(ifp);
}
}
@@ -1100,6 +1098,8 @@ void brcmf_detach(struct device *dev)
/* stop firmware event handling */
brcmf_fweh_detach(drvr);
+ if (drvr->config)
+ brcmf_p2p_detach(&drvr->config->p2p);
brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/debug.c b/drivers/net/wireless/brcm80211/brcmfmac/debug.c
index 9b473d50b005..2d6d00553858 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.c
@@ -41,15 +41,6 @@ void brcmf_debugfs_exit(void)
root_folder = NULL;
}
-static int brcmf_debugfs_chipinfo_read(struct seq_file *seq, void *data)
-{
- struct brcmf_bus *bus = dev_get_drvdata(seq->private);
-
- seq_printf(seq, "chip: %x(%u) rev %u\n",
- bus->chip, bus->chip, bus->chiprev);
- return 0;
-}
-
int brcmf_debugfs_attach(struct brcmf_pub *drvr)
{
struct device *dev = drvr->bus_if->dev;
@@ -58,7 +49,6 @@ int brcmf_debugfs_attach(struct brcmf_pub *drvr)
return -ENODEV;
drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
- brcmf_debugfs_add_entry(drvr, "chipinfo", brcmf_debugfs_chipinfo_read);
return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
}
@@ -74,44 +64,12 @@ struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr)
return drvr->dbgfs_dir;
}
-struct brcmf_debugfs_entry {
- int (*read)(struct seq_file *seq, void *data);
- struct brcmf_pub *drvr;
-};
-
-static int brcmf_debugfs_entry_open(struct inode *inode, struct file *f)
-{
- struct brcmf_debugfs_entry *entry = inode->i_private;
-
- return single_open(f, entry->read, entry->drvr->bus_if->dev);
-}
-
-static const struct file_operations brcmf_debugfs_def_ops = {
- .owner = THIS_MODULE,
- .open = brcmf_debugfs_entry_open,
- .release = single_release,
- .read = seq_read,
- .llseek = seq_lseek
-};
-
int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
int (*read_fn)(struct seq_file *seq, void *data))
{
- struct dentry *dentry = drvr->dbgfs_dir;
- struct brcmf_debugfs_entry *entry;
-
- if (IS_ERR_OR_NULL(dentry))
- return -ENOENT;
-
- entry = devm_kzalloc(drvr->bus_if->dev, sizeof(*entry), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- entry->read = read_fn;
- entry->drvr = drvr;
-
- dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry,
- &brcmf_debugfs_def_ops);
+ struct dentry *e;
- return PTR_ERR_OR_ZERO(dentry);
+ e = debugfs_create_devm_seqfile(drvr->bus_if->dev, fn,
+ drvr->dbgfs_dir, read_fn);
+ return PTR_ERR_OR_ZERO(e);
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
index 7748a1ccf14f..1e94e94e01dc 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
@@ -124,10 +124,12 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
struct brcmf_if *ifp = drvr->iflist[0];
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
if (drvr->bus_if->wowl_supported)
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID)
brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_P2P, "p2p");
/* set chip related quirks */
switch (drvr->bus_if->chip) {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/brcm80211/brcmfmac/feature.h
index f5832e077bb7..6b381f799f22 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h
@@ -19,12 +19,18 @@
/*
* Features:
*
+ * MBSS: multiple BSSID support (eg. guest network in AP mode).
* MCHAN: multi-channel for concurrent P2P.
+ * PNO: preferred network offload.
+ * WOWL: Wake-On-WLAN.
+ * P2P: peer-to-peer
*/
#define BRCMF_FEAT_LIST \
BRCMF_FEAT_DEF(MBSS) \
BRCMF_FEAT_DEF(MCHAN) \
- BRCMF_FEAT_DEF(WOWL)
+ BRCMF_FEAT_DEF(PNO) \
+ BRCMF_FEAT_DEF(WOWL) \
+ BRCMF_FEAT_DEF(P2P)
/*
* Quirks:
*
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
index 9cb99152ad17..743f16b6a072 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
@@ -23,6 +23,10 @@
#include "debug.h"
#include "firmware.h"
+#define BRCMF_FW_MAX_NVRAM_SIZE 64000
+#define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */
+#define BRCMF_FW_NVRAM_PCIEDEV_LEN 10 /* pcie/1/4/ + \0 */
+
char brcmf_firmware_path[BRCMF_FW_PATH_LEN];
module_param_string(firmware_path, brcmf_firmware_path,
BRCMF_FW_PATH_LEN, 0440);
@@ -39,25 +43,35 @@ enum nvram_parser_state {
* struct nvram_parser - internal info for parser.
*
* @state: current parser state.
- * @fwnv: input buffer being parsed.
+ * @data: input buffer being parsed.
* @nvram: output buffer with parse result.
* @nvram_len: lenght of parse result.
* @line: current line.
* @column: current column in line.
* @pos: byte offset in input buffer.
* @entry: start position of key,value entry.
+ * @multi_dev_v1: detect pcie multi device v1 (compressed).
+ * @multi_dev_v2: detect pcie multi device v2.
*/
struct nvram_parser {
enum nvram_parser_state state;
- const struct firmware *fwnv;
+ const u8 *data;
u8 *nvram;
u32 nvram_len;
u32 line;
u32 column;
u32 pos;
u32 entry;
+ bool multi_dev_v1;
+ bool multi_dev_v2;
};
+/**
+ * is_nvram_char() - check if char is a valid one for NVRAM entry
+ *
+ * It accepts all printable ASCII chars except for '#' which opens a comment.
+ * Please note that ' ' (space) while accepted is not a valid key name char.
+ */
static bool is_nvram_char(char c)
{
/* comment marker excluded */
@@ -65,7 +79,7 @@ static bool is_nvram_char(char c)
return false;
/* key and value may have any other readable character */
- return (c > 0x20 && c < 0x7f);
+ return (c >= 0x20 && c < 0x7f);
}
static bool is_whitespace(char c)
@@ -77,7 +91,7 @@ static enum nvram_parser_state brcmf_nvram_handle_idle(struct nvram_parser *nvp)
{
char c;
- c = nvp->fwnv->data[nvp->pos];
+ c = nvp->data[nvp->pos];
if (c == '\n')
return COMMENT;
if (is_whitespace(c))
@@ -101,14 +115,18 @@ static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp)
enum nvram_parser_state st = nvp->state;
char c;
- c = nvp->fwnv->data[nvp->pos];
+ c = nvp->data[nvp->pos];
if (c == '=') {
/* ignore RAW1 by treating as comment */
- if (strncmp(&nvp->fwnv->data[nvp->entry], "RAW1", 4) == 0)
+ if (strncmp(&nvp->data[nvp->entry], "RAW1", 4) == 0)
st = COMMENT;
else
st = VALUE;
- } else if (!is_nvram_char(c)) {
+ if (strncmp(&nvp->data[nvp->entry], "devpath", 7) == 0)
+ nvp->multi_dev_v1 = true;
+ if (strncmp(&nvp->data[nvp->entry], "pcie/", 5) == 0)
+ nvp->multi_dev_v2 = true;
+ } else if (!is_nvram_char(c) || c == ' ') {
brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
nvp->line, nvp->column);
return COMMENT;
@@ -127,12 +145,14 @@ brcmf_nvram_handle_value(struct nvram_parser *nvp)
char *ekv;
u32 cplen;
- c = nvp->fwnv->data[nvp->pos];
+ c = nvp->data[nvp->pos];
if (!is_nvram_char(c)) {
/* key,value pair complete */
- ekv = (u8 *)&nvp->fwnv->data[nvp->pos];
- skv = (u8 *)&nvp->fwnv->data[nvp->entry];
+ ekv = (u8 *)&nvp->data[nvp->pos];
+ skv = (u8 *)&nvp->data[nvp->entry];
cplen = ekv - skv;
+ if (nvp->nvram_len + cplen + 1 >= BRCMF_FW_MAX_NVRAM_SIZE)
+ return END;
/* copy to output buffer */
memcpy(&nvp->nvram[nvp->nvram_len], skv, cplen);
nvp->nvram_len += cplen;
@@ -148,17 +168,20 @@ brcmf_nvram_handle_value(struct nvram_parser *nvp)
static enum nvram_parser_state
brcmf_nvram_handle_comment(struct nvram_parser *nvp)
{
- char *eol, *sol;
-
- sol = (char *)&nvp->fwnv->data[nvp->pos];
- eol = strchr(sol, '\n');
- if (eol == NULL)
- return END;
+ char *eoc, *sol;
+
+ sol = (char *)&nvp->data[nvp->pos];
+ eoc = strchr(sol, '\n');
+ if (!eoc) {
+ eoc = strchr(sol, '\0');
+ if (!eoc)
+ return END;
+ }
/* eat all moving to next line */
nvp->line++;
nvp->column = 1;
- nvp->pos += (eol - sol) + 1;
+ nvp->pos += (eoc - sol) + 1;
return IDLE;
}
@@ -178,12 +201,20 @@ static enum nvram_parser_state
};
static int brcmf_init_nvram_parser(struct nvram_parser *nvp,
- const struct firmware *nv)
+ const u8 *data, size_t data_len)
{
+ size_t size;
+
memset(nvp, 0, sizeof(*nvp));
- nvp->fwnv = nv;
+ nvp->data = data;
+ /* Limit size to MAX_NVRAM_SIZE, some files contain lot of comment */
+ if (data_len > BRCMF_FW_MAX_NVRAM_SIZE)
+ size = BRCMF_FW_MAX_NVRAM_SIZE;
+ else
+ size = data_len;
/* Alloc for extra 0 byte + roundup by 4 + length field */
- nvp->nvram = kzalloc(nv->size + 1 + 3 + sizeof(u32), GFP_KERNEL);
+ size += 1 + 3 + sizeof(u32);
+ nvp->nvram = kzalloc(size, GFP_KERNEL);
if (!nvp->nvram)
return -ENOMEM;
@@ -192,26 +223,171 @@ static int brcmf_init_nvram_parser(struct nvram_parser *nvp,
return 0;
}
+/* brcmf_fw_strip_multi_v1 :Some nvram files contain settings for multiple
+ * devices. Strip it down for one device, use domain_nr/bus_nr to determine
+ * which data is to be returned. v1 is the version where nvram is stored
+ * compressed and "devpath" maps to index for valid entries.
+ */
+static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr,
+ u16 bus_nr)
+{
+ /* Device path with a leading '=' key-value separator */
+ char pci_path[] = "=pci/?/?";
+ size_t pci_len;
+ char pcie_path[] = "=pcie/?/?";
+ size_t pcie_len;
+
+ u32 i, j;
+ bool found;
+ u8 *nvram;
+ u8 id;
+
+ nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
+ if (!nvram)
+ goto fail;
+
+ /* min length: devpath0=pcie/1/4/ + 0:x=y */
+ if (nvp->nvram_len < BRCMF_FW_NVRAM_DEVPATH_LEN + 6)
+ goto fail;
+
+ /* First search for the devpathX and see if it is the configuration
+ * for domain_nr/bus_nr. Search complete nvp
+ */
+ snprintf(pci_path, sizeof(pci_path), "=pci/%d/%d", domain_nr,
+ bus_nr);
+ pci_len = strlen(pci_path);
+ snprintf(pcie_path, sizeof(pcie_path), "=pcie/%d/%d", domain_nr,
+ bus_nr);
+ pcie_len = strlen(pcie_path);
+ found = false;
+ i = 0;
+ while (i < nvp->nvram_len - BRCMF_FW_NVRAM_DEVPATH_LEN) {
+ /* Format: devpathX=pcie/Y/Z/
+ * Y = domain_nr, Z = bus_nr, X = virtual ID
+ */
+ if (strncmp(&nvp->nvram[i], "devpath", 7) == 0 &&
+ (!strncmp(&nvp->nvram[i + 8], pci_path, pci_len) ||
+ !strncmp(&nvp->nvram[i + 8], pcie_path, pcie_len))) {
+ id = nvp->nvram[i + 7] - '0';
+ found = true;
+ break;
+ }
+ while (nvp->nvram[i] != 0)
+ i++;
+ i++;
+ }
+ if (!found)
+ goto fail;
+
+ /* Now copy all valid entries, release old nvram and assign new one */
+ i = 0;
+ j = 0;
+ while (i < nvp->nvram_len) {
+ if ((nvp->nvram[i] - '0' == id) && (nvp->nvram[i + 1] == ':')) {
+ i += 2;
+ while (nvp->nvram[i] != 0) {
+ nvram[j] = nvp->nvram[i];
+ i++;
+ j++;
+ }
+ nvram[j] = 0;
+ j++;
+ }
+ while (nvp->nvram[i] != 0)
+ i++;
+ i++;
+ }
+ kfree(nvp->nvram);
+ nvp->nvram = nvram;
+ nvp->nvram_len = j;
+ return;
+
+fail:
+ kfree(nvram);
+ nvp->nvram_len = 0;
+}
+
+/* brcmf_fw_strip_multi_v2 :Some nvram files contain settings for multiple
+ * devices. Strip it down for one device, use domain_nr/bus_nr to determine
+ * which data is to be returned. v2 is the version where nvram is stored
+ * uncompressed, all relevant valid entries are identified by
+ * pcie/domain_nr/bus_nr:
+ */
+static void brcmf_fw_strip_multi_v2(struct nvram_parser *nvp, u16 domain_nr,
+ u16 bus_nr)
+{
+ char prefix[BRCMF_FW_NVRAM_PCIEDEV_LEN];
+ size_t len;
+ u32 i, j;
+ u8 *nvram;
+
+ nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
+ if (!nvram)
+ goto fail;
+
+ /* Copy all valid entries, release old nvram and assign new one.
+ * Valid entries are of type pcie/X/Y/ where X = domain_nr and
+ * Y = bus_nr.
+ */
+ snprintf(prefix, sizeof(prefix), "pcie/%d/%d/", domain_nr, bus_nr);
+ len = strlen(prefix);
+ i = 0;
+ j = 0;
+ while (i < nvp->nvram_len - len) {
+ if (strncmp(&nvp->nvram[i], prefix, len) == 0) {
+ i += len;
+ while (nvp->nvram[i] != 0) {
+ nvram[j] = nvp->nvram[i];
+ i++;
+ j++;
+ }
+ nvram[j] = 0;
+ j++;
+ }
+ while (nvp->nvram[i] != 0)
+ i++;
+ i++;
+ }
+ kfree(nvp->nvram);
+ nvp->nvram = nvram;
+ nvp->nvram_len = j;
+ return;
+fail:
+ kfree(nvram);
+ nvp->nvram_len = 0;
+}
+
/* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil
* and ending in a NUL. Removes carriage returns, empty lines, comment lines,
* and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
* End of buffer is completed with token identifying length of buffer.
*/
-static void *brcmf_fw_nvram_strip(const struct firmware *nv, u32 *new_length)
+static void *brcmf_fw_nvram_strip(const u8 *data, size_t data_len,
+ u32 *new_length, u16 domain_nr, u16 bus_nr)
{
struct nvram_parser nvp;
u32 pad;
u32 token;
__le32 token_le;
- if (brcmf_init_nvram_parser(&nvp, nv) < 0)
+ if (brcmf_init_nvram_parser(&nvp, data, data_len) < 0)
return NULL;
- while (nvp.pos < nv->size) {
+ while (nvp.pos < data_len) {
nvp.state = nv_parser_states[nvp.state](&nvp);
if (nvp.state == END)
break;
}
+ if (nvp.multi_dev_v1)
+ brcmf_fw_strip_multi_v1(&nvp, domain_nr, bus_nr);
+ else if (nvp.multi_dev_v2)
+ brcmf_fw_strip_multi_v2(&nvp, domain_nr, bus_nr);
+
+ if (nvp.nvram_len == 0) {
+ kfree(nvp.nvram);
+ return NULL;
+ }
+
pad = nvp.nvram_len;
*new_length = roundup(nvp.nvram_len + 1, 4);
while (pad != *new_length) {
@@ -239,6 +415,8 @@ struct brcmf_fw {
u16 flags;
const struct firmware *code;
const char *nvram_name;
+ u16 domain_nr;
+ u16 bus_nr;
void (*done)(struct device *dev, const struct firmware *fw,
void *nvram_image, u32 nvram_len);
};
@@ -254,7 +432,8 @@ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
goto fail;
if (fw) {
- nvram = brcmf_fw_nvram_strip(fw, &nvram_length);
+ nvram = brcmf_fw_nvram_strip(fw->data, fw->size, &nvram_length,
+ fwctx->domain_nr, fwctx->bus_nr);
release_firmware(fw);
if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
goto fail;
@@ -309,11 +488,12 @@ fail:
kfree(fwctx);
}
-int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
- const char *code, const char *nvram,
- void (*fw_cb)(struct device *dev,
- const struct firmware *fw,
- void *nvram_image, u32 nvram_len))
+int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
+ const char *code, const char *nvram,
+ void (*fw_cb)(struct device *dev,
+ const struct firmware *fw,
+ void *nvram_image, u32 nvram_len),
+ u16 domain_nr, u16 bus_nr)
{
struct brcmf_fw *fwctx;
@@ -333,8 +513,21 @@ int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
fwctx->done = fw_cb;
if (flags & BRCMF_FW_REQUEST_NVRAM)
fwctx->nvram_name = nvram;
+ fwctx->domain_nr = domain_nr;
+ fwctx->bus_nr = bus_nr;
return request_firmware_nowait(THIS_MODULE, true, code, dev,
GFP_KERNEL, fwctx,
brcmf_fw_request_code_done);
}
+
+int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
+ const char *code, const char *nvram,
+ void (*fw_cb)(struct device *dev,
+ const struct firmware *fw,
+ void *nvram_image, u32 nvram_len))
+{
+ return brcmf_fw_get_firmwares_pcie(dev, flags, code, nvram, fw_cb, 0,
+ 0);
+}
+
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/brcm80211/brcmfmac/firmware.h
index 4d3482356b77..604dd48ab4e0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.h
@@ -32,6 +32,12 @@ void brcmf_fw_nvram_free(void *nvram);
* fails it will not use the callback, but call device_release_driver()
* instead which will call the driver .remove() callback.
*/
+int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
+ const char *code, const char *nvram,
+ void (*fw_cb)(struct device *dev,
+ const struct firmware *fw,
+ void *nvram_image, u32 nvram_len),
+ u16 domain_nr, u16 bus_nr);
int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
const char *code, const char *nvram,
void (*fw_cb)(struct device *dev,
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
index eb1325371d3a..59440631fec5 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
@@ -249,8 +249,8 @@ void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
}
-void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
- struct sk_buff *skb)
+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
+ struct sk_buff *skb)
{
struct brcmf_flowring_ring *ring;
@@ -271,6 +271,7 @@ void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
if (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)
brcmf_flowring_block(flow, flowid, false);
}
+ return skb_queue_len(&ring->skblist);
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
index a34cd394c616..5551861a44bc 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
@@ -64,8 +64,8 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid);
void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid);
u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid);
-void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
- struct sk_buff *skb);
+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
+ struct sk_buff *skb);
struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid);
void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
struct sk_buff *skb);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
index 374920965108..297911f38fa0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
@@ -32,7 +32,11 @@
#define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */
#define BRCMF_BSS_RSSI_ON_CHANNEL 0x0002
-#define BRCMF_STA_ASSOC 0x10 /* Associated */
+#define BRCMF_STA_WME 0x00000002 /* WMM association */
+#define BRCMF_STA_AUTHE 0x00000008 /* Authenticated */
+#define BRCMF_STA_ASSOC 0x00000010 /* Associated */
+#define BRCMF_STA_AUTHO 0x00000020 /* Authorized */
+#define BRCMF_STA_SCBSTATS 0x00004000 /* Per STA debug stats */
/* size of brcmf_scan_params not including variable length array */
#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
@@ -113,6 +117,7 @@
#define BRCMF_WOWL_MAXPATTERNSIZE 128
#define BRCMF_COUNTRY_BUF_SZ 4
+#define BRCMF_ANT_MAX 4
/* join preference types for join_pref iovar */
enum brcmf_join_pref_types {
@@ -456,25 +461,61 @@ struct brcmf_channel_info_le {
};
struct brcmf_sta_info_le {
- __le16 ver; /* version of this struct */
- __le16 len; /* length in bytes of this structure */
- __le16 cap; /* sta's advertised capabilities */
- __le32 flags; /* flags defined below */
- __le32 idle; /* time since data pkt rx'd from sta */
- u8 ea[ETH_ALEN]; /* Station address */
- __le32 count; /* # rates in this set */
- u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */
+ __le16 ver; /* version of this struct */
+ __le16 len; /* length in bytes of this structure */
+ __le16 cap; /* sta's advertised capabilities */
+ __le32 flags; /* flags defined below */
+ __le32 idle; /* time since data pkt rx'd from sta */
+ u8 ea[ETH_ALEN]; /* Station address */
+ __le32 count; /* # rates in this set */
+ u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */
/* w/hi bit set if basic */
- __le32 in; /* seconds elapsed since associated */
- __le32 listen_interval_inms; /* Min Listen interval in ms for STA */
- __le32 tx_pkts; /* # of packets transmitted */
- __le32 tx_failures; /* # of packets failed */
- __le32 rx_ucast_pkts; /* # of unicast packets received */
- __le32 rx_mcast_pkts; /* # of multicast packets received */
- __le32 tx_rate; /* Rate of last successful tx frame */
- __le32 rx_rate; /* Rate of last successful rx frame */
- __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */
- __le32 rx_decrypt_failures; /* # of packet decrypted failed */
+ __le32 in; /* seconds elapsed since associated */
+ __le32 listen_interval_inms; /* Min Listen interval in ms for STA */
+ __le32 tx_pkts; /* # of packets transmitted */
+ __le32 tx_failures; /* # of packets failed */
+ __le32 rx_ucast_pkts; /* # of unicast packets received */
+ __le32 rx_mcast_pkts; /* # of multicast packets received */
+ __le32 tx_rate; /* Rate of last successful tx frame */
+ __le32 rx_rate; /* Rate of last successful rx frame */
+ __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */
+ __le32 rx_decrypt_failures; /* # of packet decrypted failed */
+ __le32 tx_tot_pkts; /* # of tx pkts (ucast + mcast) */
+ __le32 rx_tot_pkts; /* # of data packets recvd (uni + mcast) */
+ __le32 tx_mcast_pkts; /* # of mcast pkts txed */
+ __le64 tx_tot_bytes; /* data bytes txed (ucast + mcast) */
+ __le64 rx_tot_bytes; /* data bytes recvd (ucast + mcast) */
+ __le64 tx_ucast_bytes; /* data bytes txed (ucast) */
+ __le64 tx_mcast_bytes; /* # data bytes txed (mcast) */
+ __le64 rx_ucast_bytes; /* data bytes recvd (ucast) */
+ __le64 rx_mcast_bytes; /* data bytes recvd (mcast) */
+ s8 rssi[BRCMF_ANT_MAX]; /* per antenna rssi */
+ s8 nf[BRCMF_ANT_MAX]; /* per antenna noise floor */
+ __le16 aid; /* association ID */
+ __le16 ht_capabilities; /* advertised ht caps */
+ __le16 vht_flags; /* converted vht flags */
+ __le32 tx_pkts_retry_cnt; /* # of frames where a retry was
+ * exhausted.
+ */
+ __le32 tx_pkts_retry_exhausted; /* # of user frames where a retry
+ * was exhausted
+ */
+ s8 rx_lastpkt_rssi[BRCMF_ANT_MAX]; /* Per antenna RSSI of last
+ * received data frame.
+ */
+ /* TX WLAN retry/failure statistics:
+ * Separated for host requested frames and locally generated frames.
+ * Include unicast frame only where the retries/failures can be counted.
+ */
+ __le32 tx_pkts_total; /* # user frames sent successfully */
+ __le32 tx_pkts_retries; /* # user frames retries */
+ __le32 tx_pkts_fw_total; /* # FW generated sent successfully */
+ __le32 tx_pkts_fw_retries; /* # retries for FW generated frames */
+ __le32 tx_pkts_fw_retry_exhausted; /* # FW generated where a retry
+ * was exhausted
+ */
+ __le32 rx_pkts_retried; /* # rx with retry bit set */
+ __le32 tx_rate_fallback; /* lowest fallback TX rate */
};
struct brcmf_chanspec_list {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index f0dda0ecd23b..5017eaa4af45 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -635,7 +635,7 @@ static int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h,
return 0;
}
-static int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
+static inline int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
u32 slot_id, struct sk_buff **pktout,
bool remove_item)
{
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
index 4ec9811f49c8..898c3801e658 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
@@ -73,8 +73,10 @@
#define BRCMF_MSGBUF_TX_FLUSH_CNT1 32
#define BRCMF_MSGBUF_TX_FLUSH_CNT2 96
-#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 64
+#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 96
#define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS 32
+#define BRCMF_MSGBUF_UPDATE_RX_PTR_THRS 48
+
struct msgbuf_common_hdr {
u8 msgtype;
@@ -278,16 +280,6 @@ struct brcmf_msgbuf_pktids {
struct brcmf_msgbuf_pktid *array;
};
-
-/* dma flushing needs implementation for mips and arm platforms. Should
- * be put in util. Note, this is not real flushing. It is virtual non
- * cached memory. Only write buffers should have to be drained. Though
- * this may be different depending on platform......
- */
-#define brcmf_dma_flush(addr, len)
-#define brcmf_dma_invalidate_cache(addr, len)
-
-
static void brcmf_msgbuf_rxbuf_ioctlresp_post(struct brcmf_msgbuf *msgbuf);
@@ -462,7 +454,6 @@ static int brcmf_msgbuf_tx_ioctl(struct brcmf_pub *drvr, int ifidx,
memcpy(msgbuf->ioctbuf, buf, buf_len);
else
memset(msgbuf->ioctbuf, 0, buf_len);
- brcmf_dma_flush(ioctl_buf, buf_len);
err = brcmf_commonring_write_complete(commonring);
brcmf_commonring_unlock(commonring);
@@ -511,11 +502,9 @@ static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,
msgbuf->rx_pktids,
msgbuf->ioctl_resp_pktid);
if (msgbuf->ioctl_resp_ret_len != 0) {
- if (!skb) {
- brcmf_err("Invalid packet id idx recv'd %d\n",
- msgbuf->ioctl_resp_pktid);
+ if (!skb)
return -EBADF;
- }
+
memcpy(buf, skb->data, (len < msgbuf->ioctl_resp_ret_len) ?
len : msgbuf->ioctl_resp_ret_len);
}
@@ -797,6 +786,8 @@ static int brcmf_msgbuf_txdata(struct brcmf_pub *drvr, int ifidx,
struct brcmf_flowring *flow = msgbuf->flow;
struct ethhdr *eh = (struct ethhdr *)(skb->data);
u32 flowid;
+ u32 queue_count;
+ bool force;
flowid = brcmf_flowring_lookup(flow, eh->h_dest, skb->priority, ifidx);
if (flowid == BRCMF_FLOWRING_INVALID_ID) {
@@ -804,8 +795,9 @@ static int brcmf_msgbuf_txdata(struct brcmf_pub *drvr, int ifidx,
if (flowid == BRCMF_FLOWRING_INVALID_ID)
return -ENOMEM;
}
- brcmf_flowring_enqueue(flow, flowid, skb);
- brcmf_msgbuf_schedule_txdata(msgbuf, flowid, false);
+ queue_count = brcmf_flowring_enqueue(flow, flowid, skb);
+ force = ((queue_count % BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) == 0);
+ brcmf_msgbuf_schedule_txdata(msgbuf, flowid, force);
return 0;
}
@@ -874,10 +866,8 @@ brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf)
flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS;
skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
msgbuf->tx_pktids, idx);
- if (!skb) {
- brcmf_err("Invalid packet id idx recv'd %d\n", idx);
+ if (!skb)
return;
- }
set_bit(flowid, msgbuf->txstatus_done_map);
commonring = msgbuf->flowrings[flowid];
@@ -1156,6 +1146,8 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev,
msgbuf->rx_pktids, idx);
+ if (!skb)
+ return;
if (data_offset)
skb_pull(skb, data_offset);
@@ -1267,19 +1259,27 @@ static void brcmf_msgbuf_process_rx(struct brcmf_msgbuf *msgbuf,
{
void *buf;
u16 count;
+ u16 processed;
again:
buf = brcmf_commonring_get_read_ptr(commonring, &count);
if (buf == NULL)
return;
+ processed = 0;
while (count) {
brcmf_msgbuf_process_msgtype(msgbuf,
buf + msgbuf->rx_dataoffset);
buf += brcmf_commonring_len_item(commonring);
+ processed++;
+ if (processed == BRCMF_MSGBUF_UPDATE_RX_PTR_THRS) {
+ brcmf_commonring_read_complete(commonring, processed);
+ processed = 0;
+ }
count--;
}
- brcmf_commonring_read_complete(commonring);
+ if (processed)
+ brcmf_commonring_read_complete(commonring, processed);
if (commonring->r_ptr == 0)
goto again;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/of.c b/drivers/net/wireless/brcm80211/brcmfmac/of.c
index c824570ddea3..03f35e0c52ca 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/of.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/of.c
@@ -39,10 +39,16 @@ void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
if (!sdiodev->pdata)
return;
+ if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
+ sdiodev->pdata->drive_strength = val;
+
+ /* make sure there are interrupts defined in the node */
+ if (!of_find_property(np, "interrupts", NULL))
+ return;
+
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
brcmf_err("interrupt could not be mapped\n");
- devm_kfree(dev, sdiodev->pdata);
return;
}
irqf = irqd_get_trigger_type(irq_get_irq_data(irq));
@@ -50,7 +56,4 @@ void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
sdiodev->pdata->oob_irq_supported = true;
sdiodev->pdata->oob_irq_nr = irq;
sdiodev->pdata->oob_irq_flags = irqf;
-
- if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
- sdiodev->pdata->drive_strength = val;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
index 710fbe570eb2..a9ba775a24c1 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
#include <net/cfg80211.h>
#include <brcmu_wifi.h>
@@ -1908,105 +1909,6 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
/**
- * brcmf_p2p_attach() - attach for P2P.
- *
- * @cfg: driver private data for cfg80211 interface.
- */
-s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
-{
- struct brcmf_if *pri_ifp;
- struct brcmf_if *p2p_ifp;
- struct brcmf_cfg80211_vif *p2p_vif;
- struct brcmf_p2p_info *p2p;
- struct brcmf_pub *drvr;
- s32 bssidx;
- s32 err = 0;
-
- p2p = &cfg->p2p;
- p2p->cfg = cfg;
-
- drvr = cfg->pub;
-
- pri_ifp = drvr->iflist[0];
- p2p_ifp = drvr->iflist[1];
-
- p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
-
- if (p2p_ifp) {
- p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE,
- false);
- if (IS_ERR(p2p_vif)) {
- brcmf_err("could not create discovery vif\n");
- err = -ENOMEM;
- goto exit;
- }
-
- p2p_vif->ifp = p2p_ifp;
- p2p_ifp->vif = p2p_vif;
- p2p_vif->wdev.netdev = p2p_ifp->ndev;
- p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev;
- SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy));
-
- p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
-
- brcmf_p2p_generate_bss_mac(p2p, NULL);
- memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
- brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
-
- /* Initialize P2P Discovery in the firmware */
- err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
- if (err < 0) {
- brcmf_err("set p2p_disc error\n");
- brcmf_free_vif(p2p_vif);
- goto exit;
- }
- /* obtain bsscfg index for P2P discovery */
- err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
- if (err < 0) {
- brcmf_err("retrieving discover bsscfg index failed\n");
- brcmf_free_vif(p2p_vif);
- goto exit;
- }
- /* Verify that firmware uses same bssidx as driver !! */
- if (p2p_ifp->bssidx != bssidx) {
- brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
- bssidx, p2p_ifp->bssidx);
- brcmf_free_vif(p2p_vif);
- goto exit;
- }
-
- init_completion(&p2p->send_af_done);
- INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
- init_completion(&p2p->afx_hdl.act_frm_scan);
- init_completion(&p2p->wait_next_af);
- }
-exit:
- return err;
-}
-
-
-/**
- * brcmf_p2p_detach() - detach P2P.
- *
- * @p2p: P2P specific data.
- */
-void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
-{
- struct brcmf_cfg80211_vif *vif;
-
- vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
- if (vif != NULL) {
- brcmf_p2p_cancel_remain_on_channel(vif->ifp);
- brcmf_p2p_deinit_discovery(p2p);
- /* remove discovery interface */
- brcmf_free_vif(vif);
- p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
- }
- /* just set it all to zero */
- memset(p2p, 0, sizeof(*p2p));
-}
-
-/**
* brcmf_p2p_get_current_chanspec() - Get current operation channel.
*
* @p2p: P2P specific data.
@@ -2238,6 +2140,7 @@ static void brcmf_p2p_delete_p2pdev(struct brcmf_p2p_info *p2p,
{
cfg80211_unregister_wdev(&vif->wdev);
p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+ brcmf_remove_interface(vif->ifp->drvr, vif->ifp->bssidx);
brcmf_free_vif(vif);
}
@@ -2364,6 +2267,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
break;
case NL80211_IFTYPE_P2P_DEVICE:
+ brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+ brcmf_p2p_deinit_discovery(p2p);
brcmf_p2p_delete_p2pdev(p2p, vif);
return 0;
default:
@@ -2425,3 +2330,103 @@ void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev)
clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
mutex_unlock(&cfg->usr_sync);
}
+
+/**
+ * brcmf_p2p_attach() - attach for P2P.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ */
+s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_if *pri_ifp;
+ struct brcmf_if *p2p_ifp;
+ struct brcmf_cfg80211_vif *p2p_vif;
+ struct brcmf_p2p_info *p2p;
+ struct brcmf_pub *drvr;
+ s32 bssidx;
+ s32 err = 0;
+
+ p2p = &cfg->p2p;
+ p2p->cfg = cfg;
+
+ drvr = cfg->pub;
+
+ pri_ifp = drvr->iflist[0];
+ p2p_ifp = drvr->iflist[1];
+
+ p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
+
+ if (p2p_ifp) {
+ p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE,
+ false);
+ if (IS_ERR(p2p_vif)) {
+ brcmf_err("could not create discovery vif\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ p2p_vif->ifp = p2p_ifp;
+ p2p_ifp->vif = p2p_vif;
+ p2p_vif->wdev.netdev = p2p_ifp->ndev;
+ p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev;
+ SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy));
+
+ p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
+
+ brcmf_p2p_generate_bss_mac(p2p, NULL);
+ memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
+ brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
+
+ /* Initialize P2P Discovery in the firmware */
+ err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
+ if (err < 0) {
+ brcmf_err("set p2p_disc error\n");
+ brcmf_free_vif(p2p_vif);
+ goto exit;
+ }
+ /* obtain bsscfg index for P2P discovery */
+ err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
+ if (err < 0) {
+ brcmf_err("retrieving discover bsscfg index failed\n");
+ brcmf_free_vif(p2p_vif);
+ goto exit;
+ }
+ /* Verify that firmware uses same bssidx as driver !! */
+ if (p2p_ifp->bssidx != bssidx) {
+ brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
+ bssidx, p2p_ifp->bssidx);
+ brcmf_free_vif(p2p_vif);
+ goto exit;
+ }
+
+ init_completion(&p2p->send_af_done);
+ INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
+ init_completion(&p2p->afx_hdl.act_frm_scan);
+ init_completion(&p2p->wait_next_af);
+ }
+exit:
+ return err;
+}
+
+/**
+ * brcmf_p2p_detach() - detach P2P.
+ *
+ * @p2p: P2P specific data.
+ */
+void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
+{
+ struct brcmf_cfg80211_vif *vif;
+
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ if (vif != NULL) {
+ brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+ brcmf_p2p_deinit_discovery(p2p);
+ /* remove discovery interface */
+ rtnl_lock();
+ brcmf_p2p_delete_p2pdev(p2p, vif);
+ rtnl_unlock();
+ }
+ /* just set it all to zero */
+ memset(p2p, 0, sizeof(*p2p));
+}
+
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
index 1831ecd0813e..3a98c4306d1d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
@@ -51,6 +51,8 @@ enum brcmf_pcie_state {
#define BRCMF_PCIE_4356_NVRAM_NAME "brcm/brcmfmac4356-pcie.txt"
#define BRCMF_PCIE_43570_FW_NAME "brcm/brcmfmac43570-pcie.bin"
#define BRCMF_PCIE_43570_NVRAM_NAME "brcm/brcmfmac43570-pcie.txt"
+#define BRCMF_PCIE_4358_FW_NAME "brcm/brcmfmac4358-pcie.bin"
+#define BRCMF_PCIE_4358_NVRAM_NAME "brcm/brcmfmac4358-pcie.txt"
#define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */
@@ -110,10 +112,11 @@ enum brcmf_pcie_state {
BRCMF_PCIE_MB_INT_D2H3_DB0 | \
BRCMF_PCIE_MB_INT_D2H3_DB1)
-#define BRCMF_PCIE_MIN_SHARED_VERSION 4
+#define BRCMF_PCIE_MIN_SHARED_VERSION 5
#define BRCMF_PCIE_MAX_SHARED_VERSION 5
#define BRCMF_PCIE_SHARED_VERSION_MASK 0x00FF
-#define BRCMF_PCIE_SHARED_TXPUSH_SUPPORT 0x4000
+#define BRCMF_PCIE_SHARED_DMA_INDEX 0x10000
+#define BRCMF_PCIE_SHARED_DMA_2B_IDX 0x100000
#define BRCMF_PCIE_FLAGS_HTOD_SPLIT 0x4000
#define BRCMF_PCIE_FLAGS_DTOH_SPLIT 0x8000
@@ -145,6 +148,10 @@ enum brcmf_pcie_state {
#define BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET 8
#define BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET 12
#define BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET 16
+#define BRCMF_SHARED_RING_H2D_WP_HADDR_OFFSET 20
+#define BRCMF_SHARED_RING_H2D_RP_HADDR_OFFSET 28
+#define BRCMF_SHARED_RING_D2H_WP_HADDR_OFFSET 36
+#define BRCMF_SHARED_RING_D2H_RP_HADDR_OFFSET 44
#define BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET 0
#define BRCMF_SHARED_RING_MAX_SUB_QUEUES 52
@@ -189,6 +196,8 @@ MODULE_FIRMWARE(BRCMF_PCIE_4356_FW_NAME);
MODULE_FIRMWARE(BRCMF_PCIE_4356_NVRAM_NAME);
MODULE_FIRMWARE(BRCMF_PCIE_43570_FW_NAME);
MODULE_FIRMWARE(BRCMF_PCIE_43570_NVRAM_NAME);
+MODULE_FIRMWARE(BRCMF_PCIE_4358_FW_NAME);
+MODULE_FIRMWARE(BRCMF_PCIE_4358_NVRAM_NAME);
struct brcmf_pcie_console {
@@ -244,6 +253,13 @@ struct brcmf_pciedev_info {
bool mbdata_completed;
bool irq_allocated;
bool wowl_enabled;
+ u8 dma_idx_sz;
+ void *idxbuf;
+ u32 idxbuf_sz;
+ dma_addr_t idxbuf_dmahandle;
+ u16 (*read_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset);
+ void (*write_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
+ u16 value);
};
struct brcmf_pcie_ringbuf {
@@ -273,15 +289,6 @@ static const u32 brcmf_ring_itemsize[BRCMF_NROF_COMMON_MSGRINGS] = {
};
-/* dma flushing needs implementation for mips and arm platforms. Should
- * be put in util. Note, this is not real flushing. It is virtual non
- * cached memory. Only write buffers should have to be drained. Though
- * this may be different depending on platform......
- */
-#define brcmf_dma_flush(addr, len)
-#define brcmf_dma_invalidate_cache(addr, len)
-
-
static u32
brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset)
{
@@ -329,6 +336,25 @@ brcmf_pcie_write_tcm16(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
}
+static u16
+brcmf_pcie_read_idx(struct brcmf_pciedev_info *devinfo, u32 mem_offset)
+{
+ u16 *address = devinfo->idxbuf + mem_offset;
+
+ return (*(address));
+}
+
+
+static void
+brcmf_pcie_write_idx(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
+ u16 value)
+{
+ u16 *address = devinfo->idxbuf + mem_offset;
+
+ *(address) = value;
+}
+
+
static u32
brcmf_pcie_read_tcm32(struct brcmf_pciedev_info *devinfo, u32 mem_offset)
{
@@ -874,7 +900,7 @@ static int brcmf_pcie_ring_mb_write_rptr(void *ctx)
brcmf_dbg(PCIE, "W r_ptr %d (%d), ring %d\n", commonring->r_ptr,
commonring->w_ptr, ring->id);
- brcmf_pcie_write_tcm16(devinfo, ring->r_idx_addr, commonring->r_ptr);
+ devinfo->write_ptr(devinfo, ring->r_idx_addr, commonring->r_ptr);
return 0;
}
@@ -892,7 +918,7 @@ static int brcmf_pcie_ring_mb_write_wptr(void *ctx)
brcmf_dbg(PCIE, "W w_ptr %d (%d), ring %d\n", commonring->w_ptr,
commonring->r_ptr, ring->id);
- brcmf_pcie_write_tcm16(devinfo, ring->w_idx_addr, commonring->w_ptr);
+ devinfo->write_ptr(devinfo, ring->w_idx_addr, commonring->w_ptr);
return 0;
}
@@ -921,7 +947,7 @@ static int brcmf_pcie_ring_mb_update_rptr(void *ctx)
if (devinfo->state != BRCMFMAC_PCIE_STATE_UP)
return -EIO;
- commonring->r_ptr = brcmf_pcie_read_tcm16(devinfo, ring->r_idx_addr);
+ commonring->r_ptr = devinfo->read_ptr(devinfo, ring->r_idx_addr);
brcmf_dbg(PCIE, "R r_ptr %d (%d), ring %d\n", commonring->r_ptr,
commonring->w_ptr, ring->id);
@@ -939,7 +965,7 @@ static int brcmf_pcie_ring_mb_update_wptr(void *ctx)
if (devinfo->state != BRCMFMAC_PCIE_STATE_UP)
return -EIO;
- commonring->w_ptr = brcmf_pcie_read_tcm16(devinfo, ring->w_idx_addr);
+ commonring->w_ptr = devinfo->read_ptr(devinfo, ring->w_idx_addr);
brcmf_dbg(PCIE, "R w_ptr %d (%d), ring %d\n", commonring->w_ptr,
commonring->r_ptr, ring->id);
@@ -1044,6 +1070,13 @@ static void brcmf_pcie_release_ringbuffers(struct brcmf_pciedev_info *devinfo)
}
kfree(devinfo->shared.flowrings);
devinfo->shared.flowrings = NULL;
+ if (devinfo->idxbuf) {
+ dma_free_coherent(&devinfo->pdev->dev,
+ devinfo->idxbuf_sz,
+ devinfo->idxbuf,
+ devinfo->idxbuf_dmahandle);
+ devinfo->idxbuf = NULL;
+ }
}
@@ -1059,19 +1092,72 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo)
u32 addr;
u32 ring_mem_ptr;
u32 i;
+ u64 address;
+ u32 bufsz;
u16 max_sub_queues;
+ u8 idx_offset;
ring_addr = devinfo->shared.ring_info_addr;
brcmf_dbg(PCIE, "Base ring addr = 0x%08x\n", ring_addr);
+ addr = ring_addr + BRCMF_SHARED_RING_MAX_SUB_QUEUES;
+ max_sub_queues = brcmf_pcie_read_tcm16(devinfo, addr);
- addr = ring_addr + BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET;
- d2h_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
- addr = ring_addr + BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET;
- d2h_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
- addr = ring_addr + BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET;
- h2d_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
- addr = ring_addr + BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET;
- h2d_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
+ if (devinfo->dma_idx_sz != 0) {
+ bufsz = (BRCMF_NROF_D2H_COMMON_MSGRINGS + max_sub_queues) *
+ devinfo->dma_idx_sz * 2;
+ devinfo->idxbuf = dma_alloc_coherent(&devinfo->pdev->dev, bufsz,
+ &devinfo->idxbuf_dmahandle,
+ GFP_KERNEL);
+ if (!devinfo->idxbuf)
+ devinfo->dma_idx_sz = 0;
+ }
+
+ if (devinfo->dma_idx_sz == 0) {
+ addr = ring_addr + BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET;
+ d2h_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
+ addr = ring_addr + BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET;
+ d2h_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
+ addr = ring_addr + BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET;
+ h2d_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
+ addr = ring_addr + BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET;
+ h2d_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
+ idx_offset = sizeof(u32);
+ devinfo->write_ptr = brcmf_pcie_write_tcm16;
+ devinfo->read_ptr = brcmf_pcie_read_tcm16;
+ brcmf_dbg(PCIE, "Using TCM indices\n");
+ } else {
+ memset(devinfo->idxbuf, 0, bufsz);
+ devinfo->idxbuf_sz = bufsz;
+ idx_offset = devinfo->dma_idx_sz;
+ devinfo->write_ptr = brcmf_pcie_write_idx;
+ devinfo->read_ptr = brcmf_pcie_read_idx;
+
+ h2d_w_idx_ptr = 0;
+ addr = ring_addr + BRCMF_SHARED_RING_H2D_WP_HADDR_OFFSET;
+ address = (u64)devinfo->idxbuf_dmahandle;
+ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
+ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
+
+ h2d_r_idx_ptr = h2d_w_idx_ptr + max_sub_queues * idx_offset;
+ addr = ring_addr + BRCMF_SHARED_RING_H2D_RP_HADDR_OFFSET;
+ address += max_sub_queues * idx_offset;
+ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
+ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
+
+ d2h_w_idx_ptr = h2d_r_idx_ptr + max_sub_queues * idx_offset;
+ addr = ring_addr + BRCMF_SHARED_RING_D2H_WP_HADDR_OFFSET;
+ address += max_sub_queues * idx_offset;
+ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
+ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
+
+ d2h_r_idx_ptr = d2h_w_idx_ptr +
+ BRCMF_NROF_D2H_COMMON_MSGRINGS * idx_offset;
+ addr = ring_addr + BRCMF_SHARED_RING_D2H_RP_HADDR_OFFSET;
+ address += BRCMF_NROF_D2H_COMMON_MSGRINGS * idx_offset;
+ brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
+ brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
+ brcmf_dbg(PCIE, "Using host memory indices\n");
+ }
addr = ring_addr + BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET;
ring_mem_ptr = brcmf_pcie_read_tcm32(devinfo, addr);
@@ -1085,8 +1171,8 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo)
ring->id = i;
devinfo->shared.commonrings[i] = ring;
- h2d_w_idx_ptr += sizeof(u32);
- h2d_r_idx_ptr += sizeof(u32);
+ h2d_w_idx_ptr += idx_offset;
+ h2d_r_idx_ptr += idx_offset;
ring_mem_ptr += BRCMF_RING_MEM_SZ;
}
@@ -1100,13 +1186,11 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo)
ring->id = i;
devinfo->shared.commonrings[i] = ring;
- d2h_w_idx_ptr += sizeof(u32);
- d2h_r_idx_ptr += sizeof(u32);
+ d2h_w_idx_ptr += idx_offset;
+ d2h_r_idx_ptr += idx_offset;
ring_mem_ptr += BRCMF_RING_MEM_SZ;
}
- addr = ring_addr + BRCMF_SHARED_RING_MAX_SUB_QUEUES;
- max_sub_queues = brcmf_pcie_read_tcm16(devinfo, addr);
devinfo->shared.nrof_flowrings =
max_sub_queues - BRCMF_NROF_H2D_COMMON_MSGRINGS;
rings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(*ring),
@@ -1130,15 +1214,15 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo)
ring);
ring->w_idx_addr = h2d_w_idx_ptr;
ring->r_idx_addr = h2d_r_idx_ptr;
- h2d_w_idx_ptr += sizeof(u32);
- h2d_r_idx_ptr += sizeof(u32);
+ h2d_w_idx_ptr += idx_offset;
+ h2d_r_idx_ptr += idx_offset;
}
devinfo->shared.flowrings = rings;
return 0;
fail:
- brcmf_err("Allocating commonring buffers failed\n");
+ brcmf_err("Allocating ring buffers failed\n");
brcmf_pcie_release_ringbuffers(devinfo);
return -ENOMEM;
}
@@ -1171,7 +1255,6 @@ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo)
goto fail;
memset(devinfo->shared.scratch, 0, BRCMF_DMA_D2H_SCRATCH_BUF_LEN);
- brcmf_dma_flush(devinfo->shared.scratch, BRCMF_DMA_D2H_SCRATCH_BUF_LEN);
addr = devinfo->shared.tcm_base_address +
BRCMF_SHARED_DMA_SCRATCH_ADDR_OFFSET;
@@ -1189,7 +1272,6 @@ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo)
goto fail;
memset(devinfo->shared.ringupd, 0, BRCMF_DMA_D2H_RINGUPD_BUF_LEN);
- brcmf_dma_flush(devinfo->shared.ringupd, BRCMF_DMA_D2H_RINGUPD_BUF_LEN);
addr = devinfo->shared.tcm_base_address +
BRCMF_SHARED_DMA_RINGUPD_ADDR_OFFSET;
@@ -1276,10 +1358,13 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
brcmf_err("Unsupported PCIE version %d\n", version);
return -EINVAL;
}
- if (shared->flags & BRCMF_PCIE_SHARED_TXPUSH_SUPPORT) {
- brcmf_err("Unsupported legacy TX mode 0x%x\n",
- shared->flags & BRCMF_PCIE_SHARED_TXPUSH_SUPPORT);
- return -EINVAL;
+
+ /* check firmware support dma indicies */
+ if (shared->flags & BRCMF_PCIE_SHARED_DMA_INDEX) {
+ if (shared->flags & BRCMF_PCIE_SHARED_DMA_2B_IDX)
+ devinfo->dma_idx_sz = sizeof(u16);
+ else
+ devinfo->dma_idx_sz = sizeof(u32);
}
addr = sharedram_addr + BRCMF_SHARED_MAX_RXBUFPOST_OFFSET;
@@ -1333,6 +1418,10 @@ static int brcmf_pcie_get_fwnames(struct brcmf_pciedev_info *devinfo)
fw_name = BRCMF_PCIE_43570_FW_NAME;
nvram_name = BRCMF_PCIE_43570_NVRAM_NAME;
break;
+ case BRCM_CC_4358_CHIP_ID:
+ fw_name = BRCMF_PCIE_4358_FW_NAME;
+ nvram_name = BRCMF_PCIE_4358_NVRAM_NAME;
+ break;
default:
brcmf_err("Unsupported chip 0x%04x\n", devinfo->ci->chip);
return -ENODEV;
@@ -1540,20 +1629,7 @@ static void brcmf_pcie_buscore_write32(void *ctx, u32 addr, u32 value)
static int brcmf_pcie_buscoreprep(void *ctx)
{
- struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx;
- int err;
-
- err = brcmf_pcie_get_resource(devinfo);
- if (err == 0) {
- /* Set CC watchdog to reset all the cores on the chip to bring
- * back dongle to a sane state.
- */
- brcmf_pcie_buscore_write32(ctx, CORE_CC_REG(SI_ENUM_BASE,
- watchdog), 4);
- msleep(100);
- }
-
- return err;
+ return brcmf_pcie_get_resource(ctx);
}
@@ -1609,7 +1685,7 @@ static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw,
bus->msgbuf->commonrings[i] =
&devinfo->shared.commonrings[i]->commonring;
- flowrings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(flowrings),
+ flowrings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(*flowrings),
GFP_KERNEL);
if (!flowrings)
goto fail;
@@ -1641,8 +1717,13 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct brcmf_pciedev_info *devinfo;
struct brcmf_pciedev *pcie_bus_dev;
struct brcmf_bus *bus;
+ u16 domain_nr;
+ u16 bus_nr;
- brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device);
+ domain_nr = pci_domain_nr(pdev->bus) + 1;
+ bus_nr = pdev->bus->number;
+ brcmf_dbg(PCIE, "Enter %x:%x (%d/%d)\n", pdev->vendor, pdev->device,
+ domain_nr, bus_nr);
ret = -ENOMEM;
devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
@@ -1691,10 +1772,10 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
goto fail_bus;
- ret = brcmf_fw_get_firmwares(bus->dev, BRCMF_FW_REQUEST_NVRAM |
- BRCMF_FW_REQ_NV_OPTIONAL,
- devinfo->fw_name, devinfo->nvram_name,
- brcmf_pcie_setup);
+ ret = brcmf_fw_get_firmwares_pcie(bus->dev, BRCMF_FW_REQUEST_NVRAM |
+ BRCMF_FW_REQ_NV_OPTIONAL,
+ devinfo->fw_name, devinfo->nvram_name,
+ brcmf_pcie_setup, domain_nr, bus_nr);
if (ret == 0)
return 0;
fail_bus:
@@ -1730,6 +1811,7 @@ brcmf_pcie_remove(struct pci_dev *pdev)
brcmf_pcie_intr_disable(devinfo);
brcmf_detach(&pdev->dev);
+ brcmf_pcie_reset_device(devinfo);
kfree(bus->bus_priv.pcie);
kfree(bus->msgbuf->flowrings);
@@ -1850,9 +1932,11 @@ static struct pci_device_id brcmf_pcie_devid_table[] = {
BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4358_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_2G_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_5G_DEVICE_ID),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_RAW_DEVICE_ID),
{ /* end: all zeroes */ }
};
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
index ab0c89833013..d36f5f3d931b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
@@ -601,6 +601,8 @@ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
#define BCM43241B0_NVRAM_NAME "brcm/brcmfmac43241b0-sdio.txt"
#define BCM43241B4_FIRMWARE_NAME "brcm/brcmfmac43241b4-sdio.bin"
#define BCM43241B4_NVRAM_NAME "brcm/brcmfmac43241b4-sdio.txt"
+#define BCM43241B5_FIRMWARE_NAME "brcm/brcmfmac43241b5-sdio.bin"
+#define BCM43241B5_NVRAM_NAME "brcm/brcmfmac43241b5-sdio.txt"
#define BCM4329_FIRMWARE_NAME "brcm/brcmfmac4329-sdio.bin"
#define BCM4329_NVRAM_NAME "brcm/brcmfmac4329-sdio.txt"
#define BCM4330_FIRMWARE_NAME "brcm/brcmfmac4330-sdio.bin"
@@ -628,6 +630,8 @@ MODULE_FIRMWARE(BCM43241B0_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM43241B0_NVRAM_NAME);
MODULE_FIRMWARE(BCM43241B4_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM43241B4_NVRAM_NAME);
+MODULE_FIRMWARE(BCM43241B5_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM43241B5_NVRAM_NAME);
MODULE_FIRMWARE(BCM4329_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM4329_NVRAM_NAME);
MODULE_FIRMWARE(BCM4330_FIRMWARE_NAME);
@@ -667,7 +671,8 @@ enum brcmf_firmware_type {
static const struct brcmf_firmware_names brcmf_fwname_data[] = {
{ BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43143) },
{ BRCM_CC_43241_CHIP_ID, 0x0000001F, BRCMF_FIRMWARE_NVRAM(BCM43241B0) },
- { BRCM_CC_43241_CHIP_ID, 0xFFFFFFE0, BRCMF_FIRMWARE_NVRAM(BCM43241B4) },
+ { BRCM_CC_43241_CHIP_ID, 0x00000020, BRCMF_FIRMWARE_NVRAM(BCM43241B4) },
+ { BRCM_CC_43241_CHIP_ID, 0xFFFFFFC0, BRCMF_FIRMWARE_NVRAM(BCM43241B5) },
{ BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) },
{ BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) },
{ BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
@@ -2815,6 +2820,8 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
struct brcmf_sdio *bus = sdiodev->bus;
brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len);
+ if (sdiodev->state != BRCMF_SDIOD_DATA)
+ return -EIO;
/* Add space for the header */
skb_push(pkt, bus->tx_hdrlen);
@@ -2943,6 +2950,8 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
int ret;
brcmf_dbg(TRACE, "Enter\n");
+ if (sdiodev->state != BRCMF_SDIOD_DATA)
+ return -EIO;
/* Send from dpc */
bus->ctrl_frame_buf = msg;
@@ -3233,6 +3242,8 @@ brcmf_sdio_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
struct brcmf_sdio *bus = sdiodev->bus;
brcmf_dbg(TRACE, "Enter\n");
+ if (sdiodev->state != BRCMF_SDIOD_DATA)
+ return -EIO;
/* Wait until control frame is available */
timeleft = brcmf_sdio_dcmd_resp_wait(bus, &bus->rxlen, &pending);
@@ -3550,10 +3561,6 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus)
return;
}
- if (bus->sdiodev->state != BRCMF_SDIOD_DATA) {
- brcmf_err("bus is down. we have nothing to do\n");
- return;
- }
/* Count the interrupt call */
bus->sdcnt.intrcount++;
if (in_interrupt())
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 5df6aa72cc2d..daba86d881bc 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -1270,8 +1270,13 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
bus->chiprev = bus_pub->chiprev;
/* request firmware here */
- brcmf_fw_get_firmwares(dev, 0, brcmf_usb_get_fwname(devinfo), NULL,
- brcmf_usb_probe_phase2);
+ ret = brcmf_fw_get_firmwares(dev, 0, brcmf_usb_get_fwname(devinfo),
+ NULL, brcmf_usb_probe_phase2);
+ if (ret) {
+ brcmf_err("firmware request failed: %d\n", ret);
+ goto fail;
+ }
+
return 0;
fail:
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index 48135063347e..ab775a5d5b33 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -41,8 +41,7 @@
#define BRCMS_FLUSH_TIMEOUT 500 /* msec */
/* Flags we support */
-#define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+#define MAC_FILTERS (FIF_ALLMULTI | \
FIF_FCSFAIL | \
FIF_CONTROL | \
FIF_OTHER_BSS | \
@@ -743,8 +742,6 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw,
changed_flags &= MAC_FILTERS;
*total_flags &= MAC_FILTERS;
- if (changed_flags & FIF_PROMISC_IN_BSS)
- brcms_dbg_info(core, "FIF_PROMISC_IN_BSS\n");
if (changed_flags & FIF_ALLMULTI)
brcms_dbg_info(core, "FIF_ALLMULTI\n");
if (changed_flags & FIF_FCSFAIL)
@@ -1063,10 +1060,9 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw)
*/
static int ieee_hw_init(struct ieee80211_hw *hw)
{
- hw->flags = IEEE80211_HW_SIGNAL_DBM
- /* | IEEE80211_HW_CONNECTION_MONITOR What is this? */
- | IEEE80211_HW_REPORTS_TX_ACK_STATUS
- | IEEE80211_HW_AMPDU_AGGREGATION;
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
hw->extra_tx_headroom = brcms_c_get_header_len();
hw->queues = N_TX_QUEUES;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 369527e27689..9728be0e704b 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -3571,7 +3571,7 @@ void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags)
wlc->filter_flags = filter_flags;
- if (filter_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
+ if (filter_flags & FIF_OTHER_BSS)
promisc_bits |= MCTL_PROMISC;
if (filter_flags & FIF_BCN_PRBRESP_PROMISC)
diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
index 4efdd51af9c8..7a6daa37dc6b 100644
--- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
+++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
@@ -45,6 +45,7 @@
#define BRCM_CC_43567_CHIP_ID 43567
#define BRCM_CC_43569_CHIP_ID 43569
#define BRCM_CC_43570_CHIP_ID 43570
+#define BRCM_CC_4358_CHIP_ID 0x4358
#define BRCM_CC_43602_CHIP_ID 43602
/* USB Device IDs */
@@ -59,9 +60,11 @@
#define BRCM_PCIE_4356_DEVICE_ID 0x43ec
#define BRCM_PCIE_43567_DEVICE_ID 0x43d3
#define BRCM_PCIE_43570_DEVICE_ID 0x43d9
+#define BRCM_PCIE_4358_DEVICE_ID 0x43e9
#define BRCM_PCIE_43602_DEVICE_ID 0x43ba
#define BRCM_PCIE_43602_2G_DEVICE_ID 0x43bb
#define BRCM_PCIE_43602_5G_DEVICE_ID 0x43bc
+#define BRCM_PCIE_43602_RAW_DEVICE_ID 43602
/* brcmsmac IDs */
#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */
diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c
index 3689dbbd10bd..0e51e27d2e3f 100644
--- a/drivers/net/wireless/cw1200/main.c
+++ b/drivers/net/wireless/cw1200/main.c
@@ -278,14 +278,14 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
else
priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_CONNECTION_MONITOR |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
- IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC;
+ ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
+ ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, CONNECTION_MONITOR);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c
index b0f65fa09428..b86500b4418f 100644
--- a/drivers/net/wireless/cw1200/sta.c
+++ b/drivers/net/wireless/cw1200/sta.c
@@ -578,13 +578,11 @@ void cw1200_configure_filter(struct ieee80211_hw *dev,
{
struct cw1200_common *priv = dev->priv;
bool listening = !!(*total_flags &
- (FIF_PROMISC_IN_BSS |
- FIF_OTHER_BSS |
+ (FIF_OTHER_BSS |
FIF_BCN_PRBRESP_PROMISC |
FIF_PROBE_REQ));
- *total_flags &= FIF_PROMISC_IN_BSS |
- FIF_OTHER_BSS |
+ *total_flags &= FIF_OTHER_BSS |
FIF_FCSFAIL |
FIF_BCN_PRBRESP_PROMISC |
FIF_PROBE_REQ;
@@ -592,14 +590,12 @@ void cw1200_configure_filter(struct ieee80211_hw *dev,
down(&priv->scan.lock);
mutex_lock(&priv->conf_mutex);
- priv->rx_filter.promiscuous = (*total_flags & FIF_PROMISC_IN_BSS)
- ? 1 : 0;
+ priv->rx_filter.promiscuous = 0;
priv->rx_filter.bssid = (*total_flags & (FIF_OTHER_BSS |
FIF_PROBE_REQ)) ? 1 : 0;
priv->rx_filter.fcs = (*total_flags & FIF_FCSFAIL) ? 1 : 0;
priv->disable_beacon_filter = !(*total_flags &
(FIF_BCN_PRBRESP_PROMISC |
- FIF_PROMISC_IN_BSS |
FIF_PROBE_REQ));
if (priv->listening != listening) {
priv->listening = listening;
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index e5665804d986..7f4cb692cc57 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -3048,7 +3048,7 @@ il3945_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
D_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", changed_flags,
*total_flags);
- CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+ CHK(FIF_OTHER_BSS, RXON_FILTER_PROMISC_MSK);
CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK);
CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
@@ -3074,7 +3074,7 @@ il3945_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
* filters into the device.
*/
*total_flags &=
- FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+ FIF_OTHER_BSS | FIF_ALLMULTI |
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
@@ -3561,8 +3561,10 @@ il3945_setup_mac(struct il_priv *il)
hw->vif_data_size = sizeof(struct il_vif_priv);
/* Tell mac80211 our characteristics */
- hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 976f65fe9c38..44fa422f255e 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -5751,11 +5751,13 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
hw->rate_control_algorithm = "iwl-4965-rs";
/* Tell mac80211 our characteristics */
- hw->flags =
- IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
if (il->cfg->sku & IL_SKU_N)
hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS |
NL80211_FEATURE_STATIC_SMPS;
@@ -6166,7 +6168,7 @@ il4965_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
D_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", changed_flags,
*total_flags);
- CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+ CHK(FIF_OTHER_BSS, RXON_FILTER_PROMISC_MSK);
/* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
@@ -6192,7 +6194,7 @@ il4965_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
* filters into the device.
*/
*total_flags &=
- FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+ FIF_OTHER_BSS | FIF_ALLMULTI |
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index ab019b45551b..aba095761ac6 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -21,6 +21,8 @@ config IWLWIFI
Intel 7260 Wi-Fi Adapter
Intel 3160 Wi-Fi Adapter
Intel 7265 Wi-Fi Adapter
+ Intel 8260 Wi-Fi Adapter
+ Intel 3165 Wi-Fi Adapter
This driver uses the kernel's mac80211 subsystem.
@@ -53,16 +55,17 @@ config IWLDVM
tristate "Intel Wireless WiFi DVM Firmware support"
default IWLWIFI
help
- This is the driver that supports the DVM firmware which is
- used by most existing devices (with the exception of 7260
- and 3160).
+ This is the driver that supports the DVM firmware. The list
+ of the devices that use this firmware is available here:
+ https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi#firmware
config IWLMVM
tristate "Intel Wireless WiFi MVM Firmware support"
select WANT_DEV_COREDUMP
help
- This is the driver that supports the MVM firmware which is
- currently only available for 7260 and 3160 devices.
+ This is the driver that supports the MVM firmware. The list
+ of the devices that use this firmware is available here:
+ https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi#firmware
# don't call it _MODULE -- will confuse Kconfig/fixdep/...
config IWLWIFI_OPMODE_MODULAR
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 3d32f4120174..dbfc5b18bcb7 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -9,6 +9,7 @@ iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o
iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o
iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o
+iwlwifi-objs += iwl-trans.o
iwlwifi-objs += $(iwlwifi-m)
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 5abd62ed8cb4..7acaa266b704 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -104,15 +104,16 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
hw->rate_control_algorithm = "iwl-agn-rs";
/* Tell mac80211 our characteristics */
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
- IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_QUEUE_CONTROL |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_WANT_MONITOR_VIF;
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, QUEUE_CONTROL);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
+ ieee80211_hw_set(hw, WANT_MONITOR_VIF);
hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
@@ -135,7 +136,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
*/
if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP &&
!iwlwifi_mod_params.sw_crypto)
- hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+ ieee80211_hw_set(hw, MFP_CAPABLE);
hw->sta_data_size = sizeof(struct iwl_station_priv);
hw->vif_data_size = sizeof(struct iwl_vif_priv);
@@ -1061,7 +1062,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
changed_flags, *total_flags);
- CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+ CHK(FIF_OTHER_BSS, RXON_FILTER_PROMISC_MSK);
/* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
@@ -1088,7 +1089,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
* since we currently do not support programming multicast
* filters into the device.
*/
- *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+ *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
@@ -1140,7 +1141,6 @@ static void iwlagn_mac_event_callback(struct ieee80211_hw *hw,
return;
IWL_DEBUG_MAC80211(priv, "enter\n");
- mutex_lock(&priv->mutex);
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist) {
@@ -1149,13 +1149,12 @@ static void iwlagn_mac_event_callback(struct ieee80211_hw *hw,
else if (event->u.rssi.data == RSSI_EVENT_HIGH)
priv->bt_enable_pspoll = false;
- iwlagn_send_advance_bt_config(priv);
+ queue_work(priv->workqueue, &priv->bt_runtime_config);
} else {
IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
"ignoring RSSI callback\n");
}
- mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
}
@@ -1343,9 +1342,9 @@ static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
* other interfaces are added, this is safe.
*/
if (vif->type == NL80211_IFTYPE_MONITOR)
- priv->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
+ ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS);
else
- priv->hw->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+ __clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, priv->hw->flags);
err = iwl_setup_interface(priv, ctx);
if (!err || reset)
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
index 36e786f0387b..cc35f796d406 100644
--- a/drivers/net/wireless/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -69,16 +69,15 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
-#define IWL7260_UCODE_API_MAX 13
-#define IWL3160_UCODE_API_MAX 13
+#define IWL7260_UCODE_API_MAX 15
/* Oldest version we won't warn about */
#define IWL7260_UCODE_API_OK 12
-#define IWL3160_UCODE_API_OK 12
+#define IWL3165_UCODE_API_OK 13
/* Lowest firmware API version supported */
#define IWL7260_UCODE_API_MIN 10
-#define IWL3160_UCODE_API_MIN 10
+#define IWL3165_UCODE_API_MIN 13
/* NVM versions */
#define IWL7260_NVM_VERSION 0x0a1d
@@ -104,9 +103,6 @@
#define IWL3160_FW_PRE "iwlwifi-3160-"
#define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode"
-#define IWL3165_FW_PRE "iwlwifi-3165-"
-#define IWL3165_MODULE_FIRMWARE(api) IWL3165_FW_PRE __stringify(api) ".ucode"
-
#define IWL7265_FW_PRE "iwlwifi-7265-"
#define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode"
@@ -128,6 +124,28 @@ static const struct iwl_base_params iwl7000_base_params = {
.apmg_wake_up_wa = true,
};
+static const struct iwl_tt_params iwl7000_high_temp_tt_params = {
+ .ct_kill_entry = 118,
+ .ct_kill_exit = 96,
+ .ct_kill_duration = 5,
+ .dynamic_smps_entry = 114,
+ .dynamic_smps_exit = 110,
+ .tx_protection_entry = 114,
+ .tx_protection_exit = 108,
+ .tx_backoff = {
+ {.temperature = 112, .backoff = 300},
+ {.temperature = 113, .backoff = 800},
+ {.temperature = 114, .backoff = 1500},
+ {.temperature = 115, .backoff = 3000},
+ {.temperature = 116, .backoff = 5000},
+ {.temperature = 117, .backoff = 10000},
+ },
+ .support_ct_kill = true,
+ .support_dynamic_smps = true,
+ .support_tx_protection = true,
+ .support_tx_backoff = true,
+};
+
static const struct iwl_ht_params iwl7000_ht_params = {
.stbc = true,
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
@@ -170,6 +188,7 @@ const struct iwl_cfg iwl7260_2ac_cfg_high_temp = {
.host_interrupt_operation_mode = true,
.lp_xtal_workaround = true,
.dccm_len = IWL7260_DCCM_LEN,
+ .thermal_params = &iwl7000_high_temp_tt_params,
};
const struct iwl_cfg iwl7260_2n_cfg = {
@@ -248,8 +267,13 @@ static const struct iwl_ht_params iwl7265_ht_params = {
const struct iwl_cfg iwl3165_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 3165",
- .fw_name_pre = IWL3165_FW_PRE,
+ .fw_name_pre = IWL7265D_FW_PRE,
IWL_DEVICE_7000,
+ /* sparse doens't like the re-assignment but it is safe */
+#ifndef __CHECKER__
+ .ucode_api_ok = IWL3165_UCODE_API_OK,
+ .ucode_api_min = IWL3165_UCODE_API_MIN,
+#endif
.ht_params = &iwl7000_ht_params,
.nvm_ver = IWL3165_NVM_VERSION,
.nvm_calib_ver = IWL3165_TX_POWER_VERSION,
@@ -325,6 +349,5 @@ const struct iwl_cfg iwl7265d_n_cfg = {
MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK));
-MODULE_FIRMWARE(IWL3165_MODULE_FIRMWARE(IWL3160_UCODE_API_OK));
MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c
index ce6321b7d241..72040cd0b979 100644
--- a/drivers/net/wireless/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-8000.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2014 - 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -69,7 +69,7 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
-#define IWL8000_UCODE_API_MAX 13
+#define IWL8000_UCODE_API_MAX 15
/* Oldest version we won't warn about */
#define IWL8000_UCODE_API_OK 12
@@ -122,24 +122,49 @@ static const struct iwl_ht_params iwl8000_ht_params = {
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
};
-#define IWL_DEVICE_8000 \
- .ucode_api_max = IWL8000_UCODE_API_MAX, \
- .ucode_api_ok = IWL8000_UCODE_API_OK, \
- .ucode_api_min = IWL8000_UCODE_API_MIN, \
- .device_family = IWL_DEVICE_FAMILY_8000, \
- .max_inst_size = IWL60_RTC_INST_SIZE, \
- .max_data_size = IWL60_RTC_DATA_SIZE, \
- .base_params = &iwl8000_base_params, \
- .led_mode = IWL_LED_RF_STATE, \
- .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \
- .d0i3 = true, \
- .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
+static const struct iwl_tt_params iwl8000_tt_params = {
+ .ct_kill_entry = 115,
+ .ct_kill_exit = 93,
+ .ct_kill_duration = 5,
+ .dynamic_smps_entry = 111,
+ .dynamic_smps_exit = 107,
+ .tx_protection_entry = 112,
+ .tx_protection_exit = 105,
+ .tx_backoff = {
+ {.temperature = 110, .backoff = 200},
+ {.temperature = 111, .backoff = 600},
+ {.temperature = 112, .backoff = 1200},
+ {.temperature = 113, .backoff = 2000},
+ {.temperature = 114, .backoff = 4000},
+ },
+ .support_ct_kill = true,
+ .support_dynamic_smps = true,
+ .support_tx_protection = true,
+ .support_tx_backoff = true,
+};
+
+#define IWL_DEVICE_8000 \
+ .ucode_api_max = IWL8000_UCODE_API_MAX, \
+ .ucode_api_ok = IWL8000_UCODE_API_OK, \
+ .ucode_api_min = IWL8000_UCODE_API_MIN, \
+ .device_family = IWL_DEVICE_FAMILY_8000, \
+ .max_inst_size = IWL60_RTC_INST_SIZE, \
+ .max_data_size = IWL60_RTC_DATA_SIZE, \
+ .base_params = &iwl8000_base_params, \
+ .led_mode = IWL_LED_RF_STATE, \
+ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \
+ .d0i3 = true, \
+ .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, \
+ .default_nvm_file_B_step = DEFAULT_NVM_FILE_FAMILY_8000B, \
+ .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C, \
+ .thermal_params = &iwl8000_tt_params, \
+ .apmg_not_supported = true
const struct iwl_cfg iwl8260_2n_cfg = {
.name = "Intel(R) Dual Band Wireless N 8260",
@@ -177,8 +202,6 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
.ht_params = &iwl8000_ht_params,
.nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
- .default_nvm_file_B_step = DEFAULT_NVM_FILE_FAMILY_8000B,
- .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C,
.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
.disable_dummy_notification = true,
.max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO,
@@ -192,8 +215,6 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = {
.ht_params = &iwl8000_ht_params,
.nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
- .default_nvm_file_B_step = DEFAULT_NVM_FILE_FAMILY_8000B,
- .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C,
.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
.bt_shared_single_ant = true,
.disable_dummy_notification = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 3f33f753ce2f..08c14afeb148 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -195,6 +195,49 @@ struct iwl_ht_params {
};
/*
+ * Tx-backoff threshold
+ * @temperature: The threshold in Celsius
+ * @backoff: The tx-backoff in uSec
+ */
+struct iwl_tt_tx_backoff {
+ s32 temperature;
+ u32 backoff;
+};
+
+#define TT_TX_BACKOFF_SIZE 6
+
+/**
+ * struct iwl_tt_params - thermal throttling parameters
+ * @ct_kill_entry: CT Kill entry threshold
+ * @ct_kill_exit: CT Kill exit threshold
+ * @ct_kill_duration: The time intervals (in uSec) in which the driver needs
+ * to checks whether to exit CT Kill.
+ * @dynamic_smps_entry: Dynamic SMPS entry threshold
+ * @dynamic_smps_exit: Dynamic SMPS exit threshold
+ * @tx_protection_entry: TX protection entry threshold
+ * @tx_protection_exit: TX protection exit threshold
+ * @tx_backoff: Array of thresholds for tx-backoff , in ascending order.
+ * @support_ct_kill: Support CT Kill?
+ * @support_dynamic_smps: Support dynamic SMPS?
+ * @support_tx_protection: Support tx protection?
+ * @support_tx_backoff: Support tx-backoff?
+ */
+struct iwl_tt_params {
+ s32 ct_kill_entry;
+ s32 ct_kill_exit;
+ u32 ct_kill_duration;
+ s32 dynamic_smps_entry;
+ s32 dynamic_smps_exit;
+ s32 tx_protection_entry;
+ s32 tx_protection_exit;
+ struct iwl_tt_tx_backoff tx_backoff[TT_TX_BACKOFF_SIZE];
+ bool support_ct_kill;
+ bool support_dynamic_smps;
+ bool support_tx_protection;
+ bool support_tx_backoff;
+};
+
+/*
* information on how to parse the EEPROM
*/
#define EEPROM_REG_BAND_1_CHANNELS 0x08
@@ -316,6 +359,8 @@ struct iwl_cfg {
const u32 dccm2_len;
const u32 smem_offset;
const u32 smem_len;
+ const struct iwl_tt_params *thermal_params;
+ bool apmg_not_supported;
};
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h
index 223b8752f924..948ce0802fa7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h
@@ -1,6 +1,7 @@
/******************************************************************************
*
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 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
@@ -64,19 +65,21 @@ TRACE_EVENT(iwlwifi_dev_hcmd,
TRACE_EVENT(iwlwifi_dev_rx,
TP_PROTO(const struct device *dev, const struct iwl_trans *trans,
- void *rxbuf, size_t len),
- TP_ARGS(dev, trans, rxbuf, len),
+ struct iwl_rx_packet *pkt, size_t len),
+ TP_ARGS(dev, trans, pkt, len),
TP_STRUCT__entry(
DEV_ENTRY
- __dynamic_array(u8, rxbuf, iwl_rx_trace_len(trans, rxbuf, len))
+ __field(u8, cmd)
+ __dynamic_array(u8, rxbuf, iwl_rx_trace_len(trans, pkt, len))
),
TP_fast_assign(
DEV_ASSIGN;
- memcpy(__get_dynamic_array(rxbuf), rxbuf,
- iwl_rx_trace_len(trans, rxbuf, len));
+ __entry->cmd = pkt->hdr.cmd;
+ memcpy(__get_dynamic_array(rxbuf), pkt,
+ iwl_rx_trace_len(trans, pkt, len));
),
TP_printk("[%s] RX cmd %#.2x",
- __get_str(dev), ((u8 *)__get_dynamic_array(rxbuf))[4])
+ __get_str(dev), __entry->cmd)
);
TRACE_EVENT(iwlwifi_dev_tx,
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index 7267152e7dc7..6685259927f8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -423,13 +423,19 @@ static int iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data,
{
const struct iwl_ucode_api *ucode_api = (void *)data;
u32 api_index = le32_to_cpu(ucode_api->api_index);
+ u32 api_flags = le32_to_cpu(ucode_api->api_flags);
+ int i;
- if (api_index >= IWL_API_ARRAY_SIZE) {
+ if (api_index >= IWL_API_MAX_BITS / 32) {
IWL_ERR(drv, "api_index larger than supported by driver\n");
- return -EINVAL;
+ /* don't return an error so we can load FW that has more bits */
+ return 0;
}
- capa->api[api_index] = le32_to_cpu(ucode_api->api_flags);
+ for (i = 0; i < 32; i++) {
+ if (api_flags & BIT(i))
+ __set_bit(i + 32 * api_index, capa->_api);
+ }
return 0;
}
@@ -439,13 +445,19 @@ static int iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data,
{
const struct iwl_ucode_capa *ucode_capa = (void *)data;
u32 api_index = le32_to_cpu(ucode_capa->api_index);
+ u32 api_flags = le32_to_cpu(ucode_capa->api_capa);
+ int i;
- if (api_index >= IWL_CAPABILITIES_ARRAY_SIZE) {
+ if (api_index >= IWL_CAPABILITIES_MAX_BITS / 32) {
IWL_ERR(drv, "api_index larger than supported by driver\n");
- return -EINVAL;
+ /* don't return an error so we can load FW that has more bits */
+ return 0;
}
- capa->capa[api_index] = le32_to_cpu(ucode_capa->api_capa);
+ for (i = 0; i < 32; i++) {
+ if (api_flags & BIT(i))
+ __set_bit(i + 32 * api_index, capa->_capa);
+ }
return 0;
}
@@ -1148,7 +1160,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
if (err)
goto try_again;
- if (drv->fw.ucode_capa.api[0] & IWL_UCODE_TLV_API_NEW_VERSION)
+ if (fw_has_api(&drv->fw.ucode_capa, IWL_UCODE_TLV_API_NEW_VERSION))
api_ver = drv->fw.ucode_ver;
else
api_ver = IWL_UCODE_API(drv->fw.ucode_ver);
@@ -1239,6 +1251,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
sizeof(struct iwl_fw_dbg_trigger_txq_timer);
trigger_tlv_sz[FW_DBG_TRIGGER_TIME_EVENT] =
sizeof(struct iwl_fw_dbg_trigger_time_event);
+ trigger_tlv_sz[FW_DBG_TRIGGER_BA] =
+ sizeof(struct iwl_fw_dbg_trigger_ba);
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++) {
if (pieces->dbg_trigger_tlv[i]) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
index 41ff85de7334..21302b6f2bfd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 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
@@ -31,6 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -748,6 +750,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
return;
}
+ if (data->sku_cap_mimo_disabled)
+ rx_chains = 1;
+
ht_info->ht_supported = true;
ht_info->cap = IEEE80211_HT_CAP_DSSSCCK40;
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
index 5234a0bf11e4..750c8c9ee70d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 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
@@ -31,6 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -84,6 +86,7 @@ struct iwl_nvm_data {
bool sku_cap_11ac_enable;
bool sku_cap_amt_enable;
bool sku_cap_ipan_enable;
+ bool sku_cap_mimo_disabled;
u16 radio_cfg_type;
u8 radio_cfg_step;
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index d45dc021cda2..d56064861a9c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -438,12 +438,6 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
#define RX_QUEUE_MASK 255
#define RX_QUEUE_SIZE_LOG 8
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 64
-#define RX_LOW_WATERMARK 8
-
/**
* struct iwl_rb_status - reserve buffer status
* host memory mapped FH registers
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index 251bf8dc4a12..e57dbd0ef2e1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2014 - 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -254,6 +254,7 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
* detection.
* @FW_DBG_TRIGGER_TIME_EVENT: trigger log collection upon time events related
* events.
+ * @FW_DBG_TRIGGER_BA: trigger log collection upon BlockAck related events.
*/
enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_INVALID = 0,
@@ -267,6 +268,7 @@ enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_RSSI,
FW_DBG_TRIGGER_TXQ_TIMERS,
FW_DBG_TRIGGER_TIME_EVENT,
+ FW_DBG_TRIGGER_BA,
/* must be last */
FW_DBG_TRIGGER_MAX,
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 62db2e5e45eb..a9b5ae4ebec0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -237,6 +237,8 @@ enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_GO_UAPSD = BIT(30),
};
+typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t;
+
/**
* enum iwl_ucode_tlv_api - ucode api
* @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex
@@ -255,22 +257,27 @@ enum iwl_ucode_tlv_flag {
* @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params
* @IWL_UCODE_TLV_API_STATS_V10: uCode supports/uses statistics API version 10
* @IWL_UCODE_TLV_API_NEW_VERSION: new versioning format
+ * @IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY: scan APIs use 8-level priority
+ * instead of 3.
*/
enum iwl_ucode_tlv_api {
- IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3),
- IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8),
- IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = BIT(9),
- IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10),
- IWL_UCODE_TLV_API_TX_POWER_DEV = BIT(11),
- 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),
- IWL_UCODE_TLV_API_STATS_V10 = BIT(19),
- IWL_UCODE_TLV_API_NEW_VERSION = BIT(20),
+ IWL_UCODE_TLV_API_BT_COEX_SPLIT = (__force iwl_ucode_tlv_api_t)3,
+ IWL_UCODE_TLV_API_FRAGMENTED_SCAN = (__force iwl_ucode_tlv_api_t)8,
+ IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = (__force iwl_ucode_tlv_api_t)9,
+ IWL_UCODE_TLV_API_HDC_PHASE_0 = (__force iwl_ucode_tlv_api_t)10,
+ IWL_UCODE_TLV_API_TX_POWER_DEV = (__force iwl_ucode_tlv_api_t)11,
+ IWL_UCODE_TLV_API_BASIC_DWELL = (__force iwl_ucode_tlv_api_t)13,
+ IWL_UCODE_TLV_API_SCD_CFG = (__force iwl_ucode_tlv_api_t)15,
+ IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = (__force iwl_ucode_tlv_api_t)16,
+ IWL_UCODE_TLV_API_ASYNC_DTM = (__force iwl_ucode_tlv_api_t)17,
+ IWL_UCODE_TLV_API_LQ_SS_PARAMS = (__force iwl_ucode_tlv_api_t)18,
+ IWL_UCODE_TLV_API_STATS_V10 = (__force iwl_ucode_tlv_api_t)19,
+ IWL_UCODE_TLV_API_NEW_VERSION = (__force iwl_ucode_tlv_api_t)20,
+ IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY = (__force iwl_ucode_tlv_api_t)24,
};
+typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
+
/**
* enum iwl_ucode_tlv_capa - ucode capabilities
* @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3
@@ -290,6 +297,7 @@ enum iwl_ucode_tlv_api {
* which also implies support for the scheduler configuration command
* @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching
* @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command
+ * @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command
* @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics
* @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running
* @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different
@@ -299,22 +307,23 @@ enum iwl_ucode_tlv_api {
* @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC
*/
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),
- IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10),
- IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = BIT(11),
- IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12),
- IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = BIT(13),
- IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18),
- IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = BIT(22),
- IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = BIT(28),
- IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = BIT(29),
- IWL_UCODE_TLV_CAPA_BT_COEX_RRC = BIT(30),
+ IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = (__force iwl_ucode_tlv_capa_t)0,
+ IWL_UCODE_TLV_CAPA_LAR_SUPPORT = (__force iwl_ucode_tlv_capa_t)1,
+ IWL_UCODE_TLV_CAPA_UMAC_SCAN = (__force iwl_ucode_tlv_capa_t)2,
+ IWL_UCODE_TLV_CAPA_BEAMFORMER = (__force iwl_ucode_tlv_capa_t)3,
+ IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = (__force iwl_ucode_tlv_capa_t)6,
+ IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = (__force iwl_ucode_tlv_capa_t)8,
+ IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = (__force iwl_ucode_tlv_capa_t)9,
+ IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = (__force iwl_ucode_tlv_capa_t)10,
+ IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = (__force iwl_ucode_tlv_capa_t)11,
+ IWL_UCODE_TLV_CAPA_DQA_SUPPORT = (__force iwl_ucode_tlv_capa_t)12,
+ IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = (__force iwl_ucode_tlv_capa_t)13,
+ IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = (__force iwl_ucode_tlv_capa_t)18,
+ IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT = (__force iwl_ucode_tlv_capa_t)19,
+ IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = (__force iwl_ucode_tlv_capa_t)22,
+ IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = (__force iwl_ucode_tlv_capa_t)28,
+ IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29,
+ IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30,
};
/* The default calibrate table size if not specified by firmware file */
@@ -325,13 +334,14 @@ enum iwl_ucode_tlv_capa {
/* The default max probe length if not specified by the firmware file */
#define IWL_DEFAULT_MAX_PROBE_LENGTH 200
+#define IWL_API_MAX_BITS 64
+#define IWL_CAPABILITIES_MAX_BITS 64
+
/*
* For 16.0 uCode and above, there is no differentiation between sections,
* just an offset to the HW address.
*/
#define IWL_UCODE_SECTION_MAX 12
-#define IWL_API_ARRAY_SIZE 1
-#define IWL_CAPABILITIES_ARRAY_SIZE 1
#define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC
/* uCode version contains 4 values: Major/Minor/API/Serial */
@@ -424,11 +434,13 @@ struct iwl_fw_dbg_reg_op {
* @SMEM_MODE: monitor stores the data in SMEM
* @EXTERNAL_MODE: monitor stores the data in allocated DRAM
* @MARBH_MODE: monitor stores the data in MARBH buffer
+ * @MIPI_MODE: monitor outputs the data through the MIPI interface
*/
enum iwl_fw_dbg_monitor_mode {
SMEM_MODE = 0,
EXTERNAL_MODE = 1,
MARBH_MODE = 2,
+ MIPI_MODE = 3,
};
/**
@@ -436,6 +448,7 @@ enum iwl_fw_dbg_monitor_mode {
*
* @version: version of the TLV - currently 0
* @monitor_mode: %enum iwl_fw_dbg_monitor_mode
+ * @size_power: buffer size will be 2^(size_power + 11)
* @base_reg: addr of the base addr register (PRPH)
* @end_reg: addr of the end addr register (PRPH)
* @write_ptr_reg: the addr of the reg of the write pointer
@@ -449,7 +462,8 @@ enum iwl_fw_dbg_monitor_mode {
struct iwl_fw_dbg_dest_tlv {
u8 version;
u8 monitor_mode;
- u8 reserved[2];
+ u8 size_power;
+ u8 reserved;
__le32 base_reg;
__le32 end_reg;
__le32 write_ptr_reg;
@@ -659,6 +673,33 @@ struct iwl_fw_dbg_trigger_time_event {
} __packed;
/**
+ * struct iwl_fw_dbg_trigger_ba - configures BlockAck related trigger
+ * rx_ba_start: tid bitmap to configure on what tid the trigger should occur
+ * when an Rx BlockAck session is started.
+ * rx_ba_stop: tid bitmap to configure on what tid the trigger should occur
+ * when an Rx BlockAck session is stopped.
+ * tx_ba_start: tid bitmap to configure on what tid the trigger should occur
+ * when a Tx BlockAck session is started.
+ * tx_ba_stop: tid bitmap to configure on what tid the trigger should occur
+ * when a Tx BlockAck session is stopped.
+ * rx_bar: tid bitmap to configure on what tid the trigger should occur
+ * when a BAR is received (for a Tx BlockAck session).
+ * tx_bar: tid bitmap to configure on what tid the trigger should occur
+ * when a BAR is send (for an Rx BlocAck session).
+ * frame_timeout: tid bitmap to configure on what tid the trigger should occur
+ * when a frame times out in the reodering buffer.
+ */
+struct iwl_fw_dbg_trigger_ba {
+ __le16 rx_ba_start;
+ __le16 rx_ba_stop;
+ __le16 tx_ba_start;
+ __le16 tx_ba_stop;
+ __le16 rx_bar;
+ __le16 tx_bar;
+ __le16 frame_timeout;
+} __packed;
+
+/**
* struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration.
* @id: conf id
* @usniffer: should the uSniffer image be used
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index cf75bafae51d..3e3c9d8b3c37 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -105,10 +105,24 @@ struct iwl_ucode_capabilities {
u32 n_scan_channels;
u32 standard_phy_calibration_size;
u32 flags;
- u32 api[IWL_API_ARRAY_SIZE];
- u32 capa[IWL_CAPABILITIES_ARRAY_SIZE];
+ unsigned long _api[BITS_TO_LONGS(IWL_API_MAX_BITS)];
+ unsigned long _capa[BITS_TO_LONGS(IWL_CAPABILITIES_MAX_BITS)];
};
+static inline bool
+fw_has_api(const struct iwl_ucode_capabilities *capabilities,
+ iwl_ucode_tlv_api_t api)
+{
+ return test_bit((__force long)api, capabilities->_api);
+}
+
+static inline bool
+fw_has_capa(const struct iwl_ucode_capabilities *capabilities,
+ iwl_ucode_tlv_capa_t capa)
+{
+ return test_bit((__force long)capa, capabilities->_capa);
+}
+
/* one for each uCode image (inst/data, init/runtime/wowlan) */
struct fw_desc {
const void *data; /* vmalloc'ed data */
@@ -205,6 +219,8 @@ static inline const char *get_fw_dbg_mode_string(int mode)
return "EXTERNAL_DRAM";
case MARBH_MODE:
return "MARBH";
+ case MIPI_MODE:
+ return "MIPI";
default:
return "UNKNOWN";
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index 83903a5025c2..80fefe7d7b8c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -116,10 +116,11 @@ enum family_8000_nvm_offsets {
/* SKU Capabilities (actual values from NVM definition) */
enum nvm_sku_bits {
- NVM_SKU_CAP_BAND_24GHZ = BIT(0),
- NVM_SKU_CAP_BAND_52GHZ = BIT(1),
- NVM_SKU_CAP_11N_ENABLE = BIT(2),
- NVM_SKU_CAP_11AC_ENABLE = BIT(3),
+ NVM_SKU_CAP_BAND_24GHZ = BIT(0),
+ NVM_SKU_CAP_BAND_52GHZ = BIT(1),
+ NVM_SKU_CAP_11N_ENABLE = BIT(2),
+ NVM_SKU_CAP_11AC_ENABLE = BIT(3),
+ NVM_SKU_CAP_MIMO_DISABLE = BIT(5),
};
/*
@@ -248,7 +249,7 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
*/
if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
(flags & IEEE80211_CHAN_NO_IR))
- flags |= IEEE80211_CHAN_GO_CONCURRENT;
+ flags |= IEEE80211_CHAN_IR_CONCURRENT;
return flags;
}
@@ -368,6 +369,11 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
if (cfg->ht_params->ldpc)
vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
+ if (data->sku_cap_mimo_disabled) {
+ num_rx_ants = 1;
+ num_tx_ants = 1;
+ }
+
if (num_tx_ants > 1)
vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
else
@@ -465,7 +471,7 @@ static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, const __le16 *nvm_sw,
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
return le16_to_cpup(nvm_sw + RADIO_CFG);
- return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000));
+ return le32_to_cpup((__le32 *)(phy_sku + RADIO_CFG_FAMILY_8000));
}
@@ -527,6 +533,10 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
const u8 *hw_addr;
if (mac_override) {
+ static const u8 reserved_mac[] = {
+ 0x02, 0xcc, 0xaa, 0xff, 0xee, 0x00
+ };
+
hw_addr = (const u8 *)(mac_override +
MAC_ADDRESS_OVERRIDE_FAMILY_8000);
@@ -538,7 +548,12 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
data->hw_addr[4] = hw_addr[5];
data->hw_addr[5] = hw_addr[4];
- if (is_valid_ether_addr(data->hw_addr))
+ /*
+ * Force the use of the OTP MAC address in case of reserved MAC
+ * address in the NVM, or if address is given but invalid.
+ */
+ if (is_valid_ether_addr(data->hw_addr) &&
+ memcmp(reserved_mac, hw_addr, ETH_ALEN) != 0)
return;
IWL_ERR_DEV(dev,
@@ -610,6 +625,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
data->sku_cap_11n_enable = false;
data->sku_cap_11ac_enable = data->sku_cap_11n_enable &&
(sku & NVM_SKU_CAP_11AC_ENABLE);
+ data->sku_cap_mimo_disabled = sku & NVM_SKU_CAP_MIMO_DISABLE;
data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw);
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 88a57e6e232f..5af1c776d2d4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -348,6 +348,9 @@ enum secure_load_status_reg {
#define MON_BUFF_WRPTR (0xa03c44)
#define MON_BUFF_CYCLE_CNT (0xa03c48)
+#define MON_DMARB_RD_CTL_ADDR (0xa03c60)
+#define MON_DMARB_RD_DATA_ADDR (0xa03c5c)
+
#define DBGC_IN_SAMPLE (0xa03c00)
/* enable the ID buf for read */
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c
new file mode 100644
index 000000000000..9f8bcefc04c5
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.c
@@ -0,0 +1,113 @@
+/******************************************************************************
+ *
+ * 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) 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) 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.
+ *
+ *****************************************************************************/
+#include <linux/kernel.h>
+#include "iwl-trans.h"
+
+struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
+ struct device *dev,
+ const struct iwl_cfg *cfg,
+ const struct iwl_trans_ops *ops,
+ size_t dev_cmd_headroom)
+{
+ struct iwl_trans *trans;
+#ifdef CONFIG_LOCKDEP
+ static struct lock_class_key __key;
+#endif
+
+ trans = kzalloc(sizeof(*trans) + priv_size, GFP_KERNEL);
+ if (!trans)
+ return NULL;
+
+#ifdef CONFIG_LOCKDEP
+ lockdep_init_map(&trans->sync_cmd_lockdep_map, "sync_cmd_lockdep_map",
+ &__key, 0);
+#endif
+
+ trans->dev = dev;
+ trans->cfg = cfg;
+ trans->ops = ops;
+ trans->dev_cmd_headroom = dev_cmd_headroom;
+
+ snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name),
+ "iwl_cmd_pool:%s", dev_name(trans->dev));
+ trans->dev_cmd_pool =
+ kmem_cache_create(trans->dev_cmd_pool_name,
+ sizeof(struct iwl_device_cmd)
+ + trans->dev_cmd_headroom,
+ sizeof(void *),
+ SLAB_HWCACHE_ALIGN,
+ NULL);
+ if (!trans->dev_cmd_pool)
+ goto free;
+
+ return trans;
+ free:
+ kfree(trans);
+ return NULL;
+}
+
+void iwl_trans_free(struct iwl_trans *trans)
+{
+ kmem_cache_destroy(trans->dev_cmd_pool);
+ kfree(trans);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 56254a837214..87a230a7f4b6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -641,6 +641,8 @@ struct iwl_trans {
enum iwl_d0i3_mode d0i3_mode;
+ bool wowlan_d0i3;
+
/* pointer to trans specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */
char trans_specific[0] __aligned(sizeof(void *));
@@ -1011,19 +1013,19 @@ static inline void iwl_trans_fw_error(struct iwl_trans *trans)
}
/*****************************************************
+ * transport helper functions
+ *****************************************************/
+struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
+ struct device *dev,
+ const struct iwl_cfg *cfg,
+ const struct iwl_trans_ops *ops,
+ size_t dev_cmd_headroom);
+void iwl_trans_free(struct iwl_trans *trans);
+
+/*****************************************************
* driver (transport) register/unregister functions
******************************************************/
int __must_check iwl_pci_register_driver(void);
void iwl_pci_unregister_driver(void);
-static inline void trans_lockdep_init(struct iwl_trans *trans)
-{
-#ifdef CONFIG_LOCKDEP
- static struct lock_class_key __key;
-
- lockdep_init_map(&trans->sync_cmd_lockdep_map, "sync_cmd_lockdep_map",
- &__key, 0);
-#endif
-}
-
#endif /* __iwl_trans_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c
index 13a0a03158de..b4737e296c92 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -408,23 +408,12 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif)
int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
{
- struct iwl_bt_coex_cmd *bt_cmd;
- struct iwl_host_cmd cmd = {
- .id = BT_CONFIG,
- .len = { sizeof(*bt_cmd), },
- .dataflags = { IWL_HCMD_DFL_NOCOPY, },
- };
- int ret;
+ struct iwl_bt_coex_cmd bt_cmd = {};
u32 mode;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_send_bt_init_conf_old(mvm);
- bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL);
- if (!bt_cmd)
- return -ENOMEM;
- cmd.data[0] = bt_cmd;
-
lockdep_assert_held(&mvm->mutex);
if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) {
@@ -440,36 +429,33 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
mode = 0;
}
- bt_cmd->mode = cpu_to_le32(mode);
+ bt_cmd.mode = cpu_to_le32(mode);
goto send_cmd;
}
mode = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE;
- bt_cmd->mode = cpu_to_le32(mode);
+ bt_cmd.mode = cpu_to_le32(mode);
if (IWL_MVM_BT_COEX_SYNC2SCO)
- bt_cmd->enabled_modules |=
+ bt_cmd.enabled_modules |=
cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED);
if (iwl_mvm_bt_is_plcr_supported(mvm))
- bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_CORUN_ENABLED);
+ bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_CORUN_ENABLED);
if (IWL_MVM_BT_COEX_MPLUT) {
- bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_MPLUT_ENABLED);
- bt_cmd->enabled_modules |=
+ bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_MPLUT_ENABLED);
+ bt_cmd.enabled_modules |=
cpu_to_le32(BT_COEX_MPLUT_BOOST_ENABLED);
}
- bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET);
+ bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET);
send_cmd:
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
- ret = iwl_mvm_send_cmd(mvm, &cmd);
-
- kfree(bt_cmd);
- return ret;
+ return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, 0, sizeof(bt_cmd), &bt_cmd);
}
static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
@@ -746,7 +732,7 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_rx_bt_coex_notif_old(mvm, rxb, dev_cmd);
IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
@@ -770,52 +756,14 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
return 0;
}
-static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
- struct ieee80211_vif *vif)
-{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_bt_iterator_data *data = _data;
- struct iwl_mvm *mvm = data->mvm;
-
- struct ieee80211_sta *sta;
- struct iwl_mvm_sta *mvmsta;
-
- struct ieee80211_chanctx_conf *chanctx_conf;
-
- rcu_read_lock();
- chanctx_conf = rcu_dereference(vif->chanctx_conf);
- /* If channel context is invalid or not on 2.4GHz - don't count it */
- if (!chanctx_conf ||
- chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) {
- rcu_read_unlock();
- return;
- }
- rcu_read_unlock();
-
- if (vif->type != NL80211_IFTYPE_STATION ||
- mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
- return;
-
- sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
- lockdep_is_held(&mvm->mutex));
-
- /* This can happen if the station has been removed right now */
- if (IS_ERR_OR_NULL(sta))
- return;
-
- mvmsta = iwl_mvm_sta_from_mac80211(sta);
-}
-
void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum ieee80211_rssi_event_data rssi_event)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_bt_iterator_data data = {
- .mvm = mvm,
- };
int ret;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
+ if (!fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
iwl_mvm_bt_rssi_event_old(mvm, vif, rssi_event);
return;
}
@@ -853,10 +801,6 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (ret)
IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n");
-
- ieee80211_iterate_active_interfaces_atomic(
- mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_bt_rssi_iterator, &data);
}
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000)
@@ -870,7 +814,7 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
enum iwl_bt_coex_lut_type lut_type;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_coex_agg_time_limit_old(mvm, sta);
if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id))
@@ -897,7 +841,7 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt;
enum iwl_bt_coex_lut_type lut_type;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_bt_coex_is_mimo_allowed_old(mvm, sta);
if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id))
@@ -927,7 +871,7 @@ bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant)
if (ant & mvm->cfg->non_shared_ant)
return true;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);
return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
@@ -940,10 +884,10 @@ bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
if (mvm->cfg->bt_shared_single_ant)
return true;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);
- return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF;
+ return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC;
}
bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
@@ -951,7 +895,7 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
{
u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading);
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_bt_coex_is_tpc_allowed_old(mvm, band);
if (band != IEEE80211_BAND_2GHZ)
@@ -994,7 +938,8 @@ u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)
{
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
+ if (!fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
iwl_mvm_bt_coex_vif_change_old(mvm);
return;
}
@@ -1012,7 +957,7 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
u8 __maybe_unused lower_bound, upper_bound;
u8 lut;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd);
if (!iwl_mvm_bt_is_plcr_supported(mvm))
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
index d954591e0be5..6ac6de2af977 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
@@ -776,7 +776,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
struct iwl_host_cmd cmd = {
.id = BT_CONFIG,
.len = { sizeof(*bt_cmd), },
- .dataflags = { IWL_HCMD_DFL_NOCOPY, },
+ .dataflags = { IWL_HCMD_DFL_DUP, },
.flags = CMD_ASYNC,
};
struct iwl_mvm_sta *mvmsta;
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index 1b1b2bf26819..4165d104e4c3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -761,7 +761,7 @@ void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
{
- iwl_mvm_cancel_scan(mvm);
+ iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);
iwl_trans_stop_device(mvm->trans);
@@ -981,7 +981,8 @@ iwl_mvm_netdetect_config(struct iwl_mvm *mvm,
if (ret)
return ret;
- ret = iwl_mvm_scan_offload_start(mvm, vif, nd_config, &mvm->nd_ies);
+ ret = iwl_mvm_sched_scan_start(mvm, vif, nd_config, &mvm->nd_ies,
+ IWL_MVM_SCAN_NETDETECT);
if (ret)
return ret;
@@ -1169,7 +1170,8 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
iwl_trans_suspend(mvm->trans);
- if (wowlan->any) {
+ mvm->trans->wowlan_d0i3 = wowlan->any;
+ if (mvm->trans->wowlan_d0i3) {
/* 'any' trigger means d0i3 usage */
if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) {
int ret = iwl_mvm_enter_d0i3_sync(mvm);
@@ -1750,8 +1752,10 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
int i, j, n_matches, ret;
fw_status = iwl_mvm_get_wakeup_status(mvm, vif);
- if (!IS_ERR_OR_NULL(fw_status))
+ if (!IS_ERR_OR_NULL(fw_status)) {
reasons = le32_to_cpu(fw_status->wakeup_reasons);
+ kfree(fw_status);
+ }
if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)
wakeup.rfkill_release = true;
@@ -1782,7 +1786,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
for_each_set_bit(i, &matched_profiles, mvm->n_nd_match_sets) {
struct iwl_scan_offload_profile_match *fw_match;
struct cfg80211_wowlan_nd_match *match;
- int n_channels = 0;
+ int idx, n_channels = 0;
fw_match = &query.matches[i];
@@ -1797,8 +1801,12 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
net_detect->matches[net_detect->n_matches++] = match;
- match->ssid.ssid_len = mvm->nd_match_sets[i].ssid.ssid_len;
- memcpy(match->ssid.ssid, mvm->nd_match_sets[i].ssid.ssid,
+ /* We inverted the order of the SSIDs in the scan
+ * request, so invert the index here.
+ */
+ idx = mvm->n_nd_match_sets - i - 1;
+ match->ssid.ssid_len = mvm->nd_match_sets[idx].ssid.ssid_len;
+ memcpy(match->ssid.ssid, mvm->nd_match_sets[idx].ssid.ssid,
match->ssid.ssid_len);
if (mvm->n_nd_channels < n_channels)
@@ -1868,15 +1876,15 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
/* get the BSS vif pointer again */
vif = iwl_mvm_get_bss_vif(mvm);
if (IS_ERR_OR_NULL(vif))
- goto out_unlock;
+ goto err;
ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
if (ret)
- goto out_unlock;
+ goto err;
if (d3_status != IWL_D3_STATUS_ALIVE) {
IWL_INFO(mvm, "Device was reset during suspend\n");
- goto out_unlock;
+ goto err;
}
/* query SRAM first in case we want event logging */
@@ -1902,7 +1910,8 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
goto out_iterate;
}
- out_unlock:
+err:
+ iwl_mvm_free_nd(mvm);
mutex_unlock(&mvm->mutex);
out_iterate:
@@ -1915,6 +1924,14 @@ out:
/* return 1 to reconfigure the device */
set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status);
+
+ /* We always return 1, which causes mac80211 to do a reconfig
+ * with IEEE80211_RECONFIG_TYPE_RESTART. This type of
+ * reconfig calls iwl_mvm_restart_complete(), where we unref
+ * the IWL_MVM_REF_UCODE_DOWN, so we need to take the
+ * reference here.
+ */
+ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
return 1;
}
@@ -2021,7 +2038,6 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
__iwl_mvm_resume(mvm, true);
rtnl_unlock();
iwl_abort_notification_waits(&mvm->notif_wait);
- iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
ieee80211_restart_hw(mvm->hw);
/* wait for restart and disconnect all interfaces */
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
index 5f37eab5008d..5c8a65de0e77 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -190,6 +190,21 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
return ret ?: count;
}
+static ssize_t iwl_dbgfs_tx_pwr_lmt_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_vif *vif = file->private_data;
+ char buf[64];
+ int bufsz = sizeof(buf);
+ int pos;
+
+ pos = scnprintf(buf, bufsz, "bss limit = %d\n",
+ vif->bss_conf.txpower);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@@ -607,6 +622,7 @@ static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
} while (0)
MVM_DEBUGFS_READ_FILE_OPS(mac_params);
+MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
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);
@@ -641,6 +657,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, S_IRUSR);
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);
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index 9ac04c1ea706..ffb4b5cef275 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -493,7 +493,8 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
mutex_lock(&mvm->mutex);
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
+ if (!fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
struct iwl_bt_coex_profile_notif_old *notif =
&mvm->last_bt_notif_old;
@@ -550,7 +551,8 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
mutex_lock(&mvm->mutex);
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
+ if (!fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_BT_COEX_SPLIT)) {
struct iwl_bt_coex_ci_cmd_old *cmd = &mvm->last_bt_ci_cmd_old;
pos += scnprintf(buf+pos, bufsz-pos,
@@ -916,7 +918,8 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
if (mvm->scan_rx_ant != scan_rx_ant) {
mvm->scan_rx_ant = scan_rx_ant;
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_UMAC_SCAN))
iwl_mvm_config_scan(mvm);
}
@@ -1356,6 +1359,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN);
PRINT_MVM_REF(IWL_MVM_REF_SCAN);
PRINT_MVM_REF(IWL_MVM_REF_ROC);
+ PRINT_MVM_REF(IWL_MVM_REF_ROC_AUX);
PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT);
PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
PRINT_MVM_REF(IWL_MVM_REF_USER);
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
index d6cced47d561..5e4cbdb44c60 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -274,50 +274,18 @@ struct iwl_scan_offload_profile_cfg {
} __packed;
/**
- * iwl_scan_offload_schedule - schedule of scan offload
+ * iwl_scan_schedule_lmac - schedule of scan offload
* @delay: delay between iterations, in seconds.
* @iterations: num of scan iterations
* @full_scan_mul: number of partial scans before each full scan
*/
-struct iwl_scan_offload_schedule {
+struct iwl_scan_schedule_lmac {
__le16 delay;
u8 iterations;
u8 full_scan_mul;
-} __packed;
-
-/*
- * iwl_scan_offload_flags
- *
- * IWL_SCAN_OFFLOAD_FLAG_PASS_ALL: pass all results - no filtering.
- * IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan.
- * IWL_SCAN_OFFLOAD_FLAG_EBS_QUICK_MODE: EBS duration is 100mSec - typical
- * beacon period. Finding channel activity in this mode is not guaranteed.
- * IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE: EBS duration is 200mSec.
- * Assuming beacon period is 100ms finding channel activity is guaranteed.
- */
-enum iwl_scan_offload_flags {
- IWL_SCAN_OFFLOAD_FLAG_PASS_ALL = BIT(0),
- IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL = BIT(2),
- IWL_SCAN_OFFLOAD_FLAG_EBS_QUICK_MODE = BIT(5),
- IWL_SCAN_OFFLOAD_FLAG_EBS_ACCURATE_MODE = BIT(6),
-};
-
-/**
- * iwl_scan_offload_req - scan offload request command
- * @flags: bitmap - enum iwl_scan_offload_flags.
- * @watchdog: maximum scan duration in TU.
- * @delay: delay in seconds before first iteration.
- * @schedule_line: scan offload schedule, for fast and regular scan.
- */
-struct iwl_scan_offload_req {
- __le16 flags;
- __le16 watchdog;
- __le16 delay;
- __le16 reserved;
- struct iwl_scan_offload_schedule schedule_line[2];
-} __packed;
+} __packed; /* SCAN_SCHEDULE_API_S */
-enum iwl_scan_offload_compleate_status {
+enum iwl_scan_offload_complete_status {
IWL_SCAN_OFFLOAD_COMPLETED = 1,
IWL_SCAN_OFFLOAD_ABORTED = 2,
};
@@ -326,6 +294,7 @@ enum iwl_scan_ebs_status {
IWL_SCAN_EBS_SUCCESS,
IWL_SCAN_EBS_FAILED,
IWL_SCAN_EBS_CHAN_NOT_FOUND,
+ IWL_SCAN_EBS_INACTIVE,
};
/**
@@ -463,8 +432,19 @@ enum iwl_scan_priority {
IWL_SCAN_PRIORITY_HIGH,
};
+enum iwl_scan_priority_ext {
+ IWL_SCAN_PRIORITY_EXT_0_LOWEST,
+ IWL_SCAN_PRIORITY_EXT_1,
+ IWL_SCAN_PRIORITY_EXT_2,
+ IWL_SCAN_PRIORITY_EXT_3,
+ IWL_SCAN_PRIORITY_EXT_4,
+ IWL_SCAN_PRIORITY_EXT_5,
+ IWL_SCAN_PRIORITY_EXT_6,
+ IWL_SCAN_PRIORITY_EXT_7_HIGHEST,
+};
+
/**
- * iwl_scan_req_unified_lmac - SCAN_REQUEST_CMD_API_S_VER_1
+ * iwl_scan_req_lmac - SCAN_REQUEST_CMD_API_S_VER_1
* @reserved1: for alignment and future use
* @channel_num: num of channels to scan
* @active-dwell: dwell time for active channels
@@ -487,7 +467,7 @@ enum iwl_scan_priority {
* @channel_opt: channel optimization options, for full and partial scan
* @data: channel configuration and probe request packet.
*/
-struct iwl_scan_req_unified_lmac {
+struct iwl_scan_req_lmac {
/* SCAN_REQUEST_FIXED_PART_API_S_VER_7 */
__le32 reserved1;
u8 n_channels;
@@ -508,7 +488,7 @@ struct iwl_scan_req_unified_lmac {
/* SCAN_REQ_PERIODIC_PARAMS_API_S */
__le32 iter_num;
__le32 delay;
- struct iwl_scan_offload_schedule schedule[2];
+ struct iwl_scan_schedule_lmac schedule[2];
struct iwl_scan_channel_opt channel_opt[2];
u8 data[];
} __packed;
@@ -582,7 +562,11 @@ struct iwl_mvm_umac_cmd_hdr {
u8 ver;
} __packed;
-#define IWL_MVM_MAX_SIMULTANEOUS_SCANS 8
+/* The maximum of either of these cannot exceed 8, because we use an
+ * 8-bit mask (see IWL_MVM_SCAN_MASK in mvm.h).
+ */
+#define IWL_MVM_MAX_UMAC_SCANS 8
+#define IWL_MVM_MAX_LMAC_SCANS 1
enum scan_config_flags {
SCAN_CONFIG_FLAG_ACTIVATE = BIT(0),
@@ -865,4 +849,27 @@ struct iwl_scan_offload_profiles_query {
struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES];
} __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_2 */
+/**
+ * struct iwl_umac_scan_iter_complete_notif - notifies end of scanning iteration
+ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+ * @scanned_channels: number of channels scanned and number of valid elements in
+ * results array
+ * @status: one of SCAN_COMP_STATUS_*
+ * @bt_status: BT on/off status
+ * @last_channel: last channel that was scanned
+ * @tsf_low: TSF timer (lower half) in usecs
+ * @tsf_high: TSF timer (higher half) in usecs
+ * @results: array of scan results, only "scanned_channels" of them are valid
+ */
+struct iwl_umac_scan_iter_complete_notif {
+ __le32 uid;
+ u8 scanned_channels;
+ u8 status;
+ u8 bt_status;
+ u8 last_channel;
+ __le32 tsf_low;
+ __le32 tsf_high;
+ struct iwl_scan_results_notif results[];
+} __packed; /* SCAN_ITER_COMPLETE_NTF_UMAC_API_S_VER_1 */
+
#endif
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 01b1da6ad359..16e9ef49397f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -108,6 +108,7 @@ enum {
ANTENNA_COUPLING_NOTIFICATION = 0xa,
/* UMAC scan commands */
+ SCAN_ITERATION_COMPLETE_UMAC = 0xb5,
SCAN_CFG_CMD = 0xc,
SCAN_REQ_UMAC = 0xd,
SCAN_ABORT_UMAC = 0xe,
@@ -147,13 +148,6 @@ enum {
LQ_CMD = 0x4e,
- /* Calibration */
- TEMPERATURE_NOTIFICATION = 0x62,
- CALIBRATION_CFG_CMD = 0x65,
- CALIBRATION_RES_NOTIFICATION = 0x66,
- CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
- RADIO_VERSION_NOTIFICATION = 0x68,
-
/* Scan offload */
SCAN_OFFLOAD_REQUEST_CMD = 0x51,
SCAN_OFFLOAD_ABORT_CMD = 0x52,
@@ -177,12 +171,8 @@ enum {
/* Thermal Throttling*/
REPLY_THERMAL_MNG_BACKOFF = 0x7e,
- /* Scanning */
- SCAN_REQUEST_CMD = 0x80,
- SCAN_ABORT_CMD = 0x81,
- SCAN_START_NOTIFICATION = 0x82,
- SCAN_RESULTS_NOTIFICATION = 0x83,
- SCAN_COMPLETE_NOTIFICATION = 0x84,
+ /* Set/Get DC2DC frequency tune */
+ DC2DC_CONFIG_CMD = 0x83,
/* NVM */
NVM_ACCESS_CMD = 0x88,
@@ -1402,6 +1392,49 @@ struct iwl_mvm_marker {
__le32 metadata[0];
} __packed; /* MARKER_API_S_VER_1 */
+/*
+ * enum iwl_dc2dc_config_id - flag ids
+ *
+ * Ids of dc2dc configuration flags
+ */
+enum iwl_dc2dc_config_id {
+ DCDC_LOW_POWER_MODE_MSK_SET = 0x1, /* not used */
+ DCDC_FREQ_TUNE_SET = 0x2,
+}; /* MARKER_ID_API_E_VER_1 */
+
+/**
+ * struct iwl_dc2dc_config_cmd - configure dc2dc values
+ *
+ * (DC2DC_CONFIG_CMD = 0x83)
+ *
+ * Set/Get & configure dc2dc values.
+ * The command always returns the current dc2dc values.
+ *
+ * @flags: set/get dc2dc
+ * @enable_low_power_mode: not used.
+ * @dc2dc_freq_tune0: frequency divider - digital domain
+ * @dc2dc_freq_tune1: frequency divider - analog domain
+ */
+struct iwl_dc2dc_config_cmd {
+ __le32 flags;
+ __le32 enable_low_power_mode; /* not used */
+ __le32 dc2dc_freq_tune0;
+ __le32 dc2dc_freq_tune1;
+} __packed; /* DC2DC_CONFIG_CMD_API_S_VER_1 */
+
+/**
+ * struct iwl_dc2dc_config_resp - response for iwl_dc2dc_config_cmd
+ *
+ * Current dc2dc values returned by the FW.
+ *
+ * @dc2dc_freq_tune0: frequency divider - digital domain
+ * @dc2dc_freq_tune1: frequency divider - analog domain
+ */
+struct iwl_dc2dc_config_resp {
+ __le32 dc2dc_freq_tune0;
+ __le32 dc2dc_freq_tune1;
+} __packed; /* DC2DC_CONFIG_RESP_API_S_VER_1 */
+
/***********************************
* Smart Fifo API
***********************************/
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index df869633f4dd..eb10c5ee4a14 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -623,7 +623,7 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm)
if (!mvm->trans->ltr_enabled)
return 0;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_HDC_PHASE_0))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_HDC_PHASE_0))
return iwl_mvm_config_ltr_v1(mvm);
return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
@@ -662,9 +662,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
* device that are triggered by the INIT firwmare (MFUART).
*/
_iwl_trans_stop_device(mvm->trans, false);
- _iwl_trans_start_hw(mvm->trans, false);
+ ret = _iwl_trans_start_hw(mvm->trans, false);
if (ret)
- return ret;
+ goto error;
}
if (iwlmvm_mod_params.init_dbg)
@@ -754,7 +754,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto error;
}
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
ret = iwl_mvm_config_scan(mvm);
if (ret)
goto error;
@@ -832,21 +832,6 @@ int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm,
return 0;
}
-int iwl_mvm_rx_radio_ver(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_radio_version_notif *radio_version = (void *)pkt->data;
-
- /* TODO: what to do with that? */
- IWL_DEBUG_INFO(mvm,
- "Radio version: flavor: 0x%08x, step 0x%08x, dash 0x%08x\n",
- le32_to_cpu(radio_version->radio_flavor),
- le32_to_cpu(radio_version->radio_step),
- le32_to_cpu(radio_version->radio_dash));
- return 0;
-}
-
int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 8088c7137f7c..1812dd018af2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -852,7 +852,7 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
MAC_FILTER_IN_BEACON |
MAC_FILTER_IN_PROBE_REQUEST |
MAC_FILTER_IN_CRC32);
- mvm->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
+ ieee80211_hw_set(mvm->hw, RX_INCLUDES_FCS);
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
}
@@ -1270,7 +1270,7 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
mvmvif->uploaded = false;
if (vif->type == NL80211_IFTYPE_MONITOR)
- mvm->hw->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+ __clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, mvm->hw->flags);
return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 40265b9c66ae..dfdab38e2d4a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -80,7 +80,6 @@
#include "sta.h"
#include "time-event.h"
#include "iwl-eeprom-parse.h"
-#include "fw-api-scan.h"
#include "iwl-phy-db.h"
#include "testmode.h"
#include "iwl-fw-error-dump.h"
@@ -319,7 +318,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
resp = iwl_mvm_update_mcc(mvm, alpha2, src_id);
if (IS_ERR_OR_NULL(resp)) {
IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n",
- PTR_RET(resp));
+ PTR_ERR_OR_ZERO(resp));
goto out;
}
@@ -335,7 +334,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
kfree(resp);
if (IS_ERR_OR_NULL(regd)) {
IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n",
- PTR_RET(regd));
+ PTR_ERR_OR_ZERO(regd));
goto out;
}
@@ -416,20 +415,27 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
{
struct ieee80211_hw *hw = mvm->hw;
int num_mac, ret, i;
+ static const u32 mvm_ciphers[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ };
/* Tell mac80211 our characteristics */
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_QUEUE_CONTROL |
- IEEE80211_HW_WANT_MONITOR_VIF |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_TIMING_BEACON_ONLY |
- IEEE80211_HW_CONNECTION_MONITOR |
- IEEE80211_HW_CHANCTX_STA_CSA |
- IEEE80211_HW_SUPPORTS_CLONED_SKBS;
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, QUEUE_CONTROL);
+ ieee80211_hw_set(hw, WANT_MONITOR_VIF);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, TIMING_BEACON_ONLY);
+ ieee80211_hw_set(hw, CONNECTION_MONITOR);
+ ieee80211_hw_set(hw, CHANCTX_STA_CSA);
+ ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
+ ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
hw->queues = mvm->first_agg_queue;
hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
@@ -441,19 +447,38 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
+ BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 2);
+ memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers));
+ hw->wiphy->n_cipher_suites = ARRAY_SIZE(mvm_ciphers);
+ hw->wiphy->cipher_suites = mvm->ciphers;
+
/*
* Enable 11w if advertised by firmware and software crypto
* is not enabled (as the firmware will interpret some mgmt
* packets, so enabling it with software crypto isn't safe)
*/
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP &&
- !iwlwifi_mod_params.sw_crypto)
- hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+ !iwlwifi_mod_params.sw_crypto) {
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ mvm->ciphers[hw->wiphy->n_cipher_suites] =
+ WLAN_CIPHER_SUITE_AES_CMAC;
+ hw->wiphy->n_cipher_suites++;
+ }
- hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS;
+ /* currently FW API supports only one optional cipher scheme */
+ if (mvm->fw->cs[0].cipher) {
+ mvm->hw->n_cipher_schemes = 1;
+ mvm->hw->cipher_schemes = &mvm->fw->cs[0];
+ mvm->ciphers[hw->wiphy->n_cipher_suites] =
+ mvm->fw->cs[0].cipher;
+ hw->wiphy->n_cipher_suites++;
+ }
+
+ ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
hw->wiphy->features |=
NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
- NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
+ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR |
+ NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
hw->sta_data_size = sizeof(struct iwl_mvm_sta);
hw->vif_data_size = sizeof(struct iwl_mvm_vif);
@@ -506,10 +531,19 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
iwl_mvm_reset_phy_ctxts(mvm);
- hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm, false);
+ hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm);
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
+ BUILD_BUG_ON(IWL_MVM_SCAN_STOPPING_MASK & IWL_MVM_SCAN_MASK);
+ BUILD_BUG_ON(IWL_MVM_MAX_UMAC_SCANS > HWEIGHT32(IWL_MVM_SCAN_MASK) ||
+ IWL_MVM_MAX_LMAC_SCANS > HWEIGHT32(IWL_MVM_SCAN_MASK));
+
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN))
+ mvm->max_scans = IWL_MVM_MAX_UMAC_SCANS;
+ else
+ mvm->max_scans = IWL_MVM_MAX_LMAC_SCANS;
+
if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels)
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&mvm->nvm_data->bands[IEEE80211_BAND_2GHZ];
@@ -517,10 +551,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
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) &&
- (mvm->fw->ucode_capa.api[0] &
- IWL_UCODE_TLV_API_LQ_SS_PARAMS))
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
+ fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_LQ_SS_PARAMS))
hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |=
IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
}
@@ -532,14 +566,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
else
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
- if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) {
- hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
- hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
- hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
- /* we create the 802.11 header and zero length SSID IE. */
- hw->wiphy->max_sched_scan_ie_len =
- SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
- }
+ hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+ hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
+ hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
+ /* we create the 802.11 header and zero length SSID IE. */
+ hw->wiphy->max_sched_scan_ie_len =
+ SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
NL80211_FEATURE_LOW_PRIORITY_SCAN |
@@ -548,30 +580,24 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
NL80211_FEATURE_STATIC_SMPS |
NL80211_FEATURE_SUPPORTS_WMM_ADMISSION;
- if (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT)
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT))
hw->wiphy->features |= NL80211_FEATURE_TX_POWER_INSERTION;
- if (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT)
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT))
hw->wiphy->features |= NL80211_FEATURE_QUIET;
- if (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT)
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT))
hw->wiphy->features |=
NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES;
- if (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT)
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT))
hw->wiphy->features |= NL80211_FEATURE_WFA_TPC_IE_IN_PROBES;
mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
- /* currently FW API supports only one optional cipher scheme */
- if (mvm->fw->cs[0].cipher) {
- mvm->hw->n_cipher_schemes = 1;
- mvm->hw->cipher_schemes = &mvm->fw->cs[0];
- }
-
#ifdef CONFIG_PM_SLEEP
if (iwl_mvm_is_d0i3_supported(mvm) &&
device_can_wakeup(mvm->trans->dev)) {
@@ -611,13 +637,14 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
if (ret)
return ret;
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_TDLS_SUPPORT) {
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_TDLS_SUPPORT)) {
IWL_DEBUG_TDLS(mvm, "TDLS supported\n");
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
}
- if (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH) {
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH)) {
IWL_DEBUG_TDLS(mvm, "TDLS channel switch supported\n");
hw->wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH;
}
@@ -730,6 +757,60 @@ static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg)
return true;
}
+#define CHECK_BA_TRIGGER(_mvm, _trig, _tid_bm, _tid, _fmt...) \
+ do { \
+ if (!(le16_to_cpu(_tid_bm) & BIT(_tid))) \
+ break; \
+ iwl_mvm_fw_dbg_collect_trig(_mvm, _trig, _fmt); \
+ } while (0)
+
+static void
+iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid, u16 rx_ba_ssn,
+ enum ieee80211_ampdu_mlme_action action)
+{
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct iwl_fw_dbg_trigger_ba *ba_trig;
+
+ if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
+ return;
+
+ trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
+ ba_trig = (void *)trig->data;
+
+ if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig))
+ return;
+
+ switch (action) {
+ case IEEE80211_AMPDU_TX_OPERATIONAL: {
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
+
+ CHECK_BA_TRIGGER(mvm, trig, ba_trig->tx_ba_start, tid,
+ "TX AGG START: MAC %pM tid %d ssn %d\n",
+ sta->addr, tid, tid_data->ssn);
+ break;
+ }
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ CHECK_BA_TRIGGER(mvm, trig, ba_trig->tx_ba_stop, tid,
+ "TX AGG STOP: MAC %pM tid %d\n",
+ sta->addr, tid);
+ break;
+ case IEEE80211_AMPDU_RX_START:
+ CHECK_BA_TRIGGER(mvm, trig, ba_trig->rx_ba_start, tid,
+ "RX AGG START: MAC %pM tid %d ssn %d\n",
+ sta->addr, tid, rx_ba_ssn);
+ break;
+ case IEEE80211_AMPDU_RX_STOP:
+ CHECK_BA_TRIGGER(mvm, trig, ba_trig->rx_ba_stop, tid,
+ "RX AGG STOP: MAC %pM tid %d\n",
+ sta->addr, tid);
+ break;
+ default:
+ break;
+ }
+}
+
static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
@@ -806,6 +887,16 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
ret = -EINVAL;
break;
}
+
+ if (!ret) {
+ u16 rx_ba_ssn = 0;
+
+ if (action == IEEE80211_AMPDU_RX_START)
+ rx_ba_ssn = *ssn;
+
+ iwl_mvm_ampdu_check_trigger(mvm, vif, sta, tid,
+ rx_ba_ssn, action);
+ }
mutex_unlock(&mvm->mutex);
/*
@@ -1227,22 +1318,23 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
iwl_trans_stop_device(mvm->trans);
- mvm->scan_status = IWL_MVM_SCAN_NONE;
+ mvm->scan_status = 0;
mvm->ps_disabled = false;
mvm->calibrating = false;
/* just in case one was running */
ieee80211_remain_on_channel_expired(mvm->hw);
- ieee80211_iterate_active_interfaces_atomic(
- mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
- iwl_mvm_cleanup_iterator, mvm);
+ /*
+ * cleanup all interfaces, even inactive ones, as some might have
+ * gone down during the HW restart
+ */
+ ieee80211_iterate_interfaces(mvm->hw, 0, iwl_mvm_cleanup_iterator, mvm);
mvm->p2p_device_vif = NULL;
mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
iwl_mvm_reset_phy_ctxts(mvm);
- memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_drained));
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
@@ -1404,7 +1496,7 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
* The work item could be running or queued if the
* ROC time event stops just as we get here.
*/
- cancel_work_sync(&mvm->roc_done_wk);
+ flush_work(&mvm->roc_done_wk);
iwl_trans_stop_device(mvm->trans);
@@ -1417,20 +1509,24 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
/*
* Clear IN_HW_RESTART flag when stopping the hw (as restart_complete()
* won't be called in this case).
+ * But make sure to cleanup interfaces that have gone down before/during
+ * HW restart was requested.
*/
- clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+ if (test_and_clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+ ieee80211_iterate_interfaces(mvm->hw, 0,
+ iwl_mvm_cleanup_iterator, mvm);
/* We shouldn't have any UIDs still set. Loop over all the UIDs to
* make sure there's nothing left there and warn if any is found.
*/
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
int i;
- for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) {
- if (WARN_ONCE(mvm->scan_uid[i],
- "UMAC scan UID %d was not cleaned\n",
- mvm->scan_uid[i]))
- mvm->scan_uid[i] = 0;
+ for (i = 0; i < mvm->max_scans; i++) {
+ if (WARN_ONCE(mvm->scan_uid_status[i],
+ "UMAC scan UID %d status was not cleaned\n",
+ i))
+ mvm->scan_uid_status[i] = 0;
}
}
@@ -1495,7 +1591,7 @@ static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
.pwr_restriction = cpu_to_le16(8 * tx_power),
};
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_TX_POWER_DEV))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TX_POWER_DEV))
return iwl_mvm_set_tx_power_old(mvm, vif, tx_power);
if (tx_power == IWL_DEFAULT_MAX_TX_POWER)
@@ -2354,7 +2450,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex);
if (changes & BSS_CHANGED_IDLE && !bss_conf->idle)
- iwl_mvm_scan_offload_stop(mvm, true);
+ iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true);
switch (vif->type) {
case NL80211_IFTYPE_STATION:
@@ -2373,89 +2469,21 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED);
}
-static int iwl_mvm_cancel_scan_wait_notif(struct iwl_mvm *mvm,
- enum iwl_scan_status scan_type)
-{
- int ret;
- bool wait_for_handlers = false;
-
- mutex_lock(&mvm->mutex);
-
- if (mvm->scan_status != scan_type) {
- ret = 0;
- /* make sure there are no pending notifications */
- wait_for_handlers = true;
- goto out;
- }
-
- switch (scan_type) {
- case IWL_MVM_SCAN_SCHED:
- ret = iwl_mvm_scan_offload_stop(mvm, true);
- break;
- case IWL_MVM_SCAN_OS:
- ret = iwl_mvm_cancel_scan(mvm);
- break;
- case IWL_MVM_SCAN_NONE:
- default:
- WARN_ON_ONCE(1);
- ret = -EINVAL;
- break;
- }
- if (ret)
- goto out;
-
- wait_for_handlers = true;
-out:
- mutex_unlock(&mvm->mutex);
-
- /* make sure we consume the completion notification */
- if (wait_for_handlers)
- iwl_mvm_wait_for_async_handlers(mvm);
-
- return ret;
-}
static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- struct cfg80211_scan_request *req = &hw_req->req;
int ret;
- if (req->n_channels == 0 ||
- req->n_channels > mvm->fw->ucode_capa.n_scan_channels)
+ if (hw_req->req.n_channels == 0 ||
+ hw_req->req.n_channels > mvm->fw->ucode_capa.n_scan_channels)
return -EINVAL;
- if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
- ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED);
- if (ret)
- return ret;
- }
-
mutex_lock(&mvm->mutex);
-
- if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
- IWL_ERR(mvm, "scan while LAR regdomain is not set\n");
- ret = -EBUSY;
- goto out;
- }
-
- if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
- ret = -EBUSY;
- goto out;
- }
-
- iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
-
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
- ret = iwl_mvm_scan_umac(mvm, vif, hw_req);
- else
- ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req);
-
- if (ret)
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
-out:
+ ret = iwl_mvm_reg_scan_start(mvm, vif, &hw_req->req, &hw_req->ies);
mutex_unlock(&mvm->mutex);
+
return ret;
}
@@ -2473,12 +2501,8 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
* cancel scan scan before ieee80211_scan_work() could run.
* To handle that, simply return if the scan is not running.
*/
- /* FIXME: for now, we ignore this race for UMAC scans, since
- * they don't set the scan_status.
- */
- if ((mvm->scan_status == IWL_MVM_SCAN_OS) ||
- (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN))
- iwl_mvm_cancel_scan(mvm);
+ if (mvm->scan_status & IWL_MVM_SCAN_REGULAR)
+ iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);
mutex_unlock(&mvm->mutex);
}
@@ -2794,35 +2818,17 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
struct ieee80211_scan_ies *ies)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- int ret;
- if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
- ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS);
- if (ret)
- return ret;
- }
+ int ret;
mutex_lock(&mvm->mutex);
- if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
- IWL_ERR(mvm, "sched-scan while LAR regdomain is not set\n");
- ret = -EBUSY;
- goto out;
- }
-
if (!vif->bss_conf.idle) {
ret = -EBUSY;
goto out;
}
- if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
- ret = -EBUSY;
- goto out;
- }
-
- ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies);
- if (ret)
- mvm->scan_status = IWL_MVM_SCAN_NONE;
+ ret = iwl_mvm_sched_scan_start(mvm, vif, req, ies, IWL_MVM_SCAN_SCHED);
out:
mutex_unlock(&mvm->mutex);
@@ -2845,16 +2851,12 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
* could run. To handle this, simply return if the scan is
* not running.
*/
- /* FIXME: for now, we ignore this race for UMAC scans, since
- * they don't set the scan_status.
- */
- if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
- !(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
+ if (!(mvm->scan_status & IWL_MVM_SCAN_SCHED)) {
mutex_unlock(&mvm->mutex);
return 0;
}
- ret = iwl_mvm_scan_offload_stop(mvm, false);
+ ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, false);
mutex_unlock(&mvm->mutex);
iwl_mvm_wait_for_async_handlers(mvm);
@@ -2883,7 +2885,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
- WARN_ON_ONCE(!(hw->flags & IEEE80211_HW_MFP_CAPABLE));
+ WARN_ON_ONCE(!ieee80211_hw_check(hw, MFP_CAPABLE));
break;
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
@@ -2922,8 +2924,21 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
break;
}
+ /* During FW restart, in order to restore the state as it was,
+ * don't try to reprogram keys we previously failed for.
+ */
+ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
+ key->hw_key_idx == STA_KEY_IDX_INVALID) {
+ IWL_DEBUG_MAC80211(mvm,
+ "skip invalid idx key programming during restart\n");
+ ret = 0;
+ break;
+ }
+
IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n");
- ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, false);
+ ret = iwl_mvm_set_sta_key(mvm, vif, sta, key,
+ test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
+ &mvm->status));
if (ret) {
IWL_WARN(mvm, "set key failed\n");
/*
@@ -3001,7 +3016,7 @@ static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait,
return true;
}
-#define AUX_ROC_MAX_DELAY_ON_CHANNEL 5000
+#define AUX_ROC_MAX_DELAY_ON_CHANNEL 200
static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,
struct ieee80211_channel *channel,
struct ieee80211_vif *vif,
@@ -3106,8 +3121,8 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
switch (vif->type) {
case NL80211_IFTYPE_STATION:
- if (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT) {
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT)) {
/* Use aux roc framework (HS20) */
ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
vif, duration);
@@ -3899,7 +3914,7 @@ static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
if (idx != 0)
return -ENOENT;
- if (!(mvm->fw->ucode_capa.capa[0] &
+ if (fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
return -ENOENT;
@@ -3946,8 +3961,8 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- if (!(mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
return;
/* if beacon filtering isn't on mac80211 does it anyway */
@@ -3977,9 +3992,9 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
mutex_unlock(&mvm->mutex);
}
-static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- const struct ieee80211_event *event)
+static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ const struct ieee80211_event *event)
{
#define CHECK_MLME_TRIGGER(_mvm, _trig, _buf, _cnt, _fmt...) \
do { \
@@ -3988,16 +4003,12 @@ static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
iwl_mvm_fw_dbg_collect_trig(_mvm, _trig, _fmt);\
} while (0)
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_fw_dbg_trigger_tlv *trig;
struct iwl_fw_dbg_trigger_mlme *trig_mlme;
if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_MLME))
return;
- if (event->u.mlme.status == MLME_SUCCESS)
- return;
-
trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_MLME);
trig_mlme = (void *)trig->data;
if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig))
@@ -4035,6 +4046,75 @@ static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
#undef CHECK_MLME_TRIGGER
}
+static void iwl_mvm_event_bar_rx_callback(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ const struct ieee80211_event *event)
+{
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct iwl_fw_dbg_trigger_ba *ba_trig;
+
+ if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
+ return;
+
+ trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
+ ba_trig = (void *)trig->data;
+ if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig))
+ return;
+
+ if (!(le16_to_cpu(ba_trig->rx_bar) & BIT(event->u.ba.tid)))
+ return;
+
+ iwl_mvm_fw_dbg_collect_trig(mvm, trig,
+ "BAR received from %pM, tid %d, ssn %d",
+ event->u.ba.sta->addr, event->u.ba.tid,
+ event->u.ba.ssn);
+}
+
+static void
+iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ const struct ieee80211_event *event)
+{
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct iwl_fw_dbg_trigger_ba *ba_trig;
+
+ if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
+ return;
+
+ trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
+ ba_trig = (void *)trig->data;
+ if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig))
+ return;
+
+ if (!(le16_to_cpu(ba_trig->frame_timeout) & BIT(event->u.ba.tid)))
+ return;
+
+ iwl_mvm_fw_dbg_collect_trig(mvm, trig,
+ "Frame from %pM timed out, tid %d",
+ event->u.ba.sta->addr, event->u.ba.tid);
+}
+
+static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const struct ieee80211_event *event)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ switch (event->type) {
+ case MLME_EVENT:
+ iwl_mvm_event_mlme_callback(mvm, vif, event);
+ break;
+ case BAR_RX_EVENT:
+ iwl_mvm_event_bar_rx_callback(mvm, vif, event);
+ break;
+ case BA_FRAME_TIMEOUT:
+ iwl_mvm_event_frame_timeout_callback(mvm, vif, event);
+ break;
+ default:
+ break;
+ }
+}
+
const struct ieee80211_ops iwl_mvm_hw_ops = {
.tx = iwl_mvm_mac_tx,
.ampdu_action = iwl_mvm_mac_ampdu_action,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index cf70f681d1ac..2d4bad5fe825 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -76,6 +76,7 @@
#include "iwl-notif-wait.h"
#include "iwl-eeprom-parse.h"
#include "iwl-fw-file.h"
+#include "iwl-config.h"
#include "sta.h"
#include "fw-api.h"
#include "constants.h"
@@ -275,6 +276,7 @@ enum iwl_mvm_ref_type {
IWL_MVM_REF_UCODE_DOWN,
IWL_MVM_REF_SCAN,
IWL_MVM_REF_ROC,
+ IWL_MVM_REF_ROC_AUX,
IWL_MVM_REF_P2P_CLIENT,
IWL_MVM_REF_AP_IBSS,
IWL_MVM_REF_USER,
@@ -445,10 +447,26 @@ iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif)
extern const u8 tid_to_mac80211_ac[];
+#define IWL_MVM_SCAN_STOPPING_SHIFT 8
+
enum iwl_scan_status {
- IWL_MVM_SCAN_NONE,
- IWL_MVM_SCAN_OS,
- IWL_MVM_SCAN_SCHED,
+ IWL_MVM_SCAN_REGULAR = BIT(0),
+ IWL_MVM_SCAN_SCHED = BIT(1),
+ IWL_MVM_SCAN_NETDETECT = BIT(2),
+
+ IWL_MVM_SCAN_STOPPING_REGULAR = BIT(8),
+ IWL_MVM_SCAN_STOPPING_SCHED = BIT(9),
+ IWL_MVM_SCAN_STOPPING_NETDETECT = BIT(10),
+
+ IWL_MVM_SCAN_REGULAR_MASK = IWL_MVM_SCAN_REGULAR |
+ IWL_MVM_SCAN_STOPPING_REGULAR,
+ IWL_MVM_SCAN_SCHED_MASK = IWL_MVM_SCAN_SCHED |
+ IWL_MVM_SCAN_STOPPING_SCHED,
+ IWL_MVM_SCAN_NETDETECT_MASK = IWL_MVM_SCAN_NETDETECT |
+ IWL_MVM_SCAN_STOPPING_NETDETECT,
+
+ IWL_MVM_SCAN_STOPPING_MASK = 0xff << IWL_MVM_SCAN_STOPPING_SHIFT,
+ IWL_MVM_SCAN_MASK = 0xff,
};
/**
@@ -463,49 +481,6 @@ struct iwl_nvm_section {
const u8 *data;
};
-/*
- * Tx-backoff threshold
- * @temperature: The threshold in Celsius
- * @backoff: The tx-backoff in uSec
- */
-struct iwl_tt_tx_backoff {
- s32 temperature;
- u32 backoff;
-};
-
-#define TT_TX_BACKOFF_SIZE 6
-
-/**
- * struct iwl_tt_params - thermal throttling parameters
- * @ct_kill_entry: CT Kill entry threshold
- * @ct_kill_exit: CT Kill exit threshold
- * @ct_kill_duration: The time intervals (in uSec) in which the driver needs
- * to checks whether to exit CT Kill.
- * @dynamic_smps_entry: Dynamic SMPS entry threshold
- * @dynamic_smps_exit: Dynamic SMPS exit threshold
- * @tx_protection_entry: TX protection entry threshold
- * @tx_protection_exit: TX protection exit threshold
- * @tx_backoff: Array of thresholds for tx-backoff , in ascending order.
- * @support_ct_kill: Support CT Kill?
- * @support_dynamic_smps: Support dynamic SMPS?
- * @support_tx_protection: Support tx protection?
- * @support_tx_backoff: Support tx-backoff?
- */
-struct iwl_tt_params {
- s32 ct_kill_entry;
- s32 ct_kill_exit;
- u32 ct_kill_duration;
- s32 dynamic_smps_entry;
- s32 dynamic_smps_exit;
- s32 tx_protection_entry;
- s32 tx_protection_exit;
- struct iwl_tt_tx_backoff tx_backoff[TT_TX_BACKOFF_SIZE];
- bool support_ct_kill;
- bool support_dynamic_smps;
- bool support_tx_protection;
- bool support_tx_backoff;
-};
-
/**
* struct iwl_mvm_tt_mgnt - Thermal Throttling Management structure
* @ct_kill_exit: worker to exit thermal kill
@@ -520,7 +495,7 @@ struct iwl_mvm_tt_mgmt {
bool dynamic_smps;
u32 tx_backoff;
u32 min_backoff;
- const struct iwl_tt_params *params;
+ struct iwl_tt_params params;
bool throttle;
};
@@ -647,13 +622,15 @@ struct iwl_mvm {
u32 rts_threshold;
/* Scan status, cmd (pre-allocated) and auxiliary station */
- enum iwl_scan_status scan_status;
+ unsigned int scan_status;
void *scan_cmd;
struct iwl_mcast_filter_cmd *mcast_filter_cmd;
+ /* max number of simultaneous scans the FW supports */
+ unsigned int max_scans;
+
/* UMAC scan tracking */
- u32 scan_uid[IWL_MVM_MAX_SIMULTANEOUS_SCANS];
- u8 scan_seq_num, sched_scan_seq_num;
+ u32 scan_uid_status[IWL_MVM_MAX_UMAC_SCANS];
/* rx chain antennas set through debugfs for the scan command */
u8 scan_rx_ant;
@@ -843,6 +820,8 @@ struct iwl_mvm {
} tdls_cs;
struct iwl_mvm_shared_mem_cfg shared_mem_cfg;
+
+ u32 ciphers[6];
};
/* Extract MVM priv from op_mode and _hw */
@@ -912,14 +891,15 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)
return mvm->trans->cfg->d0i3 &&
mvm->trans->d0i3_mode != IWL_D0I3_MODE_OFF &&
!iwlwifi_mod_params.d0i3_disable &&
- (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
+ fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
}
static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm)
{
bool nvm_lar = mvm->nvm_data->lar_enabled;
- bool tlv_lar = mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_LAR_SUPPORT;
+ bool tlv_lar = fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
if (iwlwifi_mod_params.lar_disable)
return false;
@@ -936,24 +916,28 @@ static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm)
static inline bool iwl_mvm_is_wifi_mcc_supported(struct iwl_mvm *mvm)
{
- return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WIFI_MCC_UPDATE ||
- mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC;
+ return fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_WIFI_MCC_UPDATE) ||
+ fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC);
}
static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm)
{
- return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG;
+ return fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_SCD_CFG);
}
static inline bool iwl_mvm_bt_is_plcr_supported(struct iwl_mvm *mvm)
{
- return (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BT_COEX_PLCR) &&
+ return fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_BT_COEX_PLCR) &&
IWL_MVM_BT_COEX_CORUNNING;
}
static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm)
{
- return (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BT_COEX_RRC) &&
+ return fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_BT_COEX_RRC) &&
IWL_MVM_BT_COEX_RRC;
}
@@ -1083,8 +1067,6 @@ int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
-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_ant_coupling_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
@@ -1093,8 +1075,6 @@ int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
-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,
@@ -1146,48 +1126,38 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, bool force_upload,
struct ieee80211_vif *disabled_vif);
/* Scanning */
+int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct cfg80211_scan_request *req,
+ struct ieee80211_scan_ies *ies);
int iwl_mvm_scan_size(struct iwl_mvm *mvm);
-int iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
-int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan);
+int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify);
+int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm);
void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm);
/* Scheduled 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_profiles(struct iwl_mvm *mvm,
- struct cfg80211_sched_scan_request *req);
-int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies);
-int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify);
-int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd);
-
-/* Unified scan */
-int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_scan_request *req);
-int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies);
+int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_scan_ies *ies,
+ int type);
+int iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
/* UMAC scan */
int iwl_mvm_config_scan(struct iwl_mvm *mvm);
-int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct ieee80211_scan_request *req);
-int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies);
int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
/* MVM debugfs */
#ifdef CONFIG_IWLWIFI_DEBUGFS
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index 87b2a30a2308..2a6be350704a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -316,8 +316,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
phy_sku = (const __le16 *)sections[NVM_SECTION_TYPE_PHY_SKU].data;
lar_enabled = !iwlwifi_mod_params.lar_disable &&
- (mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
+ fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib,
regulatory, mac_override, phy_sku,
@@ -583,9 +583,9 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
kfree(nvm_buffer);
}
- /* load external NVM if configured */
+ /* Only if PNVM selected in the mod param - load external NVM */
if (mvm->nvm_file_name) {
- /* read External NVM file - take the default */
+ /* read External NVM file from the mod param */
ret = iwl_mvm_read_external_nvm(mvm);
if (ret) {
/* choose the nvm_file name according to the
@@ -792,8 +792,8 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
char mcc[3];
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
- tlv_lar = mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_LAR_SUPPORT;
+ tlv_lar = fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
nvm_lar = mvm->nvm_data->lar_enabled;
if (tlv_lar != nvm_lar)
IWL_INFO(mvm,
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 1c66297d82c0..e4fa50075ffd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -194,7 +194,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
* (PCIe power is lost before PERST# is asserted), causing ME FW
* to lose ownership and not being able to obtain it back.
*/
- if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
+ if (!mvm->trans->cfg->apmg_not_supported)
iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG,
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
@@ -238,15 +238,16 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false),
RX_HANDLER(SCAN_ITERATION_COMPLETE,
- iwl_mvm_rx_scan_offload_iter_complete_notif, false),
+ iwl_mvm_rx_lmac_scan_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,
+ iwl_mvm_rx_lmac_scan_complete_notif, true),
+ RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_match_found,
false),
RX_HANDLER(SCAN_COMPLETE_UMAC, iwl_mvm_rx_umac_scan_complete_notif,
true),
+ RX_HANDLER(SCAN_ITERATION_COMPLETE_UMAC,
+ iwl_mvm_rx_umac_scan_iter_complete_notif, false),
- RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
RX_HANDLER(MISSED_BEACONS_NOTIFICATION, iwl_mvm_rx_missed_beacons_notif,
@@ -280,17 +281,11 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(BINDING_CONTEXT_CMD),
CMD(TIME_QUOTA_CMD),
CMD(NON_QOS_TX_COUNTER_CMD),
- CMD(RADIO_VERSION_NOTIFICATION),
- CMD(SCAN_REQUEST_CMD),
- CMD(SCAN_ABORT_CMD),
- CMD(SCAN_START_NOTIFICATION),
- CMD(SCAN_RESULTS_NOTIFICATION),
- CMD(SCAN_COMPLETE_NOTIFICATION),
+ CMD(DC2DC_CONFIG_CMD),
CMD(NVM_ACCESS_CMD),
CMD(PHY_CONFIGURATION_CMD),
CMD(CALIB_RES_NOTIF_PHY_DB),
CMD(SET_CALIB_DEFAULT_CMD),
- CMD(CALIBRATION_COMPLETE_NOTIFICATION),
CMD(ADD_STA_KEY),
CMD(ADD_STA),
CMD(REMOVE_STA),
@@ -359,6 +354,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(TDLS_CHANNEL_SWITCH_NOTIFICATION),
CMD(TDLS_CONFIG_CMD),
CMD(MCC_UPDATE_CMD),
+ CMD(SCAN_ITERATION_COMPLETE_UMAC),
};
#undef CMD
@@ -520,15 +516,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
min_backoff = calc_min_backoff(trans, cfg);
iwl_mvm_tt_initialize(mvm, min_backoff);
- /* set the nvm_file_name according to priority */
- if (iwlwifi_mod_params.nvm_file) {
+
+ if (iwlwifi_mod_params.nvm_file)
mvm->nvm_file_name = iwlwifi_mod_params.nvm_file;
- } else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
- if (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_B_STEP)
- mvm->nvm_file_name = mvm->cfg->default_nvm_file_B_step;
- else
- mvm->nvm_file_name = mvm->cfg->default_nvm_file_C_step;
- }
+ else
+ IWL_DEBUG_EEPROM(mvm->trans->dev,
+ "working without external nvm file\n");
if (WARN(cfg->no_power_up_nic_in_init && !mvm->nvm_file_name,
"not allowing power-up and not having nvm_file\n"))
@@ -1263,11 +1256,13 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
ieee80211_iterate_active_interfaces(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_d0i3_disconnect_iter, mvm);
-
- iwl_free_resp(&get_status_cmd);
out:
iwl_mvm_d0i3_enable_tx(mvm, qos_seq);
+ /* qos_seq might point inside resp_pkt, so free it only now */
+ if (get_status_cmd.resp_pkt)
+ iwl_free_resp(&get_status_cmd);
+
/* the FW might have updated the regdomain */
iwl_mvm_update_changed_regdom(mvm);
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index f9928f2c125f..daff1d0a8e4a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -1,7 +1,7 @@
/******************************************************************************
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -138,7 +138,7 @@ struct rs_tx_column;
typedef bool (*allow_column_func_t) (struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl,
+ struct rs_rate *rate,
const struct rs_tx_column *next_col);
struct rs_tx_column {
@@ -150,14 +150,14 @@ struct rs_tx_column {
};
static bool rs_ant_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl,
+ struct rs_rate *rate,
const struct rs_tx_column *next_col)
{
return iwl_mvm_bt_coex_is_ant_avail(mvm, next_col->ant);
}
static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl,
+ struct rs_rate *rate,
const struct rs_tx_column *next_col)
{
struct iwl_mvm_sta *mvmsta;
@@ -180,11 +180,14 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
if (iwl_mvm_vif_low_latency(mvmvif) && mvmsta->vif->p2p)
return false;
+ if (mvm->nvm_data->sku_cap_mimo_disabled)
+ return false;
+
return true;
}
static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl,
+ struct rs_rate *rate,
const struct rs_tx_column *next_col)
{
if (!sta->ht_cap.ht_supported)
@@ -194,10 +197,9 @@ static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}
static bool rs_sgi_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl,
+ struct rs_rate *rate,
const struct rs_tx_column *next_col)
{
- struct rs_rate *rate = &tbl->rate;
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
@@ -1125,8 +1127,8 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
u32 tx_resp_hwrate = (uintptr_t)info->status.status_driver_data[1];
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta;
- bool allow_ant_mismatch = mvm->fw->ucode_capa.api[0] &
- IWL_UCODE_TLV_API_LQ_SS_PARAMS;
+ bool allow_ant_mismatch = fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_LQ_SS_PARAMS);
/* Treat uninitialized rate scaling data same as non-existing. */
if (!lq_sta) {
@@ -1656,7 +1658,8 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
for (j = 0; j < MAX_COLUMN_CHECKS; j++) {
allow_func = next_col->checks[j];
- if (allow_func && !allow_func(mvm, sta, tbl, next_col))
+ if (allow_func && !allow_func(mvm, sta, &tbl->rate,
+ next_col))
break;
}
@@ -2133,7 +2136,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
}
/* current tx rate */
- index = lq_sta->last_txrate_idx;
+ index = rate->index;
/* rates available for this association, and for modulation mode */
rate_mask = rs_get_supported_rates(lq_sta, rate);
@@ -2181,14 +2184,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
* or search for a new one? */
rs_stay_in_table(lq_sta, false);
- goto out;
- }
- /* Else we have enough samples; calculate estimate of
- * actual average throughput */
- if (window->average_tpt != ((window->success_ratio *
- tbl->expected_tpt[index] + 64) / 128)) {
- window->average_tpt = ((window->success_ratio *
- tbl->expected_tpt[index] + 64) / 128);
+ return;
}
/* If we are searching for better modulation mode, check success. */
@@ -2400,9 +2396,6 @@ lq_update:
rs_set_stay_in_table(mvm, 0, lq_sta);
}
}
-
-out:
- lq_sta->last_txrate_idx = index;
}
struct rs_init_rate_info {
@@ -2545,7 +2538,6 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
rate = &tbl->rate;
rs_get_initial_rate(mvm, lq_sta, band, rate);
- lq_sta->last_txrate_idx = rate->index;
WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B);
if (rate->ant == ANT_A)
@@ -2722,7 +2714,7 @@ static void rs_vht_init(struct iwl_mvm *mvm,
(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) &&
+ if (fw_has_capa(&mvm->fw->ucode_capa, 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;
@@ -3006,7 +2998,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm);
/* TODO: remove old API when min FW API hits 14 */
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) &&
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_LQ_SS_PARAMS) &&
rs_stbc_allow(mvm, sta, lq_sta))
rate.stbc = true;
@@ -3220,12 +3212,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)
+ if (fw_has_api(&mvm->fw->ucode_capa, 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;
-
mvmsta = iwl_mvm_sta_from_mac80211(sta);
mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index e4aa9346a231..2a3da314305a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -322,8 +322,6 @@ struct iwl_lq_sta {
struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
u8 tx_agg_tid_en;
- /* used to be in sta_info */
- int last_txrate_idx;
/* last tx rate_n_flags */
u32 last_rate_n_flags;
/* packets destined for this STA are aggregated */
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index d6314ddf57b5..8f1d93b7a13a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -570,7 +570,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
};
u32 temperature;
- if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_STATS_V10) {
+ if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STATS_V10)) {
struct iwl_notif_statistics_v10 *stats = (void *)&pkt->data;
if (iwl_rx_packet_payload_len(pkt) != v10_len)
@@ -610,7 +610,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
/* 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))
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_ASYNC_DTM))
iwl_mvm_tt_temp_changed(mvm, temperature);
ieee80211_iterate_active_interfaces(mvm->hw,
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 1075a213bd6a..5de144968723 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -67,11 +67,8 @@
#include <net/mac80211.h>
#include "mvm.h"
-#include "iwl-eeprom-parse.h"
#include "fw-api-scan.h"
-#define IWL_PLCP_QUIET_THRESH 1
-#define IWL_ACTIVE_QUIET_TIME 10
#define IWL_DENSE_EBS_SCAN_RATIO 5
#define IWL_SPARSE_EBS_SCAN_RATIO 1
@@ -79,23 +76,31 @@ struct iwl_mvm_scan_params {
u32 max_out_time;
u32 suspend_time;
bool passive_fragmented;
+ u32 n_channels;
+ u16 delay;
+ int n_ssids;
+ struct cfg80211_ssid *ssids;
+ struct ieee80211_channel **channels;
+ u16 interval; /* interval between scans (in secs) */
+ u32 flags;
+ u8 *mac_addr;
+ u8 *mac_addr_mask;
+ bool no_cck;
+ bool pass_all;
+ int n_match_sets;
+ struct iwl_scan_probe_req preq;
+ struct cfg80211_match_set *match_sets;
struct _dwell {
u16 passive;
u16 active;
u16 fragmented;
} dwell[IEEE80211_NUM_BANDS];
+ struct {
+ u8 iterations;
+ u8 full_scan_mul; /* not used for UMAC */
+ } schedule[2];
};
-enum iwl_umac_scan_uid_type {
- IWL_UMAC_SCAN_UID_REG_SCAN = BIT(0),
- IWL_UMAC_SCAN_UID_SCHED_SCAN = BIT(1),
- IWL_UMAC_SCAN_UID_ALL = IWL_UMAC_SCAN_UID_REG_SCAN |
- IWL_UMAC_SCAN_UID_SCHED_SCAN,
-};
-
-static int iwl_umac_scan_stop(struct iwl_mvm *mvm,
- enum iwl_umac_scan_uid_type type, bool notify);
-
static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm)
{
if (mvm->scan_rx_ant != ANT_NONE)
@@ -143,28 +148,6 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
}
/*
- * We insert the SSIDs in an inverted order, because the FW will
- * invert it back. The most prioritized SSID, which is first in the
- * request list, is not copied here, but inserted directly to the probe
- * request.
- */
-static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid,
- struct cfg80211_ssid *ssids,
- int n_ssids, int first)
-{
- int fw_idx, req_idx;
-
- for (req_idx = n_ssids - 1, fw_idx = 0; req_idx >= first;
- req_idx--, fw_idx++) {
- cmd_ssid[fw_idx].id = WLAN_EID_SSID;
- cmd_ssid[fw_idx].len = ssids[req_idx].ssid_len;
- memcpy(cmd_ssid[fw_idx].ssid,
- ssids[req_idx].ssid,
- ssids[req_idx].ssid_len);
- }
-}
-
-/*
* If req->n_ssids > 0, it means we should do an active scan.
* In case of active scan w/o directed scan, we receive a zero-length SSID
* just to notify that this scan is active and not passive.
@@ -177,7 +160,7 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid,
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)
+ if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BASIC_DWELL))
return 10;
if (band == IEEE80211_BAND_2GHZ)
return 20 + 3 * (n_ssids + 1);
@@ -187,7 +170,7 @@ static u16 iwl_mvm_get_active_dwell(struct iwl_mvm *mvm,
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)
+ if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BASIC_DWELL))
return 110;
return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10;
}
@@ -203,10 +186,9 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
*global_cnt += 1;
}
-static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- int n_ssids, u32 flags,
- struct iwl_mvm_scan_params *params)
+static void iwl_mvm_scan_calc_dwell(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct iwl_mvm_scan_params *params)
{
int global_cnt = 0;
enum ieee80211_band band;
@@ -216,7 +198,6 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_scan_condition_iterator,
&global_cnt);
-
if (!global_cnt)
goto not_bound;
@@ -224,8 +205,9 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
params->max_out_time = 120;
if (iwl_mvm_low_latency(mvm)) {
- if (mvm->fw->ucode_capa.api[0] &
- IWL_UCODE_TLV_API_FRAGMENTED_SCAN) {
+ if (fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) {
+
params->suspend_time = 105;
/*
* If there is more than one active interface make
@@ -239,8 +221,9 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
}
}
- if (frag_passive_dwell && (mvm->fw->ucode_capa.api[0] &
- IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) {
+ if (frag_passive_dwell &&
+ fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) {
/*
* P2P device scan should not be fragmented to avoid negative
* impact on P2P device discovery. Configure max_out_time to be
@@ -257,7 +240,8 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
}
}
- if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
+ if ((params->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
+ (params->max_out_time > 200))
params->max_out_time = 200;
not_bound:
@@ -268,20 +252,34 @@ not_bound:
params->dwell[band].passive = iwl_mvm_get_passive_dwell(mvm,
band);
- params->dwell[band].active = iwl_mvm_get_active_dwell(mvm, band,
- n_ssids);
+ params->dwell[band].active =
+ iwl_mvm_get_active_dwell(mvm, band, params->n_ssids);
}
+
+ IWL_DEBUG_SCAN(mvm,
+ "scan parameters: max_out_time %d, suspend_time %d, passive_fragmented %d\n",
+ params->max_out_time, params->suspend_time,
+ params->passive_fragmented);
+ IWL_DEBUG_SCAN(mvm,
+ "dwell[IEEE80211_BAND_2GHZ]: passive %d, active %d, fragmented %d\n",
+ params->dwell[IEEE80211_BAND_2GHZ].passive,
+ params->dwell[IEEE80211_BAND_2GHZ].active,
+ params->dwell[IEEE80211_BAND_2GHZ].fragmented);
+ IWL_DEBUG_SCAN(mvm,
+ "dwell[IEEE80211_BAND_5GHZ]: passive %d, active %d, fragmented %d\n",
+ params->dwell[IEEE80211_BAND_5GHZ].passive,
+ params->dwell[IEEE80211_BAND_5GHZ].active,
+ params->dwell[IEEE80211_BAND_5GHZ].fragmented);
}
static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm)
{
/* require rrm scan whenever the fw supports it */
- return mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT;
+ return fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT);
}
-static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm,
- bool is_sched_scan)
+static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm)
{
int max_probe_len;
@@ -297,9 +295,9 @@ static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm,
return max_probe_len;
}
-int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan)
+int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm)
{
- int max_ie_len = iwl_mvm_max_scan_ie_fw_cmd_room(mvm, is_sched_scan);
+ int max_ie_len = iwl_mvm_max_scan_ie_fw_cmd_room(mvm);
/* TODO: [BUG] This function should return the maximum allowed size of
* scan IEs, however the LMAC scan api contains both 2GHZ and 5GHZ IEs
@@ -314,22 +312,41 @@ int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan)
return max_ie_len;
}
-int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd)
+static u8 *iwl_mvm_dump_channel_list(struct iwl_scan_results_notif *res,
+ int num_res, u8 *buf, size_t buf_size)
+{
+ int i;
+ u8 *pos = buf, *end = buf + buf_size;
+
+ for (i = 0; pos < end && i < num_res; i++)
+ pos += snprintf(pos, end - pos, " %u", res[i].channel);
+
+ /* terminate the string in case the buffer was too short */
+ *(buf + buf_size - 1) = '\0';
+
+ return buf;
+}
+
+int iwl_mvm_rx_lmac_scan_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_lmac_scan_complete_notif *notif = (void *)pkt->data;
+ u8 buf[256];
IWL_DEBUG_SCAN(mvm,
- "Scan offload iteration complete: status=0x%x scanned channels=%d\n",
- notif->status, notif->scanned_channels);
+ "Scan offload iteration complete: status=0x%x scanned channels=%d channels list: %s\n",
+ notif->status, notif->scanned_channels,
+ iwl_mvm_dump_channel_list(notif->results,
+ notif->scanned_channels, buf,
+ sizeof(buf)));
return 0;
}
-int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd)
+int iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n");
ieee80211_sched_scan_results(mvm->hw);
@@ -337,41 +354,78 @@ int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
return 0;
}
-int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb,
- struct iwl_device_cmd *cmd)
+static const char *iwl_mvm_ebs_status_str(enum iwl_scan_ebs_status status)
{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_periodic_scan_complete *scan_notif;
+ switch (status) {
+ case IWL_SCAN_EBS_SUCCESS:
+ return "successful";
+ case IWL_SCAN_EBS_INACTIVE:
+ return "inactive";
+ case IWL_SCAN_EBS_FAILED:
+ case IWL_SCAN_EBS_CHAN_NOT_FOUND:
+ default:
+ return "failed";
+ }
+}
- scan_notif = (void *)pkt->data;
+int iwl_mvm_rx_lmac_scan_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_periodic_scan_complete *scan_notif = (void *)pkt->data;
+ bool aborted = (scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED);
/* scan status must be locked for proper checking */
lockdep_assert_held(&mvm->mutex);
- IWL_DEBUG_SCAN(mvm,
- "%s completed, status %s, EBS status %s\n",
- mvm->scan_status == IWL_MVM_SCAN_SCHED ?
- "Scheduled scan" : "Scan",
- scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
- "completed" : "aborted",
- scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS ?
- "success" : "failed");
+ /* We first check if we were stopping a scan, in which case we
+ * just clear the stopping flag. Then we check if it was a
+ * firmware initiated stop, in which case we need to inform
+ * mac80211.
+ * Note that we can have a stopping and a running scan
+ * simultaneously, but we can't have two different types of
+ * scans stopping or running at the same time (since LMAC
+ * doesn't support it).
+ */
+
+ if (mvm->scan_status & IWL_MVM_SCAN_STOPPING_SCHED) {
+ WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_STOPPING_REGULAR);
+
+ IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s\n",
+ aborted ? "aborted" : "completed",
+ iwl_mvm_ebs_status_str(scan_notif->ebs_status));
+ mvm->scan_status &= ~IWL_MVM_SCAN_STOPPING_SCHED;
+ } else if (mvm->scan_status & IWL_MVM_SCAN_STOPPING_REGULAR) {
+ IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s\n",
+ aborted ? "aborted" : "completed",
+ iwl_mvm_ebs_status_str(scan_notif->ebs_status));
- /* only call mac80211 completion if the stop was initiated by FW */
- if (mvm->scan_status == IWL_MVM_SCAN_SCHED) {
- mvm->scan_status = IWL_MVM_SCAN_NONE;
+ mvm->scan_status &= ~IWL_MVM_SCAN_STOPPING_REGULAR;
+ } else if (mvm->scan_status & IWL_MVM_SCAN_SCHED) {
+ WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_REGULAR);
+
+ IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s (FW)\n",
+ aborted ? "aborted" : "completed",
+ iwl_mvm_ebs_status_str(scan_notif->ebs_status));
+
+ mvm->scan_status &= ~IWL_MVM_SCAN_SCHED;
ieee80211_sched_scan_stopped(mvm->hw);
- } else if (mvm->scan_status == IWL_MVM_SCAN_OS) {
- mvm->scan_status = IWL_MVM_SCAN_NONE;
+ } else if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) {
+ IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s (FW)\n",
+ aborted ? "aborted" : "completed",
+ iwl_mvm_ebs_status_str(scan_notif->ebs_status));
+
+ mvm->scan_status &= ~IWL_MVM_SCAN_REGULAR;
ieee80211_scan_completed(mvm->hw,
scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED);
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
}
- if (scan_notif->ebs_status)
- mvm->last_ebs_successful = false;
+ mvm->last_ebs_successful =
+ scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS ||
+ scan_notif->ebs_status == IWL_SCAN_EBS_INACTIVE;
return 0;
}
@@ -390,9 +444,12 @@ static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)
return -1;
}
-static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
- struct iwl_ssid_ie *direct_scan,
- u32 *ssid_bitmap, bool basic_ssid)
+/* We insert the SSIDs in an inverted order, because the FW will
+ * invert it back.
+ */
+static void iwl_scan_build_ssids(struct iwl_mvm_scan_params *params,
+ struct iwl_ssid_ie *ssids,
+ u32 *ssid_bitmap)
{
int i, j;
int index;
@@ -402,39 +459,41 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
* iwl_config_sched_scan_profiles() uses the order of these ssids to
* config match list.
*/
- for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) {
+ for (i = 0, j = params->n_match_sets - 1;
+ j >= 0 && i < PROBE_OPTION_MAX;
+ i++, j--) {
/* skip empty SSID matchsets */
- if (!req->match_sets[i].ssid.ssid_len)
+ if (!params->match_sets[j].ssid.ssid_len)
continue;
- direct_scan[i].id = WLAN_EID_SSID;
- direct_scan[i].len = req->match_sets[i].ssid.ssid_len;
- memcpy(direct_scan[i].ssid, req->match_sets[i].ssid.ssid,
- direct_scan[i].len);
+ ssids[i].id = WLAN_EID_SSID;
+ ssids[i].len = params->match_sets[j].ssid.ssid_len;
+ memcpy(ssids[i].ssid, params->match_sets[j].ssid.ssid,
+ ssids[i].len);
}
/* add SSIDs from scan SSID list */
*ssid_bitmap = 0;
- for (j = 0; j < req->n_ssids && i < PROBE_OPTION_MAX; j++) {
- index = iwl_ssid_exist(req->ssids[j].ssid,
- req->ssids[j].ssid_len,
- direct_scan);
+ for (j = params->n_ssids - 1;
+ j >= 0 && i < PROBE_OPTION_MAX;
+ i++, j--) {
+ index = iwl_ssid_exist(params->ssids[j].ssid,
+ params->ssids[j].ssid_len,
+ ssids);
if (index < 0) {
- if (!req->ssids[j].ssid_len && basic_ssid)
- continue;
- direct_scan[i].id = WLAN_EID_SSID;
- direct_scan[i].len = req->ssids[j].ssid_len;
- memcpy(direct_scan[i].ssid, req->ssids[j].ssid,
- direct_scan[i].len);
- *ssid_bitmap |= BIT(i + 1);
- i++;
+ ssids[i].id = WLAN_EID_SSID;
+ ssids[i].len = params->ssids[j].ssid_len;
+ memcpy(ssids[i].ssid, params->ssids[j].ssid,
+ ssids[i].len);
+ *ssid_bitmap |= BIT(i);
} else {
- *ssid_bitmap |= BIT(index + 1);
+ *ssid_bitmap |= BIT(index);
}
}
}
-int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
- struct cfg80211_sched_scan_request *req)
+static int
+iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
+ struct cfg80211_sched_scan_request *req)
{
struct iwl_scan_offload_profile *profile;
struct iwl_scan_offload_profile_cfg *profile_cfg;
@@ -515,30 +574,7 @@ static bool iwl_mvm_scan_pass_all(struct iwl_mvm *mvm,
return true;
}
-int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies)
-{
- int ret;
-
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
- ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
- if (ret)
- return ret;
- ret = iwl_mvm_sched_scan_umac(mvm, vif, req, ies);
- } else {
- mvm->scan_status = IWL_MVM_SCAN_SCHED;
- ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
- if (ret)
- return ret;
- ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
- }
-
- return ret;
-}
-
-static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
+static int iwl_mvm_lmac_scan_abort(struct iwl_mvm *mvm)
{
int ret;
struct iwl_host_cmd cmd = {
@@ -546,12 +582,6 @@ static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
};
u32 status;
- /* Exit instantly with error when device is not ready
- * to receive scan abort command or it does not perform
- * scheduled scan currently */
- if (mvm->scan_status == IWL_MVM_SCAN_NONE)
- return -EIO;
-
ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status);
if (ret)
return ret;
@@ -571,69 +601,9 @@ static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
return ret;
}
-int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
-{
- int ret;
- struct iwl_notification_wait wait_scan_done;
- static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, };
- bool sched = mvm->scan_status == IWL_MVM_SCAN_SCHED;
-
- lockdep_assert_held(&mvm->mutex);
-
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
- 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)) {
- ret = 0;
- goto out;
- }
-
- iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
- scan_done_notif,
- ARRAY_SIZE(scan_done_notif),
- NULL, NULL);
-
- ret = iwl_mvm_send_scan_offload_abort(mvm);
- if (ret) {
- IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n",
- sched ? "offloaded " : "", ret);
- iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
- goto out;
- }
-
- IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n",
- sched ? "offloaded " : "");
-
- ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
-out:
- /*
- * Clear the scan status so the next scan requests will succeed. This
- * also ensures the Rx handler doesn't do anything, as the scan was
- * stopped from above. Since the rx handler won't do anything now,
- * we have to release the scan reference here.
- */
- if (mvm->scan_status == IWL_MVM_SCAN_OS)
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
-
- mvm->scan_status = IWL_MVM_SCAN_NONE;
-
- if (notify) {
- if (sched)
- ieee80211_sched_scan_stopped(mvm->hw);
- else
- ieee80211_scan_completed(mvm->hw, true);
- }
-
- return ret;
-}
-
-static void iwl_mvm_unified_scan_fill_tx_cmd(struct iwl_mvm *mvm,
- struct iwl_scan_req_tx_cmd *tx_cmd,
- bool no_cck)
+static void iwl_mvm_scan_fill_tx_cmd(struct iwl_mvm *mvm,
+ struct iwl_scan_req_tx_cmd *tx_cmd,
+ bool no_cck)
{
tx_cmd[0].tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
TX_CMD_FLG_BT_DIS);
@@ -654,7 +624,7 @@ static void
iwl_mvm_lmac_scan_cfg_channels(struct iwl_mvm *mvm,
struct ieee80211_channel **channels,
int n_channels, u32 ssid_bitmap,
- struct iwl_scan_req_unified_lmac *cmd)
+ struct iwl_scan_req_lmac *cmd)
{
struct iwl_scan_channel_cfg_lmac *channel_cfg = (void *)&cmd->data;
int i;
@@ -707,13 +677,14 @@ static u8 *iwl_mvm_copy_and_insert_ds_elem(struct iwl_mvm *mvm, const u8 *ies,
}
static void
-iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct ieee80211_scan_ies *ies,
- struct iwl_scan_probe_req *preq,
- const u8 *mac_addr, const u8 *mac_addr_mask)
+iwl_mvm_build_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_scan_ies *ies,
+ struct iwl_mvm_scan_params *params)
{
- struct ieee80211_mgmt *frame = (struct ieee80211_mgmt *)preq->buf;
+ struct ieee80211_mgmt *frame = (void *)params->preq.buf;
u8 *pos, *newpos;
+ const u8 *mac_addr = params->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
+ params->mac_addr : NULL;
/*
* Unfortunately, right now the offload scan doesn't support randomising
@@ -722,7 +693,8 @@ iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
* random, only when it's restarted, but at least that helps a bit.
*/
if (mac_addr)
- get_random_mask_addr(frame->sa, mac_addr, mac_addr_mask);
+ get_random_mask_addr(frame->sa, mac_addr,
+ params->mac_addr_mask);
else
memcpy(frame->sa, vif->addr, ETH_ALEN);
@@ -735,245 +707,167 @@ iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
*pos++ = WLAN_EID_SSID;
*pos++ = 0;
- preq->mac_header.offset = 0;
- preq->mac_header.len = cpu_to_le16(24 + 2);
+ params->preq.mac_header.offset = 0;
+ params->preq.mac_header.len = cpu_to_le16(24 + 2);
/* Insert ds parameter set element on 2.4 GHz band */
newpos = iwl_mvm_copy_and_insert_ds_elem(mvm,
ies->ies[IEEE80211_BAND_2GHZ],
ies->len[IEEE80211_BAND_2GHZ],
pos);
- preq->band_data[0].offset = cpu_to_le16(pos - preq->buf);
- preq->band_data[0].len = cpu_to_le16(newpos - pos);
+ params->preq.band_data[0].offset = cpu_to_le16(pos - params->preq.buf);
+ params->preq.band_data[0].len = cpu_to_le16(newpos - pos);
pos = newpos;
memcpy(pos, ies->ies[IEEE80211_BAND_5GHZ],
ies->len[IEEE80211_BAND_5GHZ]);
- preq->band_data[1].offset = cpu_to_le16(pos - preq->buf);
- preq->band_data[1].len = cpu_to_le16(ies->len[IEEE80211_BAND_5GHZ]);
+ params->preq.band_data[1].offset = cpu_to_le16(pos - params->preq.buf);
+ params->preq.band_data[1].len =
+ cpu_to_le16(ies->len[IEEE80211_BAND_5GHZ]);
pos += ies->len[IEEE80211_BAND_5GHZ];
memcpy(pos, ies->common_ies, ies->common_ie_len);
- preq->common_data.offset = cpu_to_le16(pos - preq->buf);
- preq->common_data.len = cpu_to_le16(ies->common_ie_len);
+ params->preq.common_data.offset = cpu_to_le16(pos - params->preq.buf);
+ params->preq.common_data.len = cpu_to_le16(ies->common_ie_len);
}
-static void
-iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm,
- struct iwl_scan_req_unified_lmac *cmd,
- struct iwl_mvm_scan_params *params)
+static __le32 iwl_mvm_scan_priority(struct iwl_mvm *mvm,
+ enum iwl_scan_priority_ext prio)
+{
+ if (fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY))
+ return cpu_to_le32(prio);
+
+ if (prio <= IWL_SCAN_PRIORITY_EXT_2)
+ return cpu_to_le32(IWL_SCAN_PRIORITY_LOW);
+
+ if (prio <= IWL_SCAN_PRIORITY_EXT_4)
+ return cpu_to_le32(IWL_SCAN_PRIORITY_MEDIUM);
+
+ return cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
+}
+
+static void iwl_mvm_scan_lmac_dwell(struct iwl_mvm *mvm,
+ struct iwl_scan_req_lmac *cmd,
+ struct iwl_mvm_scan_params *params)
{
- memset(cmd, 0, ksize(cmd));
cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active;
cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive;
if (params->passive_fragmented)
cmd->fragmented_dwell =
params->dwell[IEEE80211_BAND_2GHZ].fragmented;
- cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm);
cmd->max_out_time = cpu_to_le32(params->max_out_time);
cmd->suspend_time = cpu_to_le32(params->suspend_time);
- cmd->scan_prio = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
- cmd->iter_num = cpu_to_le32(1);
-
- if (iwl_mvm_rrm_scan_needed(mvm))
- cmd->scan_flags |=
- cpu_to_le32(IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED);
+ cmd->scan_prio = iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
}
-int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_scan_request *req)
+static inline bool iwl_mvm_scan_fits(struct iwl_mvm *mvm, int n_ssids,
+ struct ieee80211_scan_ies *ies,
+ int n_channels)
{
- struct iwl_host_cmd hcmd = {
- .id = SCAN_OFFLOAD_REQUEST_CMD,
- .len = { sizeof(struct iwl_scan_req_unified_lmac) +
- sizeof(struct iwl_scan_channel_cfg_lmac) *
- mvm->fw->ucode_capa.n_scan_channels +
- sizeof(struct iwl_scan_probe_req), },
- .data = { mvm->scan_cmd, },
- .dataflags = { IWL_HCMD_DFL_NOCOPY, },
- };
- struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd;
- struct iwl_scan_probe_req *preq;
- struct iwl_mvm_scan_params params = {};
- u32 flags;
- u32 ssid_bitmap = 0;
- int ret, i;
-
- lockdep_assert_held(&mvm->mutex);
-
- /* we should have failed registration if scan_cmd was NULL */
- if (WARN_ON(mvm->scan_cmd == NULL))
- return -ENOMEM;
-
- if (req->req.n_ssids > PROBE_OPTION_MAX ||
- req->ies.common_ie_len + req->ies.len[NL80211_BAND_2GHZ] +
- req->ies.len[NL80211_BAND_5GHZ] >
- iwl_mvm_max_scan_ie_fw_cmd_room(mvm, false) ||
- req->req.n_channels > mvm->fw->ucode_capa.n_scan_channels)
- return -ENOBUFS;
+ return ((n_ssids <= PROBE_OPTION_MAX) &&
+ (n_channels <= mvm->fw->ucode_capa.n_scan_channels) &
+ (ies->common_ie_len +
+ ies->len[NL80211_BAND_2GHZ] +
+ ies->len[NL80211_BAND_5GHZ] <=
+ iwl_mvm_max_scan_ie_fw_cmd_room(mvm)));
+}
- mvm->scan_status = IWL_MVM_SCAN_OS;
+static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ int n_iterations)
+{
+ const struct iwl_ucode_capabilities *capa = &mvm->fw->ucode_capa;
- iwl_mvm_scan_calc_params(mvm, vif, req->req.n_ssids, req->req.flags,
- &params);
+ /* We can only use EBS if:
+ * 1. the feature is supported;
+ * 2. the last EBS was successful;
+ * 3. if only single scan, the single scan EBS API is supported;
+ * 4. it's not a p2p find operation.
+ */
+ return ((capa->flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) &&
+ mvm->last_ebs_successful &&
+ (n_iterations > 1 ||
+ fw_has_api(capa, IWL_UCODE_TLV_API_SINGLE_SCAN_EBS)) &&
+ vif->type != NL80211_IFTYPE_P2P_DEVICE);
+}
- iwl_mvm_build_generic_unified_scan_cmd(mvm, cmd, &params);
+static int iwl_mvm_scan_total_iterations(struct iwl_mvm_scan_params *params)
+{
+ return params->schedule[0].iterations + params->schedule[1].iterations;
+}
- cmd->n_channels = (u8)req->req.n_channels;
+static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
+ struct iwl_mvm_scan_params *params)
+{
+ int flags = 0;
- flags = IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
+ if (params->n_ssids == 0)
+ flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
- if (req->req.n_ssids == 1 && req->req.ssids[0].ssid_len != 0)
+ if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0)
flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION;
- if (params.passive_fragmented)
+ if (params->passive_fragmented)
flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED;
- if (req->req.n_ssids == 0)
- flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
-
- cmd->scan_flags |= cpu_to_le32(flags);
-
- cmd->flags = iwl_mvm_scan_rxon_flags(req->req.channels[0]->band);
- cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
- MAC_FILTER_IN_BEACON);
- iwl_mvm_unified_scan_fill_tx_cmd(mvm, cmd->tx_cmd, req->req.no_cck);
- iwl_mvm_scan_fill_ssids(cmd->direct_scan, req->req.ssids,
- req->req.n_ssids, 0);
-
- cmd->schedule[0].delay = 0;
- cmd->schedule[0].iterations = 1;
- cmd->schedule[0].full_scan_mul = 0;
- cmd->schedule[1].delay = 0;
- 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);
-
- iwl_mvm_lmac_scan_cfg_channels(mvm, req->req.channels,
- req->req.n_channels, ssid_bitmap,
- cmd);
+ if (iwl_mvm_rrm_scan_needed(mvm))
+ flags |= IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED;
- preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) *
- mvm->fw->ucode_capa.n_scan_channels);
+ if (params->pass_all)
+ flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
+ else
+ flags |= IWL_MVM_LMAC_SCAN_FLAG_MATCH;
- iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, preq,
- req->req.flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
- req->req.mac_addr : NULL,
- req->req.mac_addr_mask);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ if (mvm->scan_iter_notif_enabled)
+ flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE;
+#endif
- ret = iwl_mvm_send_cmd(mvm, &hcmd);
- if (!ret) {
- IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
- } else {
- /*
- * If the scan failed, it usually means that the FW was unable
- * to allocate the time events. Warn on it, but maybe we
- * should try to send the command again with different params.
- */
- IWL_ERR(mvm, "Scan failed! ret %d\n", ret);
- mvm->scan_status = IWL_MVM_SCAN_NONE;
- ret = -EIO;
- }
- return ret;
+ return flags;
}
-int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies)
+static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_mvm_scan_params *params)
{
- struct iwl_host_cmd hcmd = {
- .id = SCAN_OFFLOAD_REQUEST_CMD,
- .len = { sizeof(struct iwl_scan_req_unified_lmac) +
- sizeof(struct iwl_scan_channel_cfg_lmac) *
- mvm->fw->ucode_capa.n_scan_channels +
- sizeof(struct iwl_scan_probe_req), },
- .data = { mvm->scan_cmd, },
- .dataflags = { IWL_HCMD_DFL_NOCOPY, },
- };
- struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd;
- struct iwl_scan_probe_req *preq;
- struct iwl_mvm_scan_params params = {};
- int ret;
- u32 flags = 0, ssid_bitmap = 0;
+ struct iwl_scan_req_lmac *cmd = mvm->scan_cmd;
+ struct iwl_scan_probe_req *preq =
+ (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) *
+ mvm->fw->ucode_capa.n_scan_channels);
+ u32 ssid_bitmap = 0;
+ int n_iterations = iwl_mvm_scan_total_iterations(params);
lockdep_assert_held(&mvm->mutex);
- /* we should have failed registration if scan_cmd was NULL */
- if (WARN_ON(mvm->scan_cmd == NULL))
- return -ENOMEM;
-
- if (req->n_ssids > PROBE_OPTION_MAX ||
- ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] +
- ies->len[NL80211_BAND_5GHZ] >
- iwl_mvm_max_scan_ie_fw_cmd_room(mvm, true) ||
- req->n_channels > mvm->fw->ucode_capa.n_scan_channels)
- return -ENOBUFS;
-
- iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, 0, &params);
-
- iwl_mvm_build_generic_unified_scan_cmd(mvm, cmd, &params);
-
- cmd->n_channels = (u8)req->n_channels;
-
- cmd->delay = cpu_to_le32(req->delay);
-
- if (iwl_mvm_scan_pass_all(mvm, req))
- flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
- else
- flags |= IWL_MVM_LMAC_SCAN_FLAG_MATCH;
+ memset(cmd, 0, ksize(cmd));
- if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0)
- flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION;
+ iwl_mvm_scan_lmac_dwell(mvm, cmd, params);
- if (params.passive_fragmented)
- flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED;
-
- if (req->n_ssids == 0)
- flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
+ cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm);
+ cmd->iter_num = cpu_to_le32(1);
+ cmd->n_channels = (u8)params->n_channels;
-#ifdef CONFIG_IWLWIFI_DEBUGFS
- if (mvm->scan_iter_notif_enabled)
- flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE;
-#endif
+ cmd->delay = cpu_to_le32(params->delay);
- cmd->scan_flags |= cpu_to_le32(flags);
+ cmd->scan_flags = cpu_to_le32(iwl_mvm_scan_lmac_flags(mvm, params));
- cmd->flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band);
+ cmd->flags = iwl_mvm_scan_rxon_flags(params->channels[0]->band);
cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
MAC_FILTER_IN_BEACON);
- iwl_mvm_unified_scan_fill_tx_cmd(mvm, cmd->tx_cmd, false);
- iwl_scan_offload_build_ssid(req, cmd->direct_scan, &ssid_bitmap, false);
+ iwl_mvm_scan_fill_tx_cmd(mvm, cmd->tx_cmd, params->no_cck);
+ iwl_scan_build_ssids(params, cmd->direct_scan, &ssid_bitmap);
- cmd->schedule[0].delay = cpu_to_le16(req->interval / MSEC_PER_SEC);
- cmd->schedule[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS;
- cmd->schedule[0].full_scan_mul = 1;
+ /* this API uses bits 1-20 instead of 0-19 */
+ ssid_bitmap <<= 1;
- cmd->schedule[1].delay = cpu_to_le16(req->interval / MSEC_PER_SEC);
- cmd->schedule[1].iterations = 0xff;
- cmd->schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER;
+ cmd->schedule[0].delay = cpu_to_le16(params->interval);
+ cmd->schedule[0].iterations = params->schedule[0].iterations;
+ cmd->schedule[0].full_scan_mul = params->schedule[0].full_scan_mul;
+ cmd->schedule[1].delay = cpu_to_le16(params->interval);
+ cmd->schedule[1].iterations = params->schedule[1].iterations;
+ cmd->schedule[1].full_scan_mul = params->schedule[1].iterations;
- if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT &&
- mvm->last_ebs_successful) {
+ if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations)) {
cmd->channel_opt[0].flags =
cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
@@ -988,61 +882,14 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO);
}
- iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels,
- ssid_bitmap, cmd);
-
- preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) *
- mvm->fw->ucode_capa.n_scan_channels);
+ iwl_mvm_lmac_scan_cfg_channels(mvm, params->channels,
+ params->n_channels, ssid_bitmap, cmd);
- iwl_mvm_build_unified_scan_probe(mvm, vif, ies, preq,
- req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
- req->mac_addr : NULL,
- req->mac_addr_mask);
+ *preq = params->preq;
- ret = iwl_mvm_send_cmd(mvm, &hcmd);
- if (!ret) {
- IWL_DEBUG_SCAN(mvm,
- "Sched scan request was sent successfully\n");
- } else {
- /*
- * If the scan failed, it usually means that the FW was unable
- * to allocate the time events. Warn on it, but maybe we
- * should try to send the command again with different params.
- */
- IWL_ERR(mvm, "Sched scan failed! ret %d\n", ret);
- mvm->scan_status = IWL_MVM_SCAN_NONE;
- ret = -EIO;
- }
- return ret;
-}
-
-
-int iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
-{
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
- return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_REG_SCAN,
- true);
-
- if (mvm->scan_status == IWL_MVM_SCAN_NONE)
- return 0;
-
- if (iwl_mvm_is_radio_killed(mvm)) {
- ieee80211_scan_completed(mvm->hw, true);
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
- mvm->scan_status = IWL_MVM_SCAN_NONE;
- return 0;
- }
-
- return iwl_mvm_scan_offload_stop(mvm, true);
+ return 0;
}
-/* UMAC scan API */
-
-struct iwl_umac_scan_done {
- struct iwl_mvm *mvm;
- enum iwl_umac_scan_uid_type type;
-};
-
static int rate_to_scan_rate_flag(unsigned int rate)
{
static const int rate_to_scan_rate[IWL_RATE_COUNT] = {
@@ -1151,79 +998,21 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
return ret;
}
-static int iwl_mvm_find_scan_uid(struct iwl_mvm *mvm, u32 uid)
-{
- int i;
-
- for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++)
- if (mvm->scan_uid[i] == uid)
- return i;
-
- return i;
-}
-
-static int iwl_mvm_find_free_scan_uid(struct iwl_mvm *mvm)
-{
- return iwl_mvm_find_scan_uid(mvm, 0);
-}
-
-static bool iwl_mvm_find_scan_type(struct iwl_mvm *mvm,
- enum iwl_umac_scan_uid_type type)
-{
- int i;
-
- for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++)
- if (mvm->scan_uid[i] & type)
- return true;
-
- return false;
-}
-
-static int iwl_mvm_find_first_scan(struct iwl_mvm *mvm,
- enum iwl_umac_scan_uid_type type)
+static int iwl_mvm_scan_uid_by_status(struct iwl_mvm *mvm, int status)
{
int i;
- for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++)
- if (mvm->scan_uid[i] & type)
+ for (i = 0; i < mvm->max_scans; i++)
+ if (mvm->scan_uid_status[i] == status)
return i;
- return i;
+ return -ENOENT;
}
-static u32 iwl_generate_scan_uid(struct iwl_mvm *mvm,
- enum iwl_umac_scan_uid_type type)
-{
- u32 uid;
-
- /* make sure exactly one bit is on in scan type */
- WARN_ON(hweight8(type) != 1);
-
- /*
- * Make sure scan uids are unique. If one scan lasts long time while
- * others are completing frequently, the seq number will wrap up and
- * we may have more than one scan with the same uid.
- */
- do {
- uid = type | (mvm->scan_seq_num <<
- IWL_UMAC_SCAN_UID_SEQ_OFFSET);
- mvm->scan_seq_num++;
- } while (iwl_mvm_find_scan_uid(mvm, uid) <
- IWL_MVM_MAX_SIMULTANEOUS_SCANS);
-
- IWL_DEBUG_SCAN(mvm, "Generated scan UID %u\n", uid);
-
- return uid;
-}
-
-static void
-iwl_mvm_build_generic_umac_scan_cmd(struct iwl_mvm *mvm,
+static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
struct iwl_scan_req_umac *cmd,
struct iwl_mvm_scan_params *params)
{
- memset(cmd, 0, ksize(cmd));
- cmd->hdr.size = cpu_to_le16(iwl_mvm_scan_size(mvm) -
- sizeof(struct iwl_mvm_umac_cmd_hdr));
cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active;
cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive;
if (params->passive_fragmented)
@@ -1231,7 +1020,15 @@ iwl_mvm_build_generic_umac_scan_cmd(struct iwl_mvm *mvm,
params->dwell[IEEE80211_BAND_2GHZ].fragmented;
cmd->max_out_time = cpu_to_le32(params->max_out_time);
cmd->suspend_time = cpu_to_le32(params->suspend_time);
- cmd->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
+ cmd->scan_priority =
+ iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
+
+ if (iwl_mvm_scan_total_iterations(params) == 0)
+ cmd->ooc_priority =
+ iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
+ else
+ cmd->ooc_priority =
+ iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_2);
}
static void
@@ -1251,230 +1048,326 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm,
}
}
-static u32 iwl_mvm_scan_umac_common_flags(struct iwl_mvm *mvm, int n_ssids,
- struct cfg80211_ssid *ssids,
- int fragmented)
+static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
+ struct iwl_mvm_scan_params *params)
{
int flags = 0;
- if (n_ssids == 0)
+ if (params->n_ssids == 0)
flags = IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE;
- if (n_ssids == 1 && ssids[0].ssid_len != 0)
+ if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT;
- if (fragmented)
+ if (params->passive_fragmented)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED;
if (iwl_mvm_rrm_scan_needed(mvm))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED;
+ if (params->pass_all)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL;
+ else
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_MATCH;
+
+ if (iwl_mvm_scan_total_iterations(params) > 1)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ if (mvm->scan_iter_notif_enabled)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
+#endif
return flags;
}
-int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct ieee80211_scan_request *req)
+static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_mvm_scan_params *params,
+ int type)
{
- struct iwl_host_cmd hcmd = {
- .id = SCAN_REQ_UMAC,
- .len = { iwl_mvm_scan_size(mvm), },
- .data = { mvm->scan_cmd, },
- .dataflags = { IWL_HCMD_DFL_NOCOPY, },
- };
struct iwl_scan_req_umac *cmd = mvm->scan_cmd;
struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data +
sizeof(struct iwl_scan_channel_cfg_umac) *
mvm->fw->ucode_capa.n_scan_channels;
- struct iwl_mvm_scan_params params = {};
- u32 uid, flags;
+ int uid;
u32 ssid_bitmap = 0;
- int ret, i, uid_idx;
+ int n_iterations = iwl_mvm_scan_total_iterations(params);
lockdep_assert_held(&mvm->mutex);
- uid_idx = iwl_mvm_find_free_scan_uid(mvm);
- if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
- return -EBUSY;
+ uid = iwl_mvm_scan_uid_by_status(mvm, 0);
+ if (uid < 0)
+ return uid;
- /* we should have failed registration if scan_cmd was NULL */
- if (WARN_ON(mvm->scan_cmd == NULL))
- return -ENOMEM;
-
- if (WARN_ON(req->req.n_ssids > PROBE_OPTION_MAX ||
- req->ies.common_ie_len +
- req->ies.len[NL80211_BAND_2GHZ] +
- req->ies.len[NL80211_BAND_5GHZ] + 24 + 2 >
- SCAN_OFFLOAD_PROBE_REQ_SIZE || req->req.n_channels >
- mvm->fw->ucode_capa.n_scan_channels))
- return -ENOBUFS;
+ memset(cmd, 0, ksize(cmd));
+ cmd->hdr.size = cpu_to_le16(iwl_mvm_scan_size(mvm) -
+ sizeof(struct iwl_mvm_umac_cmd_hdr));
- iwl_mvm_scan_calc_params(mvm, vif, req->req.n_ssids, req->req.flags,
- &params);
+ iwl_mvm_scan_umac_dwell(mvm, cmd, params);
- iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, &params);
+ mvm->scan_uid_status[uid] = type;
- uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_REG_SCAN);
- mvm->scan_uid[uid_idx] = uid;
cmd->uid = cpu_to_le32(uid);
+ cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params));
- cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
-
- flags = iwl_mvm_scan_umac_common_flags(mvm, req->req.n_ssids,
- req->req.ssids,
- params.passive_fragmented);
-
- 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)
+ if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations))
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;
+ cmd->n_channels = params->n_channels;
+
+ iwl_scan_build_ssids(params, sec_part->direct_scan, &ssid_bitmap);
- for (i = 0; i < req->req.n_ssids; i++)
- ssid_bitmap |= BIT(i);
+ iwl_mvm_umac_scan_cfg_channels(mvm, params->channels,
+ params->n_channels, ssid_bitmap, cmd);
- iwl_mvm_umac_scan_cfg_channels(mvm, req->req.channels,
- req->req.n_channels, ssid_bitmap, cmd);
+ /* With UMAC we use only one schedule for now, so use the sum
+ * of the iterations (with a a maximum of 255).
+ */
+ sec_part->schedule[0].iter_count =
+ (n_iterations > 255) ? 255 : n_iterations;
+ sec_part->schedule[0].interval = cpu_to_le16(params->interval);
- sec_part->schedule[0].iter_count = 1;
- sec_part->delay = 0;
+ sec_part->delay = cpu_to_le16(params->delay);
+ sec_part->preq = params->preq;
- iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, &sec_part->preq,
- req->req.flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
- req->req.mac_addr : NULL,
- req->req.mac_addr_mask);
+ return 0;
+}
- iwl_mvm_scan_fill_ssids(sec_part->direct_scan, req->req.ssids,
- req->req.n_ssids, 0);
+static int iwl_mvm_num_scans(struct iwl_mvm *mvm)
+{
+ return hweight32(mvm->scan_status & IWL_MVM_SCAN_MASK);
+}
- ret = iwl_mvm_send_cmd(mvm, &hcmd);
- if (!ret) {
- IWL_DEBUG_SCAN(mvm,
- "Scan request was sent successfully\n");
- } else {
- /*
- * If the scan failed, it usually means that the FW was unable
- * to allocate the time events. Warn on it, but maybe we
- * should try to send the command again with different params.
- */
- IWL_ERR(mvm, "Scan failed! ret %d\n", ret);
+static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type)
+{
+ /* This looks a bit arbitrary, but the idea is that if we run
+ * out of possible simultaneous scans and the userspace is
+ * trying to run a scan type that is already running, we
+ * return -EBUSY. But if the userspace wants to start a
+ * different type of scan, we stop the opposite type to make
+ * space for the new request. The reason is backwards
+ * compatibility with old wpa_supplicant that wouldn't stop a
+ * scheduled scan before starting a normal scan.
+ */
+
+ if (iwl_mvm_num_scans(mvm) < mvm->max_scans)
+ return 0;
+
+ /* Use a switch, even though this is a bitmask, so that more
+ * than one bits set will fall in default and we will warn.
+ */
+ switch (type) {
+ case IWL_MVM_SCAN_REGULAR:
+ if (mvm->scan_status & IWL_MVM_SCAN_REGULAR_MASK)
+ return -EBUSY;
+ return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true);
+ case IWL_MVM_SCAN_SCHED:
+ if (mvm->scan_status & IWL_MVM_SCAN_SCHED_MASK)
+ return -EBUSY;
+ iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);
+ case IWL_MVM_SCAN_NETDETECT:
+ /* No need to stop anything for net-detect since the
+ * firmware is restarted anyway. This way, any sched
+ * scans that were running will be restarted when we
+ * resume.
+ */
+ return 0;
+ default:
+ WARN_ON(1);
+ break;
}
- return ret;
+
+ return -EIO;
}
-int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct cfg80211_sched_scan_request *req,
- struct ieee80211_scan_ies *ies)
+int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct cfg80211_scan_request *req,
+ struct ieee80211_scan_ies *ies)
{
-
struct iwl_host_cmd hcmd = {
- .id = SCAN_REQ_UMAC,
.len = { iwl_mvm_scan_size(mvm), },
.data = { mvm->scan_cmd, },
.dataflags = { IWL_HCMD_DFL_NOCOPY, },
};
- struct iwl_scan_req_umac *cmd = mvm->scan_cmd;
- struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data +
- sizeof(struct iwl_scan_channel_cfg_umac) *
- mvm->fw->ucode_capa.n_scan_channels;
struct iwl_mvm_scan_params params = {};
- u32 uid, flags;
- u32 ssid_bitmap = 0;
- int ret, uid_idx;
+ int ret;
lockdep_assert_held(&mvm->mutex);
- uid_idx = iwl_mvm_find_free_scan_uid(mvm);
- if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
+ if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
+ IWL_ERR(mvm, "scan while LAR regdomain is not set\n");
return -EBUSY;
+ }
+
+ ret = iwl_mvm_check_running_scans(mvm, IWL_MVM_SCAN_REGULAR);
+ if (ret)
+ return ret;
+
+ iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
/* we should have failed registration if scan_cmd was NULL */
- if (WARN_ON(mvm->scan_cmd == NULL))
+ if (WARN_ON(!mvm->scan_cmd))
return -ENOMEM;
- if (WARN_ON(req->n_ssids > PROBE_OPTION_MAX ||
- ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] +
- ies->len[NL80211_BAND_5GHZ] + 24 + 2 >
- SCAN_OFFLOAD_PROBE_REQ_SIZE || req->n_channels >
- mvm->fw->ucode_capa.n_scan_channels))
+ if (!iwl_mvm_scan_fits(mvm, req->n_ssids, ies, req->n_channels))
return -ENOBUFS;
- iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, req->flags,
- &params);
-
- iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, &params);
-
- cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);
-
- uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN);
- mvm->scan_uid[uid_idx] = uid;
- cmd->uid = cpu_to_le32(uid);
+ params.n_ssids = req->n_ssids;
+ params.flags = req->flags;
+ params.n_channels = req->n_channels;
+ params.delay = 0;
+ params.interval = 0;
+ params.ssids = req->ssids;
+ params.channels = req->channels;
+ params.mac_addr = req->mac_addr;
+ params.mac_addr_mask = req->mac_addr_mask;
+ params.no_cck = req->no_cck;
+ params.pass_all = true;
+ params.n_match_sets = 0;
+ params.match_sets = NULL;
+
+ params.schedule[0].iterations = 1;
+ params.schedule[0].full_scan_mul = 0;
+ params.schedule[1].iterations = 0;
+ params.schedule[1].full_scan_mul = 0;
+
+ iwl_mvm_scan_calc_dwell(mvm, vif, &params);
+
+ iwl_mvm_build_scan_probe(mvm, vif, ies, &params);
+
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
+ hcmd.id = SCAN_REQ_UMAC;
+ ret = iwl_mvm_scan_umac(mvm, vif, &params,
+ IWL_MVM_SCAN_REGULAR);
+ } else {
+ hcmd.id = SCAN_OFFLOAD_REQUEST_CMD;
+ ret = iwl_mvm_scan_lmac(mvm, vif, &params);
+ }
- cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_LOW);
+ if (ret)
+ return ret;
- flags = iwl_mvm_scan_umac_common_flags(mvm, req->n_ssids, req->ssids,
- params.passive_fragmented);
+ ret = iwl_mvm_send_cmd(mvm, &hcmd);
+ if (!ret) {
+ IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
+ mvm->scan_status |= IWL_MVM_SCAN_REGULAR;
+ } else {
+ /* If the scan failed, it usually means that the FW was unable
+ * to allocate the time events. Warn on it, but maybe we
+ * should try to send the command again with different params.
+ */
+ IWL_ERR(mvm, "Scan failed! ret %d\n", ret);
+ }
- flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC;
+ if (ret)
+ iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
- if (iwl_mvm_scan_pass_all(mvm, req))
- flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL;
- else
- flags |= IWL_UMAC_SCAN_GEN_FLAGS_MATCH;
+ return ret;
+}
- cmd->general_flags = cpu_to_le32(flags);
+int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_scan_ies *ies,
+ int type)
+{
+ struct iwl_host_cmd hcmd = {
+ .len = { iwl_mvm_scan_size(mvm), },
+ .data = { mvm->scan_cmd, },
+ .dataflags = { IWL_HCMD_DFL_NOCOPY, },
+ };
+ struct iwl_mvm_scan_params params = {};
+ int ret;
- if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT &&
- mvm->last_ebs_successful)
- cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |
- IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
- IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;
+ lockdep_assert_held(&mvm->mutex);
- cmd->n_channels = req->n_channels;
+ if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) {
+ IWL_ERR(mvm, "sched-scan while LAR regdomain is not set\n");
+ return -EBUSY;
+ }
- iwl_scan_offload_build_ssid(req, sec_part->direct_scan, &ssid_bitmap,
- false);
+ ret = iwl_mvm_check_running_scans(mvm, type);
+ if (ret)
+ return ret;
- /* This API uses bits 0-19 instead of 1-20. */
- ssid_bitmap = ssid_bitmap >> 1;
+ /* we should have failed registration if scan_cmd was NULL */
+ if (WARN_ON(!mvm->scan_cmd))
+ return -ENOMEM;
- iwl_mvm_umac_scan_cfg_channels(mvm, req->channels, req->n_channels,
- ssid_bitmap, cmd);
+ if (!iwl_mvm_scan_fits(mvm, req->n_ssids, ies, req->n_channels))
+ return -ENOBUFS;
- sec_part->schedule[0].interval =
- cpu_to_le16(req->interval / MSEC_PER_SEC);
- sec_part->schedule[0].iter_count = 0xff;
+ params.n_ssids = req->n_ssids;
+ params.flags = req->flags;
+ params.n_channels = req->n_channels;
+ params.ssids = req->ssids;
+ params.channels = req->channels;
+ params.mac_addr = req->mac_addr;
+ params.mac_addr_mask = req->mac_addr_mask;
+ params.no_cck = false;
+ params.pass_all = iwl_mvm_scan_pass_all(mvm, req);
+ params.n_match_sets = req->n_match_sets;
+ params.match_sets = req->match_sets;
+
+ params.schedule[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS;
+ params.schedule[0].full_scan_mul = 1;
+ params.schedule[1].iterations = 0xff;
+ params.schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER;
+
+ if (req->interval > U16_MAX) {
+ IWL_DEBUG_SCAN(mvm,
+ "interval value is > 16-bits, set to max possible\n");
+ params.interval = U16_MAX;
+ } else {
+ params.interval = req->interval / MSEC_PER_SEC;
+ }
+ /* In theory, LMAC scans can handle a 32-bit delay, but since
+ * waiting for over 18 hours to start the scan is a bit silly
+ * and to keep it aligned with UMAC scans (which only support
+ * 16-bit delays), trim it down to 16-bits.
+ */
if (req->delay > U16_MAX) {
IWL_DEBUG_SCAN(mvm,
"delay value is > 16-bits, set to max possible\n");
- sec_part->delay = cpu_to_le16(U16_MAX);
+ params.delay = U16_MAX;
+ } else {
+ params.delay = req->delay;
+ }
+
+ iwl_mvm_scan_calc_dwell(mvm, vif, &params);
+
+ ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
+ if (ret)
+ return ret;
+
+ iwl_mvm_build_scan_probe(mvm, vif, ies, &params);
+
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
+ hcmd.id = SCAN_REQ_UMAC;
+ ret = iwl_mvm_scan_umac(mvm, vif, &params, IWL_MVM_SCAN_SCHED);
} else {
- sec_part->delay = cpu_to_le16(req->delay);
+ hcmd.id = SCAN_OFFLOAD_REQUEST_CMD;
+ ret = iwl_mvm_scan_lmac(mvm, vif, &params);
}
- iwl_mvm_build_unified_scan_probe(mvm, vif, ies, &sec_part->preq,
- req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
- req->mac_addr : NULL,
- req->mac_addr_mask);
+ if (ret)
+ return ret;
ret = iwl_mvm_send_cmd(mvm, &hcmd);
if (!ret) {
IWL_DEBUG_SCAN(mvm,
"Sched scan request was sent successfully\n");
+ mvm->scan_status |= type;
} else {
- /*
- * If the scan failed, it usually means that the FW was unable
+ /* If the scan failed, it usually means that the FW was unable
* to allocate the time events. Warn on it, but maybe we
* should try to send the command again with different params.
*/
IWL_ERR(mvm, "Sched scan failed! ret %d\n", ret);
}
+
return ret;
}
@@ -1485,150 +1378,124 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_umac_scan_complete *notif = (void *)pkt->data;
u32 uid = __le32_to_cpu(notif->uid);
- bool sched = !!(uid & IWL_UMAC_SCAN_UID_SCHED_SCAN);
- int uid_idx = iwl_mvm_find_scan_uid(mvm, uid);
+ bool aborted = (notif->status == IWL_SCAN_OFFLOAD_ABORTED);
- /*
- * Scan uid may be set to zero in case of scan abort request from above.
- */
- if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
+ if (WARN_ON(!(mvm->scan_uid_status[uid] & mvm->scan_status)))
return 0;
+ /* if the scan is already stopping, we don't need to notify mac80211 */
+ if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_REGULAR) {
+ ieee80211_scan_completed(mvm->hw, aborted);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
+ } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) {
+ ieee80211_sched_scan_stopped(mvm->hw);
+ }
+
+ mvm->scan_status &= ~mvm->scan_uid_status[uid];
+
IWL_DEBUG_SCAN(mvm,
- "Scan completed, uid %u type %s, status %s, EBS status %s\n",
- uid, sched ? "sched" : "regular",
+ "Scan completed, uid %u type %u, status %s, EBS status %s\n",
+ uid, mvm->scan_uid_status[uid],
notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
"completed" : "aborted",
- notif->ebs_status == IWL_SCAN_EBS_SUCCESS ?
- "success" : "failed");
+ iwl_mvm_ebs_status_str(notif->ebs_status));
- if (notif->ebs_status)
+ if (notif->ebs_status != IWL_SCAN_EBS_SUCCESS &&
+ notif->ebs_status != IWL_SCAN_EBS_INACTIVE)
mvm->last_ebs_successful = false;
- mvm->scan_uid[uid_idx] = 0;
-
- if (!sched) {
- ieee80211_scan_completed(mvm->hw,
- notif->status ==
- IWL_SCAN_OFFLOAD_ABORTED);
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
- } else if (!iwl_mvm_find_scan_type(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN)) {
- ieee80211_sched_scan_stopped(mvm->hw);
- } else {
- IWL_DEBUG_SCAN(mvm, "Another sched scan is running\n");
- }
+ mvm->scan_uid_status[uid] = 0;
return 0;
}
-static bool iwl_scan_umac_done_check(struct iwl_notif_wait_data *notif_wait,
- struct iwl_rx_packet *pkt, void *data)
+int iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
{
- struct iwl_umac_scan_done *scan_done = data;
- struct iwl_umac_scan_complete *notif = (void *)pkt->data;
- u32 uid = __le32_to_cpu(notif->uid);
- int uid_idx = iwl_mvm_find_scan_uid(scan_done->mvm, uid);
-
- if (WARN_ON(pkt->hdr.cmd != SCAN_COMPLETE_UMAC))
- return false;
-
- if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
- return false;
-
- /*
- * Clear scan uid of scans that was aborted from above and completed
- * 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;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_umac_scan_iter_complete_notif *notif = (void *)pkt->data;
+ u8 buf[256];
- return !iwl_mvm_find_scan_type(scan_done->mvm, scan_done->type);
+ IWL_DEBUG_SCAN(mvm,
+ "UMAC Scan iteration complete: status=0x%x scanned_channels=%d channels list: %s\n",
+ notif->status, notif->scanned_channels,
+ iwl_mvm_dump_channel_list(notif->results,
+ notif->scanned_channels, buf,
+ sizeof(buf)));
+ return 0;
}
-static int iwl_umac_scan_abort_one(struct iwl_mvm *mvm, u32 uid)
+static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)
{
struct iwl_umac_scan_abort cmd = {
.hdr.size = cpu_to_le16(sizeof(struct iwl_umac_scan_abort) -
sizeof(struct iwl_mvm_umac_cmd_hdr)),
- .uid = cpu_to_le32(uid),
};
+ int uid, ret;
lockdep_assert_held(&mvm->mutex);
+ /* We should always get a valid index here, because we already
+ * checked that this type of scan was running in the generic
+ * code.
+ */
+ uid = iwl_mvm_scan_uid_by_status(mvm, type);
+ if (WARN_ON_ONCE(uid < 0))
+ return uid;
+
+ cmd.uid = cpu_to_le32(uid);
+
IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid);
- return iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_UMAC, 0, sizeof(cmd), &cmd);
+ ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_UMAC, 0, sizeof(cmd), &cmd);
+ if (!ret)
+ mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT;
+
+ return ret;
}
-static int iwl_umac_scan_stop(struct iwl_mvm *mvm,
- enum iwl_umac_scan_uid_type type, bool notify)
+static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)
{
struct iwl_notification_wait wait_scan_done;
- static const u8 scan_done_notif[] = { SCAN_COMPLETE_UMAC, };
- struct iwl_umac_scan_done scan_done = {
- .mvm = mvm,
- .type = type,
- };
- int i, ret = -EIO;
+ static const u8 scan_done_notif[] = { SCAN_COMPLETE_UMAC,
+ SCAN_OFFLOAD_COMPLETE, };
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
scan_done_notif,
ARRAY_SIZE(scan_done_notif),
- iwl_scan_umac_done_check, &scan_done);
+ NULL, NULL);
IWL_DEBUG_SCAN(mvm, "Preparing to stop scan, type %x\n", type);
- for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) {
- if (mvm->scan_uid[i] & type) {
- int err;
-
- if (iwl_mvm_is_radio_killed(mvm) &&
- (type & IWL_UMAC_SCAN_UID_REG_SCAN)) {
- ieee80211_scan_completed(mvm->hw, true);
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
- break;
- }
-
- err = iwl_umac_scan_abort_one(mvm, mvm->scan_uid[i]);
- if (!err)
- ret = 0;
- }
- }
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN))
+ ret = iwl_mvm_umac_scan_abort(mvm, type);
+ else
+ ret = iwl_mvm_lmac_scan_abort(mvm);
if (ret) {
- IWL_DEBUG_SCAN(mvm, "Couldn't stop scan\n");
+ IWL_DEBUG_SCAN(mvm, "couldn't stop scan type %d\n", type);
iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
return ret;
}
ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
- if (ret)
- return ret;
-
- if (notify) {
- if (type & IWL_UMAC_SCAN_UID_SCHED_SCAN)
- ieee80211_sched_scan_stopped(mvm->hw);
- if (type & IWL_UMAC_SCAN_UID_REG_SCAN) {
- ieee80211_scan_completed(mvm->hw, true);
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
- }
- }
return ret;
}
int iwl_mvm_scan_size(struct iwl_mvm *mvm)
{
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN))
return sizeof(struct iwl_scan_req_umac) +
sizeof(struct iwl_scan_channel_cfg_umac) *
mvm->fw->ucode_capa.n_scan_channels +
sizeof(struct iwl_scan_req_umac_tail);
- return sizeof(struct iwl_scan_req_unified_lmac) +
+ return sizeof(struct iwl_scan_req_lmac) +
sizeof(struct iwl_scan_channel_cfg_lmac) *
mvm->fw->ucode_capa.n_scan_channels +
sizeof(struct iwl_scan_probe_req);
@@ -1640,47 +1507,76 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm)
*/
void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)
{
- if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
- u32 uid, i;
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
+ int uid, i;
- uid = iwl_mvm_find_first_scan(mvm, IWL_UMAC_SCAN_UID_REG_SCAN);
- if (uid < IWL_MVM_MAX_SIMULTANEOUS_SCANS) {
+ uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_REGULAR);
+ if (uid >= 0) {
ieee80211_scan_completed(mvm->hw, true);
- mvm->scan_uid[uid] = 0;
+ mvm->scan_uid_status[uid] = 0;
}
- uid = iwl_mvm_find_first_scan(mvm,
- IWL_UMAC_SCAN_UID_SCHED_SCAN);
- if (uid < IWL_MVM_MAX_SIMULTANEOUS_SCANS && !mvm->restart_fw) {
+ uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_SCHED);
+ if (uid >= 0 && !mvm->restart_fw) {
ieee80211_sched_scan_stopped(mvm->hw);
- mvm->scan_uid[uid] = 0;
+ mvm->scan_uid_status[uid] = 0;
}
/* We shouldn't have any UIDs still set. Loop over all the
* UIDs to make sure there's nothing left there and warn if
* any is found.
*/
- for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) {
- if (WARN_ONCE(mvm->scan_uid[i],
- "UMAC scan UID %d was not cleaned\n",
- mvm->scan_uid[i]))
- mvm->scan_uid[i] = 0;
+ for (i = 0; i < mvm->max_scans; i++) {
+ if (WARN_ONCE(mvm->scan_uid_status[i],
+ "UMAC scan UID %d status was not cleaned\n",
+ i))
+ mvm->scan_uid_status[i] = 0;
}
} else {
- switch (mvm->scan_status) {
- case IWL_MVM_SCAN_NONE:
- break;
- case IWL_MVM_SCAN_OS:
+ if (mvm->scan_status & IWL_MVM_SCAN_REGULAR)
ieee80211_scan_completed(mvm->hw, true);
- break;
- case IWL_MVM_SCAN_SCHED:
- /*
- * Sched scan will be restarted by mac80211 in
- * restart_hw, so do not report if FW is about to be
- * restarted.
- */
- if (!mvm->restart_fw)
- ieee80211_sched_scan_stopped(mvm->hw);
- break;
- }
+
+ /* Sched scan will be restarted by mac80211 in
+ * restart_hw, so do not report if FW is about to be
+ * restarted.
+ */
+ if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) && !mvm->restart_fw)
+ ieee80211_sched_scan_stopped(mvm->hw);
+ }
+}
+
+int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify)
+{
+ int ret;
+
+ if (!(mvm->scan_status & type))
+ return 0;
+
+ if (iwl_mvm_is_radio_killed(mvm)) {
+ ret = 0;
+ goto out;
+ }
+
+ ret = iwl_mvm_scan_stop_wait(mvm, type);
+ if (!ret)
+ mvm->scan_status |= type << IWL_MVM_SCAN_STOPPING_SHIFT;
+out:
+ /* Clear the scan status so the next scan requests will
+ * succeed and mark the scan as stopping, so that the Rx
+ * handler doesn't do anything, as the scan was stopped from
+ * above.
+ */
+ mvm->scan_status &= ~type;
+
+ if (type == IWL_MVM_SCAN_REGULAR) {
+ /* Since the rx handler won't do anything now, we have
+ * to release the scan reference here.
+ */
+ iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
+ if (notify)
+ ieee80211_scan_completed(mvm->hw, true);
+ } else if (notify) {
+ ieee80211_sched_scan_stopped(mvm->hw);
}
+
+ return ret;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 1845b79487c8..d68dc697a4a0 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -5,8 +5,8 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2012 - 2015 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
@@ -31,8 +31,8 @@
*
* BSD LICENSE
*
- * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2012 - 2015 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
@@ -1000,13 +1000,13 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
+ iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid,
+ buf_size, ssn, wdg_timeout);
+
ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
if (ret)
return -EIO;
- iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid,
- buf_size, ssn, wdg_timeout);
-
/*
* Even though in theory the peer could have different
* aggregation reorder buffer sizes for different sessions,
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index fd7b0d36f9a6..d24b6a83e68c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -108,12 +108,14 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
* in the case that the time event actually completed in the firmware
* (which is handled in iwl_mvm_te_handle_notif).
*/
- if (test_and_clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
+ if (test_and_clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) {
queues |= BIT(IWL_MVM_OFFCHANNEL_QUEUE);
- if (test_and_clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status))
+ iwl_mvm_unref(mvm, IWL_MVM_REF_ROC);
+ }
+ if (test_and_clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) {
queues |= BIT(mvm->aux_queue);
-
- iwl_mvm_unref(mvm, IWL_MVM_REF_ROC);
+ iwl_mvm_unref(mvm, IWL_MVM_REF_ROC_AUX);
+ }
synchronize_net();
@@ -393,6 +395,7 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
} else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
te_data->running = true;
+ iwl_mvm_ref(mvm, IWL_MVM_REF_ROC_AUX);
ieee80211_ready_on_channel(mvm->hw); /* Start TE */
} else {
IWL_DEBUG_TE(mvm,
@@ -794,13 +797,12 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
{
- struct iwl_mvm_vif *mvmvif;
+ struct iwl_mvm_vif *mvmvif = NULL;
struct iwl_mvm_time_event_data *te_data;
bool is_p2p = false;
lockdep_assert_held(&mvm->mutex);
- mvmvif = NULL;
spin_lock_bh(&mvm->time_event_lock);
/*
@@ -818,17 +820,14 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
}
}
- /*
- * Iterate over the list of aux roc time events and find the time
- * event that is associated with a BSS interface.
- * This assumes that a BSS interface can have only a single time
- * event at any given time and this time event corresponds to a ROC
- * request
+ /* There can only be at most one AUX ROC time event, we just use the
+ * list to simplify/unify code. Remove it if it exists.
*/
- list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) {
+ te_data = list_first_entry_or_null(&mvm->aux_roc_te_list,
+ struct iwl_mvm_time_event_data,
+ list);
+ if (te_data)
mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
- goto remove_te;
- }
remove_te:
spin_unlock_bh(&mvm->time_event_lock);
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c
index ba615ad2176c..80d07db6e7e8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tt.c
@@ -70,7 +70,7 @@
static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
{
struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
- u32 duration = mvm->thermal_throttle.params->ct_kill_duration;
+ u32 duration = tt->params.ct_kill_duration;
if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
return;
@@ -223,7 +223,7 @@ static void check_exit_ctkill(struct work_struct *work)
tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work);
mvm = container_of(tt, struct iwl_mvm, thermal_throttle);
- duration = tt->params->ct_kill_duration;
+ duration = tt->params.ct_kill_duration;
mutex_lock(&mvm->mutex);
@@ -247,7 +247,7 @@ static void check_exit_ctkill(struct work_struct *work)
IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
- if (temp <= tt->params->ct_kill_exit) {
+ if (temp <= tt->params.ct_kill_exit) {
mutex_unlock(&mvm->mutex);
iwl_mvm_exit_ctkill(mvm);
return;
@@ -325,7 +325,7 @@ void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
{
- const struct iwl_tt_params *params = mvm->thermal_throttle.params;
+ struct iwl_tt_params *params = &mvm->thermal_throttle.params;
struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
s32 temperature = mvm->temperature;
bool throttle_enable = false;
@@ -340,7 +340,7 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
}
if (params->support_ct_kill &&
- temperature <= tt->params->ct_kill_exit) {
+ temperature <= params->ct_kill_exit) {
iwl_mvm_exit_ctkill(mvm);
return;
}
@@ -400,7 +400,7 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
}
}
-static const struct iwl_tt_params iwl7000_tt_params = {
+static const struct iwl_tt_params iwl_mvm_default_tt_params = {
.ct_kill_entry = 118,
.ct_kill_exit = 96,
.ct_kill_duration = 5,
@@ -422,38 +422,16 @@ static const struct iwl_tt_params iwl7000_tt_params = {
.support_tx_backoff = true,
};
-static const struct iwl_tt_params iwl7000_high_temp_tt_params = {
- .ct_kill_entry = 118,
- .ct_kill_exit = 96,
- .ct_kill_duration = 5,
- .dynamic_smps_entry = 114,
- .dynamic_smps_exit = 110,
- .tx_protection_entry = 114,
- .tx_protection_exit = 108,
- .tx_backoff = {
- {.temperature = 112, .backoff = 300},
- {.temperature = 113, .backoff = 800},
- {.temperature = 114, .backoff = 1500},
- {.temperature = 115, .backoff = 3000},
- {.temperature = 116, .backoff = 5000},
- {.temperature = 117, .backoff = 10000},
- },
- .support_ct_kill = true,
- .support_dynamic_smps = true,
- .support_tx_protection = true,
- .support_tx_backoff = true,
-};
-
void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff)
{
struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n");
- if (mvm->cfg->high_temp)
- tt->params = &iwl7000_high_temp_tt_params;
+ if (mvm->cfg->thermal_params)
+ tt->params = *mvm->cfg->thermal_params;
else
- tt->params = &iwl7000_tt_params;
+ tt->params = iwl_mvm_default_tt_params;
tt->throttle = false;
tt->dynamic_smps = false;
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index ef32e177f662..7ba7a118ff5c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,6 +70,30 @@
#include "mvm.h"
#include "sta.h"
+static void
+iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr,
+ u16 tid, u16 ssn)
+{
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct iwl_fw_dbg_trigger_ba *ba_trig;
+
+ if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
+ return;
+
+ trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
+ ba_trig = (void *)trig->data;
+
+ if (!iwl_fw_dbg_trigger_check_stop(mvm, NULL, trig))
+ return;
+
+ if (!(le16_to_cpu(ba_trig->tx_bar) & BIT(tid)))
+ return;
+
+ iwl_mvm_fw_dbg_collect_trig(mvm, trig,
+ "BAR sent to %pM, tid %d, ssn %d",
+ addr, tid, ssn);
+}
+
/*
* Sets most of the Tx cmd's fields
*/
@@ -101,12 +125,15 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
} else if (ieee80211_is_back_req(fc)) {
struct ieee80211_bar *bar = (void *)skb->data;
u16 control = le16_to_cpu(bar->control);
+ u16 ssn = le16_to_cpu(bar->start_seq_num);
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);
+ iwl_mvm_bar_check_trigger(mvm, bar->ra, tx_cmd->tid_tspec,
+ ssn);
} else {
tx_cmd->tid_tspec = IWL_TID_NON_QOS;
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
@@ -144,8 +171,8 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
!is_multicast_ether_addr(ieee80211_get_DA(hdr)))
tx_flags |= TX_CMD_FLG_PROT_REQUIRE;
- if ((mvm->fw->ucode_capa.capa[0] &
- IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT) &&
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT) &&
ieee80211_action_contains_tpc(skb))
tx_flags |= TX_CMD_FLG_WRITE_TX_POWER;
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index bc55a8b82db6..03f8e06dded7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -584,7 +584,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
struct iwl_error_event_table table;
u32 base;
- if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_NEW_VERSION)) {
+ if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_NEW_VERSION)) {
iwl_mvm_dump_nic_error_log_old(mvm);
return;
}
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
index b18569734922..2ed1e4d2774d 100644
--- a/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * 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
@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -629,7 +629,18 @@ static int iwl_pci_resume(struct device *device)
if (!trans->op_mode)
return 0;
- iwl_enable_rfkill_int(trans);
+ /*
+ * On suspend, ict is disabled, and the interrupt mask
+ * gets cleared. Reconfigure them both in case of d0i3
+ * image. Otherwise, only enable rfkill interrupt (in
+ * order to keep track of the rfkill status)
+ */
+ if (trans->wowlan_d0i3) {
+ iwl_pcie_reset_ict(trans);
+ iwl_enable_interrupts(trans);
+ } else {
+ iwl_enable_rfkill_int(trans);
+ }
hw_rfkill = iwl_is_rfkill_set(trans);
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index 01996c9d98a7..31f72a61cc3f 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -1,7 +1,7 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2003 - 2015 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -44,6 +44,15 @@
#include "iwl-io.h"
#include "iwl-op-mode.h"
+/*
+ * RX related structures and functions
+ */
+#define RX_NUM_QUEUES 1
+#define RX_POST_REQ_ALLOC 2
+#define RX_CLAIM_REQ_ALLOC 8
+#define RX_POOL_SIZE ((RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC) * RX_NUM_QUEUES)
+#define RX_LOW_WATERMARK 8
+
struct iwl_host_cmd;
/*This file includes the declaration that are internal to the
@@ -77,29 +86,29 @@ struct isr_statistics {
* struct iwl_rxq - Rx queue
* @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
* @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
- * @pool:
- * @queue:
* @read: Shared index to newest available Rx buffer
* @write: Shared index to oldest written Rx packet
* @free_count: Number of pre-allocated buffers in rx_free
+ * @used_count: Number of RBDs handled to allocator to use for allocation
* @write_actual:
- * @rx_free: list of free SKBs for use
- * @rx_used: List of Rx buffers with no SKB
+ * @rx_free: list of RBDs with allocated RB ready for use
+ * @rx_used: list of RBDs with no RB attached
* @need_update: flag to indicate we need to update read/write index
* @rb_stts: driver's pointer to receive buffer status
* @rb_stts_dma: bus address of receive buffer status
* @lock:
+ * @pool: initial pool of iwl_rx_mem_buffer for the queue
+ * @queue: actual rx queue
*
* NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
*/
struct iwl_rxq {
__le32 *bd;
dma_addr_t bd_dma;
- struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
- struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
u32 read;
u32 write;
u32 free_count;
+ u32 used_count;
u32 write_actual;
struct list_head rx_free;
struct list_head rx_used;
@@ -107,6 +116,32 @@ struct iwl_rxq {
struct iwl_rb_status *rb_stts;
dma_addr_t rb_stts_dma;
spinlock_t lock;
+ struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE];
+ struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+};
+
+/**
+ * struct iwl_rb_allocator - Rx allocator
+ * @pool: initial pool of allocator
+ * @req_pending: number of requests the allcator had not processed yet
+ * @req_ready: number of requests honored and ready for claiming
+ * @rbd_allocated: RBDs with pages allocated and ready to be handled to
+ * the queue. This is a list of &struct iwl_rx_mem_buffer
+ * @rbd_empty: RBDs with no page attached for allocator use. This is a list
+ * of &struct iwl_rx_mem_buffer
+ * @lock: protects the rbd_allocated and rbd_empty lists
+ * @alloc_wq: work queue for background calls
+ * @rx_alloc: work struct for background calls
+ */
+struct iwl_rb_allocator {
+ struct iwl_rx_mem_buffer pool[RX_POOL_SIZE];
+ atomic_t req_pending;
+ atomic_t req_ready;
+ struct list_head rbd_allocated;
+ struct list_head rbd_empty;
+ spinlock_t lock;
+ struct workqueue_struct *alloc_wq;
+ struct work_struct rx_alloc;
};
struct iwl_dma_ptr {
@@ -250,7 +285,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
/**
* struct iwl_trans_pcie - PCIe transport specific data
* @rxq: all the RX queue data
- * @rx_replenish: work that will be called when buffers need to be allocated
+ * @rba: allocator for RX replenishing
* @drv - pointer to iwl_drv
* @trans: pointer to the generic transport area
* @scd_base_addr: scheduler sram base address in SRAM
@@ -273,7 +308,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
*/
struct iwl_trans_pcie {
struct iwl_rxq rxq;
- struct work_struct rx_replenish;
+ struct iwl_rb_allocator rba;
struct iwl_trans *trans;
struct iwl_drv *drv;
@@ -320,7 +355,7 @@ struct iwl_trans_pcie {
/*protect hw register */
spinlock_t reg_lock;
- bool cmd_in_flight;
+ bool cmd_hold_nic_awake;
bool ref_cmd_in_flight;
/* protect ref counter */
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index 7ff69c642103..a3fbaa0ef5e0 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -1,7 +1,7 @@
/******************************************************************************
*
* Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -74,16 +74,29 @@
* resets the Rx queue buffers with new memory.
*
* The management in the driver is as follows:
- * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When
- * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
- * to replenish the iwl->rxq->rx_free.
- * + In iwl_pcie_rx_replenish (scheduled) if 'processed' != 'read' then the
- * iwl->rxq is replenished and the READ INDEX is updated (updating the
- * 'processed' and 'read' driver indexes as well)
+ * + A list of pre-allocated RBDs is stored in iwl->rxq->rx_free.
+ * When the interrupt handler is called, the request is processed.
+ * The page is either stolen - transferred to the upper layer
+ * or reused - added immediately to the iwl->rxq->rx_free list.
+ * + When the page is stolen - the driver updates the matching queue's used
+ * count, detaches the RBD and transfers it to the queue used list.
+ * When there are two used RBDs - they are transferred to the allocator empty
+ * list. Work is then scheduled for the allocator to start allocating
+ * eight buffers.
+ * When there are another 6 used RBDs - they are transferred to the allocator
+ * empty list and the driver tries to claim the pre-allocated buffers and
+ * add them to iwl->rxq->rx_free. If it fails - it continues to claim them
+ * until ready.
+ * When there are 8+ buffers in the free list - either from allocation or from
+ * 8 reused unstolen pages - restock is called to update the FW and indexes.
+ * + In order to make sure the allocator always has RBDs to use for allocation
+ * the allocator has initial pool in the size of num_queues*(8-2) - the
+ * maximum missing RBDs per allocation request (request posted with 2
+ * empty RBDs, there is no guarantee when the other 6 RBDs are supplied).
+ * The queues supplies the recycle of the rest of the RBDs.
* + A received packet is processed and handed to the kernel network stack,
* detached from the iwl->rxq. The driver 'processed' index is updated.
- * + The Host/Firmware iwl->rxq is replenished at irq thread time from the
- * rx_free list. If there are no allocated buffers in iwl->rxq->rx_free,
+ * + If there are no allocated buffers in iwl->rxq->rx_free,
* the READ INDEX is not incremented and iwl->status(RX_STALLED) is set.
* If there were enough free buffers and RX_STALLED is set it is cleared.
*
@@ -92,18 +105,32 @@
*
* iwl_rxq_alloc() Allocates rx_free
* iwl_pcie_rx_replenish() Replenishes rx_free list from rx_used, and calls
- * iwl_pcie_rxq_restock
+ * iwl_pcie_rxq_restock.
+ * Used only during initialization.
* iwl_pcie_rxq_restock() Moves available buffers from rx_free into Rx
* queue, updates firmware pointers, and updates
- * the WRITE index. If insufficient rx_free buffers
- * are available, schedules iwl_pcie_rx_replenish
+ * the WRITE index.
+ * iwl_pcie_rx_allocator() Background work for allocating pages.
*
* -- enable interrupts --
* ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the
* READ INDEX, detaching the SKB from the pool.
* Moves the packet buffer from queue to rx_used.
+ * Posts and claims requests to the allocator.
* Calls iwl_pcie_rxq_restock to refill any empty
* slots.
+ *
+ * RBD life-cycle:
+ *
+ * Init:
+ * rxq.pool -> rxq.rx_used -> rxq.rx_free -> rxq.queue
+ *
+ * Regular Receive interrupt:
+ * Page Stolen:
+ * rxq.queue -> rxq.rx_used -> allocator.rbd_empty ->
+ * allocator.rbd_allocated -> rxq.rx_free -> rxq.queue
+ * Page not Stolen:
+ * rxq.queue -> rxq.rx_free -> rxq.queue
* ...
*
*/
@@ -240,10 +267,6 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
rxq->free_count--;
}
spin_unlock(&rxq->lock);
- /* If the pre-allocated buffer pool is dropping low, schedule to
- * refill it */
- if (rxq->free_count <= RX_LOW_WATERMARK)
- schedule_work(&trans_pcie->rx_replenish);
/* If we've added more space for the firmware to place data, tell it.
* Increment device's write pointer in multiples of 8. */
@@ -255,6 +278,44 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
}
/*
+ * iwl_pcie_rx_alloc_page - allocates and returns a page.
+ *
+ */
+static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rxq *rxq = &trans_pcie->rxq;
+ struct page *page;
+ gfp_t gfp_mask = GFP_KERNEL;
+
+ if (rxq->free_count > RX_LOW_WATERMARK)
+ gfp_mask |= __GFP_NOWARN;
+
+ if (trans_pcie->rx_page_order > 0)
+ gfp_mask |= __GFP_COMP;
+
+ /* Alloc a new receive buffer */
+ page = alloc_pages(gfp_mask, trans_pcie->rx_page_order);
+ if (!page) {
+ if (net_ratelimit())
+ IWL_DEBUG_INFO(trans, "alloc_pages failed, order: %d\n",
+ trans_pcie->rx_page_order);
+ /* Issue an error if the hardware has consumed more than half
+ * of its free buffer list and we don't have enough
+ * pre-allocated buffers.
+` */
+ if (rxq->free_count <= RX_LOW_WATERMARK &&
+ iwl_rxq_space(rxq) > (RX_QUEUE_SIZE / 2) &&
+ net_ratelimit())
+ IWL_CRIT(trans,
+ "Failed to alloc_pages with GFP_KERNEL. Only %u free buffers remaining.\n",
+ rxq->free_count);
+ return NULL;
+ }
+ return page;
+}
+
+/*
* iwl_pcie_rxq_alloc_rbs - allocate a page for each used RBD
*
* A used RBD is an Rx buffer that has been given to the stack. To use it again
@@ -263,13 +324,12 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
* iwl_pcie_rxq_restock. The latter function will update the HW to use the newly
* allocated buffers.
*/
-static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
+static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *rxq = &trans_pcie->rxq;
struct iwl_rx_mem_buffer *rxb;
struct page *page;
- gfp_t gfp_mask = priority;
while (1) {
spin_lock(&rxq->lock);
@@ -279,32 +339,10 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
}
spin_unlock(&rxq->lock);
- if (rxq->free_count > RX_LOW_WATERMARK)
- gfp_mask |= __GFP_NOWARN;
-
- if (trans_pcie->rx_page_order > 0)
- gfp_mask |= __GFP_COMP;
-
/* Alloc a new receive buffer */
- page = alloc_pages(gfp_mask, trans_pcie->rx_page_order);
- if (!page) {
- if (net_ratelimit())
- IWL_DEBUG_INFO(trans, "alloc_pages failed, "
- "order: %d\n",
- trans_pcie->rx_page_order);
-
- if ((rxq->free_count <= RX_LOW_WATERMARK) &&
- net_ratelimit())
- IWL_CRIT(trans, "Failed to alloc_pages with %s."
- "Only %u free buffers remaining.\n",
- priority == GFP_ATOMIC ?
- "GFP_ATOMIC" : "GFP_KERNEL",
- rxq->free_count);
- /* We don't reschedule replenish work here -- we will
- * call the restock method and if it still needs
- * more buffers it will schedule replenish */
+ page = iwl_pcie_rx_alloc_page(trans);
+ if (!page)
return;
- }
spin_lock(&rxq->lock);
@@ -355,7 +393,7 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
lockdep_assert_held(&rxq->lock);
- for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+ for (i = 0; i < RX_QUEUE_SIZE; i++) {
if (!rxq->pool[i].page)
continue;
dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
@@ -372,32 +410,144 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
* When moving to rx_free an page is allocated for the slot.
*
* Also restock the Rx queue via iwl_pcie_rxq_restock.
- * This is called as a scheduled work item (except for during initialization)
+ * This is called only during initialization
*/
-static void iwl_pcie_rx_replenish(struct iwl_trans *trans, gfp_t gfp)
+static void iwl_pcie_rx_replenish(struct iwl_trans *trans)
{
- iwl_pcie_rxq_alloc_rbs(trans, gfp);
+ iwl_pcie_rxq_alloc_rbs(trans);
iwl_pcie_rxq_restock(trans);
}
-static void iwl_pcie_rx_replenish_work(struct work_struct *data)
+/*
+ * iwl_pcie_rx_allocator - Allocates pages in the background for RX queues
+ *
+ * Allocates for each received request 8 pages
+ * Called as a scheduled work item.
+ */
+static void iwl_pcie_rx_allocator(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
+
+ while (atomic_read(&rba->req_pending)) {
+ int i;
+ struct list_head local_empty;
+ struct list_head local_allocated;
+
+ INIT_LIST_HEAD(&local_allocated);
+ spin_lock(&rba->lock);
+ /* swap out the entire rba->rbd_empty to a local list */
+ list_replace_init(&rba->rbd_empty, &local_empty);
+ spin_unlock(&rba->lock);
+
+ for (i = 0; i < RX_CLAIM_REQ_ALLOC;) {
+ struct iwl_rx_mem_buffer *rxb;
+ struct page *page;
+
+ /* List should never be empty - each reused RBD is
+ * returned to the list, and initial pool covers any
+ * possible gap between the time the page is allocated
+ * to the time the RBD is added.
+ */
+ BUG_ON(list_empty(&local_empty));
+ /* Get the first rxb from the rbd list */
+ rxb = list_first_entry(&local_empty,
+ struct iwl_rx_mem_buffer, list);
+ BUG_ON(rxb->page);
+
+ /* Alloc a new receive buffer */
+ page = iwl_pcie_rx_alloc_page(trans);
+ if (!page)
+ continue;
+ rxb->page = page;
+
+ /* Get physical address of the RB */
+ rxb->page_dma = dma_map_page(trans->dev, page, 0,
+ PAGE_SIZE << trans_pcie->rx_page_order,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(trans->dev, rxb->page_dma)) {
+ rxb->page = NULL;
+ __free_pages(page, trans_pcie->rx_page_order);
+ continue;
+ }
+ /* dma address must be no more than 36 bits */
+ BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
+ /* and also 256 byte aligned! */
+ BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
+
+ /* move the allocated entry to the out list */
+ list_move(&rxb->list, &local_allocated);
+ i++;
+ }
+
+ spin_lock(&rba->lock);
+ /* add the allocated rbds to the allocator allocated list */
+ list_splice_tail(&local_allocated, &rba->rbd_allocated);
+ /* add the unused rbds back to the allocator empty list */
+ list_splice_tail(&local_empty, &rba->rbd_empty);
+ spin_unlock(&rba->lock);
+
+ atomic_dec(&rba->req_pending);
+ atomic_inc(&rba->req_ready);
+ }
+}
+
+/*
+ * iwl_pcie_rx_allocator_get - Returns the pre-allocated pages
+.*
+.* Called by queue when the queue posted allocation request and
+ * has freed 8 RBDs in order to restock itself.
+ */
+static int iwl_pcie_rx_allocator_get(struct iwl_trans *trans,
+ struct iwl_rx_mem_buffer
+ *out[RX_CLAIM_REQ_ALLOC])
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
+ int i;
+
+ if (atomic_dec_return(&rba->req_ready) < 0) {
+ atomic_inc(&rba->req_ready);
+ IWL_DEBUG_RX(trans,
+ "Allocation request not ready, pending requests = %d\n",
+ atomic_read(&rba->req_pending));
+ return -ENOMEM;
+ }
+
+ spin_lock(&rba->lock);
+ for (i = 0; i < RX_CLAIM_REQ_ALLOC; i++) {
+ /* Get next free Rx buffer, remove it from free list */
+ out[i] = list_first_entry(&rba->rbd_allocated,
+ struct iwl_rx_mem_buffer, list);
+ list_del(&out[i]->list);
+ }
+ spin_unlock(&rba->lock);
+
+ return 0;
+}
+
+static void iwl_pcie_rx_allocator_work(struct work_struct *data)
{
+ struct iwl_rb_allocator *rba_p =
+ container_of(data, struct iwl_rb_allocator, rx_alloc);
struct iwl_trans_pcie *trans_pcie =
- container_of(data, struct iwl_trans_pcie, rx_replenish);
+ container_of(rba_p, struct iwl_trans_pcie, rba);
- iwl_pcie_rx_replenish(trans_pcie->trans, GFP_KERNEL);
+ iwl_pcie_rx_allocator(trans_pcie->trans);
}
static int iwl_pcie_rx_alloc(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *rxq = &trans_pcie->rxq;
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
struct device *dev = trans->dev;
memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
spin_lock_init(&rxq->lock);
+ spin_lock_init(&rba->lock);
if (WARN_ON(rxq->bd || rxq->rb_stts))
return -EINVAL;
@@ -487,15 +637,49 @@ static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq)
INIT_LIST_HEAD(&rxq->rx_free);
INIT_LIST_HEAD(&rxq->rx_used);
rxq->free_count = 0;
+ rxq->used_count = 0;
- for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+ for (i = 0; i < RX_QUEUE_SIZE; i++)
list_add(&rxq->pool[i].list, &rxq->rx_used);
}
+static void iwl_pcie_rx_init_rba(struct iwl_rb_allocator *rba)
+{
+ int i;
+
+ lockdep_assert_held(&rba->lock);
+
+ INIT_LIST_HEAD(&rba->rbd_allocated);
+ INIT_LIST_HEAD(&rba->rbd_empty);
+
+ for (i = 0; i < RX_POOL_SIZE; i++)
+ list_add(&rba->pool[i].list, &rba->rbd_empty);
+}
+
+static void iwl_pcie_rx_free_rba(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
+ int i;
+
+ lockdep_assert_held(&rba->lock);
+
+ for (i = 0; i < RX_POOL_SIZE; i++) {
+ if (!rba->pool[i].page)
+ continue;
+ dma_unmap_page(trans->dev, rba->pool[i].page_dma,
+ PAGE_SIZE << trans_pcie->rx_page_order,
+ DMA_FROM_DEVICE);
+ __free_pages(rba->pool[i].page, trans_pcie->rx_page_order);
+ rba->pool[i].page = NULL;
+ }
+}
+
int iwl_pcie_rx_init(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *rxq = &trans_pcie->rxq;
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
int i, err;
if (!rxq->bd) {
@@ -503,11 +687,21 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
if (err)
return err;
}
+ if (!rba->alloc_wq)
+ rba->alloc_wq = alloc_workqueue("rb_allocator",
+ WQ_HIGHPRI | WQ_UNBOUND, 1);
+ INIT_WORK(&rba->rx_alloc, iwl_pcie_rx_allocator_work);
+
+ spin_lock(&rba->lock);
+ atomic_set(&rba->req_pending, 0);
+ atomic_set(&rba->req_ready, 0);
+ /* free all first - we might be reconfigured for a different size */
+ iwl_pcie_rx_free_rba(trans);
+ iwl_pcie_rx_init_rba(rba);
+ spin_unlock(&rba->lock);
spin_lock(&rxq->lock);
- INIT_WORK(&trans_pcie->rx_replenish, iwl_pcie_rx_replenish_work);
-
/* free all first - we might be reconfigured for a different size */
iwl_pcie_rxq_free_rbs(trans);
iwl_pcie_rx_init_rxb_lists(rxq);
@@ -522,7 +716,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
spin_unlock(&rxq->lock);
- iwl_pcie_rx_replenish(trans, GFP_KERNEL);
+ iwl_pcie_rx_replenish(trans);
iwl_pcie_rx_hw_init(trans, rxq);
@@ -537,6 +731,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *rxq = &trans_pcie->rxq;
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
/*if rxq->bd is NULL, it means that nothing has been allocated,
* exit now */
@@ -545,7 +740,15 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
return;
}
- cancel_work_sync(&trans_pcie->rx_replenish);
+ cancel_work_sync(&rba->rx_alloc);
+ if (rba->alloc_wq) {
+ destroy_workqueue(rba->alloc_wq);
+ rba->alloc_wq = NULL;
+ }
+
+ spin_lock(&rba->lock);
+ iwl_pcie_rx_free_rba(trans);
+ spin_unlock(&rba->lock);
spin_lock(&rxq->lock);
iwl_pcie_rxq_free_rbs(trans);
@@ -566,6 +769,43 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
rxq->rb_stts = NULL;
}
+/*
+ * iwl_pcie_rx_reuse_rbd - Recycle used RBDs
+ *
+ * Called when a RBD can be reused. The RBD is transferred to the allocator.
+ * When there are 2 empty RBDs - a request for allocation is posted
+ */
+static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans,
+ struct iwl_rx_mem_buffer *rxb,
+ struct iwl_rxq *rxq)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
+
+ /* Count the used RBDs */
+ rxq->used_count++;
+
+ /* Move the RBD to the used list, will be moved to allocator in batches
+ * before claiming or posting a request*/
+ list_add_tail(&rxb->list, &rxq->rx_used);
+
+ /* If we have RX_POST_REQ_ALLOC new released rx buffers -
+ * issue a request for allocator. Modulo RX_CLAIM_REQ_ALLOC is
+ * used for the case we failed to claim RX_CLAIM_REQ_ALLOC,
+ * after but we still need to post another request.
+ */
+ if ((rxq->used_count % RX_CLAIM_REQ_ALLOC) == RX_POST_REQ_ALLOC) {
+ /* Move the 2 RBDs to the allocator ownership.
+ Allocator has another 6 from pool for the request completion*/
+ spin_lock(&rba->lock);
+ list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
+ spin_unlock(&rba->lock);
+
+ atomic_inc(&rba->req_pending);
+ queue_work(rba->alloc_wq, &rba->rx_alloc);
+ }
+}
+
static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
struct iwl_rx_mem_buffer *rxb)
{
@@ -688,13 +928,13 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
*/
__free_pages(rxb->page, trans_pcie->rx_page_order);
rxb->page = NULL;
- list_add_tail(&rxb->list, &rxq->rx_used);
+ iwl_pcie_rx_reuse_rbd(trans, rxb, rxq);
} else {
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
}
} else
- list_add_tail(&rxb->list, &rxq->rx_used);
+ iwl_pcie_rx_reuse_rbd(trans, rxb, rxq);
}
/*
@@ -704,10 +944,7 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *rxq = &trans_pcie->rxq;
- u32 r, i;
- u8 fill_rx = 0;
- u32 count = 8;
- int total_empty;
+ u32 r, i, j;
restart:
spin_lock(&rxq->lock);
@@ -720,14 +957,6 @@ restart:
if (i == r)
IWL_DEBUG_RX(trans, "HW = SW = %d\n", r);
- /* calculate total frames need to be restock after handling RX */
- total_empty = r - rxq->write_actual;
- if (total_empty < 0)
- total_empty += RX_QUEUE_SIZE;
-
- if (total_empty > (RX_QUEUE_SIZE / 2))
- fill_rx = 1;
-
while (i != r) {
struct iwl_rx_mem_buffer *rxb;
@@ -739,29 +968,48 @@ restart:
iwl_pcie_rx_handle_rb(trans, rxb);
i = (i + 1) & RX_QUEUE_MASK;
- /* If there are a lot of unused frames,
- * restock the Rx queue so ucode wont assert. */
- if (fill_rx) {
- count++;
- if (count >= 8) {
- rxq->read = i;
- spin_unlock(&rxq->lock);
- iwl_pcie_rx_replenish(trans, GFP_ATOMIC);
- count = 0;
- goto restart;
+
+ /* If we have RX_CLAIM_REQ_ALLOC released rx buffers -
+ * try to claim the pre-allocated buffers from the allocator */
+ if (rxq->used_count >= RX_CLAIM_REQ_ALLOC) {
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
+ struct iwl_rx_mem_buffer *out[RX_CLAIM_REQ_ALLOC];
+
+ /* Add the remaining 6 empty RBDs for allocator use */
+ spin_lock(&rba->lock);
+ list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
+ spin_unlock(&rba->lock);
+
+ /* If not ready - continue, will try to reclaim later.
+ * No need to reschedule work - allocator exits only on
+ * success */
+ if (!iwl_pcie_rx_allocator_get(trans, out)) {
+ /* If success - then RX_CLAIM_REQ_ALLOC
+ * buffers were retrieved and should be added
+ * to free list */
+ rxq->used_count -= RX_CLAIM_REQ_ALLOC;
+ for (j = 0; j < RX_CLAIM_REQ_ALLOC; j++) {
+ list_add_tail(&out[j]->list,
+ &rxq->rx_free);
+ rxq->free_count++;
+ }
}
}
+ /* handle restock for two cases:
+ * - we just pulled buffers from the allocator
+ * - we have 8+ unstolen pages accumulated */
+ if (rxq->free_count >= RX_CLAIM_REQ_ALLOC) {
+ rxq->read = i;
+ spin_unlock(&rxq->lock);
+ iwl_pcie_rxq_restock(trans);
+ goto restart;
+ }
}
/* Backtrack one entry */
rxq->read = i;
spin_unlock(&rxq->lock);
- if (fill_rx)
- iwl_pcie_rx_replenish(trans, GFP_ATOMIC);
- else
- iwl_pcie_rxq_restock(trans);
-
if (trans_pcie->napi.poll)
napi_gro_flush(&trans_pcie->napi, false);
}
@@ -775,6 +1023,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
/* W/A for WiFi/WiMAX coex and WiMAX own the RF */
if (trans->cfg->internal_wimax_coex &&
+ !trans->cfg->apmg_not_supported &&
(!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) &
APMS_CLK_VAL_MRB_FUNC_MODE) ||
(iwl_read_prph(trans, APMG_PS_CTRL_REG) &
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 47bbf573fdc8..43ae658af6ec 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -101,14 +101,26 @@ static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans)
trans_pcie->fw_mon_size = 0;
}
-static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
+static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct page *page = NULL;
dma_addr_t phys;
- u32 size;
+ u32 size = 0;
u8 power;
+ if (!max_power) {
+ /* default max_power is maximum */
+ max_power = 26;
+ } else {
+ max_power += 11;
+ }
+
+ if (WARN(max_power > 26,
+ "External buffer size for monitor is too big %d, check the FW TLV\n",
+ max_power))
+ return;
+
if (trans_pcie->fw_mon_page) {
dma_sync_single_for_device(trans->dev, trans_pcie->fw_mon_phys,
trans_pcie->fw_mon_size,
@@ -117,7 +129,7 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
}
phys = 0;
- for (power = 26; power >= 11; power--) {
+ for (power = max_power; power >= 11; power--) {
int order;
size = BIT(power);
@@ -143,6 +155,12 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
if (WARN_ON_ONCE(!page))
return;
+ if (power != max_power)
+ IWL_ERR(trans,
+ "Sorry - debug buffer is only %luK while you requested %luK\n",
+ (unsigned long)BIT(power - 10),
+ (unsigned long)BIT(max_power - 10));
+
trans_pcie->fw_mon_page = page;
trans_pcie->fw_mon_phys = phys;
trans_pcie->fw_mon_size = size;
@@ -164,6 +182,9 @@ static void iwl_trans_pcie_write_shr(struct iwl_trans *trans, u32 reg, u32 val)
static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
{
+ if (!trans->cfg->apmg_not_supported)
+ return;
+
if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold))
iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
@@ -297,7 +318,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
* bits do not disable clocks. This preserves any hardware
* bits already set by default in "CLK_CTRL_REG" after reset.
*/
- if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ if (!trans->cfg->apmg_not_supported) {
iwl_write_prph(trans, APMG_CLK_EN_REG,
APMG_CLK_VAL_DMA_CLK_RQT);
udelay(20);
@@ -497,8 +518,7 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans)
spin_unlock(&trans_pcie->irq_lock);
- if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
- iwl_pcie_set_pwr(trans, false);
+ iwl_pcie_set_pwr(trans, false);
iwl_op_mode_nic_config(trans->op_mode);
@@ -834,7 +854,7 @@ static void iwl_pcie_apply_destination(struct iwl_trans *trans)
get_fw_dbg_mode_string(dest->monitor_mode));
if (dest->monitor_mode == EXTERNAL_MODE)
- iwl_pcie_alloc_fw_monitor(trans);
+ iwl_pcie_alloc_fw_monitor(trans, dest->size_power);
else
IWL_WARN(trans, "PCI should have external buffer debug\n");
@@ -908,7 +928,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
/* supported for 7000 only for the moment */
if (iwlwifi_mod_params.fw_monitor &&
trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
- iwl_pcie_alloc_fw_monitor(trans);
+ iwl_pcie_alloc_fw_monitor(trans, 0);
if (trans_pcie->fw_mon_size) {
iwl_write_prph(trans, MON_BUFF_BASE_ADDR,
@@ -955,12 +975,8 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans,
return ret;
/* load to FW the binary sections of CPU2 */
- ret = iwl_pcie_load_cpu_sections_8000(trans, image, 2,
- &first_ucode_section);
- if (ret)
- return ret;
-
- return 0;
+ return iwl_pcie_load_cpu_sections_8000(trans, image, 2,
+ &first_ucode_section);
}
static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
@@ -1049,9 +1065,11 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
iwl_pcie_rx_stop(trans);
/* Power-down device's busmaster DMA clocks */
- iwl_write_prph(trans, APMG_CLK_DIS_REG,
- APMG_CLK_VAL_DMA_CLK_RQT);
- udelay(5);
+ if (!trans->cfg->apmg_not_supported) {
+ iwl_write_prph(trans, APMG_CLK_DIS_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT);
+ udelay(5);
+ }
}
/* Make sure (redundant) we've released our request to stay awake */
@@ -1344,14 +1362,13 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
iounmap(trans_pcie->hw_base);
pci_release_regions(trans_pcie->pci_dev);
pci_disable_device(trans_pcie->pci_dev);
- kmem_cache_destroy(trans->dev_cmd_pool);
if (trans_pcie->napi.poll)
netif_napi_del(&trans_pcie->napi);
iwl_pcie_free_fw_monitor(trans);
- kfree(trans);
+ iwl_trans_free(trans);
}
static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)
@@ -1370,7 +1387,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
spin_lock_irqsave(&trans_pcie->reg_lock, *flags);
- if (trans_pcie->cmd_in_flight)
+ if (trans_pcie->cmd_hold_nic_awake)
goto out;
/* this bit wakes up the NIC */
@@ -1436,7 +1453,7 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans,
*/
__acquire(&trans_pcie->reg_lock);
- if (trans_pcie->cmd_in_flight)
+ if (trans_pcie->cmd_hold_nic_awake)
goto out;
__iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
@@ -2198,6 +2215,29 @@ static u32 iwl_trans_pcie_fh_regs_dump(struct iwl_trans *trans,
return sizeof(**data) + fh_regs_len;
}
+static u32
+iwl_trans_pci_dump_marbh_monitor(struct iwl_trans *trans,
+ struct iwl_fw_error_dump_fw_mon *fw_mon_data,
+ u32 monitor_len)
+{
+ u32 buf_size_in_dwords = (monitor_len >> 2);
+ u32 *buffer = (u32 *)fw_mon_data->data;
+ unsigned long flags;
+ u32 i;
+
+ if (!iwl_trans_grab_nic_access(trans, false, &flags))
+ return 0;
+
+ __iwl_write_prph(trans, MON_DMARB_RD_CTL_ADDR, 0x1);
+ for (i = 0; i < buf_size_in_dwords; i++)
+ buffer[i] = __iwl_read_prph(trans, MON_DMARB_RD_DATA_ADDR);
+ __iwl_write_prph(trans, MON_DMARB_RD_CTL_ADDR, 0x0);
+
+ iwl_trans_release_nic_access(trans, &flags);
+
+ return monitor_len;
+}
+
static
struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
{
@@ -2250,7 +2290,8 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
trans->dbg_dest_tlv->end_shift;
/* Make "end" point to the actual end */
- if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 ||
+ trans->dbg_dest_tlv->monitor_mode == MARBH_MODE)
end += (1 << trans->dbg_dest_tlv->end_shift);
monitor_len = end - base;
len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
@@ -2326,9 +2367,6 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
len += sizeof(*data) + sizeof(*fw_mon_data);
if (trans_pcie->fw_mon_page) {
- data->len = cpu_to_le32(trans_pcie->fw_mon_size +
- sizeof(*fw_mon_data));
-
/*
* The firmware is now asserted, it won't write anything
* to the buffer. CPU can take ownership to fetch the
@@ -2343,10 +2381,8 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
page_address(trans_pcie->fw_mon_page),
trans_pcie->fw_mon_size);
- len += trans_pcie->fw_mon_size;
- } else {
- /* If we are here then the buffer is internal */
-
+ monitor_len = trans_pcie->fw_mon_size;
+ } else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) {
/*
* Update pointers to reflect actual values after
* shifting
@@ -2355,10 +2391,18 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
trans->dbg_dest_tlv->base_shift;
iwl_trans_read_mem(trans, base, fw_mon_data->data,
monitor_len / sizeof(u32));
- data->len = cpu_to_le32(sizeof(*fw_mon_data) +
- monitor_len);
- len += monitor_len;
+ } else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) {
+ monitor_len =
+ iwl_trans_pci_dump_marbh_monitor(trans,
+ fw_mon_data,
+ monitor_len);
+ } else {
+ /* Didn't match anything - output no monitor data */
+ monitor_len = 0;
}
+
+ len += monitor_len;
+ data->len = cpu_to_le32(monitor_len + sizeof(*fw_mon_data));
}
dump_data->len = len;
@@ -2417,18 +2461,13 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
u16 pci_cmd;
int err;
- trans = kzalloc(sizeof(struct iwl_trans) +
- sizeof(struct iwl_trans_pcie), GFP_KERNEL);
- if (!trans) {
- err = -ENOMEM;
- goto out;
- }
+ trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie),
+ &pdev->dev, cfg, &trans_ops_pcie, 0);
+ if (!trans)
+ return ERR_PTR(-ENOMEM);
trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- trans->ops = &trans_ops_pcie;
- trans->cfg = cfg;
- trans_lockdep_init(trans);
trans_pcie->trans = trans;
spin_lock_init(&trans_pcie->irq_lock);
spin_lock_init(&trans_pcie->reg_lock);
@@ -2552,25 +2591,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
/* Initialize the wait queue for commands */
init_waitqueue_head(&trans_pcie->wait_command_queue);
- snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name),
- "iwl_cmd_pool:%s", dev_name(trans->dev));
-
- trans->dev_cmd_headroom = 0;
- trans->dev_cmd_pool =
- kmem_cache_create(trans->dev_cmd_pool_name,
- sizeof(struct iwl_device_cmd)
- + trans->dev_cmd_headroom,
- sizeof(void *),
- SLAB_HWCACHE_ALIGN,
- NULL);
-
- if (!trans->dev_cmd_pool) {
- err = -ENOMEM;
- goto out_pci_disable_msi;
- }
-
if (iwl_pcie_alloc_ict(trans))
- goto out_free_cmd_pool;
+ goto out_pci_disable_msi;
err = request_threaded_irq(pdev->irq, iwl_pcie_isr,
iwl_pcie_irq_handler,
@@ -2587,8 +2609,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
out_free_ict:
iwl_pcie_free_ict(trans);
-out_free_cmd_pool:
- kmem_cache_destroy(trans->dev_cmd_pool);
out_pci_disable_msi:
pci_disable_msi(pdev);
out_pci_release_regions:
@@ -2596,7 +2616,6 @@ out_pci_release_regions:
out_pci_disable_device:
pci_disable_device(pdev);
out_no_pci:
- kfree(trans);
-out:
+ iwl_trans_free(trans);
return ERR_PTR(err);
}
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 06952aadfd7b..2b86c2135de3 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -1039,22 +1039,16 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
iwl_trans_pcie_ref(trans);
}
- if (trans_pcie->cmd_in_flight)
- return 0;
-
- trans_pcie->cmd_in_flight = true;
-
/*
* wake up the NIC to make sure that the firmware will see the host
* command - we will let the NIC sleep once all the host commands
* returned. This needs to be done only on NICs that have
* apmg_wake_up_wa set.
*/
- if (trans->cfg->base_params->apmg_wake_up_wa) {
+ if (trans->cfg->base_params->apmg_wake_up_wa &&
+ !trans_pcie->cmd_hold_nic_awake) {
__iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
- udelay(2);
ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
@@ -1064,10 +1058,10 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
if (ret < 0) {
__iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- trans_pcie->cmd_in_flight = false;
IWL_ERR(trans, "Failed to wake NIC for hcmd\n");
return -EIO;
}
+ trans_pcie->cmd_hold_nic_awake = true;
}
return 0;
@@ -1085,15 +1079,14 @@ static int iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans)
iwl_trans_pcie_unref(trans);
}
- if (WARN_ON(!trans_pcie->cmd_in_flight))
- return 0;
-
- trans_pcie->cmd_in_flight = false;
+ if (trans->cfg->base_params->apmg_wake_up_wa) {
+ if (WARN_ON(!trans_pcie->cmd_hold_nic_awake))
+ return 0;
- if (trans->cfg->base_params->apmg_wake_up_wa)
+ trans_pcie->cmd_hold_nic_awake = false;
__iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ }
return 0;
}
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 1a4d558022d8..8317afd065b4 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -835,14 +835,13 @@ static int lbs_cfg_scan(struct wiphy *wiphy,
* Events
*/
-void lbs_send_disconnect_notification(struct lbs_private *priv)
+void lbs_send_disconnect_notification(struct lbs_private *priv,
+ bool locally_generated)
{
lbs_deb_enter(LBS_DEB_CFG80211);
- cfg80211_disconnected(priv->dev,
- 0,
- NULL, 0,
- GFP_KERNEL);
+ cfg80211_disconnected(priv->dev, 0, NULL, 0, locally_generated,
+ GFP_KERNEL);
lbs_deb_leave(LBS_DEB_CFG80211);
}
@@ -1458,7 +1457,7 @@ int lbs_disconnect(struct lbs_private *priv, u16 reason)
cfg80211_disconnected(priv->dev,
reason,
- NULL, 0,
+ NULL, 0, true,
GFP_KERNEL);
priv->connect_status = LBS_DISCONNECTED;
@@ -2031,7 +2030,7 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
/* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */
- lbs_mac_event_disconnected(priv);
+ lbs_mac_event_disconnected(priv, true);
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
return ret;
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index 10995f59fe34..acccc2922401 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -10,7 +10,8 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev);
int lbs_cfg_register(struct lbs_private *priv);
void lbs_cfg_free(struct lbs_private *priv);
-void lbs_send_disconnect_notification(struct lbs_private *priv);
+void lbs_send_disconnect_notification(struct lbs_private *priv,
+ bool locally_generated);
void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
void lbs_scan_done(struct lbs_private *priv);
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 4279e8ab95f2..0c5444b02c64 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -68,7 +68,8 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
/* From cmdresp.c */
-void lbs_mac_event_disconnected(struct lbs_private *priv);
+void lbs_mac_event_disconnected(struct lbs_private *priv,
+ bool locally_generated);
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 65f18f1e869c..e5442e8956f7 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -19,10 +19,13 @@
* reset link state etc.
*
* @priv: A pointer to struct lbs_private structure
+ * @locally_generated: indicates disconnect was requested locally
+ * (usually by userspace)
*
* returns: n/a
*/
-void lbs_mac_event_disconnected(struct lbs_private *priv)
+void lbs_mac_event_disconnected(struct lbs_private *priv,
+ bool locally_generated)
{
if (priv->connect_status != LBS_CONNECTED)
return;
@@ -36,7 +39,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
msleep_interruptible(1000);
if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
- lbs_send_disconnect_notification(priv);
+ lbs_send_disconnect_notification(priv, locally_generated);
/* report disconnect to upper layer */
netif_stop_queue(priv->dev);
@@ -229,17 +232,17 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
case MACREG_INT_CODE_DEAUTHENTICATED:
lbs_deb_cmd("EVENT: deauthenticated\n");
- lbs_mac_event_disconnected(priv);
+ lbs_mac_event_disconnected(priv, false);
break;
case MACREG_INT_CODE_DISASSOCIATED:
lbs_deb_cmd("EVENT: disassociated\n");
- lbs_mac_event_disconnected(priv);
+ lbs_mac_event_disconnected(priv, false);
break;
case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
lbs_deb_cmd("EVENT: link lost\n");
- lbs_mac_event_disconnected(priv);
+ lbs_mac_event_disconnected(priv, true);
break;
case MACREG_INT_CODE_PS_SLEEP:
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index ed02e4bf2c26..a47f0acc099a 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -439,7 +439,7 @@ static u64 lbtf_op_prepare_multicast(struct ieee80211_hw *hw,
return mc_count;
}
-#define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)
+#define SUPPORTED_FIF_FLAGS FIF_ALLMULTI
static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *new_flags,
@@ -458,10 +458,7 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
return;
}
- if (*new_flags & (FIF_PROMISC_IN_BSS))
- priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
- else
- priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
+ priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
if (*new_flags & (FIF_ALLMULTI) ||
multicast > MRVDRV_MAX_MULTICAST_LIST_SIZE) {
priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
@@ -637,7 +634,7 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev)
priv->tx_skb = NULL;
hw->queues = 1;
- hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
hw->extra_tx_headroom = sizeof(struct txpd);
memcpy(priv->channels, lbtf_channels, sizeof(lbtf_channels));
memcpy(priv->rates, lbtf_rates, sizeof(lbtf_rates));
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index d5c0a1af08b9..99e873dc8684 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1286,7 +1286,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
if (control->sta)
hwsim_check_sta_magic(control->sta);
- if (hw->flags & IEEE80211_HW_SUPPORTS_RC_TABLE)
+ if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE))
ieee80211_get_tx_rates(txi->control.vif, control->sta, skb,
txi->control.rates,
ARRAY_SIZE(txi->control.rates));
@@ -1395,7 +1395,7 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
{
u32 _pid = ACCESS_ONCE(wmediumd_portid);
- if (hw->flags & IEEE80211_HW_SUPPORTS_RC_TABLE) {
+ if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) {
struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
ieee80211_get_tx_rates(txi->control.vif, NULL, skb,
txi->control.rates,
@@ -1432,7 +1432,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
if (skb == NULL)
return;
info = IEEE80211_SKB_CB(skb);
- if (hw->flags & IEEE80211_HW_SUPPORTS_RC_TABLE)
+ if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE))
ieee80211_get_tx_rates(vif, NULL, skb,
info->control.rates,
ARRAY_SIZE(info->control.rates));
@@ -1554,8 +1554,6 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
wiphy_debug(hw->wiphy, "%s\n", __func__);
data->rx_filter = 0;
- if (*total_flags & FIF_PROMISC_IN_BSS)
- data->rx_filter |= FIF_PROMISC_IN_BSS;
if (*total_flags & FIF_ALLMULTI)
data->rx_filter |= FIF_ALLMULTI;
@@ -2393,15 +2391,16 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
if (param->p2p_device)
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
- hw->flags = IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_WANT_MONITOR_VIF |
- IEEE80211_HW_QUEUE_CONTROL |
- IEEE80211_HW_SUPPORTS_HT_CCK_RATES |
- IEEE80211_HW_CHANCTX_STA_CSA;
+ ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
+ ieee80211_hw_set(hw, CHANCTX_STA_CSA);
+ ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
+ ieee80211_hw_set(hw, QUEUE_CONTROL);
+ ieee80211_hw_set(hw, WANT_MONITOR_VIF);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
if (rctbl)
- hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
+ ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
@@ -2438,6 +2437,31 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz);
sband->bitrates = data->rates + 4;
sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4;
+
+ sband->vht_cap.vht_supported = true;
+ sband->vht_cap.cap =
+ IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
+ IEEE80211_VHT_CAP_RXLDPC |
+ IEEE80211_VHT_CAP_SHORT_GI_80 |
+ IEEE80211_VHT_CAP_SHORT_GI_160 |
+ IEEE80211_VHT_CAP_TXSTBC |
+ IEEE80211_VHT_CAP_RXSTBC_1 |
+ IEEE80211_VHT_CAP_RXSTBC_2 |
+ IEEE80211_VHT_CAP_RXSTBC_3 |
+ IEEE80211_VHT_CAP_RXSTBC_4 |
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+ sband->vht_cap.vht_mcs.rx_mcs_map =
+ cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 14);
+ sband->vht_cap.vht_mcs.tx_mcs_map =
+ sband->vht_cap.vht_mcs.rx_mcs_map;
break;
default:
continue;
@@ -2458,31 +2482,6 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
hw->wiphy->bands[band] = sband;
-
- sband->vht_cap.vht_supported = true;
- sband->vht_cap.cap =
- IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
- IEEE80211_VHT_CAP_RXLDPC |
- IEEE80211_VHT_CAP_SHORT_GI_80 |
- IEEE80211_VHT_CAP_SHORT_GI_160 |
- IEEE80211_VHT_CAP_TXSTBC |
- IEEE80211_VHT_CAP_RXSTBC_1 |
- IEEE80211_VHT_CAP_RXSTBC_2 |
- IEEE80211_VHT_CAP_RXSTBC_3 |
- IEEE80211_VHT_CAP_RXSTBC_4 |
- IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
- sband->vht_cap.vht_mcs.rx_mcs_map =
- cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 |
- IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 |
- IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 |
- IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 |
- IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 |
- IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 |
- IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 |
- IEEE80211_VHT_MCS_SUPPORT_0_8 << 14);
- sband->vht_cap.vht_mcs.tx_mcs_map =
- sband->vht_cap.vht_mcs.rx_mcs_map;
}
/* By default all radios belong to the first group */
@@ -2510,7 +2509,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
}
if (param->no_vif)
- hw->flags |= IEEE80211_HW_NO_AUTO_VIF;
+ ieee80211_hw_set(hw, NO_AUTO_VIF);
err = ieee80211_register_hw(hw);
if (err < 0) {
diff --git a/drivers/net/wireless/mediatek/Kconfig b/drivers/net/wireless/mediatek/Kconfig
new file mode 100644
index 000000000000..cba300c6b5da
--- /dev/null
+++ b/drivers/net/wireless/mediatek/Kconfig
@@ -0,0 +1,10 @@
+menuconfig WL_MEDIATEK
+ bool "Mediatek Wireless LAN support"
+ ---help---
+ Enable community drivers for MediaTek WiFi devices.
+ Those drivers make use of the Linux mac80211 stack.
+
+
+if WL_MEDIATEK
+source "drivers/net/wireless/mediatek/mt7601u/Kconfig"
+endif # WL_MEDIATEK
diff --git a/drivers/net/wireless/mediatek/Makefile b/drivers/net/wireless/mediatek/Makefile
new file mode 100644
index 000000000000..9d5f182fd7fd
--- /dev/null
+++ b/drivers/net/wireless/mediatek/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MT7601U) += mt7601u/
diff --git a/drivers/net/wireless/mediatek/mt7601u/Kconfig b/drivers/net/wireless/mediatek/mt7601u/Kconfig
new file mode 100644
index 000000000000..f46bed92796b
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/Kconfig
@@ -0,0 +1,6 @@
+config MT7601U
+ tristate "MediaTek MT7601U (USB) support"
+ depends on MAC80211
+ depends on USB
+ ---help---
+ This adds support for MT7601U-based wireless USB dongles.
diff --git a/drivers/net/wireless/mediatek/mt7601u/Makefile b/drivers/net/wireless/mediatek/mt7601u/Makefile
new file mode 100644
index 000000000000..ea9ed8a5db4d
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/Makefile
@@ -0,0 +1,9 @@
+ccflags-y += -D__CHECK_ENDIAN__
+
+obj-$(CONFIG_MT7601U) += mt7601u.o
+
+mt7601u-objs = \
+ usb.o init.o main.o mcu.o trace.o dma.o core.o eeprom.o phy.o \
+ mac.o util.o debugfs.o tx.o
+
+CFLAGS_trace.o := -I$(src)
diff --git a/drivers/net/wireless/mediatek/mt7601u/core.c b/drivers/net/wireless/mediatek/mt7601u/core.c
new file mode 100644
index 000000000000..0aabd790f985
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/core.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include "mt7601u.h"
+
+int mt7601u_wait_asic_ready(struct mt7601u_dev *dev)
+{
+ int i = 100;
+ u32 val;
+
+ do {
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return -EIO;
+
+ val = mt7601u_rr(dev, MT_MAC_CSR0);
+ if (val && ~val)
+ return 0;
+
+ udelay(10);
+ } while (i--);
+
+ return -EIO;
+}
+
+bool mt76_poll(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
+ int timeout)
+{
+ u32 cur;
+
+ timeout /= 10;
+ do {
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return false;
+
+ cur = mt7601u_rr(dev, offset) & mask;
+ if (cur == val)
+ return true;
+
+ udelay(10);
+ } while (timeout-- > 0);
+
+ dev_err(dev->dev, "Error: Time out with reg %08x\n", offset);
+
+ return false;
+}
+
+bool mt76_poll_msec(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
+ int timeout)
+{
+ u32 cur;
+
+ timeout /= 10;
+ do {
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return false;
+
+ cur = mt7601u_rr(dev, offset) & mask;
+ if (cur == val)
+ return true;
+
+ msleep(10);
+ } while (timeout-- > 0);
+
+ dev_err(dev->dev, "Error: Time out with reg %08x\n", offset);
+
+ return false;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/debugfs.c b/drivers/net/wireless/mediatek/mt7601u/debugfs.c
new file mode 100644
index 000000000000..fc008475a03b
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/debugfs.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include <linux/debugfs.h>
+
+#include "mt7601u.h"
+#include "eeprom.h"
+
+static int
+mt76_reg_set(void *data, u64 val)
+{
+ struct mt7601u_dev *dev = data;
+
+ mt76_wr(dev, dev->debugfs_reg, val);
+ return 0;
+}
+
+static int
+mt76_reg_get(void *data, u64 *val)
+{
+ struct mt7601u_dev *dev = data;
+
+ *val = mt76_rr(dev, dev->debugfs_reg);
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n");
+
+static int
+mt7601u_ampdu_stat_read(struct seq_file *file, void *data)
+{
+ struct mt7601u_dev *dev = file->private;
+ int i, j;
+
+#define stat_printf(grp, off, name) \
+ seq_printf(file, #name ":\t%llu\n", dev->stats.grp[off])
+
+ stat_printf(rx_stat, 0, rx_crc_err);
+ stat_printf(rx_stat, 1, rx_phy_err);
+ stat_printf(rx_stat, 2, rx_false_cca);
+ stat_printf(rx_stat, 3, rx_plcp_err);
+ stat_printf(rx_stat, 4, rx_fifo_overflow);
+ stat_printf(rx_stat, 5, rx_duplicate);
+
+ stat_printf(tx_stat, 0, tx_fail_cnt);
+ stat_printf(tx_stat, 1, tx_bcn_cnt);
+ stat_printf(tx_stat, 2, tx_success);
+ stat_printf(tx_stat, 3, tx_retransmit);
+ stat_printf(tx_stat, 4, tx_zero_len);
+ stat_printf(tx_stat, 5, tx_underflow);
+
+ stat_printf(aggr_stat, 0, non_aggr_tx);
+ stat_printf(aggr_stat, 1, aggr_tx);
+
+ stat_printf(zero_len_del, 0, tx_zero_len_del);
+ stat_printf(zero_len_del, 1, rx_zero_len_del);
+#undef stat_printf
+
+ seq_puts(file, "Aggregations stats:\n");
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 8; j++)
+ seq_printf(file, "%08llx ",
+ dev->stats.aggr_n[i * 8 + j]);
+ seq_putc(file, '\n');
+ }
+
+ seq_printf(file, "recent average AMPDU len: %d\n",
+ atomic_read(&dev->avg_ampdu_len));
+
+ return 0;
+}
+
+static int
+mt7601u_ampdu_stat_open(struct inode *inode, struct file *f)
+{
+ return single_open(f, mt7601u_ampdu_stat_read, inode->i_private);
+}
+
+static const struct file_operations fops_ampdu_stat = {
+ .open = mt7601u_ampdu_stat_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int
+mt7601u_eeprom_param_read(struct seq_file *file, void *data)
+{
+ struct mt7601u_dev *dev = file->private;
+ struct mt7601u_rate_power *rp = &dev->ee->power_rate_table;
+ struct tssi_data *td = &dev->ee->tssi_data;
+ int i;
+
+ seq_printf(file, "RF freq offset: %hhx\n", dev->ee->rf_freq_off);
+ seq_printf(file, "RSSI offset: %hhx %hhx\n",
+ dev->ee->rssi_offset[0], dev->ee->rssi_offset[1]);
+ seq_printf(file, "Reference temp: %hhx\n", dev->ee->ref_temp);
+ seq_printf(file, "LNA gain: %hhx\n", dev->ee->lna_gain);
+ seq_printf(file, "Reg channels: %hhu-%hhu\n", dev->ee->reg.start,
+ dev->ee->reg.start + dev->ee->reg.num - 1);
+
+ seq_puts(file, "Per rate power:\n");
+ for (i = 0; i < 2; i++)
+ seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n",
+ rp->cck[i].raw, rp->cck[i].bw20, rp->cck[i].bw40);
+ for (i = 0; i < 4; i++)
+ seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n",
+ rp->ofdm[i].raw, rp->ofdm[i].bw20, rp->ofdm[i].bw40);
+ for (i = 0; i < 4; i++)
+ seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n",
+ rp->ht[i].raw, rp->ht[i].bw20, rp->ht[i].bw40);
+
+ seq_puts(file, "Per channel power:\n");
+ for (i = 0; i < 7; i++)
+ seq_printf(file, "\t tx_power ch%u:%02hhx ch%u:%02hhx\n",
+ i * 2 + 1, dev->ee->chan_pwr[i * 2],
+ i * 2 + 2, dev->ee->chan_pwr[i * 2 + 1]);
+
+ if (!dev->ee->tssi_enabled)
+ return 0;
+
+ seq_puts(file, "TSSI:\n");
+ seq_printf(file, "\t slope:%02hhx\n", td->slope);
+ seq_printf(file, "\t offset=%02hhx %02hhx %02hhx\n",
+ td->offset[0], td->offset[1], td->offset[2]);
+ seq_printf(file, "\t delta_off:%08x\n", td->tx0_delta_offset);
+
+ return 0;
+}
+
+static int
+mt7601u_eeprom_param_open(struct inode *inode, struct file *f)
+{
+ return single_open(f, mt7601u_eeprom_param_read, inode->i_private);
+}
+
+static const struct file_operations fops_eeprom_param = {
+ .open = mt7601u_eeprom_param_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void mt7601u_init_debugfs(struct mt7601u_dev *dev)
+{
+ struct dentry *dir;
+
+ dir = debugfs_create_dir("mt7601u", dev->hw->wiphy->debugfsdir);
+ if (!dir)
+ return;
+
+ debugfs_create_u8("temperature", S_IRUSR, dir, &dev->raw_temp);
+ debugfs_create_u32("temp_mode", S_IRUSR, dir, &dev->temp_mode);
+
+ debugfs_create_u32("regidx", S_IRUSR | S_IWUSR, dir, &dev->debugfs_reg);
+ debugfs_create_file("regval", S_IRUSR | S_IWUSR, dir, dev,
+ &fops_regval);
+ debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat);
+ debugfs_create_file("eeprom_param", S_IRUSR, dir, dev,
+ &fops_eeprom_param);
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c
new file mode 100644
index 000000000000..7217da4f1543
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/dma.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include "mt7601u.h"
+#include "dma.h"
+#include "usb.h"
+#include "trace.h"
+
+static int mt7601u_submit_rx_buf(struct mt7601u_dev *dev,
+ struct mt7601u_dma_buf_rx *e, gfp_t gfp);
+
+static unsigned int ieee80211_get_hdrlen_from_buf(const u8 *data, unsigned len)
+{
+ const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)data;
+ unsigned int hdrlen;
+
+ if (unlikely(len < 10))
+ return 0;
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ if (unlikely(hdrlen > len))
+ return 0;
+ return hdrlen;
+}
+
+static struct sk_buff *
+mt7601u_rx_skb_from_seg(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi,
+ void *data, u32 seg_len, u32 truesize, struct page *p)
+{
+ struct sk_buff *skb;
+ u32 true_len, hdr_len = 0, copy, frag;
+
+ skb = alloc_skb(p ? 128 : seg_len, GFP_ATOMIC);
+ if (!skb)
+ return NULL;
+
+ true_len = mt76_mac_process_rx(dev, skb, data, rxwi);
+ if (!true_len || true_len > seg_len)
+ goto bad_frame;
+
+ hdr_len = ieee80211_get_hdrlen_from_buf(data, true_len);
+ if (!hdr_len)
+ goto bad_frame;
+
+ if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) {
+ memcpy(skb_put(skb, hdr_len), data, hdr_len);
+
+ data += hdr_len + 2;
+ true_len -= hdr_len;
+ hdr_len = 0;
+ }
+
+ /* If not doing paged RX allocated skb will always have enough space */
+ copy = (true_len <= skb_tailroom(skb)) ? true_len : hdr_len + 8;
+ frag = true_len - copy;
+
+ memcpy(skb_put(skb, copy), data, copy);
+ data += copy;
+
+ if (frag) {
+ skb_add_rx_frag(skb, 0, p, data - page_address(p),
+ frag, truesize);
+ get_page(p);
+ }
+
+ return skb;
+
+bad_frame:
+ dev_err_ratelimited(dev->dev, "Error: incorrect frame len:%u hdr:%u\n",
+ true_len, hdr_len);
+ dev_kfree_skb(skb);
+ return NULL;
+}
+
+static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data,
+ u32 seg_len, struct page *p)
+{
+ struct sk_buff *skb;
+ struct mt7601u_rxwi *rxwi;
+ u32 fce_info, truesize = seg_len;
+
+ /* DMA_INFO field at the beginning of the segment contains only some of
+ * the information, we need to read the FCE descriptor from the end.
+ */
+ fce_info = get_unaligned_le32(data + seg_len - MT_FCE_INFO_LEN);
+ seg_len -= MT_FCE_INFO_LEN;
+
+ data += MT_DMA_HDR_LEN;
+ seg_len -= MT_DMA_HDR_LEN;
+
+ rxwi = (struct mt7601u_rxwi *) data;
+ data += sizeof(struct mt7601u_rxwi);
+ seg_len -= sizeof(struct mt7601u_rxwi);
+
+ if (unlikely(rxwi->zero[0] || rxwi->zero[1] || rxwi->zero[2]))
+ dev_err_once(dev->dev, "Error: RXWI zero fields are set\n");
+ if (unlikely(MT76_GET(MT_RXD_INFO_TYPE, fce_info)))
+ dev_err_once(dev->dev, "Error: RX path seen a non-pkt urb\n");
+
+ trace_mt_rx(dev, rxwi, fce_info);
+
+ skb = mt7601u_rx_skb_from_seg(dev, rxwi, data, seg_len, truesize, p);
+ if (!skb)
+ return;
+
+ ieee80211_rx_ni(dev->hw, skb);
+}
+
+static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len)
+{
+ u32 min_seg_len = MT_DMA_HDR_LEN + MT_RX_INFO_LEN +
+ sizeof(struct mt7601u_rxwi) + MT_FCE_INFO_LEN;
+ u16 dma_len = get_unaligned_le16(data);
+
+ if (data_len < min_seg_len ||
+ WARN_ON(!dma_len) ||
+ WARN_ON(dma_len + MT_DMA_HDRS > data_len) ||
+ WARN_ON(dma_len & 0x3))
+ return 0;
+
+ return MT_DMA_HDRS + dma_len;
+}
+
+static void
+mt7601u_rx_process_entry(struct mt7601u_dev *dev, struct mt7601u_dma_buf_rx *e)
+{
+ u32 seg_len, data_len = e->urb->actual_length;
+ u8 *data = page_address(e->p);
+ struct page *new_p = NULL;
+ int cnt = 0;
+
+ if (!test_bit(MT7601U_STATE_INITIALIZED, &dev->state))
+ return;
+
+ /* Copy if there is very little data in the buffer. */
+ if (data_len > 512)
+ new_p = dev_alloc_pages(MT_RX_ORDER);
+
+ while ((seg_len = mt7601u_rx_next_seg_len(data, data_len))) {
+ mt7601u_rx_process_seg(dev, data, seg_len, new_p ? e->p : NULL);
+
+ data_len -= seg_len;
+ data += seg_len;
+ cnt++;
+ }
+
+ if (cnt > 1)
+ trace_mt_rx_dma_aggr(dev, cnt, !!new_p);
+
+ if (new_p) {
+ /* we have one extra ref from the allocator */
+ __free_pages(e->p, MT_RX_ORDER);
+
+ e->p = new_p;
+ }
+}
+
+static struct mt7601u_dma_buf_rx *
+mt7601u_rx_get_pending_entry(struct mt7601u_dev *dev)
+{
+ struct mt7601u_rx_queue *q = &dev->rx_q;
+ struct mt7601u_dma_buf_rx *buf = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->rx_lock, flags);
+
+ if (!q->pending)
+ goto out;
+
+ buf = &q->e[q->start];
+ q->pending--;
+ q->start = (q->start + 1) % q->entries;
+out:
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+
+ return buf;
+}
+
+static void mt7601u_complete_rx(struct urb *urb)
+{
+ struct mt7601u_dev *dev = urb->context;
+ struct mt7601u_rx_queue *q = &dev->rx_q;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->rx_lock, flags);
+
+ if (mt7601u_urb_has_error(urb))
+ dev_err(dev->dev, "Error: RX urb failed:%d\n", urb->status);
+ if (WARN_ONCE(q->e[q->end].urb != urb, "RX urb mismatch"))
+ goto out;
+
+ q->end = (q->end + 1) % q->entries;
+ q->pending++;
+ tasklet_schedule(&dev->rx_tasklet);
+out:
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+}
+
+static void mt7601u_rx_tasklet(unsigned long data)
+{
+ struct mt7601u_dev *dev = (struct mt7601u_dev *) data;
+ struct mt7601u_dma_buf_rx *e;
+
+ while ((e = mt7601u_rx_get_pending_entry(dev))) {
+ if (e->urb->status)
+ continue;
+
+ mt7601u_rx_process_entry(dev, e);
+ mt7601u_submit_rx_buf(dev, e, GFP_ATOMIC);
+ }
+}
+
+static void mt7601u_complete_tx(struct urb *urb)
+{
+ struct mt7601u_tx_queue *q = urb->context;
+ struct mt7601u_dev *dev = q->dev;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->tx_lock, flags);
+
+ if (mt7601u_urb_has_error(urb))
+ dev_err(dev->dev, "Error: TX urb failed:%d\n", urb->status);
+ if (WARN_ONCE(q->e[q->start].urb != urb, "TX urb mismatch"))
+ goto out;
+
+ skb = q->e[q->start].skb;
+ trace_mt_tx_dma_done(dev, skb);
+
+ mt7601u_tx_status(dev, skb);
+
+ if (q->used == q->entries - q->entries / 8)
+ ieee80211_wake_queue(dev->hw, skb_get_queue_mapping(skb));
+
+ q->start = (q->start + 1) % q->entries;
+ q->used--;
+
+ if (urb->status)
+ goto out;
+
+ set_bit(MT7601U_STATE_MORE_STATS, &dev->state);
+ if (!test_and_set_bit(MT7601U_STATE_READING_STATS, &dev->state))
+ queue_delayed_work(dev->stat_wq, &dev->stat_work,
+ msecs_to_jiffies(10));
+out:
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
+}
+
+static int mt7601u_dma_submit_tx(struct mt7601u_dev *dev,
+ struct sk_buff *skb, u8 ep)
+{
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+ unsigned snd_pipe = usb_sndbulkpipe(usb_dev, dev->out_eps[ep]);
+ struct mt7601u_dma_buf_tx *e;
+ struct mt7601u_tx_queue *q = &dev->tx_q[ep];
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&dev->tx_lock, flags);
+
+ if (WARN_ON(q->entries <= q->used)) {
+ ret = -ENOSPC;
+ goto out;
+ }
+
+ e = &q->e[q->end];
+ e->skb = skb;
+ usb_fill_bulk_urb(e->urb, usb_dev, snd_pipe, skb->data, skb->len,
+ mt7601u_complete_tx, q);
+ ret = usb_submit_urb(e->urb, GFP_ATOMIC);
+ if (ret) {
+ /* Special-handle ENODEV from TX urb submission because it will
+ * often be the first ENODEV we see after device is removed.
+ */
+ if (ret == -ENODEV)
+ set_bit(MT7601U_STATE_REMOVED, &dev->state);
+ else
+ dev_err(dev->dev, "Error: TX urb submit failed:%d\n",
+ ret);
+ goto out;
+ }
+
+ q->end = (q->end + 1) % q->entries;
+ q->used++;
+
+ if (q->used >= q->entries)
+ ieee80211_stop_queue(dev->hw, skb_get_queue_mapping(skb));
+out:
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
+
+ return ret;
+}
+
+/* Map hardware Q to USB endpoint number */
+static u8 q2ep(u8 qid)
+{
+ /* TODO: take management packets to queue 5 */
+ return qid + 1;
+}
+
+/* Map USB endpoint number to Q id in the DMA engine */
+static enum mt76_qsel ep2dmaq(u8 ep)
+{
+ if (ep == 5)
+ return MT_QSEL_MGMT;
+ return MT_QSEL_EDCA;
+}
+
+int mt7601u_dma_enqueue_tx(struct mt7601u_dev *dev, struct sk_buff *skb,
+ struct mt76_wcid *wcid, int hw_q)
+{
+ u8 ep = q2ep(hw_q);
+ u32 dma_flags;
+ int ret;
+
+ dma_flags = MT_TXD_PKT_INFO_80211;
+ if (wcid->hw_key_idx == 0xff)
+ dma_flags |= MT_TXD_PKT_INFO_WIV;
+
+ ret = mt7601u_dma_skb_wrap_pkt(skb, ep2dmaq(ep), dma_flags);
+ if (ret)
+ return ret;
+
+ ret = mt7601u_dma_submit_tx(dev, skb, ep);
+ if (ret) {
+ ieee80211_free_txskb(dev->hw, skb);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mt7601u_kill_rx(struct mt7601u_dev *dev)
+{
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->rx_lock, flags);
+
+ for (i = 0; i < dev->rx_q.entries; i++) {
+ int next = dev->rx_q.end;
+
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+ usb_poison_urb(dev->rx_q.e[next].urb);
+ spin_lock_irqsave(&dev->rx_lock, flags);
+ }
+
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+}
+
+static int mt7601u_submit_rx_buf(struct mt7601u_dev *dev,
+ struct mt7601u_dma_buf_rx *e, gfp_t gfp)
+{
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+ u8 *buf = page_address(e->p);
+ unsigned pipe;
+ int ret;
+
+ pipe = usb_rcvbulkpipe(usb_dev, dev->in_eps[MT_EP_IN_PKT_RX]);
+
+ usb_fill_bulk_urb(e->urb, usb_dev, pipe, buf, MT_RX_URB_SIZE,
+ mt7601u_complete_rx, dev);
+
+ trace_mt_submit_urb(dev, e->urb);
+ ret = usb_submit_urb(e->urb, gfp);
+ if (ret)
+ dev_err(dev->dev, "Error: submit RX URB failed:%d\n", ret);
+
+ return ret;
+}
+
+static int mt7601u_submit_rx(struct mt7601u_dev *dev)
+{
+ int i, ret;
+
+ for (i = 0; i < dev->rx_q.entries; i++) {
+ ret = mt7601u_submit_rx_buf(dev, &dev->rx_q.e[i], GFP_KERNEL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mt7601u_free_rx(struct mt7601u_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < dev->rx_q.entries; i++) {
+ __free_pages(dev->rx_q.e[i].p, MT_RX_ORDER);
+ usb_free_urb(dev->rx_q.e[i].urb);
+ }
+}
+
+static int mt7601u_alloc_rx(struct mt7601u_dev *dev)
+{
+ int i;
+
+ memset(&dev->rx_q, 0, sizeof(dev->rx_q));
+ dev->rx_q.dev = dev;
+ dev->rx_q.entries = N_RX_ENTRIES;
+
+ for (i = 0; i < N_RX_ENTRIES; i++) {
+ dev->rx_q.e[i].urb = usb_alloc_urb(0, GFP_KERNEL);
+ dev->rx_q.e[i].p = dev_alloc_pages(MT_RX_ORDER);
+
+ if (!dev->rx_q.e[i].urb || !dev->rx_q.e[i].p)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void mt7601u_free_tx_queue(struct mt7601u_tx_queue *q)
+{
+ int i;
+
+ WARN_ON(q->used);
+
+ for (i = 0; i < q->entries; i++) {
+ usb_poison_urb(q->e[i].urb);
+ usb_free_urb(q->e[i].urb);
+ }
+}
+
+static void mt7601u_free_tx(struct mt7601u_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < __MT_EP_OUT_MAX; i++)
+ mt7601u_free_tx_queue(&dev->tx_q[i]);
+}
+
+static int mt7601u_alloc_tx_queue(struct mt7601u_dev *dev,
+ struct mt7601u_tx_queue *q)
+{
+ int i;
+
+ q->dev = dev;
+ q->entries = N_TX_ENTRIES;
+
+ for (i = 0; i < N_TX_ENTRIES; i++) {
+ q->e[i].urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!q->e[i].urb)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int mt7601u_alloc_tx(struct mt7601u_dev *dev)
+{
+ int i;
+
+ dev->tx_q = devm_kcalloc(dev->dev, __MT_EP_OUT_MAX,
+ sizeof(*dev->tx_q), GFP_KERNEL);
+
+ for (i = 0; i < __MT_EP_OUT_MAX; i++)
+ if (mt7601u_alloc_tx_queue(dev, &dev->tx_q[i]))
+ return -ENOMEM;
+
+ return 0;
+}
+
+int mt7601u_dma_init(struct mt7601u_dev *dev)
+{
+ int ret = -ENOMEM;
+
+ tasklet_init(&dev->rx_tasklet, mt7601u_rx_tasklet, (unsigned long) dev);
+
+ ret = mt7601u_alloc_tx(dev);
+ if (ret)
+ goto err;
+ ret = mt7601u_alloc_rx(dev);
+ if (ret)
+ goto err;
+
+ ret = mt7601u_submit_rx(dev);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ mt7601u_dma_cleanup(dev);
+ return ret;
+}
+
+void mt7601u_dma_cleanup(struct mt7601u_dev *dev)
+{
+ mt7601u_kill_rx(dev);
+
+ tasklet_kill(&dev->rx_tasklet);
+
+ mt7601u_free_rx(dev);
+ mt7601u_free_tx(dev);
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.h b/drivers/net/wireless/mediatek/mt7601u/dma.h
new file mode 100644
index 000000000000..978e8a90b87f
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/dma.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#ifndef __MT7601U_DMA_H
+#define __MT7601U_DMA_H
+
+#include <asm/unaligned.h>
+#include <linux/skbuff.h>
+
+#include "util.h"
+
+#define MT_DMA_HDR_LEN 4
+#define MT_RX_INFO_LEN 4
+#define MT_FCE_INFO_LEN 4
+#define MT_DMA_HDRS (MT_DMA_HDR_LEN + MT_RX_INFO_LEN)
+
+/* Common Tx DMA descriptor fields */
+#define MT_TXD_INFO_LEN GENMASK(15, 0)
+#define MT_TXD_INFO_D_PORT GENMASK(29, 27)
+#define MT_TXD_INFO_TYPE GENMASK(31, 30)
+
+enum mt76_msg_port {
+ WLAN_PORT,
+ CPU_RX_PORT,
+ CPU_TX_PORT,
+ HOST_PORT,
+ VIRTUAL_CPU_RX_PORT,
+ VIRTUAL_CPU_TX_PORT,
+ DISCARD,
+};
+
+enum mt76_info_type {
+ DMA_PACKET,
+ DMA_COMMAND,
+};
+
+/* Tx DMA packet specific flags */
+#define MT_TXD_PKT_INFO_NEXT_VLD BIT(16)
+#define MT_TXD_PKT_INFO_TX_BURST BIT(17)
+#define MT_TXD_PKT_INFO_80211 BIT(19)
+#define MT_TXD_PKT_INFO_TSO BIT(20)
+#define MT_TXD_PKT_INFO_CSO BIT(21)
+#define MT_TXD_PKT_INFO_WIV BIT(24)
+#define MT_TXD_PKT_INFO_QSEL GENMASK(26, 25)
+
+enum mt76_qsel {
+ MT_QSEL_MGMT,
+ MT_QSEL_HCCA,
+ MT_QSEL_EDCA,
+ MT_QSEL_EDCA_2,
+};
+
+/* Tx DMA MCU command specific flags */
+#define MT_TXD_CMD_INFO_SEQ GENMASK(19, 16)
+#define MT_TXD_CMD_INFO_TYPE GENMASK(26, 20)
+
+static inline int mt7601u_dma_skb_wrap(struct sk_buff *skb,
+ enum mt76_msg_port d_port,
+ enum mt76_info_type type, u32 flags)
+{
+ u32 info;
+
+ /* Buffer layout:
+ * | 4B | xfer len | pad | 4B |
+ * | TXINFO | pkt/cmd | zero pad to 4B | zero |
+ *
+ * length field of TXINFO should be set to 'xfer len'.
+ */
+
+ info = flags |
+ MT76_SET(MT_TXD_INFO_LEN, round_up(skb->len, 4)) |
+ MT76_SET(MT_TXD_INFO_D_PORT, d_port) |
+ MT76_SET(MT_TXD_INFO_TYPE, type);
+
+ put_unaligned_le32(info, skb_push(skb, sizeof(info)));
+ return skb_put_padto(skb, round_up(skb->len, 4) + 4);
+}
+
+static inline int
+mt7601u_dma_skb_wrap_pkt(struct sk_buff *skb, enum mt76_qsel qsel, u32 flags)
+{
+ flags |= MT76_SET(MT_TXD_PKT_INFO_QSEL, qsel);
+ return mt7601u_dma_skb_wrap(skb, WLAN_PORT, DMA_PACKET, flags);
+}
+
+/* Common Rx DMA descriptor fields */
+#define MT_RXD_INFO_LEN GENMASK(13, 0)
+#define MT_RXD_INFO_PCIE_INTR BIT(24)
+#define MT_RXD_INFO_QSEL GENMASK(26, 25)
+#define MT_RXD_INFO_PORT GENMASK(29, 27)
+#define MT_RXD_INFO_TYPE GENMASK(31, 30)
+
+/* Rx DMA packet specific flags */
+#define MT_RXD_PKT_INFO_UDP_ERR BIT(16)
+#define MT_RXD_PKT_INFO_TCP_ERR BIT(17)
+#define MT_RXD_PKT_INFO_IP_ERR BIT(18)
+#define MT_RXD_PKT_INFO_PKT_80211 BIT(19)
+#define MT_RXD_PKT_INFO_L3L4_DONE BIT(20)
+#define MT_RXD_PKT_INFO_MAC_LEN GENMASK(23, 21)
+
+/* Rx DMA MCU command specific flags */
+#define MT_RXD_CMD_INFO_SELF_GEN BIT(15)
+#define MT_RXD_CMD_INFO_CMD_SEQ GENMASK(19, 16)
+#define MT_RXD_CMD_INFO_EVT_TYPE GENMASK(23, 20)
+
+enum mt76_evt_type {
+ CMD_DONE,
+ CMD_ERROR,
+ CMD_RETRY,
+ EVENT_PWR_RSP,
+ EVENT_WOW_RSP,
+ EVENT_CARRIER_DETECT_RSP,
+ EVENT_DFS_DETECT_RSP,
+};
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/eeprom.c b/drivers/net/wireless/mediatek/mt7601u/eeprom.c
new file mode 100644
index 000000000000..8d8ee0344f7b
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/eeprom.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include <linux/of.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/etherdevice.h>
+#include <asm/unaligned.h>
+#include "mt7601u.h"
+#include "eeprom.h"
+
+static bool
+field_valid(u8 val)
+{
+ return val != 0xff;
+}
+
+static s8
+field_validate(u8 val)
+{
+ if (!field_valid(val))
+ return 0;
+
+ return val;
+}
+
+static int
+mt7601u_efuse_read(struct mt7601u_dev *dev, u16 addr, u8 *data,
+ enum mt7601u_eeprom_access_modes mode)
+{
+ u32 val;
+ int i;
+
+ val = mt76_rr(dev, MT_EFUSE_CTRL);
+ val &= ~(MT_EFUSE_CTRL_AIN |
+ MT_EFUSE_CTRL_MODE);
+ val |= MT76_SET(MT_EFUSE_CTRL_AIN, addr & ~0xf) |
+ MT76_SET(MT_EFUSE_CTRL_MODE, mode) |
+ MT_EFUSE_CTRL_KICK;
+ mt76_wr(dev, MT_EFUSE_CTRL, val);
+
+ if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
+ return -ETIMEDOUT;
+
+ val = mt76_rr(dev, MT_EFUSE_CTRL);
+ if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) {
+ /* Parts of eeprom not in the usage map (0x80-0xc0,0xf0)
+ * will not return valid data but it's ok.
+ */
+ memset(data, 0xff, 16);
+ return 0;
+ }
+
+ for (i = 0; i < 4; i++) {
+ val = mt76_rr(dev, MT_EFUSE_DATA(i));
+ put_unaligned_le32(val, data + 4 * i);
+ }
+
+ return 0;
+}
+
+static int
+mt7601u_efuse_physical_size_check(struct mt7601u_dev *dev)
+{
+ const int map_reads = DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16);
+ u8 data[map_reads * 16];
+ int ret, i;
+ u32 start = 0, end = 0, cnt_free;
+
+ for (i = 0; i < map_reads; i++) {
+ ret = mt7601u_efuse_read(dev, MT_EE_USAGE_MAP_START + i * 16,
+ data + i * 16, MT_EE_PHYSICAL_READ);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++)
+ if (!data[i]) {
+ if (!start)
+ start = MT_EE_USAGE_MAP_START + i;
+ end = MT_EE_USAGE_MAP_START + i;
+ }
+ cnt_free = end - start + 1;
+
+ if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) {
+ dev_err(dev->dev, "Error: your device needs default EEPROM file and this driver doesn't support it!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static bool
+mt7601u_has_tssi(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1);
+
+ return ~nic_conf1 && (nic_conf1 & MT_EE_NIC_CONF_1_TX_ALC_EN);
+}
+
+static void
+mt7601u_set_chip_cap(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ u16 nic_conf0 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_0);
+ u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1);
+
+ if (!field_valid(nic_conf1 & 0xff))
+ nic_conf1 &= 0xff00;
+
+ dev->ee->tssi_enabled = mt7601u_has_tssi(dev, eeprom) &&
+ !(nic_conf1 & MT_EE_NIC_CONF_1_TEMP_TX_ALC);
+
+ if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL)
+ dev_err(dev->dev,
+ "Error: this driver does not support HW RF ctrl\n");
+
+ if (!field_valid(nic_conf0 >> 8))
+ return;
+
+ if (MT76_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 ||
+ MT76_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1)
+ dev_err(dev->dev,
+ "Error: device has more than 1 RX/TX stream!\n");
+}
+
+static int
+mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *eeprom)
+{
+ const void *src = eeprom + MT_EE_MAC_ADDR;
+
+ ether_addr_copy(dev->macaddr, src);
+
+ if (!is_valid_ether_addr(dev->macaddr)) {
+ eth_random_addr(dev->macaddr);
+ dev_info(dev->dev,
+ "Invalid MAC address, using random address %pM\n",
+ dev->macaddr);
+ }
+
+ mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr));
+ mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) |
+ MT76_SET(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
+
+ return 0;
+}
+
+static void mt7601u_set_channel_target_power(struct mt7601u_dev *dev,
+ u8 *eeprom, u8 max_pwr)
+{
+ u8 trgt_pwr = eeprom[MT_EE_TX_TSSI_TARGET_POWER];
+
+ if (trgt_pwr > max_pwr || !trgt_pwr) {
+ dev_warn(dev->dev, "Error: EEPROM trgt power invalid %hhx!\n",
+ trgt_pwr);
+ trgt_pwr = 0x20;
+ }
+
+ memset(dev->ee->chan_pwr, trgt_pwr, sizeof(dev->ee->chan_pwr));
+}
+
+static void
+mt7601u_set_channel_power(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ u32 i, val;
+ u8 max_pwr;
+
+ val = mt7601u_rr(dev, MT_TX_ALC_CFG_0);
+ max_pwr = MT76_GET(MT_TX_ALC_CFG_0_LIMIT_0, val);
+
+ if (mt7601u_has_tssi(dev, eeprom)) {
+ mt7601u_set_channel_target_power(dev, eeprom, max_pwr);
+ return;
+ }
+
+ for (i = 0; i < 14; i++) {
+ s8 power = field_validate(eeprom[MT_EE_TX_POWER_OFFSET + i]);
+
+ if (power > max_pwr || power < 0)
+ power = MT7601U_DEFAULT_TX_POWER;
+
+ dev->ee->chan_pwr[i] = power;
+ }
+}
+
+static void
+mt7601u_set_country_reg(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ /* Note: - region 31 is not valid for mt7601u (see rtmp_init.c)
+ * - comments in rtmp_def.h are incorrect (see rt_channel.c)
+ */
+ static const struct reg_channel_bounds chan_bounds[] = {
+ /* EEPROM country regions 0 - 7 */
+ { 1, 11 }, { 1, 13 }, { 10, 2 }, { 10, 4 },
+ { 14, 1 }, { 1, 14 }, { 3, 7 }, { 5, 9 },
+ /* EEPROM country regions 32 - 33 */
+ { 1, 11 }, { 1, 14 }
+ };
+ u8 val = eeprom[MT_EE_COUNTRY_REGION];
+ int idx = -1;
+
+ if (val < 8)
+ idx = val;
+ if (val > 31 && val < 33)
+ idx = val - 32 + 8;
+
+ if (idx != -1)
+ dev_info(dev->dev,
+ "EEPROM country region %02hhx (channels %hhd-%hhd)\n",
+ val, chan_bounds[idx].start,
+ chan_bounds[idx].start + chan_bounds[idx].num - 1);
+ else
+ idx = 5; /* channels 1 - 14 */
+
+ dev->ee->reg = chan_bounds[idx];
+
+ /* TODO: country region 33 is special - phy should be set to B-mode
+ * before entering channel 14 (see sta/connect.c)
+ */
+}
+
+static void
+mt7601u_set_rf_freq_off(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ u8 comp;
+
+ dev->ee->rf_freq_off = field_validate(eeprom[MT_EE_FREQ_OFFSET]);
+ comp = field_validate(eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]);
+
+ if (comp & BIT(7))
+ dev->ee->rf_freq_off -= comp & 0x7f;
+ else
+ dev->ee->rf_freq_off += comp;
+}
+
+static void
+mt7601u_set_rssi_offset(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ int i;
+ s8 *rssi_offset = dev->ee->rssi_offset;
+
+ for (i = 0; i < 2; i++) {
+ rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET + i];
+
+ if (rssi_offset[i] < -10 || rssi_offset[i] > 10) {
+ dev_warn(dev->dev,
+ "Warning: EEPROM RSSI is invalid %02hhx\n",
+ rssi_offset[i]);
+ rssi_offset[i] = 0;
+ }
+ }
+}
+
+static void
+mt7601u_extra_power_over_mac(struct mt7601u_dev *dev)
+{
+ u32 val;
+
+ val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_1) & 0x0000ff00) >> 8);
+ val |= ((mt7601u_rr(dev, MT_TX_PWR_CFG_2) & 0x0000ff00) << 8);
+ mt7601u_wr(dev, MT_TX_PWR_CFG_7, val);
+
+ val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_4) & 0x0000ff00) >> 8);
+ mt7601u_wr(dev, MT_TX_PWR_CFG_9, val);
+}
+
+static void
+mt7601u_set_power_rate(struct power_per_rate *rate, s8 delta, u8 value)
+{
+ /* Invalid? Note: vendor driver does not handle this */
+ if (value == 0xff)
+ return;
+
+ rate->raw = s6_validate(value);
+ rate->bw20 = s6_to_int(value);
+ /* Note: vendor driver does cap the value to s6 right away */
+ rate->bw40 = rate->bw20 + delta;
+}
+
+static void
+mt7601u_save_power_rate(struct mt7601u_dev *dev, s8 delta, u32 val, int i)
+{
+ struct mt7601u_rate_power *t = &dev->ee->power_rate_table;
+
+ switch (i) {
+ case 0:
+ mt7601u_set_power_rate(&t->cck[0], delta, (val >> 0) & 0xff);
+ mt7601u_set_power_rate(&t->cck[1], delta, (val >> 8) & 0xff);
+ /* Save cck bw20 for fixups of channel 14 */
+ dev->ee->real_cck_bw20[0] = t->cck[0].bw20;
+ dev->ee->real_cck_bw20[1] = t->cck[1].bw20;
+
+ mt7601u_set_power_rate(&t->ofdm[0], delta, (val >> 16) & 0xff);
+ mt7601u_set_power_rate(&t->ofdm[1], delta, (val >> 24) & 0xff);
+ break;
+ case 1:
+ mt7601u_set_power_rate(&t->ofdm[2], delta, (val >> 0) & 0xff);
+ mt7601u_set_power_rate(&t->ofdm[3], delta, (val >> 8) & 0xff);
+ mt7601u_set_power_rate(&t->ht[0], delta, (val >> 16) & 0xff);
+ mt7601u_set_power_rate(&t->ht[1], delta, (val >> 24) & 0xff);
+ break;
+ case 2:
+ mt7601u_set_power_rate(&t->ht[2], delta, (val >> 0) & 0xff);
+ mt7601u_set_power_rate(&t->ht[3], delta, (val >> 8) & 0xff);
+ break;
+ }
+}
+
+static s8
+get_delta(u8 val)
+{
+ s8 ret;
+
+ if (!field_valid(val) || !(val & BIT(7)))
+ return 0;
+
+ ret = val & 0x1f;
+ if (ret > 8)
+ ret = 8;
+ if (val & BIT(6))
+ ret = -ret;
+
+ return ret;
+}
+
+static void
+mt7601u_config_tx_power_per_rate(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ u32 val;
+ s8 bw40_delta;
+ int i;
+
+ bw40_delta = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]);
+
+ for (i = 0; i < 5; i++) {
+ val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i));
+
+ mt7601u_save_power_rate(dev, bw40_delta, val, i);
+
+ if (~val)
+ mt7601u_wr(dev, MT_TX_PWR_CFG_0 + i * 4, val);
+ }
+
+ mt7601u_extra_power_over_mac(dev);
+}
+
+static void
+mt7601u_init_tssi_params(struct mt7601u_dev *dev, u8 *eeprom)
+{
+ struct tssi_data *d = &dev->ee->tssi_data;
+
+ if (!dev->ee->tssi_enabled)
+ return;
+
+ d->slope = eeprom[MT_EE_TX_TSSI_SLOPE];
+ d->tx0_delta_offset = eeprom[MT_EE_TX_TSSI_OFFSET] * 1024;
+ d->offset[0] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP];
+ d->offset[1] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 1];
+ d->offset[2] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 2];
+}
+
+int
+mt7601u_eeprom_init(struct mt7601u_dev *dev)
+{
+ u8 *eeprom;
+ int i, ret;
+
+ ret = mt7601u_efuse_physical_size_check(dev);
+ if (ret)
+ return ret;
+
+ dev->ee = devm_kzalloc(dev->dev, sizeof(*dev->ee), GFP_KERNEL);
+ if (!dev->ee)
+ return -ENOMEM;
+
+ eeprom = kmalloc(MT7601U_EEPROM_SIZE, GFP_KERNEL);
+ if (!eeprom)
+ return -ENOMEM;
+
+ for (i = 0; i + 16 <= MT7601U_EEPROM_SIZE; i += 16) {
+ ret = mt7601u_efuse_read(dev, i, eeprom + i, MT_EE_READ);
+ if (ret)
+ goto out;
+ }
+
+ if (eeprom[MT_EE_VERSION_EE] > MT7601U_EE_MAX_VER)
+ dev_warn(dev->dev,
+ "Warning: unsupported EEPROM version %02hhx\n",
+ eeprom[MT_EE_VERSION_EE]);
+ dev_info(dev->dev, "EEPROM ver:%02hhx fae:%02hhx\n",
+ eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]);
+
+ mt7601u_set_macaddr(dev, eeprom);
+ mt7601u_set_chip_cap(dev, eeprom);
+ mt7601u_set_channel_power(dev, eeprom);
+ mt7601u_set_country_reg(dev, eeprom);
+ mt7601u_set_rf_freq_off(dev, eeprom);
+ mt7601u_set_rssi_offset(dev, eeprom);
+ dev->ee->ref_temp = eeprom[MT_EE_REF_TEMP];
+ dev->ee->lna_gain = eeprom[MT_EE_LNA_GAIN];
+
+ mt7601u_config_tx_power_per_rate(dev, eeprom);
+
+ mt7601u_init_tssi_params(dev, eeprom);
+out:
+ kfree(eeprom);
+ return ret;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/eeprom.h b/drivers/net/wireless/mediatek/mt7601u/eeprom.h
new file mode 100644
index 000000000000..662d12703b69
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/eeprom.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#ifndef __MT7601U_EEPROM_H
+#define __MT7601U_EEPROM_H
+
+struct mt7601u_dev;
+
+#define MT7601U_EE_MAX_VER 0x0c
+#define MT7601U_EEPROM_SIZE 256
+
+#define MT7601U_DEFAULT_TX_POWER 6
+
+enum mt76_eeprom_field {
+ MT_EE_CHIP_ID = 0x00,
+ MT_EE_VERSION_FAE = 0x02,
+ MT_EE_VERSION_EE = 0x03,
+ MT_EE_MAC_ADDR = 0x04,
+ MT_EE_NIC_CONF_0 = 0x34,
+ MT_EE_NIC_CONF_1 = 0x36,
+ MT_EE_COUNTRY_REGION = 0x39,
+ MT_EE_FREQ_OFFSET = 0x3a,
+ MT_EE_NIC_CONF_2 = 0x42,
+
+ MT_EE_LNA_GAIN = 0x44,
+ MT_EE_RSSI_OFFSET = 0x46,
+
+ MT_EE_TX_POWER_DELTA_BW40 = 0x50,
+ MT_EE_TX_POWER_OFFSET = 0x52,
+
+ MT_EE_TX_TSSI_SLOPE = 0x6e,
+ MT_EE_TX_TSSI_OFFSET_GROUP = 0x6f,
+ MT_EE_TX_TSSI_OFFSET = 0x76,
+
+ MT_EE_TX_TSSI_TARGET_POWER = 0xd0,
+ MT_EE_REF_TEMP = 0xd1,
+ MT_EE_FREQ_OFFSET_COMPENSATION = 0xdb,
+ MT_EE_TX_POWER_BYRATE_BASE = 0xde,
+
+ MT_EE_USAGE_MAP_START = 0x1e0,
+ MT_EE_USAGE_MAP_END = 0x1fc,
+};
+
+#define MT_EE_NIC_CONF_0_RX_PATH GENMASK(3, 0)
+#define MT_EE_NIC_CONF_0_TX_PATH GENMASK(7, 4)
+#define MT_EE_NIC_CONF_0_BOARD_TYPE GENMASK(13, 12)
+
+#define MT_EE_NIC_CONF_1_HW_RF_CTRL BIT(0)
+#define MT_EE_NIC_CONF_1_TEMP_TX_ALC BIT(1)
+#define MT_EE_NIC_CONF_1_LNA_EXT_2G BIT(2)
+#define MT_EE_NIC_CONF_1_LNA_EXT_5G BIT(3)
+#define MT_EE_NIC_CONF_1_TX_ALC_EN BIT(13)
+
+#define MT_EE_NIC_CONF_2_RX_STREAM GENMASK(3, 0)
+#define MT_EE_NIC_CONF_2_TX_STREAM GENMASK(7, 4)
+#define MT_EE_NIC_CONF_2_HW_ANTDIV BIT(8)
+#define MT_EE_NIC_CONF_2_XTAL_OPTION GENMASK(10, 9)
+#define MT_EE_NIC_CONF_2_TEMP_DISABLE BIT(11)
+#define MT_EE_NIC_CONF_2_COEX_METHOD GENMASK(15, 13)
+
+#define MT_EE_TX_POWER_BYRATE(i) (MT_EE_TX_POWER_BYRATE_BASE + \
+ (i) * 4)
+
+#define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \
+ MT_EE_USAGE_MAP_START + 1)
+
+enum mt7601u_eeprom_access_modes {
+ MT_EE_READ = 0,
+ MT_EE_PHYSICAL_READ = 1,
+};
+
+struct power_per_rate {
+ u8 raw; /* validated s6 value */
+ s8 bw20; /* sign-extended int */
+ s8 bw40; /* sign-extended int */
+};
+
+/* Power per rate - one value per two rates */
+struct mt7601u_rate_power {
+ struct power_per_rate cck[2];
+ struct power_per_rate ofdm[4];
+ struct power_per_rate ht[4];
+};
+
+struct reg_channel_bounds {
+ u8 start;
+ u8 num;
+};
+
+struct mt7601u_eeprom_params {
+ bool tssi_enabled;
+ u8 rf_freq_off;
+ s8 rssi_offset[2];
+ s8 ref_temp;
+ s8 lna_gain;
+
+ u8 chan_pwr[14];
+ struct mt7601u_rate_power power_rate_table;
+ s8 real_cck_bw20[2];
+
+ /* TSSI stuff - only with internal TX ALC */
+ struct tssi_data {
+ int tx0_delta_offset;
+ u8 slope;
+ u8 offset[3];
+ } tssi_data;
+
+ struct reg_channel_bounds reg;
+};
+
+int mt7601u_eeprom_init(struct mt7601u_dev *dev);
+
+static inline u32 s6_validate(u32 reg)
+{
+ WARN_ON(reg & ~GENMASK(5, 0));
+ return reg & GENMASK(5, 0);
+}
+
+static inline int s6_to_int(u32 reg)
+{
+ int s6;
+
+ s6 = s6_validate(reg);
+ if (s6 & BIT(5))
+ s6 -= BIT(6);
+
+ return s6;
+}
+
+static inline u32 int_to_s6(int val)
+{
+ if (val < -0x20)
+ return 0x20;
+ if (val > 0x1f)
+ return 0x1f;
+
+ return val & 0x3f;
+}
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c
new file mode 100644
index 000000000000..df3dd56199a7
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/init.c
@@ -0,0 +1,628 @@
+/*
+ * (c) Copyright 2002-2010, Ralink Technology, Inc.
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include "mt7601u.h"
+#include "eeprom.h"
+#include "trace.h"
+#include "mcu.h"
+
+#include "initvals.h"
+
+static void
+mt7601u_set_wlan_state(struct mt7601u_dev *dev, u32 val, bool enable)
+{
+ int i;
+
+ /* Note: we don't turn off WLAN_CLK because that makes the device
+ * not respond properly on the probe path.
+ * In case anyone (PSM?) wants to use this function we can
+ * bring the clock stuff back and fixup the probe path.
+ */
+
+ if (enable)
+ val |= (MT_WLAN_FUN_CTRL_WLAN_EN |
+ MT_WLAN_FUN_CTRL_WLAN_CLK_EN);
+ else
+ val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN);
+
+ mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val);
+ udelay(20);
+
+ if (enable) {
+ set_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state);
+ } else {
+ clear_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state);
+ return;
+ }
+
+ for (i = 200; i; i--) {
+ val = mt7601u_rr(dev, MT_CMB_CTRL);
+
+ if (val & MT_CMB_CTRL_XTAL_RDY && val & MT_CMB_CTRL_PLL_LD)
+ break;
+
+ udelay(20);
+ }
+
+ /* Note: vendor driver tries to disable/enable wlan here and retry
+ * but the code which does it is so buggy it must have never
+ * triggered, so don't bother.
+ */
+ if (!i)
+ dev_err(dev->dev, "Error: PLL and XTAL check failed!\n");
+}
+
+static void mt7601u_chip_onoff(struct mt7601u_dev *dev, bool enable, bool reset)
+{
+ u32 val;
+
+ mutex_lock(&dev->hw_atomic_mutex);
+
+ val = mt7601u_rr(dev, MT_WLAN_FUN_CTRL);
+
+ if (reset) {
+ val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN;
+ val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL;
+
+ if (val & MT_WLAN_FUN_CTRL_WLAN_EN) {
+ val |= (MT_WLAN_FUN_CTRL_WLAN_RESET |
+ MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
+ mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val);
+ udelay(20);
+
+ val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET |
+ MT_WLAN_FUN_CTRL_WLAN_RESET_RF);
+ }
+ }
+
+ mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val);
+ udelay(20);
+
+ mt7601u_set_wlan_state(dev, val, enable);
+
+ mutex_unlock(&dev->hw_atomic_mutex);
+}
+
+static void mt7601u_reset_csr_bbp(struct mt7601u_dev *dev)
+{
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, (MT_MAC_SYS_CTRL_RESET_CSR |
+ MT_MAC_SYS_CTRL_RESET_BBP));
+ mt7601u_wr(dev, MT_USB_DMA_CFG, 0);
+ msleep(1);
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0);
+}
+
+static void mt7601u_init_usb_dma(struct mt7601u_dev *dev)
+{
+ u32 val;
+
+ val = MT76_SET(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, MT_USB_AGGR_TIMEOUT) |
+ MT76_SET(MT_USB_DMA_CFG_RX_BULK_AGG_LMT, MT_USB_AGGR_SIZE_LIMIT) |
+ MT_USB_DMA_CFG_RX_BULK_EN |
+ MT_USB_DMA_CFG_TX_BULK_EN;
+ if (dev->in_max_packet == 512)
+ val |= MT_USB_DMA_CFG_RX_BULK_AGG_EN;
+ mt7601u_wr(dev, MT_USB_DMA_CFG, val);
+
+ val |= MT_USB_DMA_CFG_UDMA_RX_WL_DROP;
+ mt7601u_wr(dev, MT_USB_DMA_CFG, val);
+ val &= ~MT_USB_DMA_CFG_UDMA_RX_WL_DROP;
+ mt7601u_wr(dev, MT_USB_DMA_CFG, val);
+}
+
+static int mt7601u_init_bbp(struct mt7601u_dev *dev)
+{
+ int ret;
+
+ ret = mt7601u_wait_bbp_ready(dev);
+ if (ret)
+ return ret;
+
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, bbp_common_vals,
+ ARRAY_SIZE(bbp_common_vals));
+ if (ret)
+ return ret;
+
+ return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, bbp_chip_vals,
+ ARRAY_SIZE(bbp_chip_vals));
+}
+
+static void
+mt76_init_beacon_offsets(struct mt7601u_dev *dev)
+{
+ u16 base = MT_BEACON_BASE;
+ u32 regs[4] = {};
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ u16 addr = dev->beacon_offsets[i];
+
+ regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4));
+ }
+
+ for (i = 0; i < 4; i++)
+ mt7601u_wr(dev, MT_BCN_OFFSET(i), regs[i]);
+}
+
+static int mt7601u_write_mac_initvals(struct mt7601u_dev *dev)
+{
+ int ret;
+
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, mac_common_vals,
+ ARRAY_SIZE(mac_common_vals));
+ if (ret)
+ return ret;
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN,
+ mac_chip_vals, ARRAY_SIZE(mac_chip_vals));
+ if (ret)
+ return ret;
+
+ mt76_init_beacon_offsets(dev);
+
+ mt7601u_wr(dev, MT_AUX_CLK_CFG, 0);
+
+ return 0;
+}
+
+static int mt7601u_init_wcid_mem(struct mt7601u_dev *dev)
+{
+ u32 *vals;
+ int i, ret;
+
+ vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL);
+ if (!vals)
+ return -ENOMEM;
+
+ for (i = 0; i < N_WCIDS; i++) {
+ vals[i * 2] = 0xffffffff;
+ vals[i * 2 + 1] = 0x00ffffff;
+ }
+
+ ret = mt7601u_burst_write_regs(dev, MT_WCID_ADDR_BASE,
+ vals, N_WCIDS * 2);
+ kfree(vals);
+
+ return ret;
+}
+
+static int mt7601u_init_key_mem(struct mt7601u_dev *dev)
+{
+ u32 vals[4] = {};
+
+ return mt7601u_burst_write_regs(dev, MT_SKEY_MODE_BASE_0,
+ vals, ARRAY_SIZE(vals));
+}
+
+static int mt7601u_init_wcid_attr_mem(struct mt7601u_dev *dev)
+{
+ u32 *vals;
+ int i, ret;
+
+ vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL);
+ if (!vals)
+ return -ENOMEM;
+
+ for (i = 0; i < N_WCIDS * 2; i++)
+ vals[i] = 1;
+
+ ret = mt7601u_burst_write_regs(dev, MT_WCID_ATTR_BASE,
+ vals, N_WCIDS * 2);
+ kfree(vals);
+
+ return ret;
+}
+
+static void mt7601u_reset_counters(struct mt7601u_dev *dev)
+{
+ mt7601u_rr(dev, MT_RX_STA_CNT0);
+ mt7601u_rr(dev, MT_RX_STA_CNT1);
+ mt7601u_rr(dev, MT_RX_STA_CNT2);
+ mt7601u_rr(dev, MT_TX_STA_CNT0);
+ mt7601u_rr(dev, MT_TX_STA_CNT1);
+ mt7601u_rr(dev, MT_TX_STA_CNT2);
+}
+
+int mt7601u_mac_start(struct mt7601u_dev *dev)
+{
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
+
+ if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
+ MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 200000))
+ return -ETIMEDOUT;
+
+ dev->rxfilter = MT_RX_FILTR_CFG_CRC_ERR |
+ MT_RX_FILTR_CFG_PHY_ERR | MT_RX_FILTR_CFG_PROMISC |
+ MT_RX_FILTR_CFG_VER_ERR | MT_RX_FILTR_CFG_DUP |
+ MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_CFEND |
+ MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS |
+ MT_RX_FILTR_CFG_RTS | MT_RX_FILTR_CFG_PSPOLL |
+ MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV;
+ mt7601u_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
+
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL,
+ MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
+
+ if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
+ MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 50))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static void mt7601u_mac_stop_hw(struct mt7601u_dev *dev)
+{
+ int i, ok;
+
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return;
+
+ mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN |
+ MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN |
+ MT_BEACON_TIME_CFG_BEACON_TX);
+
+ if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000))
+ dev_warn(dev->dev, "Warning: TX DMA did not stop!\n");
+
+ /* Page count on TxQ */
+ i = 200;
+ while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) ||
+ (mt76_rr(dev, 0x0a30) & 0x000000ff) ||
+ (mt76_rr(dev, 0x0a34) & 0x00ff00ff)))
+ msleep(10);
+
+ if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000))
+ dev_warn(dev->dev, "Warning: MAC TX did not stop!\n");
+
+ mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX |
+ MT_MAC_SYS_CTRL_ENABLE_TX);
+
+ /* Page count on RxQ */
+ ok = 0;
+ i = 200;
+ while (i--) {
+ if ((mt76_rr(dev, 0x0430) & 0x00ff0000) ||
+ (mt76_rr(dev, 0x0a30) & 0xffffffff) ||
+ (mt76_rr(dev, 0x0a34) & 0xffffffff))
+ ok++;
+ if (ok > 6)
+ break;
+
+ msleep(1);
+ }
+
+ if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000))
+ dev_warn(dev->dev, "Warning: MAC RX did not stop!\n");
+
+ if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000))
+ dev_warn(dev->dev, "Warning: RX DMA did not stop!\n");
+}
+
+void mt7601u_mac_stop(struct mt7601u_dev *dev)
+{
+ mt7601u_mac_stop_hw(dev);
+ flush_delayed_work(&dev->stat_work);
+ cancel_delayed_work_sync(&dev->stat_work);
+}
+
+static void mt7601u_stop_hardware(struct mt7601u_dev *dev)
+{
+ mt7601u_chip_onoff(dev, false, false);
+}
+
+int mt7601u_init_hardware(struct mt7601u_dev *dev)
+{
+ static const u16 beacon_offsets[16] = {
+ /* 512 byte per beacon */
+ 0xc000, 0xc200, 0xc400, 0xc600,
+ 0xc800, 0xca00, 0xcc00, 0xce00,
+ 0xd000, 0xd200, 0xd400, 0xd600,
+ 0xd800, 0xda00, 0xdc00, 0xde00
+ };
+ int ret;
+
+ dev->beacon_offsets = beacon_offsets;
+
+ mt7601u_chip_onoff(dev, true, false);
+
+ ret = mt7601u_wait_asic_ready(dev);
+ if (ret)
+ goto err;
+ ret = mt7601u_mcu_init(dev);
+ if (ret)
+ goto err;
+
+ if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG,
+ MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
+ MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) {
+ ret = -EIO;
+ goto err;
+ }
+
+ /* Wait for ASIC ready after FW load. */
+ ret = mt7601u_wait_asic_ready(dev);
+ if (ret)
+ goto err;
+
+ mt7601u_reset_csr_bbp(dev);
+ mt7601u_init_usb_dma(dev);
+
+ ret = mt7601u_mcu_cmd_init(dev);
+ if (ret)
+ goto err;
+ ret = mt7601u_dma_init(dev);
+ if (ret)
+ goto err_mcu;
+ ret = mt7601u_write_mac_initvals(dev);
+ if (ret)
+ goto err_rx;
+
+ if (!mt76_poll_msec(dev, MT_MAC_STATUS,
+ MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 100)) {
+ ret = -EIO;
+ goto err_rx;
+ }
+
+ ret = mt7601u_init_bbp(dev);
+ if (ret)
+ goto err_rx;
+ ret = mt7601u_init_wcid_mem(dev);
+ if (ret)
+ goto err_rx;
+ ret = mt7601u_init_key_mem(dev);
+ if (ret)
+ goto err_rx;
+ ret = mt7601u_init_wcid_attr_mem(dev);
+ if (ret)
+ goto err_rx;
+
+ mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
+ MT_BEACON_TIME_CFG_SYNC_MODE |
+ MT_BEACON_TIME_CFG_TBTT_EN |
+ MT_BEACON_TIME_CFG_BEACON_TX));
+
+ mt7601u_reset_counters(dev);
+
+ mt7601u_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);
+
+ mt7601u_wr(dev, MT_TXOP_CTRL_CFG, MT76_SET(MT_TXOP_TRUN_EN, 0x3f) |
+ MT76_SET(MT_TXOP_EXT_CCA_DLY, 0x58));
+
+ ret = mt7601u_eeprom_init(dev);
+ if (ret)
+ goto err_rx;
+
+ ret = mt7601u_phy_init(dev);
+ if (ret)
+ goto err_rx;
+
+ mt7601u_set_rx_path(dev, 0);
+ mt7601u_set_tx_dac(dev, 0);
+
+ mt7601u_mac_set_ctrlch(dev, false);
+ mt7601u_bbp_set_ctrlch(dev, false);
+ mt7601u_bbp_set_bw(dev, MT_BW_20);
+
+ return 0;
+
+err_rx:
+ mt7601u_dma_cleanup(dev);
+err_mcu:
+ mt7601u_mcu_cmd_deinit(dev);
+err:
+ mt7601u_chip_onoff(dev, false, false);
+ return ret;
+}
+
+void mt7601u_cleanup(struct mt7601u_dev *dev)
+{
+ if (!test_and_clear_bit(MT7601U_STATE_INITIALIZED, &dev->state))
+ return;
+
+ mt7601u_stop_hardware(dev);
+ mt7601u_dma_cleanup(dev);
+ mt7601u_mcu_cmd_deinit(dev);
+}
+
+struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev)
+{
+ struct ieee80211_hw *hw;
+ struct mt7601u_dev *dev;
+
+ hw = ieee80211_alloc_hw(sizeof(*dev), &mt7601u_ops);
+ if (!hw)
+ return NULL;
+
+ dev = hw->priv;
+ dev->dev = pdev;
+ dev->hw = hw;
+ mutex_init(&dev->vendor_req_mutex);
+ mutex_init(&dev->reg_atomic_mutex);
+ mutex_init(&dev->hw_atomic_mutex);
+ mutex_init(&dev->mutex);
+ spin_lock_init(&dev->tx_lock);
+ spin_lock_init(&dev->rx_lock);
+ spin_lock_init(&dev->lock);
+ spin_lock_init(&dev->con_mon_lock);
+ atomic_set(&dev->avg_ampdu_len, 1);
+
+ dev->stat_wq = alloc_workqueue("mt7601u", WQ_UNBOUND, 0);
+ if (!dev->stat_wq) {
+ ieee80211_free_hw(hw);
+ return NULL;
+ }
+
+ return dev;
+}
+
+#define CHAN2G(_idx, _freq) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_idx), \
+ .max_power = 30, \
+}
+
+static const struct ieee80211_channel mt76_channels_2ghz[] = {
+ CHAN2G(1, 2412),
+ CHAN2G(2, 2417),
+ CHAN2G(3, 2422),
+ CHAN2G(4, 2427),
+ CHAN2G(5, 2432),
+ CHAN2G(6, 2437),
+ CHAN2G(7, 2442),
+ CHAN2G(8, 2447),
+ CHAN2G(9, 2452),
+ CHAN2G(10, 2457),
+ CHAN2G(11, 2462),
+ CHAN2G(12, 2467),
+ CHAN2G(13, 2472),
+ CHAN2G(14, 2484),
+};
+
+#define CCK_RATE(_idx, _rate) { \
+ .bitrate = _rate, \
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE, \
+ .hw_value = (MT_PHY_TYPE_CCK << 8) | _idx, \
+ .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + _idx), \
+}
+
+#define OFDM_RATE(_idx, _rate) { \
+ .bitrate = _rate, \
+ .hw_value = (MT_PHY_TYPE_OFDM << 8) | _idx, \
+ .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | _idx, \
+}
+
+static struct ieee80211_rate mt76_rates[] = {
+ CCK_RATE(0, 10),
+ CCK_RATE(1, 20),
+ CCK_RATE(2, 55),
+ CCK_RATE(3, 110),
+ OFDM_RATE(0, 60),
+ OFDM_RATE(1, 90),
+ OFDM_RATE(2, 120),
+ OFDM_RATE(3, 180),
+ OFDM_RATE(4, 240),
+ OFDM_RATE(5, 360),
+ OFDM_RATE(6, 480),
+ OFDM_RATE(7, 540),
+};
+
+static int
+mt76_init_sband(struct mt7601u_dev *dev, struct ieee80211_supported_band *sband,
+ const struct ieee80211_channel *chan, int n_chan,
+ struct ieee80211_rate *rates, int n_rates)
+{
+ struct ieee80211_sta_ht_cap *ht_cap;
+ void *chanlist;
+ int size;
+
+ size = n_chan * sizeof(*chan);
+ chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
+ if (!chanlist)
+ return -ENOMEM;
+
+ sband->channels = chanlist;
+ sband->n_channels = n_chan;
+ sband->bitrates = rates;
+ sband->n_bitrates = n_rates;
+
+ ht_cap = &sband->ht_cap;
+ ht_cap->ht_supported = true;
+ ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_GRN_FLD |
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_SGI_40 |
+ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+
+ ht_cap->mcs.rx_mask[0] = 0xff;
+ ht_cap->mcs.rx_mask[4] = 0x1;
+ ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+ ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_2;
+
+ dev->chandef.chan = &sband->channels[0];
+
+ return 0;
+}
+
+static int
+mt76_init_sband_2g(struct mt7601u_dev *dev)
+{
+ dev->sband_2g = devm_kzalloc(dev->dev, sizeof(*dev->sband_2g),
+ GFP_KERNEL);
+ dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = dev->sband_2g;
+
+ WARN_ON(dev->ee->reg.start - 1 + dev->ee->reg.num >
+ ARRAY_SIZE(mt76_channels_2ghz));
+
+ return mt76_init_sband(dev, dev->sband_2g,
+ &mt76_channels_2ghz[dev->ee->reg.start - 1],
+ dev->ee->reg.num,
+ mt76_rates, ARRAY_SIZE(mt76_rates));
+}
+
+int mt7601u_register_device(struct mt7601u_dev *dev)
+{
+ struct ieee80211_hw *hw = dev->hw;
+ struct wiphy *wiphy = hw->wiphy;
+ int ret;
+
+ /* Reserve WCID 0 for mcast - thanks to this APs WCID will go to
+ * entry no. 1 like it does in the vendor driver.
+ */
+ dev->wcid_mask[0] |= 1;
+
+ /* init fake wcid for monitor interfaces */
+ dev->mon_wcid = devm_kmalloc(dev->dev, sizeof(*dev->mon_wcid),
+ GFP_KERNEL);
+ if (!dev->mon_wcid)
+ return -ENOMEM;
+ dev->mon_wcid->idx = 0xff;
+ dev->mon_wcid->hw_key_idx = -1;
+
+ SET_IEEE80211_DEV(hw, dev->dev);
+
+ hw->queues = 4;
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
+ hw->max_rates = 1;
+ hw->max_report_rates = 7;
+ hw->max_rate_tries = 1;
+
+ hw->sta_data_size = sizeof(struct mt76_sta);
+ hw->vif_data_size = sizeof(struct mt76_vif);
+
+ SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
+
+ wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
+ ret = mt76_init_sband_2g(dev);
+ if (ret)
+ return ret;
+
+ INIT_DELAYED_WORK(&dev->mac_work, mt7601u_mac_work);
+ INIT_DELAYED_WORK(&dev->stat_work, mt7601u_tx_stat);
+
+ ret = ieee80211_register_hw(hw);
+ if (ret)
+ return ret;
+
+ mt7601u_init_debugfs(dev);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/initvals.h b/drivers/net/wireless/mediatek/mt7601u/initvals.h
new file mode 100644
index 000000000000..ec11ff66969d
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/initvals.h
@@ -0,0 +1,164 @@
+/*
+ * (c) Copyright 2002-2010, Ralink Technology, Inc.
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#ifndef __MT7601U_INITVALS_H
+#define __MT7601U_INITVALS_H
+
+static const struct mt76_reg_pair bbp_common_vals[] = {
+ { 65, 0x2c },
+ { 66, 0x38 },
+ { 68, 0x0b },
+ { 69, 0x12 },
+ { 70, 0x0a },
+ { 73, 0x10 },
+ { 81, 0x37 },
+ { 82, 0x62 },
+ { 83, 0x6a },
+ { 84, 0x99 },
+ { 86, 0x00 },
+ { 91, 0x04 },
+ { 92, 0x00 },
+ { 103, 0x00 },
+ { 105, 0x05 },
+ { 106, 0x35 },
+};
+
+static const struct mt76_reg_pair bbp_chip_vals[] = {
+ { 1, 0x04 }, { 4, 0x40 }, { 20, 0x06 }, { 31, 0x08 },
+ /* CCK Tx Control */
+ { 178, 0xff },
+ /* AGC/Sync controls */
+ { 66, 0x14 }, { 68, 0x8b }, { 69, 0x12 }, { 70, 0x09 },
+ { 73, 0x11 }, { 75, 0x60 }, { 76, 0x44 }, { 84, 0x9a },
+ { 86, 0x38 }, { 91, 0x07 }, { 92, 0x02 },
+ /* Rx Path Controls */
+ { 99, 0x50 }, { 101, 0x00 }, { 103, 0xc0 }, { 104, 0x92 },
+ { 105, 0x3c }, { 106, 0x03 }, { 128, 0x12 },
+ /* Change RXWI content: Gain Report */
+ { 142, 0x04 }, { 143, 0x37 },
+ /* Change RXWI content: Antenna Report */
+ { 142, 0x03 }, { 143, 0x99 },
+ /* Calibration Index Register */
+ /* CCK Receiver Control */
+ { 160, 0xeb }, { 161, 0xc4 }, { 162, 0x77 }, { 163, 0xf9 },
+ { 164, 0x88 }, { 165, 0x80 }, { 166, 0xff }, { 167, 0xe4 },
+ /* Added AGC controls - these AGC/GLRT registers are accessed
+ * through R195 and R196.
+ */
+ { 195, 0x00 }, { 196, 0x00 },
+ { 195, 0x01 }, { 196, 0x04 },
+ { 195, 0x02 }, { 196, 0x20 },
+ { 195, 0x03 }, { 196, 0x0a },
+ { 195, 0x06 }, { 196, 0x16 },
+ { 195, 0x07 }, { 196, 0x05 },
+ { 195, 0x08 }, { 196, 0x37 },
+ { 195, 0x0a }, { 196, 0x15 },
+ { 195, 0x0b }, { 196, 0x17 },
+ { 195, 0x0c }, { 196, 0x06 },
+ { 195, 0x0d }, { 196, 0x09 },
+ { 195, 0x0e }, { 196, 0x05 },
+ { 195, 0x0f }, { 196, 0x09 },
+ { 195, 0x10 }, { 196, 0x20 },
+ { 195, 0x20 }, { 196, 0x17 },
+ { 195, 0x21 }, { 196, 0x06 },
+ { 195, 0x22 }, { 196, 0x09 },
+ { 195, 0x23 }, { 196, 0x17 },
+ { 195, 0x24 }, { 196, 0x06 },
+ { 195, 0x25 }, { 196, 0x09 },
+ { 195, 0x26 }, { 196, 0x17 },
+ { 195, 0x27 }, { 196, 0x06 },
+ { 195, 0x28 }, { 196, 0x09 },
+ { 195, 0x29 }, { 196, 0x05 },
+ { 195, 0x2a }, { 196, 0x09 },
+ { 195, 0x80 }, { 196, 0x8b },
+ { 195, 0x81 }, { 196, 0x12 },
+ { 195, 0x82 }, { 196, 0x09 },
+ { 195, 0x83 }, { 196, 0x17 },
+ { 195, 0x84 }, { 196, 0x11 },
+ { 195, 0x85 }, { 196, 0x00 },
+ { 195, 0x86 }, { 196, 0x00 },
+ { 195, 0x87 }, { 196, 0x18 },
+ { 195, 0x88 }, { 196, 0x60 },
+ { 195, 0x89 }, { 196, 0x44 },
+ { 195, 0x8a }, { 196, 0x8b },
+ { 195, 0x8b }, { 196, 0x8b },
+ { 195, 0x8c }, { 196, 0x8b },
+ { 195, 0x8d }, { 196, 0x8b },
+ { 195, 0x8e }, { 196, 0x09 },
+ { 195, 0x8f }, { 196, 0x09 },
+ { 195, 0x90 }, { 196, 0x09 },
+ { 195, 0x91 }, { 196, 0x09 },
+ { 195, 0x92 }, { 196, 0x11 },
+ { 195, 0x93 }, { 196, 0x11 },
+ { 195, 0x94 }, { 196, 0x11 },
+ { 195, 0x95 }, { 196, 0x11 },
+ /* PPAD */
+ { 47, 0x80 }, { 60, 0x80 }, { 150, 0xd2 }, { 151, 0x32 },
+ { 152, 0x23 }, { 153, 0x41 }, { 154, 0x00 }, { 155, 0x4f },
+ { 253, 0x7e }, { 195, 0x30 }, { 196, 0x32 }, { 195, 0x31 },
+ { 196, 0x23 }, { 195, 0x32 }, { 196, 0x45 }, { 195, 0x35 },
+ { 196, 0x4a }, { 195, 0x36 }, { 196, 0x5a }, { 195, 0x37 },
+ { 196, 0x5a },
+};
+
+static const struct mt76_reg_pair mac_common_vals[] = {
+ { MT_LEGACY_BASIC_RATE, 0x0000013f },
+ { MT_HT_BASIC_RATE, 0x00008003 },
+ { MT_MAC_SYS_CTRL, 0x00000000 },
+ { MT_RX_FILTR_CFG, 0x00017f97 },
+ { MT_BKOFF_SLOT_CFG, 0x00000209 },
+ { MT_TX_SW_CFG0, 0x00000000 },
+ { MT_TX_SW_CFG1, 0x00080606 },
+ { MT_TX_LINK_CFG, 0x00001020 },
+ { MT_TX_TIMEOUT_CFG, 0x000a2090 },
+ { MT_MAX_LEN_CFG, 0x00003fff },
+ { MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f },
+ { MT_PBF_RX_MAX_PCNT, 0x0000009f },
+ { MT_TX_RETRY_CFG, 0x47d01f0f },
+ { MT_AUTO_RSP_CFG, 0x00000013 },
+ { MT_CCK_PROT_CFG, 0x05740003 },
+ { MT_OFDM_PROT_CFG, 0x05740003 },
+ { MT_MM40_PROT_CFG, 0x03f44084 },
+ { MT_GF20_PROT_CFG, 0x01744004 },
+ { MT_GF40_PROT_CFG, 0x03f44084 },
+ { MT_MM20_PROT_CFG, 0x01744004 },
+ { MT_TXOP_CTRL_CFG, 0x0000583f },
+ { MT_TX_RTS_CFG, 0x01092b20 },
+ { MT_EXP_ACK_TIME, 0x002400ca },
+ { MT_TXOP_HLDR_ET, 0x00000002 },
+ { MT_XIFS_TIME_CFG, 0x33a41010 },
+ { MT_PWR_PIN_CFG, 0x00000000 },
+};
+
+static const struct mt76_reg_pair mac_chip_vals[] = {
+ { MT_TSO_CTRL, 0x00006050 },
+ { MT_BCN_OFFSET(0), 0x18100800 },
+ { MT_BCN_OFFSET(1), 0x38302820 },
+ { MT_PBF_SYS_CTRL, 0x00080c00 },
+ { MT_PBF_CFG, 0x7f723c1f },
+ { MT_FCE_PSE_CTRL, 0x00000001 },
+ { MT_PAUSE_ENABLE_CONTROL1, 0x00000000 },
+ { MT_TX0_RF_GAIN_CORR, 0x003b0005 },
+ { MT_TX0_RF_GAIN_ATTEN, 0x00006900 },
+ { MT_TX0_BB_GAIN_ATTEN, 0x00000400 },
+ { MT_TX_ALC_VGA3, 0x00060006 },
+ { MT_TX_SW_CFG0, 0x00000402 },
+ { MT_TX_SW_CFG1, 0x00000000 },
+ { MT_TX_SW_CFG2, 0x00000000 },
+ { MT_HEADER_TRANS_CTRL_REG, 0x00000000 },
+ { MT_FCE_CSO, 0x0000030f },
+ { MT_FCE_PARAMETERS, 0x00256f0f },
+};
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/initvals_phy.h b/drivers/net/wireless/mediatek/mt7601u/initvals_phy.h
new file mode 100644
index 000000000000..a2bdc3e322bf
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/initvals_phy.h
@@ -0,0 +1,291 @@
+/*
+ * (c) Copyright 2002-2010, Ralink Technology, Inc.
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#ifndef __MT7601U_PHY_INITVALS_H
+#define __MT7601U_PHY_INITVALS_H
+
+#define RF_REG_PAIR(bank, reg, value) \
+ { MT_MCU_MEMMAP_RF | (bank) << 16 | (reg), value }
+
+static const struct mt76_reg_pair rf_central[] = {
+ /* Bank 0 - for central blocks: BG, PLL, XTAL, LO, ADC/DAC */
+ RF_REG_PAIR(0, 0, 0x02),
+ RF_REG_PAIR(0, 1, 0x01),
+ RF_REG_PAIR(0, 2, 0x11),
+ RF_REG_PAIR(0, 3, 0xff),
+ RF_REG_PAIR(0, 4, 0x0a),
+ RF_REG_PAIR(0, 5, 0x20),
+ RF_REG_PAIR(0, 6, 0x00),
+ /* B/G */
+ RF_REG_PAIR(0, 7, 0x00),
+ RF_REG_PAIR(0, 8, 0x00),
+ RF_REG_PAIR(0, 9, 0x00),
+ RF_REG_PAIR(0, 10, 0x00),
+ RF_REG_PAIR(0, 11, 0x21),
+ /* XO */
+ RF_REG_PAIR(0, 13, 0x00), /* 40mhz xtal */
+ /* RF_REG_PAIR(0, 13, 0x13), */ /* 20mhz xtal */
+ RF_REG_PAIR(0, 14, 0x7c),
+ RF_REG_PAIR(0, 15, 0x22),
+ RF_REG_PAIR(0, 16, 0x80),
+ /* PLL */
+ RF_REG_PAIR(0, 17, 0x99),
+ RF_REG_PAIR(0, 18, 0x99),
+ RF_REG_PAIR(0, 19, 0x09),
+ RF_REG_PAIR(0, 20, 0x50),
+ RF_REG_PAIR(0, 21, 0xb0),
+ RF_REG_PAIR(0, 22, 0x00),
+ RF_REG_PAIR(0, 23, 0xc5),
+ RF_REG_PAIR(0, 24, 0xfc),
+ RF_REG_PAIR(0, 25, 0x40),
+ RF_REG_PAIR(0, 26, 0x4d),
+ RF_REG_PAIR(0, 27, 0x02),
+ RF_REG_PAIR(0, 28, 0x72),
+ RF_REG_PAIR(0, 29, 0x01),
+ RF_REG_PAIR(0, 30, 0x00),
+ RF_REG_PAIR(0, 31, 0x00),
+ /* test ports */
+ RF_REG_PAIR(0, 32, 0x00),
+ RF_REG_PAIR(0, 33, 0x00),
+ RF_REG_PAIR(0, 34, 0x23),
+ RF_REG_PAIR(0, 35, 0x01), /* change setting to reduce spurs */
+ RF_REG_PAIR(0, 36, 0x00),
+ RF_REG_PAIR(0, 37, 0x00),
+ /* ADC/DAC */
+ RF_REG_PAIR(0, 38, 0x00),
+ RF_REG_PAIR(0, 39, 0x20),
+ RF_REG_PAIR(0, 40, 0x00),
+ RF_REG_PAIR(0, 41, 0xd0),
+ RF_REG_PAIR(0, 42, 0x1b),
+ RF_REG_PAIR(0, 43, 0x02),
+ RF_REG_PAIR(0, 44, 0x00),
+};
+
+static const struct mt76_reg_pair rf_channel[] = {
+ RF_REG_PAIR(4, 0, 0x01),
+ RF_REG_PAIR(4, 1, 0x00),
+ RF_REG_PAIR(4, 2, 0x00),
+ RF_REG_PAIR(4, 3, 0x00),
+ /* LDO */
+ RF_REG_PAIR(4, 4, 0x00),
+ RF_REG_PAIR(4, 5, 0x08),
+ RF_REG_PAIR(4, 6, 0x00),
+ /* RX */
+ RF_REG_PAIR(4, 7, 0x5b),
+ RF_REG_PAIR(4, 8, 0x52),
+ RF_REG_PAIR(4, 9, 0xb6),
+ RF_REG_PAIR(4, 10, 0x57),
+ RF_REG_PAIR(4, 11, 0x33),
+ RF_REG_PAIR(4, 12, 0x22),
+ RF_REG_PAIR(4, 13, 0x3d),
+ RF_REG_PAIR(4, 14, 0x3e),
+ RF_REG_PAIR(4, 15, 0x13),
+ RF_REG_PAIR(4, 16, 0x22),
+ RF_REG_PAIR(4, 17, 0x23),
+ RF_REG_PAIR(4, 18, 0x02),
+ RF_REG_PAIR(4, 19, 0xa4),
+ RF_REG_PAIR(4, 20, 0x01),
+ RF_REG_PAIR(4, 21, 0x12),
+ RF_REG_PAIR(4, 22, 0x80),
+ RF_REG_PAIR(4, 23, 0xb3),
+ RF_REG_PAIR(4, 24, 0x00), /* reserved */
+ RF_REG_PAIR(4, 25, 0x00), /* reserved */
+ RF_REG_PAIR(4, 26, 0x00), /* reserved */
+ RF_REG_PAIR(4, 27, 0x00), /* reserved */
+ /* LOGEN */
+ RF_REG_PAIR(4, 28, 0x18),
+ RF_REG_PAIR(4, 29, 0xee),
+ RF_REG_PAIR(4, 30, 0x6b),
+ RF_REG_PAIR(4, 31, 0x31),
+ RF_REG_PAIR(4, 32, 0x5d),
+ RF_REG_PAIR(4, 33, 0x00), /* reserved */
+ /* TX */
+ RF_REG_PAIR(4, 34, 0x96),
+ RF_REG_PAIR(4, 35, 0x55),
+ RF_REG_PAIR(4, 36, 0x08),
+ RF_REG_PAIR(4, 37, 0xbb),
+ RF_REG_PAIR(4, 38, 0xb3),
+ RF_REG_PAIR(4, 39, 0xb3),
+ RF_REG_PAIR(4, 40, 0x03),
+ RF_REG_PAIR(4, 41, 0x00), /* reserved */
+ RF_REG_PAIR(4, 42, 0x00), /* reserved */
+ RF_REG_PAIR(4, 43, 0xc5),
+ RF_REG_PAIR(4, 44, 0xc5),
+ RF_REG_PAIR(4, 45, 0xc5),
+ RF_REG_PAIR(4, 46, 0x07),
+ RF_REG_PAIR(4, 47, 0xa8),
+ RF_REG_PAIR(4, 48, 0xef),
+ RF_REG_PAIR(4, 49, 0x1a),
+ /* PA */
+ RF_REG_PAIR(4, 54, 0x07),
+ RF_REG_PAIR(4, 55, 0xa7),
+ RF_REG_PAIR(4, 56, 0xcc),
+ RF_REG_PAIR(4, 57, 0x14),
+ RF_REG_PAIR(4, 58, 0x07),
+ RF_REG_PAIR(4, 59, 0xa8),
+ RF_REG_PAIR(4, 60, 0xd7),
+ RF_REG_PAIR(4, 61, 0x10),
+ RF_REG_PAIR(4, 62, 0x1c),
+ RF_REG_PAIR(4, 63, 0x00), /* reserved */
+};
+
+static const struct mt76_reg_pair rf_vga[] = {
+ RF_REG_PAIR(5, 0, 0x47),
+ RF_REG_PAIR(5, 1, 0x00),
+ RF_REG_PAIR(5, 2, 0x00),
+ RF_REG_PAIR(5, 3, 0x08),
+ RF_REG_PAIR(5, 4, 0x04),
+ RF_REG_PAIR(5, 5, 0x20),
+ RF_REG_PAIR(5, 6, 0x3a),
+ RF_REG_PAIR(5, 7, 0x3a),
+ RF_REG_PAIR(5, 8, 0x00),
+ RF_REG_PAIR(5, 9, 0x00),
+ RF_REG_PAIR(5, 10, 0x10),
+ RF_REG_PAIR(5, 11, 0x10),
+ RF_REG_PAIR(5, 12, 0x10),
+ RF_REG_PAIR(5, 13, 0x10),
+ RF_REG_PAIR(5, 14, 0x10),
+ RF_REG_PAIR(5, 15, 0x20),
+ RF_REG_PAIR(5, 16, 0x22),
+ RF_REG_PAIR(5, 17, 0x7c),
+ RF_REG_PAIR(5, 18, 0x00),
+ RF_REG_PAIR(5, 19, 0x00),
+ RF_REG_PAIR(5, 20, 0x00),
+ RF_REG_PAIR(5, 21, 0xf1),
+ RF_REG_PAIR(5, 22, 0x11),
+ RF_REG_PAIR(5, 23, 0x02),
+ RF_REG_PAIR(5, 24, 0x41),
+ RF_REG_PAIR(5, 25, 0x20),
+ RF_REG_PAIR(5, 26, 0x00),
+ RF_REG_PAIR(5, 27, 0xd7),
+ RF_REG_PAIR(5, 28, 0xa2),
+ RF_REG_PAIR(5, 29, 0x20),
+ RF_REG_PAIR(5, 30, 0x49),
+ RF_REG_PAIR(5, 31, 0x20),
+ RF_REG_PAIR(5, 32, 0x04),
+ RF_REG_PAIR(5, 33, 0xf1),
+ RF_REG_PAIR(5, 34, 0xa1),
+ RF_REG_PAIR(5, 35, 0x01),
+ RF_REG_PAIR(5, 41, 0x00),
+ RF_REG_PAIR(5, 42, 0x00),
+ RF_REG_PAIR(5, 43, 0x00),
+ RF_REG_PAIR(5, 44, 0x00),
+ RF_REG_PAIR(5, 45, 0x00),
+ RF_REG_PAIR(5, 46, 0x00),
+ RF_REG_PAIR(5, 47, 0x00),
+ RF_REG_PAIR(5, 48, 0x00),
+ RF_REG_PAIR(5, 49, 0x00),
+ RF_REG_PAIR(5, 50, 0x00),
+ RF_REG_PAIR(5, 51, 0x00),
+ RF_REG_PAIR(5, 52, 0x00),
+ RF_REG_PAIR(5, 53, 0x00),
+ RF_REG_PAIR(5, 54, 0x00),
+ RF_REG_PAIR(5, 55, 0x00),
+ RF_REG_PAIR(5, 56, 0x00),
+ RF_REG_PAIR(5, 57, 0x00),
+ RF_REG_PAIR(5, 58, 0x31),
+ RF_REG_PAIR(5, 59, 0x31),
+ RF_REG_PAIR(5, 60, 0x0a),
+ RF_REG_PAIR(5, 61, 0x02),
+ RF_REG_PAIR(5, 62, 0x00),
+ RF_REG_PAIR(5, 63, 0x00),
+};
+
+/* TODO: BBP178 is set to 0xff for "CCK CH14 OBW" which overrides the settings
+ * from channel switching. Seems stupid at best.
+ */
+static const struct mt76_reg_pair bbp_high_temp[] = {
+ { 75, 0x60 },
+ { 92, 0x02 },
+ { 178, 0xff }, /* For CCK CH14 OBW */
+ { 195, 0x88 }, { 196, 0x60 },
+}, bbp_high_temp_bw20[] = {
+ { 69, 0x12 },
+ { 91, 0x07 },
+ { 195, 0x23 }, { 196, 0x17 },
+ { 195, 0x24 }, { 196, 0x06 },
+ { 195, 0x81 }, { 196, 0x12 },
+ { 195, 0x83 }, { 196, 0x17 },
+}, bbp_high_temp_bw40[] = {
+ { 69, 0x15 },
+ { 91, 0x04 },
+ { 195, 0x23 }, { 196, 0x12 },
+ { 195, 0x24 }, { 196, 0x08 },
+ { 195, 0x81 }, { 196, 0x15 },
+ { 195, 0x83 }, { 196, 0x16 },
+}, bbp_low_temp[] = {
+ { 178, 0xff }, /* For CCK CH14 OBW */
+}, bbp_low_temp_bw20[] = {
+ { 69, 0x12 },
+ { 75, 0x5e },
+ { 91, 0x07 },
+ { 92, 0x02 },
+ { 195, 0x23 }, { 196, 0x17 },
+ { 195, 0x24 }, { 196, 0x06 },
+ { 195, 0x81 }, { 196, 0x12 },
+ { 195, 0x83 }, { 196, 0x17 },
+ { 195, 0x88 }, { 196, 0x5e },
+}, bbp_low_temp_bw40[] = {
+ { 69, 0x15 },
+ { 75, 0x5c },
+ { 91, 0x04 },
+ { 92, 0x03 },
+ { 195, 0x23 }, { 196, 0x10 },
+ { 195, 0x24 }, { 196, 0x08 },
+ { 195, 0x81 }, { 196, 0x15 },
+ { 195, 0x83 }, { 196, 0x16 },
+ { 195, 0x88 }, { 196, 0x5b },
+}, bbp_normal_temp[] = {
+ { 75, 0x60 },
+ { 92, 0x02 },
+ { 178, 0xff }, /* For CCK CH14 OBW */
+ { 195, 0x88 }, { 196, 0x60 },
+}, bbp_normal_temp_bw20[] = {
+ { 69, 0x12 },
+ { 91, 0x07 },
+ { 195, 0x23 }, { 196, 0x17 },
+ { 195, 0x24 }, { 196, 0x06 },
+ { 195, 0x81 }, { 196, 0x12 },
+ { 195, 0x83 }, { 196, 0x17 },
+}, bbp_normal_temp_bw40[] = {
+ { 69, 0x15 },
+ { 91, 0x04 },
+ { 195, 0x23 }, { 196, 0x12 },
+ { 195, 0x24 }, { 196, 0x08 },
+ { 195, 0x81 }, { 196, 0x15 },
+ { 195, 0x83 }, { 196, 0x16 },
+};
+
+#define BBP_TABLE(arr) { arr, ARRAY_SIZE(arr), }
+
+static const struct reg_table {
+ const struct mt76_reg_pair *regs;
+ size_t n;
+} bbp_mode_table[3][3] = {
+ {
+ BBP_TABLE(bbp_normal_temp_bw20),
+ BBP_TABLE(bbp_normal_temp_bw40),
+ BBP_TABLE(bbp_normal_temp),
+ }, {
+ BBP_TABLE(bbp_high_temp_bw20),
+ BBP_TABLE(bbp_high_temp_bw40),
+ BBP_TABLE(bbp_high_temp),
+ }, {
+ BBP_TABLE(bbp_low_temp_bw20),
+ BBP_TABLE(bbp_low_temp_bw40),
+ BBP_TABLE(bbp_low_temp),
+ }
+};
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c
new file mode 100644
index 000000000000..7514bce1ac91
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/mac.c
@@ -0,0 +1,573 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include "mt7601u.h"
+#include "trace.h"
+#include <linux/etherdevice.h>
+
+static void
+mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate)
+{
+ u8 idx = MT76_GET(MT_TXWI_RATE_MCS, rate);
+
+ txrate->idx = 0;
+ txrate->flags = 0;
+ txrate->count = 1;
+
+ switch (MT76_GET(MT_TXWI_RATE_PHY_MODE, rate)) {
+ case MT_PHY_TYPE_OFDM:
+ txrate->idx = idx + 4;
+ return;
+ case MT_PHY_TYPE_CCK:
+ if (idx >= 8)
+ idx -= 8;
+
+ txrate->idx = idx;
+ return;
+ case MT_PHY_TYPE_HT_GF:
+ txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
+ /* fall through */
+ case MT_PHY_TYPE_HT:
+ txrate->flags |= IEEE80211_TX_RC_MCS;
+ txrate->idx = idx;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ if (MT76_GET(MT_TXWI_RATE_BW, rate) == MT_PHY_BW_40)
+ txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+
+ if (rate & MT_TXWI_RATE_SGI)
+ txrate->flags |= IEEE80211_TX_RC_SHORT_GI;
+}
+
+static void
+mt76_mac_fill_tx_status(struct mt7601u_dev *dev, struct ieee80211_tx_info *info,
+ struct mt76_tx_status *st)
+{
+ struct ieee80211_tx_rate *rate = info->status.rates;
+ int cur_idx, last_rate;
+ int i;
+
+ last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1);
+ mt76_mac_process_tx_rate(&rate[last_rate], st->rate);
+ if (last_rate < IEEE80211_TX_MAX_RATES - 1)
+ rate[last_rate + 1].idx = -1;
+
+ cur_idx = rate[last_rate].idx + st->retry;
+ for (i = 0; i <= last_rate; i++) {
+ rate[i].flags = rate[last_rate].flags;
+ rate[i].idx = max_t(int, 0, cur_idx - i);
+ rate[i].count = 1;
+ }
+
+ if (last_rate > 0)
+ rate[last_rate - 1].count = st->retry + 1 - last_rate;
+
+ info->status.ampdu_len = 1;
+ info->status.ampdu_ack_len = st->success;
+
+ if (st->is_probe)
+ info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+
+ if (st->aggr)
+ info->flags |= IEEE80211_TX_CTL_AMPDU |
+ IEEE80211_TX_STAT_AMPDU;
+
+ if (!st->ack_req)
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ else if (st->success)
+ info->flags |= IEEE80211_TX_STAT_ACK;
+}
+
+u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev,
+ const struct ieee80211_tx_rate *rate, u8 *nss_val)
+{
+ u16 rateval;
+ u8 phy, rate_idx;
+ u8 nss = 1;
+ u8 bw = 0;
+
+ if (rate->flags & IEEE80211_TX_RC_MCS) {
+ rate_idx = rate->idx;
+ nss = 1 + (rate->idx >> 3);
+ phy = MT_PHY_TYPE_HT;
+ if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
+ phy = MT_PHY_TYPE_HT_GF;
+ if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ bw = 1;
+ } else {
+ const struct ieee80211_rate *r;
+ int band = dev->chandef.chan->band;
+ u16 val;
+
+ r = &dev->hw->wiphy->bands[band]->bitrates[rate->idx];
+ if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+ val = r->hw_value_short;
+ else
+ val = r->hw_value;
+
+ phy = val >> 8;
+ rate_idx = val & 0xff;
+ bw = 0;
+ }
+
+ rateval = MT76_SET(MT_RXWI_RATE_MCS, rate_idx);
+ rateval |= MT76_SET(MT_RXWI_RATE_PHY, phy);
+ rateval |= MT76_SET(MT_RXWI_RATE_BW, bw);
+ if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+ rateval |= MT_RXWI_RATE_SGI;
+
+ *nss_val = nss;
+ return rateval;
+}
+
+void mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid,
+ const struct ieee80211_tx_rate *rate)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ wcid->tx_rate = mt76_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss);
+ wcid->tx_rate_set = true;
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+struct mt76_tx_status mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev)
+{
+ struct mt76_tx_status stat = {};
+ u32 val;
+
+ val = mt7601u_rr(dev, MT_TX_STAT_FIFO);
+ stat.valid = !!(val & MT_TX_STAT_FIFO_VALID);
+ stat.success = !!(val & MT_TX_STAT_FIFO_SUCCESS);
+ stat.aggr = !!(val & MT_TX_STAT_FIFO_AGGR);
+ stat.ack_req = !!(val & MT_TX_STAT_FIFO_ACKREQ);
+ stat.pktid = MT76_GET(MT_TX_STAT_FIFO_PID_TYPE, val);
+ stat.wcid = MT76_GET(MT_TX_STAT_FIFO_WCID, val);
+ stat.rate = MT76_GET(MT_TX_STAT_FIFO_RATE, val);
+
+ return stat;
+}
+
+void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat)
+{
+ struct ieee80211_tx_info info = {};
+ struct ieee80211_sta *sta = NULL;
+ struct mt76_wcid *wcid = NULL;
+ void *msta;
+
+ rcu_read_lock();
+ if (stat->wcid < ARRAY_SIZE(dev->wcid))
+ wcid = rcu_dereference(dev->wcid[stat->wcid]);
+
+ if (wcid) {
+ msta = container_of(wcid, struct mt76_sta, wcid);
+ sta = container_of(msta, struct ieee80211_sta,
+ drv_priv);
+ }
+
+ mt76_mac_fill_tx_status(dev, &info, stat);
+ ieee80211_tx_status_noskb(dev->hw, sta, &info);
+ rcu_read_unlock();
+}
+
+void mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot,
+ int ht_mode)
+{
+ int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION;
+ bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+ u32 prot[6];
+ bool ht_rts[4] = {};
+ int i;
+
+ prot[0] = MT_PROT_NAV_SHORT |
+ MT_PROT_TXOP_ALLOW_ALL |
+ MT_PROT_RTS_THR_EN;
+ prot[1] = prot[0];
+ if (legacy_prot)
+ prot[1] |= MT_PROT_CTRL_CTS2SELF;
+
+ prot[2] = prot[4] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_BW20;
+ prot[3] = prot[5] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_ALL;
+
+ if (legacy_prot) {
+ prot[2] |= MT_PROT_RATE_CCK_11;
+ prot[3] |= MT_PROT_RATE_CCK_11;
+ prot[4] |= MT_PROT_RATE_CCK_11;
+ prot[5] |= MT_PROT_RATE_CCK_11;
+ } else {
+ prot[2] |= MT_PROT_RATE_OFDM_24;
+ prot[3] |= MT_PROT_RATE_DUP_OFDM_24;
+ prot[4] |= MT_PROT_RATE_OFDM_24;
+ prot[5] |= MT_PROT_RATE_DUP_OFDM_24;
+ }
+
+ switch (mode) {
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
+ break;
+
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
+ ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true;
+ break;
+
+ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
+ ht_rts[1] = ht_rts[3] = true;
+ break;
+
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
+ ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true;
+ break;
+ }
+
+ if (non_gf)
+ ht_rts[2] = ht_rts[3] = true;
+
+ for (i = 0; i < 4; i++)
+ if (ht_rts[i])
+ prot[i + 2] |= MT_PROT_CTRL_RTS_CTS;
+
+ for (i = 0; i < 6; i++)
+ mt7601u_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]);
+}
+
+void mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb)
+{
+ if (short_preamb)
+ mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
+ else
+ mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
+}
+
+void mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval)
+{
+ u32 val = mt7601u_rr(dev, MT_BEACON_TIME_CFG);
+
+ val &= ~(MT_BEACON_TIME_CFG_TIMER_EN |
+ MT_BEACON_TIME_CFG_SYNC_MODE |
+ MT_BEACON_TIME_CFG_TBTT_EN);
+
+ if (!enable) {
+ mt7601u_wr(dev, MT_BEACON_TIME_CFG, val);
+ return;
+ }
+
+ val &= ~MT_BEACON_TIME_CFG_INTVAL;
+ val |= MT76_SET(MT_BEACON_TIME_CFG_INTVAL, interval << 4) |
+ MT_BEACON_TIME_CFG_TIMER_EN |
+ MT_BEACON_TIME_CFG_SYNC_MODE |
+ MT_BEACON_TIME_CFG_TBTT_EN;
+}
+
+static void mt7601u_check_mac_err(struct mt7601u_dev *dev)
+{
+ u32 val = mt7601u_rr(dev, 0x10f4);
+
+ if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5))))
+ return;
+
+ dev_err(dev->dev, "Error: MAC specific condition occurred\n");
+
+ mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
+ udelay(10);
+ mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
+}
+
+void mt7601u_mac_work(struct work_struct *work)
+{
+ struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev,
+ mac_work.work);
+ struct {
+ u32 addr_base;
+ u32 span;
+ u64 *stat_base;
+ } spans[] = {
+ { MT_RX_STA_CNT0, 3, dev->stats.rx_stat },
+ { MT_TX_STA_CNT0, 3, dev->stats.tx_stat },
+ { MT_TX_AGG_STAT, 1, dev->stats.aggr_stat },
+ { MT_MPDU_DENSITY_CNT, 1, dev->stats.zero_len_del },
+ { MT_TX_AGG_CNT_BASE0, 8, &dev->stats.aggr_n[0] },
+ { MT_TX_AGG_CNT_BASE1, 8, &dev->stats.aggr_n[16] },
+ };
+ u32 sum, n;
+ int i, j, k;
+
+ /* Note: using MCU_RANDOM_READ is actually slower then reading all the
+ * registers by hand. MCU takes ca. 20ms to complete read of 24
+ * registers while reading them one by one will takes roughly
+ * 24*200us =~ 5ms.
+ */
+
+ k = 0;
+ n = 0;
+ sum = 0;
+ for (i = 0; i < ARRAY_SIZE(spans); i++)
+ for (j = 0; j < spans[i].span; j++) {
+ u32 val = mt7601u_rr(dev, spans[i].addr_base + j * 4);
+
+ spans[i].stat_base[j * 2] += val & 0xffff;
+ spans[i].stat_base[j * 2 + 1] += val >> 16;
+
+ /* Calculate average AMPDU length */
+ if (spans[i].addr_base != MT_TX_AGG_CNT_BASE0 &&
+ spans[i].addr_base != MT_TX_AGG_CNT_BASE1)
+ continue;
+
+ n += (val >> 16) + (val & 0xffff);
+ sum += (val & 0xffff) * (1 + k * 2) +
+ (val >> 16) * (2 + k * 2);
+ k++;
+ }
+
+ atomic_set(&dev->avg_ampdu_len, n ? DIV_ROUND_CLOSEST(sum, n) : 1);
+
+ mt7601u_check_mac_err(dev);
+
+ ieee80211_queue_delayed_work(dev->hw, &dev->mac_work, 10 * HZ);
+}
+
+void
+mt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac)
+{
+ u8 zmac[ETH_ALEN] = {};
+ u32 attr;
+
+ attr = MT76_SET(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) |
+ MT76_SET(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8));
+
+ mt76_wr(dev, MT_WCID_ATTR(idx), attr);
+
+ if (mac)
+ memcpy(zmac, mac, sizeof(zmac));
+
+ mt7601u_addr_wr(dev, MT_WCID_ADDR(idx), zmac);
+}
+
+void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev)
+{
+ struct ieee80211_sta *sta;
+ struct mt76_wcid *wcid;
+ void *msta;
+ u8 min_factor = 3;
+ int i;
+
+ rcu_read_lock();
+ for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) {
+ wcid = rcu_dereference(dev->wcid[i]);
+ if (!wcid)
+ continue;
+
+ msta = container_of(wcid, struct mt76_sta, wcid);
+ sta = container_of(msta, struct ieee80211_sta, drv_priv);
+
+ min_factor = min(min_factor, sta->ht_cap.ampdu_factor);
+ }
+ rcu_read_unlock();
+
+ mt7601u_wr(dev, MT_MAX_LEN_CFG, 0xa0fff |
+ MT76_SET(MT_MAX_LEN_CFG_AMPDU, min_factor));
+}
+
+static void
+mt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate)
+{
+ u8 idx = MT76_GET(MT_RXWI_RATE_MCS, rate);
+
+ switch (MT76_GET(MT_RXWI_RATE_PHY, rate)) {
+ case MT_PHY_TYPE_OFDM:
+ if (WARN_ON(idx >= 8))
+ idx = 0;
+ idx += 4;
+
+ status->rate_idx = idx;
+ return;
+ case MT_PHY_TYPE_CCK:
+ if (idx >= 8) {
+ idx -= 8;
+ status->flag |= RX_FLAG_SHORTPRE;
+ }
+
+ if (WARN_ON(idx >= 4))
+ idx = 0;
+
+ status->rate_idx = idx;
+ return;
+ case MT_PHY_TYPE_HT_GF:
+ status->flag |= RX_FLAG_HT_GF;
+ /* fall through */
+ case MT_PHY_TYPE_HT:
+ status->flag |= RX_FLAG_HT;
+ status->rate_idx = idx;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ if (rate & MT_RXWI_RATE_SGI)
+ status->flag |= RX_FLAG_SHORT_GI;
+
+ if (rate & MT_RXWI_RATE_STBC)
+ status->flag |= 1 << RX_FLAG_STBC_SHIFT;
+
+ if (rate & MT_RXWI_RATE_BW)
+ status->flag |= RX_FLAG_40MHZ;
+}
+
+static void
+mt7601u_rx_monitor_beacon(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi,
+ u16 rate, int rssi)
+{
+ dev->bcn_freq_off = rxwi->freq_off;
+ dev->bcn_phy_mode = MT76_GET(MT_RXWI_RATE_PHY, rate);
+ dev->avg_rssi = (dev->avg_rssi * 15) / 16 + (rssi << 8);
+}
+
+static int
+mt7601u_rx_is_our_beacon(struct mt7601u_dev *dev, u8 *data)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data;
+
+ return ieee80211_is_beacon(hdr->frame_control) &&
+ ether_addr_equal(hdr->addr2, dev->ap_bssid);
+}
+
+u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb,
+ u8 *data, void *rxi)
+{
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+ struct mt7601u_rxwi *rxwi = rxi;
+ u32 len, ctl = le32_to_cpu(rxwi->ctl);
+ u16 rate = le16_to_cpu(rxwi->rate);
+ int rssi;
+
+ len = MT76_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
+ if (len < 10)
+ return 0;
+
+ if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) {
+ status->flag |= RX_FLAG_DECRYPTED;
+ status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
+ }
+
+ status->chains = BIT(0);
+ rssi = mt7601u_phy_get_rssi(dev, rxwi, rate);
+ status->chain_signal[0] = status->signal = rssi;
+ status->freq = dev->chandef.chan->center_freq;
+ status->band = dev->chandef.chan->band;
+
+ mt76_mac_process_rate(status, rate);
+
+ spin_lock_bh(&dev->con_mon_lock);
+ if (mt7601u_rx_is_our_beacon(dev, data))
+ mt7601u_rx_monitor_beacon(dev, rxwi, rate, rssi);
+ else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M))
+ dev->avg_rssi = (dev->avg_rssi * 15) / 16 + (rssi << 8);
+ spin_unlock_bh(&dev->con_mon_lock);
+
+ return len;
+}
+
+static enum mt76_cipher_type
+mt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
+{
+ memset(key_data, 0, 32);
+ if (!key)
+ return MT_CIPHER_NONE;
+
+ if (key->keylen > 32)
+ return MT_CIPHER_NONE;
+
+ memcpy(key_data, key->key, key->keylen);
+
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ return MT_CIPHER_WEP40;
+ case WLAN_CIPHER_SUITE_WEP104:
+ return MT_CIPHER_WEP104;
+ case WLAN_CIPHER_SUITE_TKIP:
+ return MT_CIPHER_TKIP;
+ case WLAN_CIPHER_SUITE_CCMP:
+ return MT_CIPHER_AES_CCMP;
+ default:
+ return MT_CIPHER_NONE;
+ }
+}
+
+int mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx,
+ struct ieee80211_key_conf *key)
+{
+ enum mt76_cipher_type cipher;
+ u8 key_data[32];
+ u8 iv_data[8];
+ u32 val;
+
+ cipher = mt76_mac_get_key_info(key, key_data);
+ if (cipher == MT_CIPHER_NONE && key)
+ return -EINVAL;
+
+ trace_set_key(dev, idx);
+
+ mt7601u_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data));
+
+ memset(iv_data, 0, sizeof(iv_data));
+ if (key) {
+ iv_data[3] = key->keyidx << 6;
+ if (cipher >= MT_CIPHER_TKIP) {
+ /* Note: start with 1 to comply with spec,
+ * (see comment on common/cmm_wpa.c:4291).
+ */
+ iv_data[0] |= 1;
+ iv_data[3] |= 0x20;
+ }
+ }
+ mt7601u_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data));
+
+ val = mt7601u_rr(dev, MT_WCID_ATTR(idx));
+ val &= ~MT_WCID_ATTR_PKEY_MODE & ~MT_WCID_ATTR_PKEY_MODE_EXT;
+ val |= MT76_SET(MT_WCID_ATTR_PKEY_MODE, cipher & 7) |
+ MT76_SET(MT_WCID_ATTR_PKEY_MODE_EXT, cipher >> 3);
+ val &= ~MT_WCID_ATTR_PAIRWISE;
+ val |= MT_WCID_ATTR_PAIRWISE *
+ !!(key && key->flags & IEEE80211_KEY_FLAG_PAIRWISE);
+ mt7601u_wr(dev, MT_WCID_ATTR(idx), val);
+
+ return 0;
+}
+
+int mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx,
+ struct ieee80211_key_conf *key)
+{
+ enum mt76_cipher_type cipher;
+ u8 key_data[32];
+ u32 val;
+
+ cipher = mt76_mac_get_key_info(key, key_data);
+ if (cipher == MT_CIPHER_NONE && key)
+ return -EINVAL;
+
+ trace_set_shared_key(dev, vif_idx, key_idx);
+
+ mt7601u_wr_copy(dev, MT_SKEY(vif_idx, key_idx),
+ key_data, sizeof(key_data));
+
+ val = mt76_rr(dev, MT_SKEY_MODE(vif_idx));
+ val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx));
+ val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx);
+ mt76_wr(dev, MT_SKEY_MODE(vif_idx), val);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.h b/drivers/net/wireless/mediatek/mt7601u/mac.h
new file mode 100644
index 000000000000..2c22d63c63a2
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/mac.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#ifndef __MT76_MAC_H
+#define __MT76_MAC_H
+
+struct mt76_tx_status {
+ u8 valid:1;
+ u8 success:1;
+ u8 aggr:1;
+ u8 ack_req:1;
+ u8 is_probe:1;
+ u8 wcid;
+ u8 pktid;
+ u8 retry;
+ u16 rate;
+} __packed __aligned(2);
+
+/* Note: values in original "RSSI" and "SNR" fields are not actually what they
+ * are called for MT7601U, names used by this driver are educated guesses
+ * (see vendor mac/ral_omac.c).
+ */
+struct mt7601u_rxwi {
+ __le32 rxinfo;
+
+ __le32 ctl;
+
+ __le16 frag_sn;
+ __le16 rate;
+
+ u8 unknown;
+ u8 zero[3];
+
+ u8 snr;
+ u8 ant;
+ u8 gain;
+ u8 freq_off;
+
+ __le32 resv2;
+ __le32 expert_ant;
+} __packed __aligned(4);
+
+#define MT_RXINFO_BA BIT(0)
+#define MT_RXINFO_DATA BIT(1)
+#define MT_RXINFO_NULL BIT(2)
+#define MT_RXINFO_FRAG BIT(3)
+#define MT_RXINFO_U2M BIT(4)
+#define MT_RXINFO_MULTICAST BIT(5)
+#define MT_RXINFO_BROADCAST BIT(6)
+#define MT_RXINFO_MYBSS BIT(7)
+#define MT_RXINFO_CRCERR BIT(8)
+#define MT_RXINFO_ICVERR BIT(9)
+#define MT_RXINFO_MICERR BIT(10)
+#define MT_RXINFO_AMSDU BIT(11)
+#define MT_RXINFO_HTC BIT(12)
+#define MT_RXINFO_RSSI BIT(13)
+#define MT_RXINFO_L2PAD BIT(14)
+#define MT_RXINFO_AMPDU BIT(15)
+#define MT_RXINFO_DECRYPT BIT(16)
+#define MT_RXINFO_BSSIDX3 BIT(17)
+#define MT_RXINFO_WAPI_KEY BIT(18)
+#define MT_RXINFO_PN_LEN GENMASK(21, 19)
+#define MT_RXINFO_SW_PKT_80211 BIT(22)
+#define MT_RXINFO_TCP_SUM_BYPASS BIT(28)
+#define MT_RXINFO_IP_SUM_BYPASS BIT(29)
+#define MT_RXINFO_TCP_SUM_ERR BIT(30)
+#define MT_RXINFO_IP_SUM_ERR BIT(31)
+
+#define MT_RXWI_CTL_WCID GENMASK(7, 0)
+#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8)
+#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10)
+#define MT_RXWI_CTL_UDF GENMASK(15, 13)
+#define MT_RXWI_CTL_MPDU_LEN GENMASK(27, 16)
+#define MT_RXWI_CTL_TID GENMASK(31, 28)
+
+#define MT_RXWI_FRAG GENMASK(3, 0)
+#define MT_RXWI_SN GENMASK(15, 4)
+
+#define MT_RXWI_RATE_MCS GENMASK(6, 0)
+#define MT_RXWI_RATE_BW BIT(7)
+#define MT_RXWI_RATE_SGI BIT(8)
+#define MT_RXWI_RATE_STBC GENMASK(10, 9)
+#define MT_RXWI_RATE_ETXBF BIT(11)
+#define MT_RXWI_RATE_SND BIT(12)
+#define MT_RXWI_RATE_ITXBF BIT(13)
+#define MT_RXWI_RATE_PHY GENMASK(15, 14)
+
+#define MT_RXWI_GAIN_RSSI_VAL GENMASK(5, 0)
+#define MT_RXWI_GAIN_RSSI_LNA_ID GENMASK(7, 6)
+#define MT_RXWI_ANT_AUX_LNA BIT(7)
+
+#define MT_RXWI_EANT_ENC_ANT_ID GENMASK(7, 0)
+
+enum mt76_phy_type {
+ MT_PHY_TYPE_CCK,
+ MT_PHY_TYPE_OFDM,
+ MT_PHY_TYPE_HT,
+ MT_PHY_TYPE_HT_GF,
+};
+
+enum mt76_phy_bandwidth {
+ MT_PHY_BW_20,
+ MT_PHY_BW_40,
+};
+
+struct mt76_txwi {
+ __le16 flags;
+ __le16 rate_ctl;
+
+ u8 ack_ctl;
+ u8 wcid;
+ __le16 len_ctl;
+
+ __le32 iv;
+
+ __le32 eiv;
+
+ u8 aid;
+ u8 txstream;
+ __le16 ctl;
+} __packed __aligned(4);
+
+#define MT_TXWI_FLAGS_FRAG BIT(0)
+#define MT_TXWI_FLAGS_MMPS BIT(1)
+#define MT_TXWI_FLAGS_CFACK BIT(2)
+#define MT_TXWI_FLAGS_TS BIT(3)
+#define MT_TXWI_FLAGS_AMPDU BIT(4)
+#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5)
+#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8)
+#define MT_TXWI_FLAGS_CWMIN GENMASK(12, 10)
+#define MT_TXWI_FLAGS_NO_RATE_FALLBACK BIT(13)
+#define MT_TXWI_FLAGS_TX_RPT BIT(14)
+#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15)
+
+#define MT_TXWI_RATE_MCS GENMASK(6, 0)
+#define MT_TXWI_RATE_BW BIT(7)
+#define MT_TXWI_RATE_SGI BIT(8)
+#define MT_TXWI_RATE_STBC GENMASK(10, 9)
+#define MT_TXWI_RATE_PHY_MODE GENMASK(15, 14)
+
+#define MT_TXWI_ACK_CTL_REQ BIT(0)
+#define MT_TXWI_ACK_CTL_NSEQ BIT(1)
+#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2)
+
+#define MT_TXWI_LEN_BYTE_CNT GENMASK(11, 0)
+#define MT_TXWI_LEN_PKTID GENMASK(15, 12)
+
+#define MT_TXWI_CTL_TX_POWER_ADJ GENMASK(3, 0)
+#define MT_TXWI_CTL_CHAN_CHECK_PKT BIT(4)
+#define MT_TXWI_CTL_PIFS_REV BIT(6)
+
+u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb,
+ u8 *data, void *rxi);
+int mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx,
+ struct ieee80211_key_conf *key);
+void mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid,
+ const struct ieee80211_tx_rate *rate);
+
+int mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx,
+ struct ieee80211_key_conf *key);
+u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev,
+ const struct ieee80211_tx_rate *rate, u8 *nss_val);
+struct mt76_tx_status
+mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev);
+void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat);
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c
new file mode 100644
index 000000000000..169384b48b27
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/main.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include "mt7601u.h"
+#include "mac.h"
+#include <linux/etherdevice.h>
+#include <linux/version.h>
+
+static int mt7601u_start(struct ieee80211_hw *hw)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ int ret;
+
+ mutex_lock(&dev->mutex);
+
+ ret = mt7601u_mac_start(dev);
+ if (ret)
+ goto out;
+
+ ieee80211_queue_delayed_work(dev->hw, &dev->mac_work,
+ MT_CALIBRATE_INTERVAL);
+ ieee80211_queue_delayed_work(dev->hw, &dev->cal_work,
+ MT_CALIBRATE_INTERVAL);
+out:
+ mutex_unlock(&dev->mutex);
+ return ret;
+}
+
+static void mt7601u_stop(struct ieee80211_hw *hw)
+{
+ struct mt7601u_dev *dev = hw->priv;
+
+ mutex_lock(&dev->mutex);
+
+ cancel_delayed_work_sync(&dev->cal_work);
+ cancel_delayed_work_sync(&dev->mac_work);
+ mt7601u_mac_stop(dev);
+
+ mutex_unlock(&dev->mutex);
+}
+
+static int mt7601u_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
+ unsigned int idx = 0;
+ unsigned int wcid = GROUP_WCID(idx);
+
+ /* Note: for AP do the AP-STA things mt76 does:
+ * - beacon offsets
+ * - do mac address tricks
+ * - shift vif idx
+ */
+ mvif->idx = idx;
+
+ if (dev->wcid_mask[wcid / BITS_PER_LONG] & BIT(wcid % BITS_PER_LONG))
+ return -ENOSPC;
+ dev->wcid_mask[wcid / BITS_PER_LONG] |= BIT(wcid % BITS_PER_LONG);
+ mvif->group_wcid.idx = wcid;
+ mvif->group_wcid.hw_key_idx = -1;
+
+ return 0;
+}
+
+static void mt7601u_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
+ unsigned int wcid = mvif->group_wcid.idx;
+
+ dev->wcid_mask[wcid / BITS_PER_LONG] &= ~BIT(wcid % BITS_PER_LONG);
+}
+
+static int mt7601u_config(struct ieee80211_hw *hw, u32 changed)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ int ret = 0;
+
+ mutex_lock(&dev->mutex);
+
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ ieee80211_stop_queues(hw);
+ ret = mt7601u_phy_set_channel(dev, &hw->conf.chandef);
+ ieee80211_wake_queues(hw);
+ }
+
+ mutex_unlock(&dev->mutex);
+
+ return ret;
+}
+
+static void
+mt76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
+ unsigned int *total_flags, u64 multicast)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ u32 flags = 0;
+
+#define MT76_FILTER(_flag, _hw) do { \
+ flags |= *total_flags & FIF_##_flag; \
+ dev->rxfilter &= ~(_hw); \
+ dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \
+ } while (0)
+
+ mutex_lock(&dev->mutex);
+
+ dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS;
+
+ MT76_FILTER(OTHER_BSS, MT_RX_FILTR_CFG_PROMISC);
+ MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR);
+ MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR);
+ MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK |
+ MT_RX_FILTR_CFG_CTS |
+ MT_RX_FILTR_CFG_CFEND |
+ MT_RX_FILTR_CFG_CFACK |
+ MT_RX_FILTR_CFG_BA |
+ MT_RX_FILTR_CFG_CTRL_RSV);
+ MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL);
+
+ *total_flags = flags;
+ mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
+
+ mutex_unlock(&dev->mutex);
+}
+
+static void
+mt7601u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info, u32 changed)
+{
+ struct mt7601u_dev *dev = hw->priv;
+
+ mutex_lock(&dev->mutex);
+
+ if (changed & BSS_CHANGED_ASSOC)
+ mt7601u_phy_con_cal_onoff(dev, info);
+
+ if (changed & BSS_CHANGED_BSSID) {
+ mt7601u_addr_wr(dev, MT_MAC_BSSID_DW0, info->bssid);
+
+ /* Note: this is a hack because beacon_int is not changed
+ * on leave nor is any more appropriate event generated.
+ * rt2x00 doesn't seem to be bothered though.
+ */
+ if (is_zero_ether_addr(info->bssid))
+ mt7601u_mac_config_tsf(dev, false, 0);
+ }
+
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ mt7601u_wr(dev, MT_LEGACY_BASIC_RATE, info->basic_rates);
+ mt7601u_wr(dev, MT_HT_FBK_CFG0, 0x65432100);
+ mt7601u_wr(dev, MT_HT_FBK_CFG1, 0xedcba980);
+ mt7601u_wr(dev, MT_LG_FBK_CFG0, 0xedcba988);
+ mt7601u_wr(dev, MT_LG_FBK_CFG1, 0x00002100);
+ }
+
+ if (changed & BSS_CHANGED_BEACON_INT)
+ mt7601u_mac_config_tsf(dev, true, info->beacon_int);
+
+ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
+ mt7601u_mac_set_protection(dev, info->use_cts_prot,
+ info->ht_operation_mode);
+
+ if (changed & BSS_CHANGED_ERP_PREAMBLE)
+ mt7601u_mac_set_short_preamble(dev, info->use_short_preamble);
+
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ int slottime = info->use_short_slot ? 9 : 20;
+
+ mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG,
+ MT_BKOFF_SLOT_CFG_SLOTTIME, slottime);
+ }
+
+ if (changed & BSS_CHANGED_ASSOC)
+ mt7601u_phy_recalibrate_after_assoc(dev);
+
+ mutex_unlock(&dev->mutex);
+}
+
+static int
+mt76_wcid_alloc(struct mt7601u_dev *dev)
+{
+ int i, idx = 0;
+
+ for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) {
+ idx = ffs(~dev->wcid_mask[i]);
+ if (!idx)
+ continue;
+
+ idx--;
+ dev->wcid_mask[i] |= BIT(idx);
+ break;
+ }
+
+ idx = i * BITS_PER_LONG + idx;
+ if (idx > 119)
+ return -1;
+
+ return idx;
+}
+
+static int
+mt7601u_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
+ struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
+ int ret = 0;
+ int idx = 0;
+
+ mutex_lock(&dev->mutex);
+
+ idx = mt76_wcid_alloc(dev);
+ if (idx < 0) {
+ ret = -ENOSPC;
+ goto out;
+ }
+
+ msta->wcid.idx = idx;
+ msta->wcid.hw_key_idx = -1;
+ mt7601u_mac_wcid_setup(dev, idx, mvif->idx, sta->addr);
+ mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx));
+ rcu_assign_pointer(dev->wcid[idx], &msta->wcid);
+ mt7601u_mac_set_ampdu_factor(dev);
+
+out:
+ mutex_unlock(&dev->mutex);
+
+ return ret;
+}
+
+static int
+mt7601u_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
+ int idx = msta->wcid.idx;
+
+ mutex_lock(&dev->mutex);
+ rcu_assign_pointer(dev->wcid[idx], NULL);
+ mt76_set(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx));
+ dev->wcid_mask[idx / BITS_PER_LONG] &= ~BIT(idx % BITS_PER_LONG);
+ mt7601u_mac_wcid_setup(dev, idx, 0, NULL);
+ mt7601u_mac_set_ampdu_factor(dev);
+ mutex_unlock(&dev->mutex);
+
+ return 0;
+}
+
+static void
+mt7601u_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd, struct ieee80211_sta *sta)
+{
+}
+
+static void
+mt7601u_sw_scan(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const u8 *mac_addr)
+{
+ struct mt7601u_dev *dev = hw->priv;
+
+ mt7601u_agc_save(dev);
+ set_bit(MT7601U_STATE_SCANNING, &dev->state);
+}
+
+static void
+mt7601u_sw_scan_complete(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct mt7601u_dev *dev = hw->priv;
+
+ mt7601u_agc_restore(dev);
+ clear_bit(MT7601U_STATE_SCANNING, &dev->state);
+}
+
+static int
+mt7601u_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
+ struct mt76_sta *msta = sta ? (struct mt76_sta *) sta->drv_priv : NULL;
+ struct mt76_wcid *wcid = msta ? &msta->wcid : &mvif->group_wcid;
+ int idx = key->keyidx;
+ int ret;
+
+ if (cmd == SET_KEY) {
+ key->hw_key_idx = wcid->idx;
+ wcid->hw_key_idx = idx;
+ } else {
+ if (idx == wcid->hw_key_idx)
+ wcid->hw_key_idx = -1;
+
+ key = NULL;
+ }
+
+ if (!msta) {
+ if (key || wcid->hw_key_idx == idx) {
+ ret = mt76_mac_wcid_set_key(dev, wcid->idx, key);
+ if (ret)
+ return ret;
+ }
+
+ return mt76_mac_shared_key_setup(dev, mvif->idx, idx, key);
+ }
+
+ return mt76_mac_wcid_set_key(dev, msta->wcid.idx, key);
+}
+
+static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+ struct mt7601u_dev *dev = hw->priv;
+
+ mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, value);
+
+ return 0;
+}
+
+static int
+mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
+
+ WARN_ON(msta->wcid.idx > GROUP_WCID(0));
+
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
+ break;
+ case IEEE80211_AMPDU_RX_STOP:
+ mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4,
+ BIT(16 + tid));
+ break;
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+ ieee80211_send_bar(vif, sta->addr, tid, msta->agg_ssn[tid]);
+ break;
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+ break;
+ case IEEE80211_AMPDU_TX_START:
+ msta->agg_ssn[tid] = *ssn << 4;
+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+ }
+
+ return 0;
+}
+
+static void
+mt76_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
+ struct ieee80211_sta_rates *rates;
+ struct ieee80211_tx_rate rate = {};
+
+ rcu_read_lock();
+ rates = rcu_dereference(sta->rates);
+
+ if (!rates)
+ goto out;
+
+ rate.idx = rates->rate[0].idx;
+ rate.flags = rates->rate[0].flags;
+ mt76_mac_wcid_set_rate(dev, &msta->wcid, &rate);
+
+out:
+ rcu_read_unlock();
+}
+
+const struct ieee80211_ops mt7601u_ops = {
+ .tx = mt7601u_tx,
+ .start = mt7601u_start,
+ .stop = mt7601u_stop,
+ .add_interface = mt7601u_add_interface,
+ .remove_interface = mt7601u_remove_interface,
+ .config = mt7601u_config,
+ .configure_filter = mt76_configure_filter,
+ .bss_info_changed = mt7601u_bss_info_changed,
+ .sta_add = mt7601u_sta_add,
+ .sta_remove = mt7601u_sta_remove,
+ .sta_notify = mt7601u_sta_notify,
+ .set_key = mt7601u_set_key,
+ .conf_tx = mt7601u_conf_tx,
+ .sw_scan_start = mt7601u_sw_scan,
+ .sw_scan_complete = mt7601u_sw_scan_complete,
+ .ampdu_action = mt76_ampdu_action,
+ .sta_rate_tbl_update = mt76_sta_rate_tbl_update,
+ .set_rts_threshold = mt7601u_set_rts_threshold,
+};
diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c
new file mode 100644
index 000000000000..fbb1986eda3c
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c
@@ -0,0 +1,534 @@
+/*
+ * (c) Copyright 2002-2010, Ralink Technology, Inc.
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/usb.h>
+#include <linux/skbuff.h>
+
+#include "mt7601u.h"
+#include "dma.h"
+#include "mcu.h"
+#include "usb.h"
+#include "trace.h"
+
+#define MCU_FW_URB_MAX_PAYLOAD 0x3800
+#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12)
+#define MCU_RESP_URB_SIZE 1024
+
+static inline int firmware_running(struct mt7601u_dev *dev)
+{
+ return mt7601u_rr(dev, MT_MCU_COM_REG0) == 1;
+}
+
+static inline void skb_put_le32(struct sk_buff *skb, u32 val)
+{
+ put_unaligned_le32(val, skb_put(skb, 4));
+}
+
+static inline void mt7601u_dma_skb_wrap_cmd(struct sk_buff *skb,
+ u8 seq, enum mcu_cmd cmd)
+{
+ WARN_ON(mt7601u_dma_skb_wrap(skb, CPU_TX_PORT, DMA_COMMAND,
+ MT76_SET(MT_TXD_CMD_INFO_SEQ, seq) |
+ MT76_SET(MT_TXD_CMD_INFO_TYPE, cmd)));
+}
+
+static inline void trace_mt_mcu_msg_send_cs(struct mt7601u_dev *dev,
+ struct sk_buff *skb, bool need_resp)
+{
+ u32 i, csum = 0;
+
+ for (i = 0; i < skb->len / 4; i++)
+ csum ^= get_unaligned_le32(skb->data + i * 4);
+
+ trace_mt_mcu_msg_send(dev, skb, csum, need_resp);
+}
+
+static struct sk_buff *
+mt7601u_mcu_msg_alloc(struct mt7601u_dev *dev, const void *data, int len)
+{
+ struct sk_buff *skb;
+
+ WARN_ON(len % 4); /* if length is not divisible by 4 we need to pad */
+
+ skb = alloc_skb(len + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
+ skb_reserve(skb, MT_DMA_HDR_LEN);
+ memcpy(skb_put(skb, len), data, len);
+
+ return skb;
+}
+
+static int mt7601u_mcu_wait_resp(struct mt7601u_dev *dev, u8 seq)
+{
+ struct urb *urb = dev->mcu.resp.urb;
+ u32 rxfce;
+ int urb_status, ret, i = 5;
+
+ while (i--) {
+ if (!wait_for_completion_timeout(&dev->mcu.resp_cmpl,
+ msecs_to_jiffies(300))) {
+ dev_warn(dev->dev, "Warning: %s retrying\n", __func__);
+ continue;
+ }
+
+ /* Make copies of important data before reusing the urb */
+ rxfce = get_unaligned_le32(dev->mcu.resp.buf);
+ urb_status = urb->status * mt7601u_urb_has_error(urb);
+
+ ret = mt7601u_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP,
+ &dev->mcu.resp, GFP_KERNEL,
+ mt7601u_complete_urb,
+ &dev->mcu.resp_cmpl);
+ if (ret)
+ return ret;
+
+ if (urb_status)
+ dev_err(dev->dev, "Error: MCU resp urb failed:%d\n",
+ urb_status);
+
+ if (MT76_GET(MT_RXD_CMD_INFO_CMD_SEQ, rxfce) == seq &&
+ MT76_GET(MT_RXD_CMD_INFO_EVT_TYPE, rxfce) == CMD_DONE)
+ return 0;
+
+ dev_err(dev->dev, "Error: MCU resp evt:%hhx seq:%hhx-%hhx!\n",
+ MT76_GET(MT_RXD_CMD_INFO_EVT_TYPE, rxfce),
+ seq, MT76_GET(MT_RXD_CMD_INFO_CMD_SEQ, rxfce));
+ }
+
+ dev_err(dev->dev, "Error: %s timed out\n", __func__);
+ return -ETIMEDOUT;
+}
+
+static int
+mt7601u_mcu_msg_send(struct mt7601u_dev *dev, struct sk_buff *skb,
+ enum mcu_cmd cmd, bool wait_resp)
+{
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+ unsigned cmd_pipe = usb_sndbulkpipe(usb_dev,
+ dev->out_eps[MT_EP_OUT_INBAND_CMD]);
+ int sent, ret;
+ u8 seq = 0;
+
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return 0;
+
+ mutex_lock(&dev->mcu.mutex);
+
+ if (wait_resp)
+ while (!seq)
+ seq = ++dev->mcu.msg_seq & 0xf;
+
+ mt7601u_dma_skb_wrap_cmd(skb, seq, cmd);
+
+ if (dev->mcu.resp_cmpl.done)
+ dev_err(dev->dev, "Error: MCU response pre-completed!\n");
+
+ trace_mt_mcu_msg_send_cs(dev, skb, wait_resp);
+ trace_mt_submit_urb_sync(dev, cmd_pipe, skb->len);
+ ret = usb_bulk_msg(usb_dev, cmd_pipe, skb->data, skb->len, &sent, 500);
+ if (ret) {
+ dev_err(dev->dev, "Error: send MCU cmd failed:%d\n", ret);
+ goto out;
+ }
+ if (sent != skb->len)
+ dev_err(dev->dev, "Error: %s sent != skb->len\n", __func__);
+
+ if (wait_resp)
+ ret = mt7601u_mcu_wait_resp(dev, seq);
+out:
+ mutex_unlock(&dev->mcu.mutex);
+
+ consume_skb(skb);
+
+ return ret;
+}
+
+static int mt7601u_mcu_function_select(struct mt7601u_dev *dev,
+ enum mcu_function func, u32 val)
+{
+ struct sk_buff *skb;
+ struct {
+ __le32 id;
+ __le32 value;
+ } __packed __aligned(4) msg = {
+ .id = cpu_to_le32(func),
+ .value = cpu_to_le32(val),
+ };
+
+ skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg));
+ return mt7601u_mcu_msg_send(dev, skb, CMD_FUN_SET_OP, func == 5);
+}
+
+int mt7601u_mcu_tssi_read_kick(struct mt7601u_dev *dev, int use_hvga)
+{
+ int ret;
+
+ if (!test_bit(MT7601U_STATE_MCU_RUNNING, &dev->state))
+ return 0;
+
+ ret = mt7601u_mcu_function_select(dev, ATOMIC_TSSI_SETTING,
+ use_hvga);
+ if (ret) {
+ dev_warn(dev->dev, "Warning: MCU TSSI read kick failed\n");
+ return ret;
+ }
+
+ dev->tssi_read_trig = true;
+
+ return 0;
+}
+
+int
+mt7601u_mcu_calibrate(struct mt7601u_dev *dev, enum mcu_calibrate cal, u32 val)
+{
+ struct sk_buff *skb;
+ struct {
+ __le32 id;
+ __le32 value;
+ } __packed __aligned(4) msg = {
+ .id = cpu_to_le32(cal),
+ .value = cpu_to_le32(val),
+ };
+
+ skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg));
+ return mt7601u_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP, true);
+}
+
+int mt7601u_write_reg_pairs(struct mt7601u_dev *dev, u32 base,
+ const struct mt76_reg_pair *data, int n)
+{
+ const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 8;
+ struct sk_buff *skb;
+ int cnt, i, ret;
+
+ if (!n)
+ return 0;
+
+ cnt = min(max_vals_per_cmd, n);
+
+ skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+ skb_reserve(skb, MT_DMA_HDR_LEN);
+
+ for (i = 0; i < cnt; i++) {
+ skb_put_le32(skb, base + data[i].reg);
+ skb_put_le32(skb, data[i].value);
+ }
+
+ ret = mt7601u_mcu_msg_send(dev, skb, CMD_RANDOM_WRITE, cnt == n);
+ if (ret)
+ return ret;
+
+ return mt7601u_write_reg_pairs(dev, base, data + cnt, n - cnt);
+}
+
+int mt7601u_burst_write_regs(struct mt7601u_dev *dev, u32 offset,
+ const u32 *data, int n)
+{
+ const int max_regs_per_cmd = INBAND_PACKET_MAX_LEN / 4 - 1;
+ struct sk_buff *skb;
+ int cnt, i, ret;
+
+ if (!n)
+ return 0;
+
+ cnt = min(max_regs_per_cmd, n);
+
+ skb = alloc_skb(cnt * 4 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+ skb_reserve(skb, MT_DMA_HDR_LEN);
+
+ skb_put_le32(skb, MT_MCU_MEMMAP_WLAN + offset);
+ for (i = 0; i < cnt; i++)
+ skb_put_le32(skb, data[i]);
+
+ ret = mt7601u_mcu_msg_send(dev, skb, CMD_BURST_WRITE, cnt == n);
+ if (ret)
+ return ret;
+
+ return mt7601u_burst_write_regs(dev, offset + cnt * 4,
+ data + cnt, n - cnt);
+}
+
+struct mt76_fw_header {
+ __le32 ilm_len;
+ __le32 dlm_len;
+ __le16 build_ver;
+ __le16 fw_ver;
+ u8 pad[4];
+ char build_time[16];
+};
+
+struct mt76_fw {
+ struct mt76_fw_header hdr;
+ u8 ivb[MT_MCU_IVB_SIZE];
+ u8 ilm[];
+};
+
+static int __mt7601u_dma_fw(struct mt7601u_dev *dev,
+ const struct mt7601u_dma_buf *dma_buf,
+ const void *data, u32 len, u32 dst_addr)
+{
+ DECLARE_COMPLETION_ONSTACK(cmpl);
+ struct mt7601u_dma_buf buf = *dma_buf; /* we need to fake length */
+ __le32 reg;
+ u32 val;
+ int ret;
+
+ reg = cpu_to_le32(MT76_SET(MT_TXD_INFO_TYPE, DMA_PACKET) |
+ MT76_SET(MT_TXD_INFO_D_PORT, CPU_TX_PORT) |
+ MT76_SET(MT_TXD_INFO_LEN, len));
+ memcpy(buf.buf, &reg, sizeof(reg));
+ memcpy(buf.buf + sizeof(reg), data, len);
+ memset(buf.buf + sizeof(reg) + len, 0, 8);
+
+ ret = mt7601u_vendor_single_wr(dev, MT_VEND_WRITE_FCE,
+ MT_FCE_DMA_ADDR, dst_addr);
+ if (ret)
+ return ret;
+ len = roundup(len, 4);
+ ret = mt7601u_vendor_single_wr(dev, MT_VEND_WRITE_FCE,
+ MT_FCE_DMA_LEN, len << 16);
+ if (ret)
+ return ret;
+
+ buf.len = MT_DMA_HDR_LEN + len + 4;
+ ret = mt7601u_usb_submit_buf(dev, USB_DIR_OUT, MT_EP_OUT_INBAND_CMD,
+ &buf, GFP_KERNEL,
+ mt7601u_complete_urb, &cmpl);
+ if (ret)
+ return ret;
+
+ if (!wait_for_completion_timeout(&cmpl, msecs_to_jiffies(1000))) {
+ dev_err(dev->dev, "Error: firmware upload timed out\n");
+ usb_kill_urb(buf.urb);
+ return -ETIMEDOUT;
+ }
+ if (mt7601u_urb_has_error(buf.urb)) {
+ dev_err(dev->dev, "Error: firmware upload urb failed:%d\n",
+ buf.urb->status);
+ return buf.urb->status;
+ }
+
+ val = mt7601u_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX);
+ val++;
+ mt7601u_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val);
+
+ return 0;
+}
+
+static int
+mt7601u_dma_fw(struct mt7601u_dev *dev, struct mt7601u_dma_buf *dma_buf,
+ const void *data, int len, u32 dst_addr)
+{
+ int n, ret;
+
+ if (len == 0)
+ return 0;
+
+ n = min(MCU_FW_URB_MAX_PAYLOAD, len);
+ ret = __mt7601u_dma_fw(dev, dma_buf, data, n, dst_addr);
+ if (ret)
+ return ret;
+
+ if (!mt76_poll_msec(dev, MT_MCU_COM_REG1, BIT(31), BIT(31), 500))
+ return -ETIMEDOUT;
+
+ return mt7601u_dma_fw(dev, dma_buf, data + n, len - n, dst_addr + n);
+}
+
+static int
+mt7601u_upload_firmware(struct mt7601u_dev *dev, const struct mt76_fw *fw)
+{
+ struct mt7601u_dma_buf dma_buf;
+ void *ivb;
+ u32 ilm_len, dlm_len;
+ int i, ret;
+
+ ivb = kmemdup(fw->ivb, sizeof(fw->ivb), GFP_KERNEL);
+ if (!ivb || mt7601u_usb_alloc_buf(dev, MCU_FW_URB_SIZE, &dma_buf)) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ilm_len = le32_to_cpu(fw->hdr.ilm_len) - sizeof(fw->ivb);
+ dev_dbg(dev->dev, "loading FW - ILM %u + IVB %zu\n",
+ ilm_len, sizeof(fw->ivb));
+ ret = mt7601u_dma_fw(dev, &dma_buf, fw->ilm, ilm_len, sizeof(fw->ivb));
+ if (ret)
+ goto error;
+
+ dlm_len = le32_to_cpu(fw->hdr.dlm_len);
+ dev_dbg(dev->dev, "loading FW - DLM %u\n", dlm_len);
+ ret = mt7601u_dma_fw(dev, &dma_buf, fw->ilm + ilm_len,
+ dlm_len, MT_MCU_DLM_OFFSET);
+ if (ret)
+ goto error;
+
+ ret = mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT,
+ 0x12, 0, ivb, sizeof(fw->ivb));
+ if (ret < 0)
+ goto error;
+ ret = 0;
+
+ for (i = 100; i && !firmware_running(dev); i--)
+ msleep(10);
+ if (!i) {
+ ret = -ETIMEDOUT;
+ goto error;
+ }
+
+ dev_dbg(dev->dev, "Firmware running!\n");
+error:
+ kfree(ivb);
+ mt7601u_usb_free_buf(dev, &dma_buf);
+
+ return ret;
+}
+
+static int mt7601u_load_firmware(struct mt7601u_dev *dev)
+{
+ const struct firmware *fw;
+ const struct mt76_fw_header *hdr;
+ int len, ret;
+ u32 val;
+
+ mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
+ MT_USB_DMA_CFG_TX_BULK_EN));
+
+ if (firmware_running(dev))
+ return 0;
+
+ ret = request_firmware(&fw, MT7601U_FIRMWARE, dev->dev);
+ if (ret)
+ return ret;
+
+ if (!fw || !fw->data || fw->size < sizeof(*hdr))
+ goto err_inv_fw;
+
+ hdr = (const struct mt76_fw_header *) fw->data;
+
+ if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE)
+ goto err_inv_fw;
+
+ len = sizeof(*hdr);
+ len += le32_to_cpu(hdr->ilm_len);
+ len += le32_to_cpu(hdr->dlm_len);
+
+ if (fw->size != len)
+ goto err_inv_fw;
+
+ val = le16_to_cpu(hdr->fw_ver);
+ dev_info(dev->dev,
+ "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n",
+ (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf,
+ le16_to_cpu(hdr->build_ver), hdr->build_time);
+
+ len = le32_to_cpu(hdr->ilm_len);
+
+ mt7601u_wr(dev, 0x94c, 0);
+ mt7601u_wr(dev, MT_FCE_PSE_CTRL, 0);
+
+ mt7601u_vendor_reset(dev);
+ msleep(5);
+
+ mt7601u_wr(dev, 0xa44, 0);
+ mt7601u_wr(dev, 0x230, 0x84210);
+ mt7601u_wr(dev, 0x400, 0x80c00);
+ mt7601u_wr(dev, 0x800, 1);
+
+ mt7601u_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN |
+ MT_PBF_CFG_TX1Q_EN |
+ MT_PBF_CFG_TX2Q_EN |
+ MT_PBF_CFG_TX3Q_EN));
+
+ mt7601u_wr(dev, MT_FCE_PSE_CTRL, 1);
+
+ mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
+ MT_USB_DMA_CFG_TX_BULK_EN));
+ val = mt76_set(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_CLR);
+ val &= ~MT_USB_DMA_CFG_TX_CLR;
+ mt7601u_wr(dev, MT_USB_DMA_CFG, val);
+
+ /* FCE tx_fs_base_ptr */
+ mt7601u_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230);
+ /* FCE tx_fs_max_cnt */
+ mt7601u_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1);
+ /* FCE pdma enable */
+ mt7601u_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44);
+ /* FCE skip_fs_en */
+ mt7601u_wr(dev, MT_FCE_SKIP_FS, 3);
+
+ ret = mt7601u_upload_firmware(dev, (const struct mt76_fw *)fw->data);
+
+ release_firmware(fw);
+
+ return ret;
+
+err_inv_fw:
+ dev_err(dev->dev, "Invalid firmware image\n");
+ release_firmware(fw);
+ return -ENOENT;
+}
+
+int mt7601u_mcu_init(struct mt7601u_dev *dev)
+{
+ int ret;
+
+ mutex_init(&dev->mcu.mutex);
+
+ ret = mt7601u_load_firmware(dev);
+ if (ret)
+ return ret;
+
+ set_bit(MT7601U_STATE_MCU_RUNNING, &dev->state);
+
+ return 0;
+}
+
+int mt7601u_mcu_cmd_init(struct mt7601u_dev *dev)
+{
+ int ret;
+
+ ret = mt7601u_mcu_function_select(dev, Q_SELECT, 1);
+ if (ret)
+ return ret;
+
+ init_completion(&dev->mcu.resp_cmpl);
+ if (mt7601u_usb_alloc_buf(dev, MCU_RESP_URB_SIZE, &dev->mcu.resp)) {
+ mt7601u_usb_free_buf(dev, &dev->mcu.resp);
+ return -ENOMEM;
+ }
+
+ ret = mt7601u_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP,
+ &dev->mcu.resp, GFP_KERNEL,
+ mt7601u_complete_urb, &dev->mcu.resp_cmpl);
+ if (ret) {
+ mt7601u_usb_free_buf(dev, &dev->mcu.resp);
+ return ret;
+ }
+
+ return 0;
+}
+
+void mt7601u_mcu_cmd_deinit(struct mt7601u_dev *dev)
+{
+ usb_kill_urb(dev->mcu.resp.urb);
+ mt7601u_usb_free_buf(dev, &dev->mcu.resp);
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.h b/drivers/net/wireless/mediatek/mt7601u/mcu.h
new file mode 100644
index 000000000000..4a66d1092a18
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/mcu.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#ifndef __MT7601U_MCU_H
+#define __MT7601U_MCU_H
+
+struct mt7601u_dev;
+
+/* Register definitions */
+#define MT_MCU_RESET_CTL 0x070C
+#define MT_MCU_INT_LEVEL 0x0718
+#define MT_MCU_COM_REG0 0x0730
+#define MT_MCU_COM_REG1 0x0734
+#define MT_MCU_COM_REG2 0x0738
+#define MT_MCU_COM_REG3 0x073C
+
+#define MT_MCU_IVB_SIZE 0x40
+#define MT_MCU_DLM_OFFSET 0x80000
+
+#define MT_MCU_MEMMAP_WLAN 0x00410000
+#define MT_MCU_MEMMAP_BBP 0x40000000
+#define MT_MCU_MEMMAP_RF 0x80000000
+
+#define INBAND_PACKET_MAX_LEN 192
+
+enum mcu_cmd {
+ CMD_FUN_SET_OP = 1,
+ CMD_LOAD_CR = 2,
+ CMD_INIT_GAIN_OP = 3,
+ CMD_DYNC_VGA_OP = 6,
+ CMD_TDLS_CH_SW = 7,
+ CMD_BURST_WRITE = 8,
+ CMD_READ_MODIFY_WRITE = 9,
+ CMD_RANDOM_READ = 10,
+ CMD_BURST_READ = 11,
+ CMD_RANDOM_WRITE = 12,
+ CMD_LED_MODE_OP = 16,
+ CMD_POWER_SAVING_OP = 20,
+ CMD_WOW_CONFIG = 21,
+ CMD_WOW_QUERY = 22,
+ CMD_WOW_FEATURE = 24,
+ CMD_CARRIER_DETECT_OP = 28,
+ CMD_RADOR_DETECT_OP = 29,
+ CMD_SWITCH_CHANNEL_OP = 30,
+ CMD_CALIBRATION_OP = 31,
+ CMD_BEACON_OP = 32,
+ CMD_ANTENNA_OP = 33,
+};
+
+enum mcu_function {
+ Q_SELECT = 1,
+ ATOMIC_TSSI_SETTING = 5,
+};
+
+enum mcu_power_mode {
+ RADIO_OFF = 0x30,
+ RADIO_ON = 0x31,
+ RADIO_OFF_AUTO_WAKEUP = 0x32,
+ RADIO_OFF_ADVANCE = 0x33,
+ RADIO_ON_ADVANCE = 0x34,
+};
+
+enum mcu_calibrate {
+ MCU_CAL_R = 1,
+ MCU_CAL_DCOC,
+ MCU_CAL_LC,
+ MCU_CAL_LOFT,
+ MCU_CAL_TXIQ,
+ MCU_CAL_BW,
+ MCU_CAL_DPD,
+ MCU_CAL_RXIQ,
+ MCU_CAL_TXDCOC,
+};
+
+int mt7601u_mcu_init(struct mt7601u_dev *dev);
+int mt7601u_mcu_cmd_init(struct mt7601u_dev *dev);
+void mt7601u_mcu_cmd_deinit(struct mt7601u_dev *dev);
+
+int
+mt7601u_mcu_calibrate(struct mt7601u_dev *dev, enum mcu_calibrate cal, u32 val);
+int mt7601u_mcu_tssi_read_kick(struct mt7601u_dev *dev, int use_hvga);
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
new file mode 100644
index 000000000000..9102be6b95cb
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#ifndef MT7601U_H
+#define MT7601U_H
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/usb.h>
+#include <linux/completion.h>
+#include <net/mac80211.h>
+#include <linux/debugfs.h>
+
+#include "regs.h"
+#include "util.h"
+
+#define MT_CALIBRATE_INTERVAL (4 * HZ)
+
+#define MT_FREQ_CAL_INIT_DELAY (30 * HZ)
+#define MT_FREQ_CAL_CHECK_INTERVAL (10 * HZ)
+#define MT_FREQ_CAL_ADJ_INTERVAL (HZ / 2)
+
+#define MT_BBP_REG_VERSION 0x00
+
+#define MT_USB_AGGR_SIZE_LIMIT 28 /* * 1024B */
+#define MT_USB_AGGR_TIMEOUT 0x80 /* * 33ns */
+#define MT_RX_ORDER 3
+#define MT_RX_URB_SIZE (PAGE_SIZE << MT_RX_ORDER)
+
+struct mt7601u_dma_buf {
+ struct urb *urb;
+ void *buf;
+ dma_addr_t dma;
+ size_t len;
+};
+
+struct mt7601u_mcu {
+ struct mutex mutex;
+
+ u8 msg_seq;
+
+ struct mt7601u_dma_buf resp;
+ struct completion resp_cmpl;
+};
+
+struct mt7601u_freq_cal {
+ struct delayed_work work;
+ u8 freq;
+ bool enabled;
+ bool adjusting;
+};
+
+struct mac_stats {
+ u64 rx_stat[6];
+ u64 tx_stat[6];
+ u64 aggr_stat[2];
+ u64 aggr_n[32];
+ u64 zero_len_del[2];
+};
+
+#define N_RX_ENTRIES 16
+struct mt7601u_rx_queue {
+ struct mt7601u_dev *dev;
+
+ struct mt7601u_dma_buf_rx {
+ struct urb *urb;
+ struct page *p;
+ } e[N_RX_ENTRIES];
+
+ unsigned int start;
+ unsigned int end;
+ unsigned int entries;
+ unsigned int pending;
+};
+
+#define N_TX_ENTRIES 64
+
+struct mt7601u_tx_queue {
+ struct mt7601u_dev *dev;
+
+ struct mt7601u_dma_buf_tx {
+ struct urb *urb;
+ struct sk_buff *skb;
+ } e[N_TX_ENTRIES];
+
+ unsigned int start;
+ unsigned int end;
+ unsigned int entries;
+ unsigned int used;
+ unsigned int fifo_seq;
+};
+
+/* WCID allocation:
+ * 0: mcast wcid
+ * 1: bssid wcid
+ * 1...: STAs
+ * ...7e: group wcids
+ * 7f: reserved
+ */
+#define N_WCIDS 128
+#define GROUP_WCID(idx) (N_WCIDS - 2 - idx)
+
+struct mt7601u_eeprom_params;
+
+#define MT_EE_TEMPERATURE_SLOPE 39
+#define MT_FREQ_OFFSET_INVALID -128
+
+enum mt_temp_mode {
+ MT_TEMP_MODE_NORMAL,
+ MT_TEMP_MODE_HIGH,
+ MT_TEMP_MODE_LOW,
+};
+
+enum mt_bw {
+ MT_BW_20,
+ MT_BW_40,
+};
+
+enum {
+ MT7601U_STATE_INITIALIZED,
+ MT7601U_STATE_REMOVED,
+ MT7601U_STATE_WLAN_RUNNING,
+ MT7601U_STATE_MCU_RUNNING,
+ MT7601U_STATE_SCANNING,
+ MT7601U_STATE_READING_STATS,
+ MT7601U_STATE_MORE_STATS,
+};
+
+/**
+ * struct mt7601u_dev - adapter structure
+ * @lock: protects @wcid->tx_rate.
+ * @tx_lock: protects @tx_q and changes of MT7601U_STATE_*_STATS
+ flags in @state.
+ * @rx_lock: protects @rx_q.
+ * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi.
+ * @mutex: ensures exclusive access from mac80211 callbacks.
+ * @vendor_req_mutex: ensures atomicity of vendor requests.
+ * @reg_atomic_mutex: ensures atomicity of indirect register accesses
+ * (accesses to RF and BBP).
+ * @hw_atomic_mutex: ensures exclusive access to HW during critical
+ * operations (power management, channel switch).
+ */
+struct mt7601u_dev {
+ struct ieee80211_hw *hw;
+ struct device *dev;
+
+ unsigned long state;
+
+ struct mutex mutex;
+
+ unsigned long wcid_mask[N_WCIDS / BITS_PER_LONG];
+
+ struct cfg80211_chan_def chandef;
+ struct ieee80211_supported_band *sband_2g;
+
+ struct mt7601u_mcu mcu;
+
+ struct delayed_work cal_work;
+ struct delayed_work mac_work;
+
+ struct workqueue_struct *stat_wq;
+ struct delayed_work stat_work;
+
+ struct mt76_wcid *mon_wcid;
+ struct mt76_wcid __rcu *wcid[N_WCIDS];
+
+ spinlock_t lock;
+
+ const u16 *beacon_offsets;
+
+ u8 macaddr[ETH_ALEN];
+ struct mt7601u_eeprom_params *ee;
+
+ struct mutex vendor_req_mutex;
+ struct mutex reg_atomic_mutex;
+ struct mutex hw_atomic_mutex;
+
+ u32 rxfilter;
+ u32 debugfs_reg;
+
+ u8 out_eps[8];
+ u8 in_eps[8];
+ u16 out_max_packet;
+ u16 in_max_packet;
+
+ /* TX */
+ spinlock_t tx_lock;
+ struct mt7601u_tx_queue *tx_q;
+
+ atomic_t avg_ampdu_len;
+
+ /* RX */
+ spinlock_t rx_lock;
+ struct tasklet_struct rx_tasklet;
+ struct mt7601u_rx_queue rx_q;
+
+ /* Connection monitoring things */
+ spinlock_t con_mon_lock;
+ u8 ap_bssid[ETH_ALEN];
+
+ s8 bcn_freq_off;
+ u8 bcn_phy_mode;
+
+ int avg_rssi; /* starts at 0 and converges */
+
+ u8 agc_save;
+
+ struct mt7601u_freq_cal freq_cal;
+
+ bool tssi_read_trig;
+
+ s8 tssi_init;
+ s8 tssi_init_hvga;
+ s16 tssi_init_hvga_offset_db;
+
+ int prev_pwr_diff;
+
+ enum mt_temp_mode temp_mode;
+ int curr_temp;
+ int dpd_temp;
+ s8 raw_temp;
+ bool pll_lock_protect;
+
+ u8 bw;
+ bool chan_ext_below;
+
+ /* PA mode */
+ u32 rf_pa_mode[2];
+
+ struct mac_stats stats;
+};
+
+struct mt7601u_tssi_params {
+ char tssi0;
+ int trgt_power;
+};
+
+struct mt76_wcid {
+ u8 idx;
+ u8 hw_key_idx;
+
+ u16 tx_rate;
+ bool tx_rate_set;
+ u8 tx_rate_nss;
+};
+
+struct mt76_vif {
+ u8 idx;
+
+ struct mt76_wcid group_wcid;
+};
+
+struct mt76_sta {
+ struct mt76_wcid wcid;
+ u16 agg_ssn[IEEE80211_NUM_TIDS];
+};
+
+struct mt76_reg_pair {
+ u32 reg;
+ u32 value;
+};
+
+struct mt7601u_rxwi;
+
+extern const struct ieee80211_ops mt7601u_ops;
+
+void mt7601u_init_debugfs(struct mt7601u_dev *dev);
+
+u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset);
+void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val);
+u32 mt7601u_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val);
+u32 mt7601u_rmc(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val);
+void mt7601u_wr_copy(struct mt7601u_dev *dev, u32 offset,
+ const void *data, int len);
+
+int mt7601u_wait_asic_ready(struct mt7601u_dev *dev);
+bool mt76_poll(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
+ int timeout);
+bool mt76_poll_msec(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val,
+ int timeout);
+
+/* Compatibility with mt76 */
+#define mt76_rmw_field(_dev, _reg, _field, _val) \
+ mt76_rmw(_dev, _reg, _field, MT76_SET(_field, _val))
+
+static inline u32 mt76_rr(struct mt7601u_dev *dev, u32 offset)
+{
+ return mt7601u_rr(dev, offset);
+}
+
+static inline void mt76_wr(struct mt7601u_dev *dev, u32 offset, u32 val)
+{
+ return mt7601u_wr(dev, offset, val);
+}
+
+static inline u32
+mt76_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val)
+{
+ return mt7601u_rmw(dev, offset, mask, val);
+}
+
+static inline u32 mt76_set(struct mt7601u_dev *dev, u32 offset, u32 val)
+{
+ return mt76_rmw(dev, offset, 0, val);
+}
+
+static inline u32 mt76_clear(struct mt7601u_dev *dev, u32 offset, u32 val)
+{
+ return mt76_rmw(dev, offset, val, 0);
+}
+
+int mt7601u_write_reg_pairs(struct mt7601u_dev *dev, u32 base,
+ const struct mt76_reg_pair *data, int len);
+int mt7601u_burst_write_regs(struct mt7601u_dev *dev, u32 offset,
+ const u32 *data, int n);
+void mt7601u_addr_wr(struct mt7601u_dev *dev, const u32 offset, const u8 *addr);
+
+/* Init */
+struct mt7601u_dev *mt7601u_alloc_device(struct device *dev);
+int mt7601u_init_hardware(struct mt7601u_dev *dev);
+int mt7601u_register_device(struct mt7601u_dev *dev);
+void mt7601u_cleanup(struct mt7601u_dev *dev);
+
+int mt7601u_mac_start(struct mt7601u_dev *dev);
+void mt7601u_mac_stop(struct mt7601u_dev *dev);
+
+/* PHY */
+int mt7601u_phy_init(struct mt7601u_dev *dev);
+int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev);
+void mt7601u_set_rx_path(struct mt7601u_dev *dev, u8 path);
+void mt7601u_set_tx_dac(struct mt7601u_dev *dev, u8 path);
+int mt7601u_bbp_set_bw(struct mt7601u_dev *dev, int bw);
+void mt7601u_agc_save(struct mt7601u_dev *dev);
+void mt7601u_agc_restore(struct mt7601u_dev *dev);
+int mt7601u_phy_set_channel(struct mt7601u_dev *dev,
+ struct cfg80211_chan_def *chandef);
+void mt7601u_phy_recalibrate_after_assoc(struct mt7601u_dev *dev);
+int mt7601u_phy_get_rssi(struct mt7601u_dev *dev,
+ struct mt7601u_rxwi *rxwi, u16 rate);
+void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev,
+ struct ieee80211_bss_conf *info);
+
+/* MAC */
+void mt7601u_mac_work(struct work_struct *work);
+void mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot,
+ int ht_mode);
+void mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb);
+void mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval);
+void
+mt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac);
+void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev);
+
+/* TX */
+void mt7601u_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
+ struct sk_buff *skb);
+int mt7601u_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u16 queue, const struct ieee80211_tx_queue_params *params);
+void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb);
+void mt7601u_tx_stat(struct work_struct *work);
+
+/* util */
+void mt76_remove_hdr_pad(struct sk_buff *skb);
+int mt76_insert_hdr_pad(struct sk_buff *skb);
+
+u32 mt7601u_bbp_set_ctrlch(struct mt7601u_dev *dev, bool below);
+
+static inline u32 mt7601u_mac_set_ctrlch(struct mt7601u_dev *dev, bool below)
+{
+ return mt7601u_rmc(dev, MT_TX_BAND_CFG, 1, below);
+}
+
+int mt7601u_dma_init(struct mt7601u_dev *dev);
+void mt7601u_dma_cleanup(struct mt7601u_dev *dev);
+
+int mt7601u_dma_enqueue_tx(struct mt7601u_dev *dev, struct sk_buff *skb,
+ struct mt76_wcid *wcid, int hw_q);
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/phy.c b/drivers/net/wireless/mediatek/mt7601u/phy.c
new file mode 100644
index 000000000000..1908af6add87
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/phy.c
@@ -0,0 +1,1251 @@
+/*
+ * (c) Copyright 2002-2010, Ralink Technology, Inc.
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include "mt7601u.h"
+#include "mcu.h"
+#include "eeprom.h"
+#include "trace.h"
+#include "initvals_phy.h"
+
+#include <linux/etherdevice.h>
+
+static void mt7601u_agc_reset(struct mt7601u_dev *dev);
+
+static int
+mt7601u_rf_wr(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 value)
+{
+ int ret = 0;
+
+ if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) ||
+ WARN_ON(offset > 63))
+ return -EINVAL;
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return 0;
+
+ mutex_lock(&dev->reg_atomic_mutex);
+
+ if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ mt7601u_wr(dev, MT_RF_CSR_CFG, MT76_SET(MT_RF_CSR_CFG_DATA, value) |
+ MT76_SET(MT_RF_CSR_CFG_REG_BANK, bank) |
+ MT76_SET(MT_RF_CSR_CFG_REG_ID, offset) |
+ MT_RF_CSR_CFG_WR |
+ MT_RF_CSR_CFG_KICK);
+ trace_rf_write(dev, bank, offset, value);
+out:
+ mutex_unlock(&dev->reg_atomic_mutex);
+
+ if (ret < 0)
+ dev_err(dev->dev, "Error: RF write %02hhx:%02hhx failed:%d!!\n",
+ bank, offset, ret);
+
+ return ret;
+}
+
+static int
+mt7601u_rf_rr(struct mt7601u_dev *dev, u8 bank, u8 offset)
+{
+ int ret = -ETIMEDOUT;
+ u32 val;
+
+ if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) ||
+ WARN_ON(offset > 63))
+ return -EINVAL;
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return 0xff;
+
+ mutex_lock(&dev->reg_atomic_mutex);
+
+ if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100))
+ goto out;
+
+ mt7601u_wr(dev, MT_RF_CSR_CFG, MT76_SET(MT_RF_CSR_CFG_REG_BANK, bank) |
+ MT76_SET(MT_RF_CSR_CFG_REG_ID, offset) |
+ MT_RF_CSR_CFG_KICK);
+
+ if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100))
+ goto out;
+
+ val = mt7601u_rr(dev, MT_RF_CSR_CFG);
+ if (MT76_GET(MT_RF_CSR_CFG_REG_ID, val) == offset &&
+ MT76_GET(MT_RF_CSR_CFG_REG_BANK, val) == bank) {
+ ret = MT76_GET(MT_RF_CSR_CFG_DATA, val);
+ trace_rf_read(dev, bank, offset, ret);
+ }
+out:
+ mutex_unlock(&dev->reg_atomic_mutex);
+
+ if (ret < 0)
+ dev_err(dev->dev, "Error: RF read %02hhx:%02hhx failed:%d!!\n",
+ bank, offset, ret);
+
+ return ret;
+}
+
+static int
+mt7601u_rf_rmw(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 mask, u8 val)
+{
+ int ret;
+
+ ret = mt7601u_rf_rr(dev, bank, offset);
+ if (ret < 0)
+ return ret;
+ val |= ret & ~mask;
+ ret = mt7601u_rf_wr(dev, bank, offset, val);
+ if (ret)
+ return ret;
+
+ return val;
+}
+
+static int
+mt7601u_rf_set(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 val)
+{
+ return mt7601u_rf_rmw(dev, bank, offset, 0, val);
+}
+
+static int
+mt7601u_rf_clear(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 mask)
+{
+ return mt7601u_rf_rmw(dev, bank, offset, mask, 0);
+}
+
+static void mt7601u_bbp_wr(struct mt7601u_dev *dev, u8 offset, u8 val)
+{
+ if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) ||
+ test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return;
+
+ mutex_lock(&dev->reg_atomic_mutex);
+
+ if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000)) {
+ dev_err(dev->dev, "Error: BBP write %02hhx failed!!\n", offset);
+ goto out;
+ }
+
+ mt7601u_wr(dev, MT_BBP_CSR_CFG,
+ MT76_SET(MT_BBP_CSR_CFG_VAL, val) |
+ MT76_SET(MT_BBP_CSR_CFG_REG_NUM, offset) |
+ MT_BBP_CSR_CFG_RW_MODE | MT_BBP_CSR_CFG_BUSY);
+ trace_bbp_write(dev, offset, val);
+out:
+ mutex_unlock(&dev->reg_atomic_mutex);
+}
+
+static int mt7601u_bbp_rr(struct mt7601u_dev *dev, u8 offset)
+{
+ u32 val;
+ int ret = -ETIMEDOUT;
+
+ if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)))
+ return -EINVAL;
+ if (test_bit(MT7601U_STATE_REMOVED, &dev->state))
+ return 0xff;
+
+ mutex_lock(&dev->reg_atomic_mutex);
+
+ if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000))
+ goto out;
+
+ mt7601u_wr(dev, MT_BBP_CSR_CFG,
+ MT76_SET(MT_BBP_CSR_CFG_REG_NUM, offset) |
+ MT_BBP_CSR_CFG_RW_MODE | MT_BBP_CSR_CFG_BUSY |
+ MT_BBP_CSR_CFG_READ);
+
+ if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000))
+ goto out;
+
+ val = mt7601u_rr(dev, MT_BBP_CSR_CFG);
+ if (MT76_GET(MT_BBP_CSR_CFG_REG_NUM, val) == offset) {
+ ret = MT76_GET(MT_BBP_CSR_CFG_VAL, val);
+ trace_bbp_read(dev, offset, ret);
+ }
+out:
+ mutex_unlock(&dev->reg_atomic_mutex);
+
+ if (ret < 0)
+ dev_err(dev->dev, "Error: BBP read %02hhx failed:%d!!\n",
+ offset, ret);
+
+ return ret;
+}
+
+static int mt7601u_bbp_rmw(struct mt7601u_dev *dev, u8 offset, u8 mask, u8 val)
+{
+ int ret;
+
+ ret = mt7601u_bbp_rr(dev, offset);
+ if (ret < 0)
+ return ret;
+ val |= ret & ~mask;
+ mt7601u_bbp_wr(dev, offset, val);
+
+ return val;
+}
+
+static u8 mt7601u_bbp_rmc(struct mt7601u_dev *dev, u8 offset, u8 mask, u8 val)
+{
+ int ret;
+
+ ret = mt7601u_bbp_rr(dev, offset);
+ if (ret < 0)
+ return ret;
+ val |= ret & ~mask;
+ if (ret != val)
+ mt7601u_bbp_wr(dev, offset, val);
+
+ return val;
+}
+
+int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev)
+{
+ int i = 20;
+ u8 val;
+
+ do {
+ val = mt7601u_bbp_rr(dev, MT_BBP_REG_VERSION);
+ if (val && ~val)
+ break;
+ } while (--i);
+
+ if (!i) {
+ dev_err(dev->dev, "Error: BBP is not ready\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+u32 mt7601u_bbp_set_ctrlch(struct mt7601u_dev *dev, bool below)
+{
+ return mt7601u_bbp_rmc(dev, 3, 0x20, below ? 0x20 : 0);
+}
+
+int mt7601u_phy_get_rssi(struct mt7601u_dev *dev,
+ struct mt7601u_rxwi *rxwi, u16 rate)
+{
+ static const s8 lna[2][2][3] = {
+ /* main LNA */ {
+ /* bw20 */ { -2, 15, 33 },
+ /* bw40 */ { 0, 16, 34 }
+ },
+ /* aux LNA */ {
+ /* bw20 */ { -2, 15, 33 },
+ /* bw40 */ { -2, 16, 34 }
+ }
+ };
+ int bw = MT76_GET(MT_RXWI_RATE_BW, rate);
+ int aux_lna = MT76_GET(MT_RXWI_ANT_AUX_LNA, rxwi->ant);
+ int lna_id = MT76_GET(MT_RXWI_GAIN_RSSI_LNA_ID, rxwi->gain);
+ int val;
+
+ if (lna_id) /* LNA id can be 0, 2, 3. */
+ lna_id--;
+
+ val = 8;
+ val -= lna[aux_lna][bw][lna_id];
+ val -= MT76_GET(MT_RXWI_GAIN_RSSI_VAL, rxwi->gain);
+ val -= dev->ee->lna_gain;
+ val -= dev->ee->rssi_offset[0];
+
+ return val;
+}
+
+static void mt7601u_vco_cal(struct mt7601u_dev *dev)
+{
+ mt7601u_rf_wr(dev, 0, 4, 0x0a);
+ mt7601u_rf_wr(dev, 0, 5, 0x20);
+ mt7601u_rf_set(dev, 0, 4, BIT(7));
+ msleep(2);
+}
+
+static int mt7601u_set_bw_filter(struct mt7601u_dev *dev, bool cal)
+{
+ u32 filter = 0;
+ int ret;
+
+ if (!cal)
+ filter |= 0x10000;
+ if (dev->bw != MT_BW_20)
+ filter |= 0x00100;
+
+ /* TX */
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_BW, filter | 1);
+ if (ret)
+ return ret;
+ /* RX */
+ return mt7601u_mcu_calibrate(dev, MCU_CAL_BW, filter);
+}
+
+static int mt7601u_load_bbp_temp_table_bw(struct mt7601u_dev *dev)
+{
+ const struct reg_table *t;
+
+ if (WARN_ON(dev->temp_mode > MT_TEMP_MODE_LOW))
+ return -EINVAL;
+
+ t = &bbp_mode_table[dev->temp_mode][dev->bw];
+
+ return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, t->regs, t->n);
+}
+
+static int mt7601u_bbp_temp(struct mt7601u_dev *dev, int mode, const char *name)
+{
+ const struct reg_table *t;
+ int ret;
+
+ if (dev->temp_mode == mode)
+ return 0;
+
+ dev->temp_mode = mode;
+ trace_temp_mode(dev, mode);
+
+ t = bbp_mode_table[dev->temp_mode];
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP,
+ t[2].regs, t[2].n);
+ if (ret)
+ return ret;
+
+ return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP,
+ t[dev->bw].regs, t[dev->bw].n);
+}
+
+static void mt7601u_apply_ch14_fixup(struct mt7601u_dev *dev, int hw_chan)
+{
+ struct mt7601u_rate_power *t = &dev->ee->power_rate_table;
+
+ if (hw_chan != 14 || dev->bw != MT_BW_20) {
+ mt7601u_bbp_rmw(dev, 4, 0x20, 0);
+ mt7601u_bbp_wr(dev, 178, 0xff);
+
+ t->cck[0].bw20 = dev->ee->real_cck_bw20[0];
+ t->cck[1].bw20 = dev->ee->real_cck_bw20[1];
+ } else { /* Apply CH14 OBW fixup */
+ mt7601u_bbp_wr(dev, 4, 0x60);
+ mt7601u_bbp_wr(dev, 178, 0);
+
+ /* Note: vendor code is buggy here for negative values */
+ t->cck[0].bw20 = dev->ee->real_cck_bw20[0] - 2;
+ t->cck[1].bw20 = dev->ee->real_cck_bw20[1] - 2;
+ }
+}
+
+static int __mt7601u_phy_set_channel(struct mt7601u_dev *dev,
+ struct cfg80211_chan_def *chandef)
+{
+#define FREQ_PLAN_REGS 4
+ static const u8 freq_plan[14][FREQ_PLAN_REGS] = {
+ { 0x99, 0x99, 0x09, 0x50 },
+ { 0x46, 0x44, 0x0a, 0x50 },
+ { 0xec, 0xee, 0x0a, 0x50 },
+ { 0x99, 0x99, 0x0b, 0x50 },
+ { 0x46, 0x44, 0x08, 0x51 },
+ { 0xec, 0xee, 0x08, 0x51 },
+ { 0x99, 0x99, 0x09, 0x51 },
+ { 0x46, 0x44, 0x0a, 0x51 },
+ { 0xec, 0xee, 0x0a, 0x51 },
+ { 0x99, 0x99, 0x0b, 0x51 },
+ { 0x46, 0x44, 0x08, 0x52 },
+ { 0xec, 0xee, 0x08, 0x52 },
+ { 0x99, 0x99, 0x09, 0x52 },
+ { 0x33, 0x33, 0x0b, 0x52 },
+ };
+ struct mt76_reg_pair channel_freq_plan[FREQ_PLAN_REGS] = {
+ { 17, 0 }, { 18, 0 }, { 19, 0 }, { 20, 0 },
+ };
+ struct mt76_reg_pair bbp_settings[3] = {
+ { 62, 0x37 - dev->ee->lna_gain },
+ { 63, 0x37 - dev->ee->lna_gain },
+ { 64, 0x37 - dev->ee->lna_gain },
+ };
+
+ struct ieee80211_channel *chan = chandef->chan;
+ enum nl80211_channel_type chan_type =
+ cfg80211_get_chandef_type(chandef);
+ struct mt7601u_rate_power *t = &dev->ee->power_rate_table;
+ int chan_idx;
+ bool chan_ext_below;
+ u8 bw;
+ int i, ret;
+
+ bw = MT_BW_20;
+ chan_ext_below = (chan_type == NL80211_CHAN_HT40MINUS);
+ chan_idx = chan->hw_value - 1;
+
+ if (chandef->width == NL80211_CHAN_WIDTH_40) {
+ bw = MT_BW_40;
+
+ if (chan_idx > 1 && chan_type == NL80211_CHAN_HT40MINUS)
+ chan_idx -= 2;
+ else if (chan_idx < 12 && chan_type == NL80211_CHAN_HT40PLUS)
+ chan_idx += 2;
+ else
+ dev_err(dev->dev, "Error: invalid 40MHz channel!!\n");
+ }
+
+ if (bw != dev->bw || chan_ext_below != dev->chan_ext_below) {
+ dev_dbg(dev->dev, "Info: switching HT mode bw:%d below:%d\n",
+ bw, chan_ext_below);
+
+ mt7601u_bbp_set_bw(dev, bw);
+
+ mt7601u_bbp_set_ctrlch(dev, chan_ext_below);
+ mt7601u_mac_set_ctrlch(dev, chan_ext_below);
+ dev->chan_ext_below = chan_ext_below;
+ }
+
+ for (i = 0; i < FREQ_PLAN_REGS; i++)
+ channel_freq_plan[i].value = freq_plan[chan_idx][i];
+
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_RF,
+ channel_freq_plan, FREQ_PLAN_REGS);
+ if (ret)
+ return ret;
+
+ mt7601u_rmw(dev, MT_TX_ALC_CFG_0, 0x3f3f,
+ dev->ee->chan_pwr[chan_idx] & 0x3f);
+
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP,
+ bbp_settings, ARRAY_SIZE(bbp_settings));
+ if (ret)
+ return ret;
+
+ mt7601u_vco_cal(dev);
+ mt7601u_bbp_set_bw(dev, bw);
+ ret = mt7601u_set_bw_filter(dev, false);
+ if (ret)
+ return ret;
+
+ mt7601u_apply_ch14_fixup(dev, chan->hw_value);
+ mt7601u_wr(dev, MT_TX_PWR_CFG_0, int_to_s6(t->ofdm[1].bw20) << 24 |
+ int_to_s6(t->ofdm[0].bw20) << 16 |
+ int_to_s6(t->cck[1].bw20) << 8 |
+ int_to_s6(t->cck[0].bw20));
+
+ if (test_bit(MT7601U_STATE_SCANNING, &dev->state))
+ mt7601u_agc_reset(dev);
+
+ dev->chandef = *chandef;
+
+ return 0;
+}
+
+int mt7601u_phy_set_channel(struct mt7601u_dev *dev,
+ struct cfg80211_chan_def *chandef)
+{
+ int ret;
+
+ cancel_delayed_work_sync(&dev->cal_work);
+ cancel_delayed_work_sync(&dev->freq_cal.work);
+
+ mutex_lock(&dev->hw_atomic_mutex);
+ ret = __mt7601u_phy_set_channel(dev, chandef);
+ mutex_unlock(&dev->hw_atomic_mutex);
+ if (ret)
+ return ret;
+
+ if (test_bit(MT7601U_STATE_SCANNING, &dev->state))
+ return 0;
+
+ ieee80211_queue_delayed_work(dev->hw, &dev->cal_work,
+ MT_CALIBRATE_INTERVAL);
+ if (dev->freq_cal.enabled)
+ ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work,
+ MT_FREQ_CAL_INIT_DELAY);
+ return 0;
+}
+
+#define BBP_R47_FLAG GENMASK(2, 0)
+#define BBP_R47_F_TSSI 0
+#define BBP_R47_F_PKT_T 1
+#define BBP_R47_F_TX_RATE 2
+#define BBP_R47_F_TEMP 4
+/**
+ * mt7601u_bbp_r47_get - read value through BBP R47/R49 pair
+ * @dev: pointer to adapter structure
+ * @reg: value of BBP R47 before the operation
+ * @flag: one of the BBP_R47_F_* flags
+ *
+ * Convenience helper for reading values through BBP R47/R49 pair.
+ * Takes old value of BBP R47 as @reg, because callers usually have it
+ * cached already.
+ *
+ * Return: value of BBP R49.
+ */
+static u8 mt7601u_bbp_r47_get(struct mt7601u_dev *dev, u8 reg, u8 flag)
+{
+ flag |= reg & ~BBP_R47_FLAG;
+ mt7601u_bbp_wr(dev, 47, flag);
+ usleep_range(500, 700);
+ return mt7601u_bbp_rr(dev, 49);
+}
+
+static s8 mt7601u_read_bootup_temp(struct mt7601u_dev *dev)
+{
+ u8 bbp_val, temp;
+ u32 rf_bp, rf_set;
+ int i;
+
+ rf_set = mt7601u_rr(dev, MT_RF_SETTING_0);
+ rf_bp = mt7601u_rr(dev, MT_RF_BYPASS_0);
+
+ mt7601u_wr(dev, MT_RF_BYPASS_0, 0);
+ mt7601u_wr(dev, MT_RF_SETTING_0, 0x00000010);
+ mt7601u_wr(dev, MT_RF_BYPASS_0, 0x00000010);
+
+ bbp_val = mt7601u_bbp_rmw(dev, 47, 0, 0x10);
+
+ mt7601u_bbp_wr(dev, 22, 0x40);
+
+ for (i = 100; i && (bbp_val & 0x10); i--)
+ bbp_val = mt7601u_bbp_rr(dev, 47);
+
+ temp = mt7601u_bbp_r47_get(dev, bbp_val, BBP_R47_F_TEMP);
+
+ mt7601u_bbp_wr(dev, 22, 0);
+
+ bbp_val = mt7601u_bbp_rr(dev, 21);
+ bbp_val |= 0x02;
+ mt7601u_bbp_wr(dev, 21, bbp_val);
+ bbp_val &= ~0x02;
+ mt7601u_bbp_wr(dev, 21, bbp_val);
+
+ mt7601u_wr(dev, MT_RF_BYPASS_0, 0);
+ mt7601u_wr(dev, MT_RF_SETTING_0, rf_set);
+ mt7601u_wr(dev, MT_RF_BYPASS_0, rf_bp);
+
+ trace_read_temp(dev, temp);
+ return temp;
+}
+
+static s8 mt7601u_read_temp(struct mt7601u_dev *dev)
+{
+ int i;
+ u8 val;
+ s8 temp;
+
+ val = mt7601u_bbp_rmw(dev, 47, 0x7f, 0x10);
+
+ /* Note: this rarely succeeds, temp can change even if it fails. */
+ for (i = 100; i && (val & 0x10); i--)
+ val = mt7601u_bbp_rr(dev, 47);
+
+ temp = mt7601u_bbp_r47_get(dev, val, BBP_R47_F_TEMP);
+
+ trace_read_temp(dev, temp);
+ return temp;
+}
+
+static void mt7601u_rxdc_cal(struct mt7601u_dev *dev)
+{
+ static const struct mt76_reg_pair intro[] = {
+ { 158, 0x8d }, { 159, 0xfc },
+ { 158, 0x8c }, { 159, 0x4c },
+ }, outro[] = {
+ { 158, 0x8d }, { 159, 0xe0 },
+ };
+ u32 mac_ctrl;
+ int i, ret;
+
+ mac_ctrl = mt7601u_rr(dev, MT_MAC_SYS_CTRL);
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX);
+
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP,
+ intro, ARRAY_SIZE(intro));
+ if (ret)
+ dev_err(dev->dev, "%s intro failed:%d\n", __func__, ret);
+
+ for (i = 20; i; i--) {
+ usleep_range(300, 500);
+
+ mt7601u_bbp_wr(dev, 158, 0x8c);
+ if (mt7601u_bbp_rr(dev, 159) == 0x0c)
+ break;
+ }
+ if (!i)
+ dev_err(dev->dev, "%s timed out\n", __func__);
+
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0);
+
+ ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP,
+ outro, ARRAY_SIZE(outro));
+ if (ret)
+ dev_err(dev->dev, "%s outro failed:%d\n", __func__, ret);
+
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, mac_ctrl);
+}
+
+void mt7601u_phy_recalibrate_after_assoc(struct mt7601u_dev *dev)
+{
+ mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->curr_temp);
+
+ mt7601u_rxdc_cal(dev);
+}
+
+/* Note: function copied from vendor driver */
+static s16 lin2dBd(u16 linear)
+{
+ short exp = 0;
+ unsigned int mantisa;
+ int app, dBd;
+
+ if (WARN_ON(!linear))
+ return -10000;
+
+ mantisa = linear;
+
+ exp = fls(mantisa) - 16;
+ if (exp > 0)
+ mantisa >>= exp;
+ else
+ mantisa <<= abs(exp);
+
+ if (mantisa <= 0xb800)
+ app = (mantisa + (mantisa >> 3) + (mantisa >> 4) - 0x9600);
+ else
+ app = (mantisa - (mantisa >> 3) - (mantisa >> 6) - 0x5a00);
+ if (app < 0)
+ app = 0;
+
+ dBd = ((15 + exp) << 15) + app;
+ dBd = (dBd << 2) + (dBd << 1) + (dBd >> 6) + (dBd >> 7);
+ dBd = (dBd >> 10);
+
+ return dBd;
+}
+
+static void
+mt7601u_set_initial_tssi(struct mt7601u_dev *dev, s16 tssi_db, s16 tssi_hvga_db)
+{
+ struct tssi_data *d = &dev->ee->tssi_data;
+ int init_offset;
+
+ init_offset = -((tssi_db * d->slope + d->offset[1]) / 4096) + 10;
+
+ mt76_rmw(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP,
+ int_to_s6(init_offset) & MT_TX_ALC_CFG_1_TEMP_COMP);
+}
+
+static void mt7601u_tssi_dc_gain_cal(struct mt7601u_dev *dev)
+{
+ u8 rf_vga, rf_mixer, bbp_r47;
+ int i, j;
+ s8 res[4];
+ s16 tssi_init_db, tssi_init_hvga_db;
+
+ mt7601u_wr(dev, MT_RF_SETTING_0, 0x00000030);
+ mt7601u_wr(dev, MT_RF_BYPASS_0, 0x000c0030);
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0);
+
+ mt7601u_bbp_wr(dev, 58, 0);
+ mt7601u_bbp_wr(dev, 241, 0x2);
+ mt7601u_bbp_wr(dev, 23, 0x8);
+ bbp_r47 = mt7601u_bbp_rr(dev, 47);
+
+ /* Set VGA gain */
+ rf_vga = mt7601u_rf_rr(dev, 5, 3);
+ mt7601u_rf_wr(dev, 5, 3, 8);
+
+ /* Mixer disable */
+ rf_mixer = mt7601u_rf_rr(dev, 4, 39);
+ mt7601u_rf_wr(dev, 4, 39, 0);
+
+ for (i = 0; i < 4; i++) {
+ mt7601u_rf_wr(dev, 4, 39, (i & 1) ? rf_mixer : 0);
+
+ mt7601u_bbp_wr(dev, 23, (i < 2) ? 0x08 : 0x02);
+ mt7601u_rf_wr(dev, 5, 3, (i < 2) ? 0x08 : 0x11);
+
+ /* BBP TSSI initial and soft reset */
+ mt7601u_bbp_wr(dev, 22, 0);
+ mt7601u_bbp_wr(dev, 244, 0);
+
+ mt7601u_bbp_wr(dev, 21, 1);
+ udelay(1);
+ mt7601u_bbp_wr(dev, 21, 0);
+
+ /* TSSI measurement */
+ mt7601u_bbp_wr(dev, 47, 0x50);
+ mt7601u_bbp_wr(dev, (i & 1) ? 244 : 22, (i & 1) ? 0x31 : 0x40);
+
+ for (j = 20; j; j--)
+ if (!(mt7601u_bbp_rr(dev, 47) & 0x10))
+ break;
+ if (!j)
+ dev_err(dev->dev, "%s timed out\n", __func__);
+
+ /* TSSI read */
+ mt7601u_bbp_wr(dev, 47, 0x40);
+ res[i] = mt7601u_bbp_rr(dev, 49);
+ }
+
+ tssi_init_db = lin2dBd((short)res[1] - res[0]);
+ tssi_init_hvga_db = lin2dBd(((short)res[3] - res[2]) * 4);
+ dev->tssi_init = res[0];
+ dev->tssi_init_hvga = res[2];
+ dev->tssi_init_hvga_offset_db = tssi_init_hvga_db - tssi_init_db;
+
+ dev_dbg(dev->dev,
+ "TSSI_init:%hhx db:%hx hvga:%hhx hvga_db:%hx off_db:%hx\n",
+ dev->tssi_init, tssi_init_db, dev->tssi_init_hvga,
+ tssi_init_hvga_db, dev->tssi_init_hvga_offset_db);
+
+ mt7601u_bbp_wr(dev, 22, 0);
+ mt7601u_bbp_wr(dev, 244, 0);
+
+ mt7601u_bbp_wr(dev, 21, 1);
+ udelay(1);
+ mt7601u_bbp_wr(dev, 21, 0);
+
+ mt7601u_wr(dev, MT_RF_BYPASS_0, 0);
+ mt7601u_wr(dev, MT_RF_SETTING_0, 0);
+
+ mt7601u_rf_wr(dev, 5, 3, rf_vga);
+ mt7601u_rf_wr(dev, 4, 39, rf_mixer);
+ mt7601u_bbp_wr(dev, 47, bbp_r47);
+
+ mt7601u_set_initial_tssi(dev, tssi_init_db, tssi_init_hvga_db);
+}
+
+static int mt7601u_temp_comp(struct mt7601u_dev *dev, bool on)
+{
+ int ret, temp, hi_temp = 400, lo_temp = -200;
+
+ temp = (dev->raw_temp - dev->ee->ref_temp) * MT_EE_TEMPERATURE_SLOPE;
+ dev->curr_temp = temp;
+
+ /* DPD Calibration */
+ if (temp - dev->dpd_temp > 450 || temp - dev->dpd_temp < -450) {
+ dev->dpd_temp = temp;
+
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->dpd_temp);
+ if (ret)
+ return ret;
+
+ mt7601u_vco_cal(dev);
+
+ dev_dbg(dev->dev, "Recalibrate DPD\n");
+ }
+
+ /* PLL Lock Protect */
+ if (temp < -50 && !dev->pll_lock_protect) { /* < 20C */
+ dev->pll_lock_protect = true;
+
+ mt7601u_rf_wr(dev, 4, 4, 6);
+ mt7601u_rf_clear(dev, 4, 10, 0x30);
+
+ dev_dbg(dev->dev, "PLL lock protect on - too cold\n");
+ } else if (temp > 50 && dev->pll_lock_protect) { /* > 30C */
+ dev->pll_lock_protect = false;
+
+ mt7601u_rf_wr(dev, 4, 4, 0);
+ mt7601u_rf_rmw(dev, 4, 10, 0x30, 0x10);
+
+ dev_dbg(dev->dev, "PLL lock protect off\n");
+ }
+
+ if (on) {
+ hi_temp -= 50;
+ lo_temp -= 50;
+ }
+
+ /* BBP CR for H, L, N temperature */
+ if (temp > hi_temp)
+ return mt7601u_bbp_temp(dev, MT_TEMP_MODE_HIGH, "high");
+ else if (temp > lo_temp)
+ return mt7601u_bbp_temp(dev, MT_TEMP_MODE_NORMAL, "normal");
+ else
+ return mt7601u_bbp_temp(dev, MT_TEMP_MODE_LOW, "low");
+}
+
+/* Note: this is used only with TSSI, we can just use trgt_pwr from eeprom. */
+static int mt7601u_current_tx_power(struct mt7601u_dev *dev)
+{
+ return dev->ee->chan_pwr[dev->chandef.chan->hw_value - 1];
+}
+
+static bool mt7601u_use_hvga(struct mt7601u_dev *dev)
+{
+ return !(mt7601u_current_tx_power(dev) > 20);
+}
+
+static s16
+mt7601u_phy_rf_pa_mode_val(struct mt7601u_dev *dev, int phy_mode, int tx_rate)
+{
+ static const s16 decode_tb[] = { 0, 8847, -5734, -5734 };
+ u32 reg;
+
+ switch (phy_mode) {
+ case MT_PHY_TYPE_OFDM:
+ tx_rate += 4;
+ case MT_PHY_TYPE_CCK:
+ reg = dev->rf_pa_mode[0];
+ break;
+ default:
+ reg = dev->rf_pa_mode[1];
+ break;
+ }
+
+ return decode_tb[(reg >> (tx_rate * 2)) & 0x3];
+}
+
+static struct mt7601u_tssi_params
+mt7601u_tssi_params_get(struct mt7601u_dev *dev)
+{
+ static const u8 ofdm_pkt2rate[8] = { 6, 4, 2, 0, 7, 5, 3, 1 };
+ static const int static_power[4] = { 0, -49152, -98304, 49152 };
+ struct mt7601u_tssi_params p;
+ u8 bbp_r47, pkt_type, tx_rate;
+ struct power_per_rate *rate_table;
+
+ bbp_r47 = mt7601u_bbp_rr(dev, 47);
+
+ p.tssi0 = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TSSI);
+ dev->raw_temp = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TEMP);
+ pkt_type = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_PKT_T);
+
+ p.trgt_power = mt7601u_current_tx_power(dev);
+
+ switch (pkt_type & 0x03) {
+ case MT_PHY_TYPE_CCK:
+ tx_rate = (pkt_type >> 4) & 0x03;
+ rate_table = dev->ee->power_rate_table.cck;
+ break;
+
+ case MT_PHY_TYPE_OFDM:
+ tx_rate = ofdm_pkt2rate[(pkt_type >> 4) & 0x07];
+ rate_table = dev->ee->power_rate_table.ofdm;
+ break;
+
+ default:
+ tx_rate = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TX_RATE);
+ tx_rate &= 0x7f;
+ rate_table = dev->ee->power_rate_table.ht;
+ break;
+ }
+
+ if (dev->bw == MT_BW_20)
+ p.trgt_power += rate_table[tx_rate / 2].bw20;
+ else
+ p.trgt_power += rate_table[tx_rate / 2].bw40;
+
+ p.trgt_power <<= 12;
+
+ dev_dbg(dev->dev, "tx_rate:%02hhx pwr:%08x\n", tx_rate, p.trgt_power);
+
+ p.trgt_power += mt7601u_phy_rf_pa_mode_val(dev, pkt_type & 0x03,
+ tx_rate);
+
+ /* Channel 14, cck, bw20 */
+ if ((pkt_type & 0x03) == MT_PHY_TYPE_CCK) {
+ if (mt7601u_bbp_rr(dev, 4) & 0x20)
+ p.trgt_power += mt7601u_bbp_rr(dev, 178) ? 18022 : 9830;
+ else
+ p.trgt_power += mt7601u_bbp_rr(dev, 178) ? 819 : 24576;
+ }
+
+ p.trgt_power += static_power[mt7601u_bbp_rr(dev, 1) & 0x03];
+
+ p.trgt_power += dev->ee->tssi_data.tx0_delta_offset;
+
+ dev_dbg(dev->dev,
+ "tssi:%02hhx t_power:%08x temp:%02hhx pkt_type:%02hhx\n",
+ p.tssi0, p.trgt_power, dev->raw_temp, pkt_type);
+
+ return p;
+}
+
+static bool mt7601u_tssi_read_ready(struct mt7601u_dev *dev)
+{
+ return !(mt7601u_bbp_rr(dev, 47) & 0x10);
+}
+
+static int mt7601u_tssi_cal(struct mt7601u_dev *dev)
+{
+ struct mt7601u_tssi_params params;
+ int curr_pwr, diff_pwr;
+ char tssi_offset;
+ s8 tssi_init;
+ s16 tssi_m_dc, tssi_db;
+ bool hvga;
+ u32 val;
+
+ if (!dev->ee->tssi_enabled)
+ return 0;
+
+ hvga = mt7601u_use_hvga(dev);
+ if (!dev->tssi_read_trig)
+ return mt7601u_mcu_tssi_read_kick(dev, hvga);
+
+ if (!mt7601u_tssi_read_ready(dev))
+ return 0;
+
+ params = mt7601u_tssi_params_get(dev);
+
+ tssi_init = (hvga ? dev->tssi_init_hvga : dev->tssi_init);
+ tssi_m_dc = params.tssi0 - tssi_init;
+ tssi_db = lin2dBd(tssi_m_dc);
+ dev_dbg(dev->dev, "tssi dc:%04hx db:%04hx hvga:%d\n",
+ tssi_m_dc, tssi_db, hvga);
+
+ if (dev->chandef.chan->hw_value < 5)
+ tssi_offset = dev->ee->tssi_data.offset[0];
+ else if (dev->chandef.chan->hw_value < 9)
+ tssi_offset = dev->ee->tssi_data.offset[1];
+ else
+ tssi_offset = dev->ee->tssi_data.offset[2];
+
+ if (hvga)
+ tssi_db -= dev->tssi_init_hvga_offset_db;
+
+ curr_pwr = tssi_db * dev->ee->tssi_data.slope + (tssi_offset << 9);
+ diff_pwr = params.trgt_power - curr_pwr;
+ dev_dbg(dev->dev, "Power curr:%08x diff:%08x\n", curr_pwr, diff_pwr);
+
+ if (params.tssi0 > 126 && diff_pwr > 0) {
+ dev_err(dev->dev, "Error: TSSI upper saturation\n");
+ diff_pwr = 0;
+ }
+ if (params.tssi0 - tssi_init < 1 && diff_pwr < 0) {
+ dev_err(dev->dev, "Error: TSSI lower saturation\n");
+ diff_pwr = 0;
+ }
+
+ if ((dev->prev_pwr_diff ^ diff_pwr) < 0 && abs(diff_pwr) < 4096 &&
+ (abs(diff_pwr) > abs(dev->prev_pwr_diff) ||
+ (diff_pwr > 0 && diff_pwr == -dev->prev_pwr_diff)))
+ diff_pwr = 0;
+ else
+ dev->prev_pwr_diff = diff_pwr;
+
+ diff_pwr += (diff_pwr > 0) ? 2048 : -2048;
+ diff_pwr /= 4096;
+
+ dev_dbg(dev->dev, "final diff: %08x\n", diff_pwr);
+
+ val = mt7601u_rr(dev, MT_TX_ALC_CFG_1);
+ curr_pwr = s6_to_int(MT76_GET(MT_TX_ALC_CFG_1_TEMP_COMP, val));
+ diff_pwr += curr_pwr;
+ val = (val & ~MT_TX_ALC_CFG_1_TEMP_COMP) | int_to_s6(diff_pwr);
+ mt7601u_wr(dev, MT_TX_ALC_CFG_1, val);
+
+ return mt7601u_mcu_tssi_read_kick(dev, hvga);
+}
+
+static u8 mt7601u_agc_default(struct mt7601u_dev *dev)
+{
+ return (dev->ee->lna_gain - 8) * 2 + 0x34;
+}
+
+static void mt7601u_agc_reset(struct mt7601u_dev *dev)
+{
+ u8 agc = mt7601u_agc_default(dev);
+
+ mt7601u_bbp_wr(dev, 66, agc);
+}
+
+void mt7601u_agc_save(struct mt7601u_dev *dev)
+{
+ dev->agc_save = mt7601u_bbp_rr(dev, 66);
+}
+
+void mt7601u_agc_restore(struct mt7601u_dev *dev)
+{
+ mt7601u_bbp_wr(dev, 66, dev->agc_save);
+}
+
+static void mt7601u_agc_tune(struct mt7601u_dev *dev)
+{
+ u8 val = mt7601u_agc_default(dev);
+
+ if (test_bit(MT7601U_STATE_SCANNING, &dev->state))
+ return;
+
+ /* Note: only in STA mode and not dozing; perhaps do this only if
+ * there is enough rssi updates since last run?
+ * Rssi updates are only on beacons and U2M so should work...
+ */
+ spin_lock_bh(&dev->con_mon_lock);
+ if (dev->avg_rssi <= -70)
+ val -= 0x20;
+ else if (dev->avg_rssi <= -60)
+ val -= 0x10;
+ spin_unlock_bh(&dev->con_mon_lock);
+
+ if (val != mt7601u_bbp_rr(dev, 66))
+ mt7601u_bbp_wr(dev, 66, val);
+
+ /* TODO: also if lost a lot of beacons try resetting
+ * (see RTMPSetAGCInitValue() call in mlme.c).
+ */
+}
+
+static void mt7601u_phy_calibrate(struct work_struct *work)
+{
+ struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev,
+ cal_work.work);
+
+ mt7601u_agc_tune(dev);
+ mt7601u_tssi_cal(dev);
+ /* If TSSI calibration was run it already updated temperature. */
+ if (!dev->ee->tssi_enabled)
+ dev->raw_temp = mt7601u_read_temp(dev);
+ mt7601u_temp_comp(dev, true); /* TODO: find right value for @on */
+
+ ieee80211_queue_delayed_work(dev->hw, &dev->cal_work,
+ MT_CALIBRATE_INTERVAL);
+}
+
+static unsigned long
+__mt7601u_phy_freq_cal(struct mt7601u_dev *dev, s8 last_offset, u8 phy_mode)
+{
+ u8 activate_threshold, deactivate_threshold;
+
+ trace_freq_cal_offset(dev, phy_mode, last_offset);
+
+ /* No beacons received - reschedule soon */
+ if (last_offset == MT_FREQ_OFFSET_INVALID)
+ return MT_FREQ_CAL_ADJ_INTERVAL;
+
+ switch (phy_mode) {
+ case MT_PHY_TYPE_CCK:
+ activate_threshold = 19;
+ deactivate_threshold = 5;
+ break;
+ case MT_PHY_TYPE_OFDM:
+ activate_threshold = 102;
+ deactivate_threshold = 32;
+ break;
+ case MT_PHY_TYPE_HT:
+ case MT_PHY_TYPE_HT_GF:
+ activate_threshold = 82;
+ deactivate_threshold = 20;
+ break;
+ default:
+ WARN_ON(1);
+ return MT_FREQ_CAL_CHECK_INTERVAL;
+ }
+
+ if (abs(last_offset) >= activate_threshold)
+ dev->freq_cal.adjusting = true;
+ else if (abs(last_offset) <= deactivate_threshold)
+ dev->freq_cal.adjusting = false;
+
+ if (!dev->freq_cal.adjusting)
+ return MT_FREQ_CAL_CHECK_INTERVAL;
+
+ if (last_offset > deactivate_threshold) {
+ if (dev->freq_cal.freq > 0)
+ dev->freq_cal.freq--;
+ else
+ dev->freq_cal.adjusting = false;
+ } else if (last_offset < -deactivate_threshold) {
+ if (dev->freq_cal.freq < 0xbf)
+ dev->freq_cal.freq++;
+ else
+ dev->freq_cal.adjusting = false;
+ }
+
+ trace_freq_cal_adjust(dev, dev->freq_cal.freq);
+ mt7601u_rf_wr(dev, 0, 12, dev->freq_cal.freq);
+ mt7601u_vco_cal(dev);
+
+ return dev->freq_cal.adjusting ? MT_FREQ_CAL_ADJ_INTERVAL :
+ MT_FREQ_CAL_CHECK_INTERVAL;
+}
+
+static void mt7601u_phy_freq_cal(struct work_struct *work)
+{
+ struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev,
+ freq_cal.work.work);
+ s8 last_offset;
+ u8 phy_mode;
+ unsigned long delay;
+
+ spin_lock_bh(&dev->con_mon_lock);
+ last_offset = dev->bcn_freq_off;
+ phy_mode = dev->bcn_phy_mode;
+ spin_unlock_bh(&dev->con_mon_lock);
+
+ delay = __mt7601u_phy_freq_cal(dev, last_offset, phy_mode);
+ ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, delay);
+
+ spin_lock_bh(&dev->con_mon_lock);
+ dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID;
+ spin_unlock_bh(&dev->con_mon_lock);
+}
+
+void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev,
+ struct ieee80211_bss_conf *info)
+{
+ if (!info->assoc)
+ cancel_delayed_work_sync(&dev->freq_cal.work);
+
+ /* Start/stop collecting beacon data */
+ spin_lock_bh(&dev->con_mon_lock);
+ ether_addr_copy(dev->ap_bssid, info->bssid);
+ dev->avg_rssi = 0;
+ dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID;
+ spin_unlock_bh(&dev->con_mon_lock);
+
+ dev->freq_cal.freq = dev->ee->rf_freq_off;
+ dev->freq_cal.enabled = info->assoc;
+ dev->freq_cal.adjusting = false;
+
+ if (info->assoc)
+ ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work,
+ MT_FREQ_CAL_INIT_DELAY);
+}
+
+static int mt7601u_init_cal(struct mt7601u_dev *dev)
+{
+ u32 mac_ctrl;
+ int ret;
+
+ dev->raw_temp = mt7601u_read_bootup_temp(dev);
+ dev->curr_temp = (dev->raw_temp - dev->ee->ref_temp) *
+ MT_EE_TEMPERATURE_SLOPE;
+ dev->dpd_temp = dev->curr_temp;
+
+ mac_ctrl = mt7601u_rr(dev, MT_MAC_SYS_CTRL);
+
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_R, 0);
+ if (ret)
+ return ret;
+
+ ret = mt7601u_rf_rr(dev, 0, 4);
+ if (ret < 0)
+ return ret;
+ ret |= 0x80;
+ ret = mt7601u_rf_wr(dev, 0, 4, ret);
+ if (ret)
+ return ret;
+ msleep(2);
+
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_TXDCOC, 0);
+ if (ret)
+ return ret;
+
+ mt7601u_rxdc_cal(dev);
+
+ ret = mt7601u_set_bw_filter(dev, true);
+ if (ret)
+ return ret;
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_LOFT, 0);
+ if (ret)
+ return ret;
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_TXIQ, 0);
+ if (ret)
+ return ret;
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_RXIQ, 0);
+ if (ret)
+ return ret;
+ ret = mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->dpd_temp);
+ if (ret)
+ return ret;
+
+ mt7601u_rxdc_cal(dev);
+
+ mt7601u_tssi_dc_gain_cal(dev);
+
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, mac_ctrl);
+
+ mt7601u_temp_comp(dev, true);
+
+ return 0;
+}
+
+int mt7601u_bbp_set_bw(struct mt7601u_dev *dev, int bw)
+{
+ u32 val, old;
+
+ if (bw == dev->bw) {
+ /* Vendor driver does the rmc even when no change is needed. */
+ mt7601u_bbp_rmc(dev, 4, 0x18, bw == MT_BW_20 ? 0 : 0x10);
+
+ return 0;
+ }
+ dev->bw = bw;
+
+ /* Stop MAC for the time of bw change */
+ old = mt7601u_rr(dev, MT_MAC_SYS_CTRL);
+ val = old & ~(MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, val);
+ mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX | MT_MAC_STATUS_RX,
+ 0, 500000);
+
+ mt7601u_bbp_rmc(dev, 4, 0x18, bw == MT_BW_20 ? 0 : 0x10);
+
+ mt7601u_wr(dev, MT_MAC_SYS_CTRL, old);
+
+ return mt7601u_load_bbp_temp_table_bw(dev);
+}
+
+/**
+ * mt7601u_set_rx_path - set rx path in BBP
+ * @dev: pointer to adapter structure
+ * @path: rx path to set values are 0-based
+ */
+void mt7601u_set_rx_path(struct mt7601u_dev *dev, u8 path)
+{
+ mt7601u_bbp_rmw(dev, 3, 0x18, path << 3);
+}
+
+/**
+ * mt7601u_set_tx_dac - set which tx DAC to use
+ * @dev: pointer to adapter structure
+ * @path: DAC index, values are 0-based
+ */
+void mt7601u_set_tx_dac(struct mt7601u_dev *dev, u8 dac)
+{
+ mt7601u_bbp_rmc(dev, 1, 0x18, dac << 3);
+}
+
+int mt7601u_phy_init(struct mt7601u_dev *dev)
+{
+ int ret;
+
+ dev->rf_pa_mode[0] = mt7601u_rr(dev, MT_RF_PA_MODE_CFG0);
+ dev->rf_pa_mode[1] = mt7601u_rr(dev, MT_RF_PA_MODE_CFG1);
+
+ ret = mt7601u_rf_wr(dev, 0, 12, dev->ee->rf_freq_off);
+ if (ret)
+ return ret;
+ ret = mt7601u_write_reg_pairs(dev, 0, rf_central,
+ ARRAY_SIZE(rf_central));
+ if (ret)
+ return ret;
+ ret = mt7601u_write_reg_pairs(dev, 0, rf_channel,
+ ARRAY_SIZE(rf_channel));
+ if (ret)
+ return ret;
+ ret = mt7601u_write_reg_pairs(dev, 0, rf_vga, ARRAY_SIZE(rf_vga));
+ if (ret)
+ return ret;
+
+ ret = mt7601u_init_cal(dev);
+ if (ret)
+ return ret;
+
+ dev->prev_pwr_diff = 100;
+
+ INIT_DELAYED_WORK(&dev->cal_work, mt7601u_phy_calibrate);
+ INIT_DELAYED_WORK(&dev->freq_cal.work, mt7601u_phy_freq_cal);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/regs.h b/drivers/net/wireless/mediatek/mt7601u/regs.h
new file mode 100644
index 000000000000..afd8978e83fa
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/regs.h
@@ -0,0 +1,636 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#ifndef __MT76_REGS_H
+#define __MT76_REGS_H
+
+#include <linux/bitops.h>
+
+#ifndef GENMASK
+#define GENMASK(h, l) (((U32_C(1) << ((h) - (l) + 1)) - 1) << (l))
+#endif
+
+#define MT_ASIC_VERSION 0x0000
+
+#define MT76XX_REV_E3 0x22
+#define MT76XX_REV_E4 0x33
+
+#define MT_CMB_CTRL 0x0020
+#define MT_CMB_CTRL_XTAL_RDY BIT(22)
+#define MT_CMB_CTRL_PLL_LD BIT(23)
+
+#define MT_EFUSE_CTRL 0x0024
+#define MT_EFUSE_CTRL_AOUT GENMASK(5, 0)
+#define MT_EFUSE_CTRL_MODE GENMASK(7, 6)
+#define MT_EFUSE_CTRL_LDO_OFF_TIME GENMASK(13, 8)
+#define MT_EFUSE_CTRL_LDO_ON_TIME GENMASK(15, 14)
+#define MT_EFUSE_CTRL_AIN GENMASK(25, 16)
+#define MT_EFUSE_CTRL_KICK BIT(30)
+#define MT_EFUSE_CTRL_SEL BIT(31)
+
+#define MT_EFUSE_DATA_BASE 0x0028
+#define MT_EFUSE_DATA(_n) (MT_EFUSE_DATA_BASE + ((_n) << 2))
+
+#define MT_COEXCFG0 0x0040
+#define MT_COEXCFG0_COEX_EN BIT(0)
+
+#define MT_WLAN_FUN_CTRL 0x0080
+#define MT_WLAN_FUN_CTRL_WLAN_EN BIT(0)
+#define MT_WLAN_FUN_CTRL_WLAN_CLK_EN BIT(1)
+#define MT_WLAN_FUN_CTRL_WLAN_RESET_RF BIT(2)
+
+#define MT_WLAN_FUN_CTRL_WLAN_RESET BIT(3) /* MT76x0 */
+#define MT_WLAN_FUN_CTRL_CSR_F20M_CKEN BIT(3) /* MT76x2 */
+
+#define MT_WLAN_FUN_CTRL_PCIE_CLK_REQ BIT(4)
+#define MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL BIT(5)
+#define MT_WLAN_FUN_CTRL_INV_ANT_SEL BIT(6)
+#define MT_WLAN_FUN_CTRL_WAKE_HOST BIT(7)
+
+#define MT_WLAN_FUN_CTRL_THERM_RST BIT(8) /* MT76x2 */
+#define MT_WLAN_FUN_CTRL_THERM_CKEN BIT(9) /* MT76x2 */
+
+#define MT_WLAN_FUN_CTRL_GPIO_IN GENMASK(15, 8) /* MT76x0 */
+#define MT_WLAN_FUN_CTRL_GPIO_OUT GENMASK(23, 16) /* MT76x0 */
+#define MT_WLAN_FUN_CTRL_GPIO_OUT_EN GENMASK(31, 24) /* MT76x0 */
+
+#define MT_XO_CTRL0 0x0100
+#define MT_XO_CTRL1 0x0104
+#define MT_XO_CTRL2 0x0108
+#define MT_XO_CTRL3 0x010c
+#define MT_XO_CTRL4 0x0110
+
+#define MT_XO_CTRL5 0x0114
+#define MT_XO_CTRL5_C2_VAL GENMASK(14, 8)
+
+#define MT_XO_CTRL6 0x0118
+#define MT_XO_CTRL6_C2_CTRL GENMASK(14, 8)
+
+#define MT_XO_CTRL7 0x011c
+
+#define MT_WLAN_MTC_CTRL 0x10148
+#define MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP BIT(0)
+#define MT_WLAN_MTC_CTRL_PWR_ACK BIT(12)
+#define MT_WLAN_MTC_CTRL_PWR_ACK_S BIT(13)
+#define MT_WLAN_MTC_CTRL_BBP_MEM_PD GENMASK(19, 16)
+#define MT_WLAN_MTC_CTRL_PBF_MEM_PD BIT(20)
+#define MT_WLAN_MTC_CTRL_FCE_MEM_PD BIT(21)
+#define MT_WLAN_MTC_CTRL_TSO_MEM_PD BIT(22)
+#define MT_WLAN_MTC_CTRL_BBP_MEM_RB BIT(24)
+#define MT_WLAN_MTC_CTRL_PBF_MEM_RB BIT(25)
+#define MT_WLAN_MTC_CTRL_FCE_MEM_RB BIT(26)
+#define MT_WLAN_MTC_CTRL_TSO_MEM_RB BIT(27)
+#define MT_WLAN_MTC_CTRL_STATE_UP BIT(28)
+
+#define MT_INT_SOURCE_CSR 0x0200
+#define MT_INT_MASK_CSR 0x0204
+
+#define MT_INT_RX_DONE(_n) BIT(_n)
+#define MT_INT_RX_DONE_ALL GENMASK(1, 0)
+#define MT_INT_TX_DONE_ALL GENMASK(13, 4)
+#define MT_INT_TX_DONE(_n) BIT(_n + 4)
+#define MT_INT_RX_COHERENT BIT(16)
+#define MT_INT_TX_COHERENT BIT(17)
+#define MT_INT_ANY_COHERENT BIT(18)
+#define MT_INT_MCU_CMD BIT(19)
+#define MT_INT_TBTT BIT(20)
+#define MT_INT_PRE_TBTT BIT(21)
+#define MT_INT_TX_STAT BIT(22)
+#define MT_INT_AUTO_WAKEUP BIT(23)
+#define MT_INT_GPTIMER BIT(24)
+#define MT_INT_RXDELAYINT BIT(26)
+#define MT_INT_TXDELAYINT BIT(27)
+
+#define MT_WPDMA_GLO_CFG 0x0208
+#define MT_WPDMA_GLO_CFG_TX_DMA_EN BIT(0)
+#define MT_WPDMA_GLO_CFG_TX_DMA_BUSY BIT(1)
+#define MT_WPDMA_GLO_CFG_RX_DMA_EN BIT(2)
+#define MT_WPDMA_GLO_CFG_RX_DMA_BUSY BIT(3)
+#define MT_WPDMA_GLO_CFG_DMA_BURST_SIZE GENMASK(5, 4)
+#define MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE BIT(6)
+#define MT_WPDMA_GLO_CFG_BIG_ENDIAN BIT(7)
+#define MT_WPDMA_GLO_CFG_HDR_SEG_LEN GENMASK(15, 8)
+#define MT_WPDMA_GLO_CFG_CLK_GATE_DIS BIT(30)
+#define MT_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31)
+
+#define MT_WPDMA_RST_IDX 0x020c
+
+#define MT_WPDMA_DELAY_INT_CFG 0x0210
+
+#define MT_WMM_AIFSN 0x0214
+#define MT_WMM_AIFSN_MASK GENMASK(3, 0)
+#define MT_WMM_AIFSN_SHIFT(_n) ((_n) * 4)
+
+#define MT_WMM_CWMIN 0x0218
+#define MT_WMM_CWMIN_MASK GENMASK(3, 0)
+#define MT_WMM_CWMIN_SHIFT(_n) ((_n) * 4)
+
+#define MT_WMM_CWMAX 0x021c
+#define MT_WMM_CWMAX_MASK GENMASK(3, 0)
+#define MT_WMM_CWMAX_SHIFT(_n) ((_n) * 4)
+
+#define MT_WMM_TXOP_BASE 0x0220
+#define MT_WMM_TXOP(_n) (MT_WMM_TXOP_BASE + (((_n) / 2) << 2))
+#define MT_WMM_TXOP_SHIFT(_n) ((_n & 1) * 16)
+#define MT_WMM_TXOP_MASK GENMASK(15, 0)
+
+#define MT_FCE_DMA_ADDR 0x0230
+#define MT_FCE_DMA_LEN 0x0234
+
+#define MT_USB_DMA_CFG 0x238
+#define MT_USB_DMA_CFG_RX_BULK_AGG_TOUT GENMASK(7, 0)
+#define MT_USB_DMA_CFG_RX_BULK_AGG_LMT GENMASK(15, 8)
+#define MT_USB_DMA_CFG_PHY_CLR BIT(16)
+#define MT_USB_DMA_CFG_TX_CLR BIT(19)
+#define MT_USB_DMA_CFG_TXOP_HALT BIT(20)
+#define MT_USB_DMA_CFG_RX_BULK_AGG_EN BIT(21)
+#define MT_USB_DMA_CFG_RX_BULK_EN BIT(22)
+#define MT_USB_DMA_CFG_TX_BULK_EN BIT(23)
+#define MT_USB_DMA_CFG_UDMA_RX_WL_DROP BIT(25)
+#define MT_USB_DMA_CFG_EP_OUT_VALID GENMASK(29, 27)
+#define MT_USB_DMA_CFG_RX_BUSY BIT(30)
+#define MT_USB_DMA_CFG_TX_BUSY BIT(31)
+
+#define MT_TSO_CTRL 0x0250
+#define MT_HEADER_TRANS_CTRL_REG 0x0260
+
+#define MT_US_CYC_CFG 0x02a4
+#define MT_US_CYC_CNT GENMASK(7, 0)
+
+#define MT_TX_RING_BASE 0x0300
+#define MT_RX_RING_BASE 0x03c0
+#define MT_RING_SIZE 0x10
+
+#define MT_TX_HW_QUEUE_MCU 8
+#define MT_TX_HW_QUEUE_MGMT 9
+
+#define MT_PBF_SYS_CTRL 0x0400
+#define MT_PBF_SYS_CTRL_MCU_RESET BIT(0)
+#define MT_PBF_SYS_CTRL_DMA_RESET BIT(1)
+#define MT_PBF_SYS_CTRL_MAC_RESET BIT(2)
+#define MT_PBF_SYS_CTRL_PBF_RESET BIT(3)
+#define MT_PBF_SYS_CTRL_ASY_RESET BIT(4)
+
+#define MT_PBF_CFG 0x0404
+#define MT_PBF_CFG_TX0Q_EN BIT(0)
+#define MT_PBF_CFG_TX1Q_EN BIT(1)
+#define MT_PBF_CFG_TX2Q_EN BIT(2)
+#define MT_PBF_CFG_TX3Q_EN BIT(3)
+#define MT_PBF_CFG_RX0Q_EN BIT(4)
+#define MT_PBF_CFG_RX_DROP_EN BIT(8)
+
+#define MT_PBF_TX_MAX_PCNT 0x0408
+#define MT_PBF_RX_MAX_PCNT 0x040c
+
+#define MT_BCN_OFFSET_BASE 0x041c
+#define MT_BCN_OFFSET(_n) (MT_BCN_OFFSET_BASE + ((_n) << 2))
+
+#define MT_RF_CSR_CFG 0x0500
+#define MT_RF_CSR_CFG_DATA GENMASK(7, 0)
+#define MT_RF_CSR_CFG_REG_ID GENMASK(13, 8)
+#define MT_RF_CSR_CFG_REG_BANK GENMASK(17, 14)
+#define MT_RF_CSR_CFG_WR BIT(30)
+#define MT_RF_CSR_CFG_KICK BIT(31)
+
+#define MT_RF_BYPASS_0 0x0504
+#define MT_RF_BYPASS_1 0x0508
+#define MT_RF_SETTING_0 0x050c
+
+#define MT_RF_DATA_WRITE 0x0524
+
+#define MT_RF_CTRL 0x0528
+#define MT_RF_CTRL_ADDR GENMASK(11, 0)
+#define MT_RF_CTRL_WRITE BIT(12)
+#define MT_RF_CTRL_BUSY BIT(13)
+#define MT_RF_CTRL_IDX BIT(16)
+
+#define MT_RF_DATA_READ 0x052c
+
+#define MT_FCE_PSE_CTRL 0x0800
+#define MT_FCE_PARAMETERS 0x0804
+#define MT_FCE_CSO 0x0808
+
+#define MT_FCE_L2_STUFF 0x080c
+#define MT_FCE_L2_STUFF_HT_L2_EN BIT(0)
+#define MT_FCE_L2_STUFF_QOS_L2_EN BIT(1)
+#define MT_FCE_L2_STUFF_RX_STUFF_EN BIT(2)
+#define MT_FCE_L2_STUFF_TX_STUFF_EN BIT(3)
+#define MT_FCE_L2_STUFF_WR_MPDU_LEN_EN BIT(4)
+#define MT_FCE_L2_STUFF_MVINV_BSWAP BIT(5)
+#define MT_FCE_L2_STUFF_TS_CMD_QSEL_EN GENMASK(15, 8)
+#define MT_FCE_L2_STUFF_TS_LEN_EN GENMASK(23, 16)
+#define MT_FCE_L2_STUFF_OTHER_PORT GENMASK(25, 24)
+
+#define MT_FCE_WLAN_FLOW_CONTROL1 0x0824
+
+#define MT_TX_CPU_FROM_FCE_BASE_PTR 0x09a0
+#define MT_TX_CPU_FROM_FCE_MAX_COUNT 0x09a4
+#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8
+
+#define MT_FCE_PDMA_GLOBAL_CONF 0x09c4
+
+#define MT_PAUSE_ENABLE_CONTROL1 0x0a38
+
+#define MT_FCE_SKIP_FS 0x0a6c
+
+#define MT_MAC_CSR0 0x1000
+
+#define MT_MAC_SYS_CTRL 0x1004
+#define MT_MAC_SYS_CTRL_RESET_CSR BIT(0)
+#define MT_MAC_SYS_CTRL_RESET_BBP BIT(1)
+#define MT_MAC_SYS_CTRL_ENABLE_TX BIT(2)
+#define MT_MAC_SYS_CTRL_ENABLE_RX BIT(3)
+
+#define MT_MAC_ADDR_DW0 0x1008
+#define MT_MAC_ADDR_DW1 0x100c
+#define MT_MAC_ADDR_DW1_U2ME_MASK GENMASK(23, 16)
+
+#define MT_MAC_BSSID_DW0 0x1010
+#define MT_MAC_BSSID_DW1 0x1014
+#define MT_MAC_BSSID_DW1_ADDR GENMASK(15, 0)
+#define MT_MAC_BSSID_DW1_MBSS_MODE GENMASK(17, 16)
+#define MT_MAC_BSSID_DW1_MBEACON_N GENMASK(20, 18)
+#define MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT BIT(21)
+#define MT_MAC_BSSID_DW1_MBSS_MODE_B2 BIT(22)
+#define MT_MAC_BSSID_DW1_MBEACON_N_B3 BIT(23)
+#define MT_MAC_BSSID_DW1_MBSS_IDX_BYTE GENMASK(26, 24)
+
+#define MT_MAX_LEN_CFG 0x1018
+#define MT_MAX_LEN_CFG_AMPDU GENMASK(13, 12)
+
+#define MT_BBP_CSR_CFG 0x101c
+#define MT_BBP_CSR_CFG_VAL GENMASK(7, 0)
+#define MT_BBP_CSR_CFG_REG_NUM GENMASK(15, 8)
+#define MT_BBP_CSR_CFG_READ BIT(16)
+#define MT_BBP_CSR_CFG_BUSY BIT(17)
+#define MT_BBP_CSR_CFG_PAR_DUR BIT(18)
+#define MT_BBP_CSR_CFG_RW_MODE BIT(19)
+
+#define MT_AMPDU_MAX_LEN_20M1S 0x1030
+#define MT_AMPDU_MAX_LEN_20M2S 0x1034
+#define MT_AMPDU_MAX_LEN_40M1S 0x1038
+#define MT_AMPDU_MAX_LEN_40M2S 0x103c
+#define MT_AMPDU_MAX_LEN 0x1040
+
+#define MT_WCID_DROP_BASE 0x106c
+#define MT_WCID_DROP(_n) (MT_WCID_DROP_BASE + ((_n) >> 5) * 4)
+#define MT_WCID_DROP_MASK(_n) BIT((_n) % 32)
+
+#define MT_BCN_BYPASS_MASK 0x108c
+
+#define MT_MAC_APC_BSSID_BASE 0x1090
+#define MT_MAC_APC_BSSID_L(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8))
+#define MT_MAC_APC_BSSID_H(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8 + 4))
+#define MT_MAC_APC_BSSID_H_ADDR GENMASK(15, 0)
+#define MT_MAC_APC_BSSID0_H_EN BIT(16)
+
+#define MT_XIFS_TIME_CFG 0x1100
+#define MT_XIFS_TIME_CFG_CCK_SIFS GENMASK(7, 0)
+#define MT_XIFS_TIME_CFG_OFDM_SIFS GENMASK(15, 8)
+#define MT_XIFS_TIME_CFG_OFDM_XIFS GENMASK(19, 16)
+#define MT_XIFS_TIME_CFG_EIFS GENMASK(28, 20)
+#define MT_XIFS_TIME_CFG_BB_RXEND_EN BIT(29)
+
+#define MT_BKOFF_SLOT_CFG 0x1104
+#define MT_BKOFF_SLOT_CFG_SLOTTIME GENMASK(7, 0)
+#define MT_BKOFF_SLOT_CFG_CC_DELAY GENMASK(11, 8)
+
+#define MT_BEACON_TIME_CFG 0x1114
+#define MT_BEACON_TIME_CFG_INTVAL GENMASK(15, 0)
+#define MT_BEACON_TIME_CFG_TIMER_EN BIT(16)
+#define MT_BEACON_TIME_CFG_SYNC_MODE GENMASK(18, 17)
+#define MT_BEACON_TIME_CFG_TBTT_EN BIT(19)
+#define MT_BEACON_TIME_CFG_BEACON_TX BIT(20)
+#define MT_BEACON_TIME_CFG_TSF_COMP GENMASK(31, 24)
+
+#define MT_TBTT_SYNC_CFG 0x1118
+#define MT_TBTT_TIMER_CFG 0x1124
+
+#define MT_INT_TIMER_CFG 0x1128
+#define MT_INT_TIMER_CFG_PRE_TBTT GENMASK(15, 0)
+#define MT_INT_TIMER_CFG_GP_TIMER GENMASK(31, 16)
+
+#define MT_INT_TIMER_EN 0x112c
+#define MT_INT_TIMER_EN_PRE_TBTT_EN BIT(0)
+#define MT_INT_TIMER_EN_GP_TIMER_EN BIT(1)
+
+#define MT_MAC_STATUS 0x1200
+#define MT_MAC_STATUS_TX BIT(0)
+#define MT_MAC_STATUS_RX BIT(1)
+
+#define MT_PWR_PIN_CFG 0x1204
+#define MT_AUX_CLK_CFG 0x120c
+
+#define MT_BB_PA_MODE_CFG0 0x1214
+#define MT_BB_PA_MODE_CFG1 0x1218
+#define MT_RF_PA_MODE_CFG0 0x121c
+#define MT_RF_PA_MODE_CFG1 0x1220
+
+#define MT_RF_PA_MODE_ADJ0 0x1228
+#define MT_RF_PA_MODE_ADJ1 0x122c
+
+#define MT_DACCLK_EN_DLY_CFG 0x1264
+
+#define MT_EDCA_CFG_BASE 0x1300
+#define MT_EDCA_CFG_AC(_n) (MT_EDCA_CFG_BASE + ((_n) << 2))
+#define MT_EDCA_CFG_TXOP GENMASK(7, 0)
+#define MT_EDCA_CFG_AIFSN GENMASK(11, 8)
+#define MT_EDCA_CFG_CWMIN GENMASK(15, 12)
+#define MT_EDCA_CFG_CWMAX GENMASK(19, 16)
+
+#define MT_TX_PWR_CFG_0 0x1314
+#define MT_TX_PWR_CFG_1 0x1318
+#define MT_TX_PWR_CFG_2 0x131c
+#define MT_TX_PWR_CFG_3 0x1320
+#define MT_TX_PWR_CFG_4 0x1324
+
+#define MT_TX_BAND_CFG 0x132c
+#define MT_TX_BAND_CFG_UPPER_40M BIT(0)
+#define MT_TX_BAND_CFG_5G BIT(1)
+#define MT_TX_BAND_CFG_2G BIT(2)
+
+#define MT_HT_FBK_TO_LEGACY 0x1384
+#define MT_TX_MPDU_ADJ_INT 0x1388
+
+#define MT_TX_PWR_CFG_7 0x13d4
+#define MT_TX_PWR_CFG_8 0x13d8
+#define MT_TX_PWR_CFG_9 0x13dc
+
+#define MT_TX_SW_CFG0 0x1330
+#define MT_TX_SW_CFG1 0x1334
+#define MT_TX_SW_CFG2 0x1338
+
+#define MT_TXOP_CTRL_CFG 0x1340
+#define MT_TXOP_TRUN_EN GENMASK(5, 0)
+#define MT_TXOP_EXT_CCA_DLY GENMASK(15, 8)
+#define MT_TXOP_CTRL
+
+#define MT_TX_RTS_CFG 0x1344
+#define MT_TX_RTS_CFG_RETRY_LIMIT GENMASK(7, 0)
+#define MT_TX_RTS_CFG_THRESH GENMASK(23, 8)
+#define MT_TX_RTS_FALLBACK BIT(24)
+
+#define MT_TX_TIMEOUT_CFG 0x1348
+#define MT_TX_RETRY_CFG 0x134c
+#define MT_TX_LINK_CFG 0x1350
+#define MT_HT_FBK_CFG0 0x1354
+#define MT_HT_FBK_CFG1 0x1358
+#define MT_LG_FBK_CFG0 0x135c
+#define MT_LG_FBK_CFG1 0x1360
+
+#define MT_CCK_PROT_CFG 0x1364
+#define MT_OFDM_PROT_CFG 0x1368
+#define MT_MM20_PROT_CFG 0x136c
+#define MT_MM40_PROT_CFG 0x1370
+#define MT_GF20_PROT_CFG 0x1374
+#define MT_GF40_PROT_CFG 0x1378
+
+#define MT_PROT_RATE GENMASK(15, 0)
+#define MT_PROT_CTRL_RTS_CTS BIT(16)
+#define MT_PROT_CTRL_CTS2SELF BIT(17)
+#define MT_PROT_NAV_SHORT BIT(18)
+#define MT_PROT_NAV_LONG BIT(19)
+#define MT_PROT_TXOP_ALLOW_CCK BIT(20)
+#define MT_PROT_TXOP_ALLOW_OFDM BIT(21)
+#define MT_PROT_TXOP_ALLOW_MM20 BIT(22)
+#define MT_PROT_TXOP_ALLOW_MM40 BIT(23)
+#define MT_PROT_TXOP_ALLOW_GF20 BIT(24)
+#define MT_PROT_TXOP_ALLOW_GF40 BIT(25)
+#define MT_PROT_RTS_THR_EN BIT(26)
+#define MT_PROT_RATE_CCK_11 0x0003
+#define MT_PROT_RATE_OFDM_6 0x4000
+#define MT_PROT_RATE_OFDM_24 0x4004
+#define MT_PROT_RATE_DUP_OFDM_24 0x4084
+#define MT_PROT_TXOP_ALLOW_ALL GENMASK(25, 20)
+#define MT_PROT_TXOP_ALLOW_BW20 (MT_PROT_TXOP_ALLOW_ALL & \
+ ~MT_PROT_TXOP_ALLOW_MM40 & \
+ ~MT_PROT_TXOP_ALLOW_GF40)
+
+#define MT_EXP_ACK_TIME 0x1380
+
+#define MT_TX_PWR_CFG_0_EXT 0x1390
+#define MT_TX_PWR_CFG_1_EXT 0x1394
+
+#define MT_TX_FBK_LIMIT 0x1398
+#define MT_TX_FBK_LIMIT_MPDU_FBK GENMASK(7, 0)
+#define MT_TX_FBK_LIMIT_AMPDU_FBK GENMASK(15, 8)
+#define MT_TX_FBK_LIMIT_MPDU_UP_CLEAR BIT(16)
+#define MT_TX_FBK_LIMIT_AMPDU_UP_CLEAR BIT(17)
+#define MT_TX_FBK_LIMIT_RATE_LUT BIT(18)
+
+#define MT_TX0_RF_GAIN_CORR 0x13a0
+#define MT_TX1_RF_GAIN_CORR 0x13a4
+#define MT_TX0_RF_GAIN_ATTEN 0x13a8
+
+#define MT_TX_ALC_CFG_0 0x13b0
+#define MT_TX_ALC_CFG_0_CH_INIT_0 GENMASK(5, 0)
+#define MT_TX_ALC_CFG_0_CH_INIT_1 GENMASK(13, 8)
+#define MT_TX_ALC_CFG_0_LIMIT_0 GENMASK(21, 16)
+#define MT_TX_ALC_CFG_0_LIMIT_1 GENMASK(29, 24)
+
+#define MT_TX_ALC_CFG_1 0x13b4
+#define MT_TX_ALC_CFG_1_TEMP_COMP GENMASK(5, 0)
+
+#define MT_TX_ALC_CFG_2 0x13a8
+#define MT_TX_ALC_CFG_2_TEMP_COMP GENMASK(5, 0)
+
+#define MT_TX0_BB_GAIN_ATTEN 0x13c0
+
+#define MT_TX_ALC_VGA3 0x13c8
+
+#define MT_TX_PROT_CFG6 0x13e0
+#define MT_TX_PROT_CFG7 0x13e4
+#define MT_TX_PROT_CFG8 0x13e8
+
+#define MT_PIFS_TX_CFG 0x13ec
+
+#define MT_RX_FILTR_CFG 0x1400
+
+#define MT_RX_FILTR_CFG_CRC_ERR BIT(0)
+#define MT_RX_FILTR_CFG_PHY_ERR BIT(1)
+#define MT_RX_FILTR_CFG_PROMISC BIT(2)
+#define MT_RX_FILTR_CFG_OTHER_BSS BIT(3)
+#define MT_RX_FILTR_CFG_VER_ERR BIT(4)
+#define MT_RX_FILTR_CFG_MCAST BIT(5)
+#define MT_RX_FILTR_CFG_BCAST BIT(6)
+#define MT_RX_FILTR_CFG_DUP BIT(7)
+#define MT_RX_FILTR_CFG_CFACK BIT(8)
+#define MT_RX_FILTR_CFG_CFEND BIT(9)
+#define MT_RX_FILTR_CFG_ACK BIT(10)
+#define MT_RX_FILTR_CFG_CTS BIT(11)
+#define MT_RX_FILTR_CFG_RTS BIT(12)
+#define MT_RX_FILTR_CFG_PSPOLL BIT(13)
+#define MT_RX_FILTR_CFG_BA BIT(14)
+#define MT_RX_FILTR_CFG_BAR BIT(15)
+#define MT_RX_FILTR_CFG_CTRL_RSV BIT(16)
+
+#define MT_AUTO_RSP_CFG 0x1404
+
+#define MT_AUTO_RSP_PREAMB_SHORT BIT(4)
+
+#define MT_LEGACY_BASIC_RATE 0x1408
+#define MT_HT_BASIC_RATE 0x140c
+
+#define MT_RX_PARSER_CFG 0x1418
+#define MT_RX_PARSER_RX_SET_NAV_ALL BIT(0)
+
+#define MT_EXT_CCA_CFG 0x141c
+#define MT_EXT_CCA_CFG_CCA0 GENMASK(1, 0)
+#define MT_EXT_CCA_CFG_CCA1 GENMASK(3, 2)
+#define MT_EXT_CCA_CFG_CCA2 GENMASK(5, 4)
+#define MT_EXT_CCA_CFG_CCA3 GENMASK(7, 6)
+#define MT_EXT_CCA_CFG_CCA_MASK GENMASK(11, 8)
+#define MT_EXT_CCA_CFG_ED_CCA_MASK GENMASK(15, 12)
+
+#define MT_TX_SW_CFG3 0x1478
+
+#define MT_PN_PAD_MODE 0x150c
+
+#define MT_TXOP_HLDR_ET 0x1608
+
+#define MT_PROT_AUTO_TX_CFG 0x1648
+
+#define MT_RX_STA_CNT0 0x1700
+#define MT_RX_STA_CNT1 0x1704
+#define MT_RX_STA_CNT2 0x1708
+#define MT_TX_STA_CNT0 0x170c
+#define MT_TX_STA_CNT1 0x1710
+#define MT_TX_STA_CNT2 0x1714
+
+/* Vendor driver defines content of the second word of STAT_FIFO as follows:
+ * MT_TX_STAT_FIFO_RATE GENMASK(26, 16)
+ * MT_TX_STAT_FIFO_ETXBF BIT(27)
+ * MT_TX_STAT_FIFO_SND BIT(28)
+ * MT_TX_STAT_FIFO_ITXBF BIT(29)
+ * However, tests show that b16-31 have the same layout as TXWI rate_ctl
+ * with rate set to rate at which frame was acked.
+ */
+#define MT_TX_STAT_FIFO 0x1718
+#define MT_TX_STAT_FIFO_VALID BIT(0)
+#define MT_TX_STAT_FIFO_PID_TYPE GENMASK(4, 1)
+#define MT_TX_STAT_FIFO_SUCCESS BIT(5)
+#define MT_TX_STAT_FIFO_AGGR BIT(6)
+#define MT_TX_STAT_FIFO_ACKREQ BIT(7)
+#define MT_TX_STAT_FIFO_WCID GENMASK(15, 8)
+#define MT_TX_STAT_FIFO_RATE GENMASK(31, 16)
+
+#define MT_TX_AGG_STAT 0x171c
+
+#define MT_TX_AGG_CNT_BASE0 0x1720
+
+#define MT_MPDU_DENSITY_CNT 0x1740
+
+#define MT_TX_AGG_CNT_BASE1 0x174c
+
+#define MT_TX_AGG_CNT(_id) ((_id) < 8 ? \
+ MT_TX_AGG_CNT_BASE0 + ((_id) << 2) : \
+ MT_TX_AGG_CNT_BASE1 + ((_id - 8) << 2))
+
+#define MT_TX_STAT_FIFO_EXT 0x1798
+#define MT_TX_STAT_FIFO_EXT_RETRY GENMASK(7, 0)
+
+#define MT_BBP_CORE_BASE 0x2000
+#define MT_BBP_IBI_BASE 0x2100
+#define MT_BBP_AGC_BASE 0x2300
+#define MT_BBP_TXC_BASE 0x2400
+#define MT_BBP_RXC_BASE 0x2500
+#define MT_BBP_TXO_BASE 0x2600
+#define MT_BBP_TXBE_BASE 0x2700
+#define MT_BBP_RXFE_BASE 0x2800
+#define MT_BBP_RXO_BASE 0x2900
+#define MT_BBP_DFS_BASE 0x2a00
+#define MT_BBP_TR_BASE 0x2b00
+#define MT_BBP_CAL_BASE 0x2c00
+#define MT_BBP_DSC_BASE 0x2e00
+#define MT_BBP_PFMU_BASE 0x2f00
+
+#define MT_BBP(_type, _n) (MT_BBP_##_type##_BASE + ((_n) << 2))
+
+#define MT_BBP_CORE_R1_BW GENMASK(4, 3)
+
+#define MT_BBP_AGC_R0_CTRL_CHAN GENMASK(9, 8)
+#define MT_BBP_AGC_R0_BW GENMASK(14, 12)
+
+/* AGC, R4/R5 */
+#define MT_BBP_AGC_LNA_GAIN GENMASK(21, 16)
+
+/* AGC, R8/R9 */
+#define MT_BBP_AGC_GAIN GENMASK(14, 8)
+
+#define MT_BBP_AGC20_RSSI0 GENMASK(7, 0)
+#define MT_BBP_AGC20_RSSI1 GENMASK(15, 8)
+
+#define MT_BBP_TXBE_R0_CTRL_CHAN GENMASK(1, 0)
+
+#define MT_WCID_ADDR_BASE 0x1800
+#define MT_WCID_ADDR(_n) (MT_WCID_ADDR_BASE + (_n) * 8)
+
+#define MT_SRAM_BASE 0x4000
+
+#define MT_WCID_KEY_BASE 0x8000
+#define MT_WCID_KEY(_n) (MT_WCID_KEY_BASE + (_n) * 32)
+
+#define MT_WCID_IV_BASE 0xa000
+#define MT_WCID_IV(_n) (MT_WCID_IV_BASE + (_n) * 8)
+
+#define MT_WCID_ATTR_BASE 0xa800
+#define MT_WCID_ATTR(_n) (MT_WCID_ATTR_BASE + (_n) * 4)
+
+#define MT_WCID_ATTR_PAIRWISE BIT(0)
+#define MT_WCID_ATTR_PKEY_MODE GENMASK(3, 1)
+#define MT_WCID_ATTR_BSS_IDX GENMASK(6, 4)
+#define MT_WCID_ATTR_RXWI_UDF GENMASK(9, 7)
+#define MT_WCID_ATTR_PKEY_MODE_EXT BIT(10)
+#define MT_WCID_ATTR_BSS_IDX_EXT BIT(11)
+#define MT_WCID_ATTR_WAPI_MCBC BIT(15)
+#define MT_WCID_ATTR_WAPI_KEYID GENMASK(31, 24)
+
+#define MT_SKEY_BASE_0 0xac00
+#define MT_SKEY_BASE_1 0xb400
+#define MT_SKEY_0(_bss, _idx) \
+ (MT_SKEY_BASE_0 + (4 * (_bss) + _idx) * 32)
+#define MT_SKEY_1(_bss, _idx) \
+ (MT_SKEY_BASE_1 + (4 * ((_bss) & 7) + _idx) * 32)
+#define MT_SKEY(_bss, _idx) \
+ ((_bss & 8) ? MT_SKEY_1(_bss, _idx) : MT_SKEY_0(_bss, _idx))
+
+#define MT_SKEY_MODE_BASE_0 0xb000
+#define MT_SKEY_MODE_BASE_1 0xb3f0
+#define MT_SKEY_MODE_0(_bss) \
+ (MT_SKEY_MODE_BASE_0 + ((_bss / 2) << 2))
+#define MT_SKEY_MODE_1(_bss) \
+ (MT_SKEY_MODE_BASE_1 + ((((_bss) & 7) / 2) << 2))
+#define MT_SKEY_MODE(_bss) \
+ ((_bss & 8) ? MT_SKEY_MODE_1(_bss) : MT_SKEY_MODE_0(_bss))
+#define MT_SKEY_MODE_MASK GENMASK(3, 0)
+#define MT_SKEY_MODE_SHIFT(_bss, _idx) (4 * ((_idx) + 4 * (_bss & 1)))
+
+#define MT_BEACON_BASE 0xc000
+
+#define MT_TEMP_SENSOR 0x1d000
+#define MT_TEMP_SENSOR_VAL GENMASK(6, 0)
+
+enum mt76_cipher_type {
+ MT_CIPHER_NONE,
+ MT_CIPHER_WEP40,
+ MT_CIPHER_WEP104,
+ MT_CIPHER_TKIP,
+ MT_CIPHER_AES_CCMP,
+ MT_CIPHER_CKIP40,
+ MT_CIPHER_CKIP104,
+ MT_CIPHER_CKIP128,
+ MT_CIPHER_WAPI,
+};
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/trace.c b/drivers/net/wireless/mediatek/mt7601u/trace.c
new file mode 100644
index 000000000000..8abdd3cd546d
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/trace.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include <linux/module.h>
+
+#ifndef __CHECKER__
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/trace.h b/drivers/net/wireless/mediatek/mt7601u/trace.h
new file mode 100644
index 000000000000..289897300ef0
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/trace.h
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#if !defined(__MT7601U_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __MT7601U_TRACE_H
+
+#include <linux/tracepoint.h>
+#include "mt7601u.h"
+#include "mac.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mt7601u
+
+#define MAXNAME 32
+#define DEV_ENTRY __array(char, wiphy_name, 32)
+#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \
+ wiphy_name(dev->hw->wiphy), MAXNAME)
+#define DEV_PR_FMT "%s "
+#define DEV_PR_ARG __entry->wiphy_name
+
+#define REG_ENTRY __field(u32, reg) __field(u32, val)
+#define REG_ASSIGN __entry->reg = reg; __entry->val = val
+#define REG_PR_FMT "%04x=%08x"
+#define REG_PR_ARG __entry->reg, __entry->val
+
+DECLARE_EVENT_CLASS(dev_reg_evt,
+ TP_PROTO(struct mt7601u_dev *dev, u32 reg, u32 val),
+ TP_ARGS(dev, reg, val),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ REG_ENTRY
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ REG_ASSIGN;
+ ),
+ TP_printk(
+ DEV_PR_FMT REG_PR_FMT,
+ DEV_PR_ARG, REG_PR_ARG
+ )
+);
+
+DEFINE_EVENT(dev_reg_evt, reg_read,
+ TP_PROTO(struct mt7601u_dev *dev, u32 reg, u32 val),
+ TP_ARGS(dev, reg, val)
+);
+
+DEFINE_EVENT(dev_reg_evt, reg_write,
+ TP_PROTO(struct mt7601u_dev *dev, u32 reg, u32 val),
+ TP_ARGS(dev, reg, val)
+);
+
+TRACE_EVENT(mt_submit_urb,
+ TP_PROTO(struct mt7601u_dev *dev, struct urb *u),
+ TP_ARGS(dev, u),
+ TP_STRUCT__entry(
+ DEV_ENTRY __field(unsigned, pipe) __field(u32, len)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->pipe = u->pipe;
+ __entry->len = u->transfer_buffer_length;
+ ),
+ TP_printk(DEV_PR_FMT "p:%08x len:%u",
+ DEV_PR_ARG, __entry->pipe, __entry->len)
+);
+
+#define trace_mt_submit_urb_sync(__dev, __pipe, __len) ({ \
+ struct urb u; \
+ u.pipe = __pipe; \
+ u.transfer_buffer_length = __len; \
+ trace_mt_submit_urb(__dev, &u); \
+})
+
+TRACE_EVENT(mt_mcu_msg_send,
+ TP_PROTO(struct mt7601u_dev *dev,
+ struct sk_buff *skb, u32 csum, bool resp),
+ TP_ARGS(dev, skb, csum, resp),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u32, info)
+ __field(u32, csum)
+ __field(bool, resp)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->info = *(u32 *)skb->data;
+ __entry->csum = csum;
+ __entry->resp = resp;
+ ),
+ TP_printk(DEV_PR_FMT "i:%08x c:%08x r:%d",
+ DEV_PR_ARG, __entry->info, __entry->csum, __entry->resp)
+);
+
+TRACE_EVENT(mt_vend_req,
+ TP_PROTO(struct mt7601u_dev *dev, unsigned pipe, u8 req, u8 req_type,
+ u16 val, u16 offset, void *buf, size_t buflen, int ret),
+ TP_ARGS(dev, pipe, req, req_type, val, offset, buf, buflen, ret),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(unsigned, pipe) __field(u8, req) __field(u8, req_type)
+ __field(u16, val) __field(u16, offset) __field(void*, buf)
+ __field(int, buflen) __field(int, ret)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->pipe = pipe;
+ __entry->req = req;
+ __entry->req_type = req_type;
+ __entry->val = val;
+ __entry->offset = offset;
+ __entry->buf = buf;
+ __entry->buflen = buflen;
+ __entry->ret = ret;
+ ),
+ TP_printk(DEV_PR_FMT
+ "%d p:%08x req:%02hhx %02hhx val:%04hx %04hx buf:%d %d",
+ DEV_PR_ARG, __entry->ret, __entry->pipe, __entry->req,
+ __entry->req_type, __entry->val, __entry->offset,
+ !!__entry->buf, __entry->buflen)
+);
+
+TRACE_EVENT(ee_read,
+ TP_PROTO(struct mt7601u_dev *dev, int offset, u16 val),
+ TP_ARGS(dev, offset, val),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(int, o) __field(u16, v)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->o = offset;
+ __entry->v = val;
+ ),
+ TP_printk(DEV_PR_FMT "%04x=%04x", DEV_PR_ARG, __entry->o, __entry->v)
+);
+
+DECLARE_EVENT_CLASS(dev_rf_reg_evt,
+ TP_PROTO(struct mt7601u_dev *dev, u8 bank, u8 reg, u8 val),
+ TP_ARGS(dev, bank, reg, val),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u8, bank)
+ __field(u8, reg)
+ __field(u8, val)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ REG_ASSIGN;
+ __entry->bank = bank;
+ ),
+ TP_printk(
+ DEV_PR_FMT "%02hhx:%02hhx=%02hhx",
+ DEV_PR_ARG, __entry->bank, __entry->reg, __entry->val
+ )
+);
+
+DEFINE_EVENT(dev_rf_reg_evt, rf_read,
+ TP_PROTO(struct mt7601u_dev *dev, u8 bank, u8 reg, u8 val),
+ TP_ARGS(dev, bank, reg, val)
+);
+
+DEFINE_EVENT(dev_rf_reg_evt, rf_write,
+ TP_PROTO(struct mt7601u_dev *dev, u8 bank, u8 reg, u8 val),
+ TP_ARGS(dev, bank, reg, val)
+);
+
+DECLARE_EVENT_CLASS(dev_bbp_reg_evt,
+ TP_PROTO(struct mt7601u_dev *dev, u8 reg, u8 val),
+ TP_ARGS(dev, reg, val),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u8, reg)
+ __field(u8, val)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ REG_ASSIGN;
+ ),
+ TP_printk(
+ DEV_PR_FMT "%02hhx=%02hhx",
+ DEV_PR_ARG, __entry->reg, __entry->val
+ )
+);
+
+DEFINE_EVENT(dev_bbp_reg_evt, bbp_read,
+ TP_PROTO(struct mt7601u_dev *dev, u8 reg, u8 val),
+ TP_ARGS(dev, reg, val)
+);
+
+DEFINE_EVENT(dev_bbp_reg_evt, bbp_write,
+ TP_PROTO(struct mt7601u_dev *dev, u8 reg, u8 val),
+ TP_ARGS(dev, reg, val)
+);
+
+DECLARE_EVENT_CLASS(dev_simple_evt,
+ TP_PROTO(struct mt7601u_dev *dev, u8 val),
+ TP_ARGS(dev, val),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u8, val)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->val = val;
+ ),
+ TP_printk(
+ DEV_PR_FMT "%02hhx", DEV_PR_ARG, __entry->val
+ )
+);
+
+DEFINE_EVENT(dev_simple_evt, temp_mode,
+ TP_PROTO(struct mt7601u_dev *dev, u8 val),
+ TP_ARGS(dev, val)
+);
+
+DEFINE_EVENT(dev_simple_evt, read_temp,
+ TP_PROTO(struct mt7601u_dev *dev, u8 val),
+ TP_ARGS(dev, val)
+);
+
+DEFINE_EVENT(dev_simple_evt, freq_cal_adjust,
+ TP_PROTO(struct mt7601u_dev *dev, u8 val),
+ TP_ARGS(dev, val)
+);
+
+TRACE_EVENT(freq_cal_offset,
+ TP_PROTO(struct mt7601u_dev *dev, u8 phy_mode, s8 freq_off),
+ TP_ARGS(dev, phy_mode, freq_off),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u8, phy_mode)
+ __field(s8, freq_off)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->phy_mode = phy_mode;
+ __entry->freq_off = freq_off;
+ ),
+ TP_printk(DEV_PR_FMT "phy:%02hhx off:%02hhx",
+ DEV_PR_ARG, __entry->phy_mode, __entry->freq_off)
+);
+
+TRACE_EVENT(mt_rx,
+ TP_PROTO(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, u32 f),
+ TP_ARGS(dev, rxwi, f),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field_struct(struct mt7601u_rxwi, rxwi)
+ __field(u32, fce_info)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->rxwi = *rxwi;
+ __entry->fce_info = f;
+ ),
+ TP_printk(DEV_PR_FMT "rxi:%08x ctl:%08x frag_sn:%04hx rate:%04hx "
+ "uknw:%02hhx z:%02hhx%02hhx%02hhx snr:%02hhx "
+ "ant:%02hhx gain:%02hhx freq_o:%02hhx "
+ "r:%08x ea:%08x fce:%08x", DEV_PR_ARG,
+ le32_to_cpu(__entry->rxwi.rxinfo),
+ le32_to_cpu(__entry->rxwi.ctl),
+ le16_to_cpu(__entry->rxwi.frag_sn),
+ le16_to_cpu(__entry->rxwi.rate),
+ __entry->rxwi.unknown,
+ __entry->rxwi.zero[0], __entry->rxwi.zero[1],
+ __entry->rxwi.zero[2],
+ __entry->rxwi.snr, __entry->rxwi.ant,
+ __entry->rxwi.gain, __entry->rxwi.freq_off,
+ __entry->rxwi.resv2, __entry->rxwi.expert_ant,
+ __entry->fce_info)
+);
+
+TRACE_EVENT(mt_tx,
+ TP_PROTO(struct mt7601u_dev *dev, struct sk_buff *skb,
+ struct mt76_sta *sta, struct mt76_txwi *h),
+ TP_ARGS(dev, skb, sta, h),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field_struct(struct mt76_txwi, h)
+ __field(struct sk_buff *, skb)
+ __field(struct mt76_sta *, sta)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->h = *h;
+ __entry->skb = skb;
+ __entry->sta = sta;
+ ),
+ TP_printk(DEV_PR_FMT "skb:%p sta:%p flg:%04hx rate_ctl:%04hx "
+ "ack:%02hhx wcid:%02hhx len_ctl:%05hx", DEV_PR_ARG,
+ __entry->skb, __entry->sta,
+ le16_to_cpu(__entry->h.flags),
+ le16_to_cpu(__entry->h.rate_ctl),
+ __entry->h.ack_ctl, __entry->h.wcid,
+ le16_to_cpu(__entry->h.len_ctl))
+);
+
+TRACE_EVENT(mt_tx_dma_done,
+ TP_PROTO(struct mt7601u_dev *dev, struct sk_buff *skb),
+ TP_ARGS(dev, skb),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(struct sk_buff *, skb)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->skb = skb;
+ ),
+ TP_printk(DEV_PR_FMT "%p", DEV_PR_ARG, __entry->skb)
+);
+
+TRACE_EVENT(mt_tx_status_cleaned,
+ TP_PROTO(struct mt7601u_dev *dev, int cleaned),
+ TP_ARGS(dev, cleaned),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(int, cleaned)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->cleaned = cleaned;
+ ),
+ TP_printk(DEV_PR_FMT "%d", DEV_PR_ARG, __entry->cleaned)
+);
+
+TRACE_EVENT(mt_tx_status,
+ TP_PROTO(struct mt7601u_dev *dev, u32 stat1, u32 stat2),
+ TP_ARGS(dev, stat1, stat2),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u32, stat1) __field(u32, stat2)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->stat1 = stat1;
+ __entry->stat2 = stat2;
+ ),
+ TP_printk(DEV_PR_FMT "%08x %08x",
+ DEV_PR_ARG, __entry->stat1, __entry->stat2)
+);
+
+TRACE_EVENT(mt_rx_dma_aggr,
+ TP_PROTO(struct mt7601u_dev *dev, int cnt, bool paged),
+ TP_ARGS(dev, cnt, paged),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u8, cnt)
+ __field(bool, paged)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->cnt = cnt;
+ __entry->paged = paged;
+ ),
+ TP_printk(DEV_PR_FMT "cnt:%d paged:%d",
+ DEV_PR_ARG, __entry->cnt, __entry->paged)
+);
+
+DEFINE_EVENT(dev_simple_evt, set_key,
+ TP_PROTO(struct mt7601u_dev *dev, u8 val),
+ TP_ARGS(dev, val)
+);
+
+TRACE_EVENT(set_shared_key,
+ TP_PROTO(struct mt7601u_dev *dev, u8 vid, u8 key),
+ TP_ARGS(dev, vid, key),
+ TP_STRUCT__entry(
+ DEV_ENTRY
+ __field(u8, vid)
+ __field(u8, key)
+ ),
+ TP_fast_assign(
+ DEV_ASSIGN;
+ __entry->vid = vid;
+ __entry->key = key;
+ ),
+ TP_printk(DEV_PR_FMT "phy:%02hhx off:%02hhx",
+ DEV_PR_ARG, __entry->vid, __entry->key)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c
new file mode 100644
index 000000000000..0be2080ceab3
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/tx.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include "mt7601u.h"
+#include "trace.h"
+
+enum mt76_txq_id {
+ MT_TXQ_VO = IEEE80211_AC_VO,
+ MT_TXQ_VI = IEEE80211_AC_VI,
+ MT_TXQ_BE = IEEE80211_AC_BE,
+ MT_TXQ_BK = IEEE80211_AC_BK,
+ MT_TXQ_PSD,
+ MT_TXQ_MCU,
+ __MT_TXQ_MAX
+};
+
+/* Hardware uses mirrored order of queues with Q0 having the highest priority */
+static u8 q2hwq(u8 q)
+{
+ return q ^ 0x3;
+}
+
+/* Take mac80211 Q id from the skb and translate it to hardware Q id */
+static u8 skb2q(struct sk_buff *skb)
+{
+ int qid = skb_get_queue_mapping(skb);
+
+ if (WARN_ON(qid >= MT_TXQ_PSD)) {
+ qid = MT_TXQ_BE;
+ skb_set_queue_mapping(skb, qid);
+ }
+
+ return q2hwq(qid);
+}
+
+/* Note: TX retry reporting is a bit broken.
+ * Retries are reported only once per AMPDU and often come a frame early
+ * i.e. they are reported in the last status preceding the AMPDU. Apart
+ * from the fact that it's hard to know the length of the AMPDU (which is
+ * required to know to how many consecutive frames retries should be
+ * applied), if status comes early on full FIFO it gets lost and retries
+ * of the whole AMPDU become invisible.
+ * As a work-around encode the desired rate in PKT_ID of TX descriptor
+ * and based on that guess the retries (every rate is tried once).
+ * Only downside here is that for MCS0 we have to rely solely on
+ * transmission failures as no retries can ever be reported.
+ * Not having to read EXT_FIFO has a nice effect of doubling the number
+ * of reports which can be fetched.
+ * Also the vendor driver never uses the EXT_FIFO register so it may be
+ * undertested.
+ */
+static u8 mt7601u_tx_pktid_enc(struct mt7601u_dev *dev, u8 rate, bool is_probe)
+{
+ u8 encoded = (rate + 1) + is_probe * 8;
+
+ /* Because PKT_ID 0 disables status reporting only 15 values are
+ * available but 16 are needed (8 MCS * 2 for encoding is_probe)
+ * - we need to cram together two rates. MCS0 and MCS7 with is_probe
+ * share PKT_ID 9.
+ */
+ if (is_probe && rate == 7)
+ return encoded - 7;
+
+ return encoded;
+}
+
+static void
+mt7601u_tx_pktid_dec(struct mt7601u_dev *dev, struct mt76_tx_status *stat)
+{
+ u8 req_rate = stat->pktid;
+ u8 eff_rate = stat->rate & 0x7;
+
+ req_rate -= 1;
+
+ if (req_rate > 7) {
+ stat->is_probe = true;
+ req_rate -= 8;
+
+ /* Decide between MCS0 and MCS7 which share pktid 9 */
+ if (!req_rate && eff_rate)
+ req_rate = 7;
+ }
+
+ stat->retry = req_rate - eff_rate;
+}
+
+static void mt7601u_tx_skb_remove_dma_overhead(struct sk_buff *skb,
+ struct ieee80211_tx_info *info)
+{
+ int pkt_len = (unsigned long)info->status.status_driver_data[0];
+
+ skb_pull(skb, sizeof(struct mt76_txwi) + 4);
+ if (ieee80211_get_hdrlen_from_skb(skb) % 4)
+ mt76_remove_hdr_pad(skb);
+
+ skb_trim(skb, pkt_len);
+}
+
+void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ mt7601u_tx_skb_remove_dma_overhead(skb, info);
+
+ ieee80211_tx_info_clear_status(info);
+ info->status.rates[0].idx = -1;
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ ieee80211_tx_status(dev->hw, skb);
+}
+
+static int mt7601u_skb_rooms(struct mt7601u_dev *dev, struct sk_buff *skb)
+{
+ int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
+ u32 need_head;
+
+ need_head = sizeof(struct mt76_txwi) + 4;
+ if (hdr_len % 4)
+ need_head += 2;
+
+ return skb_cow(skb, need_head);
+}
+
+static struct mt76_txwi *
+mt7601u_push_txwi(struct mt7601u_dev *dev, struct sk_buff *skb,
+ struct ieee80211_sta *sta, struct mt76_wcid *wcid,
+ int pkt_len)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_rate *rate = &info->control.rates[0];
+ struct mt76_txwi *txwi;
+ unsigned long flags;
+ bool is_probe;
+ u32 pkt_id;
+ u16 rate_ctl;
+ u8 nss;
+
+ txwi = (struct mt76_txwi *)skb_push(skb, sizeof(struct mt76_txwi));
+ memset(txwi, 0, sizeof(*txwi));
+
+ if (!wcid->tx_rate_set)
+ ieee80211_get_tx_rates(info->control.vif, sta, skb,
+ info->control.rates, 1);
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (rate->idx < 0 || !rate->count)
+ rate_ctl = wcid->tx_rate;
+ else
+ rate_ctl = mt76_mac_tx_rate_val(dev, rate, &nss);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ txwi->rate_ctl = cpu_to_le16(rate_ctl);
+
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+ txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ;
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+ txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ;
+
+ if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) {
+ u8 ba_size = IEEE80211_MIN_AMPDU_BUF;
+
+ ba_size <<= sta->ht_cap.ampdu_factor;
+ ba_size = min_t(int, 63, ba_size);
+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
+ ba_size = 0;
+ txwi->ack_ctl |= MT76_SET(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size);
+
+ txwi->flags = cpu_to_le16(MT_TXWI_FLAGS_AMPDU |
+ MT76_SET(MT_TXWI_FLAGS_MPDU_DENSITY,
+ sta->ht_cap.ampdu_density));
+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
+ txwi->flags = 0;
+ }
+
+ txwi->wcid = wcid->idx;
+
+ is_probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
+ pkt_id = mt7601u_tx_pktid_enc(dev, rate_ctl & 0x7, is_probe);
+ pkt_len |= MT76_SET(MT_TXWI_LEN_PKTID, pkt_id);
+ txwi->len_ctl = cpu_to_le16(pkt_len);
+
+ return txwi;
+}
+
+void mt7601u_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct mt7601u_dev *dev = hw->priv;
+ struct ieee80211_vif *vif = info->control.vif;
+ struct ieee80211_sta *sta = control->sta;
+ struct mt76_sta *msta = NULL;
+ struct mt76_wcid *wcid = dev->mon_wcid;
+ struct mt76_txwi *txwi;
+ int pkt_len = skb->len;
+ int hw_q = skb2q(skb);
+
+ BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1);
+ info->status.status_driver_data[0] = (void *)(unsigned long)pkt_len;
+
+ if (mt7601u_skb_rooms(dev, skb) || mt76_insert_hdr_pad(skb)) {
+ ieee80211_free_txskb(dev->hw, skb);
+ return;
+ }
+
+ if (sta) {
+ msta = (struct mt76_sta *) sta->drv_priv;
+ wcid = &msta->wcid;
+ } else if (vif) {
+ struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
+
+ wcid = &mvif->group_wcid;
+ }
+
+ txwi = mt7601u_push_txwi(dev, skb, sta, wcid, pkt_len);
+
+ if (mt7601u_dma_enqueue_tx(dev, skb, wcid, hw_q))
+ return;
+
+ trace_mt_tx(dev, skb, msta, txwi);
+}
+
+void mt7601u_tx_stat(struct work_struct *work)
+{
+ struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev,
+ stat_work.work);
+ struct mt76_tx_status stat;
+ unsigned long flags;
+ int cleaned = 0;
+
+ while (!test_bit(MT7601U_STATE_REMOVED, &dev->state)) {
+ stat = mt7601u_mac_fetch_tx_status(dev);
+ if (!stat.valid)
+ break;
+
+ mt7601u_tx_pktid_dec(dev, &stat);
+ mt76_send_tx_status(dev, &stat);
+
+ cleaned++;
+ }
+ trace_mt_tx_status_cleaned(dev, cleaned);
+
+ spin_lock_irqsave(&dev->tx_lock, flags);
+ if (cleaned)
+ queue_delayed_work(dev->stat_wq, &dev->stat_work,
+ msecs_to_jiffies(10));
+ else if (test_and_clear_bit(MT7601U_STATE_MORE_STATS, &dev->state))
+ queue_delayed_work(dev->stat_wq, &dev->stat_work,
+ msecs_to_jiffies(20));
+ else
+ clear_bit(MT7601U_STATE_READING_STATS, &dev->state);
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
+}
+
+int mt7601u_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u16 queue, const struct ieee80211_tx_queue_params *params)
+{
+ struct mt7601u_dev *dev = hw->priv;
+ u8 cw_min = 5, cw_max = 10, hw_q = q2hwq(queue);
+ u32 val;
+
+ /* TODO: should we do funny things with the parameters?
+ * See what mt7601u_set_default_edca() used to do in init.c.
+ */
+
+ if (params->cw_min)
+ cw_min = fls(params->cw_min);
+ if (params->cw_max)
+ cw_max = fls(params->cw_max);
+
+ WARN_ON(params->txop > 0xff);
+ WARN_ON(params->aifs > 0xf);
+ WARN_ON(cw_min > 0xf);
+ WARN_ON(cw_max > 0xf);
+
+ val = MT76_SET(MT_EDCA_CFG_AIFSN, params->aifs) |
+ MT76_SET(MT_EDCA_CFG_CWMIN, cw_min) |
+ MT76_SET(MT_EDCA_CFG_CWMAX, cw_max);
+ /* TODO: based on user-controlled EnableTxBurst var vendor drv sets
+ * a really long txop on AC0 (see connect.c:2009) but only on
+ * connect? When not connected should be 0.
+ */
+ if (!hw_q)
+ val |= 0x60;
+ else
+ val |= MT76_SET(MT_EDCA_CFG_TXOP, params->txop);
+ mt76_wr(dev, MT_EDCA_CFG_AC(hw_q), val);
+
+ val = mt76_rr(dev, MT_WMM_TXOP(hw_q));
+ val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(hw_q));
+ val |= params->txop << MT_WMM_TXOP_SHIFT(hw_q);
+ mt76_wr(dev, MT_WMM_TXOP(hw_q), val);
+
+ val = mt76_rr(dev, MT_WMM_AIFSN);
+ val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(hw_q));
+ val |= params->aifs << MT_WMM_AIFSN_SHIFT(hw_q);
+ mt76_wr(dev, MT_WMM_AIFSN, val);
+
+ val = mt76_rr(dev, MT_WMM_CWMIN);
+ val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(hw_q));
+ val |= cw_min << MT_WMM_CWMIN_SHIFT(hw_q);
+ mt76_wr(dev, MT_WMM_CWMIN, val);
+
+ val = mt76_rr(dev, MT_WMM_CWMAX);
+ val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(hw_q));
+ val |= cw_max << MT_WMM_CWMAX_SHIFT(hw_q);
+ mt76_wr(dev, MT_WMM_CWMAX, val);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c
new file mode 100644
index 000000000000..54dba4001865
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/usb.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "mt7601u.h"
+#include "usb.h"
+#include "trace.h"
+
+static struct usb_device_id mt7601u_device_table[] = {
+ { USB_DEVICE(0x0b05, 0x17d3) },
+ { USB_DEVICE(0x0e8d, 0x760a) },
+ { USB_DEVICE(0x0e8d, 0x760b) },
+ { USB_DEVICE(0x13d3, 0x3431) },
+ { USB_DEVICE(0x13d3, 0x3434) },
+ { USB_DEVICE(0x148f, 0x7601) },
+ { USB_DEVICE(0x148f, 0x760a) },
+ { USB_DEVICE(0x148f, 0x760b) },
+ { USB_DEVICE(0x148f, 0x760c) },
+ { USB_DEVICE(0x148f, 0x760d) },
+ { USB_DEVICE(0x2001, 0x3d04) },
+ { USB_DEVICE(0x2717, 0x4106) },
+ { USB_DEVICE(0x2955, 0x0001) },
+ { USB_DEVICE(0x2955, 0x1001) },
+ { USB_DEVICE(0x2a5f, 0x1000) },
+ { USB_DEVICE(0x7392, 0x7710) },
+ { 0, }
+};
+
+bool mt7601u_usb_alloc_buf(struct mt7601u_dev *dev, size_t len,
+ struct mt7601u_dma_buf *buf)
+{
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+
+ buf->len = len;
+ buf->urb = usb_alloc_urb(0, GFP_KERNEL);
+ buf->buf = usb_alloc_coherent(usb_dev, buf->len, GFP_KERNEL, &buf->dma);
+
+ return !buf->urb || !buf->buf;
+}
+
+void mt7601u_usb_free_buf(struct mt7601u_dev *dev, struct mt7601u_dma_buf *buf)
+{
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+
+ usb_free_coherent(usb_dev, buf->len, buf->buf, buf->dma);
+ usb_free_urb(buf->urb);
+}
+
+int mt7601u_usb_submit_buf(struct mt7601u_dev *dev, int dir, int ep_idx,
+ struct mt7601u_dma_buf *buf, gfp_t gfp,
+ usb_complete_t complete_fn, void *context)
+{
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+ unsigned pipe;
+ int ret;
+
+ if (dir == USB_DIR_IN)
+ pipe = usb_rcvbulkpipe(usb_dev, dev->in_eps[ep_idx]);
+ else
+ pipe = usb_sndbulkpipe(usb_dev, dev->out_eps[ep_idx]);
+
+ usb_fill_bulk_urb(buf->urb, usb_dev, pipe, buf->buf, buf->len,
+ complete_fn, context);
+ buf->urb->transfer_dma = buf->dma;
+ buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ trace_mt_submit_urb(dev, buf->urb);
+ ret = usb_submit_urb(buf->urb, gfp);
+ if (ret)
+ dev_err(dev->dev, "Error: submit URB dir:%d ep:%d failed:%d\n",
+ dir, ep_idx, ret);
+ return ret;
+}
+
+void mt7601u_complete_urb(struct urb *urb)
+{
+ struct completion *cmpl = urb->context;
+
+ complete(cmpl);
+}
+
+static int
+__mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,
+ const u8 direction, const u16 val, const u16 offset,
+ void *buf, const size_t buflen)
+{
+ int i, ret;
+ struct usb_device *usb_dev = mt7601u_to_usb_dev(dev);
+ const u8 req_type = direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ const unsigned int pipe = (direction == USB_DIR_IN) ?
+ usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0);
+
+ for (i = 0; i < MT_VEND_REQ_MAX_RETRY; i++) {
+ ret = usb_control_msg(usb_dev, pipe, req, req_type,
+ val, offset, buf, buflen,
+ MT_VEND_REQ_TOUT_MS);
+ trace_mt_vend_req(dev, pipe, req, req_type, val, offset,
+ buf, buflen, ret);
+
+ if (ret >= 0 || ret == -ENODEV)
+ return ret;
+
+ msleep(5);
+ }
+
+ dev_err(dev->dev, "Vendor request req:%02x off:%04x failed:%d\n",
+ req, offset, ret);
+
+ return ret;
+}
+
+int
+mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,
+ const u8 direction, const u16 val, const u16 offset,
+ void *buf, const size_t buflen)
+{
+ int ret;
+
+ mutex_lock(&dev->vendor_req_mutex);
+
+ ret = __mt7601u_vendor_request(dev, req, direction, val, offset,
+ buf, buflen);
+ if (ret == -ENODEV)
+ set_bit(MT7601U_STATE_REMOVED, &dev->state);
+
+ mutex_unlock(&dev->vendor_req_mutex);
+
+ return ret;
+}
+
+void mt7601u_vendor_reset(struct mt7601u_dev *dev)
+{
+ mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT,
+ MT_VEND_DEV_MODE_RESET, 0, NULL, 0);
+}
+
+u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset)
+{
+ int ret;
+ __le32 reg;
+ u32 val;
+
+ WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset);
+
+ ret = mt7601u_vendor_request(dev, MT_VEND_MULTI_READ, USB_DIR_IN,
+ 0, offset, &reg, sizeof(reg));
+ val = le32_to_cpu(reg);
+ if (ret > 0 && ret != sizeof(reg)) {
+ dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n",
+ ret, offset);
+ val = ~0;
+ }
+
+ trace_reg_read(dev, offset, val);
+ return val;
+}
+
+int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req,
+ const u16 offset, const u32 val)
+{
+ int ret;
+
+ ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT,
+ val & 0xffff, offset, NULL, 0);
+ if (ret)
+ return ret;
+ return mt7601u_vendor_request(dev, req, USB_DIR_OUT,
+ val >> 16, offset + 2, NULL, 0);
+}
+
+void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val)
+{
+ WARN_ONCE(offset > USHRT_MAX, "write high off:%08x", offset);
+
+ mt7601u_vendor_single_wr(dev, MT_VEND_WRITE, offset, val);
+ trace_reg_write(dev, offset, val);
+}
+
+u32 mt7601u_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val)
+{
+ val |= mt7601u_rr(dev, offset) & ~mask;
+ mt7601u_wr(dev, offset, val);
+ return val;
+}
+
+u32 mt7601u_rmc(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val)
+{
+ u32 reg = mt7601u_rr(dev, offset);
+
+ val |= reg & ~mask;
+ if (reg != val)
+ mt7601u_wr(dev, offset, val);
+ return val;
+}
+
+void mt7601u_wr_copy(struct mt7601u_dev *dev, u32 offset,
+ const void *data, int len)
+{
+ WARN_ONCE(offset & 3, "unaligned write copy off:%08x", offset);
+ WARN_ONCE(len & 3, "short write copy off:%08x", offset);
+
+ mt7601u_burst_write_regs(dev, offset, data, len / 4);
+}
+
+void mt7601u_addr_wr(struct mt7601u_dev *dev, const u32 offset, const u8 *addr)
+{
+ mt7601u_wr(dev, offset, get_unaligned_le32(addr));
+ mt7601u_wr(dev, offset + 4, addr[4] | addr[5] << 8);
+}
+
+static int mt7601u_assign_pipes(struct usb_interface *usb_intf,
+ struct mt7601u_dev *dev)
+{
+ struct usb_endpoint_descriptor *ep_desc;
+ struct usb_host_interface *intf_desc = usb_intf->cur_altsetting;
+ unsigned i, ep_i = 0, ep_o = 0;
+
+ BUILD_BUG_ON(sizeof(dev->in_eps) < __MT_EP_IN_MAX);
+ BUILD_BUG_ON(sizeof(dev->out_eps) < __MT_EP_OUT_MAX);
+
+ for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
+ ep_desc = &intf_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_bulk_in(ep_desc) &&
+ ep_i++ < __MT_EP_IN_MAX) {
+ dev->in_eps[ep_i - 1] = usb_endpoint_num(ep_desc);
+ dev->in_max_packet = usb_endpoint_maxp(ep_desc);
+ /* Note: this is ignored by usb sub-system but vendor
+ * code does it. We can drop this at some point.
+ */
+ dev->in_eps[ep_i - 1] |= USB_DIR_IN;
+ } else if (usb_endpoint_is_bulk_out(ep_desc) &&
+ ep_o++ < __MT_EP_OUT_MAX) {
+ dev->out_eps[ep_o - 1] = usb_endpoint_num(ep_desc);
+ dev->out_max_packet = usb_endpoint_maxp(ep_desc);
+ }
+ }
+
+ if (ep_i != __MT_EP_IN_MAX || ep_o != __MT_EP_OUT_MAX) {
+ dev_err(dev->dev, "Error: wrong pipe number in:%d out:%d\n",
+ ep_i, ep_o);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mt7601u_probe(struct usb_interface *usb_intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usb_dev = interface_to_usbdev(usb_intf);
+ struct mt7601u_dev *dev;
+ u32 asic_rev, mac_rev;
+ int ret;
+
+ dev = mt7601u_alloc_device(&usb_intf->dev);
+ if (!dev)
+ return -ENOMEM;
+
+ usb_dev = usb_get_dev(usb_dev);
+ usb_reset_device(usb_dev);
+
+ usb_set_intfdata(usb_intf, dev);
+
+ ret = mt7601u_assign_pipes(usb_intf, dev);
+ if (ret)
+ goto err;
+ ret = mt7601u_wait_asic_ready(dev);
+ if (ret)
+ goto err;
+
+ asic_rev = mt7601u_rr(dev, MT_ASIC_VERSION);
+ mac_rev = mt7601u_rr(dev, MT_MAC_CSR0);
+ dev_info(dev->dev, "ASIC revision: %08x MAC revision: %08x\n",
+ asic_rev, mac_rev);
+
+ /* Note: vendor driver skips this check for MT7601U */
+ if (!(mt7601u_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL))
+ dev_warn(dev->dev, "Warning: eFUSE not present\n");
+
+ ret = mt7601u_init_hardware(dev);
+ if (ret)
+ goto err;
+ ret = mt7601u_register_device(dev);
+ if (ret)
+ goto err_hw;
+
+ set_bit(MT7601U_STATE_INITIALIZED, &dev->state);
+
+ return 0;
+err_hw:
+ mt7601u_cleanup(dev);
+err:
+ usb_set_intfdata(usb_intf, NULL);
+ usb_put_dev(interface_to_usbdev(usb_intf));
+
+ destroy_workqueue(dev->stat_wq);
+ ieee80211_free_hw(dev->hw);
+ return ret;
+}
+
+static void mt7601u_disconnect(struct usb_interface *usb_intf)
+{
+ struct mt7601u_dev *dev = usb_get_intfdata(usb_intf);
+
+ ieee80211_unregister_hw(dev->hw);
+ mt7601u_cleanup(dev);
+
+ usb_set_intfdata(usb_intf, NULL);
+ usb_put_dev(interface_to_usbdev(usb_intf));
+
+ destroy_workqueue(dev->stat_wq);
+ ieee80211_free_hw(dev->hw);
+}
+
+static int mt7601u_suspend(struct usb_interface *usb_intf, pm_message_t state)
+{
+ struct mt7601u_dev *dev = usb_get_intfdata(usb_intf);
+
+ mt7601u_cleanup(dev);
+
+ return 0;
+}
+
+static int mt7601u_resume(struct usb_interface *usb_intf)
+{
+ struct mt7601u_dev *dev = usb_get_intfdata(usb_intf);
+ int ret;
+
+ ret = mt7601u_init_hardware(dev);
+ if (ret)
+ return ret;
+
+ set_bit(MT7601U_STATE_INITIALIZED, &dev->state);
+
+ return 0;
+}
+
+MODULE_DEVICE_TABLE(usb, mt7601u_device_table);
+MODULE_FIRMWARE(MT7601U_FIRMWARE);
+MODULE_LICENSE("GPL");
+
+static struct usb_driver mt7601u_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = mt7601u_device_table,
+ .probe = mt7601u_probe,
+ .disconnect = mt7601u_disconnect,
+ .suspend = mt7601u_suspend,
+ .resume = mt7601u_resume,
+ .reset_resume = mt7601u_resume,
+ .soft_unbind = 1,
+ .disable_hub_initiated_lpm = 1,
+};
+module_usb_driver(mt7601u_driver);
diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.h b/drivers/net/wireless/mediatek/mt7601u/usb.h
new file mode 100644
index 000000000000..49e188fa3798
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/usb.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#ifndef __MT7601U_USB_H
+#define __MT7601U_USB_H
+
+#include "mt7601u.h"
+
+#define MT7601U_FIRMWARE "mt7601u.bin"
+
+#define MT_VEND_REQ_MAX_RETRY 10
+#define MT_VEND_REQ_TOUT_MS 300
+
+#define MT_VEND_DEV_MODE_RESET 1
+
+enum mt_vendor_req {
+ MT_VEND_DEV_MODE = 1,
+ MT_VEND_WRITE = 2,
+ MT_VEND_MULTI_READ = 7,
+ MT_VEND_WRITE_FCE = 0x42,
+};
+
+enum mt_usb_ep_in {
+ MT_EP_IN_PKT_RX,
+ MT_EP_IN_CMD_RESP,
+ __MT_EP_IN_MAX,
+};
+
+enum mt_usb_ep_out {
+ MT_EP_OUT_INBAND_CMD,
+ MT_EP_OUT_AC_BK,
+ MT_EP_OUT_AC_BE,
+ MT_EP_OUT_AC_VI,
+ MT_EP_OUT_AC_VO,
+ MT_EP_OUT_HCCA,
+ __MT_EP_OUT_MAX,
+};
+
+static inline struct usb_device *mt7601u_to_usb_dev(struct mt7601u_dev *mt7601u)
+{
+ return interface_to_usbdev(to_usb_interface(mt7601u->dev));
+}
+
+static inline bool mt7601u_urb_has_error(struct urb *urb)
+{
+ return urb->status &&
+ urb->status != -ENOENT &&
+ urb->status != -ECONNRESET &&
+ urb->status != -ESHUTDOWN;
+}
+
+bool mt7601u_usb_alloc_buf(struct mt7601u_dev *dev, size_t len,
+ struct mt7601u_dma_buf *buf);
+void mt7601u_usb_free_buf(struct mt7601u_dev *dev, struct mt7601u_dma_buf *buf);
+int mt7601u_usb_submit_buf(struct mt7601u_dev *dev, int dir, int ep_idx,
+ struct mt7601u_dma_buf *buf, gfp_t gfp,
+ usb_complete_t complete_fn, void *context);
+void mt7601u_complete_urb(struct urb *urb);
+
+int mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req,
+ const u8 direction, const u16 val, const u16 offset,
+ void *buf, const size_t buflen);
+void mt7601u_vendor_reset(struct mt7601u_dev *dev);
+int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req,
+ const u16 offset, const u32 val);
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/util.c b/drivers/net/wireless/mediatek/mt7601u/util.c
new file mode 100644
index 000000000000..7c1787c1ddcd
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/util.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include "mt7601u.h"
+
+void mt76_remove_hdr_pad(struct sk_buff *skb)
+{
+ int len = ieee80211_get_hdrlen_from_skb(skb);
+
+ memmove(skb->data + 2, skb->data, len);
+ skb_pull(skb, 2);
+}
+
+int mt76_insert_hdr_pad(struct sk_buff *skb)
+{
+ int len = ieee80211_get_hdrlen_from_skb(skb);
+ int ret;
+
+ if (len % 4 == 0)
+ return 0;
+
+ ret = skb_cow(skb, 2);
+ if (ret)
+ return ret;
+
+ skb_push(skb, 2);
+ memmove(skb->data, skb->data + 2, len);
+
+ skb->data[len] = 0;
+ skb->data[len + 1] = 0;
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt7601u/util.h b/drivers/net/wireless/mediatek/mt7601u/util.h
new file mode 100644
index 000000000000..b89140bf1210
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt7601u/util.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#ifndef __MT76_UTIL_H
+#define __MT76_UTIL_H
+
+/*
+ * Power of two check, this will check
+ * if the mask that has been given contains and contiguous set of bits.
+ * Note that we cannot use the is_power_of_2() function since this
+ * check must be done at compile-time.
+ */
+#define is_power_of_two(x) ( !((x) & ((x)-1)) )
+#define low_bit_mask(x) ( ((x)-1) & ~(x) )
+#define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x))
+
+/*
+ * Macros to find first set bit in a variable.
+ * These macros behave the same as the __ffs() functions but
+ * the most important difference that this is done during
+ * compile-time rather then run-time.
+ */
+#define compile_ffs2(__x) \
+ __builtin_choose_expr(((__x) & 0x1), 0, 1)
+
+#define compile_ffs4(__x) \
+ __builtin_choose_expr(((__x) & 0x3), \
+ (compile_ffs2((__x))), \
+ (compile_ffs2((__x) >> 2) + 2))
+
+#define compile_ffs8(__x) \
+ __builtin_choose_expr(((__x) & 0xf), \
+ (compile_ffs4((__x))), \
+ (compile_ffs4((__x) >> 4) + 4))
+
+#define compile_ffs16(__x) \
+ __builtin_choose_expr(((__x) & 0xff), \
+ (compile_ffs8((__x))), \
+ (compile_ffs8((__x) >> 8) + 8))
+
+#define compile_ffs32(__x) \
+ __builtin_choose_expr(((__x) & 0xffff), \
+ (compile_ffs16((__x))), \
+ (compile_ffs16((__x) >> 16) + 16))
+
+/*
+ * This macro will check the requirements for the FIELD{8,16,32} macros
+ * The mask should be a constant non-zero contiguous set of bits which
+ * does not exceed the given typelimit.
+ */
+#define FIELD_CHECK(__mask) \
+ BUILD_BUG_ON(!(__mask) || !is_valid_mask(__mask))
+
+#define MT76_SET(_mask, _val) \
+ ({ \
+ FIELD_CHECK(_mask); \
+ (((u32) (_val)) << compile_ffs32(_mask)) & _mask; \
+ })
+
+#define MT76_GET(_mask, _val) \
+ ({ \
+ FIELD_CHECK(_mask); \
+ (u32) (((_val) & _mask) >> compile_ffs32(_mask)); \
+ })
+
+#endif
diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c
index 3ab87a855122..71a1b580796f 100644
--- a/drivers/net/wireless/mwifiex/11h.c
+++ b/drivers/net/wireless/mwifiex/11h.c
@@ -134,8 +134,8 @@ void mwifiex_dfs_cac_work_queue(struct work_struct *work)
chandef = priv->dfs_chandef;
if (priv->wdev.cac_started) {
- dev_dbg(priv->adapter->dev,
- "CAC timer finished; No radar detected\n");
+ mwifiex_dbg(priv->adapter, MSG,
+ "CAC timer finished; No radar detected\n");
cfg80211_cac_event(priv->netdev, &chandef,
NL80211_RADAR_CAC_FINISHED,
GFP_KERNEL);
@@ -161,21 +161,40 @@ int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv,
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);
+ if (radar_params->cac_time_ms)
+ mwifiex_dbg(priv->adapter, MSG,
+ "11h: issuing DFS Radar check for channel=%d\n",
+ radar_params->chandef->chan->hw_value);
+ else
+ mwifiex_dbg(priv->adapter, MSG, "cancelling CAC\n");
return 0;
}
+int mwifiex_stop_radar_detection(struct mwifiex_private *priv,
+ struct cfg80211_chan_def *chandef)
+{
+ struct mwifiex_radar_params radar_params;
+
+ memset(&radar_params, 0, sizeof(struct mwifiex_radar_params));
+ radar_params.chandef = chandef;
+ radar_params.cac_time_ms = 0;
+
+ return mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST,
+ HostCmd_ACT_GEN_SET, 0, &radar_params, true);
+}
+
/* 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");
+ if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef))
+ mwifiex_dbg(priv->adapter, ERROR,
+ "failed to stop CAC in FW\n");
+ mwifiex_dbg(priv->adapter, MSG,
+ "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);
@@ -199,7 +218,8 @@ int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv,
sizeof(u32));
if (le32_to_cpu(rpt_event->result) != HostCmd_RESULT_OK) {
- dev_err(priv->adapter->dev, "Error in channel report event\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Error in channel report event\n");
return -1;
}
@@ -212,8 +232,8 @@ int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv,
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",
+ mwifiex_dbg(priv->adapter, MSG,
+ "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,
@@ -242,16 +262,20 @@ int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
rdr_event = (void *)(skb->data + sizeof(u32));
if (le32_to_cpu(rdr_event->passed)) {
- dev_notice(priv->adapter->dev,
- "radar detected; indicating kernel\n");
+ mwifiex_dbg(priv->adapter, MSG,
+ "radar detected; indicating kernel\n");
+ if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef))
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to stop CAC in FW\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);
+ mwifiex_dbg(priv->adapter, MSG, "regdomain: %d\n",
+ rdr_event->reg_domain);
+ mwifiex_dbg(priv->adapter, MSG, "radar detection type: %d\n",
+ rdr_event->det_type);
} else {
- dev_dbg(priv->adapter->dev, "false radar detection event!\n");
+ mwifiex_dbg(priv->adapter, MSG,
+ "false radar detection event!\n");
}
return 0;
@@ -276,20 +300,20 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work)
bss_cfg = &priv->bss_cfg;
if (!bss_cfg->beacon_period) {
- dev_err(priv->adapter->dev,
- "channel switch: AP already stopped\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "channel switch: AP already stopped\n");
return;
}
- mwifiex_uap_set_channel(bss_cfg, priv->dfs_chandef);
+ mwifiex_uap_set_channel(priv, 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");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to start AP after channel switch\n");
return;
}
- dev_notice(priv->adapter->dev,
- "indicating channel switch completion to kernel\n");
+ mwifiex_dbg(priv->adapter, MSG,
+ "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 433bd6837c79..c174e79e6df2 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -42,7 +42,7 @@ int mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type,
priv->wdev.wiphy->bands[radio_type];
if (WARN_ON_ONCE(!sband)) {
- dev_err(priv->adapter->dev, "Invalid radio type!\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Invalid radio type!\n");
return -EINVAL;
}
@@ -156,7 +156,7 @@ int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp)
{
- int tid;
+ int tid, tid_down;
struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp;
struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
struct mwifiex_ra_list_tbl *ra_list;
@@ -167,7 +167,9 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
>> BLOCKACKPARAM_TID_POS;
- ra_list = mwifiex_wmm_get_ralist_node(priv, tid, add_ba_rsp->
+
+ tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
+ ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, add_ba_rsp->
peer_mac_addr);
if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) {
if (ra_list) {
@@ -184,7 +186,7 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
tx_ba_tbl = mwifiex_get_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr);
if (tx_ba_tbl) {
- dev_dbg(priv->adapter->dev, "info: BA stream complete\n");
+ mwifiex_dbg(priv->adapter, EVENT, "info: BA stream complete\n");
tx_ba_tbl->ba_status = BA_SETUP_COMPLETE;
if ((block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
priv->add_ba_param.tx_amsdu &&
@@ -197,7 +199,7 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
ra_list->ba_status = BA_SETUP_COMPLETE;
}
} else {
- dev_err(priv->adapter->dev, "BA stream not created\n");
+ mwifiex_dbg(priv->adapter, ERROR, "BA stream not created\n");
}
return 0;
@@ -224,7 +226,8 @@ int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
tx_buf->action = cpu_to_le16(action);
switch (action) {
case HostCmd_ACT_GEN_SET:
- dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", *buf_size);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: set tx_buf=%d\n", *buf_size);
tx_buf->buff_size = cpu_to_le16(*buf_size);
break;
case HostCmd_ACT_GEN_GET:
@@ -466,7 +469,8 @@ void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl))
return;
- dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl);
list_del(&tx_ba_tsr_tbl->list);
@@ -528,13 +532,16 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid,
struct mwifiex_tx_ba_stream_tbl *new_node;
struct mwifiex_ra_list_tbl *ra_list;
unsigned long flags;
+ int tid_down;
if (!mwifiex_get_ba_tbl(priv, tid, ra)) {
new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl),
GFP_ATOMIC);
if (!new_node)
return;
- ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra);
+
+ tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
+ ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, ra);
if (ra_list) {
ra_list->ba_status = ba_status;
ra_list->amsdu_in_ampdu = false;
@@ -563,7 +570,7 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
unsigned long flags;
u16 block_ack_param_set;
- dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid);
+ mwifiex_dbg(priv->adapter, CMD, "cmd: %s: tid %d\n", __func__, tid);
if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
@@ -575,9 +582,9 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
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);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "BA setup with unknown TDLS peer %pM!\n",
+ peer_mac);
return -1;
}
if (sta_ptr->is_11ac_enabled)
@@ -641,6 +648,30 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
}
/*
+ * This function sends delba to specific tid
+ */
+void mwifiex_11n_delba(struct mwifiex_private *priv, int tid)
+{
+ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
+
+ if (list_empty(&priv->rx_reorder_tbl_ptr)) {
+ dev_dbg(priv->adapter->dev,
+ "mwifiex_11n_delba: rx_reorder_tbl_ptr empty\n");
+ return;
+ }
+
+ list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) {
+ if (rx_reor_tbl_ptr->tid == tid) {
+ dev_dbg(priv->adapter->dev,
+ "Send delba to tid=%d, %pM\n",
+ tid, rx_reor_tbl_ptr->ta);
+ mwifiex_send_delba(priv, tid, rx_reor_tbl_ptr->ta, 0);
+ return;
+ }
+ }
+}
+
+/*
* This function handles the command response of a delete BA request.
*/
void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba)
@@ -706,8 +737,8 @@ int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid;
- dev_dbg(priv->adapter->dev, "data: %s tid=%d\n",
- __func__, rx_reo_tbl->tid);
+ mwifiex_dbg(priv->adapter, DATA, "data: %s tid=%d\n",
+ __func__, rx_reo_tbl->tid);
memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN);
rx_reo_tbl->amsdu = tx_ba_tsr_tbl->amsdu;
rx_reo_tbl++;
@@ -812,3 +843,72 @@ u8 mwifiex_get_sec_chan_offset(int chan)
return sec_offset;
}
+
+/* This function will send DELBA to entries in the priv's
+ * Tx BA stream table
+ */
+static void
+mwifiex_send_delba_txbastream_tbl(struct mwifiex_private *priv, u8 tid)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_tx_ba_stream_tbl *tx_ba_stream_tbl_ptr;
+
+ if (list_empty(&priv->tx_ba_stream_tbl_ptr))
+ return;
+
+ list_for_each_entry(tx_ba_stream_tbl_ptr,
+ &priv->tx_ba_stream_tbl_ptr, list) {
+ if (tx_ba_stream_tbl_ptr->ba_status == BA_SETUP_COMPLETE) {
+ if (tid == tx_ba_stream_tbl_ptr->tid) {
+ dev_dbg(adapter->dev,
+ "Tx:Send delba to tid=%d, %pM\n", tid,
+ tx_ba_stream_tbl_ptr->ra);
+ mwifiex_send_delba(priv,
+ tx_ba_stream_tbl_ptr->tid,
+ tx_ba_stream_tbl_ptr->ra, 1);
+ return;
+ }
+ }
+ }
+}
+
+/* This function updates all the tx_win_size
+ */
+void mwifiex_update_ampdu_txwinsize(struct mwifiex_adapter *adapter)
+{
+ u8 i;
+ u32 tx_win_size;
+ struct mwifiex_private *priv;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (!adapter->priv[i])
+ continue;
+ priv = adapter->priv[i];
+ tx_win_size = priv->add_ba_param.tx_win_size;
+
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_TXWINSIZE;
+
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_TXWINSIZE;
+
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE;
+
+ if (adapter->coex_win_size) {
+ if (adapter->coex_tx_win_size)
+ priv->add_ba_param.tx_win_size =
+ adapter->coex_tx_win_size;
+ }
+
+ if (tx_win_size != priv->add_ba_param.tx_win_size) {
+ if (!priv->media_connected)
+ continue;
+ for (i = 0; i < MAX_NUM_TID; i++)
+ mwifiex_send_delba_txbastream_tbl(priv, i);
+ }
+ }
+}
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
index 6183e255e62a..f7c717253a66 100644
--- a/drivers/net/wireless/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -187,7 +187,6 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
skb_aggr = mwifiex_alloc_dma_align_buf(adapter->tx_buf_size,
GFP_ATOMIC | GFP_DMA);
if (!skb_aggr) {
- dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__);
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
return -1;
@@ -297,13 +296,13 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
- dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+ mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
break;
case -1:
if (adapter->iface_type != MWIFIEX_PCIE)
adapter->data_sent = false;
- dev_err(adapter->dev, "%s: host_to_card failed: %#x\n",
- __func__, ret);
+ mwifiex_dbg(adapter, ERROR, "%s: host_to_card failed: %#x\n",
+ __func__, ret);
adapter->dbg.num_tx_host_to_card_failure++;
mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);
return 0;
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index f75f8acfaca0..2906cd543532 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -51,8 +51,8 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
rx_skb = __skb_dequeue(&list);
ret = mwifiex_recv_packet(priv, rx_skb);
if (ret == -1)
- dev_err(priv->adapter->dev,
- "Rx of A-MSDU failed");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Rx of A-MSDU failed");
}
return 0;
}
@@ -304,7 +304,7 @@ mwifiex_flush_data(unsigned long context)
if (seq_num < 0)
return;
- dev_dbg(ctx->priv->adapter->dev, "info: flush data %d\n", seq_num);
+ mwifiex_dbg(ctx->priv->adapter, INFO, "info: flush data %d\n", seq_num);
start_win = (ctx->ptr->start_win + seq_num + 1) & (MAX_TID_VALUE - 1);
mwifiex_11n_dispatch_pkt_until_start_win(ctx->priv, ctx->ptr,
start_win);
@@ -367,8 +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);
+ mwifiex_dbg(priv->adapter, INFO,
+ "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) {
@@ -382,8 +383,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
GFP_KERNEL);
if (!new_node->rx_reorder_ptr) {
kfree((u8 *) new_node);
- dev_err(priv->adapter->dev,
- "%s: failed to alloc reorder_ptr\n", __func__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: failed to alloc reorder_ptr\n", __func__);
return;
}
@@ -467,9 +468,9 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *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);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "BA setup with unknown TDLS peer %pM!\n",
+ cmd_addba_req->peer_mac_addr);
return -1;
}
if (sta_ptr->is_11ac_enabled)
@@ -573,14 +574,14 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
}
if (tbl->flags & RXREOR_FORCE_NO_DROP) {
- dev_dbg(priv->adapter->dev,
- "RXREOR_FORCE_NO_DROP when HS is activated\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "RXREOR_FORCE_NO_DROP when HS is activated\n");
tbl->flags &= ~RXREOR_FORCE_NO_DROP;
} else if (init_window_shift && seq_num < start_win &&
seq_num >= tbl->init_win) {
- dev_dbg(priv->adapter->dev,
- "Sender TID sequence number reset %d->%d for SSN %d\n",
- start_win, seq_num, tbl->init_win);
+ mwifiex_dbg(priv->adapter, INFO,
+ "Sender TID sequence number reset %d->%d for SSN %d\n",
+ start_win, seq_num, tbl->init_win);
tbl->start_win = start_win = seq_num;
end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
} else {
@@ -662,32 +663,35 @@ mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac,
struct mwifiex_ra_list_tbl *ra_list;
u8 cleanup_rx_reorder_tbl;
unsigned long flags;
+ int tid_down;
if (type == TYPE_DELBA_RECEIVE)
cleanup_rx_reorder_tbl = (initiator) ? true : false;
else
cleanup_rx_reorder_tbl = (initiator) ? false : true;
- dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d initiator=%d\n",
- peer_mac, tid, initiator);
+ mwifiex_dbg(priv->adapter, EVENT, "event: DELBA: %pM tid=%d initiator=%d\n",
+ peer_mac, tid, initiator);
if (cleanup_rx_reorder_tbl) {
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
peer_mac);
if (!tbl) {
- dev_dbg(priv->adapter->dev,
- "event: TID, TA not found in table\n");
+ mwifiex_dbg(priv->adapter, EVENT,
+ "event: TID, TA not found in table\n");
return;
}
mwifiex_del_rx_reorder_entry(priv, tbl);
} else {
ptx_tbl = mwifiex_get_ba_tbl(priv, tid, peer_mac);
if (!ptx_tbl) {
- dev_dbg(priv->adapter->dev,
- "event: TID, RA not found in table\n");
+ mwifiex_dbg(priv->adapter, EVENT,
+ "event: TID, RA not found in table\n");
return;
}
- ra_list = mwifiex_wmm_get_ralist_node(priv, tid, peer_mac);
+
+ tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
+ ra_list = mwifiex_wmm_get_ralist_node(priv, tid_down, peer_mac);
if (ra_list) {
ra_list->amsdu_in_ampdu = false;
ra_list->ba_status = BA_SETUP_NONE;
@@ -721,8 +725,8 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
* the stream
*/
if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) {
- dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n",
- add_ba_rsp->peer_mac_addr, tid);
+ mwifiex_dbg(priv->adapter, ERROR, "ADDBA RSP: failed %pM tid=%d)\n",
+ add_ba_rsp->peer_mac_addr, tid);
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
add_ba_rsp->peer_mac_addr);
@@ -746,8 +750,8 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
tbl->amsdu = false;
}
- dev_dbg(priv->adapter->dev,
- "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n",
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: ADDBA RSP: %pM tid=%d ssn=%d win_size=%d\n",
add_ba_rsp->peer_mac_addr, tid, add_ba_rsp->ssn, win_size);
return 0;
@@ -824,3 +828,83 @@ void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags)
return;
}
+
+/* This function update all the rx_win_size based on coex flag
+ */
+static void mwifiex_update_ampdu_rxwinsize(struct mwifiex_adapter *adapter,
+ bool coex_flag)
+{
+ u8 i;
+ u32 rx_win_size;
+ struct mwifiex_private *priv;
+
+ dev_dbg(adapter->dev, "Update rxwinsize %d\n", coex_flag);
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (!adapter->priv[i])
+ continue;
+ priv = adapter->priv[i];
+ rx_win_size = priv->add_ba_param.rx_win_size;
+ if (coex_flag) {
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_UAP_COEX_AMPDU_DEF_RXWINSIZE;
+ } else {
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE;
+ }
+
+ if (adapter->coex_win_size && adapter->coex_rx_win_size)
+ priv->add_ba_param.rx_win_size =
+ adapter->coex_rx_win_size;
+
+ if (rx_win_size != priv->add_ba_param.rx_win_size) {
+ if (!priv->media_connected)
+ continue;
+ for (i = 0; i < MAX_NUM_TID; i++)
+ mwifiex_11n_delba(priv, i);
+ }
+ }
+}
+
+/* This function check coex for RX BA
+ */
+void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter)
+{
+ u8 i;
+ struct mwifiex_private *priv;
+ u8 count = 0;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ priv = adapter->priv[i];
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
+ if (priv->media_connected)
+ count++;
+ }
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ if (priv->bss_started)
+ count++;
+ }
+ }
+ if (count >= MWIFIEX_BSS_COEX_COUNT)
+ break;
+ }
+ if (count >= MWIFIEX_BSS_COEX_COUNT)
+ mwifiex_update_ampdu_rxwinsize(adapter, true);
+ else
+ mwifiex_update_ampdu_rxwinsize(adapter, false);
+}
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig
index aa01c9bc77f9..48edf387683e 100644
--- a/drivers/net/wireless/mwifiex/Kconfig
+++ b/drivers/net/wireless/mwifiex/Kconfig
@@ -12,6 +12,7 @@ config MWIFIEX_SDIO
tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797/SD8887/SD8897"
depends on MWIFIEX && MMC
select FW_LOADER
+ select WANT_DEV_COREDUMP
---help---
This adds support for wireless adapters based on Marvell
8786/8787/8797/8887/8897 chipsets with SDIO interface.
@@ -23,6 +24,7 @@ config MWIFIEX_PCIE
tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897"
depends on MWIFIEX && PCI
select FW_LOADER
+ select WANT_DEV_COREDUMP
---help---
This adds support for wireless adapters based on Marvell
8766/8897 chipsets with PCIe interface.
diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README
index 31928caeeed2..2f0f9b5609d0 100644
--- a/drivers/net/wireless/mwifiex/README
+++ b/drivers/net/wireless/mwifiex/README
@@ -230,9 +230,9 @@ getlog
cat getlog
-fw_dump
- This command is used to dump firmware memory into files.
- Separate file will be created for each memory segment.
+device_dump
+ This command is used to dump driver information and firmware memory
+ segments.
Usage:
cat fw_dump
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index bf9020ff2d33..b15e4c7acbec 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -67,6 +67,22 @@ u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type)
}
}
+/* This function maps IEEE HT secondary channel type to NL80211 channel type
+ */
+u8 mwifiex_sec_chan_offset_to_chan_type(u8 second_chan_offset)
+{
+ switch (second_chan_offset) {
+ case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+ return NL80211_CHAN_HT20;
+ case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+ return NL80211_CHAN_HT40PLUS;
+ case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+ return NL80211_CHAN_HT40MINUS;
+ default:
+ return NL80211_CHAN_HT20;
+ }
+}
+
/*
* This function checks whether WEP is set.
*/
@@ -104,11 +120,11 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index, peer_mac, 1)) {
- wiphy_err(wiphy, "deleting the crypto keys\n");
+ mwifiex_dbg(priv->adapter, ERROR, "deleting the crypto keys\n");
return -EFAULT;
}
- wiphy_dbg(wiphy, "info: crypto keys deleted\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: crypto keys deleted\n");
return 0;
}
@@ -163,7 +179,7 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
if (!buf || !len) {
- wiphy_err(wiphy, "invalid buffer and length\n");
+ mwifiex_dbg(priv->adapter, ERROR, "invalid buffer and length\n");
return -EFAULT;
}
@@ -172,8 +188,8 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
ieee80211_is_probe_resp(mgmt->frame_control)) {
/* Since we support offload probe resp, we need to skip probe
* resp in AP or GO mode */
- wiphy_dbg(wiphy,
- "info: skip to send probe resp in AP or GO mode\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: skip to send probe resp in AP or GO mode\n");
return 0;
}
@@ -183,7 +199,8 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
pkt_len + sizeof(pkt_len));
if (!skb) {
- wiphy_err(wiphy, "allocate skb failed for management frame\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "allocate skb failed for management frame\n");
return -ENOMEM;
}
@@ -206,7 +223,7 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
mwifiex_queue_tx_pkt(priv, skb);
- wiphy_dbg(wiphy, "info: management frame transmitted\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: management frame transmitted\n");
return 0;
}
@@ -231,7 +248,7 @@ mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG,
HostCmd_ACT_GEN_SET, 0,
&priv->mgmt_frame_mask, false);
- wiphy_dbg(wiphy, "info: mgmt frame registered\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: mgmt frame registered\n");
}
}
@@ -248,13 +265,14 @@ mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
int ret;
if (!chan || !cookie) {
- wiphy_err(wiphy, "Invalid parameter for ROC\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Invalid parameter for ROC\n");
return -EINVAL;
}
if (priv->roc_cfg.cookie) {
- wiphy_dbg(wiphy, "info: ongoing ROC, cookie = 0x%llx\n",
- priv->roc_cfg.cookie);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ongoing ROC, cookie = 0x%llx\n",
+ priv->roc_cfg.cookie);
return -EBUSY;
}
@@ -269,7 +287,8 @@ mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
cfg80211_ready_on_channel(wdev, *cookie, chan,
duration, GFP_ATOMIC);
- wiphy_dbg(wiphy, "info: ROC, cookie = 0x%llx\n", *cookie);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ROC, cookie = 0x%llx\n", *cookie);
}
return ret;
@@ -298,7 +317,8 @@ mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
memset(&priv->roc_cfg, 0, sizeof(struct mwifiex_roc_cfg));
- wiphy_dbg(wiphy, "info: cancel ROC, cookie = 0x%llx\n", cookie);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: cancel ROC, cookie = 0x%llx\n", cookie);
}
return ret;
@@ -344,8 +364,8 @@ mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy,
u32 ps_mode;
if (timeout)
- wiphy_dbg(wiphy,
- "info: ignore timeout value for IEEE Power Save\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ignore timeout value for IEEE Power Save\n");
ps_mode = enabled;
@@ -370,7 +390,7 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
priv->wep_key_curr_index = key_index;
} else if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index,
NULL, 0)) {
- wiphy_err(wiphy, "set default Tx key index\n");
+ mwifiex_dbg(priv->adapter, ERROR, "set default Tx key index\n");
return -EFAULT;
}
@@ -407,7 +427,7 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
if (mwifiex_set_encode(priv, params, params->key, params->key_len,
key_index, peer_mac, 0)) {
- wiphy_err(wiphy, "crypto keys added\n");
+ mwifiex_dbg(priv->adapter, ERROR, "crypto keys added\n");
return -EFAULT;
}
@@ -442,7 +462,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
band = mwifiex_band_to_radio_type(adapter->config_bands);
if (!wiphy->bands[band]) {
- wiphy_err(wiphy, "11D: setting domain info in FW\n");
+ mwifiex_dbg(adapter, ERROR,
+ "11D: setting domain info in FW\n");
return -1;
}
@@ -493,7 +514,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
HostCmd_ACT_GEN_SET, 0, NULL, false)) {
- wiphy_err(wiphy, "11D: setting domain info in FW\n");
+ mwifiex_dbg(adapter, INFO,
+ "11D: setting domain info in FW\n");
return -1;
}
@@ -516,9 +538,9 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy,
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
struct mwifiex_private *priv = mwifiex_get_priv(adapter,
MWIFIEX_BSS_ROLE_ANY);
-
- wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for %c%c\n",
- request->alpha2[0], request->alpha2[1]);
+ mwifiex_dbg(adapter, INFO,
+ "info: cfg80211 regulatory domain callback for %c%c\n",
+ request->alpha2[0], request->alpha2[1]);
switch (request->initiator) {
case NL80211_REGDOM_SET_BY_DRIVER:
@@ -527,8 +549,9 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy,
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
break;
default:
- wiphy_err(wiphy, "unknown regdom initiator: %d\n",
- request->initiator);
+ mwifiex_dbg(adapter, ERROR,
+ "unknown regdom initiator: %d\n",
+ request->initiator);
return;
}
@@ -597,8 +620,8 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
switch (priv->bss_role) {
case MWIFIEX_BSS_ROLE_UAP:
if (priv->bss_started) {
- dev_err(adapter->dev,
- "cannot change wiphy params when bss started");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot change wiphy params when bss started");
return -EINVAL;
}
@@ -622,15 +645,16 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
kfree(bss_cfg);
if (ret) {
- wiphy_err(wiphy, "Failed to set wiphy phy params\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to set wiphy phy params\n");
return ret;
}
break;
case MWIFIEX_BSS_ROLE_STA:
if (priv->media_connected) {
- dev_err(adapter->dev,
- "cannot change wiphy params when connected");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot change wiphy params when connected");
return -EINVAL;
}
if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
@@ -724,8 +748,8 @@ static int mwifiex_deinit_priv_params(struct mwifiex_private *priv)
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");
+ mwifiex_dbg(adapter, ERROR,
+ "could not unregister mgmt frame rx\n");
return -1;
}
@@ -789,9 +813,9 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv,
priv->bss_role = MWIFIEX_BSS_ROLE_UAP;
break;
default:
- dev_err(priv->adapter->dev,
- "%s: changing to %d not supported\n",
- dev->name, type);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
@@ -824,12 +848,13 @@ mwifiex_change_vif_to_p2p(struct net_device *dev,
if (adapter->curr_iface_comb.p2p_intf ==
adapter->iface_limit.p2p_intf) {
- dev_err(adapter->dev,
- "cannot create multiple P2P ifaces\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create multiple P2P ifaces\n");
return -1;
}
- dev_dbg(priv->adapter->dev, "%s: changing role to p2p\n", dev->name);
+ mwifiex_dbg(adapter, INFO,
+ "%s: changing role to p2p\n", dev->name);
if (mwifiex_deinit_priv_params(priv))
return -1;
@@ -846,9 +871,9 @@ mwifiex_change_vif_to_p2p(struct net_device *dev,
return -EFAULT;
break;
default:
- dev_err(priv->adapter->dev,
- "%s: changing to %d not supported\n",
- dev->name, type);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
@@ -897,17 +922,17 @@ mwifiex_change_vif_to_sta_adhoc(struct net_device *dev,
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");
+ mwifiex_dbg(adapter, ERROR,
+ "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);
+ mwifiex_dbg(adapter, INFO,
+ "%s: changing role to station\n", dev->name);
else
- dev_notice(adapter->dev,
- "%s: changing role to adhoc\n", dev->name);
+ mwifiex_dbg(adapter, INFO,
+ "%s: changing role to adhoc\n", dev->name);
if (mwifiex_deinit_priv_params(priv))
return -1;
@@ -954,12 +979,13 @@ mwifiex_change_vif_to_ap(struct net_device *dev,
if (adapter->curr_iface_comb.uap_intf ==
adapter->iface_limit.uap_intf) {
- dev_err(adapter->dev,
- "cannot create multiple AP ifaces\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create multiple AP ifaces\n");
return -1;
}
- dev_notice(adapter->dev, "%s: changing role to AP\n", dev->name);
+ mwifiex_dbg(adapter, INFO,
+ "%s: changing role to AP\n", dev->name);
if (mwifiex_deinit_priv_params(priv))
return -1;
@@ -1020,12 +1046,14 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
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);
+ mwifiex_dbg(priv->adapter, INFO,
+ "%s: kept type as IBSS\n", dev->name);
case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */
return 0;
default:
- wiphy_err(wiphy, "%s: changing to %d not supported\n",
- dev->name, type);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
break;
@@ -1048,12 +1076,14 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
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);
+ mwifiex_dbg(priv->adapter, INFO,
+ "%s: kept type as STA\n", dev->name);
case NL80211_IFTYPE_STATION: /* This shouldn't happen */
return 0;
default:
- wiphy_err(wiphy, "%s: changing to %d not supported\n",
- dev->name, type);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
break;
@@ -1070,12 +1100,14 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
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);
+ mwifiex_dbg(priv->adapter, INFO,
+ "%s: kept type as AP\n", dev->name);
case NL80211_IFTYPE_AP: /* This shouldn't happen */
return 0;
default:
- wiphy_err(wiphy, "%s: changing to %d not supported\n",
- dev->name, type);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
break;
@@ -1100,19 +1132,22 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
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);
+ mwifiex_dbg(priv->adapter, INFO,
+ "%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);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
break;
default:
- wiphy_err(wiphy, "%s: unknown iftype: %d\n",
- dev->name, dev->ieee80211_ptr->iftype);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: unknown iftype: %d\n",
+ dev->name, dev->ieee80211_ptr->iftype);
return -EOPNOTSUPP;
}
@@ -1194,6 +1229,7 @@ mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo,
*/
static int
mwifiex_dump_station_info(struct mwifiex_private *priv,
+ struct mwifiex_sta_node *node,
struct station_info *sinfo)
{
u32 rate;
@@ -1203,15 +1239,41 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
BIT(NL80211_STA_INFO_TX_BITRATE) |
BIT(NL80211_STA_INFO_SIGNAL) | BIT(NL80211_STA_INFO_SIGNAL_AVG);
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ if (!node)
+ return -ENOENT;
+
+ sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME) |
+ BIT(NL80211_STA_INFO_TX_FAILED);
+ sinfo->inactive_time =
+ jiffies_to_msecs(jiffies - node->stats.last_rx);
+
+ sinfo->signal = node->stats.rssi;
+ sinfo->signal_avg = node->stats.rssi;
+ sinfo->rx_bytes = node->stats.rx_bytes;
+ sinfo->tx_bytes = node->stats.tx_bytes;
+ sinfo->rx_packets = node->stats.rx_packets;
+ sinfo->tx_packets = node->stats.tx_packets;
+ sinfo->tx_failed = node->stats.tx_failed;
+
+ mwifiex_parse_htinfo(priv, node->stats.last_tx_htinfo,
+ &sinfo->txrate);
+ sinfo->txrate.legacy = node->stats.last_tx_rate * 5;
+
+ return 0;
+ }
+
/* Get signal information from the firmware */
if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
HostCmd_ACT_GEN_GET, 0, NULL, true)) {
- dev_err(priv->adapter->dev, "failed to get signal information\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "failed to get signal information\n");
return -EFAULT;
}
if (mwifiex_drv_get_data_rate(priv, &rate)) {
- dev_err(priv->adapter->dev, "getting data rate\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "getting data rate error\n");
return -EFAULT;
}
@@ -1267,7 +1329,7 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
if (memcmp(mac, priv->cfg_bssid, ETH_ALEN))
return -ENOENT;
- return mwifiex_dump_station_info(priv, sinfo);
+ return mwifiex_dump_station_info(priv, NULL, sinfo);
}
/*
@@ -1278,13 +1340,29 @@ mwifiex_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
int idx, u8 *mac, struct station_info *sinfo)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ static struct mwifiex_sta_node *node;
- if (!priv->media_connected || idx)
- return -ENOENT;
+ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+ priv->media_connected && idx == 0) {
+ ether_addr_copy(mac, priv->cfg_bssid);
+ return mwifiex_dump_station_info(priv, NULL, sinfo);
+ } else if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ mwifiex_send_cmd(priv, HOST_CMD_APCMD_STA_LIST,
+ HostCmd_ACT_GEN_GET, 0, NULL, true);
+
+ if (node && (&node->list == &priv->sta_list)) {
+ node = NULL;
+ return -ENOENT;
+ }
- memcpy(mac, priv->cfg_bssid, ETH_ALEN);
+ node = list_prepare_entry(node, &priv->sta_list, list);
+ list_for_each_entry_continue(node, &priv->sta_list, list) {
+ ether_addr_copy(mac, node->mac_addr);
+ return mwifiex_dump_station_info(priv, node, sinfo);
+ }
+ }
- return mwifiex_dump_station_info(priv, sinfo);
+ return -ENOENT;
}
static int
@@ -1295,7 +1373,7 @@ mwifiex_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
struct mwifiex_chan_stats *pchan_stats = priv->adapter->chan_stats;
enum ieee80211_band band;
- dev_dbg(priv->adapter->dev, "dump_survey idx=%d\n", idx);
+ mwifiex_dbg(priv->adapter, DUMP, "dump_survey idx=%d\n", idx);
memset(survey, 0, sizeof(struct survey_info));
@@ -1472,8 +1550,8 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
struct mwifiex_adapter *adapter = priv->adapter;
if (!priv->media_connected) {
- dev_err(adapter->dev,
- "Can not set Tx data rate in disconnected state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Can not set Tx data rate in disconnected state\n");
return -EINVAL;
}
@@ -1556,17 +1634,20 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy,
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) {
- wiphy_err(wiphy, "%s: bss_type mismatched\n", __func__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: bss_type mismatched\n", __func__);
return -EINVAL;
}
if (!priv->bss_started) {
- wiphy_err(wiphy, "%s: bss not started\n", __func__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: bss not started\n", __func__);
return -EINVAL;
}
if (mwifiex_set_mgmt_ies(priv, data)) {
- wiphy_err(wiphy, "%s: setting mgmt ies failed\n", __func__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: setting mgmt ies failed\n", __func__);
return -EFAULT;
}
@@ -1594,7 +1675,8 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
if (!params->mac || is_broadcast_ether_addr(params->mac))
return 0;
- wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__, params->mac);
+ mwifiex_dbg(priv->adapter, INFO, "%s: mac address %pM\n",
+ __func__, params->mac);
eth_zero_addr(deauth_mac);
@@ -1687,14 +1769,23 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
mwifiex_abort_cac(priv);
if (mwifiex_del_mgmt_ies(priv))
- wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "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)) {
- wiphy_err(wiphy, "Failed to stop the BSS\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to stop the BSS\n");
+ return -1;
+ }
+
+ if (mwifiex_send_cmd(priv, HOST_CMD_APCMD_SYS_RESET,
+ HostCmd_ACT_GEN_SET, 0, NULL, true)) {
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to reset BSS\n");
return -1;
}
@@ -1751,12 +1842,13 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
return -EINVAL;
}
- mwifiex_uap_set_channel(bss_cfg, params->chandef);
+ mwifiex_uap_set_channel(priv, bss_cfg, params->chandef);
mwifiex_set_uap_rates(bss_cfg, params);
if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
kfree(bss_cfg);
- wiphy_err(wiphy, "Failed to parse secuirty parameters!\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to parse secuirty parameters!\n");
return -1;
}
@@ -1775,20 +1867,25 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
mwifiex_set_wmm_params(priv, bss_cfg, params);
+ if (mwifiex_is_11h_active(priv))
+ mwifiex_set_tpc_params(priv, bss_cfg, params);
+
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");
+ mwifiex_dbg(priv->adapter, INFO,
+ "Disable 11h extensions in FW\n");
if (mwifiex_11h_activate(priv, false)) {
- dev_err(priv->adapter->dev,
- "Failed to disable 11h extensions!!");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to disable 11h extensions!!");
return -1;
}
- priv->state_11h.is_11h_active = true;
+ priv->state_11h.is_11h_active = false;
}
if (mwifiex_config_start_uap(priv, bss_cfg)) {
- wiphy_err(wiphy, "Failed to start AP\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to start AP\n");
kfree(bss_cfg);
return -1;
}
@@ -1816,8 +1913,9 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
if (mwifiex_deauthenticate(priv, NULL))
return -EFAULT;
- wiphy_dbg(wiphy, "info: successfully disconnected from %pM:"
- " reason code %d\n", priv->cfg_bssid, reason_code);
+ mwifiex_dbg(priv->adapter, MSG,
+ "info: successfully disconnected from %pM:\t"
+ "reason code %d\n", priv->cfg_bssid, reason_code);
eth_zero_addr(priv->cfg_bssid);
priv->hs2_enabled = false;
@@ -1899,13 +1997,13 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len,
req_ssid.ssid_len = ssid_len;
if (ssid_len > IEEE80211_MAX_SSID_LEN) {
- dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
+ mwifiex_dbg(priv->adapter, ERROR, "invalid SSID - aborting\n");
return -EINVAL;
}
memcpy(req_ssid.ssid, ssid, ssid_len);
if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
- dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
+ mwifiex_dbg(priv->adapter, ERROR, "invalid SSID - aborting\n");
return -EINVAL;
}
@@ -1959,9 +2057,9 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len,
if (sme->key) {
if (mwifiex_is_alg_wep(priv->sec_info.encryption_mode)) {
- dev_dbg(priv->adapter->dev,
- "info: setting wep encryption"
- " with key len %d\n", sme->key_len);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: setting wep encryption\t"
+ "with key len %d\n", sme->key_len);
priv->wep_key_curr_index = sme->key_idx;
ret = mwifiex_set_encode(priv, NULL, sme->key,
sme->key_len, sme->key_idx,
@@ -1978,7 +2076,7 @@ done:
if (is_scanning_required) {
/* Do specific SSID scanning */
if (mwifiex_request_scan(priv, &req_ssid)) {
- dev_err(priv->adapter->dev, "scan error\n");
+ mwifiex_dbg(priv->adapter, ERROR, "scan error\n");
return -EFAULT;
}
}
@@ -1997,15 +2095,15 @@ done:
if (!bss) {
if (is_scanning_required) {
- dev_warn(priv->adapter->dev,
- "assoc: requested bss not found in scan results\n");
+ mwifiex_dbg(priv->adapter, WARN,
+ "assoc: requested bss not found in scan results\n");
break;
}
is_scanning_required = 1;
} else {
- dev_dbg(priv->adapter->dev,
- "info: trying to associate to '%s' bssid %pM\n",
- (char *) req_ssid.ssid, bss->bssid);
+ mwifiex_dbg(priv->adapter, MSG,
+ "info: trying to associate to '%s' bssid %pM\n",
+ (char *)req_ssid.ssid, bss->bssid);
memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN);
break;
}
@@ -2041,26 +2139,29 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
int ret;
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) {
- wiphy_err(wiphy,
- "%s: reject infra assoc request in non-STA role\n",
- dev->name);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: reject infra assoc request in non-STA role\n",
+ dev->name);
return -EINVAL;
}
if (priv->wdev.current_bss) {
- wiphy_warn(wiphy, "%s: already connected\n", dev->name);
+ mwifiex_dbg(adapter, ERROR,
+ "%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);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: Ignore connection.\t"
+ "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);
+ mwifiex_dbg(adapter, INFO,
+ "info: Trying to associate to %s and bssid %pM\n",
+ (char *)sme->ssid, sme->bssid);
ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid,
priv->bss_mode, sme->channel, sme, 0);
@@ -2068,17 +2169,17 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0,
NULL, 0, WLAN_STATUS_SUCCESS,
GFP_KERNEL);
- dev_dbg(priv->adapter->dev,
- "info: associated to bssid %pM successfully\n",
- priv->cfg_bssid);
+ mwifiex_dbg(priv->adapter, MSG,
+ "info: associated to bssid %pM successfully\n",
+ priv->cfg_bssid);
if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
priv->adapter->auto_tdls &&
priv->bss_type == MWIFIEX_BSS_TYPE_STA)
mwifiex_setup_auto_tdls_timer(priv);
} else {
- dev_dbg(priv->adapter->dev,
- "info: association to bssid %pM failed\n",
- priv->cfg_bssid);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "info: association to bssid %pM failed\n",
+ priv->cfg_bssid);
eth_zero_addr(priv->cfg_bssid);
if (ret > 0)
@@ -2105,7 +2206,6 @@ 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 mwifiex_adapter *adapter = priv->adapter;
int index = 0, i;
u8 config_bands = 0;
@@ -2162,8 +2262,10 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv,
priv->adhoc_channel = ieee80211_frequency_to_channel(
params->chandef.chan->center_freq);
- wiphy_dbg(wiphy, "info: set ibss band %d, chan %d, chan offset %d\n",
- config_bands, priv->adhoc_channel, adapter->sec_chan_offset);
+ mwifiex_dbg(adapter, INFO,
+ "info: set ibss band %d, chan %d, chan offset %d\n",
+ config_bands, priv->adhoc_channel,
+ adapter->sec_chan_offset);
return 0;
}
@@ -2182,13 +2284,15 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
int ret = 0;
if (priv->bss_mode != NL80211_IFTYPE_ADHOC) {
- wiphy_err(wiphy, "request to join ibss received "
- "when station is not in ibss mode\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "request to join ibss received\t"
+ "when station is not in ibss mode\n");
goto done;
}
- wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n",
- (char *) params->ssid, params->bssid);
+ mwifiex_dbg(priv->adapter, MSG,
+ "info: trying to join to %s and bssid %pM\n",
+ (char *)params->ssid, params->bssid);
mwifiex_set_ibss_params(priv, params);
@@ -2200,12 +2304,12 @@ done:
if (!ret) {
cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid,
params->chandef.chan, GFP_KERNEL);
- dev_dbg(priv->adapter->dev,
- "info: joined/created adhoc network with bssid"
- " %pM successfully\n", priv->cfg_bssid);
+ mwifiex_dbg(priv->adapter, MSG,
+ "info: joined/created adhoc network with bssid\t"
+ "%pM successfully\n", priv->cfg_bssid);
} else {
- dev_dbg(priv->adapter->dev,
- "info: failed creating/joining adhoc network\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "info: failed creating/joining adhoc network\n");
}
return ret;
@@ -2222,8 +2326,8 @@ mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n",
- priv->cfg_bssid);
+ mwifiex_dbg(priv->adapter, MSG, "info: disconnecting from essid %pM\n",
+ priv->cfg_bssid);
if (mwifiex_deauthenticate(priv, NULL))
return -EFAULT;
@@ -2250,13 +2354,15 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
struct ieee_types_header *ie;
struct mwifiex_user_scan_cfg *user_scan_cfg;
- wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name);
+ mwifiex_dbg(priv->adapter, CMD,
+ "info: received scan request on %s\n", dev->name);
/* Block scan request if scan operation or scan cleanup when interface
* is disabled is in process
*/
if (priv->scan_request || priv->scan_aborting) {
- dev_err(priv->adapter->dev, "cmd: Scan already in process..\n");
+ mwifiex_dbg(priv->adapter, WARN,
+ "cmd: Scan already in process..\n");
return -EBUSY;
}
@@ -2308,7 +2414,8 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
ret = mwifiex_scan_networks(priv, user_scan_cfg);
kfree(user_scan_cfg);
if (ret) {
- dev_err(priv->adapter->dev, "scan failed: %d\n", ret);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "scan failed: %d\n", ret);
priv->scan_aborting = false;
priv->scan_request = NULL;
return ret;
@@ -2454,15 +2561,15 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
case NL80211_IFTYPE_ADHOC:
if (adapter->curr_iface_comb.sta_intf ==
adapter->iface_limit.sta_intf) {
- wiphy_err(wiphy,
- "cannot create multiple sta/adhoc ifaces\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create multiple sta/adhoc ifaces\n");
return ERR_PTR(-EINVAL);
}
priv = mwifiex_get_unused_priv(adapter);
if (!priv) {
- wiphy_err(wiphy,
- "could not get free private struct\n");
+ mwifiex_dbg(adapter, ERROR,
+ "could not get free private struct\n");
return ERR_PTR(-EFAULT);
}
@@ -2478,21 +2585,21 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
priv->bss_priority = 0;
priv->bss_role = MWIFIEX_BSS_ROLE_STA;
- priv->bss_num = 0;
+ priv->bss_num = adapter->curr_iface_comb.sta_intf;
break;
case NL80211_IFTYPE_AP:
if (adapter->curr_iface_comb.uap_intf ==
adapter->iface_limit.uap_intf) {
- wiphy_err(wiphy,
- "cannot create multiple AP ifaces\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create multiple AP ifaces\n");
return ERR_PTR(-EINVAL);
}
priv = mwifiex_get_unused_priv(adapter);
if (!priv) {
- wiphy_err(wiphy,
- "could not get free private struct\n");
+ mwifiex_dbg(adapter, ERROR,
+ "could not get free private struct\n");
return ERR_PTR(-EFAULT);
}
@@ -2504,22 +2611,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
priv->bss_priority = 0;
priv->bss_role = MWIFIEX_BSS_ROLE_UAP;
priv->bss_started = 0;
- priv->bss_num = 0;
+ priv->bss_num = adapter->curr_iface_comb.uap_intf;
priv->bss_mode = type;
break;
case NL80211_IFTYPE_P2P_CLIENT:
if (adapter->curr_iface_comb.p2p_intf ==
adapter->iface_limit.p2p_intf) {
- wiphy_err(wiphy,
- "cannot create multiple P2P ifaces\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create multiple P2P ifaces\n");
return ERR_PTR(-EINVAL);
}
priv = mwifiex_get_unused_priv(adapter);
if (!priv) {
- wiphy_err(wiphy,
- "could not get free private struct\n");
+ mwifiex_dbg(adapter, ERROR,
+ "could not get free private struct\n");
return ERR_PTR(-EFAULT);
}
@@ -2540,7 +2647,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
priv->bss_priority = MWIFIEX_BSS_ROLE_STA;
priv->bss_role = MWIFIEX_BSS_ROLE_STA;
priv->bss_started = 0;
- priv->bss_num = 0;
+ priv->bss_num = adapter->curr_iface_comb.p2p_intf;
if (mwifiex_cfg80211_init_p2p_client(priv)) {
memset(&priv->wdev, 0, sizeof(priv->wdev));
@@ -2550,7 +2657,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
break;
default:
- wiphy_err(wiphy, "type not supported\n");
+ mwifiex_dbg(adapter, ERROR, "type not supported\n");
return ERR_PTR(-EINVAL);
}
@@ -2558,7 +2665,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
name_assign_type, ether_setup,
IEEE80211_NUM_ACS, 1);
if (!dev) {
- wiphy_err(wiphy, "no memory available for netdevice\n");
+ mwifiex_dbg(adapter, ERROR,
+ "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;
@@ -2599,7 +2707,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
/* Register network device */
if (register_netdevice(dev)) {
- wiphy_err(wiphy, "cannot register virtual network device\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot register virtual network device\n");
free_netdev(dev);
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
priv->netdev = NULL;
@@ -2613,7 +2722,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
WQ_MEM_RECLAIM |
WQ_UNBOUND, 1, name);
if (!priv->dfs_cac_workqueue) {
- wiphy_err(wiphy, "cannot register virtual network device\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot register virtual network device\n");
free_netdev(dev);
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
priv->netdev = NULL;
@@ -2628,7 +2738,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
WQ_HIGHPRI | WQ_UNBOUND |
WQ_MEM_RECLAIM, 1, name);
if (!priv->dfs_chan_sw_workqueue) {
- wiphy_err(wiphy, "cannot register virtual network device\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot register virtual network device\n");
free_netdev(dev);
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
priv->netdev = NULL;
@@ -2642,7 +2753,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
sema_init(&priv->async_sem, 1);
- dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: Marvell 802.11 Adapter\n", dev->name);
#ifdef CONFIG_DEBUG_FS
mwifiex_dev_debugfs_init(priv);
@@ -2661,7 +2773,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
adapter->curr_iface_comb.p2p_intf++;
break;
default:
- wiphy_err(wiphy, "type not supported\n");
+ mwifiex_dbg(adapter, ERROR, "type not supported\n");
return ERR_PTR(-EINVAL);
}
@@ -2721,7 +2833,8 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
adapter->curr_iface_comb.p2p_intf++;
break;
default:
- dev_err(adapter->dev, "del_virtual_intf: type not supported\n");
+ mwifiex_dbg(adapter, ERROR,
+ "del_virtual_intf: type not supported\n");
break;
}
@@ -2839,7 +2952,8 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv,
if (!mwifiex_is_pattern_supported(&wowlan->patterns[i],
byte_seq,
MWIFIEX_MEF_MAX_BYTESEQ)) {
- dev_err(priv->adapter->dev, "Pattern not supported\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Pattern not supported\n");
kfree(mef_entry);
return -EOPNOTSUPP;
}
@@ -2954,21 +3068,22 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
mwifiex_cancel_all_pending_cmd(adapter);
if (!wowlan) {
- dev_warn(adapter->dev, "None of the WOWLAN triggers enabled\n");
+ mwifiex_dbg(adapter, ERROR,
+ "None of the WOWLAN triggers enabled\n");
return 0;
}
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
if (!priv->media_connected) {
- dev_warn(adapter->dev,
- "Can not configure WOWLAN in disconnected state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Can not configure WOWLAN in disconnected state\n");
return 0;
}
ret = mwifiex_set_mef_filter(priv, wowlan);
if (ret) {
- dev_err(adapter->dev, "Failed to set MEF filter\n");
+ mwifiex_dbg(adapter, ERROR, "Failed to set MEF filter\n");
return ret;
}
@@ -2981,7 +3096,8 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
MWIFIEX_SYNC_CMD, &hs_cfg);
if (ret) {
- dev_err(adapter->dev, "Failed to set HS params\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to set HS params\n");
return ret;
}
}
@@ -3041,7 +3157,8 @@ mwifiex_fill_coalesce_rule_info(struct mwifiex_private *priv,
if (!mwifiex_is_pattern_supported(&crule->patterns[i],
byte_seq,
MWIFIEX_COALESCE_MAX_BYTESEQ)) {
- dev_err(priv->adapter->dev, "Pattern not supported\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Pattern not supported\n");
return -EOPNOTSUPP;
}
@@ -3050,8 +3167,8 @@ mwifiex_fill_coalesce_rule_info(struct mwifiex_private *priv,
pkt_type = mwifiex_get_coalesce_pkt_type(byte_seq);
if (pkt_type && mrule->pkt_type) {
- dev_err(priv->adapter->dev,
- "Multiple packet types not allowed\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Multiple packet types not allowed\n");
return -EOPNOTSUPP;
} else if (pkt_type) {
mrule->pkt_type = pkt_type;
@@ -3074,8 +3191,8 @@ mwifiex_fill_coalesce_rule_info(struct mwifiex_private *priv,
}
if (!mrule->pkt_type) {
- dev_err(priv->adapter->dev,
- "Packet type can not be determined\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Packet type can not be determined\n");
return -EOPNOTSUPP;
}
@@ -3093,8 +3210,8 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy,
memset(&coalesce_cfg, 0, sizeof(coalesce_cfg));
if (!coalesce) {
- dev_dbg(adapter->dev,
- "Disable coalesce and reset all previous rules\n");
+ mwifiex_dbg(adapter, WARN,
+ "Disable coalesce and reset all previous rules\n");
return mwifiex_send_cmd(priv, HostCmd_CMD_COALESCE_CFG,
HostCmd_ACT_GEN_SET, 0,
&coalesce_cfg, true);
@@ -3105,8 +3222,8 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy,
ret = mwifiex_fill_coalesce_rule_info(priv, &coalesce->rules[i],
&coalesce_cfg.rule[i]);
if (ret) {
- dev_err(priv->adapter->dev,
- "Recheck the patterns provided for rule %d\n",
+ mwifiex_dbg(adapter, ERROR,
+ "Recheck the patterns provided for rule %d\n",
i + 1);
return ret;
}
@@ -3138,9 +3255,9 @@ mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
switch (action_code) {
case WLAN_TDLS_SETUP_REQUEST:
- dev_dbg(priv->adapter->dev,
- "Send TDLS Setup Request to %pM status_code=%d\n", peer,
- status_code);
+ mwifiex_dbg(priv->adapter, MSG,
+ "Send TDLS Setup Request to %pM status_code=%d\n",
+ peer, status_code);
mwifiex_add_auto_tdls_peer(priv, peer);
ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
dialog_token, status_code,
@@ -3148,45 +3265,45 @@ mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
break;
case WLAN_TDLS_SETUP_RESPONSE:
mwifiex_add_auto_tdls_peer(priv, peer);
- dev_dbg(priv->adapter->dev,
- "Send TDLS Setup Response to %pM status_code=%d\n",
- peer, status_code);
+ mwifiex_dbg(priv->adapter, MSG,
+ "Send TDLS Setup Response to %pM status_code=%d\n",
+ peer, status_code);
ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
dialog_token, status_code,
extra_ies, extra_ies_len);
break;
case WLAN_TDLS_SETUP_CONFIRM:
- dev_dbg(priv->adapter->dev,
- "Send TDLS Confirm to %pM status_code=%d\n", peer,
- status_code);
+ mwifiex_dbg(priv->adapter, MSG,
+ "Send TDLS Confirm to %pM status_code=%d\n", peer,
+ status_code);
ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
dialog_token, status_code,
extra_ies, extra_ies_len);
break;
case WLAN_TDLS_TEARDOWN:
- dev_dbg(priv->adapter->dev, "Send TDLS Tear down to %pM\n",
- peer);
+ mwifiex_dbg(priv->adapter, MSG,
+ "Send TDLS Tear down to %pM\n", peer);
ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
dialog_token, status_code,
extra_ies, extra_ies_len);
break;
case WLAN_TDLS_DISCOVERY_REQUEST:
- dev_dbg(priv->adapter->dev,
- "Send TDLS Discovery Request to %pM\n", peer);
+ mwifiex_dbg(priv->adapter, MSG,
+ "Send TDLS Discovery Request to %pM\n", peer);
ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
dialog_token, status_code,
extra_ies, extra_ies_len);
break;
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
- dev_dbg(priv->adapter->dev,
- "Send TDLS Discovery Response to %pM\n", peer);
+ mwifiex_dbg(priv->adapter, MSG,
+ "Send TDLS Discovery Response to %pM\n", peer);
ret = mwifiex_send_tdls_action_frame(priv, peer, action_code,
dialog_token, status_code,
extra_ies, extra_ies_len);
break;
default:
- dev_warn(priv->adapter->dev,
- "Unknown TDLS mgmt/action frame %pM\n", peer);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Unknown TDLS mgmt/action frame %pM\n", peer);
ret = -EINVAL;
break;
}
@@ -3208,8 +3325,8 @@ mwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected))
return -ENOTSUPP;
- dev_dbg(priv->adapter->dev,
- "TDLS peer=%pM, oper=%d\n", peer, action);
+ mwifiex_dbg(priv->adapter, MSG,
+ "TDLS peer=%pM, oper=%d\n", peer, action);
switch (action) {
case NL80211_TDLS_ENABLE_LINK:
@@ -3220,22 +3337,22 @@ mwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
break;
case NL80211_TDLS_TEARDOWN:
/* shouldn't happen!*/
- dev_warn(priv->adapter->dev,
- "tdls_oper: teardown from driver not supported\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "tdls_oper: teardown from driver not supported\n");
return -EINVAL;
case NL80211_TDLS_SETUP:
/* shouldn't happen!*/
- dev_warn(priv->adapter->dev,
- "tdls_oper: setup from driver not supported\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "tdls_oper: setup from driver not supported\n");
return -EINVAL;
case NL80211_TDLS_DISCOVERY_REQ:
/* shouldn't happen!*/
- dev_warn(priv->adapter->dev,
- "tdls_oper: discovery from driver not supported\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "tdls_oper: discovery from driver not supported\n");
return -EINVAL;
default:
- dev_err(priv->adapter->dev,
- "tdls_oper: operation not supported\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "tdls_oper: operation not supported\n");
return -ENOTSUPP;
}
@@ -3268,8 +3385,8 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
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");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "radar detection: scan in process...\n");
return -EBUSY;
}
@@ -3284,8 +3401,8 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
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");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Could not parse channel switch announcement IE\n");
return -EINVAL;
}
@@ -3297,10 +3414,12 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
}
if (mwifiex_del_mgmt_ies(priv))
- wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "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__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: setting mgmt ies failed\n", __func__);
return -EFAULT;
}
@@ -3314,6 +3433,45 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
+static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_chan_def *chandef)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
+ struct mwifiex_bssdescriptor *curr_bss;
+ struct ieee80211_channel *chan;
+ u8 second_chan_offset;
+ enum nl80211_channel_type chan_type;
+ enum ieee80211_band band;
+ int freq;
+ int ret = -ENODATA;
+
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP &&
+ cfg80211_chandef_valid(&priv->bss_chandef)) {
+ *chandef = priv->bss_chandef;
+ ret = 0;
+ } else if (priv->media_connected) {
+ curr_bss = &priv->curr_bss_params.bss_descriptor;
+ band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
+ freq = ieee80211_channel_to_frequency(curr_bss->channel, band);
+ chan = ieee80211_get_channel(wiphy, freq);
+
+ if (curr_bss->bcn_ht_oper) {
+ second_chan_offset = curr_bss->bcn_ht_oper->ht_param &
+ IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
+ chan_type = mwifiex_sec_chan_offset_to_chan_type
+ (second_chan_offset);
+ cfg80211_chandef_create(chandef, chan, chan_type);
+ } else {
+ cfg80211_chandef_create(chandef, chan,
+ NL80211_CHAN_NO_HT);
+ }
+ ret = 0;
+ }
+
+ return ret;
+}
+
static int
mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
struct net_device *dev,
@@ -3324,16 +3482,17 @@ mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
struct mwifiex_radar_params radar_params;
if (priv->adapter->scan_processing) {
- dev_err(priv->adapter->dev,
- "radar detection: scan already in process...\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "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");
+ mwifiex_dbg(priv->adapter, INFO,
+ "Enable 11h extensions in FW\n");
if (mwifiex_11h_activate(priv, true)) {
- dev_err(priv->adapter->dev,
- "Failed to activate 11h extensions!!");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to activate 11h extensions!!");
return -1;
}
priv->state_11h.is_11h_active = true;
@@ -3418,6 +3577,7 @@ 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,
+ .get_channel = mwifiex_cfg80211_get_channel,
.start_radar_detection = mwifiex_cfg80211_start_radar_detection,
.channel_switch = mwifiex_cfg80211_channel_switch,
};
@@ -3492,7 +3652,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy = wiphy_new(&mwifiex_cfg80211_ops,
sizeof(struct mwifiex_adapter *));
if (!wiphy) {
- dev_err(adapter->dev, "%s: creating new wiphy\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: creating new wiphy\n", __func__);
return -ENOMEM;
}
wiphy->max_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH;
@@ -3524,7 +3685,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
- WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+ WIPHY_FLAG_HAS_CHANNEL_SWITCH |
+ WIPHY_FLAG_PS_ON_BY_DEFAULT;
if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
@@ -3563,20 +3725,22 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
ret = wiphy_register(wiphy);
if (ret < 0) {
- dev_err(adapter->dev,
- "%s: wiphy_register failed: %d\n", __func__, ret);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: wiphy_register failed: %d\n", __func__, ret);
wiphy_free(wiphy);
return ret;
}
if (reg_alpha2 && mwifiex_is_valid_alpha2(reg_alpha2)) {
- wiphy_info(wiphy, "driver hint alpha2: %2.2s\n", reg_alpha2);
+ mwifiex_dbg(adapter, INFO,
+ "driver hint alpha2: %2.2s\n", reg_alpha2);
regulatory_hint(wiphy, reg_alpha2);
} else {
country_code = mwifiex_11d_code_2_region(adapter->region_code);
if (country_code)
- wiphy_info(wiphy, "ignoring F/W country code %2.2s\n",
- country_code);
+ mwifiex_dbg(adapter, WARN,
+ "ignoring F/W country code %2.2s\n",
+ country_code);
}
mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
index e9df8826f124..3ddb8ec676ed 100644
--- a/drivers/net/wireless/mwifiex/cfp.c
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -327,8 +327,9 @@ mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq)
sband = priv->wdev.wiphy->bands[IEEE80211_BAND_5GHZ];
if (!sband) {
- dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d\n",
- __func__, band);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: cannot find cfp by band %d\n",
+ __func__, band);
return cfp;
}
@@ -349,9 +350,10 @@ mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq)
}
}
if (i == sband->n_channels) {
- dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
- " & channel=%d freq=%d\n", __func__, band, channel,
- freq);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: cannot find cfp by band %d\t"
+ "& channel=%d freq=%d\n",
+ __func__, band, channel, freq);
} else {
if (!ch)
return cfp;
@@ -431,15 +433,17 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
switch (adapter->config_bands) {
case BAND_B:
- dev_dbg(adapter->dev, "info: infra band=%d "
- "supported_rates_b\n", adapter->config_bands);
+ mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
+ "supported_rates_b\n",
+ adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_b,
sizeof(supported_rates_b));
break;
case BAND_G:
case BAND_G | BAND_GN:
- dev_dbg(adapter->dev, "info: infra band=%d "
- "supported_rates_g\n", adapter->config_bands);
+ mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
+ "supported_rates_g\n",
+ adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_g,
sizeof(supported_rates_g));
break;
@@ -449,15 +453,17 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC:
case BAND_B | BAND_G | BAND_GN:
- dev_dbg(adapter->dev, "info: infra band=%d "
- "supported_rates_bg\n", adapter->config_bands);
+ mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
+ "supported_rates_bg\n",
+ adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_bg,
sizeof(supported_rates_bg));
break;
case BAND_A:
case BAND_A | BAND_G:
- dev_dbg(adapter->dev, "info: infra band=%d "
- "supported_rates_a\n", adapter->config_bands);
+ mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
+ "supported_rates_a\n",
+ adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_a,
sizeof(supported_rates_a));
break;
@@ -466,14 +472,16 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
case BAND_A | BAND_AN | BAND_AAC:
case BAND_A | BAND_G | BAND_AN | BAND_GN:
case BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC:
- dev_dbg(adapter->dev, "info: infra band=%d "
- "supported_rates_a\n", adapter->config_bands);
+ mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
+ "supported_rates_a\n",
+ adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_a,
sizeof(supported_rates_a));
break;
case BAND_GN:
- dev_dbg(adapter->dev, "info: infra band=%d "
- "supported_rates_n\n", adapter->config_bands);
+ mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
+ "supported_rates_n\n",
+ adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_n,
sizeof(supported_rates_n));
break;
@@ -482,25 +490,25 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
/* Ad-hoc mode */
switch (adapter->adhoc_start_band) {
case BAND_B:
- dev_dbg(adapter->dev, "info: adhoc B\n");
+ mwifiex_dbg(adapter, INFO, "info: adhoc B\n");
k = mwifiex_copy_rates(rates, k, adhoc_rates_b,
sizeof(adhoc_rates_b));
break;
case BAND_G:
case BAND_G | BAND_GN:
- dev_dbg(adapter->dev, "info: adhoc G only\n");
+ mwifiex_dbg(adapter, INFO, "info: adhoc G only\n");
k = mwifiex_copy_rates(rates, k, adhoc_rates_g,
sizeof(adhoc_rates_g));
break;
case BAND_B | BAND_G:
case BAND_B | BAND_G | BAND_GN:
- dev_dbg(adapter->dev, "info: adhoc BG\n");
+ mwifiex_dbg(adapter, INFO, "info: adhoc BG\n");
k = mwifiex_copy_rates(rates, k, adhoc_rates_bg,
sizeof(adhoc_rates_bg));
break;
case BAND_A:
case BAND_A | BAND_AN:
- dev_dbg(adapter->dev, "info: adhoc A\n");
+ mwifiex_dbg(adapter, INFO, "info: adhoc A\n");
k = mwifiex_copy_rates(rates, k, adhoc_rates_a,
sizeof(adhoc_rates_a));
break;
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index c5a14ff7eb82..207da40500f4 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -62,7 +62,8 @@ mwifiex_get_cmd_node(struct mwifiex_adapter *adapter)
spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
if (list_empty(&adapter->cmd_free_q)) {
- dev_err(adapter->dev, "GET_CMD_NODE: cmd node not available\n");
+ mwifiex_dbg(adapter, ERROR,
+ "GET_CMD_NODE: cmd node not available\n");
spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
return NULL;
}
@@ -116,7 +117,8 @@ static int mwifiex_cmd_host_cmd(struct mwifiex_private *priv,
{
/* Copy the HOST command to command buffer */
memcpy(cmd, pcmd_ptr->cmd, pcmd_ptr->len);
- dev_dbg(priv->adapter->dev, "cmd: host cmd size = %d\n", pcmd_ptr->len);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: host cmd size = %d\n", pcmd_ptr->len);
return 0;
}
@@ -147,8 +149,9 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
/* Sanity test */
if (host_cmd == NULL || host_cmd->size == 0) {
- dev_err(adapter->dev, "DNLD_CMD: host_cmd is null"
- " or cmd size is 0, not sending\n");
+ mwifiex_dbg(adapter, ERROR,
+ "DNLD_CMD: host_cmd is null\t"
+ "or cmd size is 0, not sending\n");
if (cmd_node->wait_q_enabled)
adapter->cmd_wait_q.status = -1;
mwifiex_recycle_cmd_node(adapter, cmd_node);
@@ -161,8 +164,8 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET &&
cmd_code != HostCmd_CMD_FUNC_SHUTDOWN &&
cmd_code != HostCmd_CMD_FUNC_INIT) {
- dev_err(adapter->dev,
- "DNLD_CMD: FW in reset state, ignore cmd %#x\n",
+ mwifiex_dbg(adapter, ERROR,
+ "DNLD_CMD: FW in reset state, ignore cmd %#x\n",
cmd_code);
if (cmd_node->wait_q_enabled)
mwifiex_complete_cmd(adapter, cmd_node);
@@ -197,10 +200,12 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
*/
skb_put(cmd_node->cmd_skb, cmd_size - cmd_node->cmd_skb->len);
- dev_dbg(adapter->dev,
- "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n", cmd_code,
- le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size,
- le16_to_cpu(host_cmd->seq_num));
+ mwifiex_dbg(adapter, CMD,
+ "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n",
+ cmd_code,
+ le16_to_cpu(*(__le16 *)((u8 *)host_cmd + S_DS_GEN)),
+ cmd_size, le16_to_cpu(host_cmd->seq_num));
+ mwifiex_dbg_dump(adapter, CMD_D, "cmd buffer:", host_cmd, cmd_size);
if (adapter->iface_type == MWIFIEX_USB) {
tmp = cpu_to_le32(MWIFIEX_USB_TYPE_CMD);
@@ -221,7 +226,8 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
}
if (ret == -1) {
- dev_err(adapter->dev, "DNLD_CMD: host to card failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "DNLD_CMD: host to card failed\n");
if (adapter->iface_type == MWIFIEX_USB)
adapter->cmd_sent = false;
if (cmd_node->wait_q_enabled)
@@ -280,12 +286,14 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
(adapter->seq_num, priv->bss_num,
priv->bss_type)));
- dev_dbg(adapter->dev,
- "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n",
+ mwifiex_dbg(adapter, CMD,
+ "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n",
le16_to_cpu(sleep_cfm_buf->command),
le16_to_cpu(sleep_cfm_buf->action),
le16_to_cpu(sleep_cfm_buf->size),
le16_to_cpu(sleep_cfm_buf->seq_num));
+ mwifiex_dbg_dump(adapter, CMD_D, "SLEEP_CFM buffer: ", sleep_cfm_buf,
+ le16_to_cpu(sleep_cfm_buf->size));
if (adapter->iface_type == MWIFIEX_USB) {
sleep_cfm_tmp =
@@ -311,7 +319,7 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
}
if (ret == -1) {
- dev_err(adapter->dev, "SLEEP_CFM: failed\n");
+ mwifiex_dbg(adapter, ERROR, "SLEEP_CFM: failed\n");
adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
return -1;
}
@@ -362,8 +370,9 @@ int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter)
for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
cmd_array[i].skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
if (!cmd_array[i].skb) {
- dev_err(adapter->dev, "ALLOC_CMD_BUF: out of memory\n");
- return -1;
+ mwifiex_dbg(adapter, ERROR,
+ "unable to allocate command buffer\n");
+ return -ENOMEM;
}
}
@@ -386,7 +395,8 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter)
/* Need to check if cmd pool is allocated or not */
if (!adapter->cmd_pool) {
- dev_dbg(adapter->dev, "info: FREE_CMD_BUF: cmd_pool is null\n");
+ mwifiex_dbg(adapter, FATAL,
+ "info: FREE_CMD_BUF: cmd_pool is null\n");
return 0;
}
@@ -395,7 +405,8 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter)
/* Release shared memory buffers */
for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
if (cmd_array[i].skb) {
- dev_dbg(adapter->dev, "cmd: free cmd buffer %d\n", i);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: free cmd buffer %d\n", i);
dev_kfree_skb_any(cmd_array[i].skb);
}
if (!cmd_array[i].resp_skb)
@@ -409,7 +420,8 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter)
}
/* Release struct cmd_ctrl_node */
if (adapter->cmd_pool) {
- dev_dbg(adapter->dev, "cmd: free cmd pool\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: free cmd pool\n");
kfree(adapter->cmd_pool);
adapter->cmd_pool = NULL;
}
@@ -457,9 +469,11 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
memset(rx_info, 0, sizeof(*rx_info));
rx_info->bss_num = priv->bss_num;
rx_info->bss_type = priv->bss_type;
+ mwifiex_dbg_dump(adapter, EVT_D, "Event Buf:",
+ skb->data, skb->len);
}
- dev_dbg(adapter->dev, "EVENT: cause: %#x\n", eventcause);
+ mwifiex_dbg(adapter, EVENT, "EVENT: cause: %#x\n", eventcause);
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
ret = mwifiex_process_uap_event(priv);
@@ -498,28 +512,33 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
}
if (adapter->is_suspended) {
- dev_err(adapter->dev, "PREP_CMD: device in suspended state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: device in suspended state\n");
return -1;
}
if (adapter->hs_enabling && cmd_no != HostCmd_CMD_802_11_HS_CFG_ENH) {
- dev_err(adapter->dev, "PREP_CMD: host entering sleep state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: host entering sleep state\n");
return -1;
}
if (adapter->surprise_removed) {
- dev_err(adapter->dev, "PREP_CMD: card is removed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: card is removed\n");
return -1;
}
if (adapter->is_cmd_timedout) {
- dev_err(adapter->dev, "PREP_CMD: FW is in bad state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: FW is in bad state\n");
return -1;
}
if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) {
if (cmd_no != HostCmd_CMD_FUNC_INIT) {
- dev_err(adapter->dev, "PREP_CMD: FW in reset state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: FW in reset state\n");
return -1;
}
}
@@ -528,7 +547,8 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
cmd_node = mwifiex_get_cmd_node(adapter);
if (!cmd_node) {
- dev_err(adapter->dev, "PREP_CMD: no free cmd node\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: no free cmd node\n");
return -1;
}
@@ -536,7 +556,8 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf, sync);
if (!cmd_node->cmd_skb) {
- dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: no free cmd buf\n");
return -1;
}
@@ -554,6 +575,8 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
case HostCmd_CMD_UAP_BSS_START:
case HostCmd_CMD_UAP_BSS_STOP:
case HostCmd_CMD_UAP_STA_DEAUTH:
+ case HOST_CMD_APCMD_SYS_RESET:
+ case HOST_CMD_APCMD_STA_LIST:
ret = mwifiex_uap_prepare_cmd(priv, cmd_no, cmd_action,
cmd_oid, data_buf,
cmd_ptr);
@@ -571,7 +594,8 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
/* Return error, since the command preparation failed */
if (ret) {
- dev_err(adapter->dev, "PREP_CMD: cmd %#x preparation failed\n",
+ mwifiex_dbg(adapter, ERROR,
+ "PREP_CMD: cmd %#x preparation failed\n",
cmd_no);
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
return -1;
@@ -626,7 +650,8 @@ void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
atomic_dec(&adapter->cmd_pending);
- dev_dbg(adapter->dev, "cmd: FREE_CMD: cmd=%#x, cmd_pending=%d\n",
+ mwifiex_dbg(adapter, CMD,
+ "cmd: FREE_CMD: cmd=%#x, cmd_pending=%d\n",
le16_to_cpu(host_cmd->command),
atomic_read(&adapter->cmd_pending));
}
@@ -648,7 +673,7 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
if (!host_cmd) {
- dev_err(adapter->dev, "QUEUE_CMD: host_cmd is NULL\n");
+ mwifiex_dbg(adapter, ERROR, "QUEUE_CMD: host_cmd is NULL\n");
return;
}
@@ -673,7 +698,8 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
atomic_inc(&adapter->cmd_pending);
- dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x, cmd_pending=%d\n",
+ mwifiex_dbg(adapter, CMD,
+ "cmd: QUEUE_CMD: cmd=%#x, cmd_pending=%d\n",
command, atomic_read(&adapter->cmd_pending));
}
@@ -699,7 +725,8 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
/* Check if already in processing */
if (adapter->curr_cmd) {
- dev_err(adapter->dev, "EXEC_NEXT_CMD: cmd in processing\n");
+ mwifiex_dbg(adapter, FATAL,
+ "EXEC_NEXT_CMD: cmd in processing\n");
return -1;
}
@@ -721,8 +748,9 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
priv = cmd_node->priv;
if (adapter->ps_state != PS_STATE_AWAKE) {
- dev_err(adapter->dev, "%s: cannot send cmd in sleep state,"
- " this should not happen\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: cannot send cmd in sleep state,\t"
+ "this should not happen\n", __func__);
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
return ret;
}
@@ -772,8 +800,9 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) {
resp = (struct host_cmd_ds_command *) adapter->upld_buf;
- dev_err(adapter->dev, "CMD_RESP: NULL curr_cmd, %#x\n",
- le16_to_cpu(resp->command));
+ mwifiex_dbg(adapter, ERROR,
+ "CMD_RESP: NULL curr_cmd, %#x\n",
+ le16_to_cpu(resp->command));
return -1;
}
@@ -781,8 +810,9 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data;
if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
- dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n",
- le16_to_cpu(resp->command));
+ mwifiex_dbg(adapter, ERROR,
+ "CMD_RESP: %#x been canceled\n",
+ le16_to_cpu(resp->command));
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL;
@@ -794,7 +824,8 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
/* Copy original response back to response buffer */
struct mwifiex_ds_misc_cmd *hostcmd;
uint16_t size = le16_to_cpu(resp->size);
- dev_dbg(adapter->dev, "info: host cmd resp size = %d\n", size);
+ mwifiex_dbg(adapter, INFO,
+ "info: host cmd resp size = %d\n", size);
size = min_t(u16, size, MWIFIEX_SIZE_OF_CMD_BUFFER);
if (adapter->curr_cmd->data_buf) {
hostcmd = adapter->curr_cmd->data_buf;
@@ -822,13 +853,15 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] =
orig_cmdresp_no;
- dev_dbg(adapter->dev,
- "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n",
- orig_cmdresp_no, cmdresp_result,
- le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num));
+ mwifiex_dbg(adapter, CMD,
+ "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n",
+ orig_cmdresp_no, cmdresp_result,
+ le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num));
+ mwifiex_dbg_dump(adapter, CMD_D, "CMD_RESP buffer:", resp,
+ le16_to_cpu(resp->size));
if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
- dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n");
+ mwifiex_dbg(adapter, ERROR, "CMD_RESP: invalid cmd resp\n");
if (adapter->curr_cmd->wait_q_enabled)
adapter->cmd_wait_q.status = -1;
@@ -852,8 +885,9 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
/* Check init command response */
if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) {
if (ret) {
- dev_err(adapter->dev, "%s: cmd %#x failed during "
- "initialization\n", __func__, cmdresp_no);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: cmd %#x failed during\t"
+ "initialization\n", __func__, cmdresp_no);
mwifiex_init_fw_complete(adapter);
return -1;
} else if (adapter->last_init_cmd == cmdresp_no)
@@ -888,7 +922,8 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
adapter->is_cmd_timedout = 1;
if (!adapter->curr_cmd) {
- dev_dbg(adapter->dev, "cmd: empty curr_cmd\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cmd: empty curr_cmd\n");
return;
}
cmd_node = adapter->curr_cmd;
@@ -897,47 +932,60 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index];
adapter->dbg.timeout_cmd_act =
adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index];
- dev_err(adapter->dev,
- "%s: Timeout cmd id = %#x, act = %#x\n", __func__,
- adapter->dbg.timeout_cmd_id,
- adapter->dbg.timeout_cmd_act);
-
- dev_err(adapter->dev, "num_data_h2c_failure = %d\n",
- adapter->dbg.num_tx_host_to_card_failure);
- dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n",
- adapter->dbg.num_cmd_host_to_card_failure);
-
- dev_err(adapter->dev, "is_cmd_timedout = %d\n",
- adapter->is_cmd_timedout);
- dev_err(adapter->dev, "num_tx_timeout = %d\n",
- adapter->dbg.num_tx_timeout);
-
- dev_err(adapter->dev, "last_cmd_index = %d\n",
- adapter->dbg.last_cmd_index);
- dev_err(adapter->dev, "last_cmd_id: %*ph\n",
- (int)sizeof(adapter->dbg.last_cmd_id),
- adapter->dbg.last_cmd_id);
- dev_err(adapter->dev, "last_cmd_act: %*ph\n",
- (int)sizeof(adapter->dbg.last_cmd_act),
- adapter->dbg.last_cmd_act);
-
- dev_err(adapter->dev, "last_cmd_resp_index = %d\n",
- adapter->dbg.last_cmd_resp_index);
- dev_err(adapter->dev, "last_cmd_resp_id: %*ph\n",
- (int)sizeof(adapter->dbg.last_cmd_resp_id),
- adapter->dbg.last_cmd_resp_id);
-
- dev_err(adapter->dev, "last_event_index = %d\n",
- adapter->dbg.last_event_index);
- dev_err(adapter->dev, "last_event: %*ph\n",
- (int)sizeof(adapter->dbg.last_event),
- adapter->dbg.last_event);
-
- dev_err(adapter->dev, "data_sent=%d cmd_sent=%d\n",
- adapter->data_sent, adapter->cmd_sent);
-
- dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n",
- adapter->ps_mode, adapter->ps_state);
+ mwifiex_dbg(adapter, MSG,
+ "%s: Timeout cmd id = %#x, act = %#x\n", __func__,
+ adapter->dbg.timeout_cmd_id,
+ adapter->dbg.timeout_cmd_act);
+
+ mwifiex_dbg(adapter, MSG,
+ "num_data_h2c_failure = %d\n",
+ adapter->dbg.num_tx_host_to_card_failure);
+ mwifiex_dbg(adapter, MSG,
+ "num_cmd_h2c_failure = %d\n",
+ adapter->dbg.num_cmd_host_to_card_failure);
+
+ mwifiex_dbg(adapter, MSG,
+ "is_cmd_timedout = %d\n",
+ adapter->is_cmd_timedout);
+ mwifiex_dbg(adapter, MSG,
+ "num_tx_timeout = %d\n",
+ adapter->dbg.num_tx_timeout);
+
+ mwifiex_dbg(adapter, MSG,
+ "last_cmd_index = %d\n",
+ adapter->dbg.last_cmd_index);
+ mwifiex_dbg(adapter, MSG,
+ "last_cmd_id: %*ph\n",
+ (int)sizeof(adapter->dbg.last_cmd_id),
+ adapter->dbg.last_cmd_id);
+ mwifiex_dbg(adapter, MSG,
+ "last_cmd_act: %*ph\n",
+ (int)sizeof(adapter->dbg.last_cmd_act),
+ adapter->dbg.last_cmd_act);
+
+ mwifiex_dbg(adapter, MSG,
+ "last_cmd_resp_index = %d\n",
+ adapter->dbg.last_cmd_resp_index);
+ mwifiex_dbg(adapter, MSG,
+ "last_cmd_resp_id: %*ph\n",
+ (int)sizeof(adapter->dbg.last_cmd_resp_id),
+ adapter->dbg.last_cmd_resp_id);
+
+ mwifiex_dbg(adapter, MSG,
+ "last_event_index = %d\n",
+ adapter->dbg.last_event_index);
+ mwifiex_dbg(adapter, MSG,
+ "last_event: %*ph\n",
+ (int)sizeof(adapter->dbg.last_event),
+ adapter->dbg.last_event);
+
+ mwifiex_dbg(adapter, MSG,
+ "data_sent=%d cmd_sent=%d\n",
+ adapter->data_sent, adapter->cmd_sent);
+
+ mwifiex_dbg(adapter, MSG,
+ "ps_mode=%d ps_state=%d\n",
+ adapter->ps_mode, adapter->ps_state);
if (cmd_node->wait_q_enabled) {
adapter->cmd_wait_q.status = -ETIMEDOUT;
@@ -948,8 +996,8 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
mwifiex_init_fw_complete(adapter);
- if (adapter->if_ops.fw_dump)
- adapter->if_ops.fw_dump(adapter);
+ if (adapter->if_ops.device_dump)
+ adapter->if_ops.device_dump(adapter);
if (adapter->if_ops.card_reset)
adapter->if_ops.card_reset(adapter);
@@ -1015,7 +1063,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
if (!priv)
continue;
if (priv->scan_request) {
- dev_dbg(adapter->dev, "info: aborting scan\n");
+ mwifiex_dbg(adapter, WARN, "info: aborting scan\n");
cfg80211_scan_done(priv->scan_request, 1);
priv->scan_request = NULL;
}
@@ -1075,7 +1123,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
if (!priv)
continue;
if (priv->scan_request) {
- dev_dbg(adapter->dev, "info: aborting scan\n");
+ mwifiex_dbg(adapter, WARN, "info: aborting scan\n");
cfg80211_scan_done(priv->scan_request, 1);
priv->scan_request = NULL;
}
@@ -1100,11 +1148,11 @@ mwifiex_check_ps_cond(struct mwifiex_adapter *adapter)
!adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter))
mwifiex_dnld_sleep_confirm_cmd(adapter);
else
- dev_dbg(adapter->dev,
- "cmd: Delay Sleep Confirm (%s%s%s)\n",
- (adapter->cmd_sent) ? "D" : "",
- (adapter->curr_cmd) ? "C" : "",
- (IS_CARD_RX_RCVD(adapter)) ? "R" : "");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Delay Sleep Confirm (%s%s%s)\n",
+ (adapter->cmd_sent) ? "D" : "",
+ (adapter->curr_cmd) ? "C" : "",
+ (IS_CARD_RX_RCVD(adapter)) ? "R" : "");
}
/*
@@ -1120,15 +1168,18 @@ mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated)
priv->adapter->hs_activated = true;
mwifiex_update_rxreor_flags(priv->adapter,
RXREOR_FORCE_NO_DROP);
- dev_dbg(priv->adapter->dev, "event: hs_activated\n");
+ mwifiex_dbg(priv->adapter, EVENT,
+ "event: hs_activated\n");
priv->adapter->hs_activate_wait_q_woken = true;
wake_up_interruptible(
&priv->adapter->hs_activate_wait_q);
} else {
- dev_dbg(priv->adapter->dev, "event: HS not configured\n");
+ mwifiex_dbg(priv->adapter, EVENT,
+ "event: HS not configured\n");
}
} else {
- dev_dbg(priv->adapter->dev, "event: hs_deactivated\n");
+ mwifiex_dbg(priv->adapter, EVENT,
+ "event: hs_deactivated\n");
priv->adapter->hs_activated = false;
}
}
@@ -1156,11 +1207,12 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
mwifiex_hs_activated_event(priv, true);
return 0;
} else {
- dev_dbg(adapter->dev, "cmd: CMD_RESP: HS_CFG cmd reply"
- " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n",
- resp->result, conditions,
- phs_cfg->params.hs_config.gpio,
- phs_cfg->params.hs_config.gap);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: CMD_RESP: HS_CFG cmd reply\t"
+ " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n",
+ resp->result, conditions,
+ phs_cfg->params.hs_config.gpio,
+ phs_cfg->params.hs_config.gap);
}
if (conditions != HS_CFG_CANCEL) {
adapter->is_hs_configured = true;
@@ -1182,8 +1234,10 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
void
mwifiex_process_hs_config(struct mwifiex_adapter *adapter)
{
- dev_dbg(adapter->dev, "info: %s: auto cancelling host sleep"
- " since there is interrupt from the firmware\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: auto cancelling host sleep\t"
+ "since there is interrupt from the firmware\n",
+ __func__);
adapter->if_ops.wakeup(adapter);
adapter->hs_activated = false;
@@ -1212,13 +1266,14 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter,
uint16_t seq_num = le16_to_cpu(cmd->seq_num);
if (!upld_len) {
- dev_err(adapter->dev, "%s: cmd size is 0\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: cmd size is 0\n", __func__);
return;
}
- dev_dbg(adapter->dev,
- "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n",
- command, result, le16_to_cpu(cmd->size), seq_num);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n",
+ command, result, le16_to_cpu(cmd->size), seq_num);
/* Get BSS number and corresponding priv */
priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num),
@@ -1232,15 +1287,16 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter,
command &= HostCmd_CMD_ID_MASK;
if (command != HostCmd_CMD_802_11_PS_MODE_ENH) {
- dev_err(adapter->dev,
- "%s: rcvd unexpected resp for cmd %#x, result = %x\n",
- __func__, command, result);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: rcvd unexpected resp for cmd %#x, result = %x\n",
+ __func__, command, result);
return;
}
if (result) {
- dev_err(adapter->dev, "%s: sleep confirm cmd failed\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: sleep confirm cmd failed\n",
+ __func__);
adapter->pm_wakeup_card_req = false;
adapter->ps_state = PS_STATE_AWAKE;
return;
@@ -1305,7 +1361,8 @@ int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv,
sizeof(struct mwifiex_ie_types_header));
cmd_size += sizeof(*ps_tlv);
tlv += sizeof(*ps_tlv);
- dev_dbg(adapter->dev, "cmd: PS Command: Enter PS\n");
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: PS Command: Enter PS\n");
ps_mode->null_pkt_interval =
cpu_to_le16(adapter->null_pkt_interval);
ps_mode->multiple_dtims =
@@ -1335,8 +1392,8 @@ int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv,
tlv += sizeof(*auto_ds_tlv);
if (auto_ds)
idletime = auto_ds->idle_time;
- dev_dbg(priv->adapter->dev,
- "cmd: PS Command: Enter Auto Deep Sleep\n");
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: PS Command: Enter Auto Deep Sleep\n");
auto_ds_tlv->deep_sleep_timeout = cpu_to_le16(idletime);
}
cmd->size = cpu_to_le16(cmd_size);
@@ -1363,27 +1420,31 @@ int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv,
uint16_t auto_ps_bitmap =
le16_to_cpu(ps_mode->params.ps_bitmap);
- dev_dbg(adapter->dev,
- "info: %s: PS_MODE cmd reply result=%#x action=%#X\n",
- __func__, resp->result, action);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: PS_MODE cmd reply result=%#x action=%#X\n",
+ __func__, resp->result, action);
if (action == EN_AUTO_PS) {
if (auto_ps_bitmap & BITMAP_AUTO_DS) {
- dev_dbg(adapter->dev, "cmd: Enabled auto deep sleep\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Enabled auto deep sleep\n");
priv->adapter->is_deep_sleep = true;
}
if (auto_ps_bitmap & BITMAP_STA_PS) {
- dev_dbg(adapter->dev, "cmd: Enabled STA power save\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Enabled STA power save\n");
if (adapter->sleep_period.period)
- dev_dbg(adapter->dev,
- "cmd: set to uapsd/pps mode\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: set to uapsd/pps mode\n");
}
} else if (action == DIS_AUTO_PS) {
if (ps_bitmap & BITMAP_AUTO_DS) {
priv->adapter->is_deep_sleep = false;
- dev_dbg(adapter->dev, "cmd: Disabled auto deep sleep\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Disabled auto deep sleep\n");
}
if (ps_bitmap & BITMAP_STA_PS) {
- dev_dbg(adapter->dev, "cmd: Disabled STA power save\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Disabled STA power save\n");
if (adapter->sleep_period.period) {
adapter->delay_null_pkt = false;
adapter->tx_lock_flag = false;
@@ -1396,7 +1457,8 @@ int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv,
else
adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
- dev_dbg(adapter->dev, "cmd: ps_bitmap=%#x\n", ps_bitmap);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: ps_bitmap=%#x\n", ps_bitmap);
if (pm_cfg) {
/* This section is for get power save mode */
@@ -1533,29 +1595,29 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
api_rev->major_ver;
adapter->key_api_minor_ver =
api_rev->minor_ver;
- dev_dbg(adapter->dev,
- "key_api v%d.%d\n",
- adapter->key_api_major_ver,
- adapter->key_api_minor_ver);
+ mwifiex_dbg(adapter, INFO,
+ "key_api v%d.%d\n",
+ adapter->key_api_major_ver,
+ adapter->key_api_minor_ver);
break;
case FW_API_VER_ID:
adapter->fw_api_ver =
api_rev->major_ver;
- dev_dbg(adapter->dev,
- "Firmware api version %d\n",
- adapter->fw_api_ver);
+ mwifiex_dbg(adapter, INFO,
+ "Firmware api version %d\n",
+ adapter->fw_api_ver);
break;
default:
- dev_warn(adapter->dev,
- "Unknown api_id: %d\n",
- api_id);
+ mwifiex_dbg(adapter, FATAL,
+ "Unknown api_id: %d\n",
+ api_id);
break;
}
break;
default:
- dev_warn(adapter->dev,
- "Unknown GET_HW_SPEC TLV type: %#x\n",
- le16_to_cpu(tlv->type));
+ mwifiex_dbg(adapter, FATAL,
+ "Unknown GET_HW_SPEC TLV type: %#x\n",
+ le16_to_cpu(tlv->type));
break;
}
parsed_len += le16_to_cpu(tlv->len) +
@@ -1565,14 +1627,16 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
}
}
- dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n",
- adapter->fw_release_number);
- dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n",
- hw_spec->permanent_addr);
- dev_dbg(adapter->dev,
- "info: GET_HW_SPEC: hw_if_version=%#x version=%#x\n",
- le16_to_cpu(hw_spec->hw_if_version),
- le16_to_cpu(hw_spec->version));
+ mwifiex_dbg(adapter, INFO,
+ "info: GET_HW_SPEC: fw_release_number- %#x\n",
+ adapter->fw_release_number);
+ mwifiex_dbg(adapter, INFO,
+ "info: GET_HW_SPEC: permanent addr: %pM\n",
+ hw_spec->permanent_addr);
+ mwifiex_dbg(adapter, INFO,
+ "info: GET_HW_SPEC: hw_if_version=%#x version=%#x\n",
+ le16_to_cpu(hw_spec->hw_if_version),
+ le16_to_cpu(hw_spec->version));
ether_addr_copy(priv->adapter->perm_addr, hw_spec->permanent_addr);
adapter->region_code = le16_to_cpu(hw_spec->region_code);
@@ -1585,8 +1649,8 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
/* If it's unidentified region code, use the default (USA) */
if (i >= MWIFIEX_MAX_REGION_CODE) {
adapter->region_code = 0x10;
- dev_dbg(adapter->dev,
- "cmd: unknown region code, use default (USA)\n");
+ mwifiex_dbg(adapter, WARN,
+ "cmd: unknown region code, use default (USA)\n");
}
adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap);
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
index 1fb329dc6744..5a0636d43a1b 100644
--- a/drivers/net/wireless/mwifiex/debugfs.c
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -152,24 +152,24 @@ free_and_exit:
}
/*
- * Proc firmware dump read handler.
+ * Proc device dump read handler.
*
- * This function is called when the 'fw_dump' file is opened for
+ * This function is called when the 'device_dump' file is opened for
* reading.
- * This function dumps firmware memory in different files
- * (ex. DTCM, ITCM, SQRAM etc.) based on the the segments for
+ * This function dumps driver information and firmware memory segments
+ * (ex. DTCM, ITCM, SQRAM etc.) for
* debugging.
*/
static ssize_t
-mwifiex_fw_dump_read(struct file *file, char __user *ubuf,
- size_t count, loff_t *ppos)
+mwifiex_device_dump_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
{
struct mwifiex_private *priv = file->private_data;
- if (!priv->adapter->if_ops.fw_dump)
+ if (!priv->adapter->if_ops.device_dump)
return -EIO;
- priv->adapter->if_ops.fw_dump(priv->adapter);
+ priv->adapter->if_ops.device_dump(priv->adapter);
return 0;
}
@@ -535,6 +535,144 @@ done:
return ret;
}
+/* Proc debug_mask file read handler.
+ * This function is called when the 'debug_mask' file is opened for reading
+ * This function can be used read driver debugging mask value.
+ */
+static ssize_t
+mwifiex_debug_mask_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwifiex_private *priv =
+ (struct mwifiex_private *)file->private_data;
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)page;
+ size_t ret = 0;
+ int pos = 0;
+
+ if (!buf)
+ return -ENOMEM;
+
+ pos += snprintf(buf, PAGE_SIZE, "debug mask=0x%08x\n",
+ priv->adapter->debug_mask);
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
+
+ free_page(page);
+ return ret;
+}
+
+/* Proc debug_mask file read handler.
+ * This function is called when the 'debug_mask' file is opened for reading
+ * This function can be used read driver debugging mask value.
+ */
+static ssize_t
+mwifiex_debug_mask_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int ret;
+ unsigned long debug_mask;
+ struct mwifiex_private *priv = (void *)file->private_data;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (void *)addr;
+ size_t buf_size = min(count, (size_t)(PAGE_SIZE - 1));
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, ubuf, buf_size)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (kstrtoul(buf, 0, &debug_mask)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ priv->adapter->debug_mask = debug_mask;
+ ret = count;
+done:
+ free_page(addr);
+ return ret;
+}
+
+/* Proc memrw file write handler.
+ * This function is called when the 'memrw' file is opened for writing
+ * This function can be used to write to a memory location.
+ */
+static ssize_t
+mwifiex_memrw_write(struct file *file, const char __user *ubuf, size_t count,
+ loff_t *ppos)
+{
+ int ret;
+ char cmd;
+ struct mwifiex_ds_mem_rw mem_rw;
+ u16 cmd_action;
+ struct mwifiex_private *priv = (void *)file->private_data;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (void *)addr;
+ size_t buf_size = min(count, (size_t)(PAGE_SIZE - 1));
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, ubuf, buf_size)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value);
+ if (ret != 3) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((cmd == 'r') || (cmd == 'R')) {
+ cmd_action = HostCmd_ACT_GEN_GET;
+ mem_rw.value = 0;
+ } else if ((cmd == 'w') || (cmd == 'W')) {
+ cmd_action = HostCmd_ACT_GEN_SET;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw));
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0,
+ &mem_rw, true))
+ ret = -1;
+ else
+ ret = count;
+
+done:
+ free_page(addr);
+ return ret;
+}
+
+/* Proc memrw file read handler.
+ * This function is called when the 'memrw' file is opened for reading
+ * This function can be used to read from a memory location.
+ */
+static ssize_t
+mwifiex_memrw_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwifiex_private *priv = (void *)file->private_data;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ int ret, pos = 0;
+
+ if (!buf)
+ return -ENOMEM;
+
+ pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr,
+ priv->mem_rw.value);
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
+
+ free_page(addr);
+ return ret;
+}
+
static u32 saved_offset = -1, saved_bytes = -1;
/*
@@ -654,7 +792,8 @@ mwifiex_hscfg_write(struct file *file, const char __user *ubuf,
memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg));
if (arg_num > 3) {
- dev_err(priv->adapter->dev, "Too many arguments\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Too many arguments\n");
ret = -EINVAL;
goto done;
}
@@ -746,11 +885,13 @@ static const struct file_operations mwifiex_dfs_##name##_fops = { \
MWIFIEX_DFS_FILE_READ_OPS(info);
MWIFIEX_DFS_FILE_READ_OPS(debug);
MWIFIEX_DFS_FILE_READ_OPS(getlog);
-MWIFIEX_DFS_FILE_READ_OPS(fw_dump);
+MWIFIEX_DFS_FILE_READ_OPS(device_dump);
MWIFIEX_DFS_FILE_OPS(regrdwr);
MWIFIEX_DFS_FILE_OPS(rdeeprom);
+MWIFIEX_DFS_FILE_OPS(memrw);
MWIFIEX_DFS_FILE_OPS(hscfg);
MWIFIEX_DFS_FILE_OPS(histogram);
+MWIFIEX_DFS_FILE_OPS(debug_mask);
/*
* This function creates the debug FS directory structure and the files.
@@ -772,9 +913,11 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
MWIFIEX_DFS_ADD_FILE(getlog);
MWIFIEX_DFS_ADD_FILE(regrdwr);
MWIFIEX_DFS_ADD_FILE(rdeeprom);
- MWIFIEX_DFS_ADD_FILE(fw_dump);
+ MWIFIEX_DFS_ADD_FILE(device_dump);
+ MWIFIEX_DFS_ADD_FILE(memrw);
MWIFIEX_DFS_ADD_FILE(hscfg);
MWIFIEX_DFS_ADD_FILE(histogram);
+ MWIFIEX_DFS_ADD_FILE(debug_mask);
}
/*
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index 38f24e0427d2..51e344789ba2 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -29,7 +29,7 @@
#include <uapi/linux/if_arp.h>
#include <net/mac80211.h>
-
+#define MWIFIEX_BSS_COEX_COUNT 2
#define MWIFIEX_MAX_BSS_NUM (3)
#define MWIFIEX_DMA_ALIGN_SZ 64
@@ -49,7 +49,12 @@
#define MWIFIEX_STA_AMPDU_DEF_TXWINSIZE 64
#define MWIFIEX_STA_AMPDU_DEF_RXWINSIZE 64
+#define MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE 16
+
#define MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE 32
+
+#define MWIFIEX_UAP_COEX_AMPDU_DEF_RXWINSIZE 16
+
#define MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE 16
#define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE 64
#define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE 64
diff --git a/drivers/net/wireless/mwifiex/ethtool.c b/drivers/net/wireless/mwifiex/ethtool.c
index 65d8d6d4b6ba..58400c69ab26 100644
--- a/drivers/net/wireless/mwifiex/ethtool.c
+++ b/drivers/net/wireless/mwifiex/ethtool.c
@@ -64,104 +64,7 @@ static int mwifiex_ethtool_set_wol(struct net_device *dev,
return 0;
}
-static int
-mwifiex_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump)
-{
- struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- struct mwifiex_adapter *adapter = priv->adapter;
- struct memory_type_mapping *entry;
-
- if (!adapter->if_ops.fw_dump)
- return -ENOTSUPP;
-
- dump->flag = adapter->curr_mem_idx;
- dump->version = 1;
- if (adapter->curr_mem_idx == MWIFIEX_DRV_INFO_IDX) {
- dump->len = adapter->drv_info_size;
- } else if (adapter->curr_mem_idx != MWIFIEX_FW_DUMP_IDX) {
- entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx];
- dump->len = entry->mem_size;
- } else {
- dump->len = 0;
- }
-
- return 0;
-}
-
-static int
-mwifiex_get_dump_data(struct net_device *dev, struct ethtool_dump *dump,
- void *buffer)
-{
- u8 *p = buffer;
- struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- struct mwifiex_adapter *adapter = priv->adapter;
- struct memory_type_mapping *entry;
-
- if (!adapter->if_ops.fw_dump)
- return -ENOTSUPP;
-
- if (adapter->curr_mem_idx == MWIFIEX_DRV_INFO_IDX) {
- if (!adapter->drv_info_dump)
- return -EFAULT;
- memcpy(p, adapter->drv_info_dump, adapter->drv_info_size);
- return 0;
- }
-
- if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) {
- dev_err(adapter->dev, "firmware dump in progress!!\n");
- return -EBUSY;
- }
-
- entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx];
-
- if (!entry->mem_ptr)
- return -EFAULT;
-
- memcpy(p, entry->mem_ptr, entry->mem_size);
-
- entry->mem_size = 0;
- vfree(entry->mem_ptr);
- entry->mem_ptr = NULL;
-
- return 0;
-}
-
-static int mwifiex_set_dump(struct net_device *dev, struct ethtool_dump *val)
-{
- struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- struct mwifiex_adapter *adapter = priv->adapter;
-
- if (!adapter->if_ops.fw_dump)
- return -ENOTSUPP;
-
- if (val->flag == MWIFIEX_DRV_INFO_IDX) {
- adapter->curr_mem_idx = MWIFIEX_DRV_INFO_IDX;
- return 0;
- }
-
- if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) {
- dev_err(adapter->dev, "firmware dump in progress!!\n");
- return -EBUSY;
- }
-
- if (val->flag == MWIFIEX_FW_DUMP_IDX) {
- adapter->curr_mem_idx = val->flag;
- adapter->if_ops.fw_dump(adapter);
- return 0;
- }
-
- if (val->flag < 0 || val->flag >= adapter->num_mem_types)
- return -EINVAL;
-
- adapter->curr_mem_idx = val->flag;
-
- return 0;
-}
-
const struct ethtool_ops mwifiex_ethtool_ops = {
.get_wol = mwifiex_ethtool_get_wol,
.set_wol = mwifiex_ethtool_set_wol,
- .get_dump_flag = mwifiex_get_dump_flag,
- .get_dump_data = mwifiex_get_dump_data,
- .set_dump = mwifiex_set_dump,
};
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 59d8964dd0dc..cd09051710e6 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -128,6 +128,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_UAP_SSID 0x0000
#define TLV_TYPE_UAP_RATES 0x0001
+#define TLV_TYPE_PWR_CONSTRAINT 0x0020
#define PROPRIETARY_TLV_BASE_ID 0x0100
#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
@@ -174,6 +175,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_SCAN_CHANNEL_GAP (PROPRIETARY_TLV_BASE_ID + 197)
#define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199)
#define TLV_TYPE_CHANNEL_STATS (PROPRIETARY_TLV_BASE_ID + 198)
+#define TLV_BTCOEX_WL_AGGR_WINSIZE (PROPRIETARY_TLV_BASE_ID + 202)
+#define TLV_BTCOEX_WL_SCANTIME (PROPRIETARY_TLV_BASE_ID + 203)
#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
@@ -323,15 +326,18 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075
#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f
#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
+#define HostCmd_CMD_MEM_ACCESS 0x0086
#define HostCmd_CMD_CFG_DATA 0x008f
#define HostCmd_CMD_VERSION_EXT 0x0097
#define HostCmd_CMD_MEF_CFG 0x009a
#define HostCmd_CMD_RSSI_INFO 0x00a4
#define HostCmd_CMD_FUNC_INIT 0x00a9
#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
+#define HOST_CMD_APCMD_SYS_RESET 0x00af
#define HostCmd_CMD_UAP_SYS_CONFIG 0x00b0
#define HostCmd_CMD_UAP_BSS_START 0x00b1
#define HostCmd_CMD_UAP_BSS_STOP 0x00b2
+#define HOST_CMD_APCMD_STA_LIST 0x00b3
#define HostCmd_CMD_UAP_STA_DEAUTH 0x00b5
#define HostCmd_CMD_11N_CFG 0x00cd
#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce
@@ -418,8 +424,12 @@ enum P2P_MODES {
#define HS_CFG_COND_MAC_EVENT 0x00000004
#define HS_CFG_COND_MULTICAST_DATA 0x00000008
-#define MWIFIEX_TIMEOUT_FOR_AP_RESP 0xfffc
-#define MWIFIEX_STATUS_CODE_AUTH_TIMEOUT 2
+#define CONNECT_ERR_AUTH_ERR_STA_FAILURE 0xFFFB
+#define CONNECT_ERR_ASSOC_ERR_TIMEOUT 0xFFFC
+#define CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED 0xFFFD
+#define CONNECT_ERR_AUTH_MSG_UNHANDLED 0xFFFE
+#define CONNECT_ERR_STA_FAILURE 0xFFFF
+
#define CMD_F_HOSTCMD (1 << 0)
#define CMD_F_CANCELED (1 << 1)
@@ -502,6 +512,7 @@ enum P2P_MODES {
#define EVENT_EXT_SCAN_REPORT 0x00000058
#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f
#define EVENT_TX_STATUS_REPORT 0x00000074
+#define EVENT_BT_COEX_WLAN_PARA_CHANGE 0X00000076
#define EVENT_ID_MASK 0xffff
#define BSS_NUM_MASK 0xf
@@ -626,7 +637,12 @@ struct uap_rxpd {
__le16 rx_pkt_type;
__le16 seq_num;
u8 priority;
- u8 reserved1;
+ u8 rx_rate;
+ s8 snr;
+ s8 nf;
+ u8 ht_info;
+ u8 reserved[3];
+ u8 flags;
};
struct mwifiex_fw_chan_stats {
@@ -1150,6 +1166,13 @@ enum SNMP_MIB_INDEX {
DOT11H_I = 10,
};
+enum mwifiex_assocmd_failurepoint {
+ MWIFIEX_ASSOC_CMD_SUCCESS = 0,
+ MWIFIEX_ASSOC_CMD_FAILURE_ASSOC,
+ MWIFIEX_ASSOC_CMD_FAILURE_AUTH,
+ MWIFIEX_ASSOC_CMD_FAILURE_JOIN
+};
+
#define MAX_SNMP_BUF_SIZE 128
struct host_cmd_ds_802_11_snmp_mib {
@@ -1447,6 +1470,18 @@ struct host_cmd_ds_sta_deauth {
__le16 reason;
} __packed;
+struct mwifiex_ie_types_sta_info {
+ struct mwifiex_ie_types_header header;
+ u8 mac[ETH_ALEN];
+ u8 power_mfg_status;
+ s8 rssi;
+};
+
+struct host_cmd_ds_sta_list {
+ u16 sta_count;
+ u8 tlv[0];
+} __packed;
+
struct mwifiex_ie_types_pwr_capability {
struct mwifiex_ie_types_header header;
s8 min_pwr;
@@ -1576,6 +1611,13 @@ struct mwifiex_ie_types_extcap {
u8 ext_capab[0];
} __packed;
+struct host_cmd_ds_mem_access {
+ __le16 action;
+ __le16 reserved;
+ __le32 addr;
+ __le32 value;
+};
+
struct mwifiex_ie_types_qos_info {
struct mwifiex_ie_types_header header;
u8 qos_info;
@@ -1742,6 +1784,27 @@ struct host_cmd_tlv_ageout_timer {
__le32 sta_ao_timer;
} __packed;
+struct host_cmd_tlv_power_constraint {
+ struct mwifiex_ie_types_header header;
+ u8 constraint;
+} __packed;
+
+struct mwifiex_ie_types_btcoex_scan_time {
+ struct mwifiex_ie_types_header header;
+ u8 coex_scan;
+ u8 reserved;
+ u16 min_scan_time;
+ u16 max_scan_time;
+} __packed;
+
+struct mwifiex_ie_types_btcoex_aggr_win_size {
+ struct mwifiex_ie_types_header header;
+ u8 coex_win_size;
+ u8 tx_win_size;
+ u8 rx_win_size;
+ u8 reserved;
+} __packed;
+
struct host_cmd_ds_version_ext {
u8 version_str_sel;
char version_str[128];
@@ -1958,6 +2021,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_p2p_mode_cfg mode_cfg;
struct host_cmd_ds_802_11_ibss_status ibss_coalescing;
struct host_cmd_ds_mef_cfg mef_cfg;
+ struct host_cmd_ds_mem_access mem;
struct host_cmd_ds_mac_reg_access mac_reg;
struct host_cmd_ds_bbp_reg_access bbp_reg;
struct host_cmd_ds_rf_reg_access rf_reg;
@@ -1968,6 +2032,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_802_11_subsc_evt subsc_evt;
struct host_cmd_ds_sys_config uap_sys_config;
struct host_cmd_ds_sta_deauth sta_deauth;
+ struct host_cmd_ds_sta_list sta_list;
struct host_cmd_11ac_vht_cfg vht_cfg;
struct host_cmd_ds_coalesce_cfg coalesce_cfg;
struct host_cmd_ds_tdls_oper tdls_oper;
diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c
index f3b6ed249403..0ba894509413 100644
--- a/drivers/net/wireless/mwifiex/ie.c
+++ b/drivers/net/wireless/mwifiex/ie.c
@@ -320,63 +320,81 @@ done:
/* This function parses head and tail IEs, from cfg80211_beacon_data and sets
* these IE to FW.
*/
-static int mwifiex_uap_set_head_tail_ies(struct mwifiex_private *priv,
- struct cfg80211_beacon_data *info)
+static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
+ struct cfg80211_beacon_data *info)
{
struct mwifiex_ie *gen_ie;
- struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL;
- struct ieee_types_header *chsw_ie = NULL;
+ struct ieee_types_header *hdr;
+ struct ieee80211_vendor_ie *vendorhdr;
u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
- const u8 *vendor_ie;
+ int left_len, parsed_len = 0;
+
+ if (!info->tail || !info->tail_len)
+ return 0;
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) {
- memcpy(gen_ie->ie_buffer, rsn_ie, rsn_ie->len + 2);
- ie_len = rsn_ie->len + 2;
- gen_ie->ie_length = cpu_to_le16(ie_len);
+ left_len = info->tail_len;
+
+ /* Many IEs are generated in FW by parsing bss configuration.
+ * Let's not add them here; else we may end up duplicating these IEs
+ */
+ while (left_len > sizeof(struct ieee_types_header)) {
+ hdr = (void *)(info->tail + parsed_len);
+ switch (hdr->element_id) {
+ case WLAN_EID_SSID:
+ case WLAN_EID_SUPP_RATES:
+ case WLAN_EID_COUNTRY:
+ case WLAN_EID_PWR_CONSTRAINT:
+ case WLAN_EID_EXT_SUPP_RATES:
+ case WLAN_EID_HT_CAPABILITY:
+ case WLAN_EID_HT_OPERATION:
+ case WLAN_EID_VHT_CAPABILITY:
+ case WLAN_EID_VHT_OPERATION:
+ case WLAN_EID_VENDOR_SPECIFIC:
+ break;
+ default:
+ memcpy(gen_ie->ie_buffer + ie_len, hdr,
+ hdr->len + sizeof(struct ieee_types_header));
+ ie_len += hdr->len + sizeof(struct ieee_types_header);
+ break;
}
+ left_len -= hdr->len + sizeof(struct ieee_types_header);
+ parsed_len += hdr->len + sizeof(struct ieee_types_header);
+ }
- vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+ /* parse only WPA vendor IE from tail, WMM IE is configured by
+ * bss_config command
+ */
+ vendorhdr = (void *)cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
WLAN_OUI_TYPE_MICROSOFT_WPA,
- info->tail,
- info->tail_len);
- if (vendor_ie) {
- wpa_ie = (struct ieee_types_header *)vendor_ie;
- memcpy(gen_ie->ie_buffer + ie_len,
- wpa_ie, wpa_ie->len + 2);
- ie_len += wpa_ie->len + 2;
- gen_ie->ie_length = cpu_to_le16(ie_len);
- }
+ info->tail, info->tail_len);
+ if (vendorhdr) {
+ memcpy(gen_ie->ie_buffer + ie_len, vendorhdr,
+ vendorhdr->len + sizeof(struct ieee_types_header));
+ ie_len += vendorhdr->len + sizeof(struct ieee_types_header);
+ }
- 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);
- }
+ if (!ie_len) {
+ kfree(gen_ie);
+ return 0;
}
- 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;
+ 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);
+ gen_ie->ie_length = cpu_to_le16(ie_len);
+
+ 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;
}
@@ -390,7 +408,7 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
{
int ret;
- ret = mwifiex_uap_set_head_tail_ies(priv, info);
+ ret = mwifiex_uap_parse_tail_ies(priv, info);
return ret;
return mwifiex_set_mgmt_beacon_data_ies(priv, info);
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index e12192f5cfad..df7fdc09d38c 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -56,7 +56,7 @@ static void wakeup_timer_fn(unsigned long data)
{
struct mwifiex_adapter *adapter = (struct mwifiex_adapter *)data;
- dev_err(adapter->dev, "Firmware wakeup failed\n");
+ mwifiex_dbg(adapter, ERROR, "Firmware wakeup failed\n");
adapter->hw_status = MWIFIEX_HW_STATUS_RESET;
mwifiex_cancel_all_pending_cmd(adapter);
@@ -172,8 +172,9 @@ static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter)
/* Allocate command buffer */
ret = mwifiex_alloc_cmd_buffer(adapter);
if (ret) {
- dev_err(adapter->dev, "%s: failed to alloc cmd buffer\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to alloc cmd buffer\n",
+ __func__);
return -1;
}
@@ -182,8 +183,9 @@ static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter)
+ INTF_HEADER_LEN);
if (!adapter->sleep_cfm) {
- dev_err(adapter->dev, "%s: failed to alloc sleep cfm"
- " cmd buffer\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to alloc sleep cfm\t"
+ " cmd buffer\n", __func__);
return -1;
}
skb_reserve(adapter->sleep_cfm, INTF_HEADER_LEN);
@@ -417,7 +419,7 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
mwifiex_free_lock_list(adapter);
/* Free command buffer */
- dev_dbg(adapter->dev, "info: free cmd buffer\n");
+ mwifiex_dbg(adapter, INFO, "info: free cmd buffer\n");
mwifiex_free_cmd_buffer(adapter);
for (idx = 0; idx < adapter->num_mem_types; idx++) {
@@ -433,6 +435,7 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
if (adapter->drv_info_dump) {
vfree(adapter->drv_info_dump);
+ adapter->drv_info_dump = NULL;
adapter->drv_info_size = 0;
}
@@ -595,10 +598,11 @@ static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
for (i = 0; i < adapter->priv_num; ++i) {
head = &adapter->bss_prio_tbl[i].bss_prio_head;
lock = &adapter->bss_prio_tbl[i].bss_prio_lock;
- dev_dbg(adapter->dev, "info: delete BSS priority table,"
- " bss_type = %d, bss_num = %d, i = %d,"
- " head = %p\n",
- priv->bss_type, priv->bss_num, i, head);
+ mwifiex_dbg(adapter, INFO,
+ "info: delete BSS priority table,\t"
+ "bss_type = %d, bss_num = %d, i = %d,\t"
+ "head = %p\n",
+ priv->bss_type, priv->bss_num, i, head);
{
spin_lock_irqsave(lock, flags);
@@ -609,9 +613,10 @@ static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
list_for_each_entry_safe(bssprio_node, tmp_node, head,
list) {
if (bssprio_node->priv == priv) {
- dev_dbg(adapter->dev, "info: Delete "
- "node %p, next = %p\n",
- bssprio_node, tmp_node);
+ mwifiex_dbg(adapter, INFO,
+ "info: Delete\t"
+ "node %p, next = %p\n",
+ bssprio_node, tmp_node);
list_del(&bssprio_node->list);
kfree(bssprio_node);
}
@@ -659,20 +664,23 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
adapter->hw_status = MWIFIEX_HW_STATUS_CLOSING;
/* wait for mwifiex_process to complete */
if (adapter->mwifiex_processing) {
- dev_warn(adapter->dev, "main process is still running\n");
+ mwifiex_dbg(adapter, WARN,
+ "main process is still running\n");
return ret;
}
/* cancel current command */
if (adapter->curr_cmd) {
- dev_warn(adapter->dev, "curr_cmd is still in processing\n");
+ mwifiex_dbg(adapter, WARN,
+ "curr_cmd is still in processing\n");
del_timer_sync(&adapter->cmd_timer);
mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
adapter->curr_cmd = NULL;
}
/* shut down mwifiex */
- dev_dbg(adapter->dev, "info: shutdown mwifiex...\n");
+ mwifiex_dbg(adapter, MSG,
+ "info: shutdown mwifiex...\n");
/* Clean up Tx/Rx queues and delete BSS priority table */
for (i = 0; i < adapter->priv_num; i++) {
@@ -741,8 +749,8 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
/* check if firmware is already running */
ret = adapter->if_ops.check_fw_status(adapter, poll_num);
if (!ret) {
- dev_notice(adapter->dev,
- "WLAN FW already running! Skip FW dnld\n");
+ mwifiex_dbg(adapter, MSG,
+ "WLAN FW already running! Skip FW dnld\n");
return 0;
}
@@ -750,8 +758,8 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
/* check if we are the winner for downloading FW */
if (!adapter->winner) {
- dev_notice(adapter->dev,
- "FW already running! Skip FW dnld\n");
+ mwifiex_dbg(adapter, MSG,
+ "FW already running! Skip FW dnld\n");
goto poll_fw;
}
}
@@ -760,7 +768,8 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
/* Download firmware with helper */
ret = adapter->if_ops.prog_fw(adapter, pmfw);
if (ret) {
- dev_err(adapter->dev, "prog_fw failed ret=%#x\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "prog_fw failed ret=%#x\n", ret);
return ret;
}
}
@@ -769,7 +778,8 @@ poll_fw:
/* Check if the firmware is downloaded successfully or not */
ret = adapter->if_ops.check_fw_status(adapter, poll_num);
if (ret)
- dev_err(adapter->dev, "FW failed to be active in time\n");
+ mwifiex_dbg(adapter, ERROR,
+ "FW failed to be active in time\n");
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index d2b05c3a96da..4f0174c64946 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -113,6 +113,7 @@ struct mwifiex_uap_bss_param {
u32 sta_ao_timer;
u32 ps_sta_ao_timer;
u8 qos_info;
+ u8 power_constraint;
struct mwifiex_types_wmm_info wmm_info;
};
@@ -189,6 +190,7 @@ struct tdls_peer_info {
};
struct mwifiex_debug_info {
+ unsigned int debug_mask;
u32 int_counter;
u32 packets_out[MAX_NUM_TID];
u32 tx_buf_size;
@@ -342,6 +344,11 @@ struct mwifiex_ds_read_eeprom {
u8 value[MAX_EEPROM_DATA];
};
+struct mwifiex_ds_mem_rw {
+ u32 addr;
+ u32 value;
+};
+
#define IEEE_MAX_IE_SIZE 256
#define MWIFIEX_IE_HDR_SIZE (sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE)
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 411a6c2f4aca..56b024a6aaa5 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -53,9 +53,9 @@ mwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer)
* parameter buffer pointer.
*/
if (priv->gen_ie_buf_len) {
- dev_dbg(priv->adapter->dev,
- "info: %s: append generic ie len %d to %p\n",
- __func__, priv->gen_ie_buf_len, *buffer);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: %s: append generic ie len %d to %p\n",
+ __func__, priv->gen_ie_buf_len, *buffer);
/* Wrap the generic IE buffer with a pass through TLV type */
ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
@@ -125,9 +125,9 @@ mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer,
tsf_val = cpu_to_le64(bss_desc->timestamp);
- dev_dbg(priv->adapter->dev,
- "info: %s: TSF offset calc: %016llx - %016llx\n",
- __func__, bss_desc->timestamp, bss_desc->fw_tsf);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: %s: TSF offset calc: %016llx - %016llx\n",
+ __func__, bss_desc->timestamp, bss_desc->fw_tsf);
memcpy(*buffer, &tsf_val, sizeof(tsf_val));
*buffer += sizeof(tsf_val);
@@ -152,7 +152,7 @@ static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
tmp = kmemdup(rate1, rate1_size, GFP_KERNEL);
if (!tmp) {
- dev_err(priv->adapter->dev, "failed to alloc tmp buf\n");
+ mwifiex_dbg(priv->adapter, ERROR, "failed to alloc tmp buf\n");
return -ENOMEM;
}
@@ -169,8 +169,8 @@ static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
}
}
- dev_dbg(priv->adapter->dev, "info: Tx data rate set to %#x\n",
- priv->data_rate);
+ mwifiex_dbg(priv->adapter, INFO, "info: Tx data rate set to %#x\n",
+ priv->data_rate);
if (!priv->is_data_rate_auto) {
while (*ptr) {
@@ -180,9 +180,10 @@ static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
}
ptr++;
}
- dev_err(priv->adapter->dev, "previously set fixed data rate %#x"
- " is not compatible with the network\n",
- priv->data_rate);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "previously set fixed data rate %#x\t"
+ "is not compatible with the network\n",
+ priv->data_rate);
ret = -1;
goto done;
@@ -214,8 +215,9 @@ mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv,
if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES,
card_rates, card_rates_size)) {
*out_rates_size = 0;
- dev_err(priv->adapter->dev, "%s: cannot get common rates\n",
- __func__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: cannot get common rates\n",
+ __func__);
return -1;
}
@@ -246,8 +248,9 @@ mwifiex_cmd_append_wps_ie(struct mwifiex_private *priv, u8 **buffer)
* parameter buffer pointer.
*/
if (priv->wps_ie_len) {
- dev_dbg(priv->adapter->dev, "cmd: append wps ie %d to %p\n",
- priv->wps_ie_len, *buffer);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: append wps ie %d to %p\n",
+ priv->wps_ie_len, *buffer);
/* Wrap the generic IE buffer with a pass through TLV type */
ie_header.type = cpu_to_le16(TLV_TYPE_MGMT_IE);
@@ -292,8 +295,9 @@ mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer)
* parameter buffer pointer.
*/
if (priv->wapi_ie_len) {
- dev_dbg(priv->adapter->dev, "cmd: append wapi ie %d to %p\n",
- priv->wapi_ie_len, *buffer);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: append wapi ie %d to %p\n",
+ priv->wapi_ie_len, *buffer);
/* Wrap the generic IE buffer with a pass through TLV type */
ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE);
@@ -453,8 +457,8 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
rates_tlv->header.len = cpu_to_le16((u16) rates_size);
memcpy(rates_tlv->rates, rates, rates_size);
pos += sizeof(rates_tlv->header) + rates_size;
- dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n",
- rates_size);
+ mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_CMD: rates size = %d\n",
+ rates_size);
/* Add the Authentication type to be used for Auth frames */
auth_tlv = (struct mwifiex_ie_types_auth_type *) pos;
@@ -487,14 +491,14 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
sizeof(struct mwifiex_chan_scan_param_set));
chan_tlv->chan_scan_param[0].chan_number =
(bss_desc->phy_param_set.ds_param_set.current_chan);
- dev_dbg(priv->adapter->dev, "info: Assoc: TLV Chan = %d\n",
- chan_tlv->chan_scan_param[0].chan_number);
+ mwifiex_dbg(priv->adapter, INFO, "info: Assoc: TLV Chan = %d\n",
+ chan_tlv->chan_scan_param[0].chan_number);
chan_tlv->chan_scan_param[0].radio_type =
mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
- dev_dbg(priv->adapter->dev, "info: Assoc: TLV Band = %d\n",
- chan_tlv->chan_scan_param[0].radio_type);
+ mwifiex_dbg(priv->adapter, INFO, "info: Assoc: TLV Band = %d\n",
+ chan_tlv->chan_scan_param[0].radio_type);
pos += sizeof(chan_tlv->header) +
sizeof(struct mwifiex_chan_scan_param_set);
}
@@ -544,13 +548,31 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
tmp_cap &= CAPINFO_MASK;
- dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
- tmp_cap, CAPINFO_MASK);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
+ tmp_cap, CAPINFO_MASK);
assoc->cap_info_bitmap = cpu_to_le16(tmp_cap);
return 0;
}
+static const char *assoc_failure_reason_to_str(u16 cap_info)
+{
+ switch (cap_info) {
+ case CONNECT_ERR_AUTH_ERR_STA_FAILURE:
+ return "CONNECT_ERR_AUTH_ERR_STA_FAILURE";
+ case CONNECT_ERR_AUTH_MSG_UNHANDLED:
+ return "CONNECT_ERR_AUTH_MSG_UNHANDLED";
+ case CONNECT_ERR_ASSOC_ERR_TIMEOUT:
+ return "CONNECT_ERR_ASSOC_ERR_TIMEOUT";
+ case CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED:
+ return "CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED";
+ case CONNECT_ERR_STA_FAILURE:
+ return "CONNECT_ERR_STA_FAILURE";
+ }
+
+ return "Unknown connect failure";
+}
/*
* Association firmware command response handler
*
@@ -621,29 +643,48 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
struct ieee_types_assoc_rsp *assoc_rsp;
struct mwifiex_bssdescriptor *bss_desc;
bool enable_data = true;
- u16 cap_info, status_code;
+ u16 cap_info, status_code, aid;
assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap);
status_code = le16_to_cpu(assoc_rsp->status_code);
+ aid = le16_to_cpu(assoc_rsp->a_id);
+
+ if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
+ dev_err(priv->adapter->dev,
+ "invalid AID value 0x%x; bits 15:14 not set\n",
+ aid);
+
+ aid &= ~(BIT(15) | BIT(14));
priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN,
sizeof(priv->assoc_rsp_buf));
memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
+ assoc_rsp->a_id = cpu_to_le16(aid);
+
if (status_code) {
priv->adapter->dbg.num_cmd_assoc_failure++;
- dev_err(priv->adapter->dev,
- "ASSOC_RESP: failed, status code=%d err=%#x a_id=%#x\n",
- status_code, cap_info, le16_to_cpu(assoc_rsp->a_id));
-
- if (cap_info == MWIFIEX_TIMEOUT_FOR_AP_RESP) {
- if (status_code == MWIFIEX_STATUS_CODE_AUTH_TIMEOUT)
+ mwifiex_dbg(priv->adapter, ERROR,
+ "ASSOC_RESP: failed,\t"
+ "status code=%d err=%#x a_id=%#x\n",
+ status_code, cap_info,
+ le16_to_cpu(assoc_rsp->a_id));
+
+ mwifiex_dbg(priv->adapter, ERROR, "assoc failure: reason %s\n",
+ assoc_failure_reason_to_str(cap_info));
+ if (cap_info == CONNECT_ERR_ASSOC_ERR_TIMEOUT) {
+ if (status_code == MWIFIEX_ASSOC_CMD_FAILURE_AUTH) {
ret = WLAN_STATUS_AUTH_TIMEOUT;
- else
+ mwifiex_dbg(priv->adapter, ERROR,
+ "ASSOC_RESP: AUTH timeout\n");
+ } else {
ret = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ mwifiex_dbg(priv->adapter, ERROR,
+ "ASSOC_RESP: UNSPECIFIED failure\n");
+ }
} else {
ret = status_code;
}
@@ -661,8 +702,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
/* Set the attempted BSSID Index to current */
bss_desc = priv->attempted_bss_desc;
- dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: %s\n",
- bss_desc->ssid.ssid);
+ mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: %s\n",
+ bss_desc->ssid.ssid);
/* Make a copy of current BSSID descriptor */
memcpy(&priv->curr_bss_params.bss_descriptor,
@@ -692,8 +733,9 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
= ((bss_desc->wmm_ie.qos_info_bitmap &
IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0);
- dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: curr_pkt_filter is %#x\n",
- priv->curr_pkt_filter);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ASSOC_RESP: curr_pkt_filter is %#x\n",
+ priv->curr_pkt_filter);
if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
priv->wpa_is_gtk_set = false;
@@ -709,8 +751,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
}
if (enable_data)
- dev_dbg(priv->adapter->dev,
- "info: post association, re-enabling data flow\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: post association, re-enabling data flow\n");
/* Reset SNR/NF/RSSI values */
priv->data_rssi_last = 0;
@@ -728,7 +770,7 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
priv->adapter->dbg.num_cmd_assoc_success++;
- dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: associated\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: associated\n");
/* Add the ra_list here for infra mode as there will be only 1 ra
always */
@@ -815,8 +857,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
memcpy(adhoc_start->ssid, req_ssid->ssid, req_ssid->ssid_len);
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n",
- adhoc_start->ssid);
+ mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: SSID = %s\n",
+ adhoc_start->ssid);
memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN);
memcpy(bss_desc->ssid.ssid, req_ssid->ssid, req_ssid->ssid_len);
@@ -848,12 +890,14 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
}
if (!priv->adhoc_channel) {
- dev_err(adapter->dev, "ADHOC_S_CMD: adhoc_channel cannot be 0\n");
+ mwifiex_dbg(adapter, ERROR,
+ "ADHOC_S_CMD: adhoc_channel cannot be 0\n");
return -1;
}
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: creating ADHOC on channel %d\n",
- priv->adhoc_channel);
+ mwifiex_dbg(adapter, INFO,
+ "info: ADHOC_S_CMD: creating ADHOC on channel %d\n",
+ priv->adhoc_channel);
priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel;
priv->curr_bss_params.band = adapter->adhoc_start_band;
@@ -885,13 +929,14 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
/* Set up privacy in bss_desc */
if (priv->sec_info.encryption_mode) {
/* Ad-Hoc capability privacy on */
- dev_dbg(adapter->dev,
- "info: ADHOC_S_CMD: wep_status set privacy to WEP\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: ADHOC_S_CMD: wep_status set privacy to WEP\n");
bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
tmp_cap |= WLAN_CAPABILITY_PRIVACY;
} else {
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status NOT set,"
- " setting privacy to ACCEPT ALL\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: ADHOC_S_CMD: wep_status NOT set,\t"
+ "setting privacy to ACCEPT ALL\n");
bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
}
@@ -902,8 +947,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
HostCmd_ACT_GEN_SET, 0,
&priv->curr_pkt_filter, false)) {
- dev_err(adapter->dev,
- "ADHOC_S_CMD: G Protection config failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "ADHOC_S_CMD: G Protection config failed\n");
return -1;
}
}
@@ -918,10 +963,10 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
memcpy(&priv->curr_bss_params.data_rates,
&adhoc_start->data_rate, priv->curr_bss_params.num_of_rates);
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%4ph\n",
- adhoc_start->data_rate);
+ mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: rates=%4ph\n",
+ adhoc_start->data_rate);
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
+ mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
if (IS_SUPPORT_MULTI_BANDS(adapter)) {
/* Append a channel TLV */
@@ -935,8 +980,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
chan_tlv->chan_scan_param[0].chan_number =
(u8) priv->curr_bss_params.bss_descriptor.channel;
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Chan = %d\n",
- chan_tlv->chan_scan_param[0].chan_number);
+ mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Chan = %d\n",
+ chan_tlv->chan_scan_param[0].chan_number);
chan_tlv->chan_scan_param[0].radio_type
= mwifiex_band_to_radio_type(priv->curr_bss_params.band);
@@ -951,8 +996,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
chan_tlv->chan_scan_param[0].radio_type |=
(IEEE80211_HT_PARAM_CHA_SEC_BELOW << 4);
}
- dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Band = %d\n",
- chan_tlv->chan_scan_param[0].radio_type);
+ mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Band = %d\n",
+ chan_tlv->chan_scan_param[0].radio_type);
pos += sizeof(chan_tlv->header) +
sizeof(struct mwifiex_chan_scan_param_set);
cmd_append_size +=
@@ -1074,8 +1119,8 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
HostCmd_ACT_GEN_SET, 0,
&curr_pkt_filter, false)) {
- dev_err(priv->adapter->dev,
- "ADHOC_J_CMD: G Protection config failed\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "ADHOC_J_CMD: G Protection config failed\n");
return -1;
}
}
@@ -1106,14 +1151,15 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
tmp_cap &= CAPINFO_MASK;
- dev_dbg(priv->adapter->dev,
- "info: ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
- tmp_cap, CAPINFO_MASK);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
+ tmp_cap, CAPINFO_MASK);
/* Information on BSSID descriptor passed to FW */
- dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: BSSID=%pM, SSID='%s'\n",
- adhoc_join->bss_descriptor.bssid,
- adhoc_join->bss_descriptor.ssid);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ADHOC_J_CMD: BSSID=%pM, SSID='%s'\n",
+ adhoc_join->bss_descriptor.bssid,
+ adhoc_join->bss_descriptor.ssid);
for (i = 0; i < MWIFIEX_SUPPORTED_RATES &&
bss_desc->supported_rates[i]; i++)
@@ -1149,14 +1195,14 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
sizeof(struct mwifiex_chan_scan_param_set));
chan_tlv->chan_scan_param[0].chan_number =
(bss_desc->phy_param_set.ds_param_set.current_chan);
- dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Chan=%d\n",
- chan_tlv->chan_scan_param[0].chan_number);
+ mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Chan=%d\n",
+ chan_tlv->chan_scan_param[0].chan_number);
chan_tlv->chan_scan_param[0].radio_type =
mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
- dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Band=%d\n",
- chan_tlv->chan_scan_param[0].radio_type);
+ mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Band=%d\n",
+ chan_tlv->chan_scan_param[0].radio_type);
pos += sizeof(chan_tlv->header) +
sizeof(struct mwifiex_chan_scan_param_set);
cmd_append_size += sizeof(chan_tlv->header) +
@@ -1210,7 +1256,7 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
/* Join result code 0 --> SUCCESS */
reason_code = le16_to_cpu(resp->result);
if (reason_code) {
- dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n");
+ mwifiex_dbg(priv->adapter, ERROR, "ADHOC_RESP: failed\n");
if (priv->media_connected)
mwifiex_reset_connect_state(priv, reason_code);
@@ -1225,8 +1271,8 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
priv->media_connected = true;
if (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_AD_HOC_START) {
- dev_dbg(priv->adapter->dev, "info: ADHOC_S_RESP %s\n",
- bss_desc->ssid.ssid);
+ mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_S_RESP %s\n",
+ bss_desc->ssid.ssid);
/* Update the created network descriptor with the new BSSID */
memcpy(bss_desc->mac_address,
@@ -1238,8 +1284,9 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
* Now the join cmd should be successful.
* If BSSID has changed use SSID to compare instead of BSSID
*/
- dev_dbg(priv->adapter->dev, "info: ADHOC_J_RESP %s\n",
- bss_desc->ssid.ssid);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ADHOC_J_RESP %s\n",
+ bss_desc->ssid.ssid);
/*
* Make a copy of current BSSID descriptor, only needed for
@@ -1252,10 +1299,10 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
priv->adhoc_state = ADHOC_JOINED;
}
- dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: channel = %d\n",
- priv->adhoc_channel);
- dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: BSSID = %pM\n",
- priv->curr_bss_params.bss_descriptor.mac_address);
+ mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: channel = %d\n",
+ priv->adhoc_channel);
+ mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: BSSID = %pM\n",
+ priv->curr_bss_params.bss_descriptor.mac_address);
if (!netif_carrier_ok(priv->netdev))
netif_carrier_on(priv->netdev);
@@ -1317,12 +1364,12 @@ int
mwifiex_adhoc_start(struct mwifiex_private *priv,
struct cfg80211_ssid *adhoc_ssid)
{
- dev_dbg(priv->adapter->dev, "info: Adhoc Channel = %d\n",
- priv->adhoc_channel);
- dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
- priv->curr_bss_params.bss_descriptor.channel);
- dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n",
- priv->curr_bss_params.band);
+ mwifiex_dbg(priv->adapter, INFO, "info: Adhoc Channel = %d\n",
+ priv->adhoc_channel);
+ mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.channel = %d\n",
+ priv->curr_bss_params.bss_descriptor.channel);
+ mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.band = %d\n",
+ priv->curr_bss_params.band);
if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
priv->adapter->config_bands & BAND_AAC)
@@ -1343,14 +1390,16 @@ mwifiex_adhoc_start(struct mwifiex_private *priv,
int mwifiex_adhoc_join(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc)
{
- dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid =%s\n",
- priv->curr_bss_params.bss_descriptor.ssid.ssid);
- dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid_len =%u\n",
- priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
- dev_dbg(priv->adapter->dev, "info: adhoc join: ssid =%s\n",
- bss_desc->ssid.ssid);
- dev_dbg(priv->adapter->dev, "info: adhoc join: ssid_len =%u\n",
- bss_desc->ssid.ssid_len);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: adhoc join: curr_bss ssid =%s\n",
+ priv->curr_bss_params.bss_descriptor.ssid.ssid);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: adhoc join: curr_bss ssid_len =%u\n",
+ priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
+ mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid =%s\n",
+ bss_desc->ssid.ssid);
+ mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid_len =%u\n",
+ bss_desc->ssid.ssid_len);
/* Check if the requested SSID is already joined */
if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
@@ -1358,8 +1407,9 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv,
&priv->curr_bss_params.bss_descriptor.ssid) &&
(priv->curr_bss_params.bss_descriptor.bss_mode ==
NL80211_IFTYPE_ADHOC)) {
- dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: new ad-hoc SSID"
- " is the same as current; not attempting to re-join\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ADHOC_J_CMD: new ad-hoc SSID\t"
+ "is the same as current; not attempting to re-join\n");
return -1;
}
@@ -1370,10 +1420,12 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv,
else
mwifiex_set_ba_params(priv);
- dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
- priv->curr_bss_params.bss_descriptor.channel);
- dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n",
- priv->curr_bss_params.band);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: curr_bss_params.channel = %d\n",
+ priv->curr_bss_params.bss_descriptor.channel);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: curr_bss_params.band = %c\n",
+ priv->curr_bss_params.band);
return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
HostCmd_ACT_GEN_SET, 0, bss_desc, true);
@@ -1421,7 +1473,7 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
ret = mwifiex_deauthenticate_infra(priv, mac);
if (ret)
cfg80211_disconnected(priv->netdev, 0, NULL, 0,
- GFP_KERNEL);
+ true, GFP_KERNEL);
break;
case NL80211_IFTYPE_ADHOC:
return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP,
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 03a95c7d34bf..3ba4e0e04223 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -24,6 +24,10 @@
#define VERSION "1.0"
+static unsigned int debug_mask = MWIFIEX_DEFAULT_DEBUG_MASK;
+module_param(debug_mask, uint, 0);
+MODULE_PARM_DESC(debug_mask, "bitmap for debug flags");
+
const char driver_version[] = "mwifiex " VERSION " (%s) ";
static char *cal_data_cfg;
module_param(cal_data_cfg, charp, 0);
@@ -63,6 +67,7 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
/* Save interface specific operations in adapter */
memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops));
+ adapter->debug_mask = debug_mask;
/* card specific initialization has been deferred until now .. */
if (adapter->if_ops.init_if)
@@ -89,7 +94,8 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
return 0;
error:
- dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n");
+ mwifiex_dbg(adapter, ERROR,
+ "info: leave mwifiex_register with error\n");
for (i = 0; i < adapter->priv_num; i++)
kfree(adapter->priv[i]);
@@ -231,11 +237,10 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter)
goto exit_main_proc;
} else {
adapter->mwifiex_processing = true;
+ spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
}
process_start:
do {
- adapter->more_task_flag = false;
- spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) ||
(adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY))
break;
@@ -275,7 +280,6 @@ process_start:
adapter->pm_wakeup_fw_try = true;
mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3));
adapter->if_ops.wakeup(adapter);
- spin_lock_irqsave(&adapter->main_proc_lock, flags);
continue;
}
@@ -335,7 +339,6 @@ process_start:
(adapter->ps_state == PS_STATE_PRE_SLEEP) ||
(adapter->ps_state == PS_STATE_SLEEP_CFM) ||
adapter->tx_lock_flag){
- spin_lock_irqsave(&adapter->main_proc_lock, flags);
continue;
}
@@ -386,12 +389,14 @@ process_start:
}
break;
}
- spin_lock_irqsave(&adapter->main_proc_lock, flags);
} while (true);
spin_lock_irqsave(&adapter->main_proc_lock, flags);
- if (adapter->more_task_flag)
+ if (adapter->more_task_flag) {
+ adapter->more_task_flag = false;
+ spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
goto process_start;
+ }
adapter->mwifiex_processing = false;
spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
@@ -455,8 +460,8 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
struct wireless_dev *wdev;
if (!firmware) {
- dev_err(adapter->dev,
- "Failed to get firmware %s\n", adapter->fw_name);
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to get firmware %s\n", adapter->fw_name);
goto err_dnld_fw;
}
@@ -472,13 +477,13 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
if (ret == -1)
goto err_dnld_fw;
- dev_notice(adapter->dev, "WLAN FW is active\n");
+ mwifiex_dbg(adapter, MSG, "WLAN FW is active\n");
if (cal_data_cfg) {
if ((request_firmware(&adapter->cal_data, cal_data_cfg,
adapter->dev)) < 0)
- dev_err(adapter->dev,
- "Cal data request_firmware() failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Cal data request_firmware() failed\n");
}
/* enable host interrupt after fw dnld is successful */
@@ -503,12 +508,14 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
priv = adapter->priv[MWIFIEX_BSS_ROLE_STA];
if (mwifiex_register_cfg80211(adapter)) {
- dev_err(adapter->dev, "cannot register with cfg80211\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot register with cfg80211\n");
goto err_init_fw;
}
if (mwifiex_init_channel_scan_gap(adapter)) {
- dev_err(adapter->dev, "could not init channel stats table\n");
+ mwifiex_dbg(adapter, ERROR,
+ "could not init channel stats table\n");
goto err_init_fw;
}
@@ -522,7 +529,8 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", NET_NAME_ENUM,
NL80211_IFTYPE_STATION, NULL, NULL);
if (IS_ERR(wdev)) {
- dev_err(adapter->dev, "cannot create default STA interface\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create default STA interface\n");
rtnl_unlock();
goto err_add_intf;
}
@@ -531,7 +539,8 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", NET_NAME_ENUM,
NL80211_IFTYPE_AP, NULL, NULL);
if (IS_ERR(wdev)) {
- dev_err(adapter->dev, "cannot create AP interface\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create AP interface\n");
rtnl_unlock();
goto err_add_intf;
}
@@ -542,8 +551,8 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
NL80211_IFTYPE_P2P_CLIENT, NULL,
NULL);
if (IS_ERR(wdev)) {
- dev_err(adapter->dev,
- "cannot create p2p client interface\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot create p2p client interface\n");
rtnl_unlock();
goto err_add_intf;
}
@@ -551,7 +560,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
rtnl_unlock();
mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
- dev_notice(adapter->dev, "driver_version = %s\n", fmt);
+ mwifiex_dbg(adapter, MSG, "driver_version = %s\n", fmt);
goto done;
err_add_intf:
@@ -561,7 +570,8 @@ err_init_fw:
if (adapter->if_ops.disable_int)
adapter->if_ops.disable_int(adapter);
err_dnld_fw:
- pr_debug("info: %s: unregister device\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "info: %s: unregister device\n", __func__);
if (adapter->if_ops.unregister_dev)
adapter->if_ops.unregister_dev(adapter);
@@ -602,8 +612,8 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
adapter->dev, GFP_KERNEL, adapter,
mwifiex_fw_dpc);
if (ret < 0)
- dev_err(adapter->dev,
- "request_firmware_nowait() returned error %d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "request_firmware_nowait error %d\n", ret);
return ret;
}
@@ -629,7 +639,8 @@ mwifiex_close(struct net_device *dev)
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (priv->scan_request) {
- dev_dbg(priv->adapter->dev, "aborting scan on ndo_stop\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "aborting scan on ndo_stop\n");
cfg80211_scan_done(priv->scan_request, 1);
priv->scan_request = NULL;
priv->scan_aborting = true;
@@ -650,7 +661,8 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
txq = netdev_get_tx_queue(priv->netdev, index);
if (!netif_tx_queue_stopped(txq)) {
netif_tx_stop_queue(txq);
- dev_dbg(priv->adapter->dev, "stop queue: %d\n", index);
+ mwifiex_dbg(priv->adapter, DATA,
+ "stop queue: %d\n", index);
}
}
@@ -715,8 +727,9 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct mwifiex_txinfo *tx_info;
bool multicast;
- dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n",
- jiffies, priv->bss_type, priv->bss_num);
+ mwifiex_dbg(priv->adapter, DATA,
+ "data: %lu BSS(%d-%d): Data <= kernel\n",
+ jiffies, priv->bss_type, priv->bss_num);
if (priv->adapter->surprise_removed) {
kfree_skb(skb);
@@ -724,28 +737,31 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
- dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Tx: bad skb len %d\n", skb->len);
kfree_skb(skb);
priv->stats.tx_dropped++;
return 0;
}
if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
- dev_dbg(priv->adapter->dev,
- "data: Tx: insufficient skb headroom %d\n",
- skb_headroom(skb));
+ mwifiex_dbg(priv->adapter, DATA,
+ "data: Tx: insufficient skb headroom %d\n",
+ skb_headroom(skb));
/* Insufficient skb headroom - allocate a new skb */
new_skb =
skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
if (unlikely(!new_skb)) {
- dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Tx: cannot alloca new_skb\n");
kfree_skb(skb);
priv->stats.tx_dropped++;
return 0;
}
kfree_skb(skb);
skb = new_skb;
- dev_dbg(priv->adapter->dev, "info: new skb headroomd %d\n",
- skb_headroom(skb));
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: new skb headroomd %d\n",
+ skb_headroom(skb));
}
tx_info = MWIFIEX_SKB_TXCB(skb);
@@ -803,8 +819,8 @@ mwifiex_set_mac_address(struct net_device *dev, void *addr)
if (!ret)
memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN);
else
- dev_err(priv->adapter->dev,
- "set mac address failed: ret=%d\n", ret);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "set mac address failed: ret=%d\n", ret);
memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
@@ -842,20 +858,22 @@ mwifiex_tx_timeout(struct net_device *dev)
priv->num_tx_timeout++;
priv->tx_timeout_cnt++;
- dev_err(priv->adapter->dev,
- "%lu : Tx timeout(#%d), bss_type-num = %d-%d\n",
- jiffies, priv->tx_timeout_cnt, priv->bss_type, priv->bss_num);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%lu : Tx timeout(#%d), bss_type-num = %d-%d\n",
+ jiffies, priv->tx_timeout_cnt, priv->bss_type,
+ priv->bss_num);
mwifiex_set_trans_start(dev);
if (priv->tx_timeout_cnt > TX_TIMEOUT_THRESHOLD &&
priv->adapter->if_ops.card_reset) {
- dev_err(priv->adapter->dev,
- "tx_timeout_cnt exceeds threshold. Triggering card reset!\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "tx_timeout_cnt exceeds threshold.\t"
+ "Triggering card reset!\n");
priv->adapter->if_ops.card_reset(priv->adapter);
}
}
-void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter)
+void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter)
{
void *p;
char drv_version[64];
@@ -868,10 +886,11 @@ void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter)
if (adapter->drv_info_dump) {
vfree(adapter->drv_info_dump);
+ adapter->drv_info_dump = NULL;
adapter->drv_info_size = 0;
}
- dev_info(adapter->dev, "=== DRIVER INFO DUMP START===\n");
+ mwifiex_dbg(adapter, MSG, "===mwifiex driverinfo dump start===\n");
adapter->drv_info_dump = vzalloc(MWIFIEX_DRV_INFO_SIZE_MAX);
@@ -939,12 +958,12 @@ void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter)
}
if (adapter->iface_type == MWIFIEX_SDIO) {
- p += sprintf(p, "\n=== SDIO register DUMP===\n");
+ p += sprintf(p, "\n=== SDIO register dump===\n");
if (adapter->if_ops.reg_dump)
p += adapter->if_ops.reg_dump(adapter, p);
}
- p += sprintf(p, "\n=== MORE DEBUG INFORMATION\n");
+ p += sprintf(p, "\n=== more debug information\n");
debug_info = kzalloc(sizeof(*debug_info), GFP_KERNEL);
if (debug_info) {
for (i = 0; i < adapter->priv_num; i++) {
@@ -959,9 +978,99 @@ void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter)
}
adapter->drv_info_size = p - adapter->drv_info_dump;
- dev_info(adapter->dev, "=== DRIVER INFO DUMP END===\n");
+ mwifiex_dbg(adapter, MSG, "===mwifiex driverinfo dump end===\n");
+}
+EXPORT_SYMBOL_GPL(mwifiex_drv_info_dump);
+
+void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter)
+{
+ u8 idx, *dump_data, *fw_dump_ptr;
+ u32 dump_len;
+
+ dump_len = (strlen("========Start dump driverinfo========\n") +
+ adapter->drv_info_size +
+ strlen("\n========End dump========\n"));
+
+ for (idx = 0; idx < adapter->num_mem_types; idx++) {
+ struct memory_type_mapping *entry =
+ &adapter->mem_type_mapping_tbl[idx];
+
+ if (entry->mem_ptr) {
+ dump_len += (strlen("========Start dump ") +
+ strlen(entry->mem_name) +
+ strlen("========\n") +
+ (entry->mem_size + 1) +
+ strlen("\n========End dump========\n"));
+ }
+ }
+
+ dump_data = vzalloc(dump_len + 1);
+ if (!dump_data)
+ goto done;
+
+ fw_dump_ptr = dump_data;
+
+ /* Dump all the memory data into single file, a userspace script will
+ * be used to split all the memory data to multiple files
+ */
+ mwifiex_dbg(adapter, MSG,
+ "== mwifiex dump information to /sys/class/devcoredump start");
+
+ strcpy(fw_dump_ptr, "========Start dump driverinfo========\n");
+ fw_dump_ptr += strlen("========Start dump driverinfo========\n");
+ memcpy(fw_dump_ptr, adapter->drv_info_dump, adapter->drv_info_size);
+ fw_dump_ptr += adapter->drv_info_size;
+ strcpy(fw_dump_ptr, "\n========End dump========\n");
+ fw_dump_ptr += strlen("\n========End dump========\n");
+
+ for (idx = 0; idx < adapter->num_mem_types; idx++) {
+ struct memory_type_mapping *entry =
+ &adapter->mem_type_mapping_tbl[idx];
+
+ if (entry->mem_ptr) {
+ strcpy(fw_dump_ptr, "========Start dump ");
+ fw_dump_ptr += strlen("========Start dump ");
+
+ strcpy(fw_dump_ptr, entry->mem_name);
+ fw_dump_ptr += strlen(entry->mem_name);
+
+ strcpy(fw_dump_ptr, "========\n");
+ fw_dump_ptr += strlen("========\n");
+
+ memcpy(fw_dump_ptr, entry->mem_ptr, entry->mem_size);
+ fw_dump_ptr += entry->mem_size;
+
+ strcpy(fw_dump_ptr, "\n========End dump========\n");
+ fw_dump_ptr += strlen("\n========End dump========\n");
+ }
+ }
+
+ /* device dump data will be free in device coredump release function
+ * after 5 min
+ */
+ dev_coredumpv(adapter->dev, dump_data, dump_len, GFP_KERNEL);
+ mwifiex_dbg(adapter, MSG,
+ "== mwifiex dump information to /sys/class/devcoredump end");
+
+done:
+ for (idx = 0; idx < adapter->num_mem_types; idx++) {
+ struct memory_type_mapping *entry =
+ &adapter->mem_type_mapping_tbl[idx];
+
+ if (entry->mem_ptr) {
+ vfree(entry->mem_ptr);
+ entry->mem_ptr = NULL;
+ }
+ entry->mem_size = 0;
+ }
+
+ if (adapter->drv_info_dump) {
+ vfree(adapter->drv_info_dump);
+ adapter->drv_info_dump = NULL;
+ adapter->drv_info_size = 0;
+ }
}
-EXPORT_SYMBOL_GPL(mwifiex_dump_drv_info);
+EXPORT_SYMBOL_GPL(mwifiex_upload_device_dump);
/*
* CFG802.11 network device handler for statistics retrieval.
@@ -1230,21 +1339,24 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
}
}
- dev_dbg(adapter->dev, "cmd: calling mwifiex_shutdown_drv...\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: calling mwifiex_shutdown_drv...\n");
adapter->init_wait_q_woken = false;
if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS)
wait_event_interruptible(adapter->init_wait_q,
adapter->init_wait_q_woken);
- dev_dbg(adapter->dev, "cmd: mwifiex_shutdown_drv done\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: mwifiex_shutdown_drv done\n");
if (atomic_read(&adapter->rx_pending) ||
atomic_read(&adapter->tx_pending) ||
atomic_read(&adapter->cmd_pending)) {
- dev_err(adapter->dev, "rx_pending=%d, tx_pending=%d, "
- "cmd_pending=%d\n",
- atomic_read(&adapter->rx_pending),
- atomic_read(&adapter->tx_pending),
- atomic_read(&adapter->cmd_pending));
+ mwifiex_dbg(adapter, ERROR,
+ "rx_pending=%d, tx_pending=%d,\t"
+ "cmd_pending=%d\n",
+ atomic_read(&adapter->rx_pending),
+ atomic_read(&adapter->tx_pending),
+ atomic_read(&adapter->cmd_pending));
}
for (i = 0; i < adapter->priv_num; i++) {
@@ -1264,11 +1376,13 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
wiphy_free(adapter->wiphy);
/* Unregister device */
- dev_dbg(adapter->dev, "info: unregister device\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: unregister device\n");
if (adapter->if_ops.unregister_dev)
adapter->if_ops.unregister_dev(adapter);
/* Free adapter structure */
- dev_dbg(adapter->dev, "info: free adapter\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: free adapter\n");
mwifiex_free_adapter(adapter);
exit_remove:
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index fe1256044a6c..ae98b5b83b1f 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -36,6 +36,7 @@
#include <linux/of.h>
#include <linux/idr.h>
#include <linux/inetdevice.h>
+#include <linux/devcoredump.h>
#include "decl.h"
#include "ioctl.h"
@@ -147,6 +148,54 @@ enum {
/* Address alignment */
#define MWIFIEX_ALIGN_ADDR(p, a) (((long)(p) + (a) - 1) & ~((a) - 1))
+/**
+ *enum mwifiex_debug_level - marvell wifi debug level
+ */
+enum MWIFIEX_DEBUG_LEVEL {
+ MWIFIEX_DBG_MSG = 0x00000001,
+ MWIFIEX_DBG_FATAL = 0x00000002,
+ MWIFIEX_DBG_ERROR = 0x00000004,
+ MWIFIEX_DBG_DATA = 0x00000008,
+ MWIFIEX_DBG_CMD = 0x00000010,
+ MWIFIEX_DBG_EVENT = 0x00000020,
+ MWIFIEX_DBG_INTR = 0x00000040,
+ MWIFIEX_DBG_IOCTL = 0x00000080,
+
+ MWIFIEX_DBG_MPA_D = 0x00008000,
+ MWIFIEX_DBG_DAT_D = 0x00010000,
+ MWIFIEX_DBG_CMD_D = 0x00020000,
+ MWIFIEX_DBG_EVT_D = 0x00040000,
+ MWIFIEX_DBG_FW_D = 0x00080000,
+ MWIFIEX_DBG_IF_D = 0x00100000,
+
+ MWIFIEX_DBG_ENTRY = 0x10000000,
+ MWIFIEX_DBG_WARN = 0x20000000,
+ MWIFIEX_DBG_INFO = 0x40000000,
+ MWIFIEX_DBG_DUMP = 0x80000000,
+
+ MWIFIEX_DBG_ANY = 0xffffffff
+};
+
+#define MWIFIEX_DEFAULT_DEBUG_MASK (MWIFIEX_DBG_MSG | \
+ MWIFIEX_DBG_FATAL | \
+ MWIFIEX_DBG_ERROR)
+
+#define mwifiex_dbg(adapter, dbg_mask, fmt, args...) \
+do { \
+ if ((adapter)->debug_mask & MWIFIEX_DBG_##dbg_mask) \
+ if ((adapter)->dev) \
+ dev_info((adapter)->dev, fmt, ## args); \
+} while (0)
+
+#define DEBUG_DUMP_DATA_MAX_LEN 128
+#define mwifiex_dbg_dump(adapter, dbg_mask, str, buf, len) \
+do { \
+ if ((adapter)->debug_mask & MWIFIEX_DBG_##dbg_mask) \
+ print_hex_dump(KERN_DEBUG, str, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, len, false); \
+} while (0)
+
struct mwifiex_dbg {
u32 num_cmd_host_to_card_failure;
u32 num_cmd_sleep_cfm_host_to_card_failure;
@@ -451,7 +500,7 @@ enum rdwr_status {
};
enum mwifiex_iface_work_flags {
- MWIFIEX_IFACE_WORK_FW_DUMP,
+ MWIFIEX_IFACE_WORK_DEVICE_DUMP,
MWIFIEX_IFACE_WORK_CARD_RESET,
};
@@ -593,6 +642,7 @@ struct mwifiex_private {
u8 del_list_idx;
bool hs2_enabled;
struct mwifiex_uap_bss_param bss_cfg;
+ struct cfg80211_chan_def bss_chandef;
struct station_parameters *sta_params;
struct sk_buff_head tdls_txq;
u8 check_tdls_tx;
@@ -611,6 +661,7 @@ struct mwifiex_private {
struct delayed_work dfs_chan_sw_work;
struct cfg80211_beacon_data beacon_after;
struct mwifiex_11h_intf_state state_11h;
+ struct mwifiex_ds_mem_rw mem_rw;
};
@@ -690,6 +741,18 @@ struct mwifiex_tdls_capab {
struct ieee80211_vht_operation vhtoper;
};
+struct mwifiex_station_stats {
+ u64 last_rx;
+ s8 rssi;
+ u64 rx_bytes;
+ u64 tx_bytes;
+ u32 rx_packets;
+ u32 tx_packets;
+ u32 tx_failed;
+ u8 last_tx_rate;
+ u8 last_tx_htinfo;
+};
+
/* This is AP/TDLS specific structure which stores information
* about associated/peer STA
*/
@@ -704,6 +767,7 @@ struct mwifiex_sta_node {
u16 max_amsdu;
u8 tdls_status;
struct mwifiex_tdls_capab tdls_cap;
+ struct mwifiex_station_stats stats;
};
struct mwifiex_auto_tdls_peer {
@@ -740,8 +804,8 @@ struct mwifiex_if_ops {
int (*init_fw_port) (struct mwifiex_adapter *);
int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
void (*card_reset) (struct mwifiex_adapter *);
- void (*fw_dump)(struct mwifiex_adapter *);
int (*reg_dump)(struct mwifiex_adapter *, char *);
+ void (*device_dump)(struct mwifiex_adapter *);
int (*clean_pcie_ring) (struct mwifiex_adapter *adapter);
void (*iface_work)(struct work_struct *work);
void (*submit_rem_rx_urbs)(struct mwifiex_adapter *adapter);
@@ -750,6 +814,7 @@ struct mwifiex_if_ops {
struct mwifiex_adapter {
u8 iface_type;
+ unsigned int debug_mask;
struct mwifiex_iface_comb iface_limit;
struct mwifiex_iface_comb curr_iface_comb;
struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
@@ -900,7 +965,6 @@ struct mwifiex_adapter {
u8 key_api_major_ver, key_api_minor_ver;
struct memory_type_mapping *mem_type_mapping_tbl;
u8 num_mem_types;
- u8 curr_mem_idx;
void *drv_info_dump;
u32 drv_info_size;
bool scan_chan_gap_enabled;
@@ -909,6 +973,12 @@ struct mwifiex_adapter {
u32 num_in_chan_stats;
int survey_idx;
bool auto_tdls;
+ u8 coex_scan;
+ u8 coex_min_scan_time;
+ u8 coex_max_scan_time;
+ u8 coex_win_size;
+ u8 coex_tx_win_size;
+ u8 coex_rx_win_size;
};
void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
@@ -1085,6 +1155,9 @@ void mwifiex_set_ht_params(struct mwifiex_private *priv,
void mwifiex_set_vht_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
+void mwifiex_set_tpc_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params);
void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
void mwifiex_set_vht_width(struct mwifiex_private *priv,
@@ -1095,6 +1168,11 @@ mwifiex_set_wmm_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
void mwifiex_set_ba_params(struct mwifiex_private *priv);
+
+void mwifiex_update_ampdu_txwinsize(struct mwifiex_adapter *pmadapter);
+void mwifiex_bt_coex_wlan_param_update_event(struct mwifiex_private *priv,
+ struct sk_buff *event_skb);
+
void mwifiex_set_11ac_ba_params(struct mwifiex_private *priv);
int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
@@ -1332,6 +1410,7 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc);
u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type);
+u8 mwifiex_sec_chan_offset_to_chan_type(u8 second_chan_offset);
struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
const char *name,
@@ -1349,7 +1428,8 @@ 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,
+void mwifiex_uap_set_channel(struct mwifiex_private *priv,
+ 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);
@@ -1423,6 +1503,8 @@ mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
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_stop_radar_detection(struct mwifiex_private *priv,
+ struct cfg80211_chan_def *chandef);
int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
struct sk_buff *skb);
@@ -1434,10 +1516,12 @@ void mwifiex_hist_data_add(struct mwifiex_private *priv,
u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv,
u8 rx_rate, u8 ht_info);
-void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter);
+void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter);
+void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter);
void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags);
void mwifiex_queue_main_work(struct mwifiex_adapter *adapter);
-
+void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter);
+void mwifiex_11n_delba(struct mwifiex_private *priv, int tid);
#ifdef CONFIG_DEBUG_FS
void mwifiex_debugfs_init(void);
void mwifiex_debugfs_remove(void);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index bcc7751d883c..77b9055a2d14 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -57,7 +57,7 @@ mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
mapping.addr = pci_map_single(card->dev, skb->data, size, flags);
if (pci_dma_mapping_error(card->dev, mapping.addr)) {
- dev_err(adapter->dev, "failed to map pci memory!\n");
+ mwifiex_dbg(adapter, ERROR, "failed to map pci memory!\n");
return -1;
}
mapping.len = size;
@@ -89,8 +89,9 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
if (card->sleep_cookie_vbase) {
cookie_addr = (u32 *)card->sleep_cookie_vbase;
- dev_dbg(adapter->dev, "info: ACCESS_HW: sleep cookie=0x%x\n",
- *cookie_addr);
+ mwifiex_dbg(adapter, INFO,
+ "info: ACCESS_HW: sleep cookie=0x%x\n",
+ *cookie_addr);
if (*cookie_addr == FW_AWAKE_COOKIE)
return true;
}
@@ -164,7 +165,8 @@ static int mwifiex_pcie_resume(struct device *dev)
adapter = card->adapter;
if (!adapter->is_suspended) {
- dev_warn(adapter->dev, "Device already resumed\n");
+ mwifiex_dbg(adapter, WARN,
+ "Device already resumed\n");
return 0;
}
@@ -361,16 +363,16 @@ static void mwifiex_delay_for_sleep_cookie(struct mwifiex_adapter *adapter,
sleep_cookie = *(u32 *)buffer;
if (sleep_cookie == MWIFIEX_DEF_SLEEP_COOKIE) {
- dev_dbg(adapter->dev,
- "sleep cookie found at count %d\n", count);
+ mwifiex_dbg(adapter, INFO,
+ "sleep cookie found at count %d\n", count);
break;
}
usleep_range(20, 30);
}
if (count >= max_delay_loop_cnt)
- dev_dbg(adapter->dev,
- "max count reached while accessing sleep cookie\n");
+ mwifiex_dbg(adapter, INFO,
+ "max count reached while accessing sleep cookie\n");
}
/* This function wakes up the card by reading fw_status register. */
@@ -380,20 +382,23 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
struct pcie_service_card *card = adapter->card;
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
- dev_dbg(adapter->dev, "event: Wakeup device...\n");
+ mwifiex_dbg(adapter, EVENT,
+ "event: Wakeup device...\n");
if (reg->sleep_cookie)
mwifiex_pcie_dev_wakeup_delay(adapter);
/* Reading fw_status register will wakeup device */
if (mwifiex_read_reg(adapter, reg->fw_status, &fw_status)) {
- dev_warn(adapter->dev, "Reading fw_status register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Reading fw_status register failed\n");
return -1;
}
if (reg->sleep_cookie) {
mwifiex_pcie_dev_wakeup_delay(adapter);
- dev_dbg(adapter->dev, "PCIE wakeup: Setting PS_STATE_AWAKE\n");
+ mwifiex_dbg(adapter, INFO,
+ "PCIE wakeup: Setting PS_STATE_AWAKE\n");
adapter->ps_state = PS_STATE_AWAKE;
}
@@ -407,7 +412,8 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
*/
static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
{
- dev_dbg(adapter->dev, "cmd: Wakeup device completed\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Wakeup device completed\n");
return 0;
}
@@ -423,7 +429,8 @@ static int mwifiex_pcie_disable_host_int(struct mwifiex_adapter *adapter)
if (mwifiex_pcie_ok_to_access_hw(adapter)) {
if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
0x00000000)) {
- dev_warn(adapter->dev, "Disable host interrupt failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Disable host interrupt failed\n");
return -1;
}
}
@@ -443,7 +450,8 @@ static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter)
/* Simply write the mask to the register */
if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
HOST_INTR_MASK)) {
- dev_warn(adapter->dev, "Enable host interrupt failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Enable host interrupt failed\n");
return -1;
}
}
@@ -499,8 +507,8 @@ static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter)
skb = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE,
GFP_KERNEL | GFP_DMA);
if (!skb) {
- dev_err(adapter->dev,
- "Unable to allocate skb for RX ring.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Unable to allocate skb for RX ring.\n");
kfree(card->rxbd_ring_vbase);
return -ENOMEM;
}
@@ -512,10 +520,10 @@ static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter)
buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
- dev_dbg(adapter->dev,
- "info: RX ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
- skb, skb->len, skb->data, (u32)buf_pa,
- (u32)((u64)buf_pa >> 32));
+ mwifiex_dbg(adapter, INFO,
+ "info: RX ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
+ skb, skb->len, skb->data, (u32)buf_pa,
+ (u32)((u64)buf_pa >> 32));
card->rx_buf_list[i] = skb;
if (reg->pfu_enabled) {
@@ -556,8 +564,8 @@ static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter)
/* Allocate skb here so that firmware can DMA data from it */
skb = dev_alloc_skb(MAX_EVENT_SIZE);
if (!skb) {
- dev_err(adapter->dev,
- "Unable to allocate skb for EVENT buf.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Unable to allocate skb for EVENT buf.\n");
kfree(card->evtbd_ring_vbase);
return -ENOMEM;
}
@@ -569,10 +577,10 @@ static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter)
buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
- dev_dbg(adapter->dev,
- "info: EVT ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
- skb, skb->len, skb->data, (u32)buf_pa,
- (u32)((u64)buf_pa >> 32));
+ mwifiex_dbg(adapter, EVENT,
+ "info: EVT ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
+ skb, skb->len, skb->data, (u32)buf_pa,
+ (u32)((u64)buf_pa >> 32));
card->evt_buf_list[i] = skb;
card->evtbd_ring[i] = (void *)(card->evtbd_ring_vbase +
@@ -715,21 +723,23 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
MWIFIEX_MAX_TXRX_BD;
- dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n",
- card->txbd_ring_size);
+ mwifiex_dbg(adapter, INFO,
+ "info: txbd_ring: Allocating %d bytes\n",
+ card->txbd_ring_size);
card->txbd_ring_vbase = pci_alloc_consistent(card->dev,
card->txbd_ring_size,
&card->txbd_ring_pbase);
if (!card->txbd_ring_vbase) {
- dev_err(adapter->dev,
- "allocate consistent memory (%d bytes) failed!\n",
- card->txbd_ring_size);
+ mwifiex_dbg(adapter, ERROR,
+ "allocate consistent memory (%d bytes) failed!\n",
+ card->txbd_ring_size);
return -ENOMEM;
}
- dev_dbg(adapter->dev,
- "info: txbd_ring - base: %p, pbase: %#x:%x, len: %x\n",
- card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase,
- (u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size);
+ mwifiex_dbg(adapter, DATA,
+ "info: txbd_ring - base: %p, pbase: %#x:%x, len: %x\n",
+ card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase,
+ (u32)((u64)card->txbd_ring_pbase >> 32),
+ card->txbd_ring_size);
return mwifiex_init_txq_ring(adapter);
}
@@ -777,23 +787,24 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
MWIFIEX_MAX_TXRX_BD;
- dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n",
- card->rxbd_ring_size);
+ mwifiex_dbg(adapter, INFO,
+ "info: rxbd_ring: Allocating %d bytes\n",
+ card->rxbd_ring_size);
card->rxbd_ring_vbase = pci_alloc_consistent(card->dev,
card->rxbd_ring_size,
&card->rxbd_ring_pbase);
if (!card->rxbd_ring_vbase) {
- dev_err(adapter->dev,
- "allocate consistent memory (%d bytes) failed!\n",
- card->rxbd_ring_size);
+ mwifiex_dbg(adapter, ERROR,
+ "allocate consistent memory (%d bytes) failed!\n",
+ card->rxbd_ring_size);
return -ENOMEM;
}
- dev_dbg(adapter->dev,
- "info: rxbd_ring - base: %p, pbase: %#x:%x, len: %#x\n",
- card->rxbd_ring_vbase, (u32)card->rxbd_ring_pbase,
- (u32)((u64)card->rxbd_ring_pbase >> 32),
- card->rxbd_ring_size);
+ mwifiex_dbg(adapter, DATA,
+ "info: rxbd_ring - base: %p, pbase: %#x:%x, len: %#x\n",
+ card->rxbd_ring_vbase, (u32)card->rxbd_ring_pbase,
+ (u32)((u64)card->rxbd_ring_pbase >> 32),
+ card->rxbd_ring_size);
return mwifiex_init_rxq_ring(adapter);
}
@@ -840,23 +851,24 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
card->evtbd_ring_size = sizeof(struct mwifiex_evt_buf_desc) *
MWIFIEX_MAX_EVT_BD;
- dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n",
+ mwifiex_dbg(adapter, INFO,
+ "info: evtbd_ring: Allocating %d bytes\n",
card->evtbd_ring_size);
card->evtbd_ring_vbase = pci_alloc_consistent(card->dev,
card->evtbd_ring_size,
&card->evtbd_ring_pbase);
if (!card->evtbd_ring_vbase) {
- dev_err(adapter->dev,
- "allocate consistent memory (%d bytes) failed!\n",
- card->evtbd_ring_size);
+ mwifiex_dbg(adapter, ERROR,
+ "allocate consistent memory (%d bytes) failed!\n",
+ card->evtbd_ring_size);
return -ENOMEM;
}
- dev_dbg(adapter->dev,
- "info: CMDRSP/EVT bd_ring - base: %p pbase: %#x:%x len: %#x\n",
- card->evtbd_ring_vbase, (u32)card->evtbd_ring_pbase,
- (u32)((u64)card->evtbd_ring_pbase >> 32),
- card->evtbd_ring_size);
+ mwifiex_dbg(adapter, EVENT,
+ "info: CMDRSP/EVT bd_ring - base: %p pbase: %#x:%x len: %#x\n",
+ card->evtbd_ring_vbase, (u32)card->evtbd_ring_pbase,
+ (u32)((u64)card->evtbd_ring_pbase >> 32),
+ card->evtbd_ring_size);
return mwifiex_pcie_init_evt_ring(adapter);
}
@@ -895,8 +907,8 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter)
/* Allocate memory for receiving command response data */
skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE);
if (!skb) {
- dev_err(adapter->dev,
- "Unable to allocate skb for command response data.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Unable to allocate skb for command response data.\n");
return -ENOMEM;
}
skb_put(skb, MWIFIEX_UPLD_SIZE);
@@ -944,14 +956,16 @@ static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
card->sleep_cookie_vbase = pci_alloc_consistent(card->dev, sizeof(u32),
&card->sleep_cookie_pbase);
if (!card->sleep_cookie_vbase) {
- dev_err(adapter->dev, "pci_alloc_consistent failed!\n");
+ mwifiex_dbg(adapter, ERROR,
+ "pci_alloc_consistent failed!\n");
return -ENOMEM;
}
/* Init val of Sleep Cookie */
*(u32 *)card->sleep_cookie_vbase = FW_AWAKE_COOKIE;
- dev_dbg(adapter->dev, "alloc_scook: sleep cookie=0x%x\n",
- *((u32 *)card->sleep_cookie_vbase));
+ mwifiex_dbg(adapter, INFO,
+ "alloc_scook: sleep cookie=0x%x\n",
+ *((u32 *)card->sleep_cookie_vbase));
return 0;
}
@@ -993,8 +1007,8 @@ static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
*/
if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
CPU_INTR_DNLD_RDY)) {
- dev_err(adapter->dev,
- "failed to assert dnld-rdy interrupt.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "failed to assert dnld-rdy interrupt.\n");
return -1;
}
}
@@ -1018,13 +1032,14 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
/* Read the TX ring read pointer set by firmware */
if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) {
- dev_err(adapter->dev,
- "SEND COMP: failed to read reg->tx_rdptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "SEND COMP: failed to read reg->tx_rdptr\n");
return -1;
}
- dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
- card->txbd_rdptr, rdptr);
+ mwifiex_dbg(adapter, DATA,
+ "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
+ card->txbd_rdptr, rdptr);
num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
/* free from previous txbd_rdptr to current txbd_rdptr */
@@ -1038,9 +1053,9 @@ static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
skb = card->tx_buf_list[wrdoneidx];
if (skb) {
- dev_dbg(adapter->dev,
- "SEND COMP: Detach skb %p at txbd_rdidx=%d\n",
- skb, wrdoneidx);
+ mwifiex_dbg(adapter, DATA,
+ "SEND COMP: Detach skb %p at txbd_rdidx=%d\n",
+ skb, wrdoneidx);
mwifiex_unmap_pci_memory(adapter, skb,
PCI_DMA_TODEVICE);
@@ -1112,8 +1127,9 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
__le16 *tmp;
if (!(skb->data && skb->len)) {
- dev_err(adapter->dev, "%s(): invalid parameter <%p, %#x>\n",
- __func__, skb->data, skb->len);
+ mwifiex_dbg(adapter, ERROR,
+ "%s(): invalid parameter <%p, %#x>\n",
+ __func__, skb->data, skb->len);
return -1;
}
@@ -1121,7 +1137,8 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
mwifiex_pm_wakeup_card(adapter);
num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
- dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n",
+ mwifiex_dbg(adapter, DATA,
+ "info: SEND DATA: <Rd: %#x, Wr: %#x>\n",
card->txbd_rdptr, card->txbd_wrptr);
if (mwifiex_pcie_txbd_not_full(card)) {
u8 *payload;
@@ -1175,39 +1192,40 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
/* Write the TX ring write pointer in to reg->tx_wrptr */
if (mwifiex_write_reg(adapter, reg->tx_wrptr,
card->txbd_wrptr | rx_val)) {
- dev_err(adapter->dev,
- "SEND DATA: failed to write reg->tx_wrptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "SEND DATA: failed to write reg->tx_wrptr\n");
ret = -1;
goto done_unmap;
}
if ((mwifiex_pcie_txbd_not_full(card)) &&
tx_param->next_pkt_len) {
/* have more packets and TxBD still can hold more */
- dev_dbg(adapter->dev,
- "SEND DATA: delay dnld-rdy interrupt.\n");
+ mwifiex_dbg(adapter, DATA,
+ "SEND DATA: delay dnld-rdy interrupt.\n");
adapter->data_sent = false;
} else {
/* Send the TX ready interrupt */
if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
CPU_INTR_DNLD_RDY)) {
- dev_err(adapter->dev,
- "SEND DATA: failed to assert dnld-rdy interrupt.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "SEND DATA: failed to assert dnld-rdy interrupt.\n");
ret = -1;
goto done_unmap;
}
}
- dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: "
- "%#x> and sent packet to firmware successfully\n",
- card->txbd_rdptr, card->txbd_wrptr);
+ mwifiex_dbg(adapter, DATA,
+ "info: SEND DATA: Updated <Rd: %#x, Wr:\t"
+ "%#x> and sent packet to firmware successfully\n",
+ card->txbd_rdptr, card->txbd_wrptr);
} else {
- dev_dbg(adapter->dev,
- "info: TX Ring full, can't send packets to fw\n");
+ mwifiex_dbg(adapter, DATA,
+ "info: TX Ring full, can't send packets to fw\n");
adapter->data_sent = true;
/* Send the TX ready interrupt */
if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
CPU_INTR_DNLD_RDY))
- dev_err(adapter->dev,
- "SEND DATA: failed to assert door-bell intr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "SEND DATA: failed to assert door-bell intr\n");
return -EBUSY;
}
@@ -1243,8 +1261,8 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
/* Read the RX ring Write pointer set by firmware */
if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
- dev_err(adapter->dev,
- "RECV DATA: failed to read reg->rx_wrptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "RECV DATA: failed to read reg->rx_wrptr\n");
ret = -1;
goto done;
}
@@ -1277,15 +1295,15 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
rx_len = le16_to_cpu(pkt_len);
if (WARN_ON(rx_len <= INTF_HEADER_LEN ||
rx_len > MWIFIEX_RX_DATA_BUF_SIZE)) {
- dev_err(adapter->dev,
- "Invalid RX len %d, Rd=%#x, Wr=%#x\n",
- rx_len, card->rxbd_rdptr, wrptr);
+ mwifiex_dbg(adapter, ERROR,
+ "Invalid RX len %d, Rd=%#x, Wr=%#x\n",
+ rx_len, card->rxbd_rdptr, wrptr);
dev_kfree_skb_any(skb_data);
} else {
skb_put(skb_data, rx_len);
- dev_dbg(adapter->dev,
- "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
- card->rxbd_rdptr, wrptr, rx_len);
+ mwifiex_dbg(adapter, DATA,
+ "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
+ card->rxbd_rdptr, wrptr, rx_len);
skb_pull(skb_data, INTF_HEADER_LEN);
if (adapter->rx_work_enabled) {
skb_queue_tail(&adapter->rx_data_q, skb_data);
@@ -1299,8 +1317,8 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
skb_tmp = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE,
GFP_KERNEL | GFP_DMA);
if (!skb_tmp) {
- dev_err(adapter->dev,
- "Unable to allocate skb.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Unable to allocate skb.\n");
return -ENOMEM;
}
@@ -1311,9 +1329,9 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
buf_pa = MWIFIEX_SKB_DMA_ADDR(skb_tmp);
- dev_dbg(adapter->dev,
- "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
- skb_tmp, rd_index);
+ mwifiex_dbg(adapter, INFO,
+ "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
+ skb_tmp, rd_index);
card->rx_buf_list[rd_index] = skb_tmp;
if (reg->pfu_enabled) {
@@ -1336,28 +1354,29 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
reg->rx_rollover_ind) ^
reg->rx_rollover_ind);
}
- dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n",
- card->rxbd_rdptr, wrptr);
+ mwifiex_dbg(adapter, DATA,
+ "info: RECV DATA: <Rd: %#x, Wr: %#x>\n",
+ card->rxbd_rdptr, wrptr);
tx_val = card->txbd_wrptr & reg->tx_wrap_mask;
/* Write the RX ring read pointer in to reg->rx_rdptr */
if (mwifiex_write_reg(adapter, reg->rx_rdptr,
card->rxbd_rdptr | tx_val)) {
- dev_err(adapter->dev,
- "RECV DATA: failed to write reg->rx_rdptr\n");
+ mwifiex_dbg(adapter, DATA,
+ "RECV DATA: failed to write reg->rx_rdptr\n");
ret = -1;
goto done;
}
/* Read the RX ring Write pointer set by firmware */
if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
- dev_err(adapter->dev,
- "RECV DATA: failed to read reg->rx_wrptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "RECV DATA: failed to read reg->rx_wrptr\n");
ret = -1;
goto done;
}
- dev_dbg(adapter->dev,
- "info: RECV DATA: Rcvd packet from fw successfully\n");
+ mwifiex_dbg(adapter, DATA,
+ "info: RECV DATA: Rcvd packet from fw successfully\n");
card->rxbd_wrptr = wrptr;
}
@@ -1376,9 +1395,9 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
if (!(skb->data && skb->len)) {
- dev_err(adapter->dev,
- "Invalid parameter in %s <%p. len %d>\n",
- __func__, skb->data, skb->len);
+ mwifiex_dbg(adapter, ERROR,
+ "Invalid parameter in %s <%p. len %d>\n",
+ __func__, skb->data, skb->len);
return -1;
}
@@ -1391,9 +1410,9 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
* address scratch register
*/
if (mwifiex_write_reg(adapter, reg->cmd_addr_lo, (u32)buf_pa)) {
- dev_err(adapter->dev,
- "%s: failed to write download command to boot code.\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to write download command to boot code.\n",
+ __func__);
mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
return -1;
}
@@ -1403,18 +1422,18 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
*/
if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
(u32)((u64)buf_pa >> 32))) {
- dev_err(adapter->dev,
- "%s: failed to write download command to boot code.\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to write download command to boot code.\n",
+ __func__);
mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
return -1;
}
/* Write the command length to cmd_size scratch register */
if (mwifiex_write_reg(adapter, reg->cmd_size, skb->len)) {
- dev_err(adapter->dev,
- "%s: failed to write command len to cmd_size scratch reg\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to write command len to cmd_size scratch reg\n",
+ __func__);
mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
return -1;
}
@@ -1422,8 +1441,8 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
/* Ring the door bell */
if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
CPU_INTR_DOOR_BELL)) {
- dev_err(adapter->dev,
- "%s: failed to assert door-bell intr\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to assert door-bell intr\n", __func__);
mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE);
return -1;
}
@@ -1443,8 +1462,8 @@ static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter)
/* Write the RX ring read pointer in to reg->rx_rdptr */
if (mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr |
tx_wrap)) {
- dev_err(adapter->dev,
- "RECV DATA: failed to write reg->rx_rdptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "RECV DATA: failed to write reg->rx_rdptr\n");
return -1;
}
return 0;
@@ -1462,15 +1481,16 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
u8 *payload = (u8 *)skb->data;
if (!(skb->data && skb->len)) {
- dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x>\n",
- __func__, skb->data, skb->len);
+ mwifiex_dbg(adapter, ERROR,
+ "Invalid parameter in %s <%p, %#x>\n",
+ __func__, skb->data, skb->len);
return -1;
}
/* Make sure a command response buffer is available */
if (!card->cmdrsp_buf) {
- dev_err(adapter->dev,
- "No response buffer available, send command failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "No response buffer available, send command failed\n");
return -EBUSY;
}
@@ -1503,8 +1523,8 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
address */
if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo,
(u32)cmdrsp_buf_pa)) {
- dev_err(adapter->dev,
- "Failed to write download cmd to boot code.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write download cmd to boot code.\n");
ret = -1;
goto done;
}
@@ -1512,8 +1532,8 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
address */
if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi,
(u32)((u64)cmdrsp_buf_pa >> 32))) {
- dev_err(adapter->dev,
- "Failed to write download cmd to boot code.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write download cmd to boot code.\n");
ret = -1;
goto done;
}
@@ -1523,16 +1543,16 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
/* Write the lower 32bits of the physical address to reg->cmd_addr_lo */
if (mwifiex_write_reg(adapter, reg->cmd_addr_lo,
(u32)cmd_buf_pa)) {
- dev_err(adapter->dev,
- "Failed to write download cmd to boot code.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write download cmd to boot code.\n");
ret = -1;
goto done;
}
/* Write the upper 32bits of the physical address to reg->cmd_addr_hi */
if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
(u32)((u64)cmd_buf_pa >> 32))) {
- dev_err(adapter->dev,
- "Failed to write download cmd to boot code.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write download cmd to boot code.\n");
ret = -1;
goto done;
}
@@ -1540,8 +1560,8 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
/* Write the command length to reg->cmd_size */
if (mwifiex_write_reg(adapter, reg->cmd_size,
card->cmd_buf->len)) {
- dev_err(adapter->dev,
- "Failed to write cmd len to reg->cmd_size\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write cmd len to reg->cmd_size\n");
ret = -1;
goto done;
}
@@ -1549,8 +1569,8 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
/* Ring the door bell */
if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
CPU_INTR_DOOR_BELL)) {
- dev_err(adapter->dev,
- "Failed to assert door-bell intr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to assert door-bell intr\n");
ret = -1;
goto done;
}
@@ -1574,7 +1594,8 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
u16 rx_len;
__le16 pkt_len;
- dev_dbg(adapter->dev, "info: Rx CMD Response\n");
+ mwifiex_dbg(adapter, CMD,
+ "info: Rx CMD Response\n");
mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_FROMDEVICE);
@@ -1598,8 +1619,8 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
if (mwifiex_write_reg(adapter,
PCIE_CPU_INT_EVENT,
CPU_INTR_SLEEP_CFM_DONE)) {
- dev_warn(adapter->dev,
- "Write register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Write register failed\n");
return -1;
}
mwifiex_delay_for_sleep_cookie(adapter,
@@ -1608,8 +1629,8 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
mwifiex_pcie_ok_to_access_hw(adapter))
usleep_range(50, 60);
} else {
- dev_err(adapter->dev,
- "There is no command but got cmdrsp\n");
+ mwifiex_dbg(adapter, ERROR,
+ "There is no command but got cmdrsp\n");
}
memcpy(adapter->upld_buf, skb->data,
min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
@@ -1628,15 +1649,15 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
will prevent firmware from writing to the same response
buffer again. */
if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo, 0)) {
- dev_err(adapter->dev,
- "cmd_done: failed to clear cmd_rsp_addr_lo\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cmd_done: failed to clear cmd_rsp_addr_lo\n");
return -1;
}
/* Write the upper 32bits of the cmdrsp buffer physical
address */
if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi, 0)) {
- dev_err(adapter->dev,
- "cmd_done: failed to clear cmd_rsp_addr_hi\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cmd_done: failed to clear cmd_rsp_addr_hi\n");
return -1;
}
}
@@ -1678,25 +1699,28 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
mwifiex_pm_wakeup_card(adapter);
if (adapter->event_received) {
- dev_dbg(adapter->dev, "info: Event being processed, "
- "do not process this interrupt just yet\n");
+ mwifiex_dbg(adapter, EVENT,
+ "info: Event being processed,\t"
+ "do not process this interrupt just yet\n");
return 0;
}
if (rdptr >= MWIFIEX_MAX_EVT_BD) {
- dev_dbg(adapter->dev, "info: Invalid read pointer...\n");
+ mwifiex_dbg(adapter, ERROR,
+ "info: Invalid read pointer...\n");
return -1;
}
/* Read the event ring write pointer set by firmware */
if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
- dev_err(adapter->dev,
- "EventReady: failed to read reg->evt_wrptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "EventReady: failed to read reg->evt_wrptr\n");
return -1;
}
- dev_dbg(adapter->dev, "info: EventReady: Initial <Rd: 0x%x, Wr: 0x%x>",
- card->evtbd_rdptr, wrptr);
+ mwifiex_dbg(adapter, EVENT,
+ "info: EventReady: Initial <Rd: 0x%x, Wr: 0x%x>",
+ card->evtbd_rdptr, wrptr);
if (((wrptr & MWIFIEX_EVTBD_MASK) != (card->evtbd_rdptr
& MWIFIEX_EVTBD_MASK)) ||
((wrptr & reg->evt_rollover_ind) ==
@@ -1705,7 +1729,8 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
__le16 data_len = 0;
u16 evt_len;
- dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr);
+ mwifiex_dbg(adapter, INFO,
+ "info: Read Index: %d\n", rdptr);
skb_cmd = card->evt_buf_list[rdptr];
mwifiex_unmap_pci_memory(adapter, skb_cmd, PCI_DMA_FROMDEVICE);
@@ -1721,9 +1746,10 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
len is 2 bytes followed by type which is 2 bytes */
memcpy(&data_len, skb_cmd->data, sizeof(__le16));
evt_len = le16_to_cpu(data_len);
-
+ skb_trim(skb_cmd, evt_len);
skb_pull(skb_cmd, INTF_HEADER_LEN);
- dev_dbg(adapter->dev, "info: Event length: %d\n", evt_len);
+ mwifiex_dbg(adapter, EVENT,
+ "info: Event length: %d\n", evt_len);
if ((evt_len > 0) && (evt_len < MAX_EVENT_SIZE))
memcpy(adapter->event_body, skb_cmd->data +
@@ -1740,8 +1766,8 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
} else {
if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
CPU_INTR_EVENT_DONE)) {
- dev_warn(adapter->dev,
- "Write register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Write register failed\n");
return -1;
}
}
@@ -1766,15 +1792,16 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
return 0;
if (rdptr >= MWIFIEX_MAX_EVT_BD) {
- dev_err(adapter->dev, "event_complete: Invalid rdptr 0x%x\n",
- rdptr);
+ mwifiex_dbg(adapter, ERROR,
+ "event_complete: Invalid rdptr 0x%x\n",
+ rdptr);
return -EINVAL;
}
/* Read the event ring write pointer set by firmware */
if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
- dev_err(adapter->dev,
- "event_complete: failed to read reg->evt_wrptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "event_complete: failed to read reg->evt_wrptr\n");
return -1;
}
@@ -1791,9 +1818,9 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
desc->flags = 0;
skb = NULL;
} else {
- dev_dbg(adapter->dev,
- "info: ERROR: buf still valid at index %d, <%p, %p>\n",
- rdptr, card->evt_buf_list[rdptr], skb);
+ mwifiex_dbg(adapter, ERROR,
+ "info: ERROR: buf still valid at index %d, <%p, %p>\n",
+ rdptr, card->evt_buf_list[rdptr], skb);
}
if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) {
@@ -1802,18 +1829,20 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
reg->evt_rollover_ind);
}
- dev_dbg(adapter->dev, "info: Updated <Rd: 0x%x, Wr: 0x%x>",
- card->evtbd_rdptr, wrptr);
+ mwifiex_dbg(adapter, EVENT,
+ "info: Updated <Rd: 0x%x, Wr: 0x%x>",
+ card->evtbd_rdptr, wrptr);
/* Write the event ring read pointer in to reg->evt_rdptr */
if (mwifiex_write_reg(adapter, reg->evt_rdptr,
card->evtbd_rdptr)) {
- dev_err(adapter->dev,
- "event_complete: failed to read reg->evt_rdptr\n");
+ mwifiex_dbg(adapter, ERROR,
+ "event_complete: failed to read reg->evt_rdptr\n");
return -1;
}
- dev_dbg(adapter->dev, "info: Check Events Again\n");
+ mwifiex_dbg(adapter, EVENT,
+ "info: Check Events Again\n");
ret = mwifiex_pcie_process_event_ready(adapter);
return ret;
@@ -1840,17 +1869,18 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
if (!firmware || !firmware_len) {
- dev_err(adapter->dev,
- "No firmware image found! Terminating download\n");
+ mwifiex_dbg(adapter, ERROR,
+ "No firmware image found! Terminating download\n");
return -1;
}
- dev_dbg(adapter->dev, "info: Downloading FW image (%d bytes)\n",
- firmware_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: Downloading FW image (%d bytes)\n",
+ firmware_len);
if (mwifiex_pcie_disable_host_int(adapter)) {
- dev_err(adapter->dev,
- "%s: Disabling interrupts failed.\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: Disabling interrupts failed.\n", __func__);
return -1;
}
@@ -1872,8 +1902,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
ret = mwifiex_read_reg(adapter, reg->cmd_size,
&len);
if (ret) {
- dev_warn(adapter->dev,
- "Failed reading len from boot code\n");
+ mwifiex_dbg(adapter, FATAL,
+ "Failed reading len from boot code\n");
goto done;
}
if (len)
@@ -1884,8 +1914,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
if (!len) {
break;
} else if (len > MWIFIEX_UPLD_SIZE) {
- pr_err("FW download failure @ %d, invalid length %d\n",
- offset, len);
+ mwifiex_dbg(adapter, ERROR,
+ "FW download failure @ %d, invalid length %d\n",
+ offset, len);
ret = -1;
goto done;
}
@@ -1895,14 +1926,16 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
if (len & BIT(0)) {
block_retry_cnt++;
if (block_retry_cnt > MAX_WRITE_IOMEM_RETRY) {
- pr_err("FW download failure @ %d, over max "
- "retry count\n", offset);
+ mwifiex_dbg(adapter, ERROR,
+ "FW download failure @ %d, over max\t"
+ "retry count\n", offset);
ret = -1;
goto done;
}
- dev_err(adapter->dev, "FW CRC error indicated by the "
- "helper: len = 0x%04X, txlen = %d\n",
- len, txlen);
+ mwifiex_dbg(adapter, ERROR,
+ "FW CRC error indicated by the\t"
+ "helper: len = 0x%04X, txlen = %d\n",
+ len, txlen);
len &= ~BIT(0);
/* Setting this to 0 to resend from same offset */
txlen = 0;
@@ -1913,7 +1946,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
if (firmware_len - offset < txlen)
txlen = firmware_len - offset;
- dev_dbg(adapter->dev, ".");
+ mwifiex_dbg(adapter, INFO, ".");
tx_blocks = (txlen + card->pcie.blksz_fw_dl - 1) /
card->pcie.blksz_fw_dl;
@@ -1927,8 +1960,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
/* Send the boot command to device */
if (mwifiex_pcie_send_boot_cmd(adapter, skb)) {
- dev_err(adapter->dev,
- "Failed to send firmware download command\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to send firmware download command\n");
ret = -1;
goto done;
}
@@ -1937,9 +1970,10 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
do {
if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS,
&ireg_intr)) {
- dev_err(adapter->dev, "%s: Failed to read "
- "interrupt status during fw dnld.\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: Failed to read\t"
+ "interrupt status during fw dnld.\n",
+ __func__);
mwifiex_unmap_pci_memory(adapter, skb,
PCI_DMA_TODEVICE);
ret = -1;
@@ -1953,8 +1987,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
offset += txlen;
} while (true);
- dev_notice(adapter->dev,
- "info: FW download over, size %d bytes\n", offset);
+ mwifiex_dbg(adapter, MSG,
+ "info: FW download over, size %d bytes\n", offset);
ret = 0;
@@ -1980,15 +2014,17 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
/* Mask spurios interrupts */
if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS_MASK,
HOST_INTR_MASK)) {
- dev_warn(adapter->dev, "Write register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Write register failed\n");
return -1;
}
- dev_dbg(adapter->dev, "Setting driver ready signature\n");
+ mwifiex_dbg(adapter, INFO,
+ "Setting driver ready signature\n");
if (mwifiex_write_reg(adapter, reg->drv_rdy,
FIRMWARE_READY_PCIE)) {
- dev_err(adapter->dev,
- "Failed to write driver ready signature\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write driver ready signature\n");
return -1;
}
@@ -2015,12 +2051,13 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
&winner_status))
ret = -1;
else if (!winner_status) {
- dev_err(adapter->dev, "PCI-E is the winner\n");
+ mwifiex_dbg(adapter, INFO,
+ "PCI-E is the winner\n");
adapter->winner = 1;
} else {
- dev_err(adapter->dev,
- "PCI-E is not the winner <%#x,%d>, exit dnld\n",
- ret, adapter->winner);
+ mwifiex_dbg(adapter, ERROR,
+ "PCI-E is not the winner <%#x,%d>, exit dnld\n",
+ ret, adapter->winner);
}
}
@@ -2039,7 +2076,7 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
return;
if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, &pcie_ireg)) {
- dev_warn(adapter->dev, "Read register failed\n");
+ mwifiex_dbg(adapter, ERROR, "Read register failed\n");
return;
}
@@ -2050,7 +2087,8 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
/* Clear the pending interrupts */
if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS,
~pcie_ireg)) {
- dev_warn(adapter->dev, "Write register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Write register failed\n");
return;
}
spin_lock_irqsave(&adapter->int_lock, flags);
@@ -2133,21 +2171,24 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
while (pcie_ireg & HOST_INTR_MASK) {
if (pcie_ireg & HOST_INTR_DNLD_DONE) {
pcie_ireg &= ~HOST_INTR_DNLD_DONE;
- dev_dbg(adapter->dev, "info: TX DNLD Done\n");
+ mwifiex_dbg(adapter, INTR,
+ "info: TX DNLD Done\n");
ret = mwifiex_pcie_send_data_complete(adapter);
if (ret)
return ret;
}
if (pcie_ireg & HOST_INTR_UPLD_RDY) {
pcie_ireg &= ~HOST_INTR_UPLD_RDY;
- dev_dbg(adapter->dev, "info: Rx DATA\n");
+ mwifiex_dbg(adapter, INTR,
+ "info: Rx DATA\n");
ret = mwifiex_pcie_process_recv_data(adapter);
if (ret)
return ret;
}
if (pcie_ireg & HOST_INTR_EVENT_RDY) {
pcie_ireg &= ~HOST_INTR_EVENT_RDY;
- dev_dbg(adapter->dev, "info: Rx EVENT\n");
+ mwifiex_dbg(adapter, INTR,
+ "info: Rx EVENT\n");
ret = mwifiex_pcie_process_event_ready(adapter);
if (ret)
return ret;
@@ -2156,8 +2197,8 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
if (pcie_ireg & HOST_INTR_CMD_DONE) {
pcie_ireg &= ~HOST_INTR_CMD_DONE;
if (adapter->cmd_sent) {
- dev_dbg(adapter->dev,
- "info: CMD sent Interrupt\n");
+ mwifiex_dbg(adapter, INTR,
+ "info: CMD sent Interrupt\n");
adapter->cmd_sent = false;
}
/* Handle command response */
@@ -2169,8 +2210,8 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
if (mwifiex_pcie_ok_to_access_hw(adapter)) {
if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
&pcie_ireg)) {
- dev_warn(adapter->dev,
- "Read register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Read register failed\n");
return -1;
}
@@ -2178,16 +2219,17 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
if (mwifiex_write_reg(adapter,
PCIE_HOST_INT_STATUS,
~pcie_ireg)) {
- dev_warn(adapter->dev,
- "Write register failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Write register failed\n");
return -1;
}
}
}
}
- dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
- adapter->cmd_sent, adapter->data_sent);
+ mwifiex_dbg(adapter, INTR,
+ "info: cmd_sent=%d data_sent=%d\n",
+ adapter->cmd_sent, adapter->data_sent);
if (adapter->ps_state != PS_STATE_SLEEP)
mwifiex_pcie_enable_host_int(adapter);
@@ -2209,7 +2251,8 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
struct mwifiex_tx_param *tx_param)
{
if (!skb) {
- dev_err(adapter->dev, "Passed NULL skb to %s\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "Passed NULL skb to %s\n", __func__);
return -1;
}
@@ -2232,7 +2275,8 @@ mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag)
ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl, FW_DUMP_HOST_READY);
if (ret) {
- dev_err(adapter->dev, "PCIE write err\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PCIE write err\n");
return RDWR_STATUS_FAILURE;
}
@@ -2243,24 +2287,25 @@ mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag)
if (doneflag && ctrl_data == doneflag)
return RDWR_STATUS_DONE;
if (ctrl_data != FW_DUMP_HOST_READY) {
- dev_info(adapter->dev,
- "The ctrl reg was changed, re-try again!\n");
+ mwifiex_dbg(adapter, WARN,
+ "The ctrl reg was changed, re-try again!\n");
ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl,
FW_DUMP_HOST_READY);
if (ret) {
- dev_err(adapter->dev, "PCIE write err\n");
+ mwifiex_dbg(adapter, ERROR,
+ "PCIE write err\n");
return RDWR_STATUS_FAILURE;
}
}
usleep_range(100, 200);
}
- dev_err(adapter->dev, "Fail to pull ctrl_data\n");
+ mwifiex_dbg(adapter, ERROR, "Fail to pull ctrl_data\n");
return RDWR_STATUS_FAILURE;
}
/* This function dump firmware memory to file */
-static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
+static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
const struct mwifiex_pcie_card_reg *creg = card->pcie.reg;
@@ -2269,7 +2314,6 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
enum rdwr_status stat;
u32 memory_size;
int ret;
- static char *env[] = { "DRIVER=mwifiex_pcie", "EVENT=fw_dump", NULL };
if (!card->pcie.can_dump_fw)
return;
@@ -2284,12 +2328,12 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
entry->mem_size = 0;
}
- dev_info(adapter->dev, "== mwifiex firmware dump start ==\n");
+ mwifiex_dbg(adapter, DUMP, "== mwifiex firmware dump start ==\n");
/* Read the number of the memories which will dump */
stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
if (stat == RDWR_STATUS_FAILURE)
- goto done;
+ return;
reg = creg->fw_dump_start;
mwifiex_read_reg_byte(adapter, reg, &dump_num);
@@ -2300,7 +2344,7 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
if (stat == RDWR_STATUS_FAILURE)
- goto done;
+ return;
memory_size = 0;
reg = creg->fw_dump_start;
@@ -2311,36 +2355,36 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
}
if (memory_size == 0) {
- dev_info(adapter->dev, "Firmware dump Finished!\n");
+ mwifiex_dbg(adapter, MSG, "Firmware dump Finished!\n");
ret = mwifiex_write_reg(adapter, creg->fw_dump_ctrl,
FW_DUMP_READ_DONE);
if (ret) {
- dev_err(adapter->dev, "PCIE write err\n");
- goto done;
+ mwifiex_dbg(adapter, ERROR, "PCIE write err\n");
+ return;
}
break;
}
- dev_info(adapter->dev,
- "%s_SIZE=0x%x\n", entry->mem_name, memory_size);
+ mwifiex_dbg(adapter, DUMP,
+ "%s_SIZE=0x%x\n", entry->mem_name, memory_size);
entry->mem_ptr = vmalloc(memory_size + 1);
entry->mem_size = memory_size;
if (!entry->mem_ptr) {
- dev_err(adapter->dev,
- "Vmalloc %s failed\n", entry->mem_name);
- goto done;
+ mwifiex_dbg(adapter, ERROR,
+ "Vmalloc %s failed\n", entry->mem_name);
+ return;
}
dbg_ptr = entry->mem_ptr;
end_ptr = dbg_ptr + memory_size;
doneflag = entry->done_flag;
- dev_info(adapter->dev, "Start %s output, please wait...\n",
- entry->mem_name);
+ mwifiex_dbg(adapter, DUMP, "Start %s output, please wait...\n",
+ entry->mem_name);
do {
stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
if (RDWR_STATUS_FAILURE == stat)
- goto done;
+ return;
reg_start = creg->fw_dump_start;
reg_end = creg->fw_dump_end;
@@ -2349,46 +2393,49 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
if (dbg_ptr < end_ptr) {
dbg_ptr++;
} else {
- dev_err(adapter->dev,
- "Allocated buf not enough\n");
- goto done;
+ mwifiex_dbg(adapter, ERROR,
+ "Allocated buf not enough\n");
+ return;
}
}
if (stat != RDWR_STATUS_DONE)
continue;
- dev_info(adapter->dev, "%s done: size=0x%tx\n",
- entry->mem_name, dbg_ptr - entry->mem_ptr);
+ mwifiex_dbg(adapter, DUMP,
+ "%s done: size=0x%tx\n",
+ entry->mem_name, dbg_ptr - entry->mem_ptr);
break;
} while (true);
}
- dev_info(adapter->dev, "== mwifiex firmware dump end ==\n");
-
- kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env);
+ mwifiex_dbg(adapter, DUMP, "== mwifiex firmware dump end ==\n");
+}
-done:
- adapter->curr_mem_idx = 0;
+static void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter)
+{
+ mwifiex_drv_info_dump(adapter);
+ mwifiex_pcie_fw_dump(adapter);
+ mwifiex_upload_device_dump(adapter);
}
static unsigned long iface_work_flags;
static struct mwifiex_adapter *save_adapter;
static void mwifiex_pcie_work(struct work_struct *work)
{
- if (test_and_clear_bit(MWIFIEX_IFACE_WORK_FW_DUMP,
+ if (test_and_clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
&iface_work_flags))
- mwifiex_pcie_fw_dump_work(save_adapter);
+ mwifiex_pcie_device_dump_work(save_adapter);
}
static DECLARE_WORK(pcie_work, mwifiex_pcie_work);
/* This function dumps FW information */
-static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
+static void mwifiex_pcie_device_dump(struct mwifiex_adapter *adapter)
{
save_adapter = adapter;
- if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags))
+ if (test_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &iface_work_flags))
return;
- set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags);
+ set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &iface_work_flags);
schedule_work(&pcie_work);
}
@@ -2418,45 +2465,50 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter)
pci_set_master(pdev);
- dev_dbg(adapter->dev, "try set_consistent_dma_mask(32)\n");
+ mwifiex_dbg(adapter, INFO,
+ "try set_consistent_dma_mask(32)\n");
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
- dev_err(adapter->dev, "set_dma_mask(32) failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "set_dma_mask(32) failed\n");
goto err_set_dma_mask;
}
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
- dev_err(adapter->dev, "set_consistent_dma_mask(64) failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "set_consistent_dma_mask(64) failed\n");
goto err_set_dma_mask;
}
ret = pci_request_region(pdev, 0, DRV_NAME);
if (ret) {
- dev_err(adapter->dev, "req_reg(0) error\n");
+ mwifiex_dbg(adapter, ERROR,
+ "req_reg(0) error\n");
goto err_req_region0;
}
card->pci_mmap = pci_iomap(pdev, 0, 0);
if (!card->pci_mmap) {
- dev_err(adapter->dev, "iomap(0) error\n");
+ mwifiex_dbg(adapter, ERROR, "iomap(0) error\n");
ret = -EIO;
goto err_iomap0;
}
ret = pci_request_region(pdev, 2, DRV_NAME);
if (ret) {
- dev_err(adapter->dev, "req_reg(2) error\n");
+ mwifiex_dbg(adapter, ERROR, "req_reg(2) error\n");
goto err_req_region2;
}
card->pci_mmap1 = pci_iomap(pdev, 2, 0);
if (!card->pci_mmap1) {
- dev_err(adapter->dev, "iomap(2) error\n");
+ mwifiex_dbg(adapter, ERROR,
+ "iomap(2) error\n");
ret = -EIO;
goto err_iomap2;
}
- dev_dbg(adapter->dev,
- "PCI memory map Virt0: %p PCI memory map Virt2: %p\n",
- card->pci_mmap, card->pci_mmap1);
+ mwifiex_dbg(adapter, INFO,
+ "PCI memory map Virt0: %p PCI memory map Virt2: %p\n",
+ card->pci_mmap, card->pci_mmap1);
card->cmdrsp_buf = NULL;
ret = mwifiex_pcie_create_txbd_ring(adapter);
@@ -2521,10 +2573,11 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
if (user_rmmod) {
- dev_dbg(adapter->dev, "Clearing driver ready signature\n");
+ mwifiex_dbg(adapter, INFO,
+ "Clearing driver ready signature\n");
if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000))
- dev_err(adapter->dev,
- "Failed to write driver not-ready signature\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to write driver not-ready signature\n");
}
if (pdev) {
@@ -2555,7 +2608,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED,
"MRVL_PCIE", pdev);
if (ret) {
- pr_err("request_irq failed: ret=%d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "request_irq failed: ret=%d\n", ret);
adapter->card = NULL;
return -1;
}
@@ -2582,7 +2636,8 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
const struct mwifiex_pcie_card_reg *reg;
if (card) {
- dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "%s(): calling free_irq()\n", __func__);
free_irq(card->dev->irq, card->dev);
reg = card->pcie.reg;
@@ -2617,7 +2672,7 @@ static struct mwifiex_if_ops pcie_ops = {
.cleanup_mpa_buf = NULL,
.init_fw_port = mwifiex_pcie_init_fw_port,
.clean_pcie_ring = mwifiex_clean_pcie_ring_buf,
- .fw_dump = mwifiex_pcie_fw_dump,
+ .device_dump = mwifiex_pcie_device_dump,
};
/*
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 0ffdb7c5afd2..baf9715ddc10 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -241,20 +241,21 @@ mwifiex_is_bss_wpa(struct mwifiex_private *priv,
* LinkSys WRT54G && bss_desc->privacy
*/
) {
- dev_dbg(priv->adapter->dev, "info: %s: WPA:"
- " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
- "EncMode=%#x privacy=%#x\n", __func__,
- (bss_desc->bcn_wpa_ie) ?
- (*(bss_desc->bcn_wpa_ie)).
- vend_hdr.element_id : 0,
- (bss_desc->bcn_rsn_ie) ?
- (*(bss_desc->bcn_rsn_ie)).
- ieee_hdr.element_id : 0,
- (priv->sec_info.wep_enabled) ? "e" : "d",
- (priv->sec_info.wpa_enabled) ? "e" : "d",
- (priv->sec_info.wpa2_enabled) ? "e" : "d",
- priv->sec_info.encryption_mode,
- bss_desc->privacy);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: %s: WPA:\t"
+ "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s\t"
+ "EncMode=%#x privacy=%#x\n", __func__,
+ (bss_desc->bcn_wpa_ie) ?
+ (*bss_desc->bcn_wpa_ie).
+ vend_hdr.element_id : 0,
+ (bss_desc->bcn_rsn_ie) ?
+ (*bss_desc->bcn_rsn_ie).
+ ieee_hdr.element_id : 0,
+ (priv->sec_info.wep_enabled) ? "e" : "d",
+ (priv->sec_info.wpa_enabled) ? "e" : "d",
+ (priv->sec_info.wpa2_enabled) ? "e" : "d",
+ priv->sec_info.encryption_mode,
+ bss_desc->privacy);
return true;
}
return false;
@@ -277,20 +278,21 @@ mwifiex_is_bss_wpa2(struct mwifiex_private *priv,
* Privacy bit may NOT be set in some APs like
* LinkSys WRT54G && bss_desc->privacy
*/
- dev_dbg(priv->adapter->dev, "info: %s: WPA2: "
- " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
- "EncMode=%#x privacy=%#x\n", __func__,
- (bss_desc->bcn_wpa_ie) ?
- (*(bss_desc->bcn_wpa_ie)).
- vend_hdr.element_id : 0,
- (bss_desc->bcn_rsn_ie) ?
- (*(bss_desc->bcn_rsn_ie)).
- ieee_hdr.element_id : 0,
- (priv->sec_info.wep_enabled) ? "e" : "d",
- (priv->sec_info.wpa_enabled) ? "e" : "d",
- (priv->sec_info.wpa2_enabled) ? "e" : "d",
- priv->sec_info.encryption_mode,
- bss_desc->privacy);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: %s: WPA2:\t"
+ "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s\t"
+ "EncMode=%#x privacy=%#x\n", __func__,
+ (bss_desc->bcn_wpa_ie) ?
+ (*bss_desc->bcn_wpa_ie).
+ vend_hdr.element_id : 0,
+ (bss_desc->bcn_rsn_ie) ?
+ (*bss_desc->bcn_rsn_ie).
+ ieee_hdr.element_id : 0,
+ (priv->sec_info.wep_enabled) ? "e" : "d",
+ (priv->sec_info.wpa_enabled) ? "e" : "d",
+ (priv->sec_info.wpa2_enabled) ? "e" : "d",
+ priv->sec_info.encryption_mode,
+ bss_desc->privacy);
return true;
}
return false;
@@ -333,18 +335,19 @@ mwifiex_is_bss_dynamic_wep(struct mwifiex_private *priv,
((!bss_desc->bcn_rsn_ie) ||
((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) &&
priv->sec_info.encryption_mode && bss_desc->privacy) {
- dev_dbg(priv->adapter->dev, "info: %s: dynamic "
- "WEP: wpa_ie=%#x wpa2_ie=%#x "
- "EncMode=%#x privacy=%#x\n",
- __func__,
- (bss_desc->bcn_wpa_ie) ?
- (*(bss_desc->bcn_wpa_ie)).
- vend_hdr.element_id : 0,
- (bss_desc->bcn_rsn_ie) ?
- (*(bss_desc->bcn_rsn_ie)).
- ieee_hdr.element_id : 0,
- priv->sec_info.encryption_mode,
- bss_desc->privacy);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: %s: dynamic\t"
+ "WEP: wpa_ie=%#x wpa2_ie=%#x\t"
+ "EncMode=%#x privacy=%#x\n",
+ __func__,
+ (bss_desc->bcn_wpa_ie) ?
+ (*bss_desc->bcn_wpa_ie).
+ vend_hdr.element_id : 0,
+ (bss_desc->bcn_rsn_ie) ?
+ (*bss_desc->bcn_rsn_ie).
+ ieee_hdr.element_id : 0,
+ priv->sec_info.encryption_mode,
+ bss_desc->privacy);
return true;
}
return false;
@@ -383,19 +386,20 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
return 0;
if (priv->wps.session_enable) {
- dev_dbg(adapter->dev,
- "info: return success directly in WPS period\n");
+ mwifiex_dbg(adapter, IOCTL,
+ "info: return success directly in WPS period\n");
return 0;
}
if (bss_desc->chan_sw_ie_present) {
- dev_err(adapter->dev,
- "Don't connect to AP with WLAN_EID_CHANNEL_SWITCH\n");
+ mwifiex_dbg(adapter, INFO,
+ "Don't connect to AP with WLAN_EID_CHANNEL_SWITCH\n");
return -1;
}
if (mwifiex_is_bss_wapi(priv, bss_desc)) {
- dev_dbg(adapter->dev, "info: return success for WAPI AP\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: return success for WAPI AP\n");
return 0;
}
@@ -405,7 +409,8 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
return 0;
} else if (mwifiex_is_bss_static_wep(priv, bss_desc)) {
/* Static WEP enabled */
- dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Disable 11n in WEP mode.\n");
bss_desc->disable_11n = true;
return 0;
} else if (mwifiex_is_bss_wpa(priv, bss_desc)) {
@@ -418,9 +423,9 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
if (mwifiex_is_wpa_oui_present
(bss_desc, CIPHER_SUITE_TKIP)) {
- dev_dbg(adapter->dev,
- "info: Disable 11n if AES "
- "is not supported by AP\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Disable 11n if AES\t"
+ "is not supported by AP\n");
bss_desc->disable_11n = true;
} else {
return -1;
@@ -437,9 +442,9 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
if (mwifiex_is_rsn_oui_present
(bss_desc, CIPHER_SUITE_TKIP)) {
- dev_dbg(adapter->dev,
- "info: Disable 11n if AES "
- "is not supported by AP\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Disable 11n if AES\t"
+ "is not supported by AP\n");
bss_desc->disable_11n = true;
} else {
return -1;
@@ -455,17 +460,18 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
}
/* Security doesn't match */
- dev_dbg(adapter->dev,
- "info: %s: failed: wpa_ie=%#x wpa2_ie=%#x WEP=%s "
- "WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n", __func__,
- (bss_desc->bcn_wpa_ie) ?
- (*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id : 0,
- (bss_desc->bcn_rsn_ie) ?
- (*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id : 0,
- (priv->sec_info.wep_enabled) ? "e" : "d",
- (priv->sec_info.wpa_enabled) ? "e" : "d",
- (priv->sec_info.wpa2_enabled) ? "e" : "d",
- priv->sec_info.encryption_mode, bss_desc->privacy);
+ mwifiex_dbg(adapter, ERROR,
+ "info: %s: failed: wpa_ie=%#x wpa2_ie=%#x WEP=%s\t"
+ "WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n",
+ __func__,
+ (bss_desc->bcn_wpa_ie) ?
+ (*bss_desc->bcn_wpa_ie).vend_hdr.element_id : 0,
+ (bss_desc->bcn_rsn_ie) ?
+ (*bss_desc->bcn_rsn_ie).ieee_hdr.element_id : 0,
+ (priv->sec_info.wep_enabled) ? "e" : "d",
+ (priv->sec_info.wpa_enabled) ? "e" : "d",
+ (priv->sec_info.wpa2_enabled) ? "e" : "d",
+ priv->sec_info.encryption_mode, bss_desc->privacy);
return -1;
}
@@ -560,7 +566,8 @@ mwifiex_append_rate_tlv(struct mwifiex_private *priv,
else
rates_size = mwifiex_get_supported_rates(priv, rates);
- dev_dbg(priv->adapter->dev, "info: SCAN_CMD: Rates size = %d\n",
+ mwifiex_dbg(priv->adapter, CMD,
+ "info: SCAN_CMD: Rates size = %d\n",
rates_size);
rates_tlv = (struct mwifiex_ie_types_rates_param_set *)tlv_pos;
rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
@@ -600,9 +607,9 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
u8 radio_type;
if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) {
- dev_dbg(priv->adapter->dev,
- "info: Scan: Null detect: %p, %p, %p\n",
- scan_cfg_out, chan_tlv_out, scan_chan_list);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "info: Scan: Null detect: %p, %p, %p\n",
+ scan_cfg_out, chan_tlv_out, scan_chan_list);
return -1;
}
@@ -645,16 +652,16 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
}
radio_type = tmp_chan_list->radio_type;
- dev_dbg(priv->adapter->dev,
- "info: Scan: Chan(%3d), Radio(%d),"
- " Mode(%d, %d), Dur(%d)\n",
- tmp_chan_list->chan_number,
- tmp_chan_list->radio_type,
- tmp_chan_list->chan_scan_mode_bitmap
- & MWIFIEX_PASSIVE_SCAN,
- (tmp_chan_list->chan_scan_mode_bitmap
- & MWIFIEX_DISABLE_CHAN_FILT) >> 1,
- le16_to_cpu(tmp_chan_list->max_scan_time));
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: Scan: Chan(%3d), Radio(%d),\t"
+ "Mode(%d, %d), Dur(%d)\n",
+ tmp_chan_list->chan_number,
+ tmp_chan_list->radio_type,
+ tmp_chan_list->chan_scan_mode_bitmap
+ & MWIFIEX_PASSIVE_SCAN,
+ (tmp_chan_list->chan_scan_mode_bitmap
+ & MWIFIEX_DISABLE_CHAN_FILT) >> 1,
+ le16_to_cpu(tmp_chan_list->max_scan_time));
/* Copy the current channel TLV to the command being
prepared */
@@ -718,9 +725,11 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
/* The total scan time should be less than scan command timeout
value */
if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) {
- dev_err(priv->adapter->dev, "total scan time %dms"
- " is over limit (%dms), scan skipped\n",
- total_scan_time, MWIFIEX_MAX_TOTAL_SCAN_TIME);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "total scan time %dms\t"
+ "is over limit (%dms), scan skipped\n",
+ total_scan_time,
+ MWIFIEX_MAX_TOTAL_SCAN_TIME);
ret = -1;
break;
}
@@ -905,9 +914,10 @@ mwifiex_config_scan(struct mwifiex_private *priv,
tlv_pos += (sizeof(wildcard_ssid_tlv->header)
+ le16_to_cpu(wildcard_ssid_tlv->header.len));
- dev_dbg(adapter->dev, "info: scan: ssid[%d]: %s, %d\n",
- i, wildcard_ssid_tlv->ssid,
- wildcard_ssid_tlv->max_ssid_length);
+ mwifiex_dbg(adapter, INFO,
+ "info: scan: ssid[%d]: %s, %d\n",
+ i, wildcard_ssid_tlv->ssid,
+ wildcard_ssid_tlv->max_ssid_length);
/* Empty wildcard ssid with a maxlen will match many or
potentially all SSIDs (maxlen == 32), therefore do
@@ -928,8 +938,9 @@ mwifiex_config_scan(struct mwifiex_private *priv,
*filtered_scan = true;
if (user_scan_in->scan_chan_gap) {
- dev_dbg(adapter->dev, "info: scan: channel gap = %d\n",
- user_scan_in->scan_chan_gap);
+ mwifiex_dbg(adapter, INFO,
+ "info: scan: channel gap = %d\n",
+ user_scan_in->scan_chan_gap);
*max_chan_per_scan =
MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
@@ -961,8 +972,9 @@ mwifiex_config_scan(struct mwifiex_private *priv,
add tlv */
if (num_probes) {
- dev_dbg(adapter->dev, "info: scan: num_probes = %d\n",
- num_probes);
+ mwifiex_dbg(adapter, INFO,
+ "info: scan: num_probes = %d\n",
+ num_probes);
num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos;
num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
@@ -1003,7 +1015,8 @@ mwifiex_config_scan(struct mwifiex_private *priv,
if (user_scan_in && user_scan_in->chan_list[0].chan_number) {
- dev_dbg(adapter->dev, "info: Scan: Using supplied channel list\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Scan: Using supplied channel list\n");
for (chan_idx = 0;
chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX &&
@@ -1056,13 +1069,13 @@ mwifiex_config_scan(struct mwifiex_private *priv,
(user_scan_in->chan_list[0].chan_number ==
priv->curr_bss_params.bss_descriptor.channel)) {
*scan_current_only = true;
- dev_dbg(adapter->dev,
- "info: Scan: Scanning current channel only\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Scan: Scanning current channel only\n");
}
chan_num = chan_idx;
} else {
- dev_dbg(adapter->dev,
- "info: Scan: Creating full region channel list\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Scan: Creating full region channel list\n");
chan_num = mwifiex_scan_create_channel_list(priv, user_scan_in,
scan_chan_list,
*filtered_scan);
@@ -1094,8 +1107,9 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
tlv_buf_left = tlv_buf_size;
*tlv_data = NULL;
- dev_dbg(adapter->dev, "info: SCAN_RESP: tlv_buf_size = %d\n",
- tlv_buf_size);
+ mwifiex_dbg(adapter, INFO,
+ "info: SCAN_RESP: tlv_buf_size = %d\n",
+ tlv_buf_size);
while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) {
@@ -1103,26 +1117,31 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
tlv_len = le16_to_cpu(current_tlv->header.len);
if (sizeof(tlv->header) + tlv_len > tlv_buf_left) {
- dev_err(adapter->dev, "SCAN_RESP: TLV buffer corrupt\n");
+ mwifiex_dbg(adapter, ERROR,
+ "SCAN_RESP: TLV buffer corrupt\n");
break;
}
if (req_tlv_type == tlv_type) {
switch (tlv_type) {
case TLV_TYPE_TSFTIMESTAMP:
- dev_dbg(adapter->dev, "info: SCAN_RESP: TSF "
- "timestamp TLV, len = %d\n", tlv_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: SCAN_RESP: TSF\t"
+ "timestamp TLV, len = %d\n",
+ tlv_len);
*tlv_data = current_tlv;
break;
case TLV_TYPE_CHANNELBANDLIST:
- dev_dbg(adapter->dev, "info: SCAN_RESP: channel"
- " band list TLV, len = %d\n", tlv_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: SCAN_RESP: channel\t"
+ "band list TLV, len = %d\n",
+ tlv_len);
*tlv_data = current_tlv;
break;
default:
- dev_err(adapter->dev,
- "SCAN_RESP: unhandled TLV = %d\n",
- tlv_type);
+ mwifiex_dbg(adapter, ERROR,
+ "SCAN_RESP: unhandled TLV = %d\n",
+ tlv_type);
/* Give up, this seems corrupted */
return;
}
@@ -1177,8 +1196,9 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
total_ie_len = element_len + sizeof(struct ieee_types_header);
if (bytes_left < total_ie_len) {
- dev_err(adapter->dev, "err: InterpretIE: in processing"
- " IE, bytes left < IE length\n");
+ mwifiex_dbg(adapter, ERROR,
+ "err: InterpretIE: in processing\t"
+ "IE, bytes left < IE length\n");
return -1;
}
switch (element_id) {
@@ -1186,9 +1206,9 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
bss_entry->ssid.ssid_len = element_len;
memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
element_len);
- dev_dbg(adapter->dev,
- "info: InterpretIE: ssid: %-32s\n",
- bss_entry->ssid.ssid);
+ mwifiex_dbg(adapter, INFO,
+ "info: InterpretIE: ssid: %-32s\n",
+ bss_entry->ssid.ssid);
break;
case WLAN_EID_SUPP_RATES:
@@ -1419,19 +1439,20 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
unsigned long flags;
if (adapter->scan_processing) {
- dev_err(adapter->dev, "cmd: Scan already in process...\n");
+ mwifiex_dbg(adapter, WARN,
+ "cmd: Scan already in process...\n");
return -EBUSY;
}
if (priv->scan_block) {
- dev_err(adapter->dev,
- "cmd: Scan is blocked during association...\n");
+ mwifiex_dbg(adapter, WARN,
+ "cmd: Scan is blocked during association...\n");
return -EBUSY;
}
if (adapter->surprise_removed || adapter->is_cmd_timedout) {
- dev_err(adapter->dev,
- "Ignore scan. Card removed or firmware in bad state\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Ignore scan. Card removed or firmware in bad state\n");
return -EFAULT;
}
@@ -1478,7 +1499,8 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
/* Perform internal scan synchronously */
if (!priv->scan_request) {
- dev_dbg(adapter->dev, "wait internal scan\n");
+ mwifiex_dbg(adapter, INFO,
+ "wait internal scan\n");
mwifiex_wait_queue_complete(adapter, cmd_node);
}
} else {
@@ -1553,8 +1575,8 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
ret = mwifiex_is_network_compatible(priv, bss_desc,
priv->bss_mode);
if (ret)
- dev_err(priv->adapter->dev,
- "Incompatible network settings\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Incompatible network settings\n");
break;
default:
ret = 0;
@@ -1656,7 +1678,8 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
*/
if (curr_bcn_bytes < ETH_ALEN + sizeof(u8) +
sizeof(struct mwifiex_fixed_bcn_param)) {
- dev_err(adapter->dev, "InterpretIE: not enough bytes left\n");
+ mwifiex_dbg(adapter, ERROR,
+ "InterpretIE: not enough bytes left\n");
return -EFAULT;
}
@@ -1669,7 +1692,8 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
rssi = (-rssi) * 100; /* Convert dBm to mBm */
current_ptr += sizeof(u8);
curr_bcn_bytes -= sizeof(u8);
- dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%d\n", rssi);
+ mwifiex_dbg(adapter, INFO,
+ "info: InterpretIE: RSSI=%d\n", rssi);
} else {
rssi = rssi_val;
}
@@ -1682,14 +1706,16 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
beacon_period = le16_to_cpu(bcn_param->beacon_period);
cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap);
- dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n",
- cap_info_bitmap);
+ mwifiex_dbg(adapter, INFO,
+ "info: InterpretIE: capabilities=0x%X\n",
+ cap_info_bitmap);
/* Rest of the current buffer are IE's */
ie_buf = current_ptr;
ie_len = curr_bcn_bytes;
- dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n",
- curr_bcn_bytes);
+ mwifiex_dbg(adapter, INFO,
+ "info: InterpretIE: IELength for this AP = %d\n",
+ curr_bcn_bytes);
while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) {
u8 element_id, element_len;
@@ -1698,8 +1724,8 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
element_len = *(current_ptr + 1);
if (curr_bcn_bytes < element_len +
sizeof(struct ieee_types_header)) {
- dev_err(adapter->dev,
- "%s: bytes left < IE length\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: bytes left < IE length\n", __func__);
return -EFAULT;
}
if (element_id == WLAN_EID_DS_PARAMS) {
@@ -1719,8 +1745,8 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
/* Skip entry if on csa closed channel */
if (channel == priv->csa_chan) {
- dev_dbg(adapter->dev,
- "Dropping entry on csa closed channel\n");
+ mwifiex_dbg(adapter, WARN,
+ "Dropping entry on csa closed channel\n");
return 0;
}
@@ -1751,7 +1777,7 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
cfg80211_put_bss(priv->wdev.wiphy, bss);
}
} else {
- dev_dbg(adapter->dev, "missing BSS channel IE\n");
+ mwifiex_dbg(adapter, WARN, "missing BSS channel IE\n");
}
return 0;
@@ -1765,7 +1791,8 @@ static void mwifiex_complete_scan(struct mwifiex_private *priv)
if (adapter->curr_cmd->wait_q_enabled) {
adapter->cmd_wait_q.status = 0;
if (!priv->scan_request) {
- dev_dbg(adapter->dev, "complete internal scan\n");
+ mwifiex_dbg(adapter, INFO,
+ "complete internal scan\n");
mwifiex_complete_cmd(adapter, adapter->curr_cmd);
}
}
@@ -1788,12 +1815,14 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
mwifiex_complete_scan(priv);
if (priv->scan_request) {
- dev_dbg(adapter->dev, "info: notifying scan done\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: notifying scan done\n");
cfg80211_scan_done(priv->scan_request, 0);
priv->scan_request = NULL;
} else {
priv->scan_aborting = false;
- dev_dbg(adapter->dev, "info: scan already aborted\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: scan already aborted\n");
}
} else if ((priv->scan_aborting && !priv->scan_request) ||
priv->scan_block) {
@@ -1809,12 +1838,14 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
if (priv->scan_request) {
- dev_dbg(adapter->dev, "info: aborting scan\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: aborting scan\n");
cfg80211_scan_done(priv->scan_request, 1);
priv->scan_request = NULL;
} else {
priv->scan_aborting = false;
- dev_dbg(adapter->dev, "info: scan already aborted\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: scan already aborted\n");
}
} else {
/* Get scan command from scan_pending_q and put to
@@ -1877,8 +1908,9 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) {
- dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n",
- scan_rsp->number_of_sets);
+ mwifiex_dbg(adapter, ERROR,
+ "SCAN_RESP: too many AP returned (%d)\n",
+ scan_rsp->number_of_sets);
ret = -1;
goto check_next_scan;
}
@@ -1887,14 +1919,15 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
mwifiex_11h_get_csa_closed_channel(priv);
bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
- dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n",
- bytes_left);
+ mwifiex_dbg(adapter, INFO,
+ "info: SCAN_RESP: bss_descript_size %d\n",
+ bytes_left);
scan_resp_size = le16_to_cpu(resp->size);
- dev_dbg(adapter->dev,
- "info: SCAN_RESP: returned %d APs before parsing\n",
- scan_rsp->number_of_sets);
+ mwifiex_dbg(adapter, INFO,
+ "info: SCAN_RESP: returned %d APs before parsing\n",
+ scan_rsp->number_of_sets);
bss_info = scan_rsp->bss_desc_and_tlv_buffer;
@@ -2007,13 +2040,13 @@ mwifiex_update_chan_statistics(struct mwifiex_private *priv,
le16_to_cpu(fw_chan_stats->cca_scan_dur);
chan_stats.cca_busy_dur =
le16_to_cpu(fw_chan_stats->cca_busy_dur);
- dev_dbg(adapter->dev,
- "chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n",
- chan_stats.chan_num,
- chan_stats.noise,
- chan_stats.total_bss,
- chan_stats.cca_scan_dur,
- chan_stats.cca_busy_dur);
+ mwifiex_dbg(adapter, INFO,
+ "chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n",
+ chan_stats.chan_num,
+ chan_stats.noise,
+ chan_stats.total_bss,
+ chan_stats.cca_scan_dur,
+ chan_stats.cca_busy_dur);
memcpy(&adapter->chan_stats[adapter->survey_idx++], &chan_stats,
sizeof(struct mwifiex_chan_stats));
fw_chan_stats++;
@@ -2035,7 +2068,7 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
unsigned long cmd_flags, scan_flags;
bool complete_scan = false;
- dev_dbg(priv->adapter->dev, "info: EXT scan returns successfully\n");
+ mwifiex_dbg(adapter, INFO, "info: EXT scan returns successfully\n");
ext_scan_resp = &resp->params.ext_scan;
@@ -2048,8 +2081,8 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
len = le16_to_cpu(tlv->len);
if (buf_left < (sizeof(struct mwifiex_ie_types_header) + len)) {
- dev_err(adapter->dev,
- "error processing scan response TLVs");
+ mwifiex_dbg(adapter, ERROR,
+ "error processing scan response TLVs");
break;
}
@@ -2075,8 +2108,8 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
cmd_ptr = (void *)cmd_node->cmd_skb->data;
if (le16_to_cpu(cmd_ptr->command) ==
HostCmd_CMD_802_11_SCAN_EXT) {
- dev_dbg(priv->adapter->dev,
- "Scan pending in command pending list");
+ mwifiex_dbg(adapter, INFO,
+ "Scan pending in command pending list");
complete_scan = false;
break;
}
@@ -2114,17 +2147,20 @@ int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
u16 scan_resp_size = le16_to_cpu(event_scan->buf_size);
if (num_of_set > MWIFIEX_MAX_AP) {
- dev_err(adapter->dev,
- "EXT_SCAN: Invalid number of AP returned (%d)!!\n",
- num_of_set);
+ mwifiex_dbg(adapter, ERROR,
+ "EXT_SCAN: Invalid number of AP returned (%d)!!\n",
+ num_of_set);
ret = -1;
goto check_next_scan;
}
bytes_left = scan_resp_size;
- dev_dbg(adapter->dev,
- "EXT_SCAN: size %d, returned %d APs...",
- scan_resp_size, num_of_set);
+ mwifiex_dbg(adapter, INFO,
+ "EXT_SCAN: size %d, returned %d APs...",
+ scan_resp_size, num_of_set);
+ mwifiex_dbg_dump(adapter, CMD_D, "EXT_SCAN buffer:", buf,
+ scan_resp_size +
+ sizeof(struct mwifiex_event_scan_result));
tlv = (struct mwifiex_ie_types_data *)scan_resp;
@@ -2132,7 +2168,8 @@ int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
type = le16_to_cpu(tlv->header.type);
len = le16_to_cpu(tlv->header.len);
if (bytes_left < sizeof(struct mwifiex_ie_types_header) + len) {
- dev_err(adapter->dev, "EXT_SCAN: Error bytes left < TLV length\n");
+ mwifiex_dbg(adapter, ERROR,
+ "EXT_SCAN: Error bytes left < TLV length\n");
break;
}
scan_rsp_tlv = NULL;
@@ -2158,8 +2195,9 @@ int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
len = le16_to_cpu(tlv->header.len);
if (bytes_left_for_tlv <
sizeof(struct mwifiex_ie_types_header) + len) {
- dev_err(adapter->dev,
- "EXT_SCAN: Error in processing TLV, bytes left < TLV length\n");
+ mwifiex_dbg(adapter, ERROR,
+ "EXT_SCAN: Error in processing TLV,\t"
+ "bytes left < TLV length\n");
scan_rsp_tlv = NULL;
bytes_left_for_tlv = 0;
continue;
@@ -2199,8 +2237,8 @@ int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
if (scan_info_tlv) {
rssi = (s32)(s16)(le16_to_cpu(scan_info_tlv->rssi));
rssi *= 100; /* Convert dBm to mBm */
- dev_dbg(adapter->dev,
- "info: InterpretIE: RSSI=%d\n", rssi);
+ mwifiex_dbg(adapter, INFO,
+ "info: InterpretIE: RSSI=%d\n", rssi);
fw_tsf = le64_to_cpu(scan_info_tlv->tsf);
radio_type = &scan_info_tlv->radio_type;
} else {
@@ -2271,13 +2309,14 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
struct mwifiex_user_scan_cfg *scan_cfg;
if (adapter->scan_processing) {
- dev_err(adapter->dev, "cmd: Scan already in process...\n");
+ mwifiex_dbg(adapter, WARN,
+ "cmd: Scan already in process...\n");
return -EBUSY;
}
if (priv->scan_block) {
- dev_err(adapter->dev,
- "cmd: Scan is blocked during association...\n");
+ mwifiex_dbg(adapter, WARN,
+ "cmd: Scan is blocked during association...\n");
return -EBUSY;
}
@@ -2309,8 +2348,9 @@ int mwifiex_request_scan(struct mwifiex_private *priv,
int ret;
if (down_interruptible(&priv->async_sem)) {
- dev_err(priv->adapter->dev, "%s: acquire semaphore\n",
- __func__);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "%s: acquire semaphore fail\n",
+ __func__);
return -1;
}
@@ -2400,8 +2440,9 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf,
curr_bss->beacon_buf_size);
- dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n",
- priv->curr_bcn_size);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: current beacon saved %d\n",
+ priv->curr_bcn_size);
curr_bss->beacon_buf = priv->curr_bcn_buf;
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index d10320f89bc1..a0b121f3460c 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -166,7 +166,8 @@ static int mwifiex_sdio_resume(struct device *dev)
adapter = card->adapter;
if (!adapter->is_suspended) {
- dev_warn(adapter->dev, "device already resumed\n");
+ mwifiex_dbg(adapter, WARN,
+ "device already resumed\n");
return 0;
}
@@ -191,8 +192,6 @@ mwifiex_sdio_remove(struct sdio_func *func)
struct mwifiex_adapter *adapter;
struct mwifiex_private *priv;
- pr_debug("info: SDIO func num=%d\n", func->num);
-
card = sdio_get_drvdata(func);
if (!card)
return;
@@ -201,6 +200,8 @@ mwifiex_sdio_remove(struct sdio_func *func)
if (!adapter || !adapter->priv_num)
return;
+ mwifiex_dbg(adapter, INFO, "info: SDIO func num=%d\n", func->num);
+
if (user_rmmod) {
if (adapter->is_suspended)
mwifiex_sdio_resume(adapter->dev);
@@ -257,12 +258,14 @@ static int mwifiex_sdio_suspend(struct device *dev)
/* Enable the Host Sleep */
if (!mwifiex_enable_hs(adapter)) {
- dev_err(adapter->dev, "cmd: failed to suspend\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cmd: failed to suspend\n");
adapter->hs_enabling = false;
return -EFAULT;
}
- dev_dbg(adapter->dev, "cmd: suspend with MMC_PM_KEEP_POWER\n");
+ mwifiex_dbg(adapter, INFO,
+ "cmd: suspend with MMC_PM_KEEP_POWER\n");
ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
/* Indicate device suspended */
@@ -386,8 +389,8 @@ mwifiex_write_data_sync(struct mwifiex_adapter *adapter,
u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK);
if (adapter->is_suspended) {
- dev_err(adapter->dev,
- "%s: not allowed while suspended\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: not allowed while suspended\n", __func__);
return -1;
}
@@ -434,7 +437,8 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer,
*/
static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
{
- dev_dbg(adapter->dev, "event: wakeup device...\n");
+ mwifiex_dbg(adapter, EVENT,
+ "event: wakeup device...\n");
return mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP);
}
@@ -446,7 +450,8 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
*/
static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
{
- dev_dbg(adapter->dev, "cmd: wakeup device completed\n");
+ mwifiex_dbg(adapter, EVENT,
+ "cmd: wakeup device completed\n");
return mwifiex_write_reg(adapter, CONFIGURATION_REG, 0);
}
@@ -524,7 +529,8 @@ static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter)
else
return -1;
cont:
- pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport);
+ mwifiex_dbg(adapter, INFO,
+ "info: SDIO FUNC1 IO port: %#x\n", adapter->ioport);
/* Set Host interrupt reset to read to clear */
if (!mwifiex_read_reg(adapter, card->reg->host_int_rsr_reg, &reg))
@@ -556,10 +562,12 @@ static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter,
ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port);
if (ret) {
i++;
- dev_err(adapter->dev, "host_to_card, write iomem"
- " (%d) failed: %d\n", i, ret);
+ mwifiex_dbg(adapter, ERROR,
+ "host_to_card, write iomem\t"
+ "(%d) failed: %d\n", i, ret);
if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04))
- dev_err(adapter->dev, "write CFG reg failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "write CFG reg failed\n");
ret = -1;
if (i > MAX_WRITE_IOMEM_RETRY)
@@ -584,7 +592,8 @@ static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port)
const struct mwifiex_sdio_card_reg *reg = card->reg;
u32 rd_bitmap = card->mp_rd_bitmap;
- dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%08x\n", rd_bitmap);
+ mwifiex_dbg(adapter, DATA,
+ "data: mp_rd_bitmap=0x%08x\n", rd_bitmap);
if (card->supports_sdio_new_mode) {
if (!(rd_bitmap & reg->data_port_mask))
@@ -598,8 +607,9 @@ static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port)
(card->mp_rd_bitmap & CTRL_PORT_MASK)) {
card->mp_rd_bitmap &= (u32) (~CTRL_PORT_MASK);
*port = CTRL_PORT;
- dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%08x\n",
- *port, card->mp_rd_bitmap);
+ mwifiex_dbg(adapter, DATA,
+ "data: port=%d mp_rd_bitmap=0x%08x\n",
+ *port, card->mp_rd_bitmap);
return 0;
}
@@ -613,9 +623,9 @@ static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port)
if (++card->curr_rd_port == card->max_ports)
card->curr_rd_port = reg->start_rd_port;
- dev_dbg(adapter->dev,
- "data: port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n",
- *port, rd_bitmap, card->mp_rd_bitmap);
+ mwifiex_dbg(adapter, DATA,
+ "data: port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n",
+ *port, rd_bitmap, card->mp_rd_bitmap);
return 0;
}
@@ -633,7 +643,8 @@ static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u32 *port)
const struct mwifiex_sdio_card_reg *reg = card->reg;
u32 wr_bitmap = card->mp_wr_bitmap;
- dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%08x\n", wr_bitmap);
+ mwifiex_dbg(adapter, DATA,
+ "data: mp_wr_bitmap=0x%08x\n", wr_bitmap);
if (!(wr_bitmap & card->mp_data_port_mask)) {
adapter->data_sent = true;
@@ -651,15 +662,16 @@ static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u32 *port)
}
if ((card->has_control_mask) && (*port == CTRL_PORT)) {
- dev_err(adapter->dev,
- "invalid data port=%d cur port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
- *port, card->curr_wr_port, wr_bitmap,
- card->mp_wr_bitmap);
+ mwifiex_dbg(adapter, ERROR,
+ "invalid data port=%d cur port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
+ *port, card->curr_wr_port, wr_bitmap,
+ card->mp_wr_bitmap);
return -1;
}
- dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
- *port, wr_bitmap, card->mp_wr_bitmap);
+ mwifiex_dbg(adapter, DATA,
+ "data: port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
+ *port, wr_bitmap, card->mp_wr_bitmap);
return 0;
}
@@ -683,7 +695,8 @@ mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits)
usleep_range(10, 20);
}
- dev_err(adapter->dev, "poll card status failed, tries = %d\n", tries);
+ mwifiex_dbg(adapter, ERROR,
+ "poll card status failed, tries = %d\n", tries);
return -1;
}
@@ -738,7 +751,7 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
if (mwifiex_read_data_sync(adapter, card->mp_regs,
card->reg->max_mp_regs,
REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) {
- dev_err(adapter->dev, "read mp_regs failed\n");
+ mwifiex_dbg(adapter, ERROR, "read mp_regs failed\n");
return;
}
@@ -751,7 +764,8 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
* UP_LD_CMD_PORT_HOST_INT_STATUS
* Clear the interrupt status register
*/
- dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg);
+ mwifiex_dbg(adapter, INTR,
+ "int: sdio_ireg = %#x\n", sdio_ireg);
spin_lock_irqsave(&adapter->int_lock, flags);
adapter->int_status |= sdio_ireg;
spin_unlock_irqrestore(&adapter->int_lock, flags);
@@ -802,7 +816,8 @@ static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
/* Request the SDIO IRQ */
ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
if (ret) {
- dev_err(adapter->dev, "claim irq failed: ret=%d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "claim irq failed: ret=%d\n", ret);
goto out;
}
@@ -810,7 +825,8 @@ static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
ret = mwifiex_write_reg_locked(func, card->reg->host_int_mask_reg,
card->reg->host_int_enable);
if (ret) {
- dev_err(adapter->dev, "enable host interrupt failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "enable host interrupt failed\n");
sdio_release_irq(func);
}
@@ -830,22 +846,25 @@ static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter,
u32 nb;
if (!buffer) {
- dev_err(adapter->dev, "%s: buffer is NULL\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: buffer is NULL\n", __func__);
return -1;
}
ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 1);
if (ret) {
- dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__,
+ mwifiex_dbg(adapter, ERROR,
+ "%s: read iomem failed: %d\n", __func__,
ret);
return -1;
}
nb = le16_to_cpu(*(__le16 *) (buffer));
if (nb > npayload) {
- dev_err(adapter->dev, "%s: invalid packet, nb=%d npayload=%d\n",
- __func__, nb, npayload);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: invalid packet, nb=%d npayload=%d\n",
+ __func__, nb, npayload);
return -1;
}
@@ -877,13 +896,14 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
u32 i = 0;
if (!firmware_len) {
- dev_err(adapter->dev,
- "firmware image not found! Terminating download\n");
+ mwifiex_dbg(adapter, ERROR,
+ "firmware image not found! Terminating download\n");
return -1;
}
- dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n",
- firmware_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: downloading FW image (%d bytes)\n",
+ firmware_len);
/* Assume that the allocated buffer is 8-byte aligned */
fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL);
@@ -897,8 +917,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY |
DN_LD_CARD_RDY);
if (ret) {
- dev_err(adapter->dev, "FW download with helper:"
- " poll status timeout @ %d\n", offset);
+ mwifiex_dbg(adapter, ERROR,
+ "FW download with helper:\t"
+ "poll status timeout @ %d\n", offset);
goto done;
}
@@ -910,19 +931,19 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
ret = mwifiex_read_reg(adapter, reg->base_0_reg,
&base0);
if (ret) {
- dev_err(adapter->dev,
- "dev BASE0 register read failed: "
- "base0=%#04X(%d). Terminating dnld\n",
- base0, base0);
+ mwifiex_dbg(adapter, ERROR,
+ "dev BASE0 register read failed:\t"
+ "base0=%#04X(%d). Terminating dnld\n",
+ base0, base0);
goto done;
}
ret = mwifiex_read_reg(adapter, reg->base_1_reg,
&base1);
if (ret) {
- dev_err(adapter->dev,
- "dev BASE1 register read failed: "
- "base1=%#04X(%d). Terminating dnld\n",
- base1, base1);
+ mwifiex_dbg(adapter, ERROR,
+ "dev BASE1 register read failed:\t"
+ "base1=%#04X(%d). Terminating dnld\n",
+ base1, base1);
goto done;
}
len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff));
@@ -936,9 +957,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
if (!len) {
break;
} else if (len > MWIFIEX_UPLD_SIZE) {
- dev_err(adapter->dev,
- "FW dnld failed @ %d, invalid length %d\n",
- offset, len);
+ mwifiex_dbg(adapter, ERROR,
+ "FW dnld failed @ %d, invalid length %d\n",
+ offset, len);
ret = -1;
goto done;
}
@@ -948,14 +969,15 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
if (len & BIT(0)) {
i++;
if (i > MAX_WRITE_IOMEM_RETRY) {
- dev_err(adapter->dev,
- "FW dnld failed @ %d, over max retry\n",
- offset);
+ mwifiex_dbg(adapter, ERROR,
+ "FW dnld failed @ %d, over max retry\n",
+ offset);
ret = -1;
goto done;
}
- dev_err(adapter->dev, "CRC indicated by the helper:"
- " len = 0x%04X, txlen = %d\n", len, txlen);
+ mwifiex_dbg(adapter, ERROR,
+ "CRC indicated by the helper:\t"
+ "len = 0x%04X, txlen = %d\n", len, txlen);
len &= ~BIT(0);
/* Setting this to 0 to resend from same offset */
txlen = 0;
@@ -978,11 +1000,12 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
MWIFIEX_SDIO_BLOCK_SIZE,
adapter->ioport);
if (ret) {
- dev_err(adapter->dev,
- "FW download, write iomem (%d) failed @ %d\n",
- i, offset);
+ mwifiex_dbg(adapter, ERROR,
+ "FW download, write iomem (%d) failed @ %d\n",
+ i, offset);
if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04))
- dev_err(adapter->dev, "write CFG reg failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "write CFG reg failed\n");
ret = -1;
goto done;
@@ -991,8 +1014,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
offset += txlen;
} while (true);
- dev_notice(adapter->dev,
- "info: FW download over, size %d bytes\n", offset);
+ mwifiex_dbg(adapter, MSG,
+ "info: FW download over, size %d bytes\n", offset);
ret = 0;
done:
@@ -1066,18 +1089,20 @@ static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter,
blk_num = *(data + BLOCK_NUMBER_OFFSET);
blk_size = adapter->sdio_rx_block_size * blk_num;
if (blk_size > total_pkt_len) {
- dev_err(adapter->dev, "%s: error in pkt,\t"
- "blk_num=%d, blk_size=%d, total_pkt_len=%d\n",
- __func__, blk_num, blk_size, total_pkt_len);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: error in blk_size,\t"
+ "blk_num=%d, blk_size=%d, total_pkt_len=%d\n",
+ __func__, blk_num, blk_size, total_pkt_len);
break;
}
pkt_len = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET));
pkt_type = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET +
2));
if ((pkt_len + SDIO_HEADER_OFFSET) > blk_size) {
- dev_err(adapter->dev, "%s: error in pkt,\t"
- "pkt_len=%d, blk_size=%d\n",
- __func__, pkt_len, blk_size);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: error in pkt_len,\t"
+ "pkt_len=%d, blk_size=%d\n",
+ __func__, pkt_len, blk_size);
break;
}
skb_deaggr = mwifiex_alloc_dma_align_buf(pkt_len,
@@ -1116,7 +1141,8 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
switch (upld_typ) {
case MWIFIEX_TYPE_AGGR_DATA:
- dev_dbg(adapter->dev, "info: --- Rx: Aggr Data packet ---\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: --- Rx: Aggr Data packet ---\n");
rx_info = MWIFIEX_SKB_RXCB(skb);
rx_info->buf_type = MWIFIEX_TYPE_AGGR_DATA;
if (adapter->rx_work_enabled) {
@@ -1130,7 +1156,8 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
break;
case MWIFIEX_TYPE_DATA:
- dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n");
+ mwifiex_dbg(adapter, DATA,
+ "info: --- Rx: Data packet ---\n");
if (adapter->rx_work_enabled) {
skb_queue_tail(&adapter->rx_data_q, skb);
adapter->data_received = true;
@@ -1141,7 +1168,8 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
break;
case MWIFIEX_TYPE_CMD:
- dev_dbg(adapter->dev, "info: --- Rx: Cmd Response ---\n");
+ mwifiex_dbg(adapter, CMD,
+ "info: --- Rx: Cmd Response ---\n");
/* take care of curr_cmd = NULL case */
if (!adapter->curr_cmd) {
cmd_buf = adapter->upld_buf;
@@ -1163,7 +1191,8 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
break;
case MWIFIEX_TYPE_EVENT:
- dev_dbg(adapter->dev, "info: --- Rx: Event ---\n");
+ mwifiex_dbg(adapter, EVENT,
+ "info: --- Rx: Event ---\n");
adapter->event_cause = le32_to_cpu(*(__le32 *) skb->data);
if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE))
@@ -1178,7 +1207,8 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
break;
default:
- dev_err(adapter->dev, "unknown upload type %#x\n", upld_typ);
+ mwifiex_dbg(adapter, ERROR,
+ "unknown upload type %#x\n", upld_typ);
dev_kfree_skb_any(skb);
break;
}
@@ -1210,16 +1240,18 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
if ((card->has_control_mask) && (port == CTRL_PORT)) {
/* Read the command Resp without aggr */
- dev_dbg(adapter->dev, "info: %s: no aggregation for cmd "
- "response\n", __func__);
+ mwifiex_dbg(adapter, CMD,
+ "info: %s: no aggregation for cmd\t"
+ "response\n", __func__);
f_do_rx_cur = 1;
goto rx_curr_single;
}
if (!card->mpa_rx.enabled) {
- dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n",
- __func__);
+ mwifiex_dbg(adapter, WARN,
+ "info: %s: rx aggregation disabled\n",
+ __func__);
f_do_rx_cur = 1;
goto rx_curr_single;
@@ -1230,7 +1262,8 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
(card->has_control_mask && (card->mp_rd_bitmap &
(~((u32) CTRL_PORT_MASK))))) {
/* Some more data RX pending */
- dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: not last packet\n", __func__);
if (MP_RX_AGGR_IN_PROGRESS(card)) {
if (MP_RX_AGGR_BUF_HAS_ROOM(card, rx_len)) {
@@ -1247,7 +1280,8 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
} else {
/* No more data RX pending */
- dev_dbg(adapter->dev, "info: %s: last packet\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: last packet\n", __func__);
if (MP_RX_AGGR_IN_PROGRESS(card)) {
f_do_rx_aggr = 1;
@@ -1262,14 +1296,16 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
}
if (f_aggr_cur) {
- dev_dbg(adapter->dev, "info: current packet aggregation\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: current packet aggregation\n");
/* Curr pkt can be aggregated */
mp_rx_aggr_setup(card, rx_len, port);
if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) ||
mp_rx_aggr_port_limit_reached(card)) {
- dev_dbg(adapter->dev, "info: %s: aggregated packet "
- "limit reached\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: aggregated packet\t"
+ "limit reached\n", __func__);
/* No more pkts allowed in Aggr buf, rx it */
f_do_rx_aggr = 1;
}
@@ -1277,8 +1313,9 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
if (f_do_rx_aggr) {
/* do aggr RX now */
- dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n",
- card->mpa_rx.pkt_cnt);
+ mwifiex_dbg(adapter, DATA,
+ "info: do_rx_aggr: num of packets: %d\n",
+ card->mpa_rx.pkt_cnt);
if (card->supports_sdio_new_mode) {
int i;
@@ -1318,8 +1355,9 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
GFP_KERNEL |
GFP_DMA);
if (!skb_deaggr) {
- dev_err(adapter->dev, "skb allocation failure drop pkt len=%d type=%d\n",
- pkt_len, pkt_type);
+ mwifiex_dbg(adapter, ERROR, "skb allocation failure\t"
+ "drop pkt len=%d type=%d\n",
+ pkt_len, pkt_type);
curr_ptr += len_arr[pind];
continue;
}
@@ -1339,12 +1377,12 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
mwifiex_decode_rx_packet(adapter, skb_deaggr,
pkt_type);
} else {
- dev_err(adapter->dev, " drop wrong aggr pkt:\t"
- "sdio_single_port_rx_aggr=%d\t"
- "type=%d len=%d max_len=%d\n",
- adapter->sdio_rx_aggr_enable,
- pkt_type, pkt_len,
- len_arr[pind]);
+ mwifiex_dbg(adapter, ERROR,
+ "drop wrong aggr pkt:\t"
+ "sdio_single_port_rx_aggr=%d\t"
+ "type=%d len=%d max_len=%d\n",
+ adapter->sdio_rx_aggr_enable,
+ pkt_type, pkt_len, len_arr[pind]);
dev_kfree_skb_any(skb_deaggr);
}
curr_ptr += len_arr[pind];
@@ -1354,13 +1392,14 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
rx_curr_single:
if (f_do_rx_cur) {
- dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n",
- port, rx_len);
+ mwifiex_dbg(adapter, INFO, "info: RX: port: %d, rx_len: %d\n",
+ port, rx_len);
skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA);
if (!skb) {
- dev_err(adapter->dev, "single skb allocated fail,\t"
- "drop pkt port=%d len=%d\n", port, rx_len);
+ mwifiex_dbg(adapter, ERROR,
+ "single skb allocated fail,\t"
+ "drop pkt port=%d len=%d\n", port, rx_len);
if (mwifiex_sdio_card_to_host(adapter, &pkt_type,
card->mpa_rx.buf, rx_len,
adapter->ioport + port))
@@ -1376,9 +1415,9 @@ rx_curr_single:
goto error;
if (!adapter->sdio_rx_aggr_enable &&
pkt_type == MWIFIEX_TYPE_AGGR_DATA) {
- dev_err(adapter->dev, "drop wrong pkt type %d\t"
- "current SDIO RX Aggr not enabled\n",
- pkt_type);
+ mwifiex_dbg(adapter, ERROR, "drop wrong pkt type %d\t"
+ "current SDIO RX Aggr not enabled\n",
+ pkt_type);
dev_kfree_skb_any(skb);
return 0;
}
@@ -1386,7 +1425,8 @@ rx_curr_single:
mwifiex_decode_rx_packet(adapter, skb, pkt_type);
}
if (f_post_aggr_cur) {
- dev_dbg(adapter->dev, "info: current packet aggregation\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: current packet aggregation\n");
/* Curr pkt can be aggregated */
mp_rx_aggr_setup(card, rx_len, port);
}
@@ -1458,7 +1498,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
MWIFIEX_RX_DATA_BUF_SIZE)
return -1;
rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
- dev_dbg(adapter->dev, "info: rx_len = %d\n", rx_len);
+ mwifiex_dbg(adapter, INFO, "info: rx_len = %d\n", rx_len);
skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA);
if (!skb)
@@ -1469,17 +1509,17 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data,
skb->len, adapter->ioport |
CMD_PORT_SLCT)) {
- dev_err(adapter->dev,
- "%s: failed to card_to_host", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: failed to card_to_host", __func__);
dev_kfree_skb_any(skb);
goto term_cmd;
}
if ((pkt_type != MWIFIEX_TYPE_CMD) &&
(pkt_type != MWIFIEX_TYPE_EVENT))
- dev_err(adapter->dev,
- "%s:Received wrong packet on cmd port",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s:Received wrong packet on cmd port",
+ __func__);
mwifiex_decode_rx_packet(adapter, skb, pkt_type);
}
@@ -1495,12 +1535,13 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
}
card->mp_wr_bitmap = bitmap;
- dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%x\n",
- card->mp_wr_bitmap);
+ mwifiex_dbg(adapter, INTR,
+ "int: DNLD: wr_bitmap=0x%x\n",
+ card->mp_wr_bitmap);
if (adapter->data_sent &&
(card->mp_wr_bitmap & card->mp_data_port_mask)) {
- dev_dbg(adapter->dev,
- "info: <--- Tx DONE Interrupt --->\n");
+ mwifiex_dbg(adapter, INTR,
+ "info: <--- Tx DONE Interrupt --->\n");
adapter->data_sent = false;
}
}
@@ -1517,8 +1558,8 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
adapter->cmd_sent = false;
}
- dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
- adapter->cmd_sent, adapter->data_sent);
+ mwifiex_dbg(adapter, INTR, "info: cmd_sent=%d data_sent=%d\n",
+ adapter->cmd_sent, adapter->data_sent);
if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
bitmap = (u32) card->mp_regs[reg->rd_bitmap_l];
bitmap |= ((u32) card->mp_regs[reg->rd_bitmap_u]) << 8;
@@ -1529,40 +1570,45 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
((u32) card->mp_regs[reg->rd_bitmap_1u]) << 24;
}
card->mp_rd_bitmap = bitmap;
- dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%x\n",
- card->mp_rd_bitmap);
+ mwifiex_dbg(adapter, INTR,
+ "int: UPLD: rd_bitmap=0x%x\n",
+ card->mp_rd_bitmap);
while (true) {
ret = mwifiex_get_rd_port(adapter, &port);
if (ret) {
- dev_dbg(adapter->dev,
- "info: no more rd_port available\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: no more rd_port available\n");
break;
}
len_reg_l = reg->rd_len_p0_l + (port << 1);
len_reg_u = reg->rd_len_p0_u + (port << 1);
rx_len = ((u16) card->mp_regs[len_reg_u]) << 8;
rx_len |= (u16) card->mp_regs[len_reg_l];
- dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n",
- port, rx_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: RX: port=%d rx_len=%u\n",
+ port, rx_len);
rx_blocks =
(rx_len + MWIFIEX_SDIO_BLOCK_SIZE -
1) / MWIFIEX_SDIO_BLOCK_SIZE;
if (rx_len <= INTF_HEADER_LEN ||
(rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
card->mpa_rx.buf_size) {
- dev_err(adapter->dev, "invalid rx_len=%d\n",
- rx_len);
+ mwifiex_dbg(adapter, ERROR,
+ "invalid rx_len=%d\n",
+ rx_len);
return -1;
}
rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
- dev_dbg(adapter->dev, "info: rx_len = %d\n", rx_len);
+ mwifiex_dbg(adapter, INFO, "info: rx_len = %d\n",
+ rx_len);
if (mwifiex_sdio_card_to_host_mp_aggr(adapter, rx_len,
port)) {
- dev_err(adapter->dev, "card_to_host_mpa failed:"
- " int status=%#x\n", sdio_ireg);
+ mwifiex_dbg(adapter, ERROR,
+ "card_to_host_mpa failed: int status=%#x\n",
+ sdio_ireg);
goto term_cmd;
}
}
@@ -1573,19 +1619,23 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
term_cmd:
/* terminate cmd */
if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr))
- dev_err(adapter->dev, "read CFG reg failed\n");
+ mwifiex_dbg(adapter, ERROR, "read CFG reg failed\n");
else
- dev_dbg(adapter->dev, "info: CFG reg val = %d\n", cr);
+ mwifiex_dbg(adapter, INFO,
+ "info: CFG reg val = %d\n", cr);
if (mwifiex_write_reg(adapter, CONFIGURATION_REG, (cr | 0x04)))
- dev_err(adapter->dev, "write CFG reg failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "write CFG reg failed\n");
else
- dev_dbg(adapter->dev, "info: write success\n");
+ mwifiex_dbg(adapter, INFO, "info: write success\n");
if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr))
- dev_err(adapter->dev, "read CFG reg failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "read CFG reg failed\n");
else
- dev_dbg(adapter->dev, "info: CFG reg val =%x\n", cr);
+ mwifiex_dbg(adapter, INFO,
+ "info: CFG reg val =%x\n", cr);
return -1;
}
@@ -1619,8 +1669,9 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
if (!card->mpa_tx.enabled ||
(card->has_control_mask && (port == CTRL_PORT)) ||
(card->supports_sdio_new_mode && (port == CMD_PORT_SLCT))) {
- dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n",
- __func__);
+ mwifiex_dbg(adapter, WARN,
+ "info: %s: tx aggregation disabled\n",
+ __func__);
f_send_cur_buf = 1;
goto tx_curr_single;
@@ -1628,8 +1679,9 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
if (next_pkt_len) {
/* More pkt in TX queue */
- dev_dbg(adapter->dev, "info: %s: more packets in queue.\n",
- __func__);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: more packets in queue.\n",
+ __func__);
if (MP_TX_AGGR_IN_PROGRESS(card)) {
if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) {
@@ -1659,8 +1711,9 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
}
} else {
/* Last pkt in TX queue */
- dev_dbg(adapter->dev, "info: %s: Last packet in Tx Queue.\n",
- __func__);
+ mwifiex_dbg(adapter, INFO,
+ "info: %s: Last packet in Tx Queue.\n",
+ __func__);
if (MP_TX_AGGR_IN_PROGRESS(card)) {
/* some packs in Aggr buf already */
@@ -1677,8 +1730,9 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
}
if (f_precopy_cur_buf) {
- dev_dbg(adapter->dev, "data: %s: precopy current buffer\n",
- __func__);
+ mwifiex_dbg(adapter, DATA,
+ "data: %s: precopy current buffer\n",
+ __func__);
MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) ||
@@ -1688,9 +1742,10 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
}
if (f_send_aggr_buf) {
- dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n",
- __func__,
- card->mpa_tx.start_port, card->mpa_tx.ports);
+ mwifiex_dbg(adapter, DATA,
+ "data: %s: send aggr buffer: %d %d\n",
+ __func__, card->mpa_tx.start_port,
+ card->mpa_tx.ports);
if (card->supports_sdio_new_mode) {
u32 port_count;
int i;
@@ -1719,15 +1774,17 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
tx_curr_single:
if (f_send_cur_buf) {
- dev_dbg(adapter->dev, "data: %s: send current buffer %d\n",
- __func__, port);
+ mwifiex_dbg(adapter, DATA,
+ "data: %s: send current buffer %d\n",
+ __func__, port);
ret = mwifiex_write_data_to_card(adapter, payload, pkt_len,
adapter->ioport + port);
}
if (f_postcopy_cur_buf) {
- dev_dbg(adapter->dev, "data: %s: postcopy current buffer\n",
- __func__);
+ mwifiex_dbg(adapter, DATA,
+ "data: %s: postcopy current buffer\n",
+ __func__);
MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
}
@@ -1771,8 +1828,9 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
if (type == MWIFIEX_TYPE_DATA) {
ret = mwifiex_get_wr_port_data(adapter, &port);
if (ret) {
- dev_err(adapter->dev, "%s: no wr_port available\n",
- __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: no wr_port available\n",
+ __func__);
return ret;
}
} else {
@@ -1781,8 +1839,9 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
if (pkt_len <= INTF_HEADER_LEN ||
pkt_len > MWIFIEX_UPLD_SIZE)
- dev_err(adapter->dev, "%s: payload=%p, nb=%d\n",
- __func__, payload, pkt_len);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: payload=%p, nb=%d\n",
+ __func__, payload, pkt_len);
if (card->supports_sdio_new_mode)
port = CMD_PORT_SLCT;
@@ -1896,7 +1955,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE);
sdio_release_host(func);
if (ret) {
- pr_err("cannot set SDIO block size\n");
+ mwifiex_dbg(adapter, ERROR,
+ "cannot set SDIO block size\n");
return ret;
}
@@ -1977,7 +2037,8 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
card->mp_tx_agg_buf_size,
card->mp_rx_agg_buf_size);
if (ret) {
- dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n");
+ mwifiex_dbg(adapter, ERROR,
+ "failed to alloc sdio mp-a buffers\n");
kfree(card->mp_regs);
return -1;
}
@@ -2041,8 +2102,9 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port)
card->curr_wr_port = reg->start_wr_port;
- dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n",
- port, card->mp_data_port_mask);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: mp_end_port %d, data port mask 0x%x\n",
+ port, card->mp_data_port_mask);
}
static struct mwifiex_adapter *save_adapter;
@@ -2059,7 +2121,7 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter)
* We run it in a totally independent workqueue.
*/
- pr_err("Resetting card...\n");
+ mwifiex_dbg(adapter, WARN, "Resetting card...\n");
mmc_remove_host(target);
/* 200ms delay is based on experiment with sdhci controller */
mdelay(200);
@@ -2079,14 +2141,14 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter,
sdio_writeb(card->func, FW_DUMP_HOST_READY, card->reg->fw_dump_ctrl,
&ret);
if (ret) {
- dev_err(adapter->dev, "SDIO Write ERR\n");
+ mwifiex_dbg(adapter, ERROR, "SDIO Write ERR\n");
return RDWR_STATUS_FAILURE;
}
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
ctrl_data = sdio_readb(card->func, card->reg->fw_dump_ctrl,
&ret);
if (ret) {
- dev_err(adapter->dev, "SDIO read err\n");
+ mwifiex_dbg(adapter, ERROR, "SDIO read err\n");
return RDWR_STATUS_FAILURE;
}
if (ctrl_data == FW_DUMP_DONE)
@@ -2094,19 +2156,20 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter,
if (doneflag && ctrl_data == doneflag)
return RDWR_STATUS_DONE;
if (ctrl_data != FW_DUMP_HOST_READY) {
- dev_info(adapter->dev,
- "The ctrl reg was changed, re-try again!\n");
+ mwifiex_dbg(adapter, WARN,
+ "The ctrl reg was changed, re-try again!\n");
sdio_writeb(card->func, FW_DUMP_HOST_READY,
card->reg->fw_dump_ctrl, &ret);
if (ret) {
- dev_err(adapter->dev, "SDIO write err\n");
+ mwifiex_dbg(adapter, ERROR, "SDIO write err\n");
return RDWR_STATUS_FAILURE;
}
}
usleep_range(100, 200);
}
if (ctrl_data == FW_DUMP_HOST_READY) {
- dev_err(adapter->dev, "Fail to pull ctrl_data\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Fail to pull ctrl_data\n");
return RDWR_STATUS_FAILURE;
}
@@ -2114,7 +2177,7 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter,
}
/* This function dump firmware memory to file */
-static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
+static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter)
{
struct sdio_mmc_card *card = adapter->card;
int ret = 0;
@@ -2122,9 +2185,6 @@ static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0;
enum rdwr_status stat;
u32 memory_size;
- static char *env[] = { "DRIVER=mwifiex_sdio", "EVENT=fw_dump", NULL };
-
- mwifiex_dump_drv_info(adapter);
if (!card->can_dump_fw)
return;
@@ -2142,7 +2202,7 @@ static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
mwifiex_pm_wakeup_card(adapter);
sdio_claim_host(card->func);
- dev_info(adapter->dev, "== mwifiex firmware dump start ==\n");
+ mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n");
stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag);
if (stat == RDWR_STATUS_FAILURE)
@@ -2152,7 +2212,7 @@ static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
/* Read the number of the memories which will dump */
dump_num = sdio_readb(card->func, reg, &ret);
if (ret) {
- dev_err(adapter->dev, "SDIO read memory length err\n");
+ mwifiex_dbg(adapter, ERROR, "SDIO read memory length err\n");
goto done;
}
@@ -2169,7 +2229,7 @@ static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
for (i = 0; i < 4; i++) {
read_reg = sdio_readb(card->func, reg, &ret);
if (ret) {
- dev_err(adapter->dev, "SDIO read err\n");
+ mwifiex_dbg(adapter, ERROR, "SDIO read err\n");
goto done;
}
memory_size |= (read_reg << i*8);
@@ -2177,25 +2237,33 @@ static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
}
if (memory_size == 0) {
- dev_info(adapter->dev, "Firmware dump Finished!\n");
+ mwifiex_dbg(adapter, DUMP, "Firmware dump Finished!\n");
+ ret = mwifiex_write_reg(adapter,
+ card->reg->fw_dump_ctrl,
+ FW_DUMP_READ_DONE);
+ if (ret) {
+ mwifiex_dbg(adapter, ERROR, "SDIO write err\n");
+ return;
+ }
break;
}
- dev_info(adapter->dev,
- "%s_SIZE=0x%x\n", entry->mem_name, memory_size);
+ mwifiex_dbg(adapter, DUMP,
+ "%s_SIZE=0x%x\n", entry->mem_name, memory_size);
entry->mem_ptr = vmalloc(memory_size + 1);
entry->mem_size = memory_size;
if (!entry->mem_ptr) {
- dev_err(adapter->dev, "Vmalloc %s failed\n",
- entry->mem_name);
+ mwifiex_dbg(adapter, ERROR, "Vmalloc %s failed\n",
+ entry->mem_name);
goto done;
}
dbg_ptr = entry->mem_ptr;
end_ptr = dbg_ptr + memory_size;
doneflag = entry->done_flag;
- dev_info(adapter->dev, "Start %s output, please wait...\n",
- entry->mem_name);
+ mwifiex_dbg(adapter, DUMP,
+ "Start %s output, please wait...\n",
+ entry->mem_name);
do {
stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag);
@@ -2207,39 +2275,43 @@ static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter)
for (reg = reg_start; reg <= reg_end; reg++) {
*dbg_ptr = sdio_readb(card->func, reg, &ret);
if (ret) {
- dev_err(adapter->dev,
- "SDIO read err\n");
+ mwifiex_dbg(adapter, ERROR,
+ "SDIO read err\n");
goto done;
}
if (dbg_ptr < end_ptr)
dbg_ptr++;
else
- dev_err(adapter->dev,
- "Allocated buf not enough\n");
+ mwifiex_dbg(adapter, ERROR,
+ "Allocated buf not enough\n");
}
if (stat != RDWR_STATUS_DONE)
continue;
- dev_info(adapter->dev, "%s done: size=0x%tx\n",
- entry->mem_name, dbg_ptr - entry->mem_ptr);
+ mwifiex_dbg(adapter, DUMP, "%s done: size=0x%tx\n",
+ entry->mem_name, dbg_ptr - entry->mem_ptr);
break;
} while (1);
}
- dev_info(adapter->dev, "== mwifiex firmware dump end ==\n");
-
- kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env);
+ mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n");
done:
sdio_release_host(card->func);
- adapter->curr_mem_idx = 0;
+}
+
+static void mwifiex_sdio_device_dump_work(struct mwifiex_adapter *adapter)
+{
+ mwifiex_drv_info_dump(adapter);
+ mwifiex_sdio_fw_dump(adapter);
+ mwifiex_upload_device_dump(adapter);
}
static void mwifiex_sdio_work(struct work_struct *work)
{
- if (test_and_clear_bit(MWIFIEX_IFACE_WORK_FW_DUMP,
+ if (test_and_clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
&iface_work_flags))
- mwifiex_sdio_fw_dump_work(save_adapter);
+ mwifiex_sdio_device_dump_work(save_adapter);
if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET,
&iface_work_flags))
mwifiex_sdio_card_reset_work(save_adapter);
@@ -2259,13 +2331,13 @@ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter)
}
/* This function dumps FW information */
-static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter)
+static void mwifiex_sdio_device_dump(struct mwifiex_adapter *adapter)
{
save_adapter = adapter;
- if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags))
+ if (test_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &iface_work_flags))
return;
- set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags);
+ set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &iface_work_flags);
schedule_work(&sdio_work);
}
@@ -2285,7 +2357,7 @@ mwifiex_sdio_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf)
if (!p)
return 0;
- dev_info(adapter->dev, "SDIO register DUMP START\n");
+ mwifiex_dbg(adapter, MSG, "SDIO register dump start\n");
mwifiex_pm_wakeup_card(adapter);
@@ -2351,13 +2423,13 @@ mwifiex_sdio_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf)
reg++;
}
- dev_info(adapter->dev, "%s\n", buf);
+ mwifiex_dbg(adapter, MSG, "%s\n", buf);
p += sprintf(p, "%s\n", buf);
}
sdio_release_host(cardp->func);
- dev_info(adapter->dev, "SDIO register DUMP END\n");
+ mwifiex_dbg(adapter, MSG, "SDIO register dump end\n");
return p - drv_buf;
}
@@ -2382,8 +2454,8 @@ static struct mwifiex_if_ops sdio_ops = {
.cmdrsp_complete = mwifiex_sdio_cmdrsp_complete,
.event_complete = mwifiex_sdio_event_complete,
.card_reset = mwifiex_sdio_card_reset,
- .fw_dump = mwifiex_sdio_fw_dump,
.reg_dump = mwifiex_sdio_reg_dump,
+ .device_dump = mwifiex_sdio_device_dump,
.deaggr_pkt = mwifiex_deaggr_sdio_pkt,
};
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 49422f2a5380..037adcd1f484 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -77,8 +77,8 @@ static int mwifiex_cmd_mac_control(struct mwifiex_private *priv,
struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl;
if (cmd_action != HostCmd_ACT_GEN_SET) {
- dev_err(priv->adapter->dev,
- "mac_control: only support set cmd\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "mac_control: only support set cmd\n");
return -1;
}
@@ -112,7 +112,8 @@ static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv,
{
struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib;
- dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib)
- 1 + S_DS_GEN);
@@ -129,11 +130,11 @@ static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv,
le16_add_cpu(&cmd->size, sizeof(u16));
}
- dev_dbg(priv->adapter->dev,
- "cmd: SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x,"
- " Value=0x%x\n",
- cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size),
- le16_to_cpu(*(__le16 *) snmp_mib->value));
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: SNMP_CMD: Action=0x%x, OID=0x%x,\t"
+ "OIDSize=0x%x, Value=0x%x\n",
+ cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size),
+ le16_to_cpu(*(__le16 *)snmp_mib->value));
return 0;
}
@@ -356,9 +357,9 @@ mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
(hscfg_param->conditions != cpu_to_le32(HS_CFG_CANCEL)) &&
((adapter->arp_filter_size > 0) &&
(adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
- dev_dbg(adapter->dev,
- "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n",
- adapter->arp_filter_size);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n",
+ adapter->arp_filter_size);
memcpy(((u8 *) hs_cfg) +
sizeof(struct host_cmd_ds_802_11_hs_cfg_enh),
adapter->arp_filter, adapter->arp_filter_size);
@@ -378,11 +379,11 @@ mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
hs_cfg->params.hs_config.conditions = hscfg_param->conditions;
hs_cfg->params.hs_config.gpio = hscfg_param->gpio;
hs_cfg->params.hs_config.gap = hscfg_param->gap;
- dev_dbg(adapter->dev,
- "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
- hs_cfg->params.hs_config.conditions,
- hs_cfg->params.hs_config.gpio,
- hs_cfg->params.hs_config.gap);
+ mwifiex_dbg(adapter, CMD,
+ "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
+ hs_cfg->params.hs_config.conditions,
+ hs_cfg->params.hs_config.gpio,
+ hs_cfg->params.hs_config.gap);
}
return 0;
@@ -462,7 +463,7 @@ static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv,
/* Set AP MAC address */
memcpy(deauth->mac_addr, mac, ETH_ALEN);
- dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr);
+ mwifiex_dbg(priv->adapter, CMD, "cmd: Deauth: %pM\n", deauth->mac_addr);
deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING);
@@ -540,9 +541,9 @@ mwifiex_set_keyparamset_wep(struct mwifiex_private *priv,
} else if (!priv->wep_key[i].key_length) {
continue;
} else {
- dev_err(priv->adapter->dev,
- "key%d Length = %d is incorrect\n",
- (i + 1), priv->wep_key[i].key_length);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "key%d Length = %d is incorrect\n",
+ (i + 1), priv->wep_key[i].key_length);
return -1;
}
}
@@ -562,7 +563,8 @@ static int mwifiex_set_aes_key_v2(struct mwifiex_private *priv,
u16 size, len = KEY_PARAMS_FIXED_LEN;
if (enc_key->is_igtk_key) {
- dev_dbg(adapter->dev, "%s: Set CMAC AES Key\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "%s: Set CMAC AES Key\n", __func__);
if (enc_key->is_rx_seq_valid)
memcpy(km->key_param_set.key_params.cmac_aes.ipn,
enc_key->pn, enc_key->pn_len);
@@ -575,7 +577,8 @@ static int mwifiex_set_aes_key_v2(struct mwifiex_private *priv,
enc_key->key_material, enc_key->key_len);
len += sizeof(struct mwifiex_cmac_aes_param);
} else {
- dev_dbg(adapter->dev, "%s: Set AES Key\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "%s: Set AES Key\n", __func__);
if (enc_key->is_rx_seq_valid)
memcpy(km->key_param_set.key_params.aes.pn,
enc_key->pn, enc_key->pn_len);
@@ -619,7 +622,7 @@ mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv,
km->action = cpu_to_le16(cmd_action);
if (cmd_action == HostCmd_ACT_GEN_GET) {
- dev_dbg(adapter->dev, "%s: Get key\n", __func__);
+ mwifiex_dbg(adapter, INFO, "%s: Get key\n", __func__);
km->key_param_set.key_idx =
enc_key->key_index & KEY_INDEX_MASK;
km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
@@ -646,7 +649,7 @@ mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv,
sizeof(struct mwifiex_ie_type_key_param_set_v2));
if (enc_key->key_disable) {
- dev_dbg(adapter->dev, "%s: Remove key\n", __func__);
+ mwifiex_dbg(adapter, INFO, "%s: Remove key\n", __func__);
km->action = cpu_to_le16(HostCmd_ACT_GEN_REMOVE);
km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2);
km->key_param_set.len = cpu_to_le16(KEY_PARAMS_FIXED_LEN);
@@ -667,7 +670,7 @@ mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv,
memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN);
if (enc_key->key_len <= WLAN_KEY_LEN_WEP104) {
- dev_dbg(adapter->dev, "%s: Set WEP Key\n", __func__);
+ mwifiex_dbg(adapter, INFO, "%s: Set WEP Key\n", __func__);
len += sizeof(struct mwifiex_wep_param);
km->key_param_set.len = cpu_to_le16(len);
km->key_param_set.key_type = KEY_TYPE_ID_WEP;
@@ -710,7 +713,7 @@ mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv,
key_info |= KEY_UNICAST | KEY_TX_KEY | KEY_RX_KEY;
if (enc_key->is_wapi_key) {
- dev_dbg(adapter->dev, "%s: Set WAPI Key\n", __func__);
+ mwifiex_dbg(adapter, INFO, "%s: Set WAPI Key\n", __func__);
km->key_param_set.key_type = KEY_TYPE_ID_WAPI;
memcpy(km->key_param_set.key_params.wapi.pn, enc_key->pn,
PN_LEN);
@@ -750,7 +753,8 @@ mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv,
return mwifiex_set_aes_key_v2(priv, cmd, enc_key, km);
if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
- dev_dbg(adapter->dev, "%s: Set TKIP Key\n", __func__);
+ mwifiex_dbg(adapter, INFO,
+ "%s: Set TKIP Key\n", __func__);
if (enc_key->is_rx_seq_valid)
memcpy(km->key_param_set.key_params.tkip.pn,
enc_key->pn, enc_key->pn_len);
@@ -814,7 +818,7 @@ mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv,
memset(&key_material->key_param_set, 0,
sizeof(struct mwifiex_ie_type_key_param_set));
if (enc_key->is_wapi_key) {
- dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: Set WAPI Key\n");
key_material->key_param_set.key_type_id =
cpu_to_le16(KEY_TYPE_ID_WAPI);
if (cmd_oid == KEY_INFO_ENABLED)
@@ -860,7 +864,7 @@ mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv,
}
if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
if (enc_key->is_igtk_key) {
- dev_dbg(priv->adapter->dev, "cmd: CMAC_AES\n");
+ mwifiex_dbg(priv->adapter, CMD, "cmd: CMAC_AES\n");
key_material->key_param_set.key_type_id =
cpu_to_le16(KEY_TYPE_ID_AES_CMAC);
if (cmd_oid == KEY_INFO_ENABLED)
@@ -873,7 +877,7 @@ mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv,
key_material->key_param_set.key_info |=
cpu_to_le16(KEY_IGTK);
} else {
- dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
+ mwifiex_dbg(priv->adapter, CMD, "cmd: WPA_AES\n");
key_material->key_param_set.key_type_id =
cpu_to_le16(KEY_TYPE_ID_AES);
if (cmd_oid == KEY_INFO_ENABLED)
@@ -892,7 +896,7 @@ mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv,
cpu_to_le16(KEY_MCAST);
}
} else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
- dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
+ mwifiex_dbg(priv->adapter, CMD, "cmd: WPA_TKIP\n");
key_material->key_param_set.key_type_id =
cpu_to_le16(KEY_TYPE_ID_TKIP);
key_material->key_param_set.key_info =
@@ -999,7 +1003,8 @@ static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv,
&domain_info->domain;
u8 no_of_triplet = adapter->domain_reg.no_of_triplet;
- dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet);
+ mwifiex_dbg(adapter, INFO,
+ "info: 11D: no_of_triplet=0x%x\n", no_of_triplet);
cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
domain_info->action = cpu_to_le16(cmd_action);
@@ -1071,6 +1076,26 @@ static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd,
return 0;
}
+/* This function prepares command buffer to get/set memory location value.
+ */
+static int
+mwifiex_cmd_mem_access(struct host_cmd_ds_command *cmd, u16 cmd_action,
+ void *pdata_buf)
+{
+ struct mwifiex_ds_mem_rw *mem_rw = (void *)pdata_buf;
+ struct host_cmd_ds_mem_access *mem_access = (void *)&cmd->params.mem;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_MEM_ACCESS);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mem_access) +
+ S_DS_GEN);
+
+ mem_access->action = cpu_to_le16(cmd_action);
+ mem_access->addr = cpu_to_le32(mem_rw->addr);
+ mem_access->value = cpu_to_le32(mem_rw->value);
+
+ return 0;
+}
+
/*
* This function prepares command to set/get register value.
*
@@ -1215,8 +1240,9 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv,
(u32)(card->sleep_cookie_pbase);
host_spec->sleep_cookie_addr_hi =
(u32)(((u64)(card->sleep_cookie_pbase)) >> 32);
- dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: 0x%x\n",
- host_spec->sleep_cookie_addr_lo);
+ mwifiex_dbg(priv->adapter, INFO,
+ "sleep_cook_lo phy addr: 0x%x\n",
+ host_spec->sleep_cookie_addr_lo);
}
return 0;
@@ -1243,7 +1269,8 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
S_DS_GEN);
subsc_evt->action = cpu_to_le16(subsc_evt_cfg->action);
- dev_dbg(priv->adapter->dev, "cmd: action: %d\n", subsc_evt_cfg->action);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: action: %d\n", subsc_evt_cfg->action);
/*For query requests, no configuration TLV structures are to be added.*/
if (subsc_evt_cfg->action == HostCmd_ACT_GEN_GET)
@@ -1252,14 +1279,15 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
subsc_evt->events = cpu_to_le16(subsc_evt_cfg->events);
event_bitmap = subsc_evt_cfg->events;
- dev_dbg(priv->adapter->dev, "cmd: event bitmap : %16x\n",
- event_bitmap);
+ mwifiex_dbg(priv->adapter, CMD, "cmd: event bitmap : %16x\n",
+ event_bitmap);
if (((subsc_evt_cfg->action == HostCmd_ACT_BITWISE_CLR) ||
(subsc_evt_cfg->action == HostCmd_ACT_BITWISE_SET)) &&
(event_bitmap == 0)) {
- dev_dbg(priv->adapter->dev, "Error: No event specified "
- "for bitwise action type\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Error: No event specified\t"
+ "for bitwise action type\n");
return -EINVAL;
}
@@ -1284,10 +1312,11 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
rssi_tlv->abs_value = subsc_evt_cfg->bcn_l_rssi_cfg.abs_value;
rssi_tlv->evt_freq = subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq;
- dev_dbg(priv->adapter->dev, "Cfg Beacon Low Rssi event, "
- "RSSI:-%d dBm, Freq:%d\n",
- subsc_evt_cfg->bcn_l_rssi_cfg.abs_value,
- subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq);
+ mwifiex_dbg(priv->adapter, EVENT,
+ "Cfg Beacon Low Rssi event,\t"
+ "RSSI:-%d dBm, Freq:%d\n",
+ subsc_evt_cfg->bcn_l_rssi_cfg.abs_value,
+ subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq);
pos += sizeof(struct mwifiex_ie_types_rssi_threshold);
le16_add_cpu(&cmd->size,
@@ -1304,10 +1333,11 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
rssi_tlv->abs_value = subsc_evt_cfg->bcn_h_rssi_cfg.abs_value;
rssi_tlv->evt_freq = subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq;
- dev_dbg(priv->adapter->dev, "Cfg Beacon High Rssi event, "
- "RSSI:-%d dBm, Freq:%d\n",
- subsc_evt_cfg->bcn_h_rssi_cfg.abs_value,
- subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq);
+ mwifiex_dbg(priv->adapter, EVENT,
+ "Cfg Beacon High Rssi event,\t"
+ "RSSI:-%d dBm, Freq:%d\n",
+ subsc_evt_cfg->bcn_h_rssi_cfg.abs_value,
+ subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq);
pos += sizeof(struct mwifiex_ie_types_rssi_threshold);
le16_add_cpu(&cmd->size,
@@ -1463,12 +1493,14 @@ static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv,
data, len);
if (ret)
return ret;
- dev_dbg(adapter->dev,
- "download cfg_data from device tree: %s\n", prop->name);
+ mwifiex_dbg(adapter, INFO,
+ "download cfg_data from device tree: %s\n",
+ prop->name);
} else if (adapter->cal_data->data && adapter->cal_data->size > 0) {
len = mwifiex_parse_cal_cfg((u8 *)adapter->cal_data->data,
adapter->cal_data->size, data);
- dev_dbg(adapter->dev, "download cfg_data from config file\n");
+ mwifiex_dbg(adapter, INFO,
+ "download cfg_data from config file\n");
} else {
return -1;
}
@@ -1583,9 +1615,9 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv,
tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_CONFIG);
if (!params) {
- dev_err(priv->adapter->dev,
- "TDLS config params not available for %pM\n",
- oper->peer_mac);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "TDLS config params not available for %pM\n",
+ oper->peer_mac);
return -ENODATA;
}
@@ -1663,7 +1695,7 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv,
break;
default:
- dev_err(priv->adapter->dev, "Unknown TDLS operation\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS operation\n");
return -ENOTSUPP;
}
@@ -1870,8 +1902,8 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action, data_buf);
break;
case HostCmd_CMD_WMM_GET_STATUS:
- dev_dbg(priv->adapter->dev,
- "cmd: WMM: WMM_GET_STATUS cmd sent\n");
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: WMM: WMM_GET_STATUS cmd sent\n");
cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
cmd_ptr->size =
cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) +
@@ -1885,6 +1917,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
case HostCmd_CMD_802_11_SCAN_EXT:
ret = mwifiex_cmd_802_11_scan_ext(priv, cmd_ptr, data_buf);
break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = mwifiex_cmd_mem_access(cmd_ptr, cmd_action, data_buf);
+ break;
case HostCmd_CMD_MAC_REG_ACCESS:
case HostCmd_CMD_BBP_REG_ACCESS:
case HostCmd_CMD_RF_REG_ACCESS:
@@ -1932,8 +1967,8 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
data_buf);
break;
default:
- dev_err(priv->adapter->dev,
- "PREP_CMD: unknown cmd- %#x\n", cmd_no);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "PREP_CMD: unknown cmd- %#x\n", cmd_no);
ret = -1;
break;
}
@@ -2024,8 +2059,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
&sdio_sp_rx_aggr_enable,
true);
if (ret) {
- dev_err(priv->adapter->dev,
- "error while enabling SP aggregation..disable it");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "error while enabling SP aggregation..disable it");
adapter->sdio_rx_aggr_enable = false;
}
}
@@ -2108,8 +2143,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
HostCmd_ACT_GEN_SET, DOT11D_I,
&state_11d, true);
if (ret)
- dev_err(priv->adapter->dev,
- "11D: failed to enable 11D\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "11D: failed to enable 11D\n");
}
/* Send cmd to FW to configure 11n specific configuration
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 88dc6b672ef4..b645884b3b97 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -49,8 +49,9 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
struct host_cmd_ds_802_11_ps_mode_enh *pm;
unsigned long flags;
- dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n",
- resp->command, resp->result);
+ mwifiex_dbg(adapter, ERROR,
+ "CMD_RESP: cmd %#x error, result=%#x\n",
+ resp->command, resp->result);
if (adapter->curr_cmd->wait_q_enabled)
adapter->cmd_wait_q.status = -1;
@@ -58,9 +59,9 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
switch (le16_to_cpu(resp->command)) {
case HostCmd_CMD_802_11_PS_MODE_ENH:
pm = &resp->params.psmode_enh;
- dev_err(adapter->dev,
- "PS_MODE_ENH cmd failed: result=0x%x action=0x%X\n",
- resp->result, le16_to_cpu(pm->action));
+ mwifiex_dbg(adapter, ERROR,
+ "PS_MODE_ENH cmd failed: result=0x%x action=0x%X\n",
+ resp->result, le16_to_cpu(pm->action));
/* We do not re-try enter-ps command in ad-hoc mode. */
if (le16_to_cpu(pm->action) == EN_AUTO_PS &&
(le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) &&
@@ -91,7 +92,8 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
break;
case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
- dev_err(priv->adapter->dev, "SDIO RX single-port aggregation Not support\n");
+ mwifiex_dbg(adapter, MSG,
+ "SDIO RX single-port aggregation Not support\n");
break;
default:
@@ -187,29 +189,34 @@ static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv,
u16 query_type = le16_to_cpu(smib->query_type);
u32 ul_temp;
- dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x,"
- " query_type = %#x, buf size = %#x\n",
- oid, query_type, le16_to_cpu(smib->buf_size));
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: SNMP_RESP: oid value = %#x,\t"
+ "query_type = %#x, buf size = %#x\n",
+ oid, query_type, le16_to_cpu(smib->buf_size));
if (query_type == HostCmd_ACT_GEN_GET) {
ul_temp = le16_to_cpu(*((__le16 *) (smib->value)));
if (data_buf)
*data_buf = ul_temp;
switch (oid) {
case FRAG_THRESH_I:
- dev_dbg(priv->adapter->dev,
- "info: SNMP_RESP: FragThsd =%u\n", ul_temp);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: SNMP_RESP: FragThsd =%u\n",
+ ul_temp);
break;
case RTS_THRESH_I:
- dev_dbg(priv->adapter->dev,
- "info: SNMP_RESP: RTSThsd =%u\n", ul_temp);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: SNMP_RESP: RTSThsd =%u\n",
+ ul_temp);
break;
case SHORT_RETRY_LIM_I:
- dev_dbg(priv->adapter->dev,
- "info: SNMP_RESP: TxRetryCount=%u\n", ul_temp);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: SNMP_RESP: TxRetryCount=%u\n",
+ ul_temp);
break;
case DTIM_PERIOD_I:
- dev_dbg(priv->adapter->dev,
- "info: SNMP_RESP: DTIM period=%u\n", ul_temp);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: SNMP_RESP: DTIM period=%u\n",
+ ul_temp);
default:
break;
}
@@ -426,14 +433,15 @@ static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
priv->tx_power_level = (u16) pg->power_min;
break;
default:
- dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n",
- action);
+ mwifiex_dbg(adapter, ERROR,
+ "CMD_RESP: unknown cmd action %d\n",
+ action);
return 0;
}
- dev_dbg(adapter->dev,
- "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n",
- priv->tx_power_level, priv->max_tx_power_level,
- priv->min_tx_power_level);
+ mwifiex_dbg(adapter, INFO,
+ "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n",
+ priv->tx_power_level, priv->max_tx_power_level,
+ priv->min_tx_power_level);
return 0;
}
@@ -454,10 +462,10 @@ static int mwifiex_ret_rf_tx_power(struct mwifiex_private *priv,
priv->min_tx_power_level = txp->min_power;
}
- dev_dbg(priv->adapter->dev,
- "Current TxPower Level=%d, Max Power=%d, Min Power=%d\n",
- priv->tx_power_level, priv->max_tx_power_level,
- priv->min_tx_power_level);
+ mwifiex_dbg(priv->adapter, INFO,
+ "Current TxPower Level=%d, Max Power=%d, Min Power=%d\n",
+ priv->tx_power_level, priv->max_tx_power_level,
+ priv->min_tx_power_level);
return 0;
}
@@ -473,18 +481,18 @@ static int mwifiex_ret_rf_antenna(struct mwifiex_private *priv,
struct mwifiex_adapter *adapter = priv->adapter;
if (adapter->hw_dev_mcs_support == HT_STREAM_2X2)
- dev_dbg(adapter->dev,
- "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x"
- " Rx action = 0x%x, Rx Mode = 0x%04x\n",
- le16_to_cpu(ant_mimo->action_tx),
- le16_to_cpu(ant_mimo->tx_ant_mode),
- le16_to_cpu(ant_mimo->action_rx),
- le16_to_cpu(ant_mimo->rx_ant_mode));
+ mwifiex_dbg(adapter, INFO,
+ "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x\t"
+ "Rx action = 0x%x, Rx Mode = 0x%04x\n",
+ le16_to_cpu(ant_mimo->action_tx),
+ le16_to_cpu(ant_mimo->tx_ant_mode),
+ le16_to_cpu(ant_mimo->action_rx),
+ le16_to_cpu(ant_mimo->rx_ant_mode));
else
- dev_dbg(adapter->dev,
- "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x\n",
- le16_to_cpu(ant_siso->action),
- le16_to_cpu(ant_siso->ant_mode));
+ mwifiex_dbg(adapter, INFO,
+ "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x\n",
+ le16_to_cpu(ant_siso->action),
+ le16_to_cpu(ant_siso->ant_mode));
return 0;
}
@@ -502,8 +510,8 @@ static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv,
memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN);
- dev_dbg(priv->adapter->dev,
- "info: set mac address: %pM\n", priv->curr_addr);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: set mac address: %pM\n", priv->curr_addr);
return 0;
}
@@ -587,7 +595,8 @@ static int mwifiex_ret_802_11_key_material_v1(struct mwifiex_private *priv,
if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) {
if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) {
- dev_dbg(priv->adapter->dev, "info: key: GTK is set\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: key: GTK is set\n");
priv->wpa_is_gtk_set = true;
priv->scan_block = false;
}
@@ -617,7 +626,7 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv,
key_v2 = &resp->params.key_material_v2;
if (le16_to_cpu(key_v2->action) == HostCmd_ACT_GEN_SET) {
if ((le16_to_cpu(key_v2->key_param_set.key_info) & KEY_MCAST)) {
- dev_dbg(priv->adapter->dev, "info: key: GTK is set\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: key: GTK is set\n");
priv->wpa_is_gtk_set = true;
priv->scan_block = false;
}
@@ -663,14 +672,14 @@ static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv,
- IEEE80211_COUNTRY_STRING_LEN)
/ sizeof(struct ieee80211_country_ie_triplet));
- dev_dbg(priv->adapter->dev,
- "info: 11D Domain Info Resp: no_of_triplet=%d\n",
- no_of_triplet);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: 11D Domain Info Resp: no_of_triplet=%d\n",
+ no_of_triplet);
if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) {
- dev_warn(priv->adapter->dev,
- "11D: invalid number of triplets %d returned\n",
- no_of_triplet);
+ mwifiex_dbg(priv->adapter, FATAL,
+ "11D: invalid number of triplets %d returned\n",
+ no_of_triplet);
return -1;
}
@@ -680,8 +689,8 @@ static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv,
case HostCmd_ACT_GEN_GET:
break;
default:
- dev_err(priv->adapter->dev,
- "11D: invalid action:%d\n", domain_info->action);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "11D: invalid action:%d\n", domain_info->action);
return -1;
}
@@ -741,6 +750,19 @@ mwifiex_ret_p2p_mode_cfg(struct mwifiex_private *priv,
return 0;
}
+/* This function handles the command response of mem_access command
+ */
+static int
+mwifiex_ret_mem_access(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp, void *pioctl_buf)
+{
+ struct host_cmd_ds_mem_access *mem = (void *)&resp->params.mem;
+
+ priv->mem_rw.addr = le32_to_cpu(mem->addr);
+ priv->mem_rw.value = le32_to_cpu(mem->value);
+
+ return 0;
+}
/*
* This function handles the command response of register access.
*
@@ -830,12 +852,12 @@ static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv,
if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET)
return 0;
- dev_dbg(priv->adapter->dev,
- "info: new BSSID %pM\n", ibss_coal_resp->bssid);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: new BSSID %pM\n", ibss_coal_resp->bssid);
/* If rsp has NULL BSSID, Just return..... No Action */
if (is_zero_ether_addr(ibss_coal_resp->bssid)) {
- dev_warn(priv->adapter->dev, "new BSSID is NULL\n");
+ mwifiex_dbg(priv->adapter, FATAL, "new BSSID is NULL\n");
return 0;
}
@@ -871,48 +893,48 @@ static int mwifiex_ret_tdls_oper(struct mwifiex_private *priv,
case ACT_TDLS_DELETE:
if (reason) {
if (!node || reason == TDLS_ERR_LINK_NONEXISTENT)
- dev_dbg(priv->adapter->dev,
- "TDLS link delete for %pM failed: reason %d\n",
- cmd_tdls_oper->peer_mac, reason);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "TDLS link delete for %pM failed: reason %d\n",
+ cmd_tdls_oper->peer_mac, reason);
else
- dev_err(priv->adapter->dev,
- "TDLS link delete for %pM failed: reason %d\n",
- cmd_tdls_oper->peer_mac, reason);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "TDLS link delete for %pM failed: reason %d\n",
+ cmd_tdls_oper->peer_mac, reason);
} else {
- dev_dbg(priv->adapter->dev,
- "TDLS link delete for %pM successful\n",
- cmd_tdls_oper->peer_mac);
+ mwifiex_dbg(priv->adapter, MSG,
+ "TDLS link delete for %pM successful\n",
+ cmd_tdls_oper->peer_mac);
}
break;
case ACT_TDLS_CREATE:
if (reason) {
- dev_err(priv->adapter->dev,
- "TDLS link creation for %pM failed: reason %d",
- cmd_tdls_oper->peer_mac, reason);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "TDLS link creation for %pM failed: reason %d",
+ cmd_tdls_oper->peer_mac, reason);
if (node && reason != TDLS_ERR_LINK_EXISTS)
node->tdls_status = TDLS_SETUP_FAILURE;
} else {
- dev_dbg(priv->adapter->dev,
- "TDLS link creation for %pM successful",
- cmd_tdls_oper->peer_mac);
+ mwifiex_dbg(priv->adapter, MSG,
+ "TDLS link creation for %pM successful",
+ cmd_tdls_oper->peer_mac);
}
break;
case ACT_TDLS_CONFIG:
if (reason) {
- dev_err(priv->adapter->dev,
- "TDLS link config for %pM failed, reason %d\n",
- cmd_tdls_oper->peer_mac, reason);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "TDLS link config for %pM failed, reason %d\n",
+ cmd_tdls_oper->peer_mac, reason);
if (node)
node->tdls_status = TDLS_SETUP_FAILURE;
} else {
- dev_dbg(priv->adapter->dev,
- "TDLS link config for %pM successful\n",
- cmd_tdls_oper->peer_mac);
+ mwifiex_dbg(priv->adapter, MSG,
+ "TDLS link config for %pM successful\n",
+ cmd_tdls_oper->peer_mac);
}
break;
default:
- dev_err(priv->adapter->dev,
- "Unknown TDLS command action response %d", action);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Unknown TDLS command action response %d", action);
return -1;
}
@@ -929,8 +951,30 @@ static int mwifiex_ret_subsc_evt(struct mwifiex_private *priv,
/* For every subscribe event command (Get/Set/Clear), FW reports the
* current set of subscribed events*/
- dev_dbg(priv->adapter->dev, "Bitmap of currently subscribed events: %16x\n",
- le16_to_cpu(cmd_sub_event->events));
+ mwifiex_dbg(priv->adapter, EVENT,
+ "Bitmap of currently subscribed events: %16x\n",
+ le16_to_cpu(cmd_sub_event->events));
+
+ return 0;
+}
+
+static int mwifiex_ret_uap_sta_list(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct host_cmd_ds_sta_list *sta_list =
+ &resp->params.sta_list;
+ struct mwifiex_ie_types_sta_info *sta_info = (void *)&sta_list->tlv;
+ int i;
+ struct mwifiex_sta_node *sta_node;
+
+ for (i = 0; i < sta_list->sta_count; i++) {
+ sta_node = mwifiex_get_sta_entry(priv, sta_info->mac);
+ if (unlikely(!sta_node))
+ continue;
+
+ sta_node->stats.rssi = sta_info->rssi;
+ sta_info++;
+ }
return 0;
}
@@ -940,7 +984,7 @@ static int mwifiex_ret_cfg_data(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp)
{
if (resp->result != HostCmd_RESULT_OK) {
- dev_err(priv->adapter->dev, "Cal data cmd resp failed\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Cal data cmd resp failed\n");
return -1;
}
@@ -1008,8 +1052,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
break;
case HostCmd_CMD_802_11_BG_SCAN_QUERY:
ret = mwifiex_ret_802_11_scan(priv, resp);
- dev_dbg(adapter->dev,
- "info: CMD_RESP: BG_SCAN result is ready!\n");
+ mwifiex_dbg(adapter, CMD,
+ "info: CMD_RESP: BG_SCAN result is ready!\n");
break;
case HostCmd_CMD_TXPWR_CFG:
ret = mwifiex_ret_tx_power_cfg(priv, resp);
@@ -1088,8 +1132,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
/ MWIFIEX_SDIO_BLOCK_SIZE)
* MWIFIEX_SDIO_BLOCK_SIZE;
adapter->curr_tx_buf_size = adapter->tx_buf_size;
- dev_dbg(adapter->dev, "cmd: curr_tx_buf_size=%d\n",
- adapter->curr_tx_buf_size);
+ mwifiex_dbg(adapter, CMD, "cmd: curr_tx_buf_size=%d\n",
+ adapter->curr_tx_buf_size);
if (adapter->if_ops.update_mp_end_port)
adapter->if_ops.update_mp_end_port(adapter,
@@ -1103,6 +1147,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
ret = mwifiex_ret_ibss_coalescing_status(priv, resp);
break;
+ case HostCmd_CMD_MEM_ACCESS:
+ ret = mwifiex_ret_mem_access(priv, resp, data_buf);
+ break;
case HostCmd_CMD_MAC_REG_ACCESS:
case HostCmd_CMD_BBP_REG_ACCESS:
case HostCmd_CMD_RF_REG_ACCESS:
@@ -1122,6 +1169,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
break;
case HostCmd_CMD_UAP_SYS_CONFIG:
break;
+ case HOST_CMD_APCMD_STA_LIST:
+ ret = mwifiex_ret_uap_sta_list(priv, resp);
+ break;
case HostCmd_CMD_UAP_BSS_START:
adapter->tx_lock_flag = false;
adapter->pps_uapsd_mode = false;
@@ -1133,6 +1183,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
break;
case HostCmd_CMD_UAP_STA_DEAUTH:
break;
+ case HOST_CMD_APCMD_SYS_RESET:
+ break;
case HostCmd_CMD_MEF_CFG:
break;
case HostCmd_CMD_COALESCE_CFG:
@@ -1146,8 +1198,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
ret = mwifiex_ret_sdio_rx_aggr_cfg(priv, resp);
break;
default:
- dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
- resp->command);
+ mwifiex_dbg(adapter, ERROR,
+ "CMD_RESP: unknown cmd response %#x\n",
+ resp->command);
break;
}
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 0dc7a1d3993d..848de2621958 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -48,7 +48,8 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
if (!priv->media_connected)
return;
- dev_dbg(adapter->dev, "info: handles disconnect event\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: handles disconnect event\n");
priv->media_connected = false;
@@ -104,12 +105,14 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
* it could be used for re-assoc
*/
- dev_dbg(adapter->dev, "info: previous SSID=%s, SSID len=%u\n",
- priv->prev_ssid.ssid, priv->prev_ssid.ssid_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: previous SSID=%s, SSID len=%u\n",
+ priv->prev_ssid.ssid, priv->prev_ssid.ssid_len);
- dev_dbg(adapter->dev, "info: current SSID=%s, SSID len=%u\n",
- priv->curr_bss_params.bss_descriptor.ssid.ssid,
- priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
+ mwifiex_dbg(adapter, INFO,
+ "info: current SSID=%s, SSID len=%u\n",
+ priv->curr_bss_params.bss_descriptor.ssid.ssid,
+ priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
memcpy(&priv->prev_ssid,
&priv->curr_bss_params.bss_descriptor.ssid,
@@ -127,13 +130,13 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
if (adapter->is_cmd_timedout && adapter->curr_cmd)
return;
priv->media_connected = false;
- dev_dbg(adapter->dev,
- "info: successfully disconnected from %pM: reason code %d\n",
- priv->cfg_bssid, reason_code);
+ mwifiex_dbg(adapter, MSG,
+ "info: successfully disconnected from %pM: reason code %d\n",
+ priv->cfg_bssid, reason_code);
if (priv->bss_mode == NL80211_IFTYPE_STATION ||
priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
cfg80211_disconnected(priv->netdev, reason_code, NULL, 0,
- GFP_KERNEL);
+ false, GFP_KERNEL);
}
eth_zero_addr(priv->cfg_bssid);
@@ -154,13 +157,13 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv,
/* reserved 2 bytes are not mandatory in tdls event */
if (event_skb->len < (sizeof(struct mwifiex_tdls_generic_event) -
sizeof(u16) - sizeof(adapter->event_cause))) {
- dev_err(adapter->dev, "Invalid event length!\n");
+ mwifiex_dbg(adapter, ERROR, "Invalid event length!\n");
return -1;
}
sta_ptr = mwifiex_get_sta_entry(priv, tdls_evt->peer_mac);
if (!sta_ptr) {
- dev_err(adapter->dev, "cannot get sta entry!\n");
+ mwifiex_dbg(adapter, ERROR, "cannot get sta entry!\n");
return -1;
}
@@ -180,6 +183,63 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv,
}
/*
+* This function handles coex events generated by firmware
+*/
+void mwifiex_bt_coex_wlan_param_update_event(struct mwifiex_private *priv,
+ struct sk_buff *event_skb)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_ie_types_header *tlv;
+ struct mwifiex_ie_types_btcoex_aggr_win_size *winsizetlv;
+ struct mwifiex_ie_types_btcoex_scan_time *scantlv;
+ s32 len = event_skb->len - sizeof(u32);
+ u8 *cur_ptr = event_skb->data + sizeof(u32);
+ u16 tlv_type, tlv_len;
+
+ while (len >= sizeof(struct mwifiex_ie_types_header)) {
+ tlv = (struct mwifiex_ie_types_header *)cur_ptr;
+ tlv_len = le16_to_cpu(tlv->len);
+ tlv_type = le16_to_cpu(tlv->type);
+
+ if ((tlv_len + sizeof(struct mwifiex_ie_types_header)) > len)
+ break;
+ switch (tlv_type) {
+ case TLV_BTCOEX_WL_AGGR_WINSIZE:
+ winsizetlv =
+ (struct mwifiex_ie_types_btcoex_aggr_win_size *)tlv;
+ adapter->coex_win_size = winsizetlv->coex_win_size;
+ adapter->coex_tx_win_size =
+ winsizetlv->tx_win_size;
+ adapter->coex_rx_win_size =
+ winsizetlv->rx_win_size;
+ mwifiex_coex_ampdu_rxwinsize(adapter);
+ mwifiex_update_ampdu_txwinsize(adapter);
+ break;
+
+ case TLV_BTCOEX_WL_SCANTIME:
+ scantlv =
+ (struct mwifiex_ie_types_btcoex_scan_time *)tlv;
+ adapter->coex_scan = scantlv->coex_scan;
+ adapter->coex_min_scan_time = scantlv->min_scan_time;
+ adapter->coex_max_scan_time = scantlv->max_scan_time;
+ break;
+
+ default:
+ break;
+ }
+
+ len -= tlv_len + sizeof(struct mwifiex_ie_types_header);
+ cur_ptr += tlv_len +
+ sizeof(struct mwifiex_ie_types_header);
+ }
+
+ dev_dbg(adapter->dev, "coex_scan=%d min_scan=%d coex_win=%d, tx_win=%d rx_win=%d\n",
+ adapter->coex_scan, adapter->coex_min_scan_time,
+ adapter->coex_win_size, adapter->coex_tx_win_size,
+ adapter->coex_rx_win_size);
+}
+
+/*
* This function handles events generated by firmware.
*
* This is a generic function and handles all events.
@@ -239,21 +299,21 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
switch (eventcause) {
case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
- dev_err(adapter->dev,
- "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignore it\n");
+ mwifiex_dbg(adapter, ERROR,
+ "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignore it\n");
break;
case EVENT_LINK_SENSED:
- dev_dbg(adapter->dev, "event: LINK_SENSED\n");
+ mwifiex_dbg(adapter, EVENT, "event: LINK_SENSED\n");
if (!netif_carrier_ok(priv->netdev))
netif_carrier_on(priv->netdev);
mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
break;
case EVENT_DEAUTHENTICATED:
- dev_dbg(adapter->dev, "event: Deauthenticated\n");
+ mwifiex_dbg(adapter, EVENT, "event: Deauthenticated\n");
if (priv->wps.session_enable) {
- dev_dbg(adapter->dev,
- "info: receive deauth event in wps session\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: receive deauth event in wps session\n");
break;
}
adapter->dbg.num_event_deauth++;
@@ -265,10 +325,10 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_DISASSOCIATED:
- dev_dbg(adapter->dev, "event: Disassociated\n");
+ mwifiex_dbg(adapter, EVENT, "event: Disassociated\n");
if (priv->wps.session_enable) {
- dev_dbg(adapter->dev,
- "info: receive disassoc event in wps session\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: receive disassoc event in wps session\n");
break;
}
adapter->dbg.num_event_disassoc++;
@@ -280,7 +340,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_LINK_LOST:
- dev_dbg(adapter->dev, "event: Link lost\n");
+ mwifiex_dbg(adapter, EVENT, "event: Link lost\n");
adapter->dbg.num_event_link_lost++;
if (priv->media_connected) {
reason_code =
@@ -290,7 +350,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_PS_SLEEP:
- dev_dbg(adapter->dev, "info: EVENT: SLEEP\n");
+ mwifiex_dbg(adapter, EVENT, "info: EVENT: SLEEP\n");
adapter->ps_state = PS_STATE_PRE_SLEEP;
@@ -298,12 +358,12 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_PS_AWAKE:
- dev_dbg(adapter->dev, "info: EVENT: AWAKE\n");
+ mwifiex_dbg(adapter, EVENT, "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");
+ mwifiex_dbg(adapter, EVENT,
+ "event: PPS/UAPSD mode activated\n");
}
adapter->tx_lock_flag = false;
if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
@@ -333,26 +393,26 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
case EVENT_DEEP_SLEEP_AWAKE:
adapter->if_ops.wakeup_complete(adapter);
- dev_dbg(adapter->dev, "event: DS_AWAKE\n");
+ mwifiex_dbg(adapter, EVENT, "event: DS_AWAKE\n");
if (adapter->is_deep_sleep)
adapter->is_deep_sleep = false;
break;
case EVENT_HS_ACT_REQ:
- dev_dbg(adapter->dev, "event: HS_ACT_REQ\n");
+ mwifiex_dbg(adapter, EVENT, "event: HS_ACT_REQ\n");
ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH,
0, 0, NULL, false);
break;
case EVENT_MIC_ERR_UNICAST:
- dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n");
+ mwifiex_dbg(adapter, EVENT, "event: UNICAST MIC ERROR\n");
cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
NL80211_KEYTYPE_PAIRWISE,
-1, NULL, GFP_KERNEL);
break;
case EVENT_MIC_ERR_MULTICAST:
- dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n");
+ mwifiex_dbg(adapter, EVENT, "event: MULTICAST MIC ERROR\n");
cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
NL80211_KEYTYPE_GROUP,
-1, NULL, GFP_KERNEL);
@@ -362,7 +422,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_ADHOC_BCN_LOST:
- dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n");
+ mwifiex_dbg(adapter, EVENT, "event: ADHOC_BCN_LOST\n");
priv->adhoc_is_link_sensed = false;
mwifiex_clean_txrx(priv);
mwifiex_stop_net_dev_queue(priv->netdev, adapter);
@@ -371,17 +431,17 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_BG_SCAN_REPORT:
- dev_dbg(adapter->dev, "event: BGS_REPORT\n");
+ mwifiex_dbg(adapter, EVENT, "event: BGS_REPORT\n");
ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_QUERY,
HostCmd_ACT_GEN_GET, 0, NULL, false);
break;
case EVENT_PORT_RELEASE:
- dev_dbg(adapter->dev, "event: PORT RELEASE\n");
+ mwifiex_dbg(adapter, EVENT, "event: PORT RELEASE\n");
break;
case EVENT_EXT_SCAN_REPORT:
- dev_dbg(adapter->dev, "event: EXT_SCAN Report\n");
+ mwifiex_dbg(adapter, EVENT, "event: EXT_SCAN Report\n");
if (adapter->ext_scan)
ret = mwifiex_handle_event_ext_scan_report(priv,
adapter->event_skb->data);
@@ -389,7 +449,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_WMM_STATUS_CHANGE:
- dev_dbg(adapter->dev, "event: WMM status changed\n");
+ mwifiex_dbg(adapter, EVENT, "event: WMM status changed\n");
ret = mwifiex_send_cmd(priv, HostCmd_CMD_WMM_GET_STATUS,
0, 0, NULL, false);
break;
@@ -401,13 +461,13 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
HostCmd_ACT_GEN_GET, 0, NULL, false);
priv->subsc_evt_rssi_state = RSSI_LOW_RECVD;
- dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n");
+ mwifiex_dbg(adapter, EVENT, "event: Beacon RSSI_LOW\n");
break;
case EVENT_SNR_LOW:
- dev_dbg(adapter->dev, "event: Beacon SNR_LOW\n");
+ mwifiex_dbg(adapter, EVENT, "event: Beacon SNR_LOW\n");
break;
case EVENT_MAX_FAIL:
- dev_dbg(adapter->dev, "event: MAX_FAIL\n");
+ mwifiex_dbg(adapter, EVENT, "event: MAX_FAIL\n");
break;
case EVENT_RSSI_HIGH:
cfg80211_cqm_rssi_notify(priv->netdev,
@@ -416,47 +476,47 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
HostCmd_ACT_GEN_GET, 0, NULL, false);
priv->subsc_evt_rssi_state = RSSI_HIGH_RECVD;
- dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n");
+ mwifiex_dbg(adapter, EVENT, "event: Beacon RSSI_HIGH\n");
break;
case EVENT_SNR_HIGH:
- dev_dbg(adapter->dev, "event: Beacon SNR_HIGH\n");
+ mwifiex_dbg(adapter, EVENT, "event: Beacon SNR_HIGH\n");
break;
case EVENT_DATA_RSSI_LOW:
- dev_dbg(adapter->dev, "event: Data RSSI_LOW\n");
+ mwifiex_dbg(adapter, EVENT, "event: Data RSSI_LOW\n");
break;
case EVENT_DATA_SNR_LOW:
- dev_dbg(adapter->dev, "event: Data SNR_LOW\n");
+ mwifiex_dbg(adapter, EVENT, "event: Data SNR_LOW\n");
break;
case EVENT_DATA_RSSI_HIGH:
- dev_dbg(adapter->dev, "event: Data RSSI_HIGH\n");
+ mwifiex_dbg(adapter, EVENT, "event: Data RSSI_HIGH\n");
break;
case EVENT_DATA_SNR_HIGH:
- dev_dbg(adapter->dev, "event: Data SNR_HIGH\n");
+ mwifiex_dbg(adapter, EVENT, "event: Data SNR_HIGH\n");
break;
case EVENT_LINK_QUALITY:
- dev_dbg(adapter->dev, "event: Link Quality\n");
+ mwifiex_dbg(adapter, EVENT, "event: Link Quality\n");
break;
case EVENT_PRE_BEACON_LOST:
- dev_dbg(adapter->dev, "event: Pre-Beacon Lost\n");
+ mwifiex_dbg(adapter, EVENT, "event: Pre-Beacon Lost\n");
break;
case EVENT_IBSS_COALESCED:
- dev_dbg(adapter->dev, "event: IBSS_COALESCED\n");
+ mwifiex_dbg(adapter, EVENT, "event: IBSS_COALESCED\n");
ret = mwifiex_send_cmd(priv,
HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
HostCmd_ACT_GEN_GET, 0, NULL, false);
break;
case EVENT_ADDBA:
- dev_dbg(adapter->dev, "event: ADDBA Request\n");
+ mwifiex_dbg(adapter, EVENT, "event: ADDBA Request\n");
mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP,
HostCmd_ACT_GEN_SET, 0,
adapter->event_body, false);
break;
case EVENT_DELBA:
- dev_dbg(adapter->dev, "event: DELBA Request\n");
+ mwifiex_dbg(adapter, EVENT, "event: DELBA Request\n");
mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
break;
case EVENT_BA_STREAM_TIEMOUT:
- dev_dbg(adapter->dev, "event: BA Stream timeout\n");
+ mwifiex_dbg(adapter, EVENT, "event: BA Stream timeout\n");
mwifiex_11n_ba_stream_timeout(priv,
(struct host_cmd_ds_11n_batimeout
*)
@@ -464,28 +524,31 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_AMSDU_AGGR_CTRL:
ctrl = le16_to_cpu(*(__le16 *)adapter->event_body);
- dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl);
+ mwifiex_dbg(adapter, EVENT,
+ "event: AMSDU_AGGR_CTRL %d\n", ctrl);
adapter->tx_buf_size =
min_t(u16, adapter->curr_tx_buf_size, ctrl);
- dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
- adapter->tx_buf_size);
+ mwifiex_dbg(adapter, EVENT, "event: tx_buf_size %d\n",
+ adapter->tx_buf_size);
break;
case EVENT_WEP_ICV_ERR:
- dev_dbg(adapter->dev, "event: WEP ICV error\n");
+ mwifiex_dbg(adapter, EVENT, "event: WEP ICV error\n");
break;
case EVENT_BW_CHANGE:
- dev_dbg(adapter->dev, "event: BW Change\n");
+ mwifiex_dbg(adapter, EVENT, "event: BW Change\n");
break;
case EVENT_HOSTWAKE_STAIE:
- dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
+ mwifiex_dbg(adapter, EVENT,
+ "event: HOSTWAKE_STAIE %d\n", eventcause);
break;
case EVENT_REMAIN_ON_CHAN_EXPIRED:
- dev_dbg(adapter->dev, "event: Remain on channel expired\n");
+ mwifiex_dbg(adapter, EVENT,
+ "event: Remain on channel expired\n");
cfg80211_remain_on_channel_expired(&priv->wdev,
priv->roc_cfg.cookie,
&priv->roc_cfg.chan,
@@ -496,7 +559,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_CHANNEL_SWITCH_ANN:
- dev_dbg(adapter->dev, "event: Channel Switch Announcement\n");
+ mwifiex_dbg(adapter, EVENT, "event: Channel Switch Announcement\n");
priv->csa_expire_time =
jiffies + msecs_to_jiffies(DFS_CHAN_MOVE_TIME);
priv->csa_chan = priv->curr_bss_params.bss_descriptor.channel;
@@ -511,23 +574,28 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
break;
case EVENT_TX_STATUS_REPORT:
- dev_dbg(adapter->dev, "event: TX_STATUS Report\n");
+ mwifiex_dbg(adapter, EVENT, "event: TX_STATUS Report\n");
mwifiex_parse_tx_status_event(priv, adapter->event_body);
break;
case EVENT_CHANNEL_REPORT_RDY:
- dev_dbg(adapter->dev, "event: Channel Report\n");
+ mwifiex_dbg(adapter, EVENT, "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");
+ mwifiex_dbg(adapter, EVENT, "event: Radar detected\n");
ret = mwifiex_11h_handle_radar_detected(priv,
adapter->event_skb);
break;
+ case EVENT_BT_COEX_WLAN_PARA_CHANGE:
+ dev_dbg(adapter->dev, "EVENT: BT coex wlan param update\n");
+ mwifiex_bt_coex_wlan_param_update_event(priv,
+ adapter->event_skb);
+ break;
default:
- dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
- eventcause);
+ mwifiex_dbg(adapter, ERROR, "event: unknown event id: %#x\n",
+ eventcause);
break;
}
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 0599e41e253c..d8b7d9c20450 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -64,7 +64,10 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
*(cmd_queued->condition),
(12 * HZ));
if (status <= 0) {
- dev_err(adapter->dev, "cmd_wait_q terminated: %d\n", status);
+ if (status == 0)
+ status = -ETIMEDOUT;
+ mwifiex_dbg(adapter, ERROR,
+ "cmd_wait_q terminated: %d\n", status);
mwifiex_cancel_all_pending_cmd(adapter);
return status;
}
@@ -91,7 +94,8 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
old_pkt_filter = priv->curr_pkt_filter;
if (mcast_list->mode == MWIFIEX_PROMISC_MODE) {
- dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: Enable Promiscuous mode\n");
priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
priv->curr_pkt_filter &=
~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
@@ -99,16 +103,16 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
/* Multicast */
priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
if (mcast_list->mode == MWIFIEX_ALL_MULTI_MODE) {
- dev_dbg(priv->adapter->dev,
- "info: Enabling All Multicast!\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: Enabling All Multicast!\n");
priv->curr_pkt_filter |=
HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
} else {
priv->curr_pkt_filter &=
~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
- dev_dbg(priv->adapter->dev,
- "info: Set multicast list=%d\n",
- mcast_list->num_multicast_addr);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: Set multicast list=%d\n",
+ mcast_list->num_multicast_addr);
/* Send multicast addresses to firmware */
ret = mwifiex_send_cmd(priv,
HostCmd_CMD_MAC_MULTICAST_ADR,
@@ -116,9 +120,9 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
mcast_list, false);
}
}
- dev_dbg(priv->adapter->dev,
- "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
- old_pkt_filter, priv->curr_pkt_filter);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
+ old_pkt_filter, priv->curr_pkt_filter);
if (old_pkt_filter != priv->curr_pkt_filter) {
ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
HostCmd_ACT_GEN_SET,
@@ -151,7 +155,8 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
rcu_read_unlock();
if (!beacon_ie) {
- dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ " failed to alloc beacon_ie\n");
return -ENOMEM;
}
@@ -165,7 +170,8 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
bss_desc->bss_band = bss_priv->band;
bss_desc->fw_tsf = bss_priv->fw_tsf;
if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
- dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: InterpretIE: AP WEP enabled\n");
bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
} else {
bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
@@ -219,8 +225,8 @@ 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,
- "11D: skip setting domain info in FW\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "11D: skip setting domain info in FW\n");
return 0;
}
memcpy(priv->adapter->country_code, &country_ie[2], 2);
@@ -241,8 +247,8 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
HostCmd_ACT_GEN_SET, 0, NULL, false)) {
- wiphy_err(priv->adapter->wiphy,
- "11D: setting domain info in FW\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "11D: setting domain info in FW fail\n");
return -1;
}
@@ -304,14 +310,15 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
if (mwifiex_11h_get_csa_closed_channel(priv) ==
(u8)bss_desc->channel) {
- dev_err(adapter->dev,
- "Attempt to reconnect on csa closed chan(%d)\n",
- bss_desc->channel);
+ mwifiex_dbg(adapter, ERROR,
+ "Attempt to reconnect on csa closed chan(%d)\n",
+ bss_desc->channel);
goto done;
}
- dev_dbg(adapter->dev, "info: SSID found in scan list ... "
- "associating...\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: SSID found in scan list ...\t"
+ "associating...\n");
mwifiex_stop_net_dev_queue(priv->netdev, adapter);
if (netif_carrier_ok(priv->netdev))
@@ -353,15 +360,17 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
netif_carrier_off(priv->netdev);
if (!ret) {
- dev_dbg(adapter->dev, "info: network found in scan"
- " list. Joining...\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: network found in scan\t"
+ " list. Joining...\n");
ret = mwifiex_adhoc_join(priv, bss_desc);
if (bss)
cfg80211_put_bss(priv->adapter->wiphy, bss);
} else {
- dev_dbg(adapter->dev, "info: Network not found in "
- "the list, creating adhoc with ssid = %s\n",
- req_ssid->ssid);
+ mwifiex_dbg(adapter, INFO,
+ "info: Network not found in\t"
+ "the list, creating adhoc with ssid = %s\n",
+ req_ssid->ssid);
ret = mwifiex_adhoc_start(priv, req_ssid);
}
}
@@ -396,8 +405,9 @@ int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
switch (action) {
case HostCmd_ACT_GEN_SET:
if (adapter->pps_uapsd_mode) {
- dev_dbg(adapter->dev, "info: Host Sleep IOCTL"
- " is blocked in UAPSD/PPS mode\n");
+ mwifiex_dbg(adapter, INFO,
+ "info: Host Sleep IOCTL\t"
+ "is blocked in UAPSD/PPS mode\n");
status = -1;
break;
}
@@ -494,7 +504,8 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
}
if (adapter->hs_activated) {
- dev_dbg(adapter->dev, "cmd: HS Already activated\n");
+ mwifiex_dbg(adapter, CMD,
+ "cmd: HS Already activated\n");
return true;
}
@@ -510,14 +521,16 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
MWIFIEX_BSS_ROLE_STA),
HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD,
&hscfg)) {
- dev_err(adapter->dev, "IOCTL request HS enable failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "IOCTL request HS enable failed\n");
return false;
}
if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q,
adapter->hs_activate_wait_q_woken,
(10 * HZ)) <= 0) {
- dev_err(adapter->dev, "hs_activate_wait_q terminated\n");
+ mwifiex_dbg(adapter, ERROR,
+ "hs_activate_wait_q terminated\n");
return false;
}
@@ -637,10 +650,11 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv,
dbm = (u16) power_cfg->power_level;
if ((dbm < priv->min_tx_power_level) ||
(dbm > priv->max_tx_power_level)) {
- dev_err(priv->adapter->dev, "txpower value %d dBm"
- " is out of range (%d dBm-%d dBm)\n",
- dbm, priv->min_tx_power_level,
- priv->max_tx_power_level);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "txpower value %d dBm\t"
+ "is out of range (%d dBm-%d dBm)\n",
+ dbm, priv->min_tx_power_level,
+ priv->max_tx_power_level);
return -1;
}
}
@@ -739,14 +753,15 @@ static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv,
{
if (ie_len) {
if (ie_len > sizeof(priv->wpa_ie)) {
- dev_err(priv->adapter->dev,
- "failed to copy WPA IE, too big\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "failed to copy WPA IE, too big\n");
return -1;
}
memcpy(priv->wpa_ie, ie_data_ptr, ie_len);
priv->wpa_ie_len = (u8) ie_len;
- dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n",
- priv->wpa_ie_len, priv->wpa_ie[0]);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: Set Wpa_ie_len=%d IE=%#x\n",
+ priv->wpa_ie_len, priv->wpa_ie[0]);
if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) {
priv->sec_info.wpa_enabled = true;
@@ -759,8 +774,9 @@ static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv,
} else {
memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));
priv->wpa_ie_len = 0;
- dev_dbg(priv->adapter->dev, "info: reset wpa_ie_len=%d IE=%#x\n",
- priv->wpa_ie_len, priv->wpa_ie[0]);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: reset wpa_ie_len=%d IE=%#x\n",
+ priv->wpa_ie_len, priv->wpa_ie[0]);
priv->sec_info.wpa_enabled = false;
priv->sec_info.wpa2_enabled = false;
}
@@ -780,23 +796,24 @@ static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,
{
if (ie_len) {
if (ie_len > sizeof(priv->wapi_ie)) {
- dev_dbg(priv->adapter->dev,
- "info: failed to copy WAPI IE, too big\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "info: failed to copy WAPI IE, too big\n");
return -1;
}
memcpy(priv->wapi_ie, ie_data_ptr, ie_len);
priv->wapi_ie_len = ie_len;
- dev_dbg(priv->adapter->dev, "cmd: Set wapi_ie_len=%d IE=%#x\n",
- priv->wapi_ie_len, priv->wapi_ie[0]);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: Set wapi_ie_len=%d IE=%#x\n",
+ priv->wapi_ie_len, priv->wapi_ie[0]);
if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY)
priv->sec_info.wapi_enabled = true;
} else {
memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie));
priv->wapi_ie_len = ie_len;
- dev_dbg(priv->adapter->dev,
- "info: Reset wapi_ie_len=%d IE=%#x\n",
- priv->wapi_ie_len, priv->wapi_ie[0]);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: Reset wapi_ie_len=%d IE=%#x\n",
+ priv->wapi_ie_len, priv->wapi_ie[0]);
priv->sec_info.wapi_enabled = false;
}
return 0;
@@ -814,8 +831,8 @@ static int mwifiex_set_wps_ie(struct mwifiex_private *priv,
{
if (ie_len) {
if (ie_len > MWIFIEX_MAX_VSIE_LEN) {
- dev_dbg(priv->adapter->dev,
- "info: failed to copy WPS IE, too big\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "info: failed to copy WPS IE, too big\n");
return -1;
}
@@ -825,13 +842,14 @@ static int mwifiex_set_wps_ie(struct mwifiex_private *priv,
memcpy(priv->wps_ie, ie_data_ptr, ie_len);
priv->wps_ie_len = ie_len;
- dev_dbg(priv->adapter->dev, "cmd: Set wps_ie_len=%d IE=%#x\n",
- priv->wps_ie_len, priv->wps_ie[0]);
+ mwifiex_dbg(priv->adapter, CMD,
+ "cmd: Set wps_ie_len=%d IE=%#x\n",
+ priv->wps_ie_len, priv->wps_ie[0]);
} else {
kfree(priv->wps_ie);
priv->wps_ie_len = ie_len;
- dev_dbg(priv->adapter->dev,
- "info: Reset wps_ie_len=%d\n", priv->wps_ie_len);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: Reset wps_ie_len=%d\n", priv->wps_ie_len);
}
return 0;
}
@@ -875,8 +893,8 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
/* Copy the required key as the current key */
wep_key = &priv->wep_key[index];
if (!wep_key->key_length) {
- dev_err(adapter->dev,
- "key not set, so cannot enable it\n");
+ mwifiex_dbg(adapter, ERROR,
+ "key not set, so cannot enable it\n");
return -1;
}
@@ -953,7 +971,8 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,
/* Current driver only supports key length of up to 32 bytes */
if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) {
- dev_err(priv->adapter->dev, "key length too long\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "key length too long\n");
return -1;
}
@@ -1040,7 +1059,7 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
snprintf(version, max_len, driver_version, fw_ver);
- dev_dbg(adapter->dev, "info: MWIFIEX VERSION: %s\n", version);
+ mwifiex_dbg(adapter, MSG, "info: MWIFIEX VERSION: %s\n", version);
return 0;
}
@@ -1128,7 +1147,8 @@ mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
}
if (mwifiex_send_cmd(priv, HostCmd_CMD_REMAIN_ON_CHAN,
action, 0, &roc_cfg, true)) {
- dev_err(priv->adapter->dev, "failed to remain on channel\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "failed to remain on channel\n");
return -1;
}
@@ -1313,8 +1333,8 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) &&
(!memcmp(pvendor_ie->oui, wps_oui, sizeof(wps_oui)))) {
priv->wps.session_enable = true;
- dev_dbg(priv->adapter->dev,
- "info: WPS Session Enabled.\n");
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: WPS Session Enabled.\n");
ret = mwifiex_set_wps_ie(priv, ie_data_ptr, ie_len);
}
@@ -1361,7 +1381,8 @@ static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter));
if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) {
adapter->arp_filter_size = 0;
- dev_err(adapter->dev, "invalid ARP filter size\n");
+ mwifiex_dbg(adapter, ERROR,
+ "invalid ARP filter size\n");
return -1;
} else {
memcpy(adapter->arp_filter, gen_ie->ie_data,
@@ -1370,7 +1391,7 @@ static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
}
break;
default:
- dev_err(adapter->dev, "invalid IE type\n");
+ mwifiex_dbg(adapter, ERROR, "invalid IE type\n");
return -1;
}
return 0;
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c
index b8729c9394e9..d4d4cb1ce95b 100644
--- a/drivers/net/wireless/mwifiex/sta_rx.c
+++ b/drivers/net/wireless/mwifiex/sta_rx.c
@@ -141,7 +141,7 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
if (priv->hs2_enabled &&
mwifiex_discard_gratuitous_arp(priv, skb)) {
- dev_dbg(priv->adapter->dev, "Bypassed Gratuitous ARP\n");
+ mwifiex_dbg(priv->adapter, INFO, "Bypassed Gratuitous ARP\n");
dev_kfree_skb_any(skb);
return 0;
}
@@ -166,7 +166,8 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
ret = mwifiex_recv_packet(priv, skb);
if (ret == -1)
- dev_err(priv->adapter->dev, "recv packet failed\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "recv packet failed\n");
return ret;
}
@@ -203,9 +204,9 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv,
rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset;
if ((rx_pkt_offset + rx_pkt_length) > (u16) skb->len) {
- dev_err(adapter->dev,
- "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n",
- skb->len, rx_pkt_offset, rx_pkt_length);
+ mwifiex_dbg(adapter, ERROR,
+ "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n",
+ skb->len, rx_pkt_offset, rx_pkt_length);
priv->stats.rx_dropped++;
dev_kfree_skb_any(skb);
return ret;
@@ -214,7 +215,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv,
if (rx_pkt_type == PKT_TYPE_MGMT) {
ret = mwifiex_process_mgmt_packet(priv, skb);
if (ret)
- dev_err(adapter->dev, "Rx of mgmt packet failed");
+ mwifiex_dbg(adapter, ERROR, "Rx of mgmt packet failed");
dev_kfree_skb_any(skb);
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
index 5ce2d9a4f919..355ac5904fac 100644
--- a/drivers/net/wireless/mwifiex/sta_tx.c
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -53,7 +53,8 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
INTF_HEADER_LEN;
if (!skb->len) {
- dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len);
+ mwifiex_dbg(adapter, ERROR,
+ "Tx: bad packet length: %d\n", skb->len);
tx_info->status_code = -1;
return skb->data;
}
@@ -184,21 +185,24 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
switch (ret) {
case -EBUSY:
dev_kfree_skb_any(skb);
- dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n",
- __func__, ret);
+ mwifiex_dbg(adapter, ERROR,
+ "%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);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: host_to_card failed: ret=%d\n",
+ __func__, ret);
adapter->dbg.num_tx_host_to_card_failure++;
break;
case 0:
dev_kfree_skb_any(skb);
- dev_dbg(adapter->dev, "data: %s: host_to_card succeeded\n",
- __func__);
+ mwifiex_dbg(adapter, DATA,
+ "data: %s: host_to_card succeeded\n",
+ __func__);
adapter->tx_lock_flag = true;
break;
case -EINPROGRESS:
diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c
index 087d84762cd3..2faa1bc42abe 100644
--- a/drivers/net/wireless/mwifiex/tdls.c
+++ b/drivers/net/wireless/mwifiex/tdls.c
@@ -37,7 +37,7 @@ static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv,
u32 tid;
u8 tid_down;
- dev_dbg(priv->adapter->dev, "%s: %pM\n", __func__, mac);
+ mwifiex_dbg(priv->adapter, DATA, "%s: %pM\n", __func__, mac);
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) {
@@ -94,7 +94,7 @@ static void mwifiex_hold_tdls_packets(struct mwifiex_private *priv,
unsigned long flags;
int i;
- dev_dbg(priv->adapter->dev, "%s: %pM\n", __func__, mac);
+ mwifiex_dbg(priv->adapter, DATA, "%s: %pM\n", __func__, mac);
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
for (i = 0; i < MAX_NUM_TID; i++) {
@@ -132,8 +132,8 @@ mwifiex_tdls_append_rates_ie(struct mwifiex_private *priv,
supp_rates_size = min_t(u16, rates_size, MWIFIEX_TDLS_SUPPORTED_RATES);
if (skb_tailroom(skb) < rates_size + 4) {
- dev_err(priv->adapter->dev,
- "Insuffient space while adding rates\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Insuffient space while adding rates\n");
return -ENOMEM;
}
@@ -199,8 +199,8 @@ mwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, const u8 *mac,
sta_ptr = mwifiex_get_sta_entry(priv, mac);
if (unlikely(!sta_ptr)) {
- dev_warn(priv->adapter->dev,
- "TDLS peer station not found in list\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "TDLS peer station not found in list\n");
return -1;
}
@@ -247,15 +247,16 @@ static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv,
sta_ptr = mwifiex_get_sta_entry(priv, mac);
if (unlikely(!sta_ptr)) {
- dev_warn(adapter->dev, "TDLS peer station not found in list\n");
+ mwifiex_dbg(adapter, ERROR,
+ "TDLS peer station not found in list\n");
return -1;
}
if (!mwifiex_is_bss_in_11ac_mode(priv)) {
if (sta_ptr->tdls_cap.extcap.ext_capab[7] &
WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) {
- dev_dbg(adapter->dev,
- "TDLS peer doesn't support wider bandwitdh\n");
+ mwifiex_dbg(adapter, WARN,
+ "TDLS peer doesn't support wider bandwidth\n");
return 0;
}
} else {
@@ -554,7 +555,7 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv,
tf->u.discover_req.dialog_token = dialog_token;
break;
default:
- dev_err(priv->adapter->dev, "Unknown TDLS frame type.\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS frame type.\n");
return -EINVAL;
}
@@ -608,8 +609,8 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer,
skb = dev_alloc_skb(skb_len);
if (!skb) {
- dev_err(priv->adapter->dev,
- "allocate skb failed for management frame\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "allocate skb failed for management frame\n");
return -ENOMEM;
}
skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
@@ -742,7 +743,7 @@ mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv,
mwifiex_tdls_add_qos_capab(skb);
break;
default:
- dev_err(priv->adapter->dev, "Unknown TDLS action frame type\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS action frame type\n");
return -EINVAL;
}
@@ -781,8 +782,8 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer,
skb = dev_alloc_skb(skb_len);
if (!skb) {
- dev_err(priv->adapter->dev,
- "allocate skb failed for management frame\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "allocate skb failed for management frame\n");
return -ENOMEM;
}
@@ -848,8 +849,8 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
peer = buf + ETH_ALEN;
action = *(buf + sizeof(struct ethhdr) + 2);
- dev_dbg(priv->adapter->dev,
- "rx:tdls action: peer=%pM, action=%d\n", peer, action);
+ mwifiex_dbg(priv->adapter, DATA,
+ "rx:tdls action: peer=%pM, action=%d\n", peer, action);
switch (action) {
case WLAN_TDLS_SETUP_REQUEST:
@@ -880,7 +881,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
ie_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN;
break;
default:
- dev_dbg(priv->adapter->dev, "Unknown TDLS frame type.\n");
+ mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS frame type.\n");
return;
}
@@ -967,8 +968,8 @@ mwifiex_tdls_process_config_link(struct mwifiex_private *priv, const u8 *peer)
sta_ptr = mwifiex_get_sta_entry(priv, peer);
if (!sta_ptr || sta_ptr->tdls_status == TDLS_SETUP_FAILURE) {
- dev_err(priv->adapter->dev,
- "link absent for peer %pM; cannot config\n", peer);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "link absent for peer %pM; cannot config\n", peer);
return -EINVAL;
}
@@ -988,8 +989,8 @@ mwifiex_tdls_process_create_link(struct mwifiex_private *priv, const u8 *peer)
sta_ptr = mwifiex_get_sta_entry(priv, peer);
if (sta_ptr && sta_ptr->tdls_status == TDLS_SETUP_INPROGRESS) {
- dev_dbg(priv->adapter->dev,
- "Setup already in progress for peer %pM\n", peer);
+ mwifiex_dbg(priv->adapter, WARN,
+ "Setup already in progress for peer %pM\n", peer);
return 0;
}
@@ -1046,8 +1047,8 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)
sta_ptr = mwifiex_get_sta_entry(priv, peer);
if (sta_ptr && (sta_ptr->tdls_status != TDLS_SETUP_FAILURE)) {
- dev_dbg(priv->adapter->dev,
- "tdls: enable link %pM success\n", peer);
+ mwifiex_dbg(priv->adapter, MSG,
+ "tdls: enable link %pM success\n", peer);
sta_ptr->tdls_status = TDLS_SETUP_COMPLETE;
@@ -1076,8 +1077,8 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)
mwifiex_auto_tdls_update_peer_status(priv, peer,
TDLS_SETUP_COMPLETE);
} else {
- dev_dbg(priv->adapter->dev,
- "tdls: enable link %pM failed\n", peer);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "tdls: enable link %pM failed\n", peer);
if (sta_ptr) {
mwifiex_11n_cleanup_reorder_tbl(priv);
spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
@@ -1180,9 +1181,9 @@ void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv)
tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
if (mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
HostCmd_ACT_GEN_SET, 0, &tdls_oper, false))
- dev_warn(priv->adapter->dev,
- "Disable link failed for TDLS peer %pM",
- sta_ptr->mac_addr);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Disable link failed for TDLS peer %pM",
+ sta_ptr->mac_addr);
}
mwifiex_del_all_sta_list(priv);
@@ -1204,9 +1205,9 @@ int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb)
(peer->failure_count <
MWIFIEX_TDLS_MAX_FAIL_COUNT)) {
peer->tdls_status = TDLS_SETUP_INPROGRESS;
- dev_dbg(priv->adapter->dev,
- "setup TDLS link, peer=%pM rssi=%d\n",
- peer->mac_addr, peer->rssi);
+ mwifiex_dbg(priv->adapter, INFO,
+ "setup TDLS link, peer=%pM rssi=%d\n",
+ peer->mac_addr, peer->rssi);
cfg80211_tdls_oper_request(priv->netdev,
peer->mac_addr,
@@ -1272,8 +1273,8 @@ void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac)
tdls_peer->rssi_jiffies = jiffies;
INIT_LIST_HEAD(&tdls_peer->list);
list_add_tail(&tdls_peer->list, &priv->auto_tdls_list);
- dev_dbg(priv->adapter->dev, "Add auto TDLS peer= %pM to list\n",
- mac);
+ mwifiex_dbg(priv->adapter, INFO,
+ "Add auto TDLS peer= %pM to list\n", mac);
}
spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
@@ -1341,8 +1342,8 @@ void mwifiex_check_auto_tdls(unsigned long context)
return;
if (!priv->auto_tdls_timer_active) {
- dev_dbg(priv->adapter->dev,
- "auto TDLS timer inactive; return");
+ mwifiex_dbg(priv->adapter, INFO,
+ "auto TDLS timer inactive; return");
return;
}
@@ -1368,9 +1369,9 @@ void mwifiex_check_auto_tdls(unsigned long context)
!tdls_peer->rssi) &&
tdls_peer->tdls_status == TDLS_SETUP_COMPLETE) {
tdls_peer->tdls_status = TDLS_LINK_TEARDOWN;
- dev_dbg(priv->adapter->dev,
- "teardown TDLS link,peer=%pM rssi=%d\n",
- tdls_peer->mac_addr, -tdls_peer->rssi);
+ mwifiex_dbg(priv->adapter, MSG,
+ "teardown TDLS link,peer=%pM rssi=%d\n",
+ tdls_peer->mac_addr, -tdls_peer->rssi);
tdls_peer->do_discover = true;
priv->check_tdls_tx = true;
cfg80211_tdls_oper_request(priv->netdev,
@@ -1384,9 +1385,10 @@ void mwifiex_check_auto_tdls(unsigned long context)
MWIFIEX_TDLS_MAX_FAIL_COUNT) {
priv->check_tdls_tx = true;
tdls_peer->do_setup = true;
- dev_dbg(priv->adapter->dev,
- "check TDLS with peer=%pM rssi=%d\n",
- tdls_peer->mac_addr, -tdls_peer->rssi);
+ mwifiex_dbg(priv->adapter, INFO,
+ "check TDLS with peer=%pM\t"
+ "rssi=%d\n", tdls_peer->mac_addr,
+ tdls_peer->rssi);
}
}
spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index a245f444aeec..5ed9b794053e 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -50,11 +50,15 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
if (!priv) {
- dev_err(adapter->dev, "data: priv not found. Drop RX packet\n");
+ mwifiex_dbg(adapter, ERROR,
+ "data: priv not found. Drop RX packet\n");
dev_kfree_skb_any(skb);
return -1;
}
+ mwifiex_dbg_dump(adapter, DAT_D, "rx pkt:", skb->data,
+ min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN));
+
memset(rx_info, 0, sizeof(*rx_info));
rx_info->bss_num = priv->bss_num;
rx_info->bss_type = priv->bss_type;
@@ -84,13 +88,22 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
struct mwifiex_adapter *adapter = priv->adapter;
u8 *head_ptr;
struct txpd *local_tx_pd = NULL;
+ struct mwifiex_sta_node *dest_node;
+ struct ethhdr *hdr = (void *)skb->data;
hroom = (adapter->iface_type == MWIFIEX_USB) ? 0 : INTF_HEADER_LEN;
- if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+ if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
+ dest_node = mwifiex_get_sta_entry(priv, hdr->h_dest);
+ if (dest_node) {
+ dest_node->stats.tx_bytes += skb->len;
+ dest_node->stats.tx_packets++;
+ }
+
head_ptr = mwifiex_process_uap_txpd(priv, skb);
- else
+ } else {
head_ptr = mwifiex_process_sta_txpd(priv, skb);
+ }
if ((adapter->data_sent || adapter->tx_lock_flag) && head_ptr) {
skb_queue_tail(&adapter->tx_data_q, skb);
@@ -112,10 +125,12 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
skb, tx_param);
}
}
+ mwifiex_dbg_dump(adapter, DAT_D, "tx pkt:", skb->data,
+ min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN));
switch (ret) {
case -ENOSR:
- dev_dbg(adapter->dev, "data: -ENOSR is returned\n");
+ mwifiex_dbg(adapter, ERROR, "data: -ENOSR is returned\n");
break;
case -EBUSY:
if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
@@ -124,13 +139,14 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
if (local_tx_pd)
local_tx_pd->flags = 0;
}
- dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+ mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
break;
case -1:
if (adapter->iface_type != MWIFIEX_PCIE)
adapter->data_sent = false;
- dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",
- ret);
+ mwifiex_dbg(adapter, ERROR,
+ "mwifiex_write_data_async failed: 0x%X\n",
+ ret);
adapter->dbg.num_tx_host_to_card_failure++;
mwifiex_write_data_complete(adapter, skb, 0, ret);
break;
@@ -162,7 +178,8 @@ static int mwifiex_host_to_card(struct mwifiex_adapter *adapter,
priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num,
tx_info->bss_type);
if (!priv) {
- dev_err(adapter->dev, "data: priv not found. Drop TX packet\n");
+ mwifiex_dbg(adapter, ERROR,
+ "data: priv not found. Drop TX packet\n");
adapter->dbg.num_tx_host_to_card_failure++;
mwifiex_write_data_complete(adapter, skb, 0, 0);
return ret;
@@ -187,7 +204,7 @@ static int mwifiex_host_to_card(struct mwifiex_adapter *adapter,
}
switch (ret) {
case -ENOSR:
- dev_err(adapter->dev, "data: -ENOSR is returned\n");
+ mwifiex_dbg(adapter, ERROR, "data: -ENOSR is returned\n");
break;
case -EBUSY:
if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
@@ -202,13 +219,13 @@ static int mwifiex_host_to_card(struct mwifiex_adapter *adapter,
atomic_add(tx_info->aggr_num, &adapter->tx_queued);
else
atomic_inc(&adapter->tx_queued);
- dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+ mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
break;
case -1:
if (adapter->iface_type != MWIFIEX_PCIE)
adapter->data_sent = false;
- dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",
- ret);
+ mwifiex_dbg(adapter, ERROR,
+ "mwifiex_write_data_async failed: 0x%X\n", ret);
adapter->dbg.num_tx_host_to_card_failure++;
mwifiex_write_data_complete(adapter, skb, 0, ret);
break;
@@ -302,11 +319,11 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
priv->stats.tx_errors++;
}
- if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) {
+ if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)
atomic_dec_return(&adapter->pending_bridged_pkts);
- if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
- goto done;
- }
+
+ if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
+ goto done;
if (aggr)
/* For skb_aggr, do not wake up tx queue */
@@ -319,7 +336,7 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
txq = netdev_get_tx_queue(priv->netdev, index);
if (netif_tx_queue_stopped(txq)) {
netif_tx_wake_queue(txq);
- dev_dbg(adapter->dev, "wake queue: %d\n", index);
+ mwifiex_dbg(adapter, DATA, "wake queue: %d\n", index);
}
}
done:
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
index f5c2af01ba0a..b74930054b8c 100644
--- a/drivers/net/wireless/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -167,7 +167,7 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, params->beacon.tail,
params->beacon.tail_len);
if (ht_ie) {
- memcpy(&bss_cfg->ht_cap, ht_ie,
+ memcpy(&bss_cfg->ht_cap, ht_ie + 2,
sizeof(struct ieee80211_ht_cap));
cap_info = le16_to_cpu(bss_cfg->ht_cap.cap_info);
memset(&bss_cfg->ht_cap.mcs, 0,
@@ -184,8 +184,8 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
bss_cfg->ht_cap.mcs.rx_mask[1] = 0xff;
break;
default:
- dev_warn(priv->adapter->dev,
- "Unsupported RX-STBC, default to 2x2\n");
+ mwifiex_dbg(priv->adapter, WARN,
+ "Unsupported RX-STBC, default to 2x2\n");
bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff;
bss_cfg->ht_cap.mcs.rx_mask[1] = 0xff;
break;
@@ -222,6 +222,23 @@ void mwifiex_set_vht_params(struct mwifiex_private *priv,
return;
}
+/* This function updates 11ac related parameters from IE
+ * and sets them into bss_config structure.
+ */
+void mwifiex_set_tpc_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params)
+{
+ const u8 *tpc_ie;
+
+ tpc_ie = cfg80211_find_ie(WLAN_EID_TPC_REQUEST, params->beacon.tail,
+ params->beacon.tail_len);
+ if (tpc_ie)
+ bss_cfg->power_constraint = *(tpc_ie + 2);
+ else
+ bss_cfg->power_constraint = 0;
+}
+
/* Enable VHT only when cfg80211_ap_settings has VHT IE.
* Otherwise disable VHT.
*/
@@ -466,6 +483,7 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
struct host_cmd_tlv_auth_type *auth_type;
struct host_cmd_tlv_rates *tlv_rates;
struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer;
+ struct host_cmd_tlv_power_constraint *pwr_ct;
struct mwifiex_ie_types_htcap *htcap;
struct mwifiex_ie_types_wmmcap *wmm_cap;
struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
@@ -644,6 +662,15 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
tlv += sizeof(*ao_timer);
}
+ if (bss_cfg->power_constraint) {
+ pwr_ct = (void *)tlv;
+ pwr_ct->header.type = cpu_to_le16(TLV_TYPE_PWR_CONSTRAINT);
+ pwr_ct->header.len = cpu_to_le16(sizeof(u8));
+ pwr_ct->constraint = bss_cfg->power_constraint;
+ cmd_size += sizeof(*pwr_ct);
+ tlv += sizeof(*pwr_ct);
+ }
+
if (bss_cfg->ps_sta_ao_timer) {
ps_ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
ps_ao_timer->header.type =
@@ -754,6 +781,8 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
break;
case HostCmd_CMD_UAP_BSS_START:
case HostCmd_CMD_UAP_BSS_STOP:
+ case HOST_CMD_APCMD_SYS_RESET:
+ case HOST_CMD_APCMD_STA_LIST:
cmd->command = cpu_to_le16(cmd_no);
cmd->size = cpu_to_le16(S_DS_GEN);
break;
@@ -767,19 +796,22 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
return -1;
break;
default:
- dev_err(priv->adapter->dev,
- "PREP_CMD: unknown cmd %#x\n", cmd_no);
+ mwifiex_dbg(priv->adapter, ERROR,
+ "PREP_CMD: unknown cmd %#x\n", cmd_no);
return -1;
}
return 0;
}
-void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg,
+void mwifiex_uap_set_channel(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_chan_def chandef)
{
u8 config_bands = 0;
+ priv->bss_chandef = chandef;
+
bss_cfg->channel = ieee80211_frequency_to_channel(
chandef.chan->center_freq);
@@ -800,30 +832,53 @@ void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg,
if (chandef.width > NL80211_CHAN_WIDTH_40)
config_bands |= BAND_AAC;
}
+
+ priv->adapter->config_bands = config_bands;
}
int mwifiex_config_start_uap(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg)
{
+ enum state_11d_t state_11d;
+
if (mwifiex_del_mgmt_ies(priv))
- dev_err(priv->adapter->dev, "Failed to delete mgmt IEs!\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "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");
+ mwifiex_dbg(priv->adapter, ERROR, "Failed to stop the BSS\n");
+ return -1;
+ }
+
+ if (mwifiex_send_cmd(priv, HOST_CMD_APCMD_SYS_RESET,
+ HostCmd_ACT_GEN_SET, 0, NULL, true)) {
+ mwifiex_dbg(priv->adapter, ERROR, "Failed to reset 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");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to set the SSID\n");
+ return -1;
+ }
+
+ /* Send cmd to FW to enable 11D function */
+ state_11d = ENABLE_11D;
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, DOT11D_I,
+ &state_11d, true)) {
+ mwifiex_dbg(priv->adapter, ERROR,
+ "11D: failed to enable 11D\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");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Failed to start the BSS\n");
return -1;
}
diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c
index f4794cdc36d2..7bc1f850e3b7 100644
--- a/drivers/net/wireless/mwifiex/uap_event.c
+++ b/drivers/net/wireless/mwifiex/uap_event.c
@@ -21,8 +21,70 @@
#include "main.h"
#include "11n.h"
+#define MWIFIEX_BSS_START_EVT_FIX_SIZE 12
+static int mwifiex_check_uap_capabilties(struct mwifiex_private *priv,
+ struct sk_buff *event)
+{
+ int evt_len;
+ u8 *curr;
+ u16 tlv_len;
+ struct mwifiex_ie_types_data *tlv_hdr;
+ struct ieee_types_wmm_parameter *wmm_param_ie = NULL;
+ int mask = IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK;
+
+ priv->wmm_enabled = false;
+ skb_pull(event, MWIFIEX_BSS_START_EVT_FIX_SIZE);
+ evt_len = event->len;
+ curr = event->data;
+
+ mwifiex_dbg_dump(priv->adapter, EVT_D, "uap capabilties:",
+ event->data, event->len);
+ while ((evt_len >= sizeof(tlv_hdr->header))) {
+ tlv_hdr = (struct mwifiex_ie_types_data *)curr;
+ tlv_len = le16_to_cpu(tlv_hdr->header.len);
+
+ if (evt_len < tlv_len + sizeof(tlv_hdr->header))
+ break;
+
+ switch (le16_to_cpu(tlv_hdr->header.type)) {
+ case WLAN_EID_HT_CAPABILITY:
+ priv->ap_11n_enabled = true;
+ break;
+
+ case WLAN_EID_VHT_CAPABILITY:
+ priv->ap_11ac_enabled = true;
+ break;
+
+ case WLAN_EID_VENDOR_SPECIFIC:
+ /* Point the regular IEEE IE 2 bytes into the Marvell IE
+ * and setup the IEEE IE type and length byte fields
+ */
+ wmm_param_ie = (void *)(curr + 2);
+ wmm_param_ie->vend_hdr.len = (u8)tlv_len;
+ wmm_param_ie->vend_hdr.element_id =
+ WLAN_EID_VENDOR_SPECIFIC;
+ mwifiex_dbg(priv->adapter, EVENT,
+ "info: check uap capabilities:\t"
+ "wmm parameter set count: %d\n",
+ wmm_param_ie->qos_info_bitmap & mask);
+
+ mwifiex_wmm_setup_ac_downgrade(priv);
+ priv->wmm_enabled = true;
+ mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie);
+ break;
+
+ default:
+ break;
+ }
+
+ curr += (tlv_len + sizeof(tlv_hdr->header));
+ evt_len -= (tlv_len + sizeof(tlv_hdr->header));
+ }
+
+ return 0;
+}
/*
* This function handles AP interface specific events generated by firmware.
@@ -80,8 +142,8 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
node = mwifiex_add_sta_entry(priv, event->sta_addr);
if (!node) {
- dev_warn(adapter->dev,
- "could not create station entry!\n");
+ mwifiex_dbg(adapter, ERROR,
+ "could not create station entry!\n");
return -1;
}
@@ -128,58 +190,63 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
break;
case EVENT_UAP_BSS_START:
- dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
+ mwifiex_dbg(adapter, EVENT,
+ "AP EVENT: event id: %#x\n", eventcause);
memcpy(priv->netdev->dev_addr, adapter->event_body + 2,
ETH_ALEN);
if (priv->hist_data)
mwifiex_hist_data_reset(priv);
+ mwifiex_check_uap_capabilties(priv, adapter->event_skb);
break;
case EVENT_UAP_MIC_COUNTERMEASURES:
/* For future development */
- dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
+ mwifiex_dbg(adapter, EVENT,
+ "AP EVENT: event id: %#x\n", eventcause);
break;
case EVENT_AMSDU_AGGR_CTRL:
ctrl = le16_to_cpu(*(__le16 *)adapter->event_body);
- dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl);
+ mwifiex_dbg(adapter, EVENT,
+ "event: AMSDU_AGGR_CTRL %d\n", ctrl);
if (priv->media_connected) {
adapter->tx_buf_size =
min_t(u16, adapter->curr_tx_buf_size, ctrl);
- dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
- adapter->tx_buf_size);
+ mwifiex_dbg(adapter, EVENT,
+ "event: tx_buf_size %d\n",
+ adapter->tx_buf_size);
}
break;
case EVENT_ADDBA:
- dev_dbg(adapter->dev, "event: ADDBA Request\n");
+ mwifiex_dbg(adapter, EVENT, "event: ADDBA Request\n");
if (priv->media_connected)
mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP,
HostCmd_ACT_GEN_SET, 0,
adapter->event_body, false);
break;
case EVENT_DELBA:
- dev_dbg(adapter->dev, "event: DELBA Request\n");
+ mwifiex_dbg(adapter, EVENT, "event: DELBA Request\n");
if (priv->media_connected)
mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
break;
case EVENT_BA_STREAM_TIEMOUT:
- dev_dbg(adapter->dev, "event: BA Stream timeout\n");
+ mwifiex_dbg(adapter, EVENT, "event: BA Stream timeout\n");
if (priv->media_connected) {
ba_timeout = (void *)adapter->event_body;
mwifiex_11n_ba_stream_timeout(priv, ba_timeout);
}
break;
case EVENT_EXT_SCAN_REPORT:
- dev_dbg(adapter->dev, "event: EXT_SCAN Report\n");
+ mwifiex_dbg(adapter, EVENT, "event: EXT_SCAN Report\n");
if (adapter->ext_scan)
return mwifiex_handle_event_ext_scan_report(priv,
adapter->event_skb->data);
break;
case EVENT_TX_STATUS_REPORT:
- dev_dbg(adapter->dev, "event: TX_STATUS Report\n");
+ mwifiex_dbg(adapter, EVENT, "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");
+ mwifiex_dbg(adapter, EVENT, "info: EVENT: SLEEP\n");
adapter->ps_state = PS_STATE_PRE_SLEEP;
@@ -187,12 +254,12 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
break;
case EVENT_PS_AWAKE:
- dev_dbg(adapter->dev, "info: EVENT: AWAKE\n");
+ mwifiex_dbg(adapter, EVENT, "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");
+ mwifiex_dbg(adapter, EVENT,
+ "event: PPS/UAPSD mode activated\n");
}
adapter->tx_lock_flag = false;
if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
@@ -218,16 +285,21 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
break;
case EVENT_CHANNEL_REPORT_RDY:
- dev_dbg(adapter->dev, "event: Channel Report\n");
+ mwifiex_dbg(adapter, EVENT, "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_dbg(adapter, EVENT, "event: Radar detected\n");
mwifiex_11h_handle_radar_detected(priv, adapter->event_skb);
break;
+ case EVENT_BT_COEX_WLAN_PARA_CHANGE:
+ dev_err(adapter->dev, "EVENT: BT coex wlan param update\n");
+ mwifiex_bt_coex_wlan_param_update_event(priv,
+ adapter->event_skb);
+ break;
default:
- dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
- eventcause);
+ mwifiex_dbg(adapter, EVENT,
+ "event: unknown event id: %#x\n", eventcause);
break;
}
diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c
index 38ac4d74c486..87667418af5f 100644
--- a/drivers/net/wireless/mwifiex/uap_txrx.c
+++ b/drivers/net/wireless/mwifiex/uap_txrx.c
@@ -97,14 +97,15 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
struct mwifiex_txinfo *tx_info;
int hdr_chop;
struct ethhdr *p_ethhdr;
+ struct mwifiex_sta_node *src_node;
uap_rx_pd = (struct uap_rxpd *)(skb->data);
rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
if ((atomic_read(&adapter->pending_bridged_pkts) >=
MWIFIEX_BRIDGED_PKTS_THR_HIGH)) {
- dev_err(priv->adapter->dev,
- "Tx: Bridge packet limit reached. Drop packet!\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Tx: Bridge packet limit reached. Drop packet!\n");
kfree_skb(skb);
mwifiex_uap_cleanup_tx_queues(priv);
return;
@@ -153,15 +154,15 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
skb_pull(skb, hdr_chop);
if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
- dev_dbg(priv->adapter->dev,
- "data: Tx: insufficient skb headroom %d\n",
- skb_headroom(skb));
+ mwifiex_dbg(priv->adapter, ERROR,
+ "data: Tx: insufficient skb headroom %d\n",
+ skb_headroom(skb));
/* Insufficient skb headroom - allocate a new skb */
new_skb =
skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
if (unlikely(!new_skb)) {
- dev_err(priv->adapter->dev,
- "Tx: cannot allocate new_skb\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "Tx: cannot allocate new_skb\n");
kfree_skb(skb);
priv->stats.tx_dropped++;
return;
@@ -169,8 +170,9 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
kfree_skb(skb);
skb = new_skb;
- dev_dbg(priv->adapter->dev, "info: new skb headroom %d\n",
- skb_headroom(skb));
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: new skb headroom %d\n",
+ skb_headroom(skb));
}
tx_info = MWIFIEX_SKB_TXCB(skb);
@@ -179,6 +181,15 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
tx_info->bss_type = priv->bss_type;
tx_info->flags |= MWIFIEX_BUF_FLAG_BRIDGED_PKT;
+ src_node = mwifiex_get_sta_entry(priv, rx_pkt_hdr->eth803_hdr.h_source);
+ if (src_node) {
+ src_node->stats.last_rx = jiffies;
+ src_node->stats.rx_bytes += skb->len;
+ src_node->stats.rx_packets++;
+ src_node->stats.last_tx_rate = uap_rx_pd->rx_rate;
+ src_node->stats.last_tx_htinfo = uap_rx_pd->ht_info;
+ }
+
if (is_unicast_ether_addr(rx_pkt_hdr->eth803_hdr.h_dest)) {
/* Update bridge packet statistics as the
* packet is not going to kernel/upper layer.
@@ -225,7 +236,8 @@ int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
/* don't do packet forwarding in disconnected state */
if (!priv->media_connected) {
- dev_err(adapter->dev, "drop packet in disconnected state.\n");
+ mwifiex_dbg(adapter, ERROR,
+ "drop packet in disconnected state.\n");
dev_kfree_skb_any(skb);
return 0;
}
@@ -273,13 +285,20 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type);
rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
+ ether_addr_copy(ta, rx_pkt_hdr->eth803_hdr.h_source);
+
if ((le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
le16_to_cpu(uap_rx_pd->rx_pkt_length)) > (u16) skb->len) {
- dev_err(adapter->dev,
- "wrong rx packet: len=%d, offset=%d, length=%d\n",
- skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset),
- le16_to_cpu(uap_rx_pd->rx_pkt_length));
+ mwifiex_dbg(adapter, ERROR,
+ "wrong rx packet: len=%d, offset=%d, length=%d\n",
+ skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset),
+ le16_to_cpu(uap_rx_pd->rx_pkt_length));
priv->stats.rx_dropped++;
+
+ node = mwifiex_get_sta_entry(priv, ta);
+ if (node)
+ node->stats.tx_failed++;
+
dev_kfree_skb_any(skb);
return 0;
}
@@ -287,12 +306,12 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
if (rx_pkt_type == PKT_TYPE_MGMT) {
ret = mwifiex_process_mgmt_packet(priv, skb);
if (ret)
- dev_err(adapter->dev, "Rx of mgmt packet failed");
+ mwifiex_dbg(adapter, ERROR,
+ "Rx of mgmt packet failed");
dev_kfree_skb_any(skb);
return ret;
}
- memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
if (rx_pkt_type != PKT_TYPE_BAR && uap_rx_pd->priority < MAX_NUM_TID) {
spin_lock_irqsave(&priv->sta_list_spinlock, flags);
@@ -354,7 +373,8 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
INTF_HEADER_LEN;
if (!skb->len) {
- dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len);
+ mwifiex_dbg(adapter, ERROR,
+ "Tx: bad packet length: %d\n", skb->len);
tx_info->status_code = -1;
return skb->data;
}
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c
index fd8027f200a0..aada93425f80 100644
--- a/drivers/net/wireless/mwifiex/usb.c
+++ b/drivers/net/wireless/mwifiex/usb.c
@@ -60,7 +60,6 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size);
static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
struct sk_buff *skb, u8 ep)
{
- struct device *dev = adapter->dev;
u32 recv_type;
__le32 tmp;
int ret;
@@ -69,13 +68,15 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
mwifiex_process_hs_config(adapter);
if (skb->len < INTF_HEADER_LEN) {
- dev_err(dev, "%s: invalid skb->len\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: invalid skb->len\n", __func__);
return -1;
}
switch (ep) {
case MWIFIEX_USB_EP_CMD_EVENT:
- dev_dbg(dev, "%s: EP_CMD_EVENT\n", __func__);
+ mwifiex_dbg(adapter, EVENT,
+ "%s: EP_CMD_EVENT\n", __func__);
skb_copy_from_linear_data(skb, &tmp, INTF_HEADER_LEN);
recv_type = le32_to_cpu(tmp);
skb_pull(skb, INTF_HEADER_LEN);
@@ -83,11 +84,12 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
switch (recv_type) {
case MWIFIEX_USB_TYPE_CMD:
if (skb->len > MWIFIEX_SIZE_OF_CMD_BUFFER) {
- dev_err(dev, "CMD: skb->len too large\n");
+ mwifiex_dbg(adapter, ERROR,
+ "CMD: skb->len too large\n");
ret = -1;
goto exit_restore_skb;
} else if (!adapter->curr_cmd) {
- dev_dbg(dev, "CMD: no curr_cmd\n");
+ mwifiex_dbg(adapter, WARN, "CMD: no curr_cmd\n");
if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
mwifiex_process_sleep_confirm_resp(
adapter, skb->data,
@@ -104,16 +106,19 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
break;
case MWIFIEX_USB_TYPE_EVENT:
if (skb->len < sizeof(u32)) {
- dev_err(dev, "EVENT: skb->len too small\n");
+ mwifiex_dbg(adapter, ERROR,
+ "EVENT: skb->len too small\n");
ret = -1;
goto exit_restore_skb;
}
skb_copy_from_linear_data(skb, &tmp, sizeof(u32));
adapter->event_cause = le32_to_cpu(tmp);
- dev_dbg(dev, "event_cause %#x\n", adapter->event_cause);
+ mwifiex_dbg(adapter, EVENT,
+ "event_cause %#x\n", adapter->event_cause);
if (skb->len > MAX_EVENT_SIZE) {
- dev_err(dev, "EVENT: event body too large\n");
+ mwifiex_dbg(adapter, ERROR,
+ "EVENT: event body too large\n");
ret = -1;
goto exit_restore_skb;
}
@@ -125,14 +130,16 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
adapter->event_skb = skb;
break;
default:
- dev_err(dev, "unknown recv_type %#x\n", recv_type);
+ mwifiex_dbg(adapter, ERROR,
+ "unknown recv_type %#x\n", recv_type);
return -1;
}
break;
case MWIFIEX_USB_EP_DATA:
- dev_dbg(dev, "%s: EP_DATA\n", __func__);
+ mwifiex_dbg(adapter, DATA, "%s: EP_DATA\n", __func__);
if (skb->len > MWIFIEX_RX_DATA_BUF_SIZE) {
- dev_err(dev, "DATA: skb->len too large\n");
+ mwifiex_dbg(adapter, ERROR,
+ "DATA: skb->len too large\n");
return -1;
}
@@ -141,7 +148,8 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
atomic_inc(&adapter->rx_pending);
break;
default:
- dev_err(dev, "%s: unknown endport %#x\n", __func__, ep);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: unknown endport %#x\n", __func__, ep);
return -1;
}
@@ -176,8 +184,8 @@ static void mwifiex_usb_rx_complete(struct urb *urb)
if (recv_length) {
if (urb->status || (adapter->surprise_removed)) {
- dev_err(adapter->dev,
- "URB status is failed: %d\n", urb->status);
+ mwifiex_dbg(adapter, ERROR,
+ "URB status is failed: %d\n", urb->status);
/* Do not free skb in case of command ep */
if (card->rx_cmd_ep != context->ep)
dev_kfree_skb_any(skb);
@@ -190,8 +198,9 @@ static void mwifiex_usb_rx_complete(struct urb *urb)
status = mwifiex_usb_recv(adapter, skb, context->ep);
- dev_dbg(adapter->dev, "info: recv_length=%d, status=%d\n",
- recv_length, status);
+ mwifiex_dbg(adapter, INFO,
+ "info: recv_length=%d, status=%d\n",
+ recv_length, status);
if (status == -EINPROGRESS) {
mwifiex_queue_main_work(adapter);
@@ -203,8 +212,8 @@ static void mwifiex_usb_rx_complete(struct urb *urb)
return;
} else {
if (status == -1)
- dev_err(adapter->dev,
- "received data processing failed!\n");
+ mwifiex_dbg(adapter, ERROR,
+ "received data processing failed!\n");
/* Do not free skb in case of command ep */
if (card->rx_cmd_ep != context->ep)
@@ -212,8 +221,8 @@ static void mwifiex_usb_rx_complete(struct urb *urb)
}
} else if (urb->status) {
if (!adapter->is_suspended) {
- dev_warn(adapter->dev,
- "Card is removed: %d\n", urb->status);
+ mwifiex_dbg(adapter, FATAL,
+ "Card is removed: %d\n", urb->status);
adapter->surprise_removed = true;
}
dev_kfree_skb_any(skb);
@@ -249,14 +258,17 @@ static void mwifiex_usb_tx_complete(struct urb *urb)
struct mwifiex_adapter *adapter = context->adapter;
struct usb_card_rec *card = adapter->card;
- dev_dbg(adapter->dev, "%s: status: %d\n", __func__, urb->status);
+ mwifiex_dbg(adapter, INFO,
+ "%s: status: %d\n", __func__, urb->status);
if (context->ep == card->tx_cmd_ep) {
- dev_dbg(adapter->dev, "%s: CMD\n", __func__);
+ mwifiex_dbg(adapter, CMD,
+ "%s: CMD\n", __func__);
atomic_dec(&card->tx_cmd_urb_pending);
adapter->cmd_sent = false;
} else {
- dev_dbg(adapter->dev, "%s: DATA\n", __func__);
+ mwifiex_dbg(adapter, DATA,
+ "%s: DATA\n", __func__);
atomic_dec(&card->tx_data_urb_pending);
mwifiex_write_data_complete(adapter, context->skb, 0,
urb->status ? -1 : 0);
@@ -275,8 +287,8 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size)
if (card->rx_cmd_ep != ctx->ep) {
ctx->skb = dev_alloc_skb(size);
if (!ctx->skb) {
- dev_err(adapter->dev,
- "%s: dev_alloc_skb failed\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: dev_alloc_skb failed\n", __func__);
return -ENOMEM;
}
}
@@ -291,7 +303,7 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size)
atomic_inc(&card->rx_data_urb_pending);
if (usb_submit_urb(ctx->urb, GFP_ATOMIC)) {
- dev_err(adapter->dev, "usb_submit_urb failed\n");
+ mwifiex_dbg(adapter, ERROR, "usb_submit_urb failed\n");
dev_kfree_skb_any(ctx->skb);
ctx->skb = NULL;
@@ -468,7 +480,8 @@ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message)
adapter = card->adapter;
if (unlikely(adapter->is_suspended))
- dev_warn(adapter->dev, "Device already suspended\n");
+ mwifiex_dbg(adapter, WARN,
+ "Device already suspended\n");
mwifiex_enable_hs(adapter);
@@ -519,7 +532,8 @@ static int mwifiex_usb_resume(struct usb_interface *intf)
adapter = card->adapter;
if (unlikely(!adapter->is_suspended)) {
- dev_warn(adapter->dev, "Device already resumed\n");
+ mwifiex_dbg(adapter, WARN,
+ "Device already resumed\n");
return 0;
}
@@ -578,7 +592,8 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
mwifiex_usb_free(card);
- dev_dbg(adapter->dev, "%s: removing card\n", __func__);
+ mwifiex_dbg(adapter, FATAL,
+ "%s: removing card\n", __func__);
mwifiex_remove_card(adapter, &add_remove_card_sem);
usb_set_intfdata(intf, NULL);
@@ -608,7 +623,8 @@ static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
card->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
if (!card->tx_cmd.urb) {
- dev_err(adapter->dev, "tx_cmd.urb allocation failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "tx_cmd.urb allocation failed\n");
return -ENOMEM;
}
@@ -620,8 +636,8 @@ static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
card->tx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
if (!card->tx_data_list[i].urb) {
- dev_err(adapter->dev,
- "tx_data_list[] urb allocation failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "tx_data_list[] urb allocation failed\n");
return -ENOMEM;
}
}
@@ -639,15 +655,13 @@ static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter)
card->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
if (!card->rx_cmd.urb) {
- dev_err(adapter->dev, "rx_cmd.urb allocation failed\n");
+ mwifiex_dbg(adapter, ERROR, "rx_cmd.urb allocation failed\n");
return -ENOMEM;
}
card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE);
- if (!card->rx_cmd.skb) {
- dev_err(adapter->dev, "rx_cmd.skb allocation failed\n");
+ if (!card->rx_cmd.skb)
return -ENOMEM;
- }
if (mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE))
return -1;
@@ -658,8 +672,8 @@ static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter)
card->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
if (!card->rx_data_list[i].urb) {
- dev_err(adapter->dev,
- "rx_data_list[] urb allocation failed\n");
+ mwifiex_dbg(adapter, ERROR,
+ "rx_data_list[] urb allocation failed\n");
return -1;
}
if (mwifiex_usb_submit_rx_urb(&card->rx_data_list[i],
@@ -683,7 +697,8 @@ static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf,
ret = usb_bulk_msg(card->udev, usb_sndbulkpipe(card->udev, ep), pbuf,
*len, &actual_length, timeout);
if (ret) {
- dev_err(adapter->dev, "usb_bulk_msg for tx failed: %d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "usb_bulk_msg for tx failed: %d\n", ret);
return ret;
}
@@ -702,7 +717,8 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf,
ret = usb_bulk_msg(card->udev, usb_rcvbulkpipe(card->udev, ep), pbuf,
*len, &actual_length, timeout);
if (ret) {
- dev_err(adapter->dev, "usb_bulk_msg for rx failed: %d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "usb_bulk_msg for rx failed: %d\n", ret);
return ret;
}
@@ -722,13 +738,13 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
struct urb *tx_urb;
if (adapter->is_suspended) {
- dev_err(adapter->dev,
- "%s: not allowed while suspended\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: not allowed while suspended\n", __func__);
return -1;
}
if (adapter->surprise_removed) {
- dev_err(adapter->dev, "%s: device removed\n", __func__);
+ mwifiex_dbg(adapter, ERROR, "%s: device removed\n", __func__);
return -1;
}
@@ -737,7 +753,7 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
return -EBUSY;
}
- dev_dbg(adapter->dev, "%s: ep=%d\n", __func__, ep);
+ mwifiex_dbg(adapter, INFO, "%s: ep=%d\n", __func__, ep);
if (ep == card->tx_cmd_ep) {
context = &card->tx_cmd;
@@ -764,7 +780,8 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
atomic_inc(&card->tx_data_urb_pending);
if (usb_submit_urb(tx_urb, GFP_ATOMIC)) {
- dev_err(adapter->dev, "%s: usb_submit_urb failed\n", __func__);
+ mwifiex_dbg(adapter, ERROR,
+ "%s: usb_submit_urb failed\n", __func__);
if (ep == card->tx_cmd_ep) {
atomic_dec(&card->tx_cmd_urb_pending);
} else {
@@ -843,8 +860,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
u8 check_winner = 1;
if (!firmware) {
- dev_err(adapter->dev,
- "No firmware image found! Terminating download\n");
+ mwifiex_dbg(adapter, ERROR,
+ "No firmware image found! Terminating download\n");
ret = -1;
goto fw_exit;
}
@@ -889,8 +906,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
MWIFIEX_USB_EP_CMD_EVENT,
MWIFIEX_USB_TIMEOUT);
if (ret) {
- dev_err(adapter->dev,
- "write_data_sync: failed: %d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "write_data_sync: failed: %d\n",
+ ret);
continue;
}
@@ -902,8 +920,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
MWIFIEX_USB_EP_CMD_EVENT,
MWIFIEX_USB_TIMEOUT);
if (ret) {
- dev_err(adapter->dev,
- "read_data_sync: failed: %d\n", ret);
+ mwifiex_dbg(adapter, ERROR,
+ "read_data_sync: failed: %d\n",
+ ret);
continue;
}
@@ -913,17 +932,17 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
/* check 1st firmware block resp for highest bit set */
if (check_winner) {
if (le32_to_cpu(sync_fw.cmd) & 0x80000000) {
- dev_warn(adapter->dev,
- "USB is not the winner %#x\n",
- sync_fw.cmd);
+ mwifiex_dbg(adapter, WARN,
+ "USB is not the winner %#x\n",
+ sync_fw.cmd);
/* returning success */
ret = 0;
goto cleanup;
}
- dev_dbg(adapter->dev,
- "USB is the winner, start to download FW\n");
+ mwifiex_dbg(adapter, MSG,
+ "start to download FW...\n");
check_winner = 0;
break;
@@ -931,9 +950,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
/* check the firmware block response for CRC errors */
if (sync_fw.cmd) {
- dev_err(adapter->dev,
- "FW received block with CRC %#x\n",
- sync_fw.cmd);
+ mwifiex_dbg(adapter, ERROR,
+ "FW received block with CRC %#x\n",
+ sync_fw.cmd);
ret = -1;
continue;
}
@@ -945,8 +964,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
} while ((dnld_cmd != FW_HAS_LAST_BLOCK) && retries);
cleanup:
- dev_notice(adapter->dev,
- "info: FW download over, size %d bytes\n", tlen);
+ mwifiex_dbg(adapter, MSG,
+ "info: FW download over, size %d bytes\n", tlen);
kfree(recv_buff);
kfree(fwdata);
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index b8a45872354d..790e61953abf 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -26,6 +26,8 @@
#include "11n.h"
static struct mwifiex_debug_data items[] = {
+ {"debug_mask", item_size(debug_mask),
+ item_addr(debug_mask), 1},
{"int_counter", item_size(int_counter),
item_addr(int_counter), 1},
{"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
@@ -158,7 +160,8 @@ int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
} else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) {
cmd = HostCmd_CMD_FUNC_SHUTDOWN;
} else {
- dev_err(priv->adapter->dev, "unsupported parameter\n");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "unsupported parameter\n");
return -1;
}
@@ -178,6 +181,7 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,
struct mwifiex_adapter *adapter = priv->adapter;
if (info) {
+ info->debug_mask = adapter->debug_mask;
memcpy(info->packets_out,
priv->wmm.packets_out,
sizeof(priv->wmm.packets_out));
@@ -325,7 +329,7 @@ mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len,
struct rxpd *rx_pd)
{
u16 stype;
- u8 category, action_code;
+ u8 category, action_code, *addr2;
struct ieee80211_hdr *ieee_hdr = (void *)payload;
stype = (le16_to_cpu(ieee_hdr->frame_control) & IEEE80211_FCTL_STYPE);
@@ -333,21 +337,35 @@ mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len,
switch (stype) {
case IEEE80211_STYPE_ACTION:
category = *(payload + sizeof(struct ieee80211_hdr));
- action_code = *(payload + sizeof(struct ieee80211_hdr) + 1);
- if (category == WLAN_CATEGORY_PUBLIC &&
- action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
- dev_dbg(priv->adapter->dev,
- "TDLS discovery response %pM nf=%d, snr=%d\n",
- ieee_hdr->addr2, rx_pd->nf, rx_pd->snr);
- mwifiex_auto_tdls_update_peer_signal(priv,
- ieee_hdr->addr2,
- rx_pd->snr,
- rx_pd->nf);
+ switch (category) {
+ case WLAN_CATEGORY_PUBLIC:
+ action_code = *(payload + sizeof(struct ieee80211_hdr)
+ + 1);
+ if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
+ addr2 = ieee_hdr->addr2;
+ mwifiex_dbg(priv->adapter, INFO,
+ "TDLS discovery response %pM nf=%d, snr=%d\n",
+ addr2, rx_pd->nf, rx_pd->snr);
+ mwifiex_auto_tdls_update_peer_signal(priv,
+ addr2,
+ rx_pd->snr,
+ rx_pd->nf);
+ }
+ break;
+ case WLAN_CATEGORY_BACK:
+ /*we dont indicate BACK action frames to cfg80211*/
+ mwifiex_dbg(priv->adapter, INFO,
+ "drop BACK action frames");
+ return -1;
+ default:
+ mwifiex_dbg(priv->adapter, INFO,
+ "unknown public action frame category %d\n",
+ category);
}
- break;
default:
- dev_dbg(priv->adapter->dev,
- "unknown mgmt frame subytpe %#x\n", stype);
+ mwifiex_dbg(priv->adapter, INFO,
+ "unknown mgmt frame subtype %#x\n", stype);
+ return 0;
}
return 0;
@@ -369,8 +387,8 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
if (!priv->mgmt_frame_mask ||
priv->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) {
- dev_dbg(priv->adapter->dev,
- "do not receive mgmt frames on uninitialized intf");
+ mwifiex_dbg(priv->adapter, ERROR,
+ "do not receive mgmt frames on uninitialized intf");
return -1;
}
@@ -383,8 +401,9 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
ieee_hdr = (void *)skb->data;
if (ieee80211_is_mgmt(ieee_hdr->frame_control)) {
- mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr,
- pkt_len, rx_pd);
+ if (mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr,
+ pkt_len, rx_pd))
+ return -1;
}
/* Remove address4 */
memmove(skb->data + sizeof(struct ieee80211_hdr_3addr),
@@ -412,12 +431,25 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
*/
int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
{
+ struct mwifiex_sta_node *src_node;
+ struct ethhdr *p_ethhdr;
+
if (!skb)
return -1;
priv->stats.rx_bytes += skb->len;
priv->stats.rx_packets++;
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ p_ethhdr = (void *)skb->data;
+ src_node = mwifiex_get_sta_entry(priv, p_ethhdr->h_source);
+ if (src_node) {
+ src_node->stats.last_rx = jiffies;
+ src_node->stats.rx_bytes += skb->len;
+ src_node->stats.rx_packets++;
+ }
+ }
+
skb->dev = priv->netdev;
skb->protocol = eth_type_trans(skb, priv->netdev);
skb->ip_summed = CHECKSUM_NONE;
@@ -464,13 +496,14 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node)
{
- dev_dbg(adapter->dev, "cmd completed: status=%d\n",
- adapter->cmd_wait_q.status);
+ mwifiex_dbg(adapter, CMD,
+ "cmd completed: status=%d\n",
+ adapter->cmd_wait_q.status);
*(cmd_node->condition) = true;
if (adapter->cmd_wait_q.status == -ETIMEDOUT)
- dev_err(adapter->dev, "cmd timeout\n");
+ mwifiex_dbg(adapter, ERROR, "cmd timeout\n");
else
wake_up_interruptible(&adapter->cmd_wait_q.wait);
@@ -536,13 +569,16 @@ void
mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
int ies_len, struct mwifiex_sta_node *node)
{
+ struct ieee_types_header *ht_cap_ie;
const struct ieee80211_ht_cap *ht_cap;
if (!ies)
return;
- ht_cap = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
- if (ht_cap) {
+ ht_cap_ie = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies,
+ ies_len);
+ if (ht_cap_ie) {
+ ht_cap = (void *)(ht_cap_ie + 1);
node->is_11n_enabled = 1;
node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
IEEE80211_HT_CAP_MAX_AMSDU ?
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index b2e99569a0f8..a8ea21c3340c 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -107,7 +107,7 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, const u8 *ra)
ra_list->total_pkt_count = 0;
- dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list);
+ mwifiex_dbg(adapter, INFO, "info: allocated ra_list %p\n", ra_list);
return ra_list;
}
@@ -150,7 +150,8 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra)
for (i = 0; i < MAX_NUM_TID; ++i) {
ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra);
- dev_dbg(adapter->dev, "info: created ra_list %p\n", ra_list);
+ mwifiex_dbg(adapter, INFO,
+ "info: created ra_list %p\n", ra_list);
if (!ra_list)
break;
@@ -178,8 +179,8 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra)
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
}
- dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n",
- ra_list, ra_list->is_11n_enabled);
+ mwifiex_dbg(adapter, DATA, "data: ralist %p: is_11n_enabled=%d\n",
+ ra_list, ra_list->is_11n_enabled);
if (ra_list->is_11n_enabled) {
ra_list->ba_pkt_count = 0;
@@ -241,11 +242,12 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
return;
}
- dev_dbg(priv->adapter->dev, "info: WMM Parameter IE: version=%d, "
- "qos_info Parameter Set Count=%d, Reserved=%#x\n",
- wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap &
- IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK,
- wmm_ie->reserved);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: WMM Parameter IE: version=%d,\t"
+ "qos_info Parameter Set Count=%d, Reserved=%#x\n",
+ wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap &
+ IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK,
+ wmm_ie->reserved);
for (num_ac = 0; num_ac < ARRAY_SIZE(wmm_ie->ac_params); num_ac++) {
u8 ecw = wmm_ie->ac_params[num_ac].ecw_bitmap;
@@ -257,10 +259,10 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
priv->wmm.queue_priority[ac_idx] = ac_idx;
tmp[ac_idx] = avg_back_off;
- dev_dbg(priv->adapter->dev,
- "info: WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
- (1 << ((ecw & MWIFIEX_ECW_MAX) >> 4)) - 1,
- cw_min, avg_back_off);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
+ (1 << ((ecw & MWIFIEX_ECW_MAX) >> 4)) - 1,
+ cw_min, avg_back_off);
mwifiex_wmm_ac_debug_print(&wmm_ie->ac_params[num_ac]);
}
@@ -333,8 +335,8 @@ mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv)
{
int ac_val;
- dev_dbg(priv->adapter->dev, "info: WMM: AC Priorities:"
- "BK(0), BE(1), VI(2), VO(3)\n");
+ mwifiex_dbg(priv->adapter, INFO, "info: WMM: AC Priorities:\t"
+ "BK(0), BE(1), VI(2), VO(3)\n");
if (!priv->wmm_enabled) {
/* WMM is not enabled, default priorities */
@@ -346,9 +348,10 @@ mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv)
priv->wmm.ac_down_graded_vals[ac_val]
= mwifiex_wmm_eval_downgrade_ac(priv,
(enum mwifiex_wmm_ac_e) ac_val);
- dev_dbg(priv->adapter->dev,
- "info: WMM: AC PRIO %d maps to %d\n",
- ac_val, priv->wmm.ac_down_graded_vals[ac_val]);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: WMM: AC PRIO %d maps to %d\n",
+ ac_val,
+ priv->wmm.ac_down_graded_vals[ac_val]);
}
}
}
@@ -428,6 +431,15 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
priv->tos_to_tid_inv[i];
}
+ priv->aggr_prio_tbl[6].amsdu
+ = priv->aggr_prio_tbl[6].ampdu_ap
+ = priv->aggr_prio_tbl[6].ampdu_user
+ = BA_STREAM_NOT_ALLOWED;
+
+ priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap
+ = priv->aggr_prio_tbl[7].ampdu_user
+ = BA_STREAM_NOT_ALLOWED;
+
mwifiex_set_ba_params(priv);
mwifiex_reset_11n_rx_seq_num(priv);
@@ -512,8 +524,8 @@ static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv)
int i;
for (i = 0; i < MAX_NUM_TID; ++i) {
- dev_dbg(priv->adapter->dev,
- "info: ra_list: freeing buf for tid %d\n", i);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: ra_list: freeing buf for tid %d\n", i);
list_for_each_entry_safe(ra_list, tmp_node,
&priv->wmm.tid_tbl_ptr[i].ra_list,
list) {
@@ -685,14 +697,15 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA &&
ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) {
if (ntohs(eth_hdr->h_proto) == ETH_P_TDLS)
- dev_dbg(adapter->dev,
- "TDLS setup packet for %pM. Don't block\n", ra);
+ mwifiex_dbg(adapter, DATA,
+ "TDLS setup packet for %pM.\t"
+ "Don't block\n", ra);
else if (memcmp(priv->cfg_bssid, ra, ETH_ALEN))
tdls_status = mwifiex_get_tdls_link_status(priv, ra);
}
if (!priv->media_connected && !mwifiex_is_skb_mgmt_frame(skb)) {
- dev_dbg(adapter->dev, "data: drop packet in disconnect\n");
+ mwifiex_dbg(adapter, DATA, "data: drop packet in disconnect\n");
mwifiex_write_data_complete(adapter, skb, 0, -1);
return;
}
@@ -773,6 +786,7 @@ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
{
u8 *curr = (u8 *) &resp->params.get_wmm_status;
uint16_t resp_len = le16_to_cpu(resp->size), tlv_len;
+ int mask = IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK;
bool valid = true;
struct mwifiex_ie_types_data *tlv_hdr;
@@ -780,8 +794,9 @@ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
struct ieee_types_wmm_parameter *wmm_param_ie = NULL;
struct mwifiex_wmm_ac_status *ac_status;
- dev_dbg(priv->adapter->dev, "info: WMM: WMM_GET_STATUS cmdresp received: %d\n",
- resp_len);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: WMM: WMM_GET_STATUS cmdresp received: %d\n",
+ resp_len);
while ((resp_len >= sizeof(tlv_hdr->header)) && valid) {
tlv_hdr = (struct mwifiex_ie_types_data *) curr;
@@ -795,12 +810,12 @@ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
tlv_wmm_qstatus =
(struct mwifiex_ie_types_wmm_queue_status *)
tlv_hdr;
- dev_dbg(priv->adapter->dev,
- "info: CMD_RESP: WMM_GET_STATUS:"
- " QSTATUS TLV: %d, %d, %d\n",
- tlv_wmm_qstatus->queue_index,
- tlv_wmm_qstatus->flow_required,
- tlv_wmm_qstatus->disabled);
+ mwifiex_dbg(priv->adapter, CMD,
+ "info: CMD_RESP: WMM_GET_STATUS:\t"
+ "QSTATUS TLV: %d, %d, %d\n",
+ tlv_wmm_qstatus->queue_index,
+ tlv_wmm_qstatus->flow_required,
+ tlv_wmm_qstatus->disabled);
ac_status = &priv->wmm.ac_status[tlv_wmm_qstatus->
queue_index];
@@ -823,11 +838,10 @@ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
wmm_param_ie->vend_hdr.element_id =
WLAN_EID_VENDOR_SPECIFIC;
- dev_dbg(priv->adapter->dev,
- "info: CMD_RESP: WMM_GET_STATUS:"
- " WMM Parameter Set Count: %d\n",
- wmm_param_ie->qos_info_bitmap &
- IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK);
+ mwifiex_dbg(priv->adapter, CMD,
+ "info: CMD_RESP: WMM_GET_STATUS:\t"
+ "WMM Parameter Set Count: %d\n",
+ wmm_param_ie->qos_info_bitmap & mask);
memcpy((u8 *) &priv->curr_bss_params.bss_descriptor.
wmm_ie, wmm_param_ie,
@@ -875,9 +889,9 @@ mwifiex_wmm_process_association_req(struct mwifiex_private *priv,
if (!wmm_ie)
return 0;
- dev_dbg(priv->adapter->dev,
- "info: WMM: process assoc req: bss->wmm_ie=%#x\n",
- wmm_ie->vend_hdr.element_id);
+ mwifiex_dbg(priv->adapter, INFO,
+ "info: WMM: process assoc req: bss->wmm_ie=%#x\n",
+ wmm_ie->vend_hdr.element_id);
if ((priv->wmm_required ||
(ht_cap && (priv->adapter->config_bands & BAND_GN ||
@@ -927,8 +941,8 @@ mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv,
*/
ret_val = (u8) (min(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1);
- dev_dbg(priv->adapter->dev, "data: WMM: Pkt Delay: %d ms,"
- " %d ms sent to FW\n", queue_delay, ret_val);
+ mwifiex_dbg(priv->adapter, DATA, "data: WMM: Pkt Delay: %d ms,\t"
+ "%d ms sent to FW\n", queue_delay, ret_val);
return ret_val;
}
@@ -1082,14 +1096,15 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
if (skb_queue_empty(&ptr->skb_head)) {
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
- dev_dbg(adapter->dev, "data: nothing to send\n");
+ mwifiex_dbg(adapter, DATA, "data: nothing to send\n");
return;
}
skb = skb_dequeue(&ptr->skb_head);
tx_info = MWIFIEX_SKB_TXCB(skb);
- dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb);
+ mwifiex_dbg(adapter, DATA,
+ "data: dequeuing the packet %p %p\n", ptr, skb);
ptr->total_pkt_count--;
@@ -1205,7 +1220,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
switch (ret) {
case -EBUSY:
- dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+ mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
@@ -1224,7 +1239,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
case -1:
if (adapter->iface_type != MWIFIEX_PCIE)
adapter->data_sent = false;
- dev_err(adapter->dev, "host_to_card failed: %#x\n", ret);
+ mwifiex_dbg(adapter, ERROR, "host_to_card failed: %#x\n", ret);
adapter->dbg.num_tx_host_to_card_failure++;
mwifiex_write_data_complete(adapter, skb, 0, ret);
break;
@@ -1263,7 +1278,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
tid = mwifiex_get_tid(ptr);
- dev_dbg(adapter->dev, "data: tid=%d\n", tid);
+ mwifiex_dbg(adapter, DATA, "data: tid=%d\n", tid);
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 95921167b53f..77361af68b18 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2380,7 +2380,7 @@ mwl8k_set_ht_caps(struct ieee80211_hw *hw,
if (cap & MWL8K_CAP_GREENFIELD)
band->ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD;
if (cap & MWL8K_CAP_AMPDU) {
- hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
}
@@ -5192,7 +5192,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw,
priv->sniffer_enabled = true;
}
- *total_flags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI |
+ *total_flags &= FIF_ALLMULTI |
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL |
FIF_OTHER_BSS;
@@ -5431,7 +5431,7 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u8 *addr = sta->addr, idx;
struct mwl8k_sta *sta_info = MWL8K_STA(sta);
- if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
+ if (!ieee80211_hw_check(hw, AMPDU_AGGREGATION))
return -ENOTSUPP;
spin_lock(&priv->stream_lock);
@@ -6076,14 +6076,15 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
hw->queues = MWL8K_TX_WMM_QUEUES;
/* Set rssi values to dBm */
- hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL;
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, HAS_RATE_CONTROL);
/*
* Ask mac80211 to not to trigger PS mode
* based on PM bit of incoming frames.
*/
if (priv->ap_fw)
- hw->flags |= IEEE80211_HW_AP_LINK_PS;
+ ieee80211_hw_set(hw, AP_LINK_PS);
hw->vif_data_size = sizeof(struct mwl8k_vif);
hw->sta_data_size = sizeof(struct mwl8k_sta);
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index 275408eaf95e..257a9eadd595 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -351,8 +351,7 @@ int p54_setup_mac(struct p54_common *priv)
* "TRANSPARENT and PROMISCUOUS are mutually exclusive"
* STSW45X0C LMAC API - page 12
*/
- if (((priv->filter_flags & FIF_PROMISC_IN_BSS) ||
- (priv->filter_flags & FIF_OTHER_BSS)) &&
+ if (priv->filter_flags & FIF_OTHER_BSS &&
(mode != P54_FILTER_TYPE_PROMISCUOUS))
mode |= P54_FILTER_TYPE_TRANSPARENT;
} else {
diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c
index 1f6fd5ff5531..9a8fedd3c0f5 100644
--- a/drivers/net/wireless/p54/led.c
+++ b/drivers/net/wireless/p54/led.c
@@ -83,7 +83,7 @@ static void p54_led_brightness_set(struct led_classdev *led_dev,
static int p54_register_led(struct p54_common *priv,
unsigned int led_index,
- char *name, char *trigger)
+ char *name, const char *trigger)
{
struct p54_led_dev *led = &priv->leds[led_index];
int err;
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index e79674f73dc5..7805864e76f9 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -395,13 +395,11 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
{
struct p54_common *priv = dev->priv;
- *total_flags &= FIF_PROMISC_IN_BSS |
- FIF_ALLMULTI |
- FIF_OTHER_BSS;
+ *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS;
priv->filter_flags = *total_flags;
- if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
+ if (changed_flags & FIF_OTHER_BSS)
p54_setup_mac(priv);
if (changed_flags & FIF_ALLMULTI || multicast)
@@ -748,12 +746,12 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
spin_lock_init(&priv->tx_stats_lock);
skb_queue_head_init(&priv->tx_queue);
skb_queue_head_init(&priv->tx_pending);
- dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK |
- IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+ ieee80211_hw_set(dev, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(dev, MFP_CAPABLE);
+ ieee80211_hw_set(dev, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(dev, SUPPORTS_PS);
+ ieee80211_hw_set(dev, RX_INCLUDES_FCS);
+ ieee80211_hw_set(dev, SIGNAL_DBM);
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 477f86354dc5..0881ba8535f4 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -143,7 +143,7 @@ static int psm;
static char *essid;
/* Default to encapsulation unless translation requested */
-static bool translate = 1;
+static bool translate = true;
static int country = USA;
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index d72ff8e7125d..71a825c750cf 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -356,9 +356,9 @@ struct ndis_80211_pmkid {
#define CAP_MODE_80211G 4
#define CAP_MODE_MASK 7
-#define WORK_LINK_UP (1<<0)
-#define WORK_LINK_DOWN (1<<1)
-#define WORK_SET_MULTICAST_LIST (1<<2)
+#define WORK_LINK_UP 0
+#define WORK_LINK_DOWN 1
+#define WORK_SET_MULTICAST_LIST 2
#define RNDIS_WLAN_ALG_NONE 0
#define RNDIS_WLAN_ALG_WEP (1<<0)
@@ -2861,7 +2861,7 @@ static void rndis_wlan_do_link_down_work(struct usbnet *usbdev)
deauthenticate(usbdev);
- cfg80211_disconnected(usbdev->net, 0, NULL, 0, GFP_KERNEL);
+ cfg80211_disconnected(usbdev->net, 0, NULL, 0, true, GFP_KERNEL);
}
netif_carrier_off(usbdev->net);
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index aeaf87bb5518..7e804324bfa7 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -1062,10 +1062,9 @@ int rsi_mac80211_attach(struct rsi_common *common)
hw->priv = adapter;
adapter->hw = hw;
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_HAS_RATE_CONTROL |
- IEEE80211_HW_AMPDU_AGGREGATION |
- 0;
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
hw->queues = MAX_HW_QUEUES;
hw->extra_tx_headroom = RSI_NEEDED_HEADROOM;
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index bdf5590ba304..9a3966cd6fbe 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -273,10 +273,8 @@ static void rt2400pci_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
!(filter_flags & FIF_CONTROL));
- rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
- !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME, 1);
rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
- !(filter_flags & FIF_PROMISC_IN_BSS) &&
!rt2x00dev->intf_ap_count);
rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg);
@@ -1576,10 +1574,10 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all hw fields.
*/
- rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS);
+ ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM);
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 79f4fe65a119..1a6740b4d396 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -274,10 +274,8 @@ static void rt2500pci_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
!(filter_flags & FIF_CONTROL));
- rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
- !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME, 1);
rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
- !(filter_flags & FIF_PROMISC_IN_BSS) &&
!rt2x00dev->intf_ap_count);
rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
rt2x00_set_field32(&reg, RXCSR0_DROP_MCAST,
@@ -1871,10 +1869,10 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all hw fields.
*/
- rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS);
+ ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM);
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 05c64597838d..b50d873145d5 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -434,10 +434,8 @@ static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CONTROL,
!(filter_flags & FIF_CONTROL));
- rt2x00_set_field16(&reg, TXRX_CSR2_DROP_NOT_TO_ME,
- !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_NOT_TO_ME, 1);
rt2x00_set_field16(&reg, TXRX_CSR2_DROP_TODS,
- !(filter_flags & FIF_PROMISC_IN_BSS) &&
!rt2x00dev->intf_ap_count);
rt2x00_set_field16(&reg, TXRX_CSR2_DROP_VERSION_ERROR, 1);
rt2x00_set_field16(&reg, TXRX_CSR2_DROP_MULTICAST,
@@ -1698,11 +1696,10 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
* multicast and broadcast traffic immediately instead of buffering it
* infinitly and thus dropping it after some time.
*/
- rt2x00dev->hw->flags =
- IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS);
+ ieee80211_hw_set(rt2x00dev->hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM);
/*
* Disable powersaving as default.
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index ebd5625d13f1..95c1d7c0a2f3 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -2961,6 +2961,15 @@ enum rt2800_eeprom_word {
#define BCN_TBTT_OFFSET 64
/*
+ * Hardware has 255 WCID table entries. First 32 entries are reserved for
+ * shared keys. Since parts of the pairwise key table might be shared with
+ * the beacon frame buffers 6 & 7 we could only use the first 222 entries.
+ */
+#define WCID_START 33
+#define WCID_END 222
+#define STA_IDS_SIZE (WCID_END - WCID_START + 2)
+
+/*
* RT2800 driver data structure
*/
struct rt2800_drv_data {
@@ -2971,6 +2980,7 @@ struct rt2800_drv_data {
u8 txmixer_gain_24g;
u8 txmixer_gain_5g;
unsigned int tbtt_tick;
+ DECLARE_BITMAP(sta_ids, STA_IDS_SIZE);
};
#endif /* RT2800_H */
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index be2d54f257b1..9524564f873b 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -1381,38 +1381,6 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2800_config_shared_key);
-static inline int rt2800_find_wcid(struct rt2x00_dev *rt2x00dev)
-{
- struct mac_wcid_entry wcid_entry;
- int idx;
- u32 offset;
-
- /*
- * Search for the first free WCID entry and return the corresponding
- * index.
- *
- * Make sure the WCID starts _after_ the last possible shared key
- * entry (>32).
- *
- * Since parts of the pairwise key table might be shared with
- * the beacon frame buffers 6 & 7 we should only write into the
- * first 222 entries.
- */
- for (idx = 33; idx <= 222; idx++) {
- offset = MAC_WCID_ENTRY(idx);
- rt2800_register_multiread(rt2x00dev, offset, &wcid_entry,
- sizeof(wcid_entry));
- if (is_broadcast_ether_addr(wcid_entry.mac))
- return idx;
- }
-
- /*
- * Use -1 to indicate that we don't have any more space in the WCID
- * table.
- */
- return -1;
-}
-
int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key)
@@ -1425,7 +1393,7 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
* Allow key configuration only for STAs that are
* known by the hw.
*/
- if (crypto->wcid < 0)
+ if (crypto->wcid > WCID_END)
return -ENOSPC;
key->hw_key_idx = crypto->wcid;
@@ -1455,11 +1423,13 @@ int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif,
{
int wcid;
struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta);
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
/*
- * Find next free WCID.
+ * Search for the first free WCID entry and return the corresponding
+ * index.
*/
- wcid = rt2800_find_wcid(rt2x00dev);
+ wcid = find_first_zero_bit(drv_data->sta_ids, STA_IDS_SIZE) + WCID_START;
/*
* Store selected wcid even if it is invalid so that we can
@@ -1471,9 +1441,11 @@ int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif,
* No space left in the device, however, we can still communicate
* with the STA -> No error.
*/
- if (wcid < 0)
+ if (wcid > WCID_END)
return 0;
+ __set_bit(wcid - WCID_START, drv_data->sta_ids);
+
/*
* Clean up WCID attributes and write STA address to the device.
*/
@@ -1487,11 +1459,16 @@ EXPORT_SYMBOL_GPL(rt2800_sta_add);
int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, int wcid)
{
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+
+ if (wcid > WCID_END)
+ return 0;
/*
* Remove WCID entry, no need to clean the attributes as they will
* get renewed when the WCID is reused.
*/
rt2800_config_wcid(rt2x00dev, NULL, wcid);
+ __clear_bit(wcid - WCID_START, drv_data->sta_ids);
return 0;
}
@@ -1513,8 +1490,7 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_FCSFAIL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PHY_ERROR,
!(filter_flags & FIF_PLCPFAIL));
- rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME,
- !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME, 1);
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0);
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_VER_ERROR, 1);
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_MULTICAST,
@@ -7498,13 +7474,12 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all hw fields.
*/
- rt2x00dev->hw->flags =
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_HT_CCK_RATES);
+ ieee80211_hw_set(rt2x00dev->hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(rt2x00dev->hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM);
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS);
/*
* Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
@@ -7514,8 +7489,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
* infinitly and thus dropping it after some time.
*/
if (!rt2x00_is_usb(rt2x00dev))
- rt2x00dev->hw->flags |=
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING);
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -7818,21 +7792,25 @@ EXPORT_SYMBOL_GPL(rt2800_probe_hw);
/*
* IEEE80211 stack callback functions.
*/
-void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
- u16 *iv16)
+void rt2800_get_key_seq(struct ieee80211_hw *hw,
+ struct ieee80211_key_conf *key,
+ struct ieee80211_key_seq *seq)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct mac_iveiv_entry iveiv_entry;
u32 offset;
- offset = MAC_IVEIV_ENTRY(hw_key_idx);
+ if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
+ return;
+
+ offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
rt2800_register_multiread(rt2x00dev, offset,
&iveiv_entry, sizeof(iveiv_entry));
- memcpy(iv16, &iveiv_entry.iv[0], sizeof(*iv16));
- memcpy(iv32, &iveiv_entry.iv[4], sizeof(*iv32));
+ memcpy(&seq->tkip.iv16, &iveiv_entry.iv[0], 2);
+ memcpy(&seq->tkip.iv32, &iveiv_entry.iv[4], 4);
}
-EXPORT_SYMBOL_GPL(rt2800_get_tkip_seq);
+EXPORT_SYMBOL_GPL(rt2800_get_key_seq);
int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
@@ -7967,11 +7945,11 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
/*
* Don't allow aggregation for stations the hardware isn't aware
* of because tx status reports for frames to an unknown station
- * always contain wcid=255 and thus we can't distinguish between
- * multiple stations which leads to unwanted situations when the
- * hw reorders frames due to aggregation.
+ * always contain wcid=WCID_END+1 and thus we can't distinguish
+ * between multiple stations which leads to unwanted situations
+ * when the hw reorders frames due to aggregation.
*/
- if (sta_priv->wcid < 0)
+ if (sta_priv->wcid > WCID_END)
return 1;
switch (action) {
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 3019db637a4b..1609b8a7f7eb 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -209,8 +209,9 @@ int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev);
-void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
- u16 *iv16);
+void rt2800_get_key_seq(struct ieee80211_hw *hw,
+ struct ieee80211_key_conf *key,
+ struct ieee80211_key_seq *seq);
int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
int rt2800_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue_idx,
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index cc1b3cc73c5a..0af22573a2eb 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -309,7 +309,7 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
- .get_tkip_seq = rt2800_get_tkip_seq,
+ .get_key_seq = rt2800_get_key_seq,
.set_rts_threshold = rt2800_set_rts_threshold,
.sta_add = rt2x00mac_sta_add,
.sta_remove = rt2x00mac_sta_remove,
diff --git a/drivers/net/wireless/rt2x00/rt2800soc.c b/drivers/net/wireless/rt2x00/rt2800soc.c
index aaa7aa4cad9d..a985a5a7945e 100644
--- a/drivers/net/wireless/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/rt2x00/rt2800soc.c
@@ -148,7 +148,7 @@ static const struct ieee80211_ops rt2800soc_mac80211_ops = {
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
- .get_tkip_seq = rt2800_get_tkip_seq,
+ .get_key_seq = rt2800_get_key_seq,
.set_rts_threshold = rt2800_set_rts_threshold,
.sta_add = rt2x00mac_sta_add,
.sta_remove = rt2x00mac_sta_remove,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 6ec2466b52b6..5932306084fd 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -835,7 +835,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
- .get_tkip_seq = rt2800_get_tkip_seq,
+ .get_key_seq = rt2800_get_key_seq,
.set_rts_threshold = rt2800_set_rts_threshold,
.sta_add = rt2x00mac_sta_add,
.sta_remove = rt2x00mac_sta_remove,
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 300876df056f..3c26ee65a415 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -359,8 +359,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
FIF_PLCPFAIL |
FIF_CONTROL |
FIF_PSPOLL |
- FIF_OTHER_BSS |
- FIF_PROMISC_IN_BSS;
+ FIF_OTHER_BSS;
/*
* Apply some rules to the filters:
@@ -369,9 +368,6 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
* - Multicast filter seems to kill broadcast traffic so never use it.
*/
*total_flags |= FIF_ALLMULTI;
- if (*total_flags & FIF_OTHER_BSS ||
- *total_flags & FIF_PROMISC_IN_BSS)
- *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
/*
* If the device has a single filter for all control frames,
@@ -539,16 +535,8 @@ int rt2x00mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta);
- /*
- * If there's no space left in the device table store
- * -1 as wcid but tell mac80211 everything went ok.
- */
- if (rt2x00dev->ops->lib->sta_add(rt2x00dev, vif, sta))
- sta_priv->wcid = -1;
-
- return 0;
+ return rt2x00dev->ops->lib->sta_add(rt2x00dev, vif, sta);
}
EXPORT_SYMBOL_GPL(rt2x00mac_sta_add);
@@ -558,12 +546,6 @@ int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta);
- /*
- * If we never sent the STA to the device no need to clean it up.
- */
- if (sta_priv->wcid < 0)
- return 0;
-
return rt2x00dev->ops->lib->sta_remove(rt2x00dev, sta_priv->wcid);
}
EXPORT_SYMBOL_GPL(rt2x00mac_sta_remove);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 819455009fe4..c0e730ea1b69 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -530,10 +530,8 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
!(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
- !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
- !(filter_flags & FIF_PROMISC_IN_BSS) &&
!rt2x00dev->intf_ap_count);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
@@ -2760,11 +2758,10 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all hw fields.
*/
- rt2x00dev->hw->flags =
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS);
+ ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM);
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index a5458cf01fb2..7081e13b4fd6 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -480,10 +480,8 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_PLCPFAIL));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
!(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
- rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
- !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
- !(filter_flags & FIF_PROMISC_IN_BSS) &&
!rt2x00dev->intf_ap_count);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
@@ -2107,16 +2105,15 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all hw fields.
*
- * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING unless we are
+ * Don't set IEEE80211_HOST_BROADCAST_PS_BUFFERING unless we are
* capable of sending the buffered frames out after the DTIM
* transmission using rt2x00lib_beacondone. This will send out
* multicast and broadcast traffic immediately instead of buffering it
* infinitly and thus dropping it after some time.
*/
- rt2x00dev->hw->flags =
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ ieee80211_hw_set(rt2x00dev->hw, PS_NULLFUNC_STACK);
+ ieee80211_hw_set(rt2x00dev->hw, SIGNAL_DBM);
+ ieee80211_hw_set(rt2x00dev->hw, SUPPORTS_PS);
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c
index 706b844bce00..a43a16fde59d 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c
@@ -1802,8 +1802,9 @@ static int rtl8180_probe(struct pci_dev *pdev,
priv->band.n_bitrates = 4;
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
- dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_RX_INCLUDES_FCS;
+ ieee80211_hw_set(dev, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(dev, RX_INCLUDES_FCS);
+
dev->vif_data_size = sizeof(struct rtl8180_vif);
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
@@ -1868,9 +1869,9 @@ static int rtl8180_probe(struct pci_dev *pdev,
}
if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180)
- dev->flags |= IEEE80211_HW_SIGNAL_DBM;
+ ieee80211_hw_set(dev, SIGNAL_DBM);
else
- dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
+ ieee80211_hw_set(dev, SIGNAL_UNSPEC);
rtl8180_eeprom_read(priv);
diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c
index 629ad8cfa17b..b7f72f9c7988 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c
@@ -1478,9 +1478,9 @@ static int rtl8187_probe(struct usb_interface *intf,
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
- dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_RX_INCLUDES_FCS;
+ ieee80211_hw_set(dev, RX_INCLUDES_FCS);
+ ieee80211_hw_set(dev, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(dev, SIGNAL_DBM);
/* Initialize rate-control variables */
dev->max_rates = 1;
dev->max_rate_tries = RETRY_COUNT;
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig
index 5cf509d346e8..73067cac289c 100644
--- a/drivers/net/wireless/rtlwifi/Kconfig
+++ b/drivers/net/wireless/rtlwifi/Kconfig
@@ -100,7 +100,7 @@ config RTL8821AE
select RTLWIFI_PCI
select RTLBTCOEXIST
---help---
- This is the driver for Realtek RTL8i821AE/RTL8812AE 802.11av PCIe
+ This is the driver for Realtek RTL8821AE/RTL8812AE 802.11ac PCIe
wireless network adapters.
If you choose to build it as a module, it will be called rtl8821ae
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 01f56c7df8b5..0517a4f2d3f2 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -394,20 +394,18 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
}
}
/* <5> set hw caps */
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_CONNECTION_MONITOR |
- /* IEEE80211_HW_SUPPORTS_CQM_RSSI | */
- IEEE80211_HW_MFP_CAPABLE |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0;
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, CONNECTION_MONITOR);
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
/* swlps or hwlps has been set in diff chip in init_sw_vars */
- if (rtlpriv->psc.swctrl_lps)
- hw->flags |= IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK |
- /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
- 0;
+ if (rtlpriv->psc.swctrl_lps) {
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
+ }
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
index cefe26991421..f2b9d11adc9e 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
@@ -1286,8 +1286,11 @@ static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec,
0x12, 0xe1, 0x90);
break;
case 3:
- btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c,
- 0x3, 0xf1, 0x90);
+ /* This call breaks BT when wireless is active -
+ * comment it out for now until a better fix is found:
+ * btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c,
+ * 0x3, 0xf1, 0x90);
+ */
break;
case 4:
btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x10,
diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h
index 82733c6b8c46..782ac2fc4b28 100644
--- a/drivers/net/wireless/rtlwifi/core.h
+++ b/drivers/net/wireless/rtlwifi/core.h
@@ -27,8 +27,7 @@
#define __RTL_CORE_H__
#define RTL_SUPPORTED_FILTERS \
- (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | FIF_CONTROL | \
+ (FIF_ALLMULTI | FIF_CONTROL | \
FIF_OTHER_BSS | \
FIF_FCSFAIL | \
FIF_BCN_PRBRESP_PROMISC)
diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c
index 1893d01b9e78..a62bf0a65c32 100644
--- a/drivers/net/wireless/rtlwifi/regd.c
+++ b/drivers/net/wireless/rtlwifi/regd.c
@@ -40,6 +40,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{COUNTRY_CODE_GLOBAL_DOMAIN, "JP"},
{COUNTRY_CODE_WORLD_WIDE_13, "EC"},
{COUNTRY_CODE_TELEC_NETGEAR, "EC"},
+ {COUNTRY_CODE_WORLD_WIDE_13_5G_ALL, "US"},
};
/*
@@ -124,6 +125,17 @@ static const struct ieee80211_regdomain rtl_regdom_14_60_64 = {
}
};
+static const struct ieee80211_regdomain rtl_regdom_12_13_5g_all = {
+ .n_reg_rules = 4,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTL819x_2GHZ_CH01_11,
+ RTL819x_2GHZ_CH12_13,
+ RTL819x_5GHZ_5150_5350,
+ RTL819x_5GHZ_5470_5850,
+ }
+};
+
static const struct ieee80211_regdomain rtl_regdom_14 = {
.n_reg_rules = 3,
.alpha2 = "99",
@@ -348,6 +360,8 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select(
return &rtl_regdom_14_60_64;
case COUNTRY_CODE_GLOBAL_DOMAIN:
return &rtl_regdom_14;
+ case COUNTRY_CODE_WORLD_WIDE_13_5G_ALL:
+ return &rtl_regdom_12_13_5g_all;
default:
return &rtl_regdom_no_midband;
}
@@ -384,6 +398,25 @@ static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode)
return NULL;
}
+static u8 channel_plan_to_country_code(u8 channelplan)
+{
+ switch (channelplan) {
+ case 0x20:
+ case 0x21:
+ return COUNTRY_CODE_WORLD_WIDE_13;
+ case 0x22:
+ return COUNTRY_CODE_IC;
+ case 0x32:
+ return COUNTRY_CODE_TELEC_NETGEAR;
+ case 0x41:
+ return COUNTRY_CODE_GLOBAL_DOMAIN;
+ case 0x7f:
+ return COUNTRY_CODE_WORLD_WIDE_13_5G_ALL;
+ default:
+ return COUNTRY_CODE_MAX; /*Error*/
+ }
+}
+
int rtl_regd_init(struct ieee80211_hw *hw,
void (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request))
@@ -396,11 +429,12 @@ int rtl_regd_init(struct ieee80211_hw *hw,
return -EINVAL;
/* init country_code from efuse channel plan */
- rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan;
+ rtlpriv->regd.country_code =
+ channel_plan_to_country_code(rtlpriv->efuse.channel_plan);
- RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE,
- "rtl: EEPROM regdomain: 0x%0x\n",
- rtlpriv->regd.country_code);
+ RT_TRACE(rtlpriv, COMP_REGD, DBG_DMESG,
+ "rtl: EEPROM regdomain: 0x%0x conuntry code: %d\n",
+ rtlpriv->efuse.channel_plan, rtlpriv->regd.country_code);
if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) {
RT_TRACE(rtlpriv, COMP_REGD, DBG_DMESG,
diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h
index 3bbbaaa68530..f7f15bce35dd 100644
--- a/drivers/net/wireless/rtlwifi/regd.h
+++ b/drivers/net/wireless/rtlwifi/regd.h
@@ -49,6 +49,7 @@ enum country_code_type_t {
COUNTRY_CODE_GLOBAL_DOMAIN = 10,
COUNTRY_CODE_WORLD_WIDE_13 = 11,
COUNTRY_CODE_TELEC_NETGEAR = 12,
+ COUNTRY_CODE_WORLD_WIDE_13_5G_ALL = 13,
/*add new channel plan above this line */
COUNTRY_CODE_MAX
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
index d930c1f78721..ce4da9d79fbd 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
@@ -1123,23 +1123,22 @@ static void rtl88e_dm_init_txpower_tracking(struct ieee80211_hw *hw)
void rtl88e_dm_check_txpower_tracking(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- static u8 tm_trigger;
if (!rtlpriv->dm.txpower_tracking)
return;
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17)|BIT(16),
0x03);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Trigger 88E Thermal Meter!!\n");
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
return;
} else {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Schedule TxPowerTracking !!\n");
dm_txpower_track_cb_therm(hw);
- tm_trigger = 0;
+ rtlpriv->dm.tm_trigger = 0;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
index 86ce5b1930e6..8ee83b093c0d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
@@ -1354,27 +1354,11 @@ void rtl88ee_set_qos(struct ieee80211_hw *hw, int aci)
}
}
-static void rtl88ee_clear_interrupt(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 tmp;
-
- tmp = rtl_read_dword(rtlpriv, REG_HISR);
- rtl_write_dword(rtlpriv, REG_HISR, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HISRE);
- rtl_write_dword(rtlpriv, REG_HISRE, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HSISR);
- rtl_write_dword(rtlpriv, REG_HSISR, tmp);
-}
-
void rtl88ee_enable_interrupt(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- rtl88ee_clear_interrupt(hw);/*clear it here first*/
rtl_write_dword(rtlpriv, REG_HIMR,
rtlpci->irq_mask[0] & 0xFFFFFFFF);
rtl_write_dword(rtlpriv, REG_HIMRE,
@@ -1919,8 +1903,8 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
"dev_addr: %pM\n", rtlefuse->dev_addr);
/*channel plan */
rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN];
- /* set channel paln to world wide 13 */
- rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+ /* set channel plan from efuse */
+ rtlefuse->channel_plan = rtlefuse->eeprom_channelplan;
/*tx power*/
_rtl88ee_read_txpower_info_from_hwpg(hw,
rtlefuse->autoload_failflag,
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c
index ef28c8ea1e84..02013df968a0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c
@@ -23,7 +23,7 @@
*
*****************************************************************************/
-#include "pwrseqcmd.h"
+#include "../pwrseqcmd.h"
#include "pwrseq.h"
/* drivers should parse below arrays and do the corresponding actions */
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
index 79103347d967..f2d9c6116e5c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
@@ -26,7 +26,7 @@
#ifndef __RTL8723E_PWRSEQ_H__
#define __RTL8723E_PWRSEQ_H__
-#include "pwrseqcmd.h"
+#include "../pwrseqcmd.h"
/* Check document WM-20110607-Paul-RTL8188EE_Power_Architecture-R02.vsd
* There are 6 HW Power States:
* 0: POFF--Power Off
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
index f5ee67cda73a..0aca6f47487c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
@@ -1169,23 +1169,22 @@ static void rtl92c_dm_check_txpower_tracking_thermal_meter(
struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- static u8 tm_trigger;
if (!rtlpriv->dm.txpower_tracking)
return;
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, RFREG_OFFSET_MASK,
0x60);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Trigger 92S Thermal Meter!!\n");
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
return;
} else {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Schedule TxPowerTracking direct call!!\n");
rtl92c_dm_txpower_tracking_directcall(hw);
- tm_trigger = 0;
+ rtlpriv->dm.tm_trigger = 0;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
index 29983bc96a89..14b819ea8b71 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
@@ -233,13 +233,14 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)
pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
pfwdata = (u8 *)rtlhal->pfirmware;
fwsize = rtlhal->fwsize;
-
if (IS_FW_HEADER_EXIST(pfwheader)) {
RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
"Firmware Version(%d), Signature(%#x),Size(%d)\n",
pfwheader->version, pfwheader->signature,
(int)sizeof(struct rtl92c_firmware_header));
+ rtlhal->fw_version = pfwheader->version;
+ rtlhal->fw_subversion = pfwheader->subversion;
pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index d310d55d800e..767358a553fb 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -840,6 +840,26 @@ static void _rtl92cu_init_wmac_setting(struct ieee80211_hw *hw)
rtl92c_set_data_filter(hw, value16);
}
+static void _rtl92cu_init_beacon_parameters(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+
+ rtl_write_word(rtlpriv, REG_BCN_CTRL, 0x1010);
+
+ /* TODO: Remove these magic number */
+ rtl_write_word(rtlpriv, REG_TBTT_PROHIBIT, 0x6404);
+ rtl_write_byte(rtlpriv, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);
+ rtl_write_byte(rtlpriv, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME);
+ /* Change beacon AIFS to the largest number
+ * beacause test chip does not contension before sending beacon.
+ */
+ if (IS_NORMAL_CHIP(rtlhal->version))
+ rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660F);
+ else
+ rtl_write_word(rtlpriv, REG_BCNTCFG, 0x66FF);
+}
+
static int _rtl92cu_init_mac(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -887,9 +907,9 @@ static int _rtl92cu_init_mac(struct ieee80211_hw *hw)
_rtl92cu_init_usb_aggregation(hw);
rtlpriv->cfg->ops->set_bw_mode(hw, NL80211_CHAN_HT20);
rtl92c_set_min_space(hw, IS_92C_SERIAL(rtlhal->version));
- rtl92c_init_beacon_parameters(hw, rtlhal->version);
+ _rtl92cu_init_beacon_parameters(hw);
rtl92c_init_ampdu_aggregation(hw);
- rtl92c_init_beacon_max_error(hw, true);
+ rtl92c_init_beacon_max_error(hw);
return err;
}
@@ -987,7 +1007,6 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
int err = 0;
- static bool iqk_initialized;
unsigned long flags;
/* As this function can take a very long time (up to 350 ms)
@@ -1038,11 +1057,11 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
if (ppsc->rfpwr_state == ERFON) {
rtl92c_phy_set_rfpath_switch(hw, 1);
- if (iqk_initialized) {
+ if (rtlphy->iqk_initialized) {
rtl92c_phy_iq_calibrate(hw, true);
} else {
rtl92c_phy_iq_calibrate(hw, false);
- iqk_initialized = true;
+ rtlphy->iqk_initialized = true;
}
rtl92c_dm_check_txpower_tracking(hw);
rtl92c_phy_lc_calibrate(hw);
@@ -1323,7 +1342,6 @@ static int _rtl92cu_set_media_status(struct ieee80211_hw *hw,
enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
bt_msr &= 0xfc;
- rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xFF);
if (type == NL80211_IFTYPE_UNSPECIFIED || type ==
NL80211_IFTYPE_STATION) {
_rtl92cu_stop_tx_beacon(hw);
@@ -1392,6 +1410,9 @@ void rtl92cu_card_disable(struct ieee80211_hw *hw)
_CardDisableHWSM(hw);
else
_CardDisableWithoutHWSM(hw);
+
+ /* after power off we should do iqk again */
+ rtlpriv->phy.iqk_initialized = false;
}
void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
@@ -1452,25 +1473,6 @@ int rtl92cu_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
return 0;
}
-static void _InitBeaconParameters(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-
- rtl_write_word(rtlpriv, REG_BCN_CTRL, 0x1010);
-
- /* TODO: Remove these magic number */
- rtl_write_word(rtlpriv, REG_TBTT_PROHIBIT, 0x6404);
- rtl_write_byte(rtlpriv, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);
- rtl_write_byte(rtlpriv, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME);
- /* Change beacon AIFS to the largest number
- * beacause test chip does not contension before sending beacon. */
- if (IS_NORMAL_CHIP(rtlhal->version))
- rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660F);
- else
- rtl_write_word(rtlpriv, REG_BCNTCFG, 0x66FF);
-}
-
static void _beacon_function_enable(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1491,7 +1493,7 @@ void rtl92cu_set_beacon_related_registers(struct ieee80211_hw *hw)
atim_window = 2; /*FIX MERGE */
rtl_write_word(rtlpriv, REG_ATIMWND, atim_window);
rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
- _InitBeaconParameters(hw);
+ _rtl92cu_init_beacon_parameters(hw);
rtl_write_byte(rtlpriv, REG_SLOT, 0x09);
/*
* Force beacon frame transmission even after receiving beacon frame
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
index adb810794eef..490a7cf7c702 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
@@ -613,7 +613,7 @@ void rtl92c_init_ampdu_aggregation(struct ieee80211_hw *hw)
rtl_write_word(rtlpriv, 0x4CA, 0x0708);
}
-void rtl92c_init_beacon_max_error(struct ieee80211_hw *hw, bool infra_mode)
+void rtl92c_init_beacon_max_error(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -641,21 +641,6 @@ void rtl92c_init_retry_function(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, REG_ACKTO, 0x40);
}
-void rtl92c_init_beacon_parameters(struct ieee80211_hw *hw,
- enum version_8192c version)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-
- rtl_write_word(rtlpriv, REG_TBTT_PROHIBIT, 0x6404);/* ms */
- rtl_write_byte(rtlpriv, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);/*ms*/
- rtl_write_byte(rtlpriv, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME);
- if (IS_NORMAL_CHIP(rtlhal->version))
- rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660F);
- else
- rtl_write_word(rtlpriv, REG_BCNTCFG, 0x66FF);
-}
-
void rtl92c_disable_fast_edca(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
index bf53652e4edd..e34f0f14ccd7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
@@ -66,13 +66,10 @@ void rtl92c_init_edca_param(struct ieee80211_hw *hw,
void rtl92c_init_edca(struct ieee80211_hw *hw);
void rtl92c_init_ampdu_aggregation(struct ieee80211_hw *hw);
-void rtl92c_init_beacon_max_error(struct ieee80211_hw *hw, bool infra_mode);
+void rtl92c_init_beacon_max_error(struct ieee80211_hw *hw);
void rtl92c_init_rdg_setting(struct ieee80211_hw *hw);
void rtl92c_init_retry_function(struct ieee80211_hw *hw);
-void rtl92c_init_beacon_parameters(struct ieee80211_hw *hw,
- enum version_8192c version);
-
void rtl92c_disable_fast_edca(struct ieee80211_hw *hw);
void rtl92c_set_min_space(struct ieee80211_hw *hw, bool is2T);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
index 12f6d474b492..c972fa50926d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
@@ -108,13 +108,8 @@ void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw,
bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw)
{
bool rtstatus;
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- bool is92c = IS_92C_SERIAL(rtlhal->version);
rtstatus = _rtl92cu_phy_config_mac_with_headerfile(hw);
- if (is92c && IS_HARDWARE_TYPE_8192CE(rtlhal))
- rtl_write_byte(rtlpriv, 0x14, 0x71);
return rtstatus;
}
@@ -122,7 +117,6 @@ bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw)
{
bool rtstatus = true;
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u16 regval;
u32 regval32;
u8 b_reg_hwparafile = 1;
@@ -134,17 +128,11 @@ bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83);
rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb);
rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB);
- if (IS_HARDWARE_TYPE_8192CE(rtlhal)) {
- rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_PPLL | FEN_PCIEA |
- FEN_DIO_PCIE | FEN_BB_GLB_RSTn | FEN_BBRSTB);
- } else if (IS_HARDWARE_TYPE_8192CU(rtlhal)) {
- rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD |
- FEN_BB_GLB_RSTn | FEN_BBRSTB);
- }
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD |
+ FEN_BB_GLB_RSTn | FEN_BBRSTB);
regval32 = rtl_read_dword(rtlpriv, 0x87c);
rtl_write_dword(rtlpriv, 0x87c, regval32 & (~BIT(31)));
- if (IS_HARDWARE_TYPE_8192CU(rtlhal))
- rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f);
+ rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f);
rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80);
if (b_reg_hwparafile == 1)
rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw);
@@ -162,7 +150,7 @@ bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read Rtl819XMACPHY_Array\n");
arraylength = rtlphy->hwparam_tables[MAC_REG].length ;
ptrarray = rtlphy->hwparam_tables[MAC_REG].pdata;
- RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Img:RTL8192CEMAC_2T_ARRAY\n");
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Img:RTL8192CUMAC_2T_ARRAY\n");
for (i = 0; i < arraylength; i = i + 2)
rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]);
return true;
@@ -259,18 +247,18 @@ bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
radiob_arraylen = rtlphy->hwparam_tables[RADIOB_2T].length;
radiob_array_table = rtlphy->hwparam_tables[RADIOB_2T].pdata;
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "Radio_A:RTL8192CERADIOA_2TARRAY\n");
+ "Radio_A:RTL8192CURADIOA_2TARRAY\n");
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "Radio_B:RTL8192CE_RADIOB_2TARRAY\n");
+ "Radio_B:RTL8192CU_RADIOB_2TARRAY\n");
} else {
radioa_arraylen = rtlphy->hwparam_tables[RADIOA_1T].length;
radioa_array_table = rtlphy->hwparam_tables[RADIOA_1T].pdata;
radiob_arraylen = rtlphy->hwparam_tables[RADIOB_1T].length;
radiob_array_table = rtlphy->hwparam_tables[RADIOB_1T].pdata;
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "Radio_A:RTL8192CE_RADIOA_1TARRAY\n");
+ "Radio_A:RTL8192CU_RADIOA_1TARRAY\n");
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "Radio_B:RTL8192CE_RADIOB_1TARRAY\n");
+ "Radio_B:RTL8192CU_RADIOB_1TARRAY\n");
}
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Radio No %x\n", rfpath);
switch (rfpath) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
index b878d56d2f4d..5624ade92cc0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
@@ -66,7 +66,6 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
- struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
u32 tx_agc[2] = { 0, 0 }, tmpval = 0;
@@ -74,14 +73,8 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
u8 idx1, idx2;
u8 *ptr;
- if (rtlhal->interface == INTF_PCI) {
- if (rtlefuse->eeprom_regulatory != 0)
- turbo_scanoff = true;
- } else {
- if ((rtlefuse->eeprom_regulatory != 0) ||
- (rtlefuse->external_pa))
- turbo_scanoff = true;
- }
+ if ((rtlefuse->eeprom_regulatory != 0) || (rtlefuse->external_pa))
+ turbo_scanoff = true;
if (mac->act_scanning) {
tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
@@ -90,11 +83,8 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
(ppowerlevel[idx1] << 8) |
(ppowerlevel[idx1] << 16) |
(ppowerlevel[idx1] << 24);
- if (rtlhal->interface == INTF_USB) {
- if (tx_agc[idx1] > 0x20 &&
- rtlefuse->external_pa)
- tx_agc[idx1] = 0x20;
- }
+ if (tx_agc[idx1] > 0x20 && rtlefuse->external_pa)
+ tx_agc[idx1] = 0x20;
}
} else {
if (rtlpriv->dm.dynamic_txhighpower_lvl ==
@@ -452,9 +442,6 @@ static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
udelay(1);
switch (rfpath) {
case RF90_PATH_A:
- rtstatus = rtl92cu_phy_config_rf_with_headerfile(hw,
- (enum radio_path) rfpath);
- break;
case RF90_PATH_B:
rtstatus = rtl92cu_phy_config_rf_with_headerfile(hw,
(enum radio_path) rfpath);
@@ -483,7 +470,6 @@ static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
}
}
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "<---\n");
- return rtstatus;
phy_rf_cfg_fail:
return rtstatus;
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index cbead007171f..95880fe4106e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -321,7 +321,7 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw,
stats->rate = (u8) GET_RX_DESC_RX_MCS(pdesc);
stats->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc);
stats->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
- stats->isampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1)
+ stats->isfirst_ampdu = (bool)((GET_RX_DESC_PAGGR(pdesc) == 1)
&& (GET_RX_DESC_FAGGR(pdesc) == 1));
stats->timestamp_low = GET_RX_DESC_TSFL(pdesc);
stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
index a1be5a68edfb..587b8c505a76 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
@@ -1240,23 +1240,22 @@ static void rtl92d_dm_initialize_txpower_tracking(struct ieee80211_hw *hw)
void rtl92d_dm_check_txpower_tracking_thermal_meter(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- static u8 tm_trigger;
if (!rtlpriv->dm.txpower_tracking)
return;
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17) |
BIT(16), 0x03);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Trigger 92S Thermal Meter!!\n");
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
return;
} else {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Schedule TxPowerTracking direct call!!\n");
rtl92d_dm_txpower_tracking_callback_thermalmeter(hw);
- tm_trigger = 0;
+ rtlpriv->dm.tm_trigger = 0;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
index c5d4b8013cde..232865cc3ffd 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
@@ -875,7 +875,7 @@ static void _rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id,
break;
default:
RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
- "[C2H], Unkown packet!! CmdId(%#X)!\n", c2h_cmd_id);
+ "[C2H], Unknown packet!! CmdId(%#X)!\n", c2h_cmd_id);
break;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
index da0a6125f314..5f14308e8eb3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
@@ -1584,28 +1584,11 @@ void rtl92ee_set_qos(struct ieee80211_hw *hw, int aci)
}
}
-static void rtl92ee_clear_interrupt(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 tmp;
-
- tmp = rtl_read_dword(rtlpriv, REG_HISR);
- rtl_write_dword(rtlpriv, REG_HISR, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HISRE);
- rtl_write_dword(rtlpriv, REG_HISRE, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HSISR);
- rtl_write_dword(rtlpriv, REG_HSISR, tmp);
-}
-
void rtl92ee_enable_interrupt(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- rtl92ee_clear_interrupt(hw);/*clear it here first*/
-
rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
rtlpci->irq_enabled = true;
@@ -2194,8 +2177,8 @@ static void _rtl92ee_read_adapter_info(struct ieee80211_hw *hw)
"dev_addr: %pM\n", rtlefuse->dev_addr);
/*channel plan */
rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
- /* set channel paln to world wide 13 */
- rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+ /* set channel plan from efuse */
+ rtlefuse->channel_plan = rtlefuse->eeprom_channelplan;
/*tx power*/
_rtl92ee_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag,
hwinfo);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
index 575980b88658..9bae5a92e30f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
@@ -200,7 +200,6 @@ static void _rtl92s_dm_check_txpowertracking_thermalmeter(
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
- static u8 tm_trigger;
u8 tx_power_checkcnt = 5;
/* 2T2R TP issue */
@@ -215,13 +214,13 @@ static void _rtl92s_dm_check_txpowertracking_thermalmeter(
return;
}
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER,
RFREG_OFFSET_MASK, 0x60);
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
} else {
_rtl92s_dm_txpowertracking_callback_thermalmeter(hw);
- tm_trigger = 0;
+ rtlpriv->dm.tm_trigger = 0;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
index 67bb47d77b68..a4b7eac6856f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
@@ -1258,18 +1258,6 @@ void rtl8723e_set_qos(struct ieee80211_hw *hw, int aci)
}
}
-static void rtl8723e_clear_interrupt(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 tmp;
-
- tmp = rtl_read_dword(rtlpriv, REG_HISR);
- rtl_write_dword(rtlpriv, REG_HISR, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HISRE);
- rtl_write_dword(rtlpriv, REG_HISRE, tmp);
-}
-
void rtl8723e_enable_interrupt(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1284,7 +1272,6 @@ void rtl8723e_disable_interrupt(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- rtl8723e_clear_interrupt(hw);/*clear it here first*/
rtl_write_dword(rtlpriv, 0x3a8, IMR8190_DISABLED);
rtl_write_dword(rtlpriv, 0x3ac, IMR8190_DISABLED);
rtlpci->irq_enabled = false;
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
index e77c3a46c94a..3a81cdba8ca3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
@@ -909,23 +909,22 @@ static void rtl8723be_dm_txpower_tracking_callback_thermalmeter(
void rtl8723be_dm_check_txpower_tracking(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- static u8 tm_trigger;
if (!rtlpriv->dm.txpower_tracking)
return;
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17) | BIT(16),
0x03);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Trigger 8723be Thermal Meter!!\n");
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
return;
} else {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Schedule TxPowerTracking !!\n");
rtl8723be_dm_txpower_tracking_callback_thermalmeter(hw);
- tm_trigger = 0;
+ rtlpriv->dm.tm_trigger = 0;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c
index 69d4f0fc1af1..d5da0f3c1217 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c
@@ -613,7 +613,7 @@ static void _rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw,
break;
default:
RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
- "[C2H], Unkown packet!! CmdId(%#X)!\n", c2h_cmd_id);
+ "[C2H], Unknown packet!! CmdId(%#X)!\n", c2h_cmd_id);
break;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c
index b681af3c7a35..c983d2fe147f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c
@@ -1634,28 +1634,11 @@ void rtl8723be_set_qos(struct ieee80211_hw *hw, int aci)
}
}
-static void rtl8723be_clear_interrupt(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 tmp;
-
- tmp = rtl_read_dword(rtlpriv, REG_HISR);
- rtl_write_dword(rtlpriv, REG_HISR, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HISRE);
- rtl_write_dword(rtlpriv, REG_HISRE, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HSISR);
- rtl_write_dword(rtlpriv, REG_HSISR, tmp);
-}
-
void rtl8723be_enable_interrupt(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- rtl8723be_clear_interrupt(hw);/*clear it here first*/
-
rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
rtlpci->irq_enabled = true;
@@ -2139,8 +2122,8 @@ static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw,
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
- /* set channel plan to world wide 13 */
- rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+ /* set channel plan from efuse */
+ rtlefuse->channel_plan = rtlefuse->eeprom_channelplan;
if (rtlhal->oem_id == RT_CID_DEFAULT) {
/* Does this one have a Toshiba SMID from group 1? */
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c
index 342678d2ed42..b57cfd965196 100644
--- a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c
@@ -1068,20 +1068,18 @@ static void rtl8812ae_dm_check_txpower_tracking_thermalmeter(
struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- static u8 tm_trigger;
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER_88E,
BIT(17) | BIT(16), 0x03);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Trigger 8812 Thermal Meter!!\n");
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
return;
}
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Schedule TxPowerTracking direct call!!\n");
rtl8812ae_dm_txpower_tracking_callback_thermalmeter(hw);
- tm_trigger = 0;
}
static void rtl8821ae_dm_iq_calibrate(struct ieee80211_hw *hw)
@@ -2519,21 +2517,19 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter(
void rtl8821ae_dm_check_txpower_tracking_thermalmeter(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- static u8 tm_trigger;
-
- if (!tm_trigger) {
+ if (!rtlpriv->dm.tm_trigger) {
rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER_88E, BIT(17)|BIT(16),
0x03);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Trigger 8821ae Thermal Meter!!\n");
- tm_trigger = 1;
+ rtlpriv->dm.tm_trigger = 1;
return;
} else {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
"Schedule TxPowerTracking !!\n");
rtl8821ae_dm_txpower_tracking_callback_thermalmeter(hw);
- tm_trigger = 0;
+ rtlpriv->dm.tm_trigger = 0;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c
index 8704eee9f3a4..3236d44b459d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c
@@ -2253,31 +2253,11 @@ void rtl8821ae_set_qos(struct ieee80211_hw *hw, int aci)
}
}
-static void rtl8821ae_clear_interrupt(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 tmp;
- tmp = rtl_read_dword(rtlpriv, REG_HISR);
- /*printk("clear interrupt first:\n");
- printk("0x%x = 0x%08x\n",REG_HISR, tmp);*/
- rtl_write_dword(rtlpriv, REG_HISR, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HISRE);
- /*printk("0x%x = 0x%08x\n",REG_HISRE, tmp);*/
- rtl_write_dword(rtlpriv, REG_HISRE, tmp);
-
- tmp = rtl_read_dword(rtlpriv, REG_HSISR);
- /*printk("0x%x = 0x%08x\n",REG_HSISR, tmp);*/
- rtl_write_dword(rtlpriv, REG_HSISR, tmp);
-}
-
void rtl8821ae_enable_interrupt(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- rtl8821ae_clear_interrupt(hw);/*clear it here first*/
-
rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
rtlpci->irq_enabled = true;
@@ -3232,8 +3212,8 @@ static void _rtl8821ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_
if (rtlefuse->eeprom_channelplan == 0xff)
rtlefuse->eeprom_channelplan = 0x7F;
- /* set channel paln to world wide 13 */
- /* rtlefuse->channel_plan = (u8)rtlefuse->eeprom_channelplan; */
+ /* set channel plan from efuse */
+ rtlefuse->channel_plan = rtlefuse->eeprom_channelplan;
/*parse xtal*/
rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_8821AE];
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 51572912c53d..2b770b5e2620 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -1665,6 +1665,7 @@ struct rtl_dm {
u8 last_dtp_lvl;
u8 thermalvalue_avg[AVG_THERMAL_NUM];
u8 thermalvalue_avg_index;
+ u8 tm_trigger;
bool done_txpower;
u8 dynamic_txhighpower_lvl; /*Tx high power level */
u8 dm_flag; /*Indicate each dynamic mechanism's status. */
diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c
index 5695628757ee..d6fbdda2cba3 100644
--- a/drivers/net/wireless/ti/wl1251/acx.c
+++ b/drivers/net/wireless/ti/wl1251/acx.c
@@ -53,10 +53,7 @@ int wl1251_acx_station_id(struct wl1251 *wl)
mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i];
ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac));
- if (ret < 0)
- goto out;
-out:
kfree(mac);
return ret;
}
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 5d54d16a59e7..cd4777954f87 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -763,8 +763,7 @@ static u64 wl1251_op_prepare_multicast(struct ieee80211_hw *hw,
return (u64)(unsigned long)fp;
}
-#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+#define WL1251_SUPPORTED_FILTERS (FIF_ALLMULTI | \
FIF_FCSFAIL | \
FIF_BCN_PRBRESP_PROMISC | \
FIF_CONTROL | \
@@ -795,10 +794,6 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
- if (*total & FIF_PROMISC_IN_BSS) {
- wl->rx_config |= CFG_BSSID_FILTER_EN;
- wl->rx_config |= CFG_RX_ALL_GOOD;
- }
if (*total & FIF_ALLMULTI)
/*
* CFG_MC_FILTER_EN in rx_config needs to be 0 to receive
@@ -825,7 +820,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- if (*total & FIF_ALLMULTI || *total & FIF_PROMISC_IN_BSS)
+ if (*total & FIF_ALLMULTI)
ret = wl1251_acx_group_address_tbl(wl, false, NULL, 0);
else if (fp)
ret = wl1251_acx_group_address_tbl(wl, fp->enabled,
@@ -1481,7 +1476,8 @@ 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_set(wl->hw, SIGNAL_DBM);
+ ieee80211_hw_set(wl->hw, SUPPORTS_PS);
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 717c4f5a02c2..49aca2cf7605 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -24,6 +24,7 @@
#include <linux/ip.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
+#include <linux/irq.h>
#include "../wlcore/wlcore.h"
#include "../wlcore/debug.h"
@@ -578,7 +579,7 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
[PART_TOP_PRCM_ELP_SOC] = {
- .mem = { .start = 0x00A02000, .size = 0x00010000 },
+ .mem = { .start = 0x00A00000, .size = 0x00012000 },
.reg = { .start = 0x00807000, .size = 0x00005000 },
.mem2 = { .start = 0x00800000, .size = 0x0000B000 },
.mem3 = { .start = 0x00000000, .size = 0x00000000 },
@@ -862,6 +863,7 @@ static int wl18xx_pre_upload(struct wl1271 *wl)
{
u32 tmp;
int ret;
+ u16 irq_invert;
BUILD_BUG_ON(sizeof(struct wl18xx_mac_and_phy_params) >
WL18XX_PHY_INIT_MEM_SIZE);
@@ -911,6 +913,28 @@ static int wl18xx_pre_upload(struct wl1271 *wl)
/* re-enable FDSP clock */
ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
MEM_FDSP_CLK_120_ENABLE);
+ if (ret < 0)
+ goto out;
+
+ ret = irq_get_trigger_type(wl->irq);
+ if ((ret == IRQ_TYPE_LEVEL_LOW) || (ret == IRQ_TYPE_EDGE_FALLING)) {
+ wl1271_info("using inverted interrupt logic: %d", ret);
+ ret = wlcore_set_partition(wl,
+ &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
+ if (ret < 0)
+ goto out;
+
+ ret = wl18xx_top_reg_read(wl, TOP_FN0_CCCR_REG_32, &irq_invert);
+ if (ret < 0)
+ goto out;
+
+ irq_invert |= BIT(1);
+ ret = wl18xx_top_reg_write(wl, TOP_FN0_CCCR_REG_32, irq_invert);
+ if (ret < 0)
+ goto out;
+
+ ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
+ }
out:
return ret;
@@ -1351,9 +1375,10 @@ out:
}
#define WL18XX_CONF_FILE_NAME "ti-connectivity/wl18xx-conf.bin"
-static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
+
+static int wl18xx_load_conf_file(struct device *dev, struct wlcore_conf *conf,
+ struct wl18xx_priv_conf *priv_conf)
{
- struct wl18xx_priv *priv = wl->priv;
struct wlcore_conf_file *conf_file;
const struct firmware *fw;
int ret;
@@ -1362,14 +1387,14 @@ static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
if (ret < 0) {
wl1271_error("could not get configuration binary %s: %d",
WL18XX_CONF_FILE_NAME, ret);
- goto out_fallback;
+ return ret;
}
if (fw->size != WL18XX_CONF_SIZE) {
wl1271_error("configuration binary file size is wrong, expected %zu got %zu",
WL18XX_CONF_SIZE, fw->size);
ret = -EINVAL;
- goto out;
+ goto out_release;
}
conf_file = (struct wlcore_conf_file *) fw->data;
@@ -1379,7 +1404,7 @@ static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
"expected 0x%0x got 0x%0x", WL18XX_CONF_MAGIC,
conf_file->header.magic);
ret = -EINVAL;
- goto out;
+ goto out_release;
}
if (conf_file->header.version != cpu_to_le32(WL18XX_CONF_VERSION)) {
@@ -1387,28 +1412,32 @@ static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
"expected 0x%08x got 0x%08x",
WL18XX_CONF_VERSION, conf_file->header.version);
ret = -EINVAL;
- goto out;
+ goto out_release;
}
- memcpy(&wl->conf, &conf_file->core, sizeof(wl18xx_conf));
- memcpy(&priv->conf, &conf_file->priv, sizeof(priv->conf));
+ memcpy(conf, &conf_file->core, sizeof(*conf));
+ memcpy(priv_conf, &conf_file->priv, sizeof(*priv_conf));
+
+out_release:
+ release_firmware(fw);
+ return ret;
+}
- goto out;
+static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
+{
+ struct wl18xx_priv *priv = wl->priv;
-out_fallback:
- wl1271_warning("falling back to default config");
+ if (wl18xx_load_conf_file(dev, &wl->conf, &priv->conf) < 0) {
+ wl1271_warning("falling back to default config");
- /* apply driver default configuration */
- memcpy(&wl->conf, &wl18xx_conf, sizeof(wl18xx_conf));
- /* apply default private configuration */
- memcpy(&priv->conf, &wl18xx_default_priv_conf, sizeof(priv->conf));
+ /* apply driver default configuration */
+ memcpy(&wl->conf, &wl18xx_conf, sizeof(wl->conf));
+ /* apply default private configuration */
+ memcpy(&priv->conf, &wl18xx_default_priv_conf,
+ sizeof(priv->conf));
+ }
- /* For now we just fallback */
return 0;
-
-out:
- release_firmware(fw);
- return ret;
}
static int wl18xx_plt_init(struct wl1271 *wl)
diff --git a/drivers/net/wireless/ti/wl18xx/reg.h b/drivers/net/wireless/ti/wl18xx/reg.h
index a433a75f3cd7..bac2364c8e72 100644
--- a/drivers/net/wireless/ti/wl18xx/reg.h
+++ b/drivers/net/wireless/ti/wl18xx/reg.h
@@ -109,6 +109,7 @@
#define WL18XX_WELP_ARM_COMMAND (WL18XX_REGISTERS_BASE + 0x7100)
#define WL18XX_ENABLE (WL18XX_REGISTERS_BASE + 0x01543C)
+#define TOP_FN0_CCCR_REG_32 (WL18XX_TOP_OCP_BASE + 0x64)
/* PRCM registers */
#define PLATFORM_DETECTION 0xA0E3E0
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 0be807951afe..337223b9f6f8 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -3175,8 +3175,7 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
return (u64)(unsigned long)fp;
}
-#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
- FIF_ALLMULTI | \
+#define WL1271_SUPPORTED_FILTERS (FIF_ALLMULTI | \
FIF_FCSFAIL | \
FIF_BCN_PRBRESP_PROMISC | \
FIF_CONTROL | \
@@ -5966,10 +5965,6 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
{
int ret;
- ret = wl12xx_set_power_on(wl);
- if (ret < 0)
- return ret;
-
ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &wl->chip.id);
if (ret < 0)
goto out;
@@ -5985,7 +5980,6 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
ret = wl->ops->get_mac(wl);
out:
- wl1271_power_off(wl);
return ret;
}
@@ -6066,18 +6060,19 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
/* FIXME: find a proper value */
wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
- wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_HAS_RATE_CONTROL |
- IEEE80211_HW_CONNECTION_MONITOR |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_AP_LINK_PS |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
- IEEE80211_HW_QUEUE_CONTROL |
- IEEE80211_HW_CHANCTX_STA_CSA;
+ ieee80211_hw_set(wl->hw, SUPPORT_FAST_XMIT);
+ ieee80211_hw_set(wl->hw, CHANCTX_STA_CSA);
+ ieee80211_hw_set(wl->hw, QUEUE_CONTROL);
+ ieee80211_hw_set(wl->hw, TX_AMPDU_SETUP_IN_HW);
+ ieee80211_hw_set(wl->hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(wl->hw, AP_LINK_PS);
+ ieee80211_hw_set(wl->hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(wl->hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(wl->hw, CONNECTION_MONITOR);
+ ieee80211_hw_set(wl->hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(wl->hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(wl->hw, SIGNAL_DBM);
+ ieee80211_hw_set(wl->hw, SUPPORTS_PS);
wl->hw->wiphy->cipher_suites = cipher_suites;
wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
@@ -6432,10 +6427,22 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
else
wl->irq_flags |= IRQF_ONESHOT;
+ ret = wl12xx_set_power_on(wl);
+ if (ret < 0)
+ goto out_free_nvs;
+
+ ret = wl12xx_get_hw_info(wl);
+ if (ret < 0) {
+ wl1271_error("couldn't get hw info");
+ wl1271_power_off(wl);
+ goto out_free_nvs;
+ }
+
ret = request_threaded_irq(wl->irq, hardirq_fn, wlcore_irq,
wl->irq_flags, pdev->name, wl);
if (ret < 0) {
- wl1271_error("request_irq() failed: %d", ret);
+ wl1271_error("interrupt configuration failed");
+ wl1271_power_off(wl);
goto out_free_nvs;
}
@@ -6449,12 +6456,7 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
}
#endif
disable_irq(wl->irq);
-
- ret = wl12xx_get_hw_info(wl);
- if (ret < 0) {
- wl1271_error("couldn't get hw info");
- goto out_irq;
- }
+ wl1271_power_off(wl);
ret = wl->ops->identify_chip(wl);
if (ret < 0)
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index e7af261e9198..e539d9b1b562 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -1230,7 +1230,7 @@ static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw,
}
#define SUPPORTED_FIF_FLAGS \
- (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
+ (FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)
static void zd_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
@@ -1256,7 +1256,7 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw,
* we will have some issue with IPv6 which uses multicast for link
* layer address resolution.
*/
- if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI))
+ if (*new_flags & FIF_ALLMULTI)
zd_mc_add_all(&hash);
spin_lock_irqsave(&mac->lock, flags);
@@ -1397,10 +1397,10 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band;
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_UNSPEC |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_MFP_CAPABLE;
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, SIGNAL_UNSPEC);
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_MESH_POINT) |