summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/at76c50x-usb.c3
-rw-r--r--drivers/net/wireless/ath/ath.h3
-rw-r--r--drivers/net/wireless/ath/ath10k/Kconfig1
-rw-r--r--drivers/net/wireless/ath/ath10k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath10k/bmi.c52
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c185
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.h28
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c246
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h66
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c339
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h34
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.c115
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.h7
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.c9
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c171
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c46
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h5
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c722
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.h6
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c1529
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h104
-rw-r--r--drivers/net/wireless/ath/ath10k/spectral.c561
-rw-r--r--drivers/net/wireless/ath/ath10k/spectral.h90
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c17
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c1089
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h699
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c97
-rw-r--r--drivers/net/wireless/ath/ath5k/led.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c1
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c1
-rw-r--r--drivers/net/wireless/ath/ath6kl/usb.c21
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c48
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig18
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile3
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_mac.c7
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h157
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c73
-rw-r--r--drivers/net/wireless/ath/ath9k/channel.c1349
-rw-r--r--drivers/net/wireless/ath/ath9k/common-beacon.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c30
-rw-r--r--drivers/net/wireless/ath/ath9k/dynack.c351
-rw-r--r--drivers/net/wireless/ath/ath9k/dynack.h103
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c22
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h7
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c90
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c633
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c62
-rw-r--r--drivers/net/wireless/ath/ath9k/spectral.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/spectral.h71
-rw-r--r--drivers/net/wireless/ath/ath9k/tx99.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/wow.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c12
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c11
-rw-r--r--drivers/net/wireless/ath/carl9170/tx.c2
-rw-r--r--drivers/net/wireless/ath/spectral_common.h113
-rw-r--r--drivers/net/wireless/ath/wil6210/Kconfig9
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile3
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c132
-rw-r--r--drivers/net/wireless/ath/wil6210/debug.c18
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c389
-rw-r--r--drivers/net/wireless/ath/wil6210/fw.c45
-rw-r--r--drivers/net/wireless/ath/wil6210/fw.h149
-rw-r--r--drivers/net/wireless/ath/wil6210/fw_inc.c495
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c33
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c207
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c25
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c46
-rw-r--r--drivers/net/wireless/ath/wil6210/rx_reorder.c29
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c69
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h11
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h73
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.c49
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.h34
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform_msm.c257
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform_msm.h24
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c89
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h22
-rw-r--r--drivers/net/wireless/atmel_cs.c22
-rw-r--r--drivers/net/wireless/b43/Makefile1
-rw-r--r--drivers/net/wireless/b43/b43.h27
-rw-r--r--drivers/net/wireless/b43/bus.c10
-rw-r--r--drivers/net/wireless/b43/bus.h15
-rw-r--r--drivers/net/wireless/b43/main.c88
-rw-r--r--drivers/net/wireless/b43/main.h2
-rw-r--r--drivers/net/wireless/b43/phy_a.c4
-rw-r--r--drivers/net/wireless/b43/phy_common.c25
-rw-r--r--drivers/net/wireless/b43/phy_g.c8
-rw-r--r--drivers/net/wireless/b43/phy_ht.c225
-rw-r--r--drivers/net/wireless/b43/phy_ht.h7
-rw-r--r--drivers/net/wireless/b43/phy_lcn.c20
-rw-r--r--drivers/net/wireless/b43/phy_lp.c20
-rw-r--r--drivers/net/wireless/b43/phy_n.c130
-rw-r--r--drivers/net/wireless/b43/phy_n.h4
-rw-r--r--drivers/net/wireless/b43/ppr.c199
-rw-r--r--drivers/net/wireless/b43/ppr.h45
-rw-r--r--drivers/net/wireless/b43/radio_2059.c341
-rw-r--r--drivers/net/wireless/b43/radio_2059.h14
-rw-r--r--drivers/net/wireless/b43/tables_nphy.c128
-rw-r--r--drivers/net/wireless/b43/tables_nphy.h2
-rw-r--r--drivers/net/wireless/b43/xmit.h22
-rw-r--r--drivers/net/wireless/brcm80211/Kconfig10
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/Makefile10
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcdc.h7
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fweh.c12
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fweh.h2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h11
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c29
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/dma.c38
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c122
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c8
-rw-r--r--drivers/net/wireless/cw1200/cw1200_spi.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_proc.c6
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c6
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c7
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig12
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c4
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/power.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rxon.c12
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tx.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-7000.c37
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-8000.c18
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-config.h9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.c9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-op-mode.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scd.h118
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h63
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/Makefile2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex.c15
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex_legacy.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/constants.h10
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c13
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c91
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-power.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h88
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c9
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c126
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c285
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h71
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c5
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/offloading.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c34
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/power.c215
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/quota.c46
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c134
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.h10
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c27
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c54
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sf.c8
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c106
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.h22
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tdls.c149
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/testmode.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.c71
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.h16
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tt.c322
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/utils.c23
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c10
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h10
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/rx.c3
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c5
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c145
-rw-r--r--drivers/net/wireless/libertas/cfg.c2
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c8
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c14
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c18
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c31
-rw-r--r--drivers/net/wireless/mwifiex/decl.h4
-rw-r--r--drivers/net/wireless/mwifiex/fw.h17
-rw-r--r--drivers/net/wireless/mwifiex/init.c25
-rw-r--r--drivers/net/wireless/mwifiex/main.c191
-rw-r--r--drivers/net/wireless/mwifiex/main.h50
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c37
-rw-r--r--drivers/net/wireless/mwifiex/pcie.h5
-rw-r--r--drivers/net/wireless/mwifiex/scan.c115
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c28
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c2
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c4
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c13
-rw-r--r--drivers/net/wireless/mwifiex/tdls.c4
-rw-r--r--drivers/net/wireless/mwifiex/usb.c2
-rw-r--r--drivers/net/wireless/mwifiex/util.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_usb.c38
-rw-r--r--drivers/net/wireless/orinoco/scan.c14
-rw-r--r--drivers/net/wireless/p54/main.c3
-rw-r--r--drivers/net/wireless/ray_cs.h5
-rw-r--r--drivers/net/wireless/rayctl.h5
-rw-r--r--drivers/net/wireless/rndis_wlan.c14
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c6
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h6
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c3849
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h185
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c3170
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h184
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c550
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h31
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c2970
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h188
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c3879
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h205
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c54
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h122
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c27
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h6
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/sw.c1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/phy.c8
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c4
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h15
-rw-r--r--drivers/net/wireless/ti/wl1251/spi.c1
-rw-r--r--drivers/net/wireless/ti/wlcore/debug.h2
-rw-r--r--drivers/net/wireless/ti/wlcore/spi.c20
243 files changed, 26575 insertions, 5381 deletions
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 334c2ece855..da92bfa76b7 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -2423,8 +2423,6 @@ static void at76_delete_device(struct at76_priv *priv)
kfree_skb(priv->rx_skb);
- usb_put_dev(priv->udev);
-
at76_dbg(DBG_PROC_ENTRY, "%s: before freeing priv/ieee80211_hw",
__func__);
ieee80211_free_hw(priv->hw);
@@ -2558,6 +2556,7 @@ static void at76_disconnect(struct usb_interface *interface)
wiphy_info(priv->hw->wiphy, "disconnecting\n");
at76_delete_device(priv);
+ usb_put_dev(priv->udev);
dev_info(&interface->dev, "disconnected\n");
}
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index fd9e5305e77..a3b6e27d912 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -234,6 +234,7 @@ void ath_printk(const char *level, const struct ath_common *common,
* AR9462.
* @ATH_DBG_DFS: radar datection
* @ATH_DBG_WOW: Wake on Wireless
+ * @ATH_DBG_DYNACK: dynack handling
* @ATH_DBG_ANY: enable all debugging
*
* The debug level is used to control the amount and type of debugging output
@@ -261,6 +262,8 @@ enum ATH_DEBUG {
ATH_DBG_MCI = 0x00008000,
ATH_DBG_DFS = 0x00010000,
ATH_DBG_WOW = 0x00020000,
+ ATH_DBG_CHAN_CTX = 0x00040000,
+ ATH_DBG_DYNACK = 0x00080000,
ATH_DBG_ANY = 0xffffffff
};
diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig
index a6f5285235a..1053bb5f2cd 100644
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
@@ -25,6 +25,7 @@ config ATH10K_DEBUG
config ATH10K_DEBUGFS
bool "Atheros ath10k debugfs support"
depends on ATH10K
+ select RELAY
---help---
Enabled debugfs support
diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index a4179f49ee1..2cfb63ca932 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -10,6 +10,7 @@ ath10k_core-y += mac.o \
wmi.o \
bmi.o
+ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o
ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c
index 17d221abd58..3d29b0875b3 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.c
+++ b/drivers/net/wireless/ath/ath10k/bmi.c
@@ -22,7 +22,7 @@
void ath10k_bmi_start(struct ath10k *ar)
{
- ath10k_dbg(ATH10K_DBG_BMI, "bmi start\n");
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n");
ar->bmi.done_sent = false;
}
@@ -33,10 +33,10 @@ int ath10k_bmi_done(struct ath10k *ar)
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi done\n");
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi done\n");
if (ar->bmi.done_sent) {
- ath10k_dbg(ATH10K_DBG_BMI, "bmi skipped\n");
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi skipped\n");
return 0;
}
@@ -45,7 +45,7 @@ int ath10k_bmi_done(struct ath10k *ar)
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
if (ret) {
- ath10k_warn("unable to write to the device: %d\n", ret);
+ ath10k_warn(ar, "unable to write to the device: %d\n", ret);
return ret;
}
@@ -61,10 +61,10 @@ int ath10k_bmi_get_target_info(struct ath10k *ar,
u32 resplen = sizeof(resp.get_target_info);
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi get target info\n");
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info\n");
if (ar->bmi.done_sent) {
- ath10k_warn("BMI Get Target Info Command disallowed\n");
+ ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
return -EBUSY;
}
@@ -72,12 +72,12 @@ int ath10k_bmi_get_target_info(struct ath10k *ar,
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
if (ret) {
- ath10k_warn("unable to get target info from device\n");
+ ath10k_warn(ar, "unable to get target info from device\n");
return ret;
}
if (resplen < sizeof(resp.get_target_info)) {
- ath10k_warn("invalid get_target_info response length (%d)\n",
+ ath10k_warn(ar, "invalid get_target_info response length (%d)\n",
resplen);
return -EIO;
}
@@ -97,11 +97,11 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
u32 rxlen;
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
address, length);
if (ar->bmi.done_sent) {
- ath10k_warn("command disallowed\n");
+ ath10k_warn(ar, "command disallowed\n");
return -EBUSY;
}
@@ -115,7 +115,7 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
&resp, &rxlen);
if (ret) {
- ath10k_warn("unable to read from the device (%d)\n",
+ ath10k_warn(ar, "unable to read from the device (%d)\n",
ret);
return ret;
}
@@ -137,11 +137,11 @@ int ath10k_bmi_write_memory(struct ath10k *ar,
u32 txlen;
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
address, length);
if (ar->bmi.done_sent) {
- ath10k_warn("command disallowed\n");
+ ath10k_warn(ar, "command disallowed\n");
return -EBUSY;
}
@@ -159,7 +159,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar,
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
NULL, NULL);
if (ret) {
- ath10k_warn("unable to write to the device (%d)\n",
+ ath10k_warn(ar, "unable to write to the device (%d)\n",
ret);
return ret;
}
@@ -183,11 +183,11 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
u32 resplen = sizeof(resp.execute);
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
address, param);
if (ar->bmi.done_sent) {
- ath10k_warn("command disallowed\n");
+ ath10k_warn(ar, "command disallowed\n");
return -EBUSY;
}
@@ -197,19 +197,19 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
if (ret) {
- ath10k_warn("unable to read from the device\n");
+ ath10k_warn(ar, "unable to read from the device\n");
return ret;
}
if (resplen < sizeof(resp.execute)) {
- ath10k_warn("invalid execute response length (%d)\n",
+ ath10k_warn(ar, "invalid execute response length (%d)\n",
resplen);
return -EIO;
}
*result = __le32_to_cpu(resp.execute.result);
- ath10k_dbg(ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
return 0;
}
@@ -221,11 +221,11 @@ int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
u32 txlen;
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n",
buffer, length);
if (ar->bmi.done_sent) {
- ath10k_warn("command disallowed\n");
+ ath10k_warn(ar, "command disallowed\n");
return -EBUSY;
}
@@ -241,7 +241,7 @@ int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
NULL, NULL);
if (ret) {
- ath10k_warn("unable to write to the device\n");
+ ath10k_warn(ar, "unable to write to the device\n");
return ret;
}
@@ -258,11 +258,11 @@ int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
int ret;
- ath10k_dbg(ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
+ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
address);
if (ar->bmi.done_sent) {
- ath10k_warn("command disallowed\n");
+ ath10k_warn(ar, "command disallowed\n");
return -EBUSY;
}
@@ -271,7 +271,7 @@ int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
if (ret) {
- ath10k_warn("unable to Start LZ Stream to the device\n");
+ ath10k_warn(ar, "unable to Start LZ Stream to the device\n");
return ret;
}
@@ -286,7 +286,7 @@ int ath10k_bmi_fast_download(struct ath10k *ar,
u32 trailer_len = length - head_len;
int ret;
- ath10k_dbg(ATH10K_DBG_BMI,
+ ath10k_dbg(ar, ATH10K_DBG_BMI,
"bmi fast download address 0x%x buffer 0x%p length %d\n",
address, buffer, length);
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 4333107ecf3..71eef233bd0 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -284,13 +284,9 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
int ret = 0;
if (nbytes > ce_state->src_sz_max)
- ath10k_warn("%s: send more we can (nbytes: %d, max: %d)\n",
+ ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n",
__func__, nbytes, ce_state->src_sz_max);
- ret = ath10k_pci_wake(ar);
- if (ret)
- return ret;
-
if (unlikely(CE_RING_DELTA(nentries_mask,
write_index, sw_index - 1) <= 0)) {
ret = -ENOSR;
@@ -325,7 +321,6 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
src_ring->write_index = write_index;
exit:
- ath10k_pci_sleep(ar);
return ret;
}
@@ -390,49 +385,57 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe)
return delta;
}
-int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
- void *per_recv_context,
- u32 buffer)
+
+int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe)
{
- struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
- u32 ctrl_addr = ce_state->ctrl_addr;
- struct ath10k *ar = ce_state->ar;
+ struct ath10k *ar = pipe->ar;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ struct ath10k_ce_ring *dest_ring = pipe->dest_ring;
unsigned int nentries_mask = dest_ring->nentries_mask;
- unsigned int write_index;
- unsigned int sw_index;
- int ret;
+ unsigned int write_index = dest_ring->write_index;
+ unsigned int sw_index = dest_ring->sw_index;
- spin_lock_bh(&ar_pci->ce_lock);
- write_index = dest_ring->write_index;
- sw_index = dest_ring->sw_index;
+ lockdep_assert_held(&ar_pci->ce_lock);
- ret = ath10k_pci_wake(ar);
- if (ret)
- goto out;
+ return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1);
+}
- if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) {
- struct ce_desc *base = dest_ring->base_addr_owner_space;
- struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index);
+int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
+{
+ struct ath10k *ar = pipe->ar;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ struct ath10k_ce_ring *dest_ring = pipe->dest_ring;
+ unsigned int nentries_mask = dest_ring->nentries_mask;
+ unsigned int write_index = dest_ring->write_index;
+ unsigned int sw_index = dest_ring->sw_index;
+ struct ce_desc *base = dest_ring->base_addr_owner_space;
+ struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index);
+ u32 ctrl_addr = pipe->ctrl_addr;
- /* Update destination descriptor */
- desc->addr = __cpu_to_le32(buffer);
- desc->nbytes = 0;
+ lockdep_assert_held(&ar_pci->ce_lock);
- dest_ring->per_transfer_context[write_index] =
- per_recv_context;
+ if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0)
+ return -EIO;
- /* Update Destination Ring Write Index */
- write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
- ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index);
- dest_ring->write_index = write_index;
- ret = 0;
- } else {
- ret = -EIO;
- }
- ath10k_pci_sleep(ar);
+ desc->addr = __cpu_to_le32(paddr);
+ desc->nbytes = 0;
+
+ dest_ring->per_transfer_context[write_index] = ctx;
+ write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
+ ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index);
+ dest_ring->write_index = write_index;
+
+ return 0;
+}
+
+int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
+{
+ struct ath10k *ar = pipe->ar;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ int ret;
-out:
+ spin_lock_bh(&ar_pci->ce_lock);
+ ret = __ath10k_ce_rx_post_buf(pipe, ctx, paddr);
spin_unlock_bh(&ar_pci->ce_lock);
return ret;
@@ -588,7 +591,6 @@ static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
unsigned int sw_index = src_ring->sw_index;
struct ce_desc *sdesc, *sbase;
unsigned int read_index;
- int ret;
if (src_ring->hw_index == sw_index) {
/*
@@ -599,18 +601,12 @@ static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
* value of the HW index has become stale.
*/
- ret = ath10k_pci_wake(ar);
- if (ret)
- return ret;
-
read_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
if (read_index == 0xffffffff)
return -ENODEV;
read_index &= nentries_mask;
src_ring->hw_index = read_index;
-
- ath10k_pci_sleep(ar);
}
read_index = src_ring->hw_index;
@@ -731,11 +727,6 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
u32 ctrl_addr = ce_state->ctrl_addr;
- int ret;
-
- ret = ath10k_pci_wake(ar);
- if (ret)
- return;
spin_lock_bh(&ar_pci->ce_lock);
@@ -760,7 +751,6 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
ath10k_ce_engine_int_status_clear(ar, ctrl_addr, CE_WATERMARK_MASK);
spin_unlock_bh(&ar_pci->ce_lock);
- ath10k_pci_sleep(ar);
}
/*
@@ -771,13 +761,9 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
void ath10k_ce_per_engine_service_any(struct ath10k *ar)
{
- int ce_id, ret;
+ int ce_id;
u32 intr_summary;
- ret = ath10k_pci_wake(ar);
- if (ret)
- return;
-
intr_summary = CE_INTERRUPT_SUMMARY(ar);
for (ce_id = 0; intr_summary && (ce_id < CE_COUNT); ce_id++) {
@@ -789,8 +775,6 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar)
ath10k_ce_per_engine_service(ar, ce_id);
}
-
- ath10k_pci_sleep(ar);
}
/*
@@ -800,16 +784,11 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar)
*
* Called with ce_lock held.
*/
-static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
- int disable_copy_compl_intr)
+static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state)
{
u32 ctrl_addr = ce_state->ctrl_addr;
struct ath10k *ar = ce_state->ar;
- int ret;
-
- ret = ath10k_pci_wake(ar);
- if (ret)
- return;
+ bool disable_copy_compl_intr = ce_state->attr_flags & CE_ATTR_DIS_INTR;
if ((!disable_copy_compl_intr) &&
(ce_state->send_cb || ce_state->recv_cb))
@@ -818,17 +797,11 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
-
- ath10k_pci_sleep(ar);
}
int ath10k_ce_disable_interrupts(struct ath10k *ar)
{
- int ce_id, ret;
-
- ret = ath10k_pci_wake(ar);
- if (ret)
- return ret;
+ int ce_id;
for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
u32 ctrl_addr = ath10k_ce_base_address(ce_id);
@@ -838,34 +811,16 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar)
ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
}
- ath10k_pci_sleep(ar);
-
return 0;
}
-void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
- void (*send_cb)(struct ath10k_ce_pipe *),
- int disable_interrupts)
+void ath10k_ce_enable_interrupts(struct ath10k *ar)
{
- struct ath10k *ar = ce_state->ar;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ int ce_id;
- spin_lock_bh(&ar_pci->ce_lock);
- ce_state->send_cb = send_cb;
- ath10k_ce_per_engine_handler_adjust(ce_state, disable_interrupts);
- spin_unlock_bh(&ar_pci->ce_lock);
-}
-
-void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
- void (*recv_cb)(struct ath10k_ce_pipe *))
-{
- struct ath10k *ar = ce_state->ar;
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- spin_lock_bh(&ar_pci->ce_lock);
- ce_state->recv_cb = recv_cb;
- ath10k_ce_per_engine_handler_adjust(ce_state, 0);
- spin_unlock_bh(&ar_pci->ce_lock);
+ for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
+ ath10k_ce_per_engine_handler_adjust(&ar_pci->ce_states[ce_id]);
}
static int ath10k_ce_init_src_ring(struct ath10k *ar,
@@ -898,7 +853,7 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0);
ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries);
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot init ce src ring id %d entries %d base_addr %p\n",
ce_id, nentries, src_ring->base_addr_owner_space);
@@ -932,7 +887,7 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0);
ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries);
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot ce dest ring id %d entries %d base_addr %p\n",
ce_id, nentries, dest_ring->base_addr_owner_space);
@@ -1067,7 +1022,9 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
* initialized by software/firmware.
*/
int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
- const struct ce_attr *attr)
+ const struct ce_attr *attr,
+ void (*send_cb)(struct ath10k_ce_pipe *),
+ void (*recv_cb)(struct ath10k_ce_pipe *))
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
@@ -1084,39 +1041,37 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
- ret = ath10k_pci_wake(ar);
- if (ret)
- return ret;
-
spin_lock_bh(&ar_pci->ce_lock);
ce_state->ar = ar;
ce_state->id = ce_id;
ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
ce_state->attr_flags = attr->flags;
ce_state->src_sz_max = attr->src_sz_max;
+ if (attr->src_nentries)
+ ce_state->send_cb = send_cb;
+ if (attr->dest_nentries)
+ ce_state->recv_cb = recv_cb;
spin_unlock_bh(&ar_pci->ce_lock);
if (attr->src_nentries) {
ret = ath10k_ce_init_src_ring(ar, ce_id, attr);
if (ret) {
- ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n",
+ ath10k_err(ar, "Failed to initialize CE src ring for ID: %d (%d)\n",
ce_id, ret);
- goto out;
+ return ret;
}
}
if (attr->dest_nentries) {
ret = ath10k_ce_init_dest_ring(ar, ce_id, attr);
if (ret) {
- ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n",
+ ath10k_err(ar, "Failed to initialize CE dest ring for ID: %d (%d)\n",
ce_id, ret);
- goto out;
+ return ret;
}
}
-out:
- ath10k_pci_sleep(ar);
- return ret;
+ return 0;
}
static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id)
@@ -1140,16 +1095,8 @@ static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id)
void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id)
{
- int ret;
-
- ret = ath10k_pci_wake(ar);
- if (ret)
- return;
-
ath10k_ce_deinit_src_ring(ar, ce_id);
ath10k_ce_deinit_dest_ring(ar, ce_id);
-
- ath10k_pci_sleep(ar);
}
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
@@ -1163,7 +1110,7 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr);
if (IS_ERR(ce_state->src_ring)) {
ret = PTR_ERR(ce_state->src_ring);
- ath10k_err("failed to allocate copy engine source ring %d: %d\n",
+ ath10k_err(ar, "failed to allocate copy engine source ring %d: %d\n",
ce_id, ret);
ce_state->src_ring = NULL;
return ret;
@@ -1175,7 +1122,7 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
attr);
if (IS_ERR(ce_state->dest_ring)) {
ret = PTR_ERR(ce_state->dest_ring);
- ath10k_err("failed to allocate copy engine destination ring %d: %d\n",
+ ath10k_err(ar, "failed to allocate copy engine destination ring %d: %d\n",
ce_id, ret);
ce_state->dest_ring = NULL;
return ret;
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index 7a5a36fc59c..82d1f23546b 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -162,30 +162,13 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe);
-void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
- void (*send_cb)(struct ath10k_ce_pipe *),
- int disable_interrupts);
-
int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe);
/*==================Recv=======================*/
-/*
- * Make a buffer available to receive. The buffer must be at least of a
- * minimal size appropriate for this copy engine (src_sz_max attribute).
- * ce - which copy engine to use
- * per_transfer_recv_context - context passed back to caller's recv_cb
- * buffer - address of buffer in CE space
- * Returns 0 on success; otherwise an error status.
- *
- * Implemenation note: Pushes a buffer to Dest ring.
- */
-int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
- void *per_transfer_recv_context,
- u32 buffer);
-
-void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
- void (*recv_cb)(struct ath10k_ce_pipe *));
+int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe);
+int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
+int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
/* recv flags */
/* Data is byte-swapped */
@@ -214,7 +197,9 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
/*==================CE Engine Initialization=======================*/
int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
- const struct ce_attr *attr);
+ const struct ce_attr *attr,
+ void (*send_cb)(struct ath10k_ce_pipe *),
+ void (*recv_cb)(struct ath10k_ce_pipe *));
void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id);
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
const struct ce_attr *attr);
@@ -245,6 +230,7 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,
void ath10k_ce_per_engine_service_any(struct ath10k *ar);
void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
int ath10k_ce_disable_interrupts(struct ath10k *ar);
+void ath10k_ce_enable_interrupts(struct ath10k *ar);
/* ce_attr.flags values */
/* Use NonSnooping PCIe accesses? */
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 93adb8c5896..651a6da8adf 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -53,7 +53,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
static void ath10k_send_suspend_complete(struct ath10k *ar)
{
- ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n");
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n");
complete(&ar->target_suspend);
}
@@ -67,14 +67,14 @@ static int ath10k_init_configure_target(struct ath10k *ar)
ret = ath10k_bmi_write32(ar, hi_app_host_interest,
HTC_PROTOCOL_VERSION);
if (ret) {
- ath10k_err("settings HTC version failed\n");
+ ath10k_err(ar, "settings HTC version failed\n");
return ret;
}
/* set the firmware mode to STA/IBSS/AP */
ret = ath10k_bmi_read32(ar, hi_option_flag, &param_host);
if (ret) {
- ath10k_err("setting firmware mode (1/2) failed\n");
+ ath10k_err(ar, "setting firmware mode (1/2) failed\n");
return ret;
}
@@ -93,14 +93,14 @@ static int ath10k_init_configure_target(struct ath10k *ar)
ret = ath10k_bmi_write32(ar, hi_option_flag, param_host);
if (ret) {
- ath10k_err("setting firmware mode (2/2) failed\n");
+ ath10k_err(ar, "setting firmware mode (2/2) failed\n");
return ret;
}
/* We do all byte-swapping on the host */
ret = ath10k_bmi_write32(ar, hi_be, 0);
if (ret) {
- ath10k_err("setting host CPU BE mode failed\n");
+ ath10k_err(ar, "setting host CPU BE mode failed\n");
return ret;
}
@@ -108,7 +108,7 @@ static int ath10k_init_configure_target(struct ath10k *ar)
ret = ath10k_bmi_write32(ar, hi_fw_swap, 0);
if (ret) {
- ath10k_err("setting FW data/desc swap flags failed\n");
+ ath10k_err(ar, "setting FW data/desc swap flags failed\n");
return ret;
}
@@ -146,11 +146,12 @@ static int ath10k_push_board_ext_data(struct ath10k *ar)
ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr);
if (ret) {
- ath10k_err("could not read board ext data addr (%d)\n", ret);
+ ath10k_err(ar, "could not read board ext data addr (%d)\n",
+ ret);
return ret;
}
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot push board extended data addr 0x%x\n",
board_ext_data_addr);
@@ -158,7 +159,7 @@ static int ath10k_push_board_ext_data(struct ath10k *ar)
return 0;
if (ar->board_len != (board_data_size + board_ext_data_size)) {
- ath10k_err("invalid board (ext) data sizes %zu != %d+%d\n",
+ ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n",
ar->board_len, board_data_size, board_ext_data_size);
return -EINVAL;
}
@@ -167,14 +168,15 @@ static int ath10k_push_board_ext_data(struct ath10k *ar)
ar->board_data + board_data_size,
board_ext_data_size);
if (ret) {
- ath10k_err("could not write board ext data (%d)\n", ret);
+ ath10k_err(ar, "could not write board ext data (%d)\n", ret);
return ret;
}
ret = ath10k_bmi_write32(ar, hi_board_ext_data_config,
(board_ext_data_size << 16) | 1);
if (ret) {
- ath10k_err("could not write board ext data bit (%d)\n", ret);
+ ath10k_err(ar, "could not write board ext data bit (%d)\n",
+ ret);
return ret;
}
@@ -189,13 +191,13 @@ static int ath10k_download_board_data(struct ath10k *ar)
ret = ath10k_push_board_ext_data(ar);
if (ret) {
- ath10k_err("could not push board ext data (%d)\n", ret);
+ ath10k_err(ar, "could not push board ext data (%d)\n", ret);
goto exit;
}
ret = ath10k_bmi_read32(ar, hi_board_data, &address);
if (ret) {
- ath10k_err("could not read board data addr (%d)\n", ret);
+ ath10k_err(ar, "could not read board data addr (%d)\n", ret);
goto exit;
}
@@ -203,13 +205,13 @@ static int ath10k_download_board_data(struct ath10k *ar)
min_t(u32, board_data_size,
ar->board_len));
if (ret) {
- ath10k_err("could not write board data (%d)\n", ret);
+ ath10k_err(ar, "could not write board data (%d)\n", ret);
goto exit;
}
ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1);
if (ret) {
- ath10k_err("could not write board data bit (%d)\n", ret);
+ ath10k_err(ar, "could not write board data bit (%d)\n", ret);
goto exit;
}
@@ -225,30 +227,30 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
/* OTP is optional */
if (!ar->otp_data || !ar->otp_len) {
- ath10k_warn("Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",
+ ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",
ar->otp_data, ar->otp_len);
return 0;
}
- ath10k_dbg(ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
address, ar->otp_len);
ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len);
if (ret) {
- ath10k_err("could not write otp (%d)\n", ret);
+ ath10k_err(ar, "could not write otp (%d)\n", ret);
return ret;
}
ret = ath10k_bmi_execute(ar, address, 0, &result);
if (ret) {
- ath10k_err("could not execute otp (%d)\n", ret);
+ ath10k_err(ar, "could not execute otp (%d)\n", ret);
return ret;
}
- ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
if (result != 0) {
- ath10k_err("otp calibration failed: %d", result);
+ ath10k_err(ar, "otp calibration failed: %d", result);
return -EINVAL;
}
@@ -265,7 +267,7 @@ static int ath10k_download_fw(struct ath10k *ar)
ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data,
ar->firmware_len);
if (ret) {
- ath10k_err("could not write fw (%d)\n", ret);
+ ath10k_err(ar, "could not write fw (%d)\n", ret);
goto exit;
}
@@ -302,12 +304,12 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
int ret = 0;
if (ar->hw_params.fw.fw == NULL) {
- ath10k_err("firmware file not defined\n");
+ ath10k_err(ar, "firmware file not defined\n");
return -EINVAL;
}
if (ar->hw_params.fw.board == NULL) {
- ath10k_err("board data file not defined");
+ ath10k_err(ar, "board data file not defined");
return -EINVAL;
}
@@ -316,7 +318,7 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
ar->hw_params.fw.board);
if (IS_ERR(ar->board)) {
ret = PTR_ERR(ar->board);
- ath10k_err("could not fetch board data (%d)\n", ret);
+ ath10k_err(ar, "could not fetch board data (%d)\n", ret);
goto err;
}
@@ -328,7 +330,7 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
ar->hw_params.fw.fw);
if (IS_ERR(ar->firmware)) {
ret = PTR_ERR(ar->firmware);
- ath10k_err("could not fetch firmware (%d)\n", ret);
+ ath10k_err(ar, "could not fetch firmware (%d)\n", ret);
goto err;
}
@@ -344,7 +346,7 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
ar->hw_params.fw.otp);
if (IS_ERR(ar->otp)) {
ret = PTR_ERR(ar->otp);
- ath10k_err("could not fetch otp (%d)\n", ret);
+ ath10k_err(ar, "could not fetch otp (%d)\n", ret);
goto err;
}
@@ -369,7 +371,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
/* first fetch the firmware file (firmware-*.bin) */
ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name);
if (IS_ERR(ar->firmware)) {
- ath10k_err("could not fetch firmware file '%s/%s': %ld\n",
+ ath10k_err(ar, "could not fetch firmware file '%s/%s': %ld\n",
ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware));
return PTR_ERR(ar->firmware);
}
@@ -381,14 +383,14 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
if (len < magic_len) {
- ath10k_err("firmware file '%s/%s' too small to contain magic: %zu\n",
+ ath10k_err(ar, "firmware file '%s/%s' too small to contain magic: %zu\n",
ar->hw_params.fw.dir, name, len);
ret = -EINVAL;
goto err;
}
if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
- ath10k_err("invalid firmware magic\n");
+ ath10k_err(ar, "invalid firmware magic\n");
ret = -EINVAL;
goto err;
}
@@ -410,7 +412,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
data += sizeof(*hdr);
if (len < ie_len) {
- ath10k_err("invalid length for FW IE %d (%zu < %zu)\n",
+ ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n",
ie_id, len, ie_len);
ret = -EINVAL;
goto err;
@@ -424,7 +426,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
memcpy(ar->hw->wiphy->fw_version, data, ie_len);
ar->hw->wiphy->fw_version[ie_len] = '\0';
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"found fw version %s\n",
ar->hw->wiphy->fw_version);
break;
@@ -434,11 +436,11 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
timestamp = (__le32 *)data;
- ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw timestamp %d\n",
le32_to_cpup(timestamp));
break;
case ATH10K_FW_IE_FEATURES:
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"found firmware features ie (%zd B)\n",
ie_len);
@@ -450,19 +452,19 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
break;
if (data[index] & (1 << bit)) {
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"Enabling feature bit: %i\n",
i);
__set_bit(i, ar->fw_features);
}
}
- ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "",
+ ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "features", "",
ar->fw_features,
sizeof(ar->fw_features));
break;
case ATH10K_FW_IE_FW_IMAGE:
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"found fw image ie (%zd B)\n",
ie_len);
@@ -471,7 +473,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
break;
case ATH10K_FW_IE_OTP_IMAGE:
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"found otp image ie (%zd B)\n",
ie_len);
@@ -480,7 +482,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
break;
default:
- ath10k_warn("Unknown FW IE: %u\n",
+ ath10k_warn(ar, "Unknown FW IE: %u\n",
le32_to_cpu(hdr->id));
break;
}
@@ -493,15 +495,22 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
}
if (!ar->firmware_data || !ar->firmware_len) {
- ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
+ ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
ar->hw_params.fw.dir, name);
ret = -ENOMEDIUM;
goto err;
}
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) &&
+ !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well");
+ ret = -EINVAL;
+ goto err;
+ }
+
/* now fetch the board file */
if (ar->hw_params.fw.board == NULL) {
- ath10k_err("board data file not defined");
+ ath10k_err(ar, "board data file not defined");
ret = -EINVAL;
goto err;
}
@@ -511,7 +520,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
ar->hw_params.fw.board);
if (IS_ERR(ar->board)) {
ret = PTR_ERR(ar->board);
- ath10k_err("could not fetch board data '%s/%s' (%d)\n",
+ 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;
@@ -531,22 +540,29 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
{
int ret;
+ ar->fw_api = 3;
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+
+ ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE);
+ if (ret == 0)
+ goto success;
+
ar->fw_api = 2;
- ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE);
if (ret == 0)
goto success;
ar->fw_api = 1;
- ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
ret = ath10k_core_fetch_firmware_api_1(ar);
if (ret)
return ret;
success:
- ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
return 0;
}
@@ -557,19 +573,19 @@ static int ath10k_init_download_firmware(struct ath10k *ar)
ret = ath10k_download_board_data(ar);
if (ret) {
- ath10k_err("failed to download board data: %d\n", ret);
+ ath10k_err(ar, "failed to download board data: %d\n", ret);
return ret;
}
ret = ath10k_download_and_run_otp(ar);
if (ret) {
- ath10k_err("failed to run otp: %d\n", ret);
+ ath10k_err(ar, "failed to run otp: %d\n", ret);
return ret;
}
ret = ath10k_download_fw(ar);
if (ret) {
- ath10k_err("failed to download firmware: %d\n", ret);
+ ath10k_err(ar, "failed to download firmware: %d\n", ret);
return ret;
}
@@ -586,7 +602,7 @@ static int ath10k_init_uart(struct ath10k *ar)
*/
ret = ath10k_bmi_write32(ar, hi_serial_enable, 0);
if (ret) {
- ath10k_warn("could not disable UART prints (%d)\n", ret);
+ ath10k_warn(ar, "could not disable UART prints (%d)\n", ret);
return ret;
}
@@ -595,24 +611,24 @@ static int ath10k_init_uart(struct ath10k *ar)
ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7);
if (ret) {
- ath10k_warn("could not enable UART prints (%d)\n", ret);
+ ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);
return ret;
}
ret = ath10k_bmi_write32(ar, hi_serial_enable, 1);
if (ret) {
- ath10k_warn("could not enable UART prints (%d)\n", ret);
+ ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);
return ret;
}
/* Set the UART baud rate to 19200. */
ret = ath10k_bmi_write32(ar, hi_desired_baud_rate, 19200);
if (ret) {
- ath10k_warn("could not set the baud rate (%d)\n", ret);
+ ath10k_warn(ar, "could not set the baud rate (%d)\n", ret);
return ret;
}
- ath10k_info("UART prints enabled\n");
+ ath10k_info(ar, "UART prints enabled\n");
return 0;
}
@@ -629,14 +645,14 @@ static int ath10k_init_hw_params(struct ath10k *ar)
}
if (i == ARRAY_SIZE(ath10k_hw_params_list)) {
- ath10k_err("Unsupported hardware version: 0x%x\n",
+ ath10k_err(ar, "Unsupported hardware version: 0x%x\n",
ar->target_version);
return -EINVAL;
}
ar->hw_params = *hw_params;
- ath10k_dbg(ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",
ar->hw_params.name, ar->target_version);
return 0;
@@ -651,14 +667,14 @@ static void ath10k_core_restart(struct work_struct *work)
switch (ar->state) {
case ATH10K_STATE_ON:
ar->state = ATH10K_STATE_RESTARTING;
- del_timer_sync(&ar->scan.timeout);
- ath10k_reset_scan((unsigned long)ar);
+ ath10k_hif_stop(ar);
+ ath10k_scan_finish(ar);
ieee80211_restart_hw(ar->hw);
break;
case ATH10K_STATE_OFF:
/* this can happen if driver is being unloaded
* or if the crash happens during FW probing */
- ath10k_warn("cannot restart a device that hasn't been started\n");
+ ath10k_warn(ar, "cannot restart a device that hasn't been started\n");
break;
case ATH10K_STATE_RESTARTING:
/* hw restart might be requested from multiple places */
@@ -667,7 +683,7 @@ static void ath10k_core_restart(struct work_struct *work)
ar->state = ATH10K_STATE_WEDGED;
/* fall through */
case ATH10K_STATE_WEDGED:
- ath10k_warn("device is wedged, will not restart\n");
+ ath10k_warn(ar, "device is wedged, will not restart\n");
break;
}
@@ -700,7 +716,7 @@ int ath10k_core_start(struct ath10k *ar)
status = ath10k_htc_init(ar);
if (status) {
- ath10k_err("could not init HTC (%d)\n", status);
+ ath10k_err(ar, "could not init HTC (%d)\n", status);
goto err;
}
@@ -710,90 +726,91 @@ int ath10k_core_start(struct ath10k *ar)
status = ath10k_wmi_attach(ar);
if (status) {
- ath10k_err("WMI attach failed: %d\n", status);
+ ath10k_err(ar, "WMI attach failed: %d\n", status);
goto err;
}
status = ath10k_htt_init(ar);
if (status) {
- ath10k_err("failed to init htt: %d\n", status);
+ ath10k_err(ar, "failed to init htt: %d\n", status);
goto err_wmi_detach;
}
status = ath10k_htt_tx_alloc(&ar->htt);
if (status) {
- ath10k_err("failed to alloc htt tx: %d\n", status);
+ ath10k_err(ar, "failed to alloc htt tx: %d\n", status);
goto err_wmi_detach;
}
status = ath10k_htt_rx_alloc(&ar->htt);
if (status) {
- ath10k_err("failed to alloc htt rx: %d\n", status);
+ ath10k_err(ar, "failed to alloc htt rx: %d\n", status);
goto err_htt_tx_detach;
}
status = ath10k_hif_start(ar);
if (status) {
- ath10k_err("could not start HIF: %d\n", status);
+ ath10k_err(ar, "could not start HIF: %d\n", status);
goto err_htt_rx_detach;
}
status = ath10k_htc_wait_target(&ar->htc);
if (status) {
- ath10k_err("failed to connect to HTC: %d\n", status);
+ ath10k_err(ar, "failed to connect to HTC: %d\n", status);
goto err_hif_stop;
}
status = ath10k_htt_connect(&ar->htt);
if (status) {
- ath10k_err("failed to connect htt (%d)\n", status);
+ ath10k_err(ar, "failed to connect htt (%d)\n", status);
goto err_hif_stop;
}
status = ath10k_wmi_connect(ar);
if (status) {
- ath10k_err("could not connect wmi: %d\n", status);
+ ath10k_err(ar, "could not connect wmi: %d\n", status);
goto err_hif_stop;
}
status = ath10k_htc_start(&ar->htc);
if (status) {
- ath10k_err("failed to start htc: %d\n", status);
+ ath10k_err(ar, "failed to start htc: %d\n", status);
goto err_hif_stop;
}
status = ath10k_wmi_wait_for_service_ready(ar);
if (status <= 0) {
- ath10k_warn("wmi service ready event not received");
+ ath10k_warn(ar, "wmi service ready event not received");
status = -ETIMEDOUT;
- goto err_htc_stop;
+ goto err_hif_stop;
}
- ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n",
ar->hw->wiphy->fw_version);
status = ath10k_wmi_cmd_init(ar);
if (status) {
- ath10k_err("could not send WMI init command (%d)\n", status);
- goto err_htc_stop;
+ ath10k_err(ar, "could not send WMI init command (%d)\n",
+ status);
+ goto err_hif_stop;
}
status = ath10k_wmi_wait_for_unified_ready(ar);
if (status <= 0) {
- ath10k_err("wmi unified ready event not received\n");
+ ath10k_err(ar, "wmi unified ready event not received\n");
status = -ETIMEDOUT;
- goto err_htc_stop;
+ goto err_hif_stop;
}
status = ath10k_htt_setup(&ar->htt);
if (status) {
- ath10k_err("failed to setup htt: %d\n", status);
- goto err_htc_stop;
+ ath10k_err(ar, "failed to setup htt: %d\n", status);
+ goto err_hif_stop;
}
status = ath10k_debug_start(ar);
if (status)
- goto err_htc_stop;
+ goto err_hif_stop;
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
ar->free_vdev_map = (1 << TARGET_10X_NUM_VDEVS) - 1;
@@ -802,28 +819,8 @@ int ath10k_core_start(struct ath10k *ar)
INIT_LIST_HEAD(&ar->arvifs);
- if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) {
- ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
- ar->hw_params.name,
- ar->target_version,
- ar->chip_id,
- ar->hw->wiphy->fw_version,
- ar->fw_api,
- ar->htt.target_version_major,
- ar->htt.target_version_minor);
- ath10k_info("debug %d debugfs %d tracing %d dfs %d\n",
- config_enabled(CONFIG_ATH10K_DEBUG),
- config_enabled(CONFIG_ATH10K_DEBUGFS),
- config_enabled(CONFIG_ATH10K_TRACING),
- config_enabled(CONFIG_ATH10K_DFS_CERTIFIED));
- }
-
- __set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags);
-
return 0;
-err_htc_stop:
- ath10k_htc_stop(&ar->htc);
err_hif_stop:
ath10k_hif_stop(ar);
err_htt_rx_detach:
@@ -845,14 +842,14 @@ int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)
ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt);
if (ret) {
- ath10k_warn("could not suspend target (%d)\n", ret);
+ ath10k_warn(ar, "could not suspend target (%d)\n", ret);
return ret;
}
ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
if (ret == 0) {
- ath10k_warn("suspend timed out - target pause event never came\n");
+ ath10k_warn(ar, "suspend timed out - target pause event never came\n");
return -ETIMEDOUT;
}
@@ -868,7 +865,6 @@ void ath10k_core_stop(struct ath10k *ar)
ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
ath10k_debug_stop(ar);
- ath10k_htc_stop(&ar->htc);
ath10k_hif_stop(ar);
ath10k_htt_tx_free(&ar->htt);
ath10k_htt_rx_free(&ar->htt);
@@ -887,14 +883,14 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ret = ath10k_hif_power_up(ar);
if (ret) {
- ath10k_err("could not start pci hif (%d)\n", ret);
+ ath10k_err(ar, "could not start pci hif (%d)\n", ret);
return ret;
}
memset(&target_info, 0, sizeof(target_info));
ret = ath10k_bmi_get_target_info(ar, &target_info);
if (ret) {
- ath10k_err("could not get target info (%d)\n", ret);
+ ath10k_err(ar, "could not get target info (%d)\n", ret);
ath10k_hif_power_down(ar);
return ret;
}
@@ -904,14 +900,14 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ret = ath10k_init_hw_params(ar);
if (ret) {
- ath10k_err("could not get hw params (%d)\n", ret);
+ ath10k_err(ar, "could not get hw params (%d)\n", ret);
ath10k_hif_power_down(ar);
return ret;
}
ret = ath10k_core_fetch_firmware_files(ar);
if (ret) {
- ath10k_err("could not fetch firmware files (%d)\n", ret);
+ ath10k_err(ar, "could not fetch firmware files (%d)\n", ret);
ath10k_hif_power_down(ar);
return ret;
}
@@ -920,13 +916,14 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ret = ath10k_core_start(ar);
if (ret) {
- ath10k_err("could not init core (%d)\n", ret);
+ ath10k_err(ar, "could not init core (%d)\n", ret);
ath10k_core_free_firmware_files(ar);
ath10k_hif_power_down(ar);
mutex_unlock(&ar->conf_mutex);
return ret;
}
+ ath10k_print_driver_info(ar);
ath10k_core_stop(ar);
mutex_unlock(&ar->conf_mutex);
@@ -939,7 +936,7 @@ static int ath10k_core_check_chip_id(struct ath10k *ar)
{
u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
ar->chip_id, hw_revision);
/* Check that we are not using hw1.0 (some of them have same pci id
@@ -947,7 +944,7 @@ static int ath10k_core_check_chip_id(struct ath10k *ar)
* due to missing hw1.0 workarounds. */
switch (hw_revision) {
case QCA988X_HW_1_0_CHIP_ID_REV:
- ath10k_err("ERROR: qca988x hw1.0 is not supported\n");
+ ath10k_err(ar, "ERROR: qca988x hw1.0 is not supported\n");
return -EOPNOTSUPP;
case QCA988X_HW_2_0_CHIP_ID_REV:
@@ -955,7 +952,7 @@ static int ath10k_core_check_chip_id(struct ath10k *ar)
return 0;
default:
- ath10k_warn("Warning: hardware revision unknown (0x%x), expect problems\n",
+ ath10k_warn(ar, "Warning: hardware revision unknown (0x%x), expect problems\n",
ar->chip_id);
return 0;
}
@@ -970,25 +967,33 @@ static void ath10k_core_register_work(struct work_struct *work)
status = ath10k_core_probe_fw(ar);
if (status) {
- ath10k_err("could not probe fw (%d)\n", status);
+ ath10k_err(ar, "could not probe fw (%d)\n", status);
goto err;
}
status = ath10k_mac_register(ar);
if (status) {
- ath10k_err("could not register to mac80211 (%d)\n", status);
+ ath10k_err(ar, "could not register to mac80211 (%d)\n", status);
goto err_release_fw;
}
status = ath10k_debug_create(ar);
if (status) {
- ath10k_err("unable to initialize debugfs\n");
+ ath10k_err(ar, "unable to initialize debugfs\n");
goto err_unregister_mac;
}
+ status = ath10k_spectral_create(ar);
+ if (status) {
+ ath10k_err(ar, "failed to initialize spectral\n");
+ goto err_debug_destroy;
+ }
+
set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags);
return;
+err_debug_destroy:
+ ath10k_debug_destroy(ar);
err_unregister_mac:
ath10k_mac_unregister(ar);
err_release_fw:
@@ -1008,7 +1013,7 @@ int ath10k_core_register(struct ath10k *ar, u32 chip_id)
status = ath10k_core_check_chip_id(ar);
if (status) {
- ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id);
+ ath10k_err(ar, "Unsupported chip id 0x%08x\n", ar->chip_id);
return status;
}
@@ -1025,6 +1030,12 @@ void ath10k_core_unregister(struct ath10k *ar)
if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
return;
+ /* Stop spectral before unregistering from mac80211 to remove the
+ * relayfs debugfs file cleanly. Otherwise the parent debugfs tree
+ * would be already be free'd recursively, leading to a double free.
+ */
+ ath10k_spectral_destroy(ar);
+
/* We must unregister from mac80211 before we stop HTC and HIF.
* Otherwise we will fail to submit commands to FW and mac80211 will be
* unhappy about callback failures. */
@@ -1036,12 +1047,12 @@ void ath10k_core_unregister(struct ath10k *ar)
}
EXPORT_SYMBOL(ath10k_core_unregister);
-struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
+struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
const struct ath10k_hif_ops *hif_ops)
{
struct ath10k *ar;
- ar = ath10k_mac_create();
+ ar = ath10k_mac_create(priv_size);
if (!ar)
return NULL;
@@ -1051,7 +1062,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
ar->p2p = !!ath10k_p2p;
ar->dev = dev;
- ar->hif.priv = hif_priv;
ar->hif.ops = hif_ops;
init_completion(&ar->scan.started);
@@ -1062,7 +1072,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
init_completion(&ar->install_key_done);
init_completion(&ar->vdev_setup_done);
- setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar);
+ INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
ar->workqueue = create_singlethread_workqueue("ath10k_wq");
if (!ar->workqueue)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 83a5fa91531..4ef47609922 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -22,6 +22,8 @@
#include <linux/if_ether.h>
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/uuid.h>
+#include <linux/time.h>
#include "htt.h"
#include "htc.h"
@@ -31,6 +33,7 @@
#include "../ath.h"
#include "../regd.h"
#include "../dfs_pattern_detector.h"
+#include "spectral.h"
#define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -237,6 +240,7 @@ struct ath10k_vif {
bool is_started;
bool is_up;
+ bool spectral_enabled;
u32 aid;
u8 bssid[ETH_ALEN];
@@ -276,11 +280,20 @@ struct ath10k_vif_iter {
struct ath10k_vif *arvif;
};
+/* used for crash-dump storage, protected by data-lock */
+struct ath10k_fw_crash_data {
+ bool crashed_since_read;
+
+ uuid_le uuid;
+ struct timespec timestamp;
+ __le32 registers[REG_DUMP_COUNT_QCA988X];
+};
+
struct ath10k_debug {
struct dentry *debugfs_phy;
struct ath10k_target_stats target_stats;
- u32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE];
+ DECLARE_BITMAP(wmi_service_bitmap, WMI_SERVICE_BM_SIZE);
struct completion event_stats_compl;
@@ -293,6 +306,8 @@ struct ath10k_debug {
u8 htt_max_amsdu;
u8 htt_max_ampdu;
+
+ struct ath10k_fw_crash_data *fw_crash_data;
};
enum ath10k_state {
@@ -330,6 +345,11 @@ enum ath10k_fw_features {
/* Firmware does not support P2P */
ATH10K_FW_FEATURE_NO_P2P = 3,
+ /* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature bit
+ * is required to be set as well.
+ */
+ ATH10K_FW_FEATURE_WMI_10_2 = 4,
+
/* keep last */
ATH10K_FW_FEATURE_COUNT,
};
@@ -337,10 +357,32 @@ enum ath10k_fw_features {
enum ath10k_dev_flags {
/* Indicates that ath10k device is during CAC phase of DFS */
ATH10K_CAC_RUNNING,
- ATH10K_FLAG_FIRST_BOOT_DONE,
ATH10K_FLAG_CORE_REGISTERED,
};
+enum ath10k_scan_state {
+ ATH10K_SCAN_IDLE,
+ ATH10K_SCAN_STARTING,
+ ATH10K_SCAN_RUNNING,
+ ATH10K_SCAN_ABORTING,
+};
+
+static inline const char *ath10k_scan_state_str(enum ath10k_scan_state state)
+{
+ switch (state) {
+ case ATH10K_SCAN_IDLE:
+ return "idle";
+ case ATH10K_SCAN_STARTING:
+ return "starting";
+ case ATH10K_SCAN_RUNNING:
+ return "running";
+ case ATH10K_SCAN_ABORTING:
+ return "aborting";
+ }
+
+ return "unknown";
+}
+
struct ath10k {
struct ath_common ath_common;
struct ieee80211_hw *hw;
@@ -368,7 +410,6 @@ struct ath10k {
bool p2p;
struct {
- void *priv;
const struct ath10k_hif_ops *ops;
} hif;
@@ -410,10 +451,9 @@ struct ath10k {
struct completion started;
struct completion completed;
struct completion on_channel;
- struct timer_list timeout;
+ struct delayed_work timeout;
+ enum ath10k_scan_state state;
bool is_roc;
- bool in_progress;
- bool aborting;
int vdev_id;
int roc_freq;
} scan;
@@ -494,9 +534,21 @@ struct ath10k {
#ifdef CONFIG_ATH10K_DEBUGFS
struct ath10k_debug debug;
#endif
+
+ struct {
+ /* relay(fs) channel for spectral scan */
+ struct rchan *rfs_chan_spec_scan;
+
+ /* spectral_mode and spec_config are protected by conf_mutex */
+ enum ath10k_spectral_mode mode;
+ struct ath10k_spec_scan config;
+ } spectral;
+
+ /* must be last */
+ u8 drv_priv[0] __aligned(sizeof(void *));
};
-struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
+struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
const struct ath10k_hif_ops *hif_ops);
void ath10k_core_destroy(struct ath10k *ar);
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 3030158c478..f3f0a80f8ba 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -17,6 +17,9 @@
#include <linux/module.h>
#include <linux/debugfs.h>
+#include <linux/version.h>
+#include <linux/vermagic.h>
+#include <linux/vmalloc.h>
#include "core.h"
#include "debug.h"
@@ -24,25 +27,86 @@
/* ms */
#define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
-static int ath10k_printk(const char *level, const char *fmt, ...)
-{
- struct va_format vaf;
- va_list args;
- int rtn;
+#define ATH10K_FW_CRASH_DUMP_VERSION 1
- va_start(args, fmt);
+/**
+ * enum ath10k_fw_crash_dump_type - types of data in the dump file
+ * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
+ */
+enum ath10k_fw_crash_dump_type {
+ ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
- vaf.fmt = fmt;
- vaf.va = &args;
+ ATH10K_FW_CRASH_DUMP_MAX,
+};
- rtn = printk("%sath10k: %pV", level, &vaf);
+struct ath10k_tlv_dump_data {
+ /* see ath10k_fw_crash_dump_type above */
+ __le32 type;
- va_end(args);
+ /* in bytes */
+ __le32 tlv_len;
- return rtn;
-}
+ /* pad to 32-bit boundaries as needed */
+ u8 tlv_data[];
+} __packed;
+
+struct ath10k_dump_file_data {
+ /* dump file information */
+
+ /* "ATH10K-FW-DUMP" */
+ char df_magic[16];
+
+ __le32 len;
+
+ /* file dump version */
+ __le32 version;
+
+ /* some info we can get from ath10k struct that might help */
+
+ u8 uuid[16];
+
+ __le32 chip_id;
+
+ /* 0 for now, in place for later hardware */
+ __le32 bus_type;
+
+ __le32 target_version;
+ __le32 fw_version_major;
+ __le32 fw_version_minor;
+ __le32 fw_version_release;
+ __le32 fw_version_build;
+ __le32 phy_capability;
+ __le32 hw_min_tx_power;
+ __le32 hw_max_tx_power;
+ __le32 ht_cap_info;
+ __le32 vht_cap_info;
+ __le32 num_rf_chains;
+
+ /* firmware version string */
+ char fw_ver[ETHTOOL_FWVERS_LEN];
+
+ /* Kernel related information */
+
+ /* time-of-day stamp */
+ __le64 tv_sec;
-int ath10k_info(const char *fmt, ...)
+ /* time-of-day stamp, nano-seconds */
+ __le64 tv_nsec;
+
+ /* LINUX_VERSION_CODE */
+ __le32 kernel_ver_code;
+
+ /* VERMAGIC_STRING */
+ char kernel_ver[64];
+
+ /* room for growth w/out changing binary format */
+ u8 unused[128];
+
+ /* struct ath10k_tlv_dump_data + more */
+ u8 data[0];
+} __packed;
+
+int ath10k_info(struct ath10k *ar, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
@@ -52,7 +116,7 @@ int ath10k_info(const char *fmt, ...)
va_start(args, fmt);
vaf.va = &args;
- ret = ath10k_printk(KERN_INFO, "%pV", &vaf);
+ ret = dev_info(ar->dev, "%pV", &vaf);
trace_ath10k_log_info(&vaf);
va_end(args);
@@ -60,7 +124,25 @@ int ath10k_info(const char *fmt, ...)
}
EXPORT_SYMBOL(ath10k_info);
-int ath10k_err(const char *fmt, ...)
+void ath10k_print_driver_info(struct ath10k *ar)
+{
+ ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
+ ar->hw_params.name,
+ ar->target_version,
+ ar->chip_id,
+ ar->hw->wiphy->fw_version,
+ ar->fw_api,
+ ar->htt.target_version_major,
+ ar->htt.target_version_minor);
+ ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d\n",
+ config_enabled(CONFIG_ATH10K_DEBUG),
+ config_enabled(CONFIG_ATH10K_DEBUGFS),
+ config_enabled(CONFIG_ATH10K_TRACING),
+ config_enabled(CONFIG_ATH10K_DFS_CERTIFIED));
+}
+EXPORT_SYMBOL(ath10k_print_driver_info);
+
+int ath10k_err(struct ath10k *ar, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
@@ -70,7 +152,7 @@ int ath10k_err(const char *fmt, ...)
va_start(args, fmt);
vaf.va = &args;
- ret = ath10k_printk(KERN_ERR, "%pV", &vaf);
+ ret = dev_err(ar->dev, "%pV", &vaf);
trace_ath10k_log_err(&vaf);
va_end(args);
@@ -78,25 +160,21 @@ int ath10k_err(const char *fmt, ...)
}
EXPORT_SYMBOL(ath10k_err);
-int ath10k_warn(const char *fmt, ...)
+int ath10k_warn(struct ath10k *ar, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
- int ret = 0;
va_start(args, fmt);
vaf.va = &args;
-
- if (net_ratelimit())
- ret = ath10k_printk(KERN_WARNING, "%pV", &vaf);
-
+ dev_warn_ratelimited(ar->dev, "%pV", &vaf);
trace_ath10k_log_warn(&vaf);
va_end(args);
- return ret;
+ return 0;
}
EXPORT_SYMBOL(ath10k_warn);
@@ -115,9 +193,10 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
{
struct ath10k *ar = file->private_data;
char *buf;
- unsigned int len = 0, buf_len = 1500;
- const char *status;
+ unsigned int len = 0, buf_len = 4096;
+ const char *name;
ssize_t ret_cnt;
+ bool enabled;
int i;
buf = kzalloc(buf_len, GFP_KERNEL);
@@ -129,15 +208,22 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
if (len > buf_len)
len = buf_len;
- for (i = 0; i < WMI_SERVICE_LAST; i++) {
- if (WMI_SERVICE_IS_ENABLED(ar->debug.wmi_service_bitmap, i))
- status = "enabled";
- else
- status = "disabled";
+ for (i = 0; i < WMI_MAX_SERVICE; i++) {
+ enabled = test_bit(i, ar->debug.wmi_service_bitmap);
+ name = wmi_service_name(i);
+
+ if (!name) {
+ if (enabled)
+ len += scnprintf(buf + len, buf_len - len,
+ "%-40s %s (bit %d)\n",
+ "unknown", "enabled", i);
+
+ continue;
+ }
len += scnprintf(buf + len, buf_len - len,
- "0x%02x - %20s - %s\n",
- i, wmi_service_name(i), status);
+ "%-40s %s\n",
+ name, enabled ? "enabled" : "-");
}
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
@@ -309,7 +395,7 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
if (ret) {
- ath10k_warn("could not request stats (%d)\n", ret);
+ ath10k_warn(ar, "could not request stats (%d)\n", ret);
goto exit;
}
@@ -527,11 +613,14 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
}
if (!strcmp(buf, "soft")) {
- ath10k_info("simulating soft firmware crash\n");
+ ath10k_info(ar, "simulating soft firmware crash\n");
ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
} else if (!strcmp(buf, "hard")) {
- ath10k_info("simulating hard firmware crash\n");
- ret = ath10k_wmi_vdev_set_param(ar, TARGET_NUM_VDEVS + 1,
+ ath10k_info(ar, "simulating hard firmware crash\n");
+ /* 0x7fff is vdev id, and it is always out of range for all
+ * firmware variants in order to force a firmware crash.
+ */
+ ret = ath10k_wmi_vdev_set_param(ar, 0x7fff,
ar->wmi.vdev_param->rts_threshold, 0);
} else {
ret = -EINVAL;
@@ -539,7 +628,7 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
}
if (ret) {
- ath10k_warn("failed to simulate firmware crash: %d\n", ret);
+ ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret);
goto exit;
}
@@ -577,6 +666,138 @@ static const struct file_operations fops_chip_id = {
.llseek = default_llseek,
};
+struct ath10k_fw_crash_data *
+ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
+{
+ struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ crash_data->crashed_since_read = true;
+ uuid_le_gen(&crash_data->uuid);
+ getnstimeofday(&crash_data->timestamp);
+
+ return crash_data;
+}
+EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data);
+
+static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
+{
+ struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
+ struct ath10k_dump_file_data *dump_data;
+ struct ath10k_tlv_dump_data *dump_tlv;
+ int hdr_len = sizeof(*dump_data);
+ unsigned int len, sofar = 0;
+ unsigned char *buf;
+
+ len = hdr_len;
+ len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
+
+ sofar += hdr_len;
+
+ /* This is going to get big when we start dumping FW RAM and such,
+ * so go ahead and use vmalloc.
+ */
+ buf = vzalloc(len);
+ if (!buf)
+ return NULL;
+
+ spin_lock_bh(&ar->data_lock);
+
+ if (!crash_data->crashed_since_read) {
+ spin_unlock_bh(&ar->data_lock);
+ vfree(buf);
+ return NULL;
+ }
+
+ dump_data = (struct ath10k_dump_file_data *)(buf);
+ strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP",
+ sizeof(dump_data->df_magic));
+ dump_data->len = cpu_to_le32(len);
+
+ dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION);
+
+ memcpy(dump_data->uuid, &crash_data->uuid, sizeof(dump_data->uuid));
+ dump_data->chip_id = cpu_to_le32(ar->chip_id);
+ dump_data->bus_type = cpu_to_le32(0);
+ dump_data->target_version = cpu_to_le32(ar->target_version);
+ dump_data->fw_version_major = cpu_to_le32(ar->fw_version_major);
+ dump_data->fw_version_minor = cpu_to_le32(ar->fw_version_minor);
+ dump_data->fw_version_release = cpu_to_le32(ar->fw_version_release);
+ dump_data->fw_version_build = cpu_to_le32(ar->fw_version_build);
+ dump_data->phy_capability = cpu_to_le32(ar->phy_capability);
+ dump_data->hw_min_tx_power = cpu_to_le32(ar->hw_min_tx_power);
+ dump_data->hw_max_tx_power = cpu_to_le32(ar->hw_max_tx_power);
+ dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info);
+ dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info);
+ dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);
+
+ strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
+ sizeof(dump_data->fw_ver));
+
+ dump_data->kernel_ver_code = cpu_to_le32(LINUX_VERSION_CODE);
+ strlcpy(dump_data->kernel_ver, VERMAGIC_STRING,
+ sizeof(dump_data->kernel_ver));
+
+ dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec);
+ dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec);
+
+ /* Gather crash-dump */
+ dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+ dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS);
+ dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers));
+ memcpy(dump_tlv->tlv_data, &crash_data->registers,
+ sizeof(crash_data->registers));
+ sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers);
+
+ ar->debug.fw_crash_data->crashed_since_read = false;
+
+ spin_unlock_bh(&ar->data_lock);
+
+ return dump_data;
+}
+
+static int ath10k_fw_crash_dump_open(struct inode *inode, struct file *file)
+{
+ struct ath10k *ar = inode->i_private;
+ struct ath10k_dump_file_data *dump;
+
+ dump = ath10k_build_dump_file(ar);
+ if (!dump)
+ return -ENODATA;
+
+ file->private_data = dump;
+
+ return 0;
+}
+
+static ssize_t ath10k_fw_crash_dump_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k_dump_file_data *dump_file = file->private_data;
+
+ return simple_read_from_buffer(user_buf, count, ppos,
+ dump_file,
+ le32_to_cpu(dump_file->len));
+}
+
+static int ath10k_fw_crash_dump_release(struct inode *inode,
+ struct file *file)
+{
+ vfree(file->private_data);
+
+ return 0;
+}
+
+static const struct file_operations fops_fw_crash_dump = {
+ .open = ath10k_fw_crash_dump_open,
+ .read = ath10k_fw_crash_dump_read,
+ .release = ath10k_fw_crash_dump_release,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static int ath10k_debug_htt_stats_req(struct ath10k *ar)
{
u64 cookie;
@@ -596,7 +817,7 @@ static int ath10k_debug_htt_stats_req(struct ath10k *ar)
ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask,
cookie);
if (ret) {
- ath10k_warn("failed to send htt stats request: %d\n", ret);
+ ath10k_warn(ar, "failed to send htt stats request: %d\n", ret);
return ret;
}
@@ -770,7 +991,7 @@ static ssize_t ath10k_write_fw_dbglog(struct file *file,
if (ar->state == ATH10K_STATE_ON) {
ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
if (ret) {
- ath10k_warn("dbglog cfg failed from debugfs: %d\n",
+ ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n",
ret);
goto exit;
}
@@ -801,13 +1022,14 @@ int ath10k_debug_start(struct ath10k *ar)
ret = ath10k_debug_htt_stats_req(ar);
if (ret)
/* continue normally anyway, this isn't serious */
- ath10k_warn("failed to start htt stats workqueue: %d\n", ret);
+ ath10k_warn(ar, "failed to start htt stats workqueue: %d\n",
+ ret);
if (ar->debug.fw_dbglog_mask) {
ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
if (ret)
/* not serious */
- ath10k_warn("failed to enable dbglog during start: %d",
+ ath10k_warn(ar, "failed to enable dbglog during start: %d",
ret);
}
@@ -910,11 +1132,20 @@ static const struct file_operations fops_dfs_stats = {
int ath10k_debug_create(struct ath10k *ar)
{
+ int ret;
+
+ ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data));
+ if (!ar->debug.fw_crash_data) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
ar->hw->wiphy->debugfsdir);
-
- if (!ar->debug.debugfs_phy)
- return -ENOMEM;
+ if (!ar->debug.debugfs_phy) {
+ ret = -ENOMEM;
+ goto err_free_fw_crash_data;
+ }
INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
ath10k_debug_htt_stats_dwork);
@@ -930,6 +1161,9 @@ int ath10k_debug_create(struct ath10k *ar)
debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_simulate_fw_crash);
+ debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
+ ar, &fops_fw_crash_dump);
+
debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_chip_id);
@@ -958,17 +1192,25 @@ int ath10k_debug_create(struct ath10k *ar)
}
return 0;
+
+err_free_fw_crash_data:
+ vfree(ar->debug.fw_crash_data);
+
+err:
+ return ret;
}
void ath10k_debug_destroy(struct ath10k *ar)
{
+ vfree(ar->debug.fw_crash_data);
cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
}
#endif /* CONFIG_ATH10K_DEBUGFS */
#ifdef CONFIG_ATH10K_DEBUG
-void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
+void ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask,
+ const char *fmt, ...)
{
struct va_format vaf;
va_list args;
@@ -979,7 +1221,7 @@ void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
vaf.va = &args;
if (ath10k_debug_mask & mask)
- ath10k_printk(KERN_DEBUG, "%pV", &vaf);
+ dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf);
trace_ath10k_log_dbg(mask, &vaf);
@@ -987,13 +1229,14 @@ void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
}
EXPORT_SYMBOL(ath10k_dbg);
-void ath10k_dbg_dump(enum ath10k_debug_mask mask,
+void ath10k_dbg_dump(struct ath10k *ar,
+ enum ath10k_debug_mask mask,
const char *msg, const char *prefix,
const void *buf, size_t len)
{
if (ath10k_debug_mask & mask) {
if (msg)
- ath10k_dbg(mask, "%s\n", msg);
+ ath10k_dbg(ar, mask, "%s\n", msg);
print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
}
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index a5824990bd2..56746539bea 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -39,9 +39,10 @@ enum ath10k_debug_mask {
extern unsigned int ath10k_debug_mask;
-__printf(1, 2) int ath10k_info(const char *fmt, ...);
-__printf(1, 2) int ath10k_err(const char *fmt, ...);
-__printf(1, 2) int ath10k_warn(const char *fmt, ...);
+__printf(2, 3) int ath10k_info(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) int ath10k_err(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) int ath10k_warn(struct ath10k *ar, const char *fmt, ...);
+void ath10k_print_driver_info(struct ath10k *ar);
#ifdef CONFIG_ATH10K_DEBUGFS
int ath10k_debug_start(struct ath10k *ar);
@@ -53,6 +54,10 @@ void ath10k_debug_read_service_map(struct ath10k *ar,
size_t map_size);
void ath10k_debug_read_target_stats(struct ath10k *ar,
struct wmi_stats_event *ev);
+struct ath10k_fw_crash_data *
+ath10k_debug_get_new_fw_crash_data(struct ath10k *ar);
+
+void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
@@ -86,25 +91,40 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
{
}
+static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer,
+ int len)
+{
+}
+
+static inline struct ath10k_fw_crash_data *
+ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
+{
+ return NULL;
+}
+
#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
#endif /* CONFIG_ATH10K_DEBUGFS */
#ifdef CONFIG_ATH10K_DEBUG
-__printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask,
+__printf(3, 4) void ath10k_dbg(struct ath10k *ar,
+ enum ath10k_debug_mask mask,
const char *fmt, ...);
-void ath10k_dbg_dump(enum ath10k_debug_mask mask,
+void ath10k_dbg_dump(struct ath10k *ar,
+ enum ath10k_debug_mask mask,
const char *msg, const char *prefix,
const void *buf, size_t len);
#else /* CONFIG_ATH10K_DEBUG */
-static inline int ath10k_dbg(enum ath10k_debug_mask dbg_mask,
+static inline int ath10k_dbg(struct ath10k *ar,
+ enum ath10k_debug_mask dbg_mask,
const char *fmt, ...)
{
return 0;
}
-static inline void ath10k_dbg_dump(enum ath10k_debug_mask mask,
+static inline void ath10k_dbg_dump(struct ath10k *ar,
+ enum ath10k_debug_mask mask,
const char *msg, const char *prefix,
const void *buf, size_t len)
{
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 5fdc40d3b37..fd9a251f065 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -46,7 +46,7 @@ static struct sk_buff *ath10k_htc_build_tx_ctrl_skb(void *ar)
skb = dev_alloc_skb(ATH10K_HTC_CONTROL_BUFFER_SIZE);
if (!skb) {
- ath10k_warn("Unable to allocate ctrl skb\n");
+ ath10k_warn(ar, "Unable to allocate ctrl skb\n");
return NULL;
}
@@ -56,7 +56,7 @@ static struct sk_buff *ath10k_htc_build_tx_ctrl_skb(void *ar)
skb_cb = ATH10K_SKB_CB(skb);
memset(skb_cb, 0, sizeof(*skb_cb));
- ath10k_dbg(ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb);
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb);
return skb;
}
@@ -72,13 +72,15 @@ static inline void ath10k_htc_restore_tx_skb(struct ath10k_htc *htc,
static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__,
+ struct ath10k *ar = ep->htc->ar;
+
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__,
ep->eid, skb);
ath10k_htc_restore_tx_skb(ep->htc, skb);
if (!ep->ep_ops.ep_tx_complete) {
- ath10k_warn("no tx handler for eid %d\n", ep->eid);
+ ath10k_warn(ar, "no tx handler for eid %d\n", ep->eid);
dev_kfree_skb_any(skb);
return;
}
@@ -89,12 +91,14 @@ static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
/* 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(ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n",
ep->eid);
return true;
}
@@ -123,6 +127,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
enum ath10k_htc_ep_id eid,
struct sk_buff *skb)
{
+ struct ath10k *ar = htc->ar;
struct ath10k_htc_ep *ep = &htc->endpoint[eid];
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
struct ath10k_hif_sg_item sg_item;
@@ -134,18 +139,10 @@ int ath10k_htc_send(struct ath10k_htc *htc,
return -ECOMM;
if (eid >= ATH10K_HTC_EP_COUNT) {
- ath10k_warn("Invalid endpoint id: %d\n", eid);
+ ath10k_warn(ar, "Invalid endpoint id: %d\n", eid);
return -ENOENT;
}
- /* FIXME: This looks ugly, can we fix it? */
- spin_lock_bh(&htc->tx_lock);
- if (htc->stopped) {
- spin_unlock_bh(&htc->tx_lock);
- return -ESHUTDOWN;
- }
- spin_unlock_bh(&htc->tx_lock);
-
skb_push(skb, sizeof(struct ath10k_htc_hdr));
if (ep->tx_credit_flow_enabled) {
@@ -157,7 +154,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
goto err_pull;
}
ep->tx_credits -= credits;
- ath10k_dbg(ATH10K_DBG_HTC,
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
"htc ep %d consumed %d credits (total %d)\n",
eid, credits, ep->tx_credits);
spin_unlock_bh(&htc->tx_lock);
@@ -188,7 +185,7 @@ err_credits:
if (ep->tx_credit_flow_enabled) {
spin_lock_bh(&htc->tx_lock);
ep->tx_credits += credits;
- ath10k_dbg(ATH10K_DBG_HTC,
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
"htc ep %d reverted %d credits back (total %d)\n",
eid, credits, ep->tx_credits);
spin_unlock_bh(&htc->tx_lock);
@@ -227,11 +224,12 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,
int len,
enum ath10k_htc_ep_id eid)
{
+ struct ath10k *ar = htc->ar;
struct ath10k_htc_ep *ep;
int i, n_reports;
if (len % sizeof(*report))
- ath10k_warn("Uneven credit report len %d", len);
+ ath10k_warn(ar, "Uneven credit report len %d", len);
n_reports = len / sizeof(*report);
@@ -243,7 +241,7 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,
ep = &htc->endpoint[report->eid];
ep->tx_credits += report->credits;
- ath10k_dbg(ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
report->eid, report->credits, ep->tx_credits);
if (ep->ep_ops.ep_tx_credits) {
@@ -260,6 +258,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
int length,
enum ath10k_htc_ep_id src_eid)
{
+ struct ath10k *ar = htc->ar;
int status = 0;
struct ath10k_htc_record *record;
u8 *orig_buffer;
@@ -279,7 +278,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
if (record->hdr.len > length) {
/* no room left in buffer for record */
- ath10k_warn("Invalid record length: %d\n",
+ ath10k_warn(ar, "Invalid record length: %d\n",
record->hdr.len);
status = -EINVAL;
break;
@@ -289,7 +288,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
case ATH10K_HTC_RECORD_CREDITS:
len = sizeof(struct ath10k_htc_credit_report);
if (record->hdr.len < len) {
- ath10k_warn("Credit report too long\n");
+ ath10k_warn(ar, "Credit report too long\n");
status = -EINVAL;
break;
}
@@ -299,7 +298,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
src_eid);
break;
default:
- ath10k_warn("Unhandled record: id:%d length:%d\n",
+ ath10k_warn(ar, "Unhandled record: id:%d length:%d\n",
record->hdr.id, record->hdr.len);
break;
}
@@ -313,7 +312,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
}
if (status)
- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc rx bad trailer", "",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc rx bad trailer", "",
orig_buffer, orig_length);
return status;
@@ -339,8 +338,8 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
eid = hdr->eid;
if (eid >= ATH10K_HTC_EP_COUNT) {
- ath10k_warn("HTC Rx: invalid eid %d\n", eid);
- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad header", "",
+ ath10k_warn(ar, "HTC Rx: invalid eid %d\n", eid);
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad header", "",
hdr, sizeof(*hdr));
status = -EINVAL;
goto out;
@@ -360,19 +359,19 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
payload_len = __le16_to_cpu(hdr->len);
if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) {
- ath10k_warn("HTC rx frame too long, len: %zu\n",
+ ath10k_warn(ar, "HTC rx frame too long, len: %zu\n",
payload_len + sizeof(*hdr));
- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len", "",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "",
hdr, sizeof(*hdr));
status = -EINVAL;
goto out;
}
if (skb->len < payload_len) {
- ath10k_dbg(ATH10K_DBG_HTC,
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
"HTC Rx: insufficient length, got %d, expected %d\n",
skb->len, payload_len);
- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len",
"", hdr, sizeof(*hdr));
status = -EINVAL;
goto out;
@@ -388,7 +387,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
if ((trailer_len < min_len) ||
(trailer_len > payload_len)) {
- ath10k_warn("Invalid trailer length: %d\n",
+ ath10k_warn(ar, "Invalid trailer length: %d\n",
trailer_len);
status = -EPROTO;
goto out;
@@ -421,7 +420,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
* this is a fatal error, target should not be
* sending unsolicited messages on the ep 0
*/
- ath10k_warn("HTC rx ctrl still processing\n");
+ ath10k_warn(ar, "HTC rx ctrl still processing\n");
status = -EINVAL;
complete(&htc->ctl_resp);
goto out;
@@ -442,7 +441,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
goto out;
}
- ath10k_dbg(ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n",
eid, skb);
ep->ep_ops.ep_rx_complete(ar, skb);
@@ -459,7 +458,7 @@ static void ath10k_htc_control_rx_complete(struct ath10k *ar,
{
/* This is unexpected. FW is not supposed to send regular rx on this
* endpoint. */
- ath10k_warn("unexpected htc rx\n");
+ ath10k_warn(ar, "unexpected htc rx\n");
kfree_skb(skb);
}
@@ -546,6 +545,7 @@ static u8 ath10k_htc_get_credit_allocation(struct ath10k_htc *htc,
int ath10k_htc_wait_target(struct ath10k_htc *htc)
{
+ struct ath10k *ar = htc->ar;
int i, status = 0;
struct ath10k_htc_svc_conn_req conn_req;
struct ath10k_htc_svc_conn_resp conn_resp;
@@ -563,7 +563,7 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
* iomap writes unmasking PCI CE irqs aren't propagated
* properly in KVM PCI-passthrough sometimes.
*/
- ath10k_warn("failed to receive control response completion, polling..\n");
+ ath10k_warn(ar, "failed to receive control response completion, polling..\n");
for (i = 0; i < CE_COUNT; i++)
ath10k_hif_send_complete_check(htc->ar, i, 1);
@@ -576,12 +576,12 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
}
if (status < 0) {
- ath10k_err("ctl_resp never came in (%d)\n", status);
+ ath10k_err(ar, "ctl_resp never came in (%d)\n", status);
return status;
}
if (htc->control_resp_len < sizeof(msg->hdr) + sizeof(msg->ready)) {
- ath10k_err("Invalid HTC ready msg len:%d\n",
+ ath10k_err(ar, "Invalid HTC ready msg len:%d\n",
htc->control_resp_len);
return -ECOMM;
}
@@ -592,21 +592,21 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
credit_size = __le16_to_cpu(msg->ready.credit_size);
if (message_id != ATH10K_HTC_MSG_READY_ID) {
- ath10k_err("Invalid HTC ready msg: 0x%x\n", message_id);
+ ath10k_err(ar, "Invalid HTC ready msg: 0x%x\n", message_id);
return -ECOMM;
}
htc->total_transmit_credits = credit_count;
htc->target_credit_size = credit_size;
- ath10k_dbg(ATH10K_DBG_HTC,
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
"Target ready! transmit resources: %d size:%d\n",
htc->total_transmit_credits,
htc->target_credit_size);
if ((htc->total_transmit_credits == 0) ||
(htc->target_credit_size == 0)) {
- ath10k_err("Invalid credit size received\n");
+ ath10k_err(ar, "Invalid credit size received\n");
return -ECOMM;
}
@@ -623,7 +623,8 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
/* connect fake service */
status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp);
if (status) {
- ath10k_err("could not connect to htc service (%d)\n", status);
+ ath10k_err(ar, "could not connect to htc service (%d)\n",
+ status);
return status;
}
@@ -634,6 +635,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
struct ath10k_htc_svc_conn_req *conn_req,
struct ath10k_htc_svc_conn_resp *conn_resp)
{
+ struct ath10k *ar = htc->ar;
struct ath10k_htc_msg *msg;
struct ath10k_htc_conn_svc *req_msg;
struct ath10k_htc_conn_svc_response resp_msg_dummy;
@@ -659,13 +661,13 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
tx_alloc = ath10k_htc_get_credit_allocation(htc,
conn_req->service_id);
if (!tx_alloc)
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot htc service %s does not allocate target credits\n",
htc_service_name(conn_req->service_id));
skb = ath10k_htc_build_tx_ctrl_skb(htc->ar);
if (!skb) {
- ath10k_err("Failed to allocate HTC packet\n");
+ ath10k_err(ar, "Failed to allocate HTC packet\n");
return -ENOMEM;
}
@@ -703,7 +705,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
if (status <= 0) {
if (status == 0)
status = -ETIMEDOUT;
- ath10k_err("Service connect timeout: %d\n", status);
+ ath10k_err(ar, "Service connect timeout: %d\n", status);
return status;
}
@@ -716,11 +718,11 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
if ((message_id != ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID) ||
(htc->control_resp_len < sizeof(msg->hdr) +
sizeof(msg->connect_service_response))) {
- ath10k_err("Invalid resp message ID 0x%x", message_id);
+ ath10k_err(ar, "Invalid resp message ID 0x%x", message_id);
return -EPROTO;
}
- ath10k_dbg(ATH10K_DBG_HTC,
+ ath10k_dbg(ar, ATH10K_DBG_HTC,
"HTC Service %s connect response: status: 0x%x, assigned ep: 0x%x\n",
htc_service_name(service_id),
resp_msg->status, resp_msg->eid);
@@ -729,7 +731,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
/* check response status */
if (resp_msg->status != ATH10K_HTC_CONN_SVC_STATUS_SUCCESS) {
- ath10k_err("HTC Service %s connect request failed: 0x%x)\n",
+ ath10k_err(ar, "HTC Service %s connect request failed: 0x%x)\n",
htc_service_name(service_id),
resp_msg->status);
return -EPROTO;
@@ -780,18 +782,18 @@ setup:
if (status)
return status;
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n",
htc_service_name(ep->service_id), ep->ul_pipe_id,
ep->dl_pipe_id, ep->eid);
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot htc ep %d ul polled %d dl polled %d\n",
ep->eid, ep->ul_is_polled, ep->dl_is_polled);
if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) {
ep->tx_credit_flow_enabled = false;
- ath10k_dbg(ATH10K_DBG_BOOT,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot htc service '%s' eid %d TX flow control disabled\n",
htc_service_name(ep->service_id), assigned_eid);
}
@@ -799,13 +801,13 @@ setup:
return status;
}
-struct sk_buff *ath10k_htc_alloc_skb(int size)
+struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size)
{
struct sk_buff *skb;
skb = dev_alloc_skb(size + sizeof(struct ath10k_htc_hdr));
if (!skb) {
- ath10k_warn("could not allocate HTC tx skb\n");
+ ath10k_warn(ar, "could not allocate HTC tx skb\n");
return NULL;
}
@@ -813,13 +815,14 @@ struct sk_buff *ath10k_htc_alloc_skb(int size)
/* FW/HTC requires 4-byte aligned streams */
if (!IS_ALIGNED((unsigned long)skb->data, 4))
- ath10k_warn("Unaligned HTC tx skb\n");
+ ath10k_warn(ar, "Unaligned HTC tx skb\n");
return skb;
}
int ath10k_htc_start(struct ath10k_htc *htc)
{
+ struct ath10k *ar = htc->ar;
struct sk_buff *skb;
int status = 0;
struct ath10k_htc_msg *msg;
@@ -835,7 +838,7 @@ int ath10k_htc_start(struct ath10k_htc *htc)
msg->hdr.message_id =
__cpu_to_le16(ATH10K_HTC_MSG_SETUP_COMPLETE_EX_ID);
- ath10k_dbg(ATH10K_DBG_HTC, "HTC is using TX credit flow control\n");
+ ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC is using TX credit flow control\n");
status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb);
if (status) {
@@ -846,13 +849,6 @@ int ath10k_htc_start(struct ath10k_htc *htc)
return 0;
}
-void ath10k_htc_stop(struct ath10k_htc *htc)
-{
- spin_lock_bh(&htc->tx_lock);
- htc->stopped = true;
- spin_unlock_bh(&htc->tx_lock);
-}
-
/* registered target arrival callback from the HIF layer */
int ath10k_htc_init(struct ath10k *ar)
{
@@ -862,7 +858,6 @@ int ath10k_htc_init(struct ath10k *ar)
spin_lock_init(&htc->tx_lock);
- htc->stopped = false;
ath10k_htc_reset_endpoint_states(htc);
/* setup HIF layer callbacks */
diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
index 4716d331e6b..bf532f67118 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -332,7 +332,7 @@ struct ath10k_htc {
struct ath10k *ar;
struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT];
- /* protects endpoint and stopped fields */
+ /* protects endpoints */
spinlock_t tx_lock;
struct ath10k_htc_ops htc_ops;
@@ -345,8 +345,6 @@ struct ath10k_htc {
int total_transmit_credits;
struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT];
int target_credit_size;
-
- bool stopped;
};
int ath10k_htc_init(struct ath10k *ar);
@@ -357,7 +355,6 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
struct ath10k_htc_svc_conn_resp *conn_resp);
int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
struct sk_buff *packet);
-void ath10k_htc_stop(struct ath10k_htc *htc);
-struct sk_buff *ath10k_htc_alloc_skb(int size);
+struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
#endif
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 19c12cc8d66..87daae11f11 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -74,12 +74,14 @@ int ath10k_htt_init(struct ath10k *ar)
static int ath10k_htt_verify_version(struct ath10k_htt *htt)
{
- ath10k_dbg(ATH10K_DBG_BOOT, "htt target version %d.%d\n",
+ struct ath10k *ar = htt->ar;
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt target version %d.%d\n",
htt->target_version_major, htt->target_version_minor);
if (htt->target_version_major != 2 &&
htt->target_version_major != 3) {
- ath10k_err("unsupported htt major version %d. supported versions are 2 and 3\n",
+ ath10k_err(ar, "unsupported htt major version %d. supported versions are 2 and 3\n",
htt->target_version_major);
return -ENOTSUPP;
}
@@ -89,6 +91,7 @@ static int ath10k_htt_verify_version(struct ath10k_htt *htt)
int ath10k_htt_setup(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
int status;
init_completion(&htt->target_version_received);
@@ -100,7 +103,7 @@ int ath10k_htt_setup(struct ath10k_htt *htt)
status = wait_for_completion_timeout(&htt->target_version_received,
HTT_TARGET_VERSION_TIMEOUT_HZ);
if (status <= 0) {
- ath10k_warn("htt version request timed out\n");
+ ath10k_warn(ar, "htt version request timed out\n");
return -ETIMEDOUT;
}
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 80cdac15588..30927b1d710 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -271,13 +271,14 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt)
static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
int idx;
struct sk_buff *msdu;
lockdep_assert_held(&htt->rx_ring.lock);
if (htt->rx_ring.fill_cnt == 0) {
- ath10k_warn("tried to pop sk_buff from an empty rx ring\n");
+ ath10k_warn(ar, "tried to pop sk_buff from an empty rx ring\n");
return NULL;
}
@@ -311,6 +312,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
struct sk_buff **tail_msdu,
u32 *attention)
{
+ struct ath10k *ar = htt->ar;
int msdu_len, msdu_chaining = 0;
struct sk_buff *msdu;
struct htt_rx_desc *rx_desc;
@@ -318,7 +320,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
lockdep_assert_held(&htt->rx_ring.lock);
if (htt->rx_confused) {
- ath10k_warn("htt is confused. refusing rx\n");
+ ath10k_warn(ar, "htt is confused. refusing rx\n");
return -1;
}
@@ -331,7 +333,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
msdu->len + skb_tailroom(msdu),
DMA_FROM_DEVICE);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",
msdu->data, msdu->len + skb_tailroom(msdu));
rx_desc = (struct htt_rx_desc *)msdu->data;
@@ -354,7 +356,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
ath10k_htt_rx_free_msdu_chain(*head_msdu);
*head_msdu = NULL;
msdu = NULL;
- ath10k_err("htt rx stopped. cannot recover\n");
+ ath10k_err(ar, "htt rx stopped. cannot recover\n");
htt->rx_confused = true;
break;
}
@@ -429,7 +431,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
next->len + skb_tailroom(next),
DMA_FROM_DEVICE);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL,
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL,
"htt rx chained: ", next->data,
next->len + skb_tailroom(next));
@@ -483,13 +485,14 @@ static void ath10k_htt_rx_replenish_task(unsigned long ptr)
int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
dma_addr_t paddr;
void *vaddr;
struct timer_list *timer = &htt->rx_ring.refill_retry_timer;
htt->rx_ring.size = ath10k_htt_rx_ring_size(htt);
if (!is_power_of_2(htt->rx_ring.size)) {
- ath10k_warn("htt rx ring size is not power of 2\n");
+ ath10k_warn(ar, "htt rx ring size is not power of 2\n");
return -EINVAL;
}
@@ -550,7 +553,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task,
(unsigned long)htt);
- ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
htt->rx_ring.size, htt->rx_ring.fill_level);
return 0;
@@ -572,7 +575,8 @@ err_netbuf:
return -ENOMEM;
}
-static int ath10k_htt_rx_crypto_param_len(enum htt_rx_mpdu_encrypt_type type)
+static int ath10k_htt_rx_crypto_param_len(struct ath10k *ar,
+ enum htt_rx_mpdu_encrypt_type type)
{
switch (type) {
case HTT_RX_MPDU_ENCRYPT_WEP40:
@@ -588,11 +592,12 @@ static int ath10k_htt_rx_crypto_param_len(enum htt_rx_mpdu_encrypt_type type)
return 0;
}
- ath10k_warn("unknown encryption type %d\n", type);
+ ath10k_warn(ar, "unknown encryption type %d\n", type);
return 0;
}
-static int ath10k_htt_rx_crypto_tail_len(enum htt_rx_mpdu_encrypt_type type)
+static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar,
+ enum htt_rx_mpdu_encrypt_type type)
{
switch (type) {
case HTT_RX_MPDU_ENCRYPT_NONE:
@@ -608,7 +613,7 @@ static int ath10k_htt_rx_crypto_tail_len(enum htt_rx_mpdu_encrypt_type type)
return 8;
}
- ath10k_warn("unknown encryption type %d\n", type);
+ ath10k_warn(ar, "unknown encryption type %d\n", type);
return 0;
}
@@ -819,19 +824,55 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
return true;
}
+static const char * const tid_to_ac[] = {
+ "BE",
+ "BK",
+ "BK",
+ "BE",
+ "VI",
+ "VI",
+ "VO",
+ "VO",
+};
+
+static char *ath10k_get_tid(struct ieee80211_hdr *hdr, char *out, size_t size)
+{
+ u8 *qc;
+ int tid;
+
+ if (!ieee80211_is_data_qos(hdr->frame_control))
+ return "";
+
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
+ if (tid < 8)
+ snprintf(out, size, "tid %d (%s)", tid, tid_to_ac[tid]);
+ else
+ snprintf(out, size, "tid %d", tid);
+
+ return out;
+}
+
static void ath10k_process_rx(struct ath10k *ar,
struct ieee80211_rx_status *rx_status,
struct sk_buff *skb)
{
struct ieee80211_rx_status *status;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ char tid[32];
status = IEEE80211_SKB_RXCB(skb);
*status = *rx_status;
- ath10k_dbg(ATH10K_DBG_DATA,
- "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %imic-err %i\n",
+ ath10k_dbg(ar, ATH10K_DBG_DATA,
+ "rx skb %p len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
skb,
skb->len,
+ ieee80211_get_SA(hdr),
+ ath10k_get_tid(hdr, tid, sizeof(tid)),
+ is_multicast_ether_addr(ieee80211_get_DA(hdr)) ?
+ "mcast" : "ucast",
+ (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4,
status->flag == 0 ? "legacy" : "",
status->flag & RX_FLAG_HT ? "ht" : "",
status->flag & RX_FLAG_VHT ? "vht" : "",
@@ -843,8 +884,9 @@ static void ath10k_process_rx(struct ath10k *ar,
status->freq,
status->band, status->flag,
!!(status->flag & RX_FLAG_FAILED_FCS_CRC),
- !!(status->flag & RX_FLAG_MMIC_ERROR));
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
+ !!(status->flag & RX_FLAG_MMIC_ERROR),
+ !!(status->flag & RX_FLAG_AMSDU_MORE));
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
skb->data, skb->len);
ieee80211_rx(ar->hw, skb);
@@ -860,13 +902,14 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
struct ieee80211_rx_status *rx_status,
struct sk_buff *skb_in)
{
+ struct ath10k *ar = htt->ar;
struct htt_rx_desc *rxd;
struct sk_buff *skb = skb_in;
struct sk_buff *first;
enum rx_msdu_decap_format fmt;
enum htt_rx_mpdu_encrypt_type enctype;
struct ieee80211_hdr *hdr;
- u8 hdr_buf[64], addr[ETH_ALEN], *qos;
+ u8 hdr_buf[64], da[ETH_ALEN], sa[ETH_ALEN], *qos;
unsigned int hdr_len;
rxd = (void *)skb->data - sizeof(*rxd);
@@ -893,8 +936,8 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
/* First frame in an A-MSDU chain has more decapped data. */
if (skb == first) {
len = round_up(ieee80211_hdrlen(hdr->frame_control), 4);
- len += round_up(ath10k_htt_rx_crypto_param_len(enctype),
- 4);
+ len += round_up(ath10k_htt_rx_crypto_param_len(ar,
+ enctype), 4);
decap_hdr += len;
}
@@ -904,10 +947,11 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
skb_trim(skb, skb->len - FCS_LEN);
break;
case RX_MSDU_DECAP_NATIVE_WIFI:
- /* pull decapped header and copy DA */
+ /* pull decapped header and copy SA & DA */
hdr = (struct ieee80211_hdr *)skb->data;
hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
- memcpy(addr, ieee80211_get_DA(hdr), ETH_ALEN);
+ memcpy(da, ieee80211_get_DA(hdr), ETH_ALEN);
+ memcpy(sa, ieee80211_get_SA(hdr), ETH_ALEN);
skb_pull(skb, hdr_len);
/* push original 802.11 header */
@@ -921,8 +965,11 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
qos = ieee80211_get_qos_ctl(hdr);
qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
- /* original 802.11 header has a different DA */
- memcpy(ieee80211_get_DA(hdr), addr, ETH_ALEN);
+ /* original 802.11 header has a different DA and in
+ * case of 4addr it may also have different SA
+ */
+ memcpy(ieee80211_get_DA(hdr), da, ETH_ALEN);
+ memcpy(ieee80211_get_SA(hdr), sa, ETH_ALEN);
break;
case RX_MSDU_DECAP_ETHERNET2_DIX:
/* strip ethernet header and insert decapped 802.11
@@ -965,6 +1012,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
struct ieee80211_rx_status *rx_status,
struct sk_buff *skb)
{
+ struct ath10k *ar = htt->ar;
struct htt_rx_desc *rxd;
struct ieee80211_hdr *hdr;
enum rx_msdu_decap_format fmt;
@@ -974,7 +1022,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
/* This shouldn't happen. If it does than it may be a FW bug. */
if (skb->next) {
- ath10k_warn("htt rx received chained non A-MSDU frame\n");
+ ath10k_warn(ar, "htt rx received chained non A-MSDU frame\n");
ath10k_htt_rx_free_msdu_chain(skb->next);
skb->next = NULL;
}
@@ -1011,7 +1059,8 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
rfc1042 = hdr;
rfc1042 += roundup(hdr_len, 4);
- rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(enctype), 4);
+ rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(ar,
+ enctype), 4);
skb_pull(skb, sizeof(struct ethhdr));
memcpy(skb_push(skb, sizeof(struct rfc1042_hdr)),
@@ -1120,27 +1169,29 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt,
bool channel_set,
u32 attention)
{
+ struct ath10k *ar = htt->ar;
+
if (head->len == 0) {
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx dropping due to zero-len\n");
return false;
}
if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) {
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx dropping due to decrypt-err\n");
return false;
}
if (!channel_set) {
- ath10k_warn("no channel configured; ignoring frame!\n");
+ ath10k_warn(ar, "no channel configured; ignoring frame!\n");
return false;
}
/* Skip mgmt frames while we handle this in WMI */
if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL ||
attention & RX_ATTENTION_FLAGS_MGMT_TYPE) {
- ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
return false;
}
@@ -1148,14 +1199,14 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt,
status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
!htt->ar->monitor_started) {
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx ignoring frame w/ status %d\n",
status);
return false;
}
if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx CAC running\n");
return false;
}
@@ -1166,6 +1217,7 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt,
static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
struct htt_rx_indication *rx)
{
+ struct ath10k *ar = htt->ar;
struct ieee80211_rx_status *rx_status = &htt->rx_status;
struct htt_rx_indication_mpdu_range *mpdu_ranges;
struct htt_rx_desc *rxd;
@@ -1211,7 +1263,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
rx_status);
}
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
rx, sizeof(*rx) +
(sizeof(struct htt_rx_indication_mpdu_range) *
num_mpdu_ranges));
@@ -1233,7 +1285,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
&attention);
if (ret < 0) {
- ath10k_warn("failed to pop amsdu from htt rx ring %d\n",
+ ath10k_warn(ar, "failed to pop amsdu from htt rx ring %d\n",
ret);
ath10k_htt_rx_free_msdu_chain(msdu_head);
continue;
@@ -1282,6 +1334,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
struct htt_rx_fragment_indication *frag)
{
+ struct ath10k *ar = htt->ar;
struct sk_buff *msdu_head, *msdu_tail;
enum htt_rx_mpdu_encrypt_type enctype;
struct htt_rx_desc *rxd;
@@ -1308,10 +1361,10 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
&attention);
spin_unlock_bh(&htt->rx_ring.lock);
- ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
+ ath10k_dbg(ar, ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
if (ret) {
- ath10k_warn("failed to pop amsdu from httr rx ring for fragmented rx %d\n",
+ ath10k_warn(ar, "failed to pop amsdu from httr rx ring for fragmented rx %d\n",
ret);
ath10k_htt_rx_free_msdu_chain(msdu_head);
return;
@@ -1328,7 +1381,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
RX_MSDU_START_INFO1_DECAP_FORMAT);
if (fmt != RX_MSDU_DECAP_RAW) {
- ath10k_warn("we dont support non-raw fragmented rx yet\n");
+ ath10k_warn(ar, "we dont support non-raw fragmented rx yet\n");
dev_kfree_skb_any(msdu_head);
goto end;
}
@@ -1340,17 +1393,17 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head);
if (tkip_mic_err)
- ath10k_warn("tkip mic error\n");
+ ath10k_warn(ar, "tkip mic error\n");
if (decrypt_err) {
- ath10k_warn("decryption err in fragmented rx\n");
+ ath10k_warn(ar, "decryption err in fragmented rx\n");
dev_kfree_skb_any(msdu_head);
goto end;
}
if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) {
hdrlen = ieee80211_hdrlen(hdr->frame_control);
- paramlen = ath10k_htt_rx_crypto_param_len(enctype);
+ paramlen = ath10k_htt_rx_crypto_param_len(ar, enctype);
/* It is more efficient to move the header than the payload */
memmove((void *)msdu_head->data + paramlen,
@@ -1364,7 +1417,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
trim = 4;
/* remove crypto trailer */
- trim += ath10k_htt_rx_crypto_tail_len(enctype);
+ trim += ath10k_htt_rx_crypto_tail_len(ar, enctype);
/* last fragment of TKIP frags has MIC */
if (!ieee80211_has_morefrags(hdr->frame_control) &&
@@ -1372,20 +1425,20 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
trim += 8;
if (trim > msdu_head->len) {
- ath10k_warn("htt rx fragment: trailer longer than the frame itself? drop\n");
+ ath10k_warn(ar, "htt rx fragment: trailer longer than the frame itself? drop\n");
dev_kfree_skb_any(msdu_head);
goto end;
}
skb_trim(msdu_head, msdu_head->len - trim);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
msdu_head->data, msdu_head->len);
ath10k_process_rx(htt->ar, rx_status, msdu_head);
end:
if (fw_desc_len > 0) {
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"expecting more fragmented rx in one indication %d\n",
fw_desc_len);
}
@@ -1415,12 +1468,12 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
tx_done.discard = true;
break;
default:
- ath10k_warn("unhandled tx completion status %d\n", status);
+ ath10k_warn(ar, "unhandled tx completion status %d\n", status);
tx_done.discard = true;
break;
}
- ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
resp->data_tx_completion.num_msdus);
for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
@@ -1441,14 +1494,14 @@ static void ath10k_htt_rx_addba(struct ath10k *ar, struct htt_resp *resp)
tid = MS(info0, HTT_RX_BA_INFO0_TID);
peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID);
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx addba tid %hu peer_id %hu size %hhu\n",
tid, peer_id, ev->window_size);
spin_lock_bh(&ar->data_lock);
peer = ath10k_peer_find_by_id(ar, peer_id);
if (!peer) {
- ath10k_warn("received addba event for invalid peer_id: %hu\n",
+ ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n",
peer_id);
spin_unlock_bh(&ar->data_lock);
return;
@@ -1456,13 +1509,13 @@ static void ath10k_htt_rx_addba(struct ath10k *ar, struct htt_resp *resp)
arvif = ath10k_get_arvif(ar, peer->vdev_id);
if (!arvif) {
- ath10k_warn("received addba event for invalid vdev_id: %u\n",
+ ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n",
peer->vdev_id);
spin_unlock_bh(&ar->data_lock);
return;
}
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx start rx ba session sta %pM tid %hu size %hhu\n",
peer->addr, tid, ev->window_size);
@@ -1481,14 +1534,14 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp)
tid = MS(info0, HTT_RX_BA_INFO0_TID);
peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID);
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx delba tid %hu peer_id %hu\n",
tid, peer_id);
spin_lock_bh(&ar->data_lock);
peer = ath10k_peer_find_by_id(ar, peer_id);
if (!peer) {
- ath10k_warn("received addba event for invalid peer_id: %hu\n",
+ ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n",
peer_id);
spin_unlock_bh(&ar->data_lock);
return;
@@ -1496,13 +1549,13 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp)
arvif = ath10k_get_arvif(ar, peer->vdev_id);
if (!arvif) {
- ath10k_warn("received addba event for invalid vdev_id: %u\n",
+ ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n",
peer->vdev_id);
spin_unlock_bh(&ar->data_lock);
return;
}
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt rx stop rx ba session sta %pM tid %hu\n",
peer->addr, tid);
@@ -1517,9 +1570,9 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
/* confirm alignment */
if (!IS_ALIGNED((unsigned long)skb->data, 4))
- ath10k_warn("unaligned htt message, expect trouble\n");
+ ath10k_warn(ar, "unaligned htt message, expect trouble\n");
- ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
resp->hdr.msg_type);
switch (resp->hdr.msg_type) {
case HTT_T2H_MSG_TYPE_VERSION_CONF: {
@@ -1583,7 +1636,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
struct ath10k *ar = htt->ar;
struct htt_security_indication *ev = &resp->security_indication;
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"sec ind peer_id %d unicast %d type %d\n",
__le16_to_cpu(ev->peer_id),
!!(ev->flags & HTT_SECURITY_IS_UNICAST),
@@ -1592,7 +1645,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
case HTT_T2H_MSG_TYPE_RX_FRAG_IND: {
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
skb->data, skb->len);
ath10k_htt_rx_frag_handler(htt, &resp->rx_frag_ind);
break;
@@ -1609,7 +1662,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
* sends all tx frames as already inspected so this shouldn't
* happen unless fw has a bug.
*/
- ath10k_warn("received an unexpected htt tx inspect event\n");
+ ath10k_warn(ar, "received an unexpected htt tx inspect event\n");
break;
case HTT_T2H_MSG_TYPE_RX_ADDBA:
ath10k_htt_rx_addba(ar, resp);
@@ -1624,9 +1677,9 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
default:
- ath10k_dbg(ATH10K_DBG_HTT, "htt event (%d) not handled\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt event (%d) not handled\n",
resp->hdr.msg_type);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
skb->data, skb->len);
break;
};
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 8b27bfcc1de..eaa73aa99c2 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -58,6 +58,7 @@ exit:
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
int msdu_id;
lockdep_assert_held(&htt->tx_lock);
@@ -67,24 +68,29 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt)
if (msdu_id == htt->max_num_pending_tx)
return -ENOBUFS;
- ath10k_dbg(ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id);
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id);
__set_bit(msdu_id, htt->used_msdu_ids);
return msdu_id;
}
void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)
{
+ struct ath10k *ar = htt->ar;
+
lockdep_assert_held(&htt->tx_lock);
if (!test_bit(msdu_id, htt->used_msdu_ids))
- ath10k_warn("trying to free unallocated msdu_id %d\n", msdu_id);
+ ath10k_warn(ar, "trying to free unallocated msdu_id %d\n",
+ msdu_id);
- ath10k_dbg(ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id);
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id);
__clear_bit(msdu_id, htt->used_msdu_ids);
}
int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
+
spin_lock_init(&htt->tx_lock);
init_waitqueue_head(&htt->empty_tx_wq);
@@ -93,7 +99,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
else
htt->max_num_pending_tx = TARGET_NUM_MSDU_DESC;
- ath10k_dbg(ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
htt->max_num_pending_tx);
htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) *
@@ -122,6 +128,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
struct htt_tx_done tx_done = {0};
int msdu_id;
@@ -130,7 +137,7 @@ static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt)
if (!test_bit(msdu_id, htt->used_msdu_ids))
continue;
- ath10k_dbg(ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n",
msdu_id);
tx_done.discard = 1;
@@ -157,6 +164,7 @@ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
struct sk_buff *skb;
struct htt_cmd *cmd;
int len = 0;
@@ -165,7 +173,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
len += sizeof(cmd->hdr);
len += sizeof(cmd->ver_req);
- skb = ath10k_htc_alloc_skb(len);
+ skb = ath10k_htc_alloc_skb(ar, len);
if (!skb)
return -ENOMEM;
@@ -184,6 +192,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
{
+ struct ath10k *ar = htt->ar;
struct htt_stats_req *req;
struct sk_buff *skb;
struct htt_cmd *cmd;
@@ -192,7 +201,7 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
len += sizeof(cmd->hdr);
len += sizeof(cmd->stats_req);
- skb = ath10k_htc_alloc_skb(len);
+ skb = ath10k_htc_alloc_skb(ar, len);
if (!skb)
return -ENOMEM;
@@ -214,7 +223,8 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
if (ret) {
- ath10k_warn("failed to send htt type stats request: %d", ret);
+ ath10k_warn(ar, "failed to send htt type stats request: %d",
+ ret);
dev_kfree_skb_any(skb);
return ret;
}
@@ -224,6 +234,7 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
{
+ struct ath10k *ar = htt->ar;
struct sk_buff *skb;
struct htt_cmd *cmd;
struct htt_rx_ring_setup_ring *ring;
@@ -242,7 +253,7 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup.hdr)
+ (sizeof(*ring) * num_rx_ring);
- skb = ath10k_htc_alloc_skb(len);
+ skb = ath10k_htc_alloc_skb(ar, len);
if (!skb)
return -ENOMEM;
@@ -311,6 +322,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
u8 max_subfrms_ampdu,
u8 max_subfrms_amsdu)
{
+ struct ath10k *ar = htt->ar;
struct htt_aggr_conf *aggr_conf;
struct sk_buff *skb;
struct htt_cmd *cmd;
@@ -328,7 +340,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
len = sizeof(cmd->hdr);
len += sizeof(cmd->aggr_conf);
- skb = ath10k_htc_alloc_skb(len);
+ skb = ath10k_htc_alloc_skb(ar, len);
if (!skb)
return -ENOMEM;
@@ -340,7 +352,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
aggr_conf->max_num_ampdu_subframes = max_subfrms_ampdu;
aggr_conf->max_num_amsdu_subframes = max_subfrms_amsdu;
- ath10k_dbg(ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d",
aggr_conf->max_num_amsdu_subframes,
aggr_conf->max_num_ampdu_subframes);
@@ -355,7 +367,8 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
{
- struct device *dev = htt->ar->dev;
+ struct ath10k *ar = htt->ar;
+ struct device *dev = ar->dev;
struct sk_buff *txdesc = NULL;
struct htt_cmd *cmd;
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
@@ -382,7 +395,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
htt->pending_tx[msdu_id] = msdu;
spin_unlock_bh(&htt->tx_lock);
- txdesc = ath10k_htc_alloc_skb(len);
+ txdesc = ath10k_htc_alloc_skb(ar, len);
if (!txdesc) {
res = -ENOMEM;
goto err_free_msdu_id;
@@ -429,7 +442,8 @@ err:
int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
{
- struct device *dev = htt->ar->dev;
+ struct ath10k *ar = htt->ar;
+ struct device *dev = ar->dev;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
struct ath10k_hif_sg_item sg_items[2];
@@ -545,11 +559,11 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID);
- ath10k_dbg(ATH10K_DBG_HTT,
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n",
flags0, flags1, msdu->len, msdu_id, frags_paddr,
(u32)skb_cb->paddr, vdev_id, tid);
- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
msdu->data, msdu->len);
sg_items[0].transfer_id = 0;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 007e855f4ba..13568b01de9 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -28,16 +28,19 @@
#define QCA988X_HW_2_0_CHIP_ID_REV 0x2
#define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0"
#define QCA988X_HW_2_0_FW_FILE "firmware.bin"
-#define QCA988X_HW_2_0_FW_2_FILE "firmware-2.bin"
+#define QCA988X_HW_2_0_FW_3_FILE "firmware-3.bin"
#define QCA988X_HW_2_0_OTP_FILE "otp.bin"
#define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
#define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
#define ATH10K_FW_API2_FILE "firmware-2.bin"
+#define ATH10K_FW_API3_FILE "firmware-3.bin"
/* includes also the null byte */
#define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K"
+#define REG_DUMP_COUNT_QCA988X 60
+
struct ath10k_fw_ie {
__le32 id;
__le32 len;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 9d61bb15718..1f35bd1ef56 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -36,6 +36,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
enum set_key_cmd cmd,
const u8 *macaddr)
{
+ struct ath10k *ar = arvif->ar;
struct wmi_vdev_install_key_arg arg = {
.vdev_id = arvif->vdev_id,
.key_idx = key->keyidx,
@@ -73,7 +74,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
arg.key_flags = WMI_KEY_PAIRWISE;
break;
default:
- ath10k_warn("cipher %d is not supported\n", key->cipher);
+ ath10k_warn(ar, "cipher %d is not supported\n", key->cipher);
return -EOPNOTSUPP;
}
@@ -168,7 +169,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
first_errno = ret;
if (ret)
- ath10k_warn("failed to remove peer wep key %d: %d\n",
+ ath10k_warn(ar, "failed to remove peer wep key %d: %d\n",
i, ret);
peer->keys[i] = NULL;
@@ -216,7 +217,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
first_errno = ret;
if (ret)
- ath10k_warn("failed to remove key for %pM: %d\n",
+ ath10k_warn(ar, "failed to remove key for %pM: %d\n",
addr, ret);
}
@@ -327,14 +328,14 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
if (ret) {
- ath10k_warn("failed to create wmi peer %pM on vdev %i: %i\n",
+ ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n",
addr, vdev_id, ret);
return ret;
}
ret = ath10k_wait_for_peer_created(ar, vdev_id, addr);
if (ret) {
- ath10k_warn("failed to wait for created wmi peer %pM on vdev %i: %i\n",
+ ath10k_warn(ar, "failed to wait for created wmi peer %pM on vdev %i: %i\n",
addr, vdev_id, ret);
return ret;
}
@@ -355,7 +356,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
ret = ath10k_wmi_pdev_set_param(ar, param,
ATH10K_KICKOUT_THRESHOLD);
if (ret) {
- ath10k_warn("failed to set kickout threshold on vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set kickout threshold on vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -364,7 +365,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
ATH10K_KEEPALIVE_MIN_IDLE);
if (ret) {
- ath10k_warn("failed to set keepalive minimum idle time on vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set keepalive minimum idle time on vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -373,7 +374,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
ATH10K_KEEPALIVE_MAX_IDLE);
if (ret) {
- ath10k_warn("failed to set keepalive maximum idle time on vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set keepalive maximum idle time on vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -382,7 +383,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
ATH10K_KEEPALIVE_MAX_UNRESPONSIVE);
if (ret) {
- ath10k_warn("failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -449,7 +450,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
if (peer->vdev_id != vdev_id)
continue;
- ath10k_warn("removing stale peer %pM from vdev_id %d\n",
+ ath10k_warn(ar, "removing stale peer %pM from vdev_id %d\n",
peer->addr, vdev_id);
list_del(&peer->list);
@@ -496,7 +497,7 @@ static bool ath10k_monitor_is_enabled(struct ath10k *ar)
{
lockdep_assert_held(&ar->conf_mutex);
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac monitor refs: promisc %d monitor %d cac %d\n",
ar->promisc, ar->monitor,
test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags));
@@ -531,35 +532,35 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
ret = ath10k_wmi_vdev_start(ar, &arg);
if (ret) {
- ath10k_warn("failed to request monitor vdev %i start: %d\n",
+ ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n",
vdev_id, ret);
return ret;
}
ret = ath10k_vdev_setup_sync(ar);
if (ret) {
- ath10k_warn("failed to synchronize setup for monitor vdev %i: %d\n",
+ ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i: %d\n",
vdev_id, ret);
return ret;
}
ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr);
if (ret) {
- ath10k_warn("failed to put up monitor vdev %i: %d\n",
+ ath10k_warn(ar, "failed to put up monitor vdev %i: %d\n",
vdev_id, ret);
goto vdev_stop;
}
ar->monitor_vdev_id = vdev_id;
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i started\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i started\n",
ar->monitor_vdev_id);
return 0;
vdev_stop:
ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
if (ret)
- ath10k_warn("failed to stop monitor vdev %i after start failure: %d\n",
+ ath10k_warn(ar, "failed to stop monitor vdev %i after start failure: %d\n",
ar->monitor_vdev_id, ret);
return ret;
@@ -573,20 +574,20 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar)
ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id);
if (ret)
- ath10k_warn("failed to put down monitor vdev %i: %d\n",
+ ath10k_warn(ar, "failed to put down monitor vdev %i: %d\n",
ar->monitor_vdev_id, ret);
ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
if (ret)
- ath10k_warn("failed to to request monitor vdev %i stop: %d\n",
+ ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n",
ar->monitor_vdev_id, ret);
ret = ath10k_vdev_setup_sync(ar);
if (ret)
- ath10k_warn("failed to synchronise monitor vdev %i: %d\n",
+ ath10k_warn(ar, "failed to synchronise monitor vdev %i: %d\n",
ar->monitor_vdev_id, ret);
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n",
ar->monitor_vdev_id);
return ret;
}
@@ -597,35 +598,29 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
- bit = ffs(ar->free_vdev_map);
- if (bit == 0) {
- ath10k_warn("failed to find free vdev id for monitor vdev\n");
+ if (ar->free_vdev_map == 0) {
+ ath10k_warn(ar, "failed to find free vdev id for monitor vdev\n");
return -ENOMEM;
}
+ bit = ffs(ar->free_vdev_map);
+
ar->monitor_vdev_id = bit - 1;
- ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id,
WMI_VDEV_TYPE_MONITOR,
0, ar->mac_addr);
if (ret) {
- ath10k_warn("failed to request monitor vdev %i creation: %d\n",
+ ath10k_warn(ar, "failed to request monitor vdev %i creation: %d\n",
ar->monitor_vdev_id, ret);
- goto vdev_fail;
+ return ret;
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
+ ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
ar->monitor_vdev_id);
return 0;
-
-vdev_fail:
- /*
- * Restore the ID to the global map.
- */
- ar->free_vdev_map |= 1 << (ar->monitor_vdev_id);
- return ret;
}
static int ath10k_monitor_vdev_delete(struct ath10k *ar)
@@ -636,14 +631,14 @@ static int ath10k_monitor_vdev_delete(struct ath10k *ar)
ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id);
if (ret) {
- ath10k_warn("failed to request wmi monitor vdev %i removal: %d\n",
+ ath10k_warn(ar, "failed to request wmi monitor vdev %i removal: %d\n",
ar->monitor_vdev_id, ret);
return ret;
}
- ar->free_vdev_map |= 1 << (ar->monitor_vdev_id);
+ ar->free_vdev_map |= 1 << ar->monitor_vdev_id;
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
ar->monitor_vdev_id);
return ret;
}
@@ -655,30 +650,30 @@ static int ath10k_monitor_start(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
if (!ath10k_monitor_is_enabled(ar)) {
- ath10k_warn("trying to start monitor with no references\n");
+ ath10k_warn(ar, "trying to start monitor with no references\n");
return 0;
}
if (ar->monitor_started) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor already started\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor already started\n");
return 0;
}
ret = ath10k_monitor_vdev_create(ar);
if (ret) {
- ath10k_warn("failed to create monitor vdev: %d\n", ret);
+ ath10k_warn(ar, "failed to create monitor vdev: %d\n", ret);
return ret;
}
ret = ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id);
if (ret) {
- ath10k_warn("failed to start monitor vdev: %d\n", ret);
+ ath10k_warn(ar, "failed to start monitor vdev: %d\n", ret);
ath10k_monitor_vdev_delete(ar);
return ret;
}
ar->monitor_started = true;
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor started\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor started\n");
return 0;
}
@@ -690,27 +685,27 @@ static void ath10k_monitor_stop(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
if (ath10k_monitor_is_enabled(ar)) {
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac monitor will be stopped later\n");
return;
}
if (!ar->monitor_started) {
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac monitor probably failed to start earlier\n");
return;
}
ret = ath10k_monitor_vdev_stop(ar);
if (ret)
- ath10k_warn("failed to stop monitor vdev: %d\n", ret);
+ ath10k_warn(ar, "failed to stop monitor vdev: %d\n", ret);
ret = ath10k_monitor_vdev_delete(ar);
if (ret)
- ath10k_warn("failed to delete monitor vdev: %d\n", ret);
+ ath10k_warn(ar, "failed to delete monitor vdev: %d\n", ret);
ar->monitor_started = false;
- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor stopped\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopped\n");
}
static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
@@ -743,12 +738,12 @@ static int ath10k_start_cac(struct ath10k *ar)
ret = ath10k_monitor_start(ar);
if (ret) {
- ath10k_warn("failed to start monitor (cac): %d\n", ret);
+ ath10k_warn(ar, "failed to start monitor (cac): %d\n", ret);
clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
return ret;
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n",
ar->monitor_vdev_id);
return 0;
@@ -765,7 +760,7 @@ static int ath10k_stop_cac(struct ath10k *ar)
clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
ath10k_monitor_stop(ar);
- ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac finished\n");
return 0;
}
@@ -791,12 +786,12 @@ static void ath10k_recalc_radar_detection(struct ath10k *ar)
* radiation is not allowed, make this channel DFS_UNAVAILABLE
* by indicating that radar was detected.
*/
- ath10k_warn("failed to start CAC: %d\n", ret);
+ ath10k_warn(ar, "failed to start CAC: %d\n", ret);
ieee80211_radar_detected(ar->hw);
}
}
-static int ath10k_vdev_start(struct ath10k_vif *arvif)
+static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart)
{
struct ath10k *ar = arvif->ar;
struct cfg80211_chan_def *chandef = &ar->chandef;
@@ -833,21 +828,25 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
arg.ssid_len = arvif->vif->bss_conf.ssid_len;
}
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d start center_freq %d phymode %s\n",
arg.vdev_id, arg.channel.freq,
ath10k_wmi_phymode_str(arg.channel.mode));
- ret = ath10k_wmi_vdev_start(ar, &arg);
+ if (restart)
+ ret = ath10k_wmi_vdev_restart(ar, &arg);
+ else
+ ret = ath10k_wmi_vdev_start(ar, &arg);
+
if (ret) {
- ath10k_warn("failed to start WMI vdev %i: %d\n",
+ ath10k_warn(ar, "failed to start WMI vdev %i: %d\n",
arg.vdev_id, ret);
return ret;
}
ret = ath10k_vdev_setup_sync(ar);
if (ret) {
- ath10k_warn("failed to synchronise setup for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to synchronise setup for vdev %i: %d\n",
arg.vdev_id, ret);
return ret;
}
@@ -858,6 +857,16 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
return ret;
}
+static int ath10k_vdev_start(struct ath10k_vif *arvif)
+{
+ return ath10k_vdev_start_restart(arvif, 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)
{
struct ath10k *ar = arvif->ar;
@@ -869,14 +878,14 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
if (ret) {
- ath10k_warn("failed to stop WMI vdev %i: %d\n",
+ 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("failed to syncronise setup for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to syncronise setup for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -894,6 +903,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
static void ath10k_control_beaconing(struct ath10k_vif *arvif,
struct ieee80211_bss_conf *info)
{
+ struct ath10k *ar = arvif->ar;
int ret = 0;
lockdep_assert_held(&arvif->ar->conf_mutex);
@@ -931,7 +941,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
arvif->bssid);
if (ret) {
- ath10k_warn("failed to bring up vdev %d: %i\n",
+ ath10k_warn(ar, "failed to bring up vdev %d: %i\n",
arvif->vdev_id, ret);
ath10k_vdev_stop(arvif);
return;
@@ -940,13 +950,14 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
arvif->is_started = true;
arvif->is_up = true;
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
}
static void ath10k_control_ibss(struct ath10k_vif *arvif,
struct ieee80211_bss_conf *info,
const u8 self_peer[ETH_ALEN])
{
+ struct ath10k *ar = arvif->ar;
u32 vdev_param;
int ret = 0;
@@ -955,7 +966,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
if (!info->ibss_joined) {
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer);
if (ret)
- ath10k_warn("failed to delete IBSS self peer %pM for vdev %d: %d\n",
+ 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))
@@ -964,7 +975,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
arvif->bssid);
if (ret) {
- ath10k_warn("failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
arvif->bssid, arvif->vdev_id, ret);
return;
}
@@ -976,7 +987,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer);
if (ret) {
- ath10k_warn("failed to create IBSS self peer %pM for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to create IBSS self peer %pM for vdev %d: %d\n",
self_peer, arvif->vdev_id, ret);
return;
}
@@ -985,7 +996,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param,
ATH10K_DEFAULT_ATIM);
if (ret)
- ath10k_warn("failed to set IBSS ATIM for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to set IBSS ATIM for vdev %d: %d\n",
arvif->vdev_id, ret);
}
@@ -1012,7 +1023,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
conf->dynamic_ps_timeout);
if (ret) {
- ath10k_warn("failed to set inactivity time for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to set inactivity time for vdev %d: %i\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1020,12 +1031,12 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
psmode = WMI_STA_PS_MODE_DISABLED;
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
arvif->vdev_id, psmode ? "enable" : "disable");
ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode);
if (ret) {
- ath10k_warn("failed to set PS Mode %d for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to set PS Mode %d for vdev %d: %d\n",
psmode, arvif->vdev_id, ret);
return ret;
}
@@ -1109,12 +1120,12 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
/* FIXME: base on RSN IE/WPA IE is a correct idea? */
if (rsnie || wpaie) {
- ath10k_dbg(ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__);
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__);
arg->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
}
if (wpaie) {
- ath10k_dbg(ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__);
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__);
arg->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
}
}
@@ -1223,7 +1234,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
arg->peer_num_spatial_streams = sta->rx_nss;
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
arg->addr,
arg->peer_ht_rates.num_rates,
arg->peer_num_spatial_streams);
@@ -1240,7 +1251,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
lockdep_assert_held(&ar->conf_mutex);
if (sta->wme && sta->uapsd_queues) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
sta->uapsd_queues, sta->max_sp);
if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
@@ -1265,7 +1276,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
WMI_AP_PS_PEER_PARAM_UAPSD,
uapsd);
if (ret) {
- ath10k_warn("failed to set ap ps peer param uapsd for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set ap ps peer param uapsd for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1275,7 +1286,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
WMI_AP_PS_PEER_PARAM_MAX_SP,
max_sp);
if (ret) {
- ath10k_warn("failed to set ap ps peer param max sp for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set ap ps peer param max sp for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1287,7 +1298,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr,
WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10);
if (ret) {
- ath10k_warn("failed to set ap ps peer param ageout time for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set ap ps peer param ageout time for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1334,7 +1345,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
arg->peer_vht_rates.tx_mcs_set =
__le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
- ath10k_dbg(ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
+ 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);
}
@@ -1407,7 +1418,7 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
break;
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac peer %pM phymode %s\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM phymode %s\n",
sta->addr, ath10k_wmi_phymode_str(phymode));
arg->peer_phymode = phymode;
@@ -1480,7 +1491,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);
if (!ap_sta) {
- ath10k_warn("failed to find station entry for bss %pM vdev %i\n",
+ ath10k_warn(ar, "failed to find station entry for bss %pM vdev %i\n",
bss_conf->bssid, arvif->vdev_id);
rcu_read_unlock();
return;
@@ -1493,7 +1504,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
bss_conf, &peer_arg);
if (ret) {
- ath10k_warn("failed to prepare peer assoc for %pM vdev %i: %d\n",
+ ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n",
bss_conf->bssid, arvif->vdev_id, ret);
rcu_read_unlock();
return;
@@ -1503,19 +1514,19 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
if (ret) {
- ath10k_warn("failed to run peer assoc for %pM vdev %i: %d\n",
+ ath10k_warn(ar, "failed to run peer assoc for %pM vdev %i: %d\n",
bss_conf->bssid, arvif->vdev_id, ret);
return;
}
ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap);
if (ret) {
- ath10k_warn("failed to setup peer SMPS for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to setup peer SMPS for vdev %i: %d\n",
arvif->vdev_id, ret);
return;
}
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d up (associated) bssid %pM aid %d\n",
arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
@@ -1524,7 +1535,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
if (ret) {
- ath10k_warn("failed to set vdev %d up: %d\n",
+ ath10k_warn(ar, "failed to set vdev %d up: %d\n",
arvif->vdev_id, ret);
return;
}
@@ -1550,7 +1561,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
* No idea why this happens, even though VDEV-DOWN is supposed
* to be analogous to link down, so just stop the VDEV.
*/
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
arvif->vdev_id);
/* FIXME: check return value */
@@ -1563,7 +1574,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
* interfaces as it expects there is no rx when no interface is
* running.
*/
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
/* FIXME: why don't we print error if wmi call fails? */
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
@@ -1584,7 +1595,7 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
if (ret) {
- ath10k_warn("failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
+ ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
return ret;
}
@@ -1592,14 +1603,14 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
peer_arg.peer_reassoc = reassoc;
ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
if (ret) {
- ath10k_warn("failed to run peer assoc for STA %pM vdev %i: %d\n",
+ ath10k_warn(ar, "failed to run peer assoc for STA %pM vdev %i: %d\n",
sta->addr, arvif->vdev_id, ret);
return ret;
}
ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
if (ret) {
- ath10k_warn("failed to setup peer SMPS for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1608,7 +1619,7 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
arvif->num_legacy_stations++;
ret = ath10k_recalc_rtscts_prot(arvif);
if (ret) {
- ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1616,14 +1627,14 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
if (ret) {
- ath10k_warn("failed to install peer wep keys for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
if (ret) {
- ath10k_warn("failed to set qos params for STA %pM for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n",
sta->addr, arvif->vdev_id, ret);
return ret;
}
@@ -1642,7 +1653,7 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
arvif->num_legacy_stations--;
ret = ath10k_recalc_rtscts_prot(arvif);
if (ret) {
- ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1650,7 +1661,7 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
ret = ath10k_clear_peer_keys(arvif, sta->addr);
if (ret) {
- ath10k_warn("failed to clear all peer wep keys for vdev %i: %d\n",
+ ath10k_warn(ar, "failed to clear all peer wep keys for vdev %i: %d\n",
arvif->vdev_id, ret);
return ret;
}
@@ -1742,7 +1753,7 @@ static int ath10k_update_channel_list(struct ath10k *ar)
if (WARN_ON_ONCE(ch->mode == MODE_UNKNOWN))
continue;
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"mac channel [%zd/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n",
ch - arg.channels, arg.n_channels,
ch->freq, ch->max_power, ch->max_reg_power,
@@ -1785,7 +1796,7 @@ static void ath10k_regd_update(struct ath10k *ar)
ret = ath10k_update_channel_list(ar);
if (ret)
- ath10k_warn("failed to update channel list: %d\n", ret);
+ ath10k_warn(ar, "failed to update channel list: %d\n", ret);
regpair = ar->ath_common.regulatory.regpair;
@@ -1806,7 +1817,7 @@ static void ath10k_regd_update(struct ath10k *ar)
regpair->reg_5ghz_ctl,
wmi_dfs_reg);
if (ret)
- ath10k_warn("failed to set pdev regdomain: %d\n", ret);
+ ath10k_warn(ar, "failed to set pdev regdomain: %d\n", ret);
}
static void ath10k_reg_notifier(struct wiphy *wiphy,
@@ -1819,12 +1830,12 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory);
if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
- ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
request->dfs_region);
result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector,
request->dfs_region);
if (!result)
- ath10k_warn("DFS region 0x%X not supported, will trigger radar for every pulse\n",
+ ath10k_warn(ar, "DFS region 0x%X not supported, will trigger radar for every pulse\n",
request->dfs_region);
}
@@ -1861,7 +1872,7 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar,
if (ar->monitor_started)
return ar->monitor_vdev_id;
- ath10k_warn("failed to resolve vdev id\n");
+ ath10k_warn(ar, "failed to resolve vdev id\n");
return 0;
}
@@ -1897,6 +1908,7 @@ static void ath10k_tx_wep_key_work(struct work_struct *work)
{
struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
wep_key_work);
+ struct ath10k *ar = arvif->ar;
int ret, keyidx = arvif->def_wep_key_newidx;
mutex_lock(&arvif->ar->conf_mutex);
@@ -1907,7 +1919,7 @@ static void ath10k_tx_wep_key_work(struct work_struct *work)
if (arvif->def_wep_key_idx == keyidx)
goto unlock;
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
arvif->vdev_id, keyidx);
ret = ath10k_wmi_vdev_set_param(arvif->ar,
@@ -1915,7 +1927,7 @@ static void ath10k_tx_wep_key_work(struct work_struct *work)
arvif->ar->wmi.vdev_param->def_keyid,
keyidx);
if (ret) {
- ath10k_warn("failed to update wep key index for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n",
arvif->vdev_id,
ret);
goto unlock;
@@ -1995,7 +2007,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
ar->fw_features)) {
if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >=
ATH10K_MAX_NUM_MGMT_PENDING) {
- ath10k_warn("reached WMI management tranmist queue limit\n");
+ ath10k_warn(ar, "reached WMI management transmit queue limit\n");
ret = -EBUSY;
goto exit;
}
@@ -2019,7 +2031,8 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
exit:
if (ret) {
- ath10k_warn("failed to transmit packet, dropping: %d\n", ret);
+ ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
+ ret);
ieee80211_free_txskb(ar->hw, skb);
}
}
@@ -2061,7 +2074,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
mutex_lock(&ar->conf_mutex);
- ath10k_dbg(ATH10K_DBG_MAC, "mac offchannel skb %p\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %p\n",
skb);
hdr = (struct ieee80211_hdr *)skb->data;
@@ -2074,13 +2087,13 @@ void ath10k_offchan_tx_work(struct work_struct *work)
if (peer)
/* FIXME: should this use ath10k_warn()? */
- ath10k_dbg(ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n",
peer_addr, vdev_id);
if (!peer) {
ret = ath10k_peer_create(ar, vdev_id, peer_addr);
if (ret)
- ath10k_warn("failed to create peer %pM on vdev %d: %d\n",
+ ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n",
peer_addr, vdev_id, ret);
}
@@ -2094,13 +2107,13 @@ void ath10k_offchan_tx_work(struct work_struct *work)
ret = wait_for_completion_timeout(&ar->offchan_tx_completed,
3 * HZ);
if (ret <= 0)
- ath10k_warn("timed out waiting for offchannel skb %p\n",
+ ath10k_warn(ar, "timed out waiting for offchannel skb %p\n",
skb);
if (!peer) {
ret = ath10k_peer_delete(ar, vdev_id, peer_addr);
if (ret)
- ath10k_warn("failed to delete peer %pM on vdev %d: %d\n",
+ ath10k_warn(ar, "failed to delete peer %pM on vdev %d: %d\n",
peer_addr, vdev_id, ret);
}
@@ -2134,7 +2147,7 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
ret = ath10k_wmi_mgmt_tx(ar, skb);
if (ret) {
- ath10k_warn("failed to transmit management frame via WMI: %d\n",
+ ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n",
ret);
ieee80211_free_txskb(ar->hw, skb);
}
@@ -2145,34 +2158,40 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
/* Scanning */
/************/
-/*
- * This gets called if we dont get a heart-beat during scan.
- * This may indicate the FW has hung and we need to abort the
- * scan manually to prevent cancel_hw_scan() from deadlocking
- */
-void ath10k_reset_scan(unsigned long ptr)
+void __ath10k_scan_finish(struct ath10k *ar)
{
- struct ath10k *ar = (struct ath10k *)ptr;
+ lockdep_assert_held(&ar->data_lock);
- spin_lock_bh(&ar->data_lock);
- if (!ar->scan.in_progress) {
- spin_unlock_bh(&ar->data_lock);
- return;
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ break;
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
+ if (ar->scan.is_roc)
+ ieee80211_remain_on_channel_expired(ar->hw);
+ else
+ ieee80211_scan_completed(ar->hw,
+ (ar->scan.state ==
+ ATH10K_SCAN_ABORTING));
+ /* fall through */
+ case ATH10K_SCAN_STARTING:
+ ar->scan.state = ATH10K_SCAN_IDLE;
+ ar->scan_channel = NULL;
+ ath10k_offchan_tx_purge(ar);
+ cancel_delayed_work(&ar->scan.timeout);
+ complete_all(&ar->scan.completed);
+ break;
}
+}
- ath10k_warn("scan timed out, firmware problem?\n");
-
- if (ar->scan.is_roc)
- ieee80211_remain_on_channel_expired(ar->hw);
- else
- ieee80211_scan_completed(ar->hw, 1 /* aborted */);
-
- ar->scan.in_progress = false;
- complete_all(&ar->scan.completed);
+void ath10k_scan_finish(struct ath10k *ar)
+{
+ spin_lock_bh(&ar->data_lock);
+ __ath10k_scan_finish(ar);
spin_unlock_bh(&ar->data_lock);
}
-static int ath10k_abort_scan(struct ath10k *ar)
+static int ath10k_scan_stop(struct ath10k *ar)
{
struct wmi_stop_scan_arg arg = {
.req_id = 1, /* FIXME */
@@ -2183,47 +2202,79 @@ static int ath10k_abort_scan(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
- del_timer_sync(&ar->scan.timeout);
+ ret = ath10k_wmi_stop_scan(ar, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to stop wmi scan: %d\n", ret);
+ goto out;
+ }
- spin_lock_bh(&ar->data_lock);
- if (!ar->scan.in_progress) {
- spin_unlock_bh(&ar->data_lock);
- return 0;
+ ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ);
+ if (ret == 0) {
+ ath10k_warn(ar, "failed to receive scan abortion completion: timed out\n");
+ ret = -ETIMEDOUT;
+ } else if (ret > 0) {
+ ret = 0;
}
- ar->scan.aborting = true;
+out:
+ /* Scan state should be updated upon scan completion but in case
+ * firmware fails to deliver the event (for whatever reason) it is
+ * desired to clean up scan state anyway. Firmware may have just
+ * dropped the scan completion event delivery due to transport pipe
+ * being overflown with data and/or it can recover on its own before
+ * next scan request is submitted.
+ */
+ spin_lock_bh(&ar->data_lock);
+ if (ar->scan.state != ATH10K_SCAN_IDLE)
+ __ath10k_scan_finish(ar);
spin_unlock_bh(&ar->data_lock);
- ret = ath10k_wmi_stop_scan(ar, &arg);
- if (ret) {
- ath10k_warn("failed to stop wmi scan: %d\n", ret);
- spin_lock_bh(&ar->data_lock);
- ar->scan.in_progress = false;
- ath10k_offchan_tx_purge(ar);
- spin_unlock_bh(&ar->data_lock);
- return -EIO;
- }
+ return ret;
+}
- ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ);
- if (ret == 0)
- ath10k_warn("timed out while waiting for scan to stop\n");
+static void ath10k_scan_abort(struct ath10k *ar)
+{
+ int ret;
- /* scan completion may be done right after we timeout here, so let's
- * check the in_progress and tell mac80211 scan is completed. if we
- * don't do that and FW fails to send us scan completion indication
- * then userspace won't be able to scan anymore */
- ret = 0;
+ lockdep_assert_held(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
- if (ar->scan.in_progress) {
- ath10k_warn("failed to stop scan, it's still in progress\n");
- ar->scan.in_progress = false;
- ath10k_offchan_tx_purge(ar);
- ret = -ETIMEDOUT;
+
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ /* This can happen if timeout worker kicked in and called
+ * abortion while scan completion was being processed.
+ */
+ break;
+ case ATH10K_SCAN_STARTING:
+ case ATH10K_SCAN_ABORTING:
+ ath10k_warn(ar, "refusing scan abortion due to invalid scan state: %s (%d)\n",
+ ath10k_scan_state_str(ar->scan.state),
+ ar->scan.state);
+ break;
+ case ATH10K_SCAN_RUNNING:
+ ar->scan.state = ATH10K_SCAN_ABORTING;
+ spin_unlock_bh(&ar->data_lock);
+
+ ret = ath10k_scan_stop(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to abort scan: %d\n", ret);
+
+ spin_lock_bh(&ar->data_lock);
+ break;
}
+
spin_unlock_bh(&ar->data_lock);
+}
- return ret;
+void ath10k_scan_timeout_work(struct work_struct *work)
+{
+ struct ath10k *ar = container_of(work, struct ath10k,
+ scan.timeout.work);
+
+ mutex_lock(&ar->conf_mutex);
+ ath10k_scan_abort(ar);
+ mutex_unlock(&ar->conf_mutex);
}
static int ath10k_start_scan(struct ath10k *ar,
@@ -2239,17 +2290,16 @@ static int ath10k_start_scan(struct ath10k *ar,
ret = wait_for_completion_timeout(&ar->scan.started, 1*HZ);
if (ret == 0) {
- ath10k_abort_scan(ar);
- return ret;
+ ret = ath10k_scan_stop(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to stop scan: %d\n", ret);
+
+ return -ETIMEDOUT;
}
- /* the scan can complete earlier, before we even
- * start the timer. in that case the timer handler
- * checks ar->scan.in_progress and bails out if its
- * false. Add a 200ms margin to account event/command
- * processing. */
- mod_timer(&ar->scan.timeout, jiffies +
- msecs_to_jiffies(arg->max_scan_time+200));
+ /* Add a 200ms margin to account for event/command processing */
+ ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
+ msecs_to_jiffies(arg->max_scan_time+200));
return 0;
}
@@ -2269,7 +2319,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
/* We should disable CCK RATE due to P2P */
if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
- ath10k_dbg(ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
+ 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.tid = ath10k_tx_h_get_tid(hdr);
@@ -2289,7 +2339,8 @@ static void ath10k_tx(struct ieee80211_hw *hw,
ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id;
spin_unlock_bh(&ar->data_lock);
- ath10k_dbg(ATH10K_DBG_MAC, "queued offchannel skb %p\n", skb);
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
+ skb);
skb_queue_tail(&ar->offchan_tx_queue, skb);
ieee80211_queue_work(hw, &ar->offchan_tx_work);
@@ -2325,8 +2376,7 @@ void ath10k_halt(struct ath10k *ar)
ath10k_monitor_stop(ar);
}
- del_timer_sync(&ar->scan.timeout);
- ath10k_reset_scan((unsigned long)ar);
+ ath10k_scan_finish(ar);
ath10k_peer_cleanup_all(ar);
ath10k_core_stop(ar);
ath10k_hif_power_down(ar);
@@ -2380,7 +2430,7 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->tx_chain_mask,
tx_ant);
if (ret) {
- ath10k_warn("failed to set tx-chainmask: %d, req 0x%x\n",
+ ath10k_warn(ar, "failed to set tx-chainmask: %d, req 0x%x\n",
ret, tx_ant);
return ret;
}
@@ -2388,7 +2438,7 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rx_chain_mask,
rx_ant);
if (ret) {
- ath10k_warn("failed to set rx-chainmask: %d, req 0x%x\n",
+ ath10k_warn(ar, "failed to set rx-chainmask: %d, req 0x%x\n",
ret, rx_ant);
return ret;
}
@@ -2439,25 +2489,25 @@ static int ath10k_start(struct ieee80211_hw *hw)
ret = ath10k_hif_power_up(ar);
if (ret) {
- ath10k_err("Could not init hif: %d\n", ret);
+ ath10k_err(ar, "Could not init hif: %d\n", ret);
goto err_off;
}
ret = ath10k_core_start(ar);
if (ret) {
- ath10k_err("Could not init core: %d\n", ret);
+ ath10k_err(ar, "Could not init core: %d\n", ret);
goto err_power_down;
}
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1);
if (ret) {
- ath10k_warn("failed to enable PMF QOS: %d\n", ret);
+ ath10k_warn(ar, "failed to enable PMF QOS: %d\n", ret);
goto err_core_stop;
}
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1);
if (ret) {
- ath10k_warn("failed to enable dynamic BW: %d\n", ret);
+ ath10k_warn(ar, "failed to enable dynamic BW: %d\n", ret);
goto err_core_stop;
}
@@ -2477,7 +2527,7 @@ static int ath10k_start(struct ieee80211_hw *hw)
ret = ath10k_wmi_pdev_set_param(ar,
ar->wmi.pdev_param->arp_ac_override, 0);
if (ret) {
- ath10k_warn("failed to set arp ac override parameter: %d\n",
+ ath10k_warn(ar, "failed to set arp ac override parameter: %d\n",
ret);
goto err_core_stop;
}
@@ -2485,6 +2535,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
ar->num_started_vdevs = 0;
ath10k_regd_update(ar);
+ ath10k_spectral_start(ar);
+
mutex_unlock(&ar->conf_mutex);
return 0;
@@ -2515,6 +2567,7 @@ static void ath10k_stop(struct ieee80211_hw *hw)
}
mutex_unlock(&ar->conf_mutex);
+ cancel_delayed_work_sync(&ar->scan.timeout);
cancel_work_sync(&ar->restart_work);
}
@@ -2528,7 +2581,7 @@ static int ath10k_config_ps(struct ath10k *ar)
list_for_each_entry(arvif, &ar->arvifs, list) {
ret = ath10k_mac_vif_setup_ps(arvif);
if (ret) {
- ath10k_warn("failed to setup powersave: %d\n", ret);
+ ath10k_warn(ar, "failed to setup powersave: %d\n", ret);
break;
}
}
@@ -2566,7 +2619,7 @@ static void ath10k_config_chan(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
- ath10k_dbg(ATH10K_DBG_MAC,
+ 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,
@@ -2582,18 +2635,21 @@ static void ath10k_config_chan(struct ath10k *ar)
if (!arvif->is_started)
continue;
+ if (!arvif->is_up)
+ continue;
+
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
continue;
- ret = ath10k_vdev_stop(arvif);
+ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
if (ret) {
- ath10k_warn("failed to stop vdev %d: %d\n",
+ ath10k_warn(ar, "failed to down vdev %d: %d\n",
arvif->vdev_id, ret);
continue;
}
}
- /* all vdevs are now stopped - now attempt to restart them */
+ /* all vdevs are downed now - attempt to restart and re-up them */
list_for_each_entry(arvif, &ar->arvifs, list) {
if (!arvif->is_started)
@@ -2602,9 +2658,9 @@ static void ath10k_config_chan(struct ath10k *ar)
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
continue;
- ret = ath10k_vdev_start(arvif);
+ ret = ath10k_vdev_restart(arvif);
if (ret) {
- ath10k_warn("failed to start vdev %d: %d\n",
+ ath10k_warn(ar, "failed to restart vdev %d: %d\n",
arvif->vdev_id, ret);
continue;
}
@@ -2615,7 +2671,7 @@ static void ath10k_config_chan(struct ath10k *ar)
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
arvif->bssid);
if (ret) {
- ath10k_warn("failed to bring vdev up %d: %d\n",
+ ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
arvif->vdev_id, ret);
continue;
}
@@ -2635,7 +2691,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&ar->conf_mutex);
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- ath10k_dbg(ATH10K_DBG_MAC,
+ 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,
@@ -2655,21 +2711,21 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac config power %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac config power %d\n",
hw->conf.power_level);
param = ar->wmi.pdev_param->txpower_limit2g;
ret = ath10k_wmi_pdev_set_param(ar, param,
hw->conf.power_level * 2);
if (ret)
- ath10k_warn("failed to set 2g txpower %d: %d\n",
+ ath10k_warn(ar, "failed to set 2g txpower %d: %d\n",
hw->conf.power_level, ret);
param = ar->wmi.pdev_param->txpower_limit5g;
ret = ath10k_wmi_pdev_set_param(ar, param,
hw->conf.power_level * 2);
if (ret)
- ath10k_warn("failed to set 5g txpower %d: %d\n",
+ ath10k_warn(ar, "failed to set 5g txpower %d: %d\n",
hw->conf.power_level, ret);
}
@@ -2681,7 +2737,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
ar->monitor = true;
ret = ath10k_monitor_start(ar);
if (ret) {
- ath10k_warn("failed to start monitor (config): %d\n",
+ ath10k_warn(ar, "failed to start monitor (config): %d\n",
ret);
ar->monitor = false;
}
@@ -2724,11 +2780,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work);
INIT_LIST_HEAD(&arvif->list);
- bit = ffs(ar->free_vdev_map);
- if (bit == 0) {
+ if (ar->free_vdev_map == 0) {
+ ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n");
ret = -EBUSY;
goto err;
}
+ bit = ffs(ar->free_vdev_map);
arvif->vdev_id = bit - 1;
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
@@ -2760,25 +2817,25 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
break;
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype);
ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,
arvif->vdev_subtype, vif->addr);
if (ret) {
- ath10k_warn("failed to create WMI vdev %i: %d\n",
+ ath10k_warn(ar, "failed to create WMI vdev %i: %d\n",
arvif->vdev_id, ret);
goto err;
}
- ar->free_vdev_map &= ~BIT(arvif->vdev_id);
+ ar->free_vdev_map &= ~(1 << arvif->vdev_id);
list_add(&arvif->list, &ar->arvifs);
vdev_param = ar->wmi.vdev_param->def_keyid;
ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param,
arvif->def_wep_key_idx);
if (ret) {
- ath10k_warn("failed to set vdev %i default key id: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i default key id: %d\n",
arvif->vdev_id, ret);
goto err_vdev_delete;
}
@@ -2788,7 +2845,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ATH10K_HW_TXRX_NATIVE_WIFI);
/* 10.X firmware does not support this VDEV parameter. Do not warn */
if (ret && ret != -EOPNOTSUPP) {
- ath10k_warn("failed to set vdev %i TX encapsulation: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i TX encapsulation: %d\n",
arvif->vdev_id, ret);
goto err_vdev_delete;
}
@@ -2796,14 +2853,14 @@ 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 (ret) {
- ath10k_warn("failed to create vdev %i peer for AP: %d\n",
+ ath10k_warn(ar, "failed to create vdev %i peer for AP: %d\n",
arvif->vdev_id, ret);
goto err_vdev_delete;
}
ret = ath10k_mac_set_kickout(arvif);
if (ret) {
- ath10k_warn("failed to set vdev %i kickout parameters: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i kickout parameters: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
@@ -2815,7 +2872,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
param, value);
if (ret) {
- ath10k_warn("failed to set vdev %i RX wake policy: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i RX wake policy: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
@@ -2825,7 +2882,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
param, value);
if (ret) {
- ath10k_warn("failed to set vdev %i TX wake thresh: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i TX wake thresh: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
@@ -2835,7 +2892,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
param, value);
if (ret) {
- ath10k_warn("failed to set vdev %i PSPOLL count: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i PSPOLL count: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
@@ -2843,14 +2900,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold);
if (ret) {
- ath10k_warn("failed to set rts threshold for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold);
if (ret) {
- ath10k_warn("failed to set frag threshold for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to set frag threshold for vdev %d: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
@@ -2864,7 +2921,7 @@ err_peer_delete:
err_vdev_delete:
ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
- ar->free_vdev_map &= ~BIT(arvif->vdev_id);
+ ar->free_vdev_map |= 1 << arvif->vdev_id;
list_del(&arvif->list);
err:
@@ -2892,26 +2949,32 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
dev_kfree_skb_any(arvif->beacon);
arvif->beacon = NULL;
}
+
spin_unlock_bh(&ar->data_lock);
- ar->free_vdev_map |= 1 << (arvif->vdev_id);
+ ret = ath10k_spectral_vif_stop(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n",
+ arvif->vdev_id, ret);
+
+ ar->free_vdev_map |= 1 << arvif->vdev_id;
list_del(&arvif->list);
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr);
if (ret)
- ath10k_warn("failed to remove peer for AP vdev %i: %d\n",
+ ath10k_warn(ar, "failed to remove peer for AP vdev %i: %d\n",
arvif->vdev_id, ret);
kfree(arvif->u.ap.noa_data);
}
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n",
arvif->vdev_id);
ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
if (ret)
- ath10k_warn("failed to delete WMI vdev %i: %d\n",
+ ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n",
arvif->vdev_id, ret);
ath10k_peer_cleanup(ar, arvif->vdev_id);
@@ -2950,7 +3013,7 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw,
ar->promisc = true;
ret = ath10k_monitor_start(ar);
if (ret) {
- ath10k_warn("failed to start monitor (promisc): %d\n",
+ ath10k_warn(ar, "failed to start monitor (promisc): %d\n",
ret);
ar->promisc = false;
}
@@ -2982,17 +3045,17 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
vdev_param = ar->wmi.vdev_param->beacon_interval;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
arvif->beacon_interval);
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d beacon_interval %d\n",
arvif->vdev_id, arvif->beacon_interval);
if (ret)
- ath10k_warn("failed to set beacon interval for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to set beacon interval for vdev %d: %i\n",
arvif->vdev_id, ret);
}
if (changed & BSS_CHANGED_BEACON) {
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"vdev %d set beacon tx mode to staggered\n",
arvif->vdev_id);
@@ -3000,14 +3063,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ret = ath10k_wmi_pdev_set_param(ar, pdev_param,
WMI_BEACON_STAGGERED_MODE);
if (ret)
- ath10k_warn("failed to set beacon mode for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n",
arvif->vdev_id, ret);
}
if (changed & BSS_CHANGED_BEACON_INFO) {
arvif->dtim_period = info->dtim_period;
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d dtim_period %d\n",
arvif->vdev_id, arvif->dtim_period);
@@ -3015,7 +3078,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
arvif->dtim_period);
if (ret)
- ath10k_warn("failed to set dtim period for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to set dtim period for vdev %d: %i\n",
arvif->vdev_id, ret);
}
@@ -3034,14 +3097,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BSSID &&
vif->type != NL80211_IFTYPE_AP) {
if (!is_zero_ether_addr(info->bssid)) {
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d create peer %pM\n",
arvif->vdev_id, info->bssid);
ret = ath10k_peer_create(ar, arvif->vdev_id,
info->bssid);
if (ret)
- ath10k_warn("failed to add peer %pM for vdev %d when changing bssid: %i\n",
+ ath10k_warn(ar, "failed to add peer %pM for vdev %d when changing bssid: %i\n",
info->bssid, arvif->vdev_id, ret);
if (vif->type == NL80211_IFTYPE_STATION) {
@@ -3051,13 +3114,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
*/
memcpy(arvif->bssid, info->bssid, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d start %pM\n",
arvif->vdev_id, info->bssid);
ret = ath10k_vdev_start(arvif);
if (ret) {
- ath10k_warn("failed to start vdev %i: %d\n",
+ ath10k_warn(ar, "failed to start vdev %i: %d\n",
arvif->vdev_id, ret);
goto exit;
}
@@ -3081,12 +3144,12 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
arvif->use_cts_prot = info->use_cts_prot;
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
arvif->vdev_id, info->use_cts_prot);
ret = ath10k_recalc_rtscts_prot(arvif);
if (ret)
- ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
arvif->vdev_id, ret);
}
@@ -3098,14 +3161,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
else
slottime = WMI_VDEV_SLOT_TIME_LONG; /* 20us */
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n",
arvif->vdev_id, slottime);
vdev_param = ar->wmi.vdev_param->slot_time;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
slottime);
if (ret)
- ath10k_warn("failed to set erp slot for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to set erp slot for vdev %d: %i\n",
arvif->vdev_id, ret);
}
@@ -3116,7 +3179,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
else
preamble = WMI_VDEV_PREAMBLE_LONG;
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d preamble %dn",
arvif->vdev_id, preamble);
@@ -3124,7 +3187,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
preamble);
if (ret)
- ath10k_warn("failed to set preamble for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to set preamble for vdev %d: %i\n",
arvif->vdev_id, ret);
}
@@ -3151,20 +3214,26 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
- if (ar->scan.in_progress) {
- spin_unlock_bh(&ar->data_lock);
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ reinit_completion(&ar->scan.started);
+ reinit_completion(&ar->scan.completed);
+ ar->scan.state = ATH10K_SCAN_STARTING;
+ ar->scan.is_roc = false;
+ ar->scan.vdev_id = arvif->vdev_id;
+ ret = 0;
+ break;
+ case ATH10K_SCAN_STARTING:
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
ret = -EBUSY;
- goto exit;
+ break;
}
-
- reinit_completion(&ar->scan.started);
- reinit_completion(&ar->scan.completed);
- ar->scan.in_progress = true;
- ar->scan.aborting = false;
- ar->scan.is_roc = false;
- ar->scan.vdev_id = arvif->vdev_id;
spin_unlock_bh(&ar->data_lock);
+ if (ret)
+ goto exit;
+
memset(&arg, 0, sizeof(arg));
ath10k_wmi_start_scan_init(ar, &arg);
arg.vdev_id = arvif->vdev_id;
@@ -3196,9 +3265,9 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
ret = ath10k_start_scan(ar, &arg);
if (ret) {
- ath10k_warn("failed to start hw scan: %d\n", ret);
+ ath10k_warn(ar, "failed to start hw scan: %d\n", ret);
spin_lock_bh(&ar->data_lock);
- ar->scan.in_progress = false;
+ ar->scan.state = ATH10K_SCAN_IDLE;
spin_unlock_bh(&ar->data_lock);
}
@@ -3211,14 +3280,10 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath10k *ar = hw->priv;
- int ret;
mutex_lock(&ar->conf_mutex);
- ret = ath10k_abort_scan(ar);
- if (ret) {
- ath10k_warn("failed to abort scan: %d\n", ret);
- ieee80211_scan_completed(hw, 1 /* aborted */);
- }
+ cancel_delayed_work_sync(&ar->scan.timeout);
+ ath10k_scan_abort(ar);
mutex_unlock(&ar->conf_mutex);
}
@@ -3256,7 +3321,7 @@ static void ath10k_set_key_h_def_keyidx(struct ath10k *ar,
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
key->keyidx);
if (ret)
- ath10k_warn("failed to set vdev %i group key as default key: %d\n",
+ ath10k_warn(ar, "failed to set vdev %i group key as default key: %d\n",
arvif->vdev_id, ret);
}
@@ -3294,7 +3359,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (!peer) {
if (cmd == SET_KEY) {
- ath10k_warn("failed to install key for non-existent peer %pM\n",
+ ath10k_warn(ar, "failed to install key for non-existent peer %pM\n",
peer_addr);
ret = -EOPNOTSUPP;
goto exit;
@@ -3317,7 +3382,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = ath10k_install_key(arvif, key, cmd, peer_addr);
if (ret) {
- ath10k_warn("failed to install key for vdev %i peer %pM: %d\n",
+ ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n",
arvif->vdev_id, peer_addr, ret);
goto exit;
}
@@ -3332,7 +3397,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
peer->keys[key->keyidx] = NULL;
else if (peer == NULL)
/* impossible unless FW goes crazy */
- ath10k_warn("Peer %pM disappeared!\n", peer_addr);
+ ath10k_warn(ar, "Peer %pM disappeared!\n", peer_addr);
spin_unlock_bh(&ar->data_lock);
exit:
@@ -3368,45 +3433,45 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
mutex_lock(&ar->conf_mutex);
if (changed & IEEE80211_RC_BW_CHANGED) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
sta->addr, bw);
err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
WMI_PEER_CHAN_WIDTH, bw);
if (err)
- ath10k_warn("failed to update STA %pM peer bw %d: %d\n",
+ ath10k_warn(ar, "failed to update STA %pM peer bw %d: %d\n",
sta->addr, bw, err);
}
if (changed & IEEE80211_RC_NSS_CHANGED) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
sta->addr, nss);
err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
WMI_PEER_NSS, nss);
if (err)
- ath10k_warn("failed to update STA %pM nss %d: %d\n",
+ ath10k_warn(ar, "failed to update STA %pM nss %d: %d\n",
sta->addr, nss, err);
}
if (changed & IEEE80211_RC_SMPS_CHANGED) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
sta->addr, smps);
err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
WMI_PEER_SMPS_STATE, smps);
if (err)
- ath10k_warn("failed to update STA %pM smps %d: %d\n",
+ ath10k_warn(ar, "failed to update STA %pM smps %d: %d\n",
sta->addr, smps, err);
}
if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
sta->addr);
err = ath10k_station_assoc(ar, arvif, sta, true);
if (err)
- ath10k_warn("failed to reassociate station: %pM\n",
+ ath10k_warn(ar, "failed to reassociate station: %pM\n",
sta->addr);
}
@@ -3451,31 +3516,31 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
max_num_peers = TARGET_NUM_PEERS;
if (ar->num_peers >= max_num_peers) {
- ath10k_warn("number of peers exceeded: peers number %d (max peers %d)\n",
+ ath10k_warn(ar, "number of peers exceeded: peers number %d (max peers %d)\n",
ar->num_peers, max_num_peers);
ret = -ENOBUFS;
goto exit;
}
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d peer create %pM (new sta) num_peers %d\n",
arvif->vdev_id, sta->addr, ar->num_peers);
ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
if (ret)
- ath10k_warn("failed to add peer %pM for vdev %d when adding a new sta: %i\n",
+ ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
sta->addr, arvif->vdev_id, ret);
} else if ((old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST)) {
/*
* Existing station deletion.
*/
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d peer delete %pM (sta gone)\n",
arvif->vdev_id, sta->addr);
ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
if (ret)
- ath10k_warn("failed to delete peer %pM for vdev %d: %i\n",
+ ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
sta->addr, arvif->vdev_id, ret);
if (vif->type == NL80211_IFTYPE_STATION)
@@ -3487,12 +3552,12 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
/*
* New association.
*/
- ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM associated\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM associated\n",
sta->addr);
ret = ath10k_station_assoc(ar, arvif, sta, false);
if (ret)
- ath10k_warn("failed to associate station %pM for vdev %i: %i\n",
+ 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 &&
@@ -3501,12 +3566,12 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
/*
* Disassociation.
*/
- ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
sta->addr);
ret = ath10k_station_disassoc(ar, arvif, sta);
if (ret)
- ath10k_warn("failed to disassociate station: %pM vdev %i: %i\n",
+ ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n",
sta->addr, arvif->vdev_id, ret);
}
exit:
@@ -3554,7 +3619,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
WMI_STA_PS_PARAM_UAPSD,
arvif->u.sta.uapsd);
if (ret) {
- ath10k_warn("failed to set uapsd params: %d\n", ret);
+ ath10k_warn(ar, "failed to set uapsd params: %d\n", ret);
goto exit;
}
@@ -3567,7 +3632,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
WMI_STA_PS_PARAM_RX_WAKE_POLICY,
value);
if (ret)
- ath10k_warn("failed to set rx wake param: %d\n", ret);
+ ath10k_warn(ar, "failed to set rx wake param: %d\n", ret);
exit:
return ret;
@@ -3617,13 +3682,13 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw,
/* FIXME: FW accepts wmm params per hw, not per vif */
ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params);
if (ret) {
- ath10k_warn("failed to set wmm params: %d\n", ret);
+ ath10k_warn(ar, "failed to set wmm params: %d\n", ret);
goto exit;
}
ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
if (ret)
- ath10k_warn("failed to set sta uapsd: %d\n", ret);
+ ath10k_warn(ar, "failed to set sta uapsd: %d\n", ret);
exit:
mutex_unlock(&ar->conf_mutex);
@@ -3641,27 +3706,33 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct wmi_start_scan_arg arg;
- int ret;
+ int ret = 0;
mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
- if (ar->scan.in_progress) {
- spin_unlock_bh(&ar->data_lock);
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ reinit_completion(&ar->scan.started);
+ reinit_completion(&ar->scan.completed);
+ reinit_completion(&ar->scan.on_channel);
+ ar->scan.state = ATH10K_SCAN_STARTING;
+ ar->scan.is_roc = true;
+ ar->scan.vdev_id = arvif->vdev_id;
+ ar->scan.roc_freq = chan->center_freq;
+ ret = 0;
+ break;
+ case ATH10K_SCAN_STARTING:
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
ret = -EBUSY;
- goto exit;
+ break;
}
-
- reinit_completion(&ar->scan.started);
- reinit_completion(&ar->scan.completed);
- reinit_completion(&ar->scan.on_channel);
- ar->scan.in_progress = true;
- ar->scan.aborting = false;
- ar->scan.is_roc = true;
- ar->scan.vdev_id = arvif->vdev_id;
- ar->scan.roc_freq = chan->center_freq;
spin_unlock_bh(&ar->data_lock);
+ if (ret)
+ goto exit;
+
memset(&arg, 0, sizeof(arg));
ath10k_wmi_start_scan_init(ar, &arg);
arg.vdev_id = arvif->vdev_id;
@@ -3676,17 +3747,21 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
ret = ath10k_start_scan(ar, &arg);
if (ret) {
- ath10k_warn("failed to start roc scan: %d\n", ret);
+ ath10k_warn(ar, "failed to start roc scan: %d\n", ret);
spin_lock_bh(&ar->data_lock);
- ar->scan.in_progress = false;
+ ar->scan.state = ATH10K_SCAN_IDLE;
spin_unlock_bh(&ar->data_lock);
goto exit;
}
ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ);
if (ret == 0) {
- ath10k_warn("failed to switch to channel for roc scan\n");
- ath10k_abort_scan(ar);
+ ath10k_warn(ar, "failed to switch to channel for roc scan\n");
+
+ ret = ath10k_scan_stop(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to stop scan: %d\n", ret);
+
ret = -ETIMEDOUT;
goto exit;
}
@@ -3702,7 +3777,8 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw)
struct ath10k *ar = hw->priv;
mutex_lock(&ar->conf_mutex);
- ath10k_abort_scan(ar);
+ cancel_delayed_work_sync(&ar->scan.timeout);
+ ath10k_scan_abort(ar);
mutex_unlock(&ar->conf_mutex);
return 0;
@@ -3721,12 +3797,12 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
mutex_lock(&ar->conf_mutex);
list_for_each_entry(arvif, &ar->arvifs, list) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n",
arvif->vdev_id, value);
ret = ath10k_mac_set_rts(arvif, value);
if (ret) {
- ath10k_warn("failed to set rts threshold for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n",
arvif->vdev_id, ret);
break;
}
@@ -3744,12 +3820,12 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
mutex_lock(&ar->conf_mutex);
list_for_each_entry(arvif, &ar->arvifs, list) {
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
arvif->vdev_id, value);
ret = ath10k_mac_set_rts(arvif, value);
if (ret) {
- ath10k_warn("failed to set fragmentation threshold for vdev %d: %d\n",
+ ath10k_warn(ar, "failed to set fragmentation threshold for vdev %d: %d\n",
arvif->vdev_id, ret);
break;
}
@@ -3789,7 +3865,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}), ATH10K_FLUSH_TIMEOUT_HZ);
if (ret <= 0 || skip)
- ath10k_warn("failed to flush transmit queue (skip %i ar-state %i): %i\n",
+ ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %i\n",
skip, ar->state, ret);
skip:
@@ -3824,7 +3900,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
ret = ath10k_hif_suspend(ar);
if (ret) {
- ath10k_warn("failed to suspend hif: %d\n", ret);
+ ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
goto resume;
}
@@ -3833,7 +3909,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
resume:
ret = ath10k_wmi_pdev_resume_target(ar);
if (ret)
- ath10k_warn("failed to resume target: %d\n", ret);
+ ath10k_warn(ar, "failed to resume target: %d\n", ret);
ret = 1;
exit:
@@ -3850,14 +3926,14 @@ static int ath10k_resume(struct ieee80211_hw *hw)
ret = ath10k_hif_resume(ar);
if (ret) {
- ath10k_warn("failed to resume hif: %d\n", 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("failed to resume target: %d\n", ret);
+ ath10k_warn(ar, "failed to resume target: %d\n", ret);
ret = 1;
goto exit;
}
@@ -3878,7 +3954,7 @@ static void ath10k_restart_complete(struct ieee80211_hw *hw)
/* If device failed to restart it will be in a different state, e.g.
* ATH10K_STATE_WEDGED */
if (ar->state == ATH10K_STATE_RESTARTED) {
- ath10k_info("device successfully recovered\n");
+ ath10k_info(ar, "device successfully recovered\n");
ar->state = ATH10K_STATE_ON;
}
@@ -4075,7 +4151,8 @@ ath10k_bitrate_mask_correct(const struct cfg80211_bitrate_mask *mask,
}
static bool
-ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask,
+ath10k_bitrate_mask_rate(struct ath10k *ar,
+ const struct cfg80211_bitrate_mask *mask,
enum ieee80211_band band,
u8 *fixed_rate,
u8 *fixed_nss)
@@ -4133,7 +4210,7 @@ ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask,
nss <<= 4;
pream <<= 6;
- ath10k_dbg(ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
pream, nss, rate);
*fixed_rate = pream | nss | rate;
@@ -4141,7 +4218,8 @@ ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask,
return true;
}
-static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask,
+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)
@@ -4151,7 +4229,7 @@ static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask,
return true;
/* Next Check single rate is set */
- return ath10k_bitrate_mask_rate(mask, band, fixed_rate, fixed_nss);
+ return ath10k_bitrate_mask_rate(ar, mask, band, fixed_rate, fixed_nss);
}
static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
@@ -4171,16 +4249,16 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
goto exit;
if (fixed_rate == WMI_FIXED_RATE_NONE)
- ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
if (force_sgi)
- ath10k_dbg(ATH10K_DBG_MAC, "mac force sgi\n");
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac force sgi\n");
vdev_param = ar->wmi.vdev_param->fixed_rate;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
vdev_param, fixed_rate);
if (ret) {
- ath10k_warn("failed to set fixed rate param 0x%02x: %d\n",
+ ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n",
fixed_rate, ret);
ret = -EINVAL;
goto exit;
@@ -4193,7 +4271,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
vdev_param, fixed_nss);
if (ret) {
- ath10k_warn("failed to set fixed nss param %d: %d\n",
+ ath10k_warn(ar, "failed to set fixed nss param %d: %d\n",
fixed_nss, ret);
ret = -EINVAL;
goto exit;
@@ -4206,7 +4284,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
force_sgi);
if (ret) {
- ath10k_warn("failed to set sgi param %d: %d\n",
+ ath10k_warn(ar, "failed to set sgi param %d: %d\n",
force_sgi, ret);
ret = -EINVAL;
goto exit;
@@ -4235,14 +4313,14 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
return -EINVAL;
if (!ath10k_default_bitrate_mask(ar, band, mask)) {
- if (!ath10k_get_fixed_rate_nss(mask, band,
+ if (!ath10k_get_fixed_rate_nss(ar, mask, band,
&fixed_rate,
&fixed_nss))
return -EINVAL;
}
if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) {
- ath10k_warn("failed to force SGI usage for default rate settings\n");
+ ath10k_warn(ar, "failed to force SGI usage for default rate settings\n");
return -EINVAL;
}
@@ -4261,7 +4339,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
spin_lock_bh(&ar->data_lock);
- ath10k_dbg(ATH10K_DBG_MAC,
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
sta->addr, changed, sta->bandwidth, sta->rx_nss,
sta->smps_mode);
@@ -4280,7 +4358,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
bw = WMI_PEER_CHWIDTH_80MHZ;
break;
case IEEE80211_STA_RX_BW_160:
- ath10k_warn("Invalid bandwith %d in rc update for %pM\n",
+ ath10k_warn(ar, "Invalid bandwith %d in rc update for %pM\n",
sta->bandwidth, sta->addr);
bw = WMI_PEER_CHWIDTH_20MHZ;
break;
@@ -4307,7 +4385,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
smps = WMI_PEER_SMPS_DYNAMIC;
break;
case IEEE80211_SMPS_NUM_MODES:
- ath10k_warn("Invalid smps %d in sta rc update for %pM\n",
+ ath10k_warn(ar, "Invalid smps %d in sta rc update for %pM\n",
sta->smps_mode, sta->addr);
smps = WMI_PEER_SMPS_PS_NONE;
break;
@@ -4339,9 +4417,10 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size)
{
+ struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- ath10k_dbg(ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n",
arvif->vdev_id, sta->addr, tid, action);
switch (action) {
@@ -4489,12 +4568,12 @@ static struct ieee80211_rate ath10k_rates[] = {
#define ath10k_g_rates (ath10k_rates + 0)
#define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates))
-struct ath10k *ath10k_mac_create(void)
+struct ath10k *ath10k_mac_create(size_t priv_size)
{
struct ieee80211_hw *hw;
struct ath10k *ar;
- hw = ieee80211_alloc_hw(sizeof(struct ath10k), &ath10k_ops);
+ hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, &ath10k_ops);
if (!hw)
return NULL;
@@ -4669,7 +4748,7 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id)
ath10k_get_arvif_iter,
&arvif_iter);
if (!arvif_iter.arvif) {
- ath10k_warn("No VIF found for vdev %d\n", vdev_id);
+ ath10k_warn(ar, "No VIF found for vdev %d\n", vdev_id);
return NULL;
}
@@ -4759,7 +4838,6 @@ int ath10k_mac_register(struct ath10k *ar)
IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_HAS_RATE_CONTROL |
- IEEE80211_HW_SUPPORTS_STATIC_SMPS |
IEEE80211_HW_AP_LINK_PS |
IEEE80211_HW_SPECTRUM_MGMT;
@@ -4767,8 +4845,10 @@ int ath10k_mac_register(struct ath10k *ar)
* bytes is used for padding/alignment if necessary. */
ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4;
+ ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
+
if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
- ar->hw->flags |= IEEE80211_HW_SUPPORTS_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;
@@ -4815,19 +4895,19 @@ int ath10k_mac_register(struct ath10k *ar)
NL80211_DFS_UNSET);
if (!ar->dfs_detector)
- ath10k_warn("failed to initialise DFS pattern detector\n");
+ ath10k_warn(ar, "failed to initialise DFS pattern detector\n");
}
ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
ath10k_reg_notifier);
if (ret) {
- ath10k_err("failed to initialise regulatory: %i\n", ret);
+ ath10k_err(ar, "failed to initialise regulatory: %i\n", ret);
goto err_free;
}
ret = ieee80211_register_hw(ar->hw);
if (ret) {
- ath10k_err("failed to register ieee80211: %d\n", ret);
+ ath10k_err(ar, "failed to register ieee80211: %d\n", ret);
goto err_free;
}
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
index ef4f84376d7..6c80eeada3e 100644
--- a/drivers/net/wireless/ath/ath10k/mac.h
+++ b/drivers/net/wireless/ath/ath10k/mac.h
@@ -26,12 +26,14 @@ struct ath10k_generic_iter {
int ret;
};
-struct ath10k *ath10k_mac_create(void);
+struct ath10k *ath10k_mac_create(size_t priv_size);
void ath10k_mac_destroy(struct ath10k *ar);
int ath10k_mac_register(struct ath10k *ar);
void ath10k_mac_unregister(struct ath10k *ar);
struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id);
-void ath10k_reset_scan(unsigned long ptr);
+void __ath10k_scan_finish(struct ath10k *ar);
+void ath10k_scan_finish(struct ath10k *ar);
+void ath10k_scan_timeout_work(struct work_struct *work);
void ath10k_offchan_tx_purge(struct ath10k *ar);
void ath10k_offchan_tx_work(struct work_struct *work);
void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar);
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 3376963a486..056a35a7713 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -44,13 +44,9 @@ enum ath10k_pci_reset_mode {
ATH10K_PCI_RESET_WARM_ONLY = 1,
};
-static unsigned int ath10k_pci_target_ps;
static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO;
static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO;
-module_param_named(target_ps, ath10k_pci_target_ps, uint, 0644);
-MODULE_PARM_DESC(target_ps, "Enable ath10k Target (SoC) PS option");
-
module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644);
MODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)");
@@ -71,10 +67,7 @@ static const struct pci_device_id ath10k_pci_id_table[] = {
static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
u32 *data);
-static int ath10k_pci_post_rx(struct ath10k *ar);
-static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
- int num);
-static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
+static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
static int ath10k_pci_cold_reset(struct ath10k *ar);
static int ath10k_pci_warm_reset(struct ath10k *ar);
static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
@@ -156,79 +149,175 @@ static const struct ce_attr host_ce_config_wlan[] = {
static const struct ce_pipe_config target_ce_config_wlan[] = {
/* CE0: host->target HTC control and raw streams */
{
- .pipenum = 0,
- .pipedir = PIPEDIR_OUT,
- .nentries = 32,
- .nbytes_max = 256,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(0),
+ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(256),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* CE1: target->host HTT + HTC control */
{
- .pipenum = 1,
- .pipedir = PIPEDIR_IN,
- .nentries = 32,
- .nbytes_max = 512,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(1),
+ .pipedir = __cpu_to_le32(PIPEDIR_IN),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(512),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* CE2: target->host WMI */
{
- .pipenum = 2,
- .pipedir = PIPEDIR_IN,
- .nentries = 32,
- .nbytes_max = 2048,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(2),
+ .pipedir = __cpu_to_le32(PIPEDIR_IN),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* CE3: host->target WMI */
{
- .pipenum = 3,
- .pipedir = PIPEDIR_OUT,
- .nentries = 32,
- .nbytes_max = 2048,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(3),
+ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* CE4: host->target HTT */
{
- .pipenum = 4,
- .pipedir = PIPEDIR_OUT,
- .nentries = 256,
- .nbytes_max = 256,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(4),
+ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+ .nentries = __cpu_to_le32(256),
+ .nbytes_max = __cpu_to_le32(256),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* NB: 50% of src nentries, since tx has 2 frags */
/* CE5: unused */
{
- .pipenum = 5,
- .pipedir = PIPEDIR_OUT,
- .nentries = 32,
- .nbytes_max = 2048,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(5),
+ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* CE6: Reserved for target autonomous hif_memcpy */
{
- .pipenum = 6,
- .pipedir = PIPEDIR_INOUT,
- .nentries = 32,
- .nbytes_max = 4096,
- .flags = CE_ATTR_FLAGS,
- .reserved = 0,
+ .pipenum = __cpu_to_le32(6),
+ .pipedir = __cpu_to_le32(PIPEDIR_INOUT),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(4096),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
/* CE7 used only by Host */
};
+/*
+ * Map from service/endpoint to Copy Engine.
+ * This table is derived from the CE_PCI TABLE, above.
+ * It is passed to the Target at startup for use by firmware.
+ */
+static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(3),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(2),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(3),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(2),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(3),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(2),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(3),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(2),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(3),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(2),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(0),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(1),
+ },
+ { /* not used */
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(0),
+ },
+ { /* not used */
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(1),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
+ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
+ __cpu_to_le32(4),
+ },
+ {
+ __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
+ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
+ __cpu_to_le32(1),
+ },
+
+ /* (Additions here) */
+
+ { /* must be last */
+ __cpu_to_le32(0),
+ __cpu_to_le32(0),
+ __cpu_to_le32(0),
+ },
+};
+
static bool ath10k_pci_irq_pending(struct ath10k *ar)
{
u32 cause;
@@ -270,44 +359,111 @@ static void ath10k_pci_enable_legacy_irq(struct ath10k *ar)
PCIE_INTR_ENABLE_ADDRESS);
}
-static irqreturn_t ath10k_pci_early_irq_handler(int irq, void *arg)
+static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar)
{
- struct ath10k *ar = arg;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- if (ar_pci->num_msi_intrs == 0) {
- if (!ath10k_pci_irq_pending(ar))
- return IRQ_NONE;
-
- ath10k_pci_disable_and_clear_legacy_irq(ar);
- }
-
- tasklet_schedule(&ar_pci->early_irq_tasklet);
-
- return IRQ_HANDLED;
+ if (ar_pci->num_msi_intrs > 1)
+ return "msi-x";
+ else if (ar_pci->num_msi_intrs == 1)
+ return "msi";
+ else
+ return "legacy";
}
-static int ath10k_pci_request_early_irq(struct ath10k *ar)
+static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe)
{
+ struct ath10k *ar = pipe->hif_ce_state;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
+ struct sk_buff *skb;
+ dma_addr_t paddr;
int ret;
- /* Regardless whether MSI-X/MSI/legacy irqs have been set up the first
- * interrupt from irq vector is triggered in all cases for FW
- * indication/errors */
- ret = request_irq(ar_pci->pdev->irq, ath10k_pci_early_irq_handler,
- IRQF_SHARED, "ath10k_pci (early)", ar);
+ lockdep_assert_held(&ar_pci->ce_lock);
+
+ skb = dev_alloc_skb(pipe->buf_sz);
+ if (!skb)
+ return -ENOMEM;
+
+ WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
+
+ paddr = dma_map_single(ar->dev, skb->data,
+ skb->len + skb_tailroom(skb),
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(ar->dev, paddr))) {
+ ath10k_warn(ar, "failed to dma map pci rx buf\n");
+ dev_kfree_skb_any(skb);
+ return -EIO;
+ }
+
+ ATH10K_SKB_CB(skb)->paddr = paddr;
+
+ ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr);
if (ret) {
- ath10k_warn("failed to request early irq: %d\n", ret);
+ ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret);
+ dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb),
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skb);
return ret;
}
return 0;
}
-static void ath10k_pci_free_early_irq(struct ath10k *ar)
+static void __ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
+{
+ struct ath10k *ar = pipe->hif_ce_state;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
+ int ret, num;
+
+ lockdep_assert_held(&ar_pci->ce_lock);
+
+ if (pipe->buf_sz == 0)
+ return;
+
+ if (!ce_pipe->dest_ring)
+ return;
+
+ num = __ath10k_ce_rx_num_free_bufs(ce_pipe);
+ while (num--) {
+ ret = __ath10k_pci_rx_post_buf(pipe);
+ if (ret) {
+ ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret);
+ mod_timer(&ar_pci->rx_post_retry, jiffies +
+ ATH10K_PCI_RX_POST_RETRY_MS);
+ break;
+ }
+ }
+}
+
+static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
+{
+ struct ath10k *ar = pipe->hif_ce_state;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+ spin_lock_bh(&ar_pci->ce_lock);
+ __ath10k_pci_rx_post_pipe(pipe);
+ spin_unlock_bh(&ar_pci->ce_lock);
+}
+
+static void ath10k_pci_rx_post(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ int i;
+
+ spin_lock_bh(&ar_pci->ce_lock);
+ for (i = 0; i < CE_COUNT; i++)
+ __ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]);
+ spin_unlock_bh(&ar_pci->ce_lock);
+}
+
+static void ath10k_pci_rx_replenish_retry(unsigned long ptr)
{
- free_irq(ath10k_pci_priv(ar)->pdev->irq, ar);
+ struct ath10k *ar = (void *)ptr;
+
+ ath10k_pci_rx_post(ar);
}
/*
@@ -376,7 +532,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
nbytes = min_t(unsigned int, remaining_bytes,
DIAG_TRANSFER_LIMIT);
- ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, ce_data);
+ ret = ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data);
if (ret != 0)
goto done;
@@ -389,10 +545,8 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
* convert it from Target CPU virtual address space
* to CE address space
*/
- ath10k_pci_wake(ar);
address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem,
address);
- ath10k_pci_sleep(ar);
ret = ath10k_ce_send(ce_diag, NULL, (u32)address, nbytes, 0,
0);
@@ -448,15 +602,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
}
done:
- if (ret == 0) {
- /* Copy data from allocated DMA buf to caller's buf */
- WARN_ON_ONCE(orig_nbytes & 3);
- for (i = 0; i < orig_nbytes / sizeof(__le32); i++) {
- ((u32 *)data)[i] =
- __le32_to_cpu(((__le32 *)data_buf)[i]);
- }
- } else
- ath10k_warn("failed to read diag value at 0x%x: %d\n",
+ if (ret == 0)
+ memcpy(data, data_buf, orig_nbytes);
+ else
+ ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n",
address, ret);
if (data_buf)
@@ -466,17 +615,54 @@ done:
return ret;
}
+static int ath10k_pci_diag_read32(struct ath10k *ar, u32 address, u32 *value)
+{
+ __le32 val = 0;
+ int ret;
+
+ ret = ath10k_pci_diag_read_mem(ar, address, &val, sizeof(val));
+ *value = __le32_to_cpu(val);
+
+ return ret;
+}
+
+static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest,
+ u32 src, u32 len)
+{
+ u32 host_addr, addr;
+ int ret;
+
+ host_addr = host_interest_item_address(src);
+
+ ret = ath10k_pci_diag_read32(ar, host_addr, &addr);
+ if (ret != 0) {
+ ath10k_warn(ar, "failed to get memcpy hi address for firmware address %d: %d\n",
+ src, ret);
+ return ret;
+ }
+
+ ret = ath10k_pci_diag_read_mem(ar, addr, dest, len);
+ if (ret != 0) {
+ ath10k_warn(ar, "failed to memcpy firmware memory from %d (%d B): %d\n",
+ addr, len, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+#define ath10k_pci_diag_read_hi(ar, dest, src, len) \
+ __ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len);
+
/* Read 4-byte aligned data from Target memory or register */
static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
u32 *data)
{
/* Assume range doesn't cross this boundary */
if (address >= DRAM_BASE_ADDRESS)
- return ath10k_pci_diag_read_mem(ar, address, data, sizeof(u32));
+ return ath10k_pci_diag_read32(ar, address, data);
- ath10k_pci_wake(ar);
*data = ath10k_pci_read32(ar, address);
- ath10k_pci_sleep(ar);
return 0;
}
@@ -514,9 +700,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
}
/* Copy caller's data to allocated DMA buf */
- WARN_ON_ONCE(orig_nbytes & 3);
- for (i = 0; i < orig_nbytes / sizeof(__le32); i++)
- ((__le32 *)data_buf)[i] = __cpu_to_le32(((u32 *)data)[i]);
+ memcpy(data_buf, data, orig_nbytes);
/*
* The address supplied by the caller is in the
@@ -528,9 +712,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
* to
* CE address space
*/
- ath10k_pci_wake(ar);
address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address);
- ath10k_pci_sleep(ar);
remaining_bytes = orig_nbytes;
ce_data = ce_data_base;
@@ -539,7 +721,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT);
/* Set up to receive directly into Target(!) address */
- ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, address);
+ ret = ath10k_ce_rx_post_buf(ce_diag, NULL, address);
if (ret != 0)
goto done;
@@ -608,66 +790,46 @@ done:
}
if (ret != 0)
- ath10k_warn("failed to write diag value at 0x%x: %d\n",
+ ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n",
address, ret);
return ret;
}
+static int ath10k_pci_diag_write32(struct ath10k *ar, u32 address, u32 value)
+{
+ __le32 val = __cpu_to_le32(value);
+
+ return ath10k_pci_diag_write_mem(ar, address, &val, sizeof(val));
+}
+
/* Write 4B data to Target memory or register */
static int ath10k_pci_diag_write_access(struct ath10k *ar, u32 address,
u32 data)
{
/* Assume range doesn't cross this boundary */
if (address >= DRAM_BASE_ADDRESS)
- return ath10k_pci_diag_write_mem(ar, address, &data,
- sizeof(u32));
+ return ath10k_pci_diag_write32(ar, address, data);
- ath10k_pci_wake(ar);
ath10k_pci_write32(ar, address, data);
- ath10k_pci_sleep(ar);
return 0;
}
-static bool ath10k_pci_target_is_awake(struct ath10k *ar)
+static bool ath10k_pci_is_awake(struct ath10k *ar)
{
- void __iomem *mem = ath10k_pci_priv(ar)->mem;
- u32 val;
- val = ioread32(mem + PCIE_LOCAL_BASE_ADDRESS +
- RTC_STATE_ADDRESS);
- return (RTC_STATE_V_GET(val) == RTC_STATE_V_ON);
+ u32 val = ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS);
+
+ return RTC_STATE_V_GET(val) == RTC_STATE_V_ON;
}
-int ath10k_do_pci_wake(struct ath10k *ar)
+static int ath10k_pci_wake_wait(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- void __iomem *pci_addr = ar_pci->mem;
int tot_delay = 0;
int curr_delay = 5;
- if (atomic_read(&ar_pci->keep_awake_count) == 0) {
- /* Force AWAKE */
- iowrite32(PCIE_SOC_WAKE_V_MASK,
- pci_addr + PCIE_LOCAL_BASE_ADDRESS +
- PCIE_SOC_WAKE_ADDRESS);
- }
- atomic_inc(&ar_pci->keep_awake_count);
-
- if (ar_pci->verified_awake)
- return 0;
-
- for (;;) {
- if (ath10k_pci_target_is_awake(ar)) {
- ar_pci->verified_awake = true;
+ while (tot_delay < PCIE_WAKE_TIMEOUT) {
+ if (ath10k_pci_is_awake(ar))
return 0;
- }
-
- if (tot_delay > PCIE_WAKE_TIMEOUT) {
- ath10k_warn("target took longer %d us to wake up (awake count %d)\n",
- PCIE_WAKE_TIMEOUT,
- atomic_read(&ar_pci->keep_awake_count));
- return -ETIMEDOUT;
- }
udelay(curr_delay);
tot_delay += curr_delay;
@@ -675,20 +837,21 @@ int ath10k_do_pci_wake(struct ath10k *ar)
if (curr_delay < 50)
curr_delay += 5;
}
+
+ return -ETIMEDOUT;
}
-void ath10k_do_pci_sleep(struct ath10k *ar)
+static int ath10k_pci_wake(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- void __iomem *pci_addr = ar_pci->mem;
+ ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
+ PCIE_SOC_WAKE_V_MASK);
+ return ath10k_pci_wake_wait(ar);
+}
- if (atomic_dec_and_test(&ar_pci->keep_awake_count)) {
- /* Allow sleep */
- ar_pci->verified_awake = false;
- iowrite32(PCIE_SOC_WAKE_RESET,
- pci_addr + PCIE_LOCAL_BASE_ADDRESS +
- PCIE_SOC_WAKE_ADDRESS);
- }
+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. */
@@ -726,19 +889,17 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
unsigned int nbytes, max_nbytes;
unsigned int transfer_id;
unsigned int flags;
- int err, num_replenish = 0;
while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
&ce_data, &nbytes, &transfer_id,
&flags) == 0) {
- num_replenish++;
skb = transfer_context;
max_nbytes = skb->len + skb_tailroom(skb);
dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
max_nbytes, DMA_FROM_DEVICE);
if (unlikely(max_nbytes < nbytes)) {
- ath10k_warn("rxed more than expected (nbytes %d, max %d)",
+ ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)",
nbytes, max_nbytes);
dev_kfree_skb_any(skb);
continue;
@@ -748,12 +909,7 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
cb->rx_completion(ar, skb, pipe_info->pipe_num);
}
- err = ath10k_pci_post_rx_pipe(pipe_info, num_replenish);
- if (unlikely(err)) {
- /* FIXME: retry */
- ath10k_warn("failed to replenish CE rx ring %d (%d bufs): %d\n",
- pipe_info->pipe_num, num_replenish, err);
- }
+ ath10k_pci_rx_post_pipe(pipe_info);
}
static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
@@ -781,10 +937,10 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
}
for (i = 0; i < n_items - 1; i++) {
- ath10k_dbg(ATH10K_DBG_PCI,
+ ath10k_dbg(ar, ATH10K_DBG_PCI,
"pci tx item %d paddr 0x%08x len %d n_items %d\n",
i, items[i].paddr, items[i].len, n_items);
- ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ",
items[i].vaddr, items[i].len);
err = ath10k_ce_send_nolock(ce_pipe,
@@ -799,10 +955,10 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
/* `i` is equal to `n_items -1` after for() */
- ath10k_dbg(ATH10K_DBG_PCI,
+ ath10k_dbg(ar, ATH10K_DBG_PCI,
"pci tx item %d paddr 0x%08x len %d n_items %d\n",
i, items[i].paddr, items[i].len, n_items);
- ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
+ ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ",
items[i].vaddr, items[i].len);
err = ath10k_ce_send_nolock(ce_pipe,
@@ -829,52 +985,64 @@ static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ath10k_dbg(ATH10K_DBG_PCI, "pci hif get free queue number\n");
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get free queue number\n");
return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);
}
-static void ath10k_pci_hif_dump_area(struct ath10k *ar)
+static void ath10k_pci_dump_registers(struct ath10k *ar,
+ struct ath10k_fw_crash_data *crash_data)
{
- u32 reg_dump_area = 0;
- u32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {};
- u32 host_addr;
- int ret;
- u32 i;
+ __le32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {};
+ int i, ret;
- ath10k_err("firmware crashed!\n");
- ath10k_err("hardware name %s version 0x%x\n",
- ar->hw_params.name, ar->target_version);
- ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version);
+ lockdep_assert_held(&ar->data_lock);
- host_addr = host_interest_item_address(HI_ITEM(hi_failure_state));
- ret = ath10k_pci_diag_read_mem(ar, host_addr,
- &reg_dump_area, sizeof(u32));
+ ret = ath10k_pci_diag_read_hi(ar, &reg_dump_values[0],
+ hi_failure_state,
+ REG_DUMP_COUNT_QCA988X * sizeof(__le32));
if (ret) {
- ath10k_err("failed to read FW dump area address: %d\n", ret);
- return;
- }
-
- ath10k_err("target register Dump Location: 0x%08X\n", reg_dump_area);
-
- ret = ath10k_pci_diag_read_mem(ar, reg_dump_area,
- &reg_dump_values[0],
- REG_DUMP_COUNT_QCA988X * sizeof(u32));
- if (ret != 0) {
- ath10k_err("failed to read FW dump area: %d\n", ret);
+ ath10k_err(ar, "failed to read firmware dump area: %d\n", ret);
return;
}
BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4);
- ath10k_err("target Register Dump\n");
+ ath10k_err(ar, "firmware register dump:\n");
for (i = 0; i < REG_DUMP_COUNT_QCA988X; i += 4)
- ath10k_err("[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n",
+ ath10k_err(ar, "[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n",
i,
- reg_dump_values[i],
- reg_dump_values[i + 1],
- reg_dump_values[i + 2],
- reg_dump_values[i + 3]);
+ __le32_to_cpu(reg_dump_values[i]),
+ __le32_to_cpu(reg_dump_values[i + 1]),
+ __le32_to_cpu(reg_dump_values[i + 2]),
+ __le32_to_cpu(reg_dump_values[i + 3]));
+
+ if (!crash_data)
+ return;
+
+ for (i = 0; i < REG_DUMP_COUNT_QCA988X; i++)
+ crash_data->registers[i] = reg_dump_values[i];
+}
+
+static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
+{
+ struct ath10k_fw_crash_data *crash_data;
+ char uuid[50];
+
+ spin_lock_bh(&ar->data_lock);
+
+ crash_data = ath10k_debug_get_new_fw_crash_data(ar);
+
+ if (crash_data)
+ scnprintf(uuid, sizeof(uuid), "%pUl", &crash_data->uuid);
+ else
+ scnprintf(uuid, sizeof(uuid), "n/a");
+
+ ath10k_err(ar, "firmware crashed! (uuid %s)\n", uuid);
+ ath10k_print_driver_info(ar);
+ ath10k_pci_dump_registers(ar, crash_data);
+
+ spin_unlock_bh(&ar->data_lock);
queue_work(ar->workqueue, &ar->restart_work);
}
@@ -882,7 +1050,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
int force)
{
- ath10k_dbg(ATH10K_DBG_PCI, "pci hif send complete check\n");
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n");
if (!force) {
int resources;
@@ -910,43 +1078,12 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ath10k_dbg(ATH10K_DBG_PCI, "pci hif set callbacks\n");
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif set callbacks\n");
memcpy(&ar_pci->msg_callbacks_current, callbacks,
sizeof(ar_pci->msg_callbacks_current));
}
-static int ath10k_pci_setup_ce_irq(struct ath10k *ar)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- const struct ce_attr *attr;
- struct ath10k_pci_pipe *pipe_info;
- int pipe_num, disable_interrupts;
-
- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
- pipe_info = &ar_pci->pipe_info[pipe_num];
-
- /* Handle Diagnostic CE specially */
- if (pipe_info->ce_hdl == ar_pci->ce_diag)
- continue;
-
- attr = &host_ce_config_wlan[pipe_num];
-
- if (attr->src_nentries) {
- disable_interrupts = attr->flags & CE_ATTR_DIS_INTR;
- ath10k_ce_send_cb_register(pipe_info->ce_hdl,
- ath10k_pci_ce_send_done,
- disable_interrupts);
- }
-
- if (attr->dest_nentries)
- ath10k_ce_recv_cb_register(pipe_info->ce_hdl,
- ath10k_pci_ce_recv_data);
- }
-
- return 0;
-}
-
static void ath10k_pci_kill_tasklet(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -954,74 +1091,64 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar)
tasklet_kill(&ar_pci->intr_tq);
tasklet_kill(&ar_pci->msi_fw_err);
- tasklet_kill(&ar_pci->early_irq_tasklet);
for (i = 0; i < CE_COUNT; i++)
tasklet_kill(&ar_pci->pipe_info[i].intr);
+
+ del_timer_sync(&ar_pci->rx_post_retry);
}
-/* TODO - temporary mapping while we have too few CE's */
static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar,
u16 service_id, u8 *ul_pipe,
u8 *dl_pipe, int *ul_is_polled,
int *dl_is_polled)
{
- int ret = 0;
+ const struct service_to_pipe *entry;
+ bool ul_set = false, dl_set = false;
+ int i;
- ath10k_dbg(ATH10K_DBG_PCI, "pci hif map service\n");
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n");
/* polling for received messages not supported */
*dl_is_polled = 0;
- switch (service_id) {
- case ATH10K_HTC_SVC_ID_HTT_DATA_MSG:
- /*
- * Host->target HTT gets its own pipe, so it can be polled
- * while other pipes are interrupt driven.
- */
- *ul_pipe = 4;
- /*
- * Use the same target->host pipe for HTC ctrl, HTC raw
- * streams, and HTT.
- */
- *dl_pipe = 1;
- break;
+ for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
+ entry = &target_service_to_ce_map_wlan[i];
- case ATH10K_HTC_SVC_ID_RSVD_CTRL:
- case ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS:
- /*
- * Note: HTC_RAW_STREAMS_SVC is currently unused, and
- * HTC_CTRL_RSVD_SVC could share the same pipe as the
- * WMI services. So, if another CE is needed, change
- * this to *ul_pipe = 3, which frees up CE 0.
- */
- /* *ul_pipe = 3; */
- *ul_pipe = 0;
- *dl_pipe = 1;
- break;
-
- case ATH10K_HTC_SVC_ID_WMI_DATA_BK:
- case ATH10K_HTC_SVC_ID_WMI_DATA_BE:
- case ATH10K_HTC_SVC_ID_WMI_DATA_VI:
- case ATH10K_HTC_SVC_ID_WMI_DATA_VO:
+ if (__le32_to_cpu(entry->service_id) != service_id)
+ continue;
- case ATH10K_HTC_SVC_ID_WMI_CONTROL:
- *ul_pipe = 3;
- *dl_pipe = 2;
- break;
+ switch (__le32_to_cpu(entry->pipedir)) {
+ case PIPEDIR_NONE:
+ break;
+ case PIPEDIR_IN:
+ WARN_ON(dl_set);
+ *dl_pipe = __le32_to_cpu(entry->pipenum);
+ dl_set = true;
+ break;
+ case PIPEDIR_OUT:
+ WARN_ON(ul_set);
+ *ul_pipe = __le32_to_cpu(entry->pipenum);
+ ul_set = true;
+ break;
+ case PIPEDIR_INOUT:
+ WARN_ON(dl_set);
+ WARN_ON(ul_set);
+ *dl_pipe = __le32_to_cpu(entry->pipenum);
+ *ul_pipe = __le32_to_cpu(entry->pipenum);
+ dl_set = true;
+ ul_set = true;
+ break;
+ }
+ }
- /* pipe 5 unused */
- /* pipe 6 reserved */
- /* pipe 7 reserved */
+ if (WARN_ON(!ul_set || !dl_set))
+ return -ENOENT;
- default:
- ret = -1;
- break;
- }
*ul_is_polled =
(host_ce_config_wlan[*ul_pipe].flags & CE_ATTR_DIS_INTR) != 0;
- return ret;
+ return 0;
}
static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
@@ -1029,7 +1156,7 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
{
int ul_is_polled, dl_is_polled;
- ath10k_dbg(ATH10K_DBG_PCI, "pci hif get default pipe\n");
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n");
(void)ath10k_pci_hif_map_service_to_pipe(ar,
ATH10K_HTC_SVC_ID_RSVD_CTRL,
@@ -1039,141 +1166,48 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
&dl_is_polled);
}
-static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
- int num)
+static void ath10k_pci_irq_disable(struct ath10k *ar)
{
- struct ath10k *ar = pipe_info->hif_ce_state;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct ath10k_ce_pipe *ce_state = pipe_info->ce_hdl;
- struct sk_buff *skb;
- dma_addr_t ce_data;
- int i, ret = 0;
-
- if (pipe_info->buf_sz == 0)
- return 0;
-
- for (i = 0; i < num; i++) {
- skb = dev_alloc_skb(pipe_info->buf_sz);
- if (!skb) {
- ath10k_warn("failed to allocate skbuff for pipe %d\n",
- num);
- ret = -ENOMEM;
- goto err;
- }
-
- WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
-
- ce_data = dma_map_single(ar->dev, skb->data,
- skb->len + skb_tailroom(skb),
- DMA_FROM_DEVICE);
-
- if (unlikely(dma_mapping_error(ar->dev, ce_data))) {
- ath10k_warn("failed to DMA map sk_buff\n");
- dev_kfree_skb_any(skb);
- ret = -EIO;
- goto err;
- }
-
- ATH10K_SKB_CB(skb)->paddr = ce_data;
-
- pci_dma_sync_single_for_device(ar_pci->pdev, ce_data,
- pipe_info->buf_sz,
- PCI_DMA_FROMDEVICE);
+ int i;
- ret = ath10k_ce_recv_buf_enqueue(ce_state, (void *)skb,
- ce_data);
- if (ret) {
- ath10k_warn("failed to enqueue to pipe %d: %d\n",
- num, ret);
- goto err;
- }
- }
+ ath10k_ce_disable_interrupts(ar);
- return ret;
+ /* Regardless how many interrupts were assigned for MSI the first one
+ * is always used for firmware indications (crashes). There's no way to
+ * mask the irq in the device so call disable_irq(). Legacy (shared)
+ * interrupts can be masked on the device though.
+ */
+ if (ar_pci->num_msi_intrs > 0)
+ disable_irq(ar_pci->pdev->irq);
+ else
+ ath10k_pci_disable_and_clear_legacy_irq(ar);
-err:
- ath10k_pci_rx_pipe_cleanup(pipe_info);
- return ret;
+ for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
+ synchronize_irq(ar_pci->pdev->irq + i);
}
-static int ath10k_pci_post_rx(struct ath10k *ar)
+static void ath10k_pci_irq_enable(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct ath10k_pci_pipe *pipe_info;
- const struct ce_attr *attr;
- int pipe_num, ret = 0;
- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
- pipe_info = &ar_pci->pipe_info[pipe_num];
- attr = &host_ce_config_wlan[pipe_num];
-
- if (attr->dest_nentries == 0)
- continue;
-
- ret = ath10k_pci_post_rx_pipe(pipe_info,
- attr->dest_nentries - 1);
- if (ret) {
- ath10k_warn("failed to post RX buffer for pipe %d: %d\n",
- pipe_num, ret);
-
- for (; pipe_num >= 0; pipe_num--) {
- pipe_info = &ar_pci->pipe_info[pipe_num];
- ath10k_pci_rx_pipe_cleanup(pipe_info);
- }
- return ret;
- }
- }
+ ath10k_ce_enable_interrupts(ar);
- return 0;
+ /* See comment in ath10k_pci_irq_disable() */
+ if (ar_pci->num_msi_intrs > 0)
+ enable_irq(ar_pci->pdev->irq);
+ else
+ ath10k_pci_enable_legacy_irq(ar);
}
static int ath10k_pci_hif_start(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- int ret, ret_early;
-
- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n");
-
- ath10k_pci_free_early_irq(ar);
- ath10k_pci_kill_tasklet(ar);
-
- ret = ath10k_pci_request_irq(ar);
- if (ret) {
- ath10k_warn("failed to post RX buffers for all pipes: %d\n",
- ret);
- goto err_early_irq;
- }
-
- ret = ath10k_pci_setup_ce_irq(ar);
- if (ret) {
- ath10k_warn("failed to setup CE interrupts: %d\n", ret);
- goto err_stop;
- }
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
- /* Post buffers once to start things off. */
- ret = ath10k_pci_post_rx(ar);
- if (ret) {
- ath10k_warn("failed to post RX buffers for all pipes: %d\n",
- ret);
- goto err_stop;
- }
+ ath10k_pci_irq_enable(ar);
+ ath10k_pci_rx_post(ar);
- ar_pci->started = 1;
return 0;
-
-err_stop:
- ath10k_ce_disable_interrupts(ar);
- ath10k_pci_free_irq(ar);
- ath10k_pci_kill_tasklet(ar);
-err_early_irq:
- /* Though there should be no interrupts (device was reset)
- * power_down() expects the early IRQ to be installed as per the
- * driver lifecycle. */
- ret_early = ath10k_pci_request_early_irq(ar);
- if (ret_early)
- ath10k_warn("failed to re-enable early irq: %d\n", ret_early);
-
- return ret;
}
static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
@@ -1193,10 +1227,6 @@ static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
ar = pipe_info->hif_ce_state;
ar_pci = ath10k_pci_priv(ar);
-
- if (!ar_pci->started)
- return;
-
ce_hdl = pipe_info->ce_hdl;
while (ath10k_ce_revoke_recv_next(ce_hdl, (void **)&netbuf,
@@ -1227,10 +1257,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
ar = pipe_info->hif_ce_state;
ar_pci = ath10k_pci_priv(ar);
-
- if (!ar_pci->started)
- return;
-
ce_hdl = pipe_info->ce_hdl;
while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf,
@@ -1275,41 +1301,24 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar)
ath10k_ce_deinit_pipe(ar, i);
}
-static void ath10k_pci_hif_stop(struct ath10k *ar)
+static void ath10k_pci_flush(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- int ret;
-
- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n");
-
- if (WARN_ON(!ar_pci->started))
- return;
-
- ret = ath10k_ce_disable_interrupts(ar);
- if (ret)
- ath10k_warn("failed to disable CE interrupts: %d\n", ret);
-
- ath10k_pci_free_irq(ar);
ath10k_pci_kill_tasklet(ar);
+ ath10k_pci_buffer_cleanup(ar);
+}
- ret = ath10k_pci_request_early_irq(ar);
- if (ret)
- ath10k_warn("failed to re-enable early irq: %d\n", ret);
-
- /* At this point, asynchronous threads are stopped, the target should
- * not DMA nor interrupt. We process the leftovers and then free
- * everything else up. */
+static void ath10k_pci_hif_stop(struct ath10k *ar)
+{
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
- ath10k_pci_buffer_cleanup(ar);
+ ath10k_pci_irq_disable(ar);
+ ath10k_pci_flush(ar);
- /* Make the sure the device won't access any structures on the host by
- * resetting it. The device was fed with PCI CE ringbuffer
- * configuration during init. If ringbuffers are freed and the device
- * were to access them this could lead to memory corruption on the
- * host. */
+ /* Most likely the device has HTT Rx ring configured. The only way to
+ * prevent the device from accessing (and possible corrupting) host
+ * memory is to reset the chip now.
+ */
ath10k_pci_warm_reset(ar);
-
- ar_pci->started = 0;
}
static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
@@ -1360,7 +1369,7 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
xfer.wait_for_resp = true;
xfer.resp_len = 0;
- ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr);
+ ath10k_ce_rx_post_buf(ce_rx, &xfer, resp_paddr);
}
ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0);
@@ -1418,6 +1427,7 @@ static void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state)
static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
{
+ struct ath10k *ar = ce_state->ar;
struct bmi_xfer *xfer;
u32 ce_data;
unsigned int nbytes;
@@ -1429,7 +1439,7 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
return;
if (!xfer->wait_for_resp) {
- ath10k_warn("unexpected: BMI data received; ignoring\n");
+ ath10k_warn(ar, "unexpected: BMI data received; ignoring\n");
return;
}
@@ -1457,102 +1467,6 @@ static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
}
/*
- * Map from service/endpoint to Copy Engine.
- * This table is derived from the CE_PCI TABLE, above.
- * It is passed to the Target at startup for use by firmware.
- */
-static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_VO,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 3,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_VO,
- PIPEDIR_IN, /* in = DL = target -> host */
- 2,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_BK,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 3,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_BK,
- PIPEDIR_IN, /* in = DL = target -> host */
- 2,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_BE,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 3,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_BE,
- PIPEDIR_IN, /* in = DL = target -> host */
- 2,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_VI,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 3,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_DATA_VI,
- PIPEDIR_IN, /* in = DL = target -> host */
- 2,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_CONTROL,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 3,
- },
- {
- ATH10K_HTC_SVC_ID_WMI_CONTROL,
- PIPEDIR_IN, /* in = DL = target -> host */
- 2,
- },
- {
- ATH10K_HTC_SVC_ID_RSVD_CTRL,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 0, /* could be moved to 3 (share with WMI) */
- },
- {
- ATH10K_HTC_SVC_ID_RSVD_CTRL,
- PIPEDIR_IN, /* in = DL = target -> host */
- 1,
- },
- {
- ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */
- PIPEDIR_OUT, /* out = UL = host -> target */
- 0,
- },
- {
- ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */
- PIPEDIR_IN, /* in = DL = target -> host */
- 1,
- },
- {
- ATH10K_HTC_SVC_ID_HTT_DATA_MSG,
- PIPEDIR_OUT, /* out = UL = host -> target */
- 4,
- },
- {
- ATH10K_HTC_SVC_ID_HTT_DATA_MSG,
- PIPEDIR_IN, /* in = DL = target -> host */
- 1,
- },
-
- /* (Additions here) */
-
- { /* Must be last */
- 0,
- 0,
- 0,
- },
-};
-
-/*
* Send an interrupt to the device to wake up the Target CPU
* so it has an opportunity to notice any changed state.
*/
@@ -1565,7 +1479,7 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar)
CORE_CTRL_ADDRESS,
&core_ctrl);
if (ret) {
- ath10k_warn("failed to read core_ctrl: %d\n", ret);
+ ath10k_warn(ar, "failed to read core_ctrl: %d\n", ret);
return ret;
}
@@ -1576,7 +1490,7 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar)
CORE_CTRL_ADDRESS,
core_ctrl);
if (ret) {
- ath10k_warn("failed to set target CPU interrupt mask: %d\n",
+ ath10k_warn(ar, "failed to set target CPU interrupt mask: %d\n",
ret);
return ret;
}
@@ -1605,13 +1519,13 @@ static int ath10k_pci_init_config(struct ath10k *ar)
ret = ath10k_pci_diag_read_access(ar, interconnect_targ_addr,
&pcie_state_targ_addr);
if (ret != 0) {
- ath10k_err("Failed to get pcie state addr: %d\n", ret);
+ ath10k_err(ar, "Failed to get pcie state addr: %d\n", ret);
return ret;
}
if (pcie_state_targ_addr == 0) {
ret = -EIO;
- ath10k_err("Invalid pcie state addr\n");
+ ath10k_err(ar, "Invalid pcie state addr\n");
return ret;
}
@@ -1620,13 +1534,13 @@ static int ath10k_pci_init_config(struct ath10k *ar)
pipe_cfg_addr),
&pipe_cfg_targ_addr);
if (ret != 0) {
- ath10k_err("Failed to get pipe cfg addr: %d\n", ret);
+ ath10k_err(ar, "Failed to get pipe cfg addr: %d\n", ret);
return ret;
}
if (pipe_cfg_targ_addr == 0) {
ret = -EIO;
- ath10k_err("Invalid pipe cfg addr\n");
+ ath10k_err(ar, "Invalid pipe cfg addr\n");
return ret;
}
@@ -1635,7 +1549,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
sizeof(target_ce_config_wlan));
if (ret != 0) {
- ath10k_err("Failed to write pipe cfg: %d\n", ret);
+ ath10k_err(ar, "Failed to write pipe cfg: %d\n", ret);
return ret;
}
@@ -1644,13 +1558,13 @@ static int ath10k_pci_init_config(struct ath10k *ar)
svc_to_pipe_map),
&svc_to_pipe_map);
if (ret != 0) {
- ath10k_err("Failed to get svc/pipe map: %d\n", ret);
+ ath10k_err(ar, "Failed to get svc/pipe map: %d\n", ret);
return ret;
}
if (svc_to_pipe_map == 0) {
ret = -EIO;
- ath10k_err("Invalid svc_to_pipe map\n");
+ ath10k_err(ar, "Invalid svc_to_pipe map\n");
return ret;
}
@@ -1658,7 +1572,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
target_service_to_ce_map_wlan,
sizeof(target_service_to_ce_map_wlan));
if (ret != 0) {
- ath10k_err("Failed to write svc/pipe map: %d\n", ret);
+ ath10k_err(ar, "Failed to write svc/pipe map: %d\n", ret);
return ret;
}
@@ -1667,18 +1581,17 @@ static int ath10k_pci_init_config(struct ath10k *ar)
config_flags),
&pcie_config_flags);
if (ret != 0) {
- ath10k_err("Failed to get pcie config_flags: %d\n", ret);
+ ath10k_err(ar, "Failed to get pcie config_flags: %d\n", ret);
return ret;
}
pcie_config_flags &= ~PCIE_CONFIG_FLAG_ENABLE_L1;
- ret = ath10k_pci_diag_write_mem(ar, pcie_state_targ_addr +
+ ret = ath10k_pci_diag_write_access(ar, pcie_state_targ_addr +
offsetof(struct pcie_state, config_flags),
- &pcie_config_flags,
- sizeof(pcie_config_flags));
+ pcie_config_flags);
if (ret != 0) {
- ath10k_err("Failed to write pcie config_flags: %d\n", ret);
+ ath10k_err(ar, "Failed to write pcie config_flags: %d\n", ret);
return ret;
}
@@ -1687,7 +1600,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
ret = ath10k_pci_diag_read_access(ar, ealloc_targ_addr, &ealloc_value);
if (ret != 0) {
- ath10k_err("Faile to get early alloc val: %d\n", ret);
+ ath10k_err(ar, "Faile to get early alloc val: %d\n", ret);
return ret;
}
@@ -1699,7 +1612,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
ret = ath10k_pci_diag_write_access(ar, ealloc_targ_addr, ealloc_value);
if (ret != 0) {
- ath10k_err("Failed to set early alloc val: %d\n", ret);
+ ath10k_err(ar, "Failed to set early alloc val: %d\n", ret);
return ret;
}
@@ -1708,7 +1621,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
ret = ath10k_pci_diag_read_access(ar, flag2_targ_addr, &flag2_value);
if (ret != 0) {
- ath10k_err("Failed to get option val: %d\n", ret);
+ ath10k_err(ar, "Failed to get option val: %d\n", ret);
return ret;
}
@@ -1716,7 +1629,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
ret = ath10k_pci_diag_write_access(ar, flag2_targ_addr, flag2_value);
if (ret != 0) {
- ath10k_err("Failed to set option val: %d\n", ret);
+ ath10k_err(ar, "Failed to set option val: %d\n", ret);
return ret;
}
@@ -1730,7 +1643,7 @@ static int ath10k_pci_alloc_ce(struct ath10k *ar)
for (i = 0; i < CE_COUNT; i++) {
ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
if (ret) {
- ath10k_err("failed to allocate copy engine pipe %d: %d\n",
+ ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",
i, ret);
return ret;
}
@@ -1761,9 +1674,11 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
pipe_info->hif_ce_state = ar;
attr = &host_ce_config_wlan[pipe_num];
- ret = ath10k_ce_init_pipe(ar, pipe_num, attr);
+ ret = ath10k_ce_init_pipe(ar, pipe_num, attr,
+ ath10k_pci_ce_send_done,
+ ath10k_pci_ce_recv_data);
if (ret) {
- ath10k_err("failed to initialize copy engine pipe %d: %d\n",
+ ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",
pipe_num, ret);
return ret;
}
@@ -1783,32 +1698,19 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
return 0;
}
-static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
+static bool ath10k_pci_has_fw_crashed(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- u32 fw_indicator;
-
- ath10k_pci_wake(ar);
-
- fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
-
- if (fw_indicator & FW_IND_EVENT_PENDING) {
- /* ACK: clear Target-side pending event */
- ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
- fw_indicator & ~FW_IND_EVENT_PENDING);
+ return ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS) &
+ FW_IND_EVENT_PENDING;
+}
- if (ar_pci->started) {
- ath10k_pci_hif_dump_area(ar);
- } else {
- /*
- * Probable Target failure before we're prepared
- * to handle it. Generally unexpected.
- */
- ath10k_warn("early firmware event indicated\n");
- }
- }
+static void ath10k_pci_fw_crashed_clear(struct ath10k *ar)
+{
+ u32 val;
- ath10k_pci_sleep(ar);
+ val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
+ val &= ~FW_IND_EVENT_PENDING;
+ ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val);
}
/* this function effectively clears target memory controller assert line */
@@ -1833,25 +1735,19 @@ static void ath10k_pci_warm_reset_si0(struct ath10k *ar)
static int ath10k_pci_warm_reset(struct ath10k *ar)
{
- int ret = 0;
u32 val;
- ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n");
-
- ret = ath10k_do_pci_wake(ar);
- if (ret) {
- ath10k_err("failed to wake up target: %d\n", ret);
- return ret;
- }
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n");
/* debug */
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
PCIE_INTR_CAUSE_ADDRESS);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n",
+ val);
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
CPU_INTR_ADDRESS);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
val);
/* disable pending irqs */
@@ -1894,11 +1790,12 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
/* debug */
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
PCIE_INTR_CAUSE_ADDRESS);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n",
+ val);
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
CPU_INTR_ADDRESS);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
val);
/* CPU warm reset */
@@ -1909,20 +1806,18 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
SOC_RESET_CONTROL_ADDRESS);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", val);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n",
+ val);
msleep(100);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n");
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset complete\n");
- ath10k_do_pci_sleep(ar);
- return ret;
+ return 0;
}
static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- const char *irq_mode;
int ret;
/*
@@ -1941,80 +1836,39 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
ret = ath10k_pci_warm_reset(ar);
if (ret) {
- ath10k_err("failed to reset target: %d\n", ret);
+ ath10k_err(ar, "failed to reset target: %d\n", ret);
goto err;
}
- if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- /* Force AWAKE forever */
- ath10k_do_pci_wake(ar);
-
ret = ath10k_pci_ce_init(ar);
if (ret) {
- ath10k_err("failed to initialize CE: %d\n", ret);
- goto err_ps;
- }
-
- ret = ath10k_ce_disable_interrupts(ar);
- if (ret) {
- ath10k_err("failed to disable CE interrupts: %d\n", ret);
- goto err_ce;
- }
-
- ret = ath10k_pci_init_irq(ar);
- if (ret) {
- ath10k_err("failed to init irqs: %d\n", ret);
- goto err_ce;
- }
-
- ret = ath10k_pci_request_early_irq(ar);
- if (ret) {
- ath10k_err("failed to request early irq: %d\n", ret);
- goto err_deinit_irq;
+ ath10k_err(ar, "failed to initialize CE: %d\n", ret);
+ goto err;
}
ret = ath10k_pci_wait_for_target_init(ar);
if (ret) {
- ath10k_err("failed to wait for target to init: %d\n", ret);
- goto err_free_early_irq;
+ ath10k_err(ar, "failed to wait for target to init: %d\n", ret);
+ goto err_ce;
}
ret = ath10k_pci_init_config(ar);
if (ret) {
- ath10k_err("failed to setup init config: %d\n", ret);
- goto err_free_early_irq;
+ ath10k_err(ar, "failed to setup init config: %d\n", ret);
+ goto err_ce;
}
ret = ath10k_pci_wake_target_cpu(ar);
if (ret) {
- ath10k_err("could not wake up target CPU: %d\n", ret);
- goto err_free_early_irq;
+ ath10k_err(ar, "could not wake up target CPU: %d\n", ret);
+ goto err_ce;
}
- if (ar_pci->num_msi_intrs > 1)
- irq_mode = "MSI-X";
- else if (ar_pci->num_msi_intrs == 1)
- irq_mode = "MSI";
- else
- irq_mode = "legacy";
-
- if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
- ath10k_info("pci irq %s irq_mode %d reset_mode %d\n",
- irq_mode, ath10k_pci_irq_mode,
- ath10k_pci_reset_mode);
-
return 0;
-err_free_early_irq:
- ath10k_pci_free_early_irq(ar);
-err_deinit_irq:
- ath10k_pci_deinit_irq(ar);
err_ce:
ath10k_pci_ce_deinit(ar);
ath10k_pci_warm_reset(ar);
-err_ps:
- if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- ath10k_do_pci_sleep(ar);
err:
return ret;
}
@@ -2034,7 +1888,7 @@ static int ath10k_pci_hif_power_up_warm(struct ath10k *ar)
if (ret == 0)
break;
- ath10k_warn("failed to warm reset (attempt %d out of %d): %d\n",
+ ath10k_warn(ar, "failed to warm reset (attempt %d out of %d): %d\n",
i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, ret);
}
@@ -2045,7 +1899,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
{
int ret;
- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power up\n");
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n");
/*
* Hardware CUS232 version 2 has some issues with cold reset and the
@@ -2057,17 +1911,17 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
*/
ret = ath10k_pci_hif_power_up_warm(ar);
if (ret) {
- ath10k_warn("failed to power up target using warm reset: %d\n",
+ ath10k_warn(ar, "failed to power up target using warm reset: %d\n",
ret);
if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY)
return ret;
- ath10k_warn("trying cold reset\n");
+ ath10k_warn(ar, "trying cold reset\n");
ret = __ath10k_pci_hif_power_up(ar, true);
if (ret) {
- ath10k_err("failed to power up target using cold reset too (%d)\n",
+ ath10k_err(ar, "failed to power up target using cold reset too (%d)\n",
ret);
return ret;
}
@@ -2078,18 +1932,9 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
static void ath10k_pci_hif_power_down(struct ath10k *ar)
{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n");
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");
- ath10k_pci_free_early_irq(ar);
- ath10k_pci_kill_tasklet(ar);
- ath10k_pci_deinit_irq(ar);
- ath10k_pci_ce_deinit(ar);
ath10k_pci_warm_reset(ar);
-
- if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- ath10k_do_pci_sleep(ar);
}
#ifdef CONFIG_PM
@@ -2171,7 +2016,13 @@ static void ath10k_msi_err_tasklet(unsigned long data)
{
struct ath10k *ar = (struct ath10k *)data;
- ath10k_pci_fw_interrupt_handler(ar);
+ if (!ath10k_pci_has_fw_crashed(ar)) {
+ ath10k_warn(ar, "received unsolicited fw crash interrupt\n");
+ return;
+ }
+
+ ath10k_pci_fw_crashed_clear(ar);
+ ath10k_pci_fw_crashed_dump(ar);
}
/*
@@ -2185,7 +2036,8 @@ static irqreturn_t ath10k_pci_per_engine_handler(int irq, void *arg)
int ce_id = irq - ar_pci->pdev->irq - MSI_ASSIGN_CE_INITIAL;
if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_pci->pipe_info)) {
- ath10k_warn("unexpected/invalid irq %d ce_id %d\n", irq, ce_id);
+ ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq,
+ ce_id);
return IRQ_HANDLED;
}
@@ -2232,36 +2084,17 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
return IRQ_HANDLED;
}
-static void ath10k_pci_early_irq_tasklet(unsigned long data)
+static void ath10k_pci_tasklet(unsigned long data)
{
struct ath10k *ar = (struct ath10k *)data;
- u32 fw_ind;
- int ret;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ret = ath10k_pci_wake(ar);
- if (ret) {
- ath10k_warn("failed to wake target in early irq tasklet: %d\n",
- ret);
+ if (ath10k_pci_has_fw_crashed(ar)) {
+ ath10k_pci_fw_crashed_clear(ar);
+ ath10k_pci_fw_crashed_dump(ar);
return;
}
- fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
- if (fw_ind & FW_IND_EVENT_PENDING) {
- ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
- fw_ind & ~FW_IND_EVENT_PENDING);
- ath10k_pci_hif_dump_area(ar);
- }
-
- ath10k_pci_sleep(ar);
- ath10k_pci_enable_legacy_irq(ar);
-}
-
-static void ath10k_pci_tasklet(unsigned long data)
-{
- struct ath10k *ar = (struct ath10k *)data;
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- ath10k_pci_fw_interrupt_handler(ar); /* FIXME: Handle FW error */
ath10k_ce_per_engine_service_any(ar);
/* Re-enable legacy irq that was disabled in the irq handler */
@@ -2278,7 +2111,7 @@ static int ath10k_pci_request_irq_msix(struct ath10k *ar)
ath10k_pci_msi_fw_handler,
IRQF_SHARED, "ath10k_pci", ar);
if (ret) {
- ath10k_warn("failed to request MSI-X fw irq %d: %d\n",
+ ath10k_warn(ar, "failed to request MSI-X fw irq %d: %d\n",
ar_pci->pdev->irq + MSI_ASSIGN_FW, ret);
return ret;
}
@@ -2288,7 +2121,7 @@ static int ath10k_pci_request_irq_msix(struct ath10k *ar)
ath10k_pci_per_engine_handler,
IRQF_SHARED, "ath10k_pci", ar);
if (ret) {
- ath10k_warn("failed to request MSI-X ce irq %d: %d\n",
+ ath10k_warn(ar, "failed to request MSI-X ce irq %d: %d\n",
ar_pci->pdev->irq + i, ret);
for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--)
@@ -2311,7 +2144,7 @@ static int ath10k_pci_request_irq_msi(struct ath10k *ar)
ath10k_pci_interrupt_handler,
IRQF_SHARED, "ath10k_pci", ar);
if (ret) {
- ath10k_warn("failed to request MSI irq %d: %d\n",
+ ath10k_warn(ar, "failed to request MSI irq %d: %d\n",
ar_pci->pdev->irq, ret);
return ret;
}
@@ -2328,7 +2161,7 @@ static int ath10k_pci_request_irq_legacy(struct ath10k *ar)
ath10k_pci_interrupt_handler,
IRQF_SHARED, "ath10k_pci", ar);
if (ret) {
- ath10k_warn("failed to request legacy irq %d: %d\n",
+ ath10k_warn(ar, "failed to request legacy irq %d: %d\n",
ar_pci->pdev->irq, ret);
return ret;
}
@@ -2349,7 +2182,7 @@ static int ath10k_pci_request_irq(struct ath10k *ar)
return ath10k_pci_request_irq_msix(ar);
}
- ath10k_warn("unknown irq configuration upon request\n");
+ ath10k_warn(ar, "unknown irq configuration upon request\n");
return -EINVAL;
}
@@ -2372,8 +2205,6 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
(unsigned long)ar);
- tasklet_init(&ar_pci->early_irq_tasklet, ath10k_pci_early_irq_tasklet,
- (unsigned long)ar);
for (i = 0; i < CE_COUNT; i++) {
ar_pci->pipe_info[i].ar_pci = ar_pci;
@@ -2385,18 +2216,16 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
static int ath10k_pci_init_irq(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- bool msix_supported = test_bit(ATH10K_PCI_FEATURE_MSI_X,
- ar_pci->features);
int ret;
ath10k_pci_init_irq_tasklets(ar);
- if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO &&
- !test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
- ath10k_info("limiting irq mode to: %d\n", ath10k_pci_irq_mode);
+ if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO)
+ ath10k_info(ar, "limiting irq mode to: %d\n",
+ ath10k_pci_irq_mode);
/* Try MSI-X */
- if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) {
+ if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO) {
ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
ar_pci->num_msi_intrs);
@@ -2426,34 +2255,16 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
* synchronization checking. */
ar_pci->num_msi_intrs = 0;
- ret = ath10k_pci_wake(ar);
- if (ret) {
- ath10k_warn("failed to wake target: %d\n", ret);
- return ret;
- }
-
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
- ath10k_pci_sleep(ar);
return 0;
}
-static int ath10k_pci_deinit_irq_legacy(struct ath10k *ar)
+static void ath10k_pci_deinit_irq_legacy(struct ath10k *ar)
{
- int ret;
-
- ret = ath10k_pci_wake(ar);
- if (ret) {
- ath10k_warn("failed to wake target: %d\n", ret);
- return ret;
- }
-
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
0);
- ath10k_pci_sleep(ar);
-
- return 0;
}
static int ath10k_pci_deinit_irq(struct ath10k *ar)
@@ -2462,7 +2273,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
switch (ar_pci->num_msi_intrs) {
case 0:
- return ath10k_pci_deinit_irq_legacy(ar);
+ ath10k_pci_deinit_irq_legacy(ar);
+ return 0;
case 1:
/* fall-through */
case MSI_NUM_REQUEST:
@@ -2472,7 +2284,7 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
pci_disable_msi(ar_pci->pdev);
}
- ath10k_warn("unknown irq configuration upon deinit\n");
+ ath10k_warn(ar, "unknown irq configuration upon deinit\n");
return -EINVAL;
}
@@ -2480,23 +2292,17 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
unsigned long timeout;
- int ret;
u32 val;
- ath10k_dbg(ATH10K_DBG_BOOT, "boot waiting target to initialise\n");
-
- ret = ath10k_pci_wake(ar);
- if (ret) {
- ath10k_err("failed to wake up target for init: %d\n", ret);
- return ret;
- }
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot waiting target to initialise\n");
timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT);
do {
val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
- ath10k_dbg(ATH10K_DBG_BOOT, "boot target indicator %x\n", val);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target indicator %x\n",
+ val);
/* target should never return this */
if (val == 0xffffffff)
@@ -2511,55 +2317,42 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
if (ar_pci->num_msi_intrs == 0)
/* Fix potential race by repeating CORE_BASE writes */
- ath10k_pci_soc_write32(ar, PCIE_INTR_ENABLE_ADDRESS,
- PCIE_INTR_FIRMWARE_MASK |
- PCIE_INTR_CE_MASK_ALL);
+ ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
+ PCIE_INTR_ENABLE_ADDRESS,
+ PCIE_INTR_FIRMWARE_MASK |
+ PCIE_INTR_CE_MASK_ALL);
mdelay(10);
} while (time_before(jiffies, timeout));
if (val == 0xffffffff) {
- ath10k_err("failed to read device register, device is gone\n");
- ret = -EIO;
- goto out;
+ ath10k_err(ar, "failed to read device register, device is gone\n");
+ return -EIO;
}
if (val & FW_IND_EVENT_PENDING) {
- ath10k_warn("device has crashed during init\n");
- ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
- val & ~FW_IND_EVENT_PENDING);
- ath10k_pci_hif_dump_area(ar);
- ret = -ECOMM;
- goto out;
+ ath10k_warn(ar, "device has crashed during init\n");
+ ath10k_pci_fw_crashed_clear(ar);
+ ath10k_pci_fw_crashed_dump(ar);
+ return -ECOMM;
}
if (!(val & FW_IND_INITIALIZED)) {
- ath10k_err("failed to receive initialized event from target: %08x\n",
+ ath10k_err(ar, "failed to receive initialized event from target: %08x\n",
val);
- ret = -ETIMEDOUT;
- goto out;
+ return -ETIMEDOUT;
}
- ath10k_dbg(ATH10K_DBG_BOOT, "boot target initialised\n");
-
-out:
- ath10k_pci_sleep(ar);
- return ret;
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target initialised\n");
+ return 0;
}
static int ath10k_pci_cold_reset(struct ath10k *ar)
{
- int i, ret;
+ int i;
u32 val;
- ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset\n");
-
- ret = ath10k_do_pci_wake(ar);
- if (ret) {
- ath10k_err("failed to wake up target: %d\n",
- ret);
- return ret;
- }
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n");
/* Put Target, including PCIe, into RESET. */
val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS);
@@ -2584,169 +2377,198 @@ static int ath10k_pci_cold_reset(struct ath10k *ar)
msleep(1);
}
- ath10k_do_pci_sleep(ar);
-
- ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n");
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n");
return 0;
}
-static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
-{
- int i;
-
- for (i = 0; i < ATH10K_PCI_FEATURE_COUNT; i++) {
- if (!test_bit(i, ar_pci->features))
- continue;
-
- switch (i) {
- case ATH10K_PCI_FEATURE_MSI_X:
- ath10k_dbg(ATH10K_DBG_BOOT, "device supports MSI-X\n");
- break;
- case ATH10K_PCI_FEATURE_SOC_POWER_SAVE:
- ath10k_dbg(ATH10K_DBG_BOOT, "QCA98XX SoC power save enabled\n");
- break;
- }
- }
-}
-
-static int ath10k_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *pci_dev)
+static int ath10k_pci_claim(struct ath10k *ar)
{
- void __iomem *mem;
- int ret = 0;
- struct ath10k *ar;
- struct ath10k_pci *ar_pci;
- u32 lcr_val, chip_id;
-
- ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n");
-
- ar_pci = kzalloc(sizeof(*ar_pci), GFP_KERNEL);
- if (ar_pci == NULL)
- return -ENOMEM;
-
- ar_pci->pdev = pdev;
- ar_pci->dev = &pdev->dev;
-
- switch (pci_dev->device) {
- case QCA988X_2_0_DEVICE_ID:
- set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features);
- break;
- default:
- ret = -ENODEV;
- ath10k_err("Unknown device ID: %d\n", pci_dev->device);
- goto err_ar_pci;
- }
-
- if (ath10k_pci_target_ps)
- set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features);
-
- ath10k_pci_dump_features(ar_pci);
-
- ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops);
- if (!ar) {
- ath10k_err("failed to create driver core\n");
- ret = -EINVAL;
- goto err_ar_pci;
- }
-
- ar_pci->ar = ar;
- atomic_set(&ar_pci->keep_awake_count, 0);
+ 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);
ret = pci_enable_device(pdev);
if (ret) {
- ath10k_err("failed to enable PCI device: %d\n", ret);
- goto err_ar;
+ ath10k_err(ar, "failed to enable pci device: %d\n", ret);
+ return ret;
}
- /* Request MMIO resources */
ret = pci_request_region(pdev, BAR_NUM, "ath");
if (ret) {
- ath10k_err("failed to request MMIO region: %d\n", ret);
+ ath10k_err(ar, "failed to request region BAR%d: %d\n", BAR_NUM,
+ ret);
goto err_device;
}
- /*
- * Target structures have a limit of 32 bit DMA pointers.
- * DMA pointers can be wider than 32 bits by default on some systems.
- */
+ /* Target expects 32 bit DMA. Enforce it. */
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
- ath10k_err("failed to set DMA mask to 32-bit: %d\n", ret);
+ ath10k_err(ar, "failed to set dma mask to 32-bit: %d\n", ret);
goto err_region;
}
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
- ath10k_err("failed to set consistent DMA mask to 32-bit\n");
+ ath10k_err(ar, "failed to set consistent dma mask to 32-bit: %d\n",
+ ret);
goto err_region;
}
- /* Set bus master bit in PCI_COMMAND to enable DMA */
pci_set_master(pdev);
- /*
- * Temporary FIX: disable ASPM
- * Will be removed after the OTP is programmed
- */
+ /* 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. */
- mem = pci_iomap(pdev, BAR_NUM, 0);
- if (!mem) {
- ath10k_err("failed to perform IOMAP for BAR%d\n", BAR_NUM);
+ ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0);
+ if (!ar_pci->mem) {
+ ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM);
ret = -EIO;
goto err_master;
}
- ar_pci->mem = mem;
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem);
+ return 0;
+
+err_master:
+ pci_clear_master(pdev);
+
+err_region:
+ pci_release_region(pdev, BAR_NUM);
+
+err_device:
+ pci_disable_device(pdev);
+
+ return ret;
+}
+
+static void ath10k_pci_release(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ struct pci_dev *pdev = ar_pci->pdev;
+
+ pci_iounmap(pdev, ar_pci->mem);
+ pci_release_region(pdev, BAR_NUM);
+ pci_clear_master(pdev);
+ pci_disable_device(pdev);
+}
+
+static int ath10k_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_dev)
+{
+ int ret = 0;
+ struct ath10k *ar;
+ struct ath10k_pci *ar_pci;
+ u32 chip_id;
+
+ ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev,
+ &ath10k_pci_hif_ops);
+ if (!ar) {
+ dev_err(&pdev->dev, "failed to allocate core\n");
+ return -ENOMEM;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci probe\n");
+
+ ar_pci = ath10k_pci_priv(ar);
+ ar_pci->pdev = pdev;
+ ar_pci->dev = &pdev->dev;
+ ar_pci->ar = ar;
spin_lock_init(&ar_pci->ce_lock);
+ setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
+ (unsigned long)ar);
- ret = ath10k_do_pci_wake(ar);
+ ret = ath10k_pci_claim(ar);
if (ret) {
- ath10k_err("Failed to get chip id: %d\n", ret);
- goto err_iomap;
+ ath10k_err(ar, "failed to claim device: %d\n", ret);
+ goto err_core_destroy;
}
- chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
+ ret = ath10k_pci_wake(ar);
+ if (ret) {
+ ath10k_err(ar, "failed to wake up: %d\n", ret);
+ goto err_release;
+ }
- ath10k_do_pci_sleep(ar);
+ chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
+ if (chip_id == 0xffffffff) {
+ ath10k_err(ar, "failed to get chip id\n");
+ goto err_sleep;
+ }
ret = ath10k_pci_alloc_ce(ar);
if (ret) {
- ath10k_err("failed to allocate copy engine pipes: %d\n", ret);
- goto err_iomap;
+ ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
+ ret);
+ goto err_sleep;
}
- ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem);
+ ath10k_pci_ce_deinit(ar);
- ret = ath10k_core_register(ar, chip_id);
+ ret = ath10k_ce_disable_interrupts(ar);
+ if (ret) {
+ ath10k_err(ar, "failed to disable copy engine interrupts: %d\n",
+ ret);
+ goto err_free_ce;
+ }
+
+ /* Workaround: There's no known way to mask all possible interrupts via
+ * device CSR. The only way to make sure device doesn't assert
+ * interrupts is to reset it. Interrupts are then disabled on host
+ * after handlers are registered.
+ */
+ ath10k_pci_warm_reset(ar);
+
+ ret = ath10k_pci_init_irq(ar);
if (ret) {
- ath10k_err("failed to register driver core: %d\n", ret);
+ ath10k_err(ar, "failed to init irqs: %d\n", ret);
goto err_free_ce;
}
+ ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n",
+ ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs,
+ ath10k_pci_irq_mode, ath10k_pci_reset_mode);
+
+ ret = ath10k_pci_request_irq(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to request irqs: %d\n", ret);
+ goto err_deinit_irq;
+ }
+
+ /* This shouldn't race as the device has been reset above. */
+ ath10k_pci_irq_disable(ar);
+
+ ret = ath10k_core_register(ar, chip_id);
+ if (ret) {
+ ath10k_err(ar, "failed to register driver core: %d\n", ret);
+ goto err_free_irq;
+ }
+
return 0;
+err_free_irq:
+ ath10k_pci_free_irq(ar);
+
+err_deinit_irq:
+ ath10k_pci_deinit_irq(ar);
+
err_free_ce:
ath10k_pci_free_ce(ar);
-err_iomap:
- pci_iounmap(pdev, mem);
-err_master:
- pci_clear_master(pdev);
-err_region:
- pci_release_region(pdev, BAR_NUM);
-err_device:
- pci_disable_device(pdev);
-err_ar:
+
+err_sleep:
+ ath10k_pci_sleep(ar);
+
+err_release:
+ ath10k_pci_release(ar);
+
+err_core_destroy:
ath10k_core_destroy(ar);
-err_ar_pci:
- /* call HIF PCI free here */
- kfree(ar_pci);
return ret;
}
@@ -2756,7 +2578,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
struct ath10k *ar = pci_get_drvdata(pdev);
struct ath10k_pci *ar_pci;
- ath10k_dbg(ATH10K_DBG_PCI, "pci remove\n");
+ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci remove\n");
if (!ar)
return;
@@ -2767,15 +2589,13 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
return;
ath10k_core_unregister(ar);
+ ath10k_pci_free_irq(ar);
+ ath10k_pci_deinit_irq(ar);
+ ath10k_pci_ce_deinit(ar);
ath10k_pci_free_ce(ar);
-
- pci_iounmap(pdev, ar_pci->mem);
- pci_release_region(pdev, BAR_NUM);
- pci_clear_master(pdev);
- pci_disable_device(pdev);
-
+ ath10k_pci_sleep(ar);
+ ath10k_pci_release(ar);
ath10k_core_destroy(ar);
- kfree(ar_pci);
}
MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table);
@@ -2793,7 +2613,8 @@ static int __init ath10k_pci_init(void)
ret = pci_register_driver(&ath10k_pci_driver);
if (ret)
- ath10k_err("failed to register PCI driver: %d\n", ret);
+ printk(KERN_ERR "failed to register ath10k pci driver: %d\n",
+ ret);
return ret;
}
@@ -2809,5 +2630,5 @@ module_exit(ath10k_pci_exit);
MODULE_AUTHOR("Qualcomm Atheros");
MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_2_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_3_FILE);
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index 94012920999..cf36511c7f4 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -23,9 +23,6 @@
#include "hw.h"
#include "ce.h"
-/* FW dump area */
-#define REG_DUMP_COUNT_QCA988X 60
-
/*
* maximum number of bytes that can be handled atomically by DiagRead/DiagWrite
*/
@@ -103,12 +100,12 @@ struct pcie_state {
* NOTE: Structure is shared between Host software and Target firmware!
*/
struct ce_pipe_config {
- u32 pipenum;
- u32 pipedir;
- u32 nentries;
- u32 nbytes_max;
- u32 flags;
- u32 reserved;
+ __le32 pipenum;
+ __le32 pipedir;
+ __le32 nentries;
+ __le32 nbytes_max;
+ __le32 flags;
+ __le32 reserved;
};
/*
@@ -130,17 +127,9 @@ struct ce_pipe_config {
/* Establish a mapping between a service/direction and a pipe. */
struct service_to_pipe {
- u32 service_id;
- u32 pipedir;
- u32 pipenum;
-};
-
-enum ath10k_pci_features {
- ATH10K_PCI_FEATURE_MSI_X = 0,
- ATH10K_PCI_FEATURE_SOC_POWER_SAVE = 1,
-
- /* keep last */
- ATH10K_PCI_FEATURE_COUNT
+ __le32 service_id;
+ __le32 pipedir;
+ __le32 pipenum;
};
/* Per-pipe state. */
@@ -169,8 +158,6 @@ struct ath10k_pci {
struct ath10k *ar;
void __iomem *mem;
- DECLARE_BITMAP(features, ATH10K_PCI_FEATURE_COUNT);
-
/*
* Number of MSI interrupts granted, 0 --> using legacy PCI line
* interrupts.
@@ -179,12 +166,6 @@ struct ath10k_pci {
struct tasklet_struct intr_tq;
struct tasklet_struct msi_fw_err;
- struct tasklet_struct early_irq_tasklet;
-
- int started;
-
- atomic_t keep_awake_count;
- bool verified_awake;
struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
@@ -198,27 +179,15 @@ struct ath10k_pci {
/* Map CE id to ce_state */
struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
+ struct timer_list rx_post_retry;
};
static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
{
- return ar->hif.priv;
-}
-
-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);
-}
-
-static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
-{
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
- iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
+ return (struct ath10k_pci *)ar->drv_priv;
}
+#define ATH10K_PCI_RX_POST_RETRY_MS 50
#define ATH_PCI_RESET_WAIT_MAX 10 /* ms */
#define PCIE_WAKE_TIMEOUT 5000 /* 5ms */
@@ -242,35 +211,17 @@ static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
/* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
#define DIAG_ACCESS_CE_TIMEOUT_MS 10
-/*
- * This API allows the Host to access Target registers directly
- * and relatively efficiently over PCIe.
- * This allows the Host to avoid extra overhead associated with
- * sending a message to firmware and waiting for a response message
- * from firmware, as is done on other interconnects.
- *
- * Yet there is some complexity with direct accesses because the
- * Target's power state is not known a priori. The Host must issue
- * special PCIe reads/writes in order to explicitly wake the Target
- * and to verify that it is awake and will remain awake.
- *
- * Usage:
+/* 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).
*
- * Use ath10k_pci_read32 and ath10k_pci_write32 to access Target space.
- * These calls must be bracketed by ath10k_pci_wake and
- * ath10k_pci_sleep. A single BEGIN/END pair is adequate for
- * multiple READ/WRITE operations.
+ * If host tries to access target registers without waking it up it can
+ * scribble over host memory.
*
- * Use ath10k_pci_wake to put the Target in a state in
- * which it is legal for the Host to directly access it. This
- * may involve waking the Target from a low power state, which
- * may take up to 2Ms!
- *
- * Use ath10k_pci_sleep to tell the Target that as far as
- * this code path is concerned, it no longer needs to remain
- * directly accessible. BEGIN/END is under a reference counter;
- * multiple code paths may issue BEGIN/END on a single targid.
+ * 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)
{
@@ -296,25 +247,18 @@ static inline void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val)
ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val);
}
-int ath10k_do_pci_wake(struct ath10k *ar);
-void ath10k_do_pci_sleep(struct ath10k *ar);
-
-static inline int ath10k_pci_wake(struct ath10k *ar)
+static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- return ath10k_do_pci_wake(ar);
-
- return 0;
+ return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
}
-static inline void ath10k_pci_sleep(struct ath10k *ar)
+static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- ath10k_do_pci_sleep(ar);
+ iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
}
#endif /* _PCI_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c
new file mode 100644
index 00000000000..3e1454b74e0
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/spectral.c
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2013 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/relay.h>
+#include "core.h"
+#include "debug.h"
+
+static void send_fft_sample(struct ath10k *ar,
+ const struct fft_sample_tlv *fft_sample_tlv)
+{
+ int length;
+
+ if (!ar->spectral.rfs_chan_spec_scan)
+ return;
+
+ length = __be16_to_cpu(fft_sample_tlv->length) +
+ sizeof(*fft_sample_tlv);
+ relay_write(ar->spectral.rfs_chan_spec_scan, fft_sample_tlv, length);
+}
+
+static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len,
+ u8 *data)
+{
+ int dc_pos;
+ u8 max_exp;
+
+ dc_pos = bin_len / 2;
+
+ /* peak index outside of bins */
+ if (dc_pos < max_index || -dc_pos >= max_index)
+ return 0;
+
+ for (max_exp = 0; max_exp < 8; max_exp++) {
+ if (data[dc_pos + max_index] == (max_magnitude >> max_exp))
+ break;
+ }
+
+ /* max_exp not found */
+ if (data[dc_pos + max_index] != (max_magnitude >> max_exp))
+ return 0;
+
+ return max_exp;
+}
+
+int ath10k_spectral_process_fft(struct ath10k *ar,
+ struct wmi_single_phyerr_rx_event *event,
+ struct phyerr_fft_report *fftr,
+ size_t bin_len, u64 tsf)
+{
+ struct fft_sample_ath10k *fft_sample;
+ u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS];
+ u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag;
+ u32 reg0, reg1, nf_list1, nf_list2;
+ u8 chain_idx, *bins;
+ int dc_pos;
+
+ fft_sample = (struct fft_sample_ath10k *)&buf;
+
+ if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS)
+ return -EINVAL;
+
+ reg0 = __le32_to_cpu(fftr->reg0);
+ reg1 = __le32_to_cpu(fftr->reg1);
+
+ length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + bin_len;
+ fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH10K;
+ fft_sample->tlv.length = __cpu_to_be16(length);
+
+ /* TODO: there might be a reason why the hardware reports 20/40/80 MHz,
+ * but the results/plots suggest that its actually 22/44/88 MHz.
+ */
+ switch (event->hdr.chan_width_mhz) {
+ case 20:
+ fft_sample->chan_width_mhz = 22;
+ break;
+ case 40:
+ fft_sample->chan_width_mhz = 44;
+ break;
+ case 80:
+ /* TODO: As experiments with an analogue sender and various
+ * configuaritions (fft-sizes of 64/128/256 and 20/40/80 Mhz)
+ * show, the particular configuration of 80 MHz/64 bins does
+ * not match with the other smaples at all. Until the reason
+ * for that is found, don't report these samples.
+ */
+ if (bin_len == 64)
+ return -EINVAL;
+ fft_sample->chan_width_mhz = 88;
+ break;
+ default:
+ fft_sample->chan_width_mhz = event->hdr.chan_width_mhz;
+ }
+
+ fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB);
+ fft_sample->avgpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB);
+
+ peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
+ fft_sample->max_magnitude = __cpu_to_be16(peak_mag);
+ fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX);
+ fft_sample->rssi = event->hdr.rssi_combined;
+
+ total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB);
+ base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB);
+ fft_sample->total_gain_db = __cpu_to_be16(total_gain_db);
+ fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db);
+
+ freq1 = __le16_to_cpu(event->hdr.freq1);
+ freq2 = __le16_to_cpu(event->hdr.freq2);
+ fft_sample->freq1 = __cpu_to_be16(freq1);
+ fft_sample->freq2 = __cpu_to_be16(freq2);
+
+ nf_list1 = __le32_to_cpu(event->hdr.nf_list_1);
+ nf_list2 = __le32_to_cpu(event->hdr.nf_list_2);
+ chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX);
+
+ switch (chain_idx) {
+ case 0:
+ fft_sample->noise = __cpu_to_be16(nf_list1 & 0xffffu);
+ break;
+ case 1:
+ fft_sample->noise = __cpu_to_be16((nf_list1 >> 16) & 0xffffu);
+ break;
+ case 2:
+ fft_sample->noise = __cpu_to_be16(nf_list2 & 0xffffu);
+ break;
+ case 3:
+ fft_sample->noise = __cpu_to_be16((nf_list2 >> 16) & 0xffffu);
+ break;
+ }
+
+ bins = (u8 *)fftr;
+ bins += sizeof(*fftr);
+
+ fft_sample->tsf = __cpu_to_be64(tsf);
+
+ /* max_exp has been directly reported by previous hardware (ath9k),
+ * maybe its possible to get it by other means?
+ */
+ fft_sample->max_exp = get_max_exp(fft_sample->max_index, peak_mag,
+ bin_len, bins);
+
+ memcpy(fft_sample->data, bins, bin_len);
+
+ /* DC value (value in the middle) is the blind spot of the spectral
+ * sample and invalid, interpolate it.
+ */
+ dc_pos = bin_len / 2;
+ fft_sample->data[dc_pos] = (fft_sample->data[dc_pos + 1] +
+ fft_sample->data[dc_pos - 1]) / 2;
+
+ send_fft_sample(ar, &fft_sample->tlv);
+
+ return 0;
+}
+
+static struct ath10k_vif *ath10k_get_spectral_vdev(struct ath10k *ar)
+{
+ struct ath10k_vif *arvif;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ if (list_empty(&ar->arvifs))
+ return NULL;
+
+ /* if there already is a vif doing spectral, return that. */
+ list_for_each_entry(arvif, &ar->arvifs, list)
+ if (arvif->spectral_enabled)
+ return arvif;
+
+ /* otherwise, return the first vif. */
+ return list_first_entry(&ar->arvifs, typeof(*arvif), list);
+}
+
+static int ath10k_spectral_scan_trigger(struct ath10k *ar)
+{
+ struct ath10k_vif *arvif;
+ int res;
+ int vdev_id;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ arvif = ath10k_get_spectral_vdev(ar);
+ if (!arvif)
+ return -ENODEV;
+ vdev_id = arvif->vdev_id;
+
+ if (ar->spectral.mode == SPECTRAL_DISABLED)
+ return 0;
+
+ res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
+ WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
+ WMI_SPECTRAL_ENABLE_CMD_ENABLE);
+ if (res < 0)
+ return res;
+
+ res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
+ WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
+ WMI_SPECTRAL_ENABLE_CMD_ENABLE);
+ if (res < 0)
+ return res;
+
+ return 0;
+}
+
+static int ath10k_spectral_scan_config(struct ath10k *ar,
+ enum ath10k_spectral_mode mode)
+{
+ struct wmi_vdev_spectral_conf_arg arg;
+ struct ath10k_vif *arvif;
+ int vdev_id, count, res = 0;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ arvif = ath10k_get_spectral_vdev(ar);
+ if (!arvif)
+ return -ENODEV;
+
+ vdev_id = arvif->vdev_id;
+
+ arvif->spectral_enabled = (mode != SPECTRAL_DISABLED);
+ ar->spectral.mode = mode;
+
+ res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
+ WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
+ WMI_SPECTRAL_ENABLE_CMD_DISABLE);
+ if (res < 0) {
+ ath10k_warn(ar, "failed to enable spectral scan: %d\n", res);
+ return res;
+ }
+
+ if (mode == SPECTRAL_DISABLED)
+ return 0;
+
+ if (mode == SPECTRAL_BACKGROUND)
+ count = WMI_SPECTRAL_COUNT_DEFAULT;
+ else
+ count = max_t(u8, 1, ar->spectral.config.count);
+
+ arg.vdev_id = vdev_id;
+ arg.scan_count = count;
+ arg.scan_period = WMI_SPECTRAL_PERIOD_DEFAULT;
+ arg.scan_priority = WMI_SPECTRAL_PRIORITY_DEFAULT;
+ arg.scan_fft_size = ar->spectral.config.fft_size;
+ arg.scan_gc_ena = WMI_SPECTRAL_GC_ENA_DEFAULT;
+ arg.scan_restart_ena = WMI_SPECTRAL_RESTART_ENA_DEFAULT;
+ arg.scan_noise_floor_ref = WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
+ arg.scan_init_delay = WMI_SPECTRAL_INIT_DELAY_DEFAULT;
+ arg.scan_nb_tone_thr = WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
+ arg.scan_str_bin_thr = WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
+ arg.scan_wb_rpt_mode = WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
+ arg.scan_rssi_rpt_mode = WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
+ arg.scan_rssi_thr = WMI_SPECTRAL_RSSI_THR_DEFAULT;
+ arg.scan_pwr_format = WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
+ arg.scan_rpt_mode = WMI_SPECTRAL_RPT_MODE_DEFAULT;
+ arg.scan_bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
+ arg.scan_dbm_adj = WMI_SPECTRAL_DBM_ADJ_DEFAULT;
+ arg.scan_chn_mask = WMI_SPECTRAL_CHN_MASK_DEFAULT;
+
+ res = ath10k_wmi_vdev_spectral_conf(ar, &arg);
+ if (res < 0) {
+ ath10k_warn(ar, "failed to configure spectral scan: %d\n", res);
+ return res;
+ }
+
+ return 0;
+}
+
+static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ char *mode = "";
+ unsigned int len;
+ enum ath10k_spectral_mode spectral_mode;
+
+ mutex_lock(&ar->conf_mutex);
+ spectral_mode = ar->spectral.mode;
+ mutex_unlock(&ar->conf_mutex);
+
+ switch (spectral_mode) {
+ case SPECTRAL_DISABLED:
+ mode = "disable";
+ break;
+ case SPECTRAL_BACKGROUND:
+ mode = "background";
+ break;
+ case SPECTRAL_MANUAL:
+ mode = "manual";
+ break;
+ }
+
+ len = strlen(mode);
+ return simple_read_from_buffer(user_buf, count, ppos, mode, len);
+}
+
+static ssize_t write_file_spec_scan_ctl(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ char buf[32];
+ ssize_t len;
+ int res;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (strncmp("trigger", buf, 7) == 0) {
+ if (ar->spectral.mode == SPECTRAL_MANUAL ||
+ ar->spectral.mode == SPECTRAL_BACKGROUND) {
+ /* reset the configuration to adopt possibly changed
+ * debugfs parameters
+ */
+ res = ath10k_spectral_scan_config(ar,
+ ar->spectral.mode);
+ if (res < 0) {
+ ath10k_warn(ar, "failed to reconfigure spectral scan: %d\n",
+ res);
+ }
+ res = ath10k_spectral_scan_trigger(ar);
+ if (res < 0) {
+ ath10k_warn(ar, "failed to trigger spectral scan: %d\n",
+ res);
+ }
+ } else {
+ res = -EINVAL;
+ }
+ } else if (strncmp("background", buf, 9) == 0) {
+ res = ath10k_spectral_scan_config(ar, SPECTRAL_BACKGROUND);
+ } else if (strncmp("manual", buf, 6) == 0) {
+ res = ath10k_spectral_scan_config(ar, SPECTRAL_MANUAL);
+ } else if (strncmp("disable", buf, 7) == 0) {
+ res = ath10k_spectral_scan_config(ar, SPECTRAL_DISABLED);
+ } else {
+ res = -EINVAL;
+ }
+
+ mutex_unlock(&ar->conf_mutex);
+
+ if (res < 0)
+ return res;
+
+ return count;
+}
+
+static const struct file_operations fops_spec_scan_ctl = {
+ .read = read_file_spec_scan_ctl,
+ .write = write_file_spec_scan_ctl,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_count(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ char buf[32];
+ unsigned int len;
+ u8 spectral_count;
+
+ mutex_lock(&ar->conf_mutex);
+ spectral_count = ar->spectral.config.count;
+ mutex_unlock(&ar->conf_mutex);
+
+ len = sprintf(buf, "%d\n", spectral_count);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_count(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ unsigned long val;
+ char buf[32];
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val < 0 || val > 255)
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+ ar->spectral.config.count = val;
+ mutex_unlock(&ar->conf_mutex);
+
+ return count;
+}
+
+static const struct file_operations fops_spectral_count = {
+ .read = read_file_spectral_count,
+ .write = write_file_spectral_count,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_bins(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ char buf[32];
+ unsigned int len, bins, fft_size, bin_scale;
+
+ mutex_lock(&ar->conf_mutex);
+
+ fft_size = ar->spectral.config.fft_size;
+ bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
+ bins = 1 << (fft_size - bin_scale);
+
+ mutex_unlock(&ar->conf_mutex);
+
+ len = sprintf(buf, "%d\n", bins);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_bins(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ unsigned long val;
+ char buf[32];
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val < 64 || val > SPECTRAL_ATH10K_MAX_NUM_BINS)
+ return -EINVAL;
+
+ if (!is_power_of_2(val))
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+ ar->spectral.config.fft_size = ilog2(val);
+ ar->spectral.config.fft_size += WMI_SPECTRAL_BIN_SCALE_DEFAULT;
+ mutex_unlock(&ar->conf_mutex);
+
+ return count;
+}
+
+static const struct file_operations fops_spectral_bins = {
+ .read = read_file_spectral_bins,
+ .write = write_file_spectral_bins,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static struct dentry *create_buf_file_handler(const char *filename,
+ struct dentry *parent,
+ umode_t mode,
+ struct rchan_buf *buf,
+ int *is_global)
+{
+ struct dentry *buf_file;
+
+ buf_file = debugfs_create_file(filename, mode, parent, buf,
+ &relay_file_operations);
+ *is_global = 1;
+ return buf_file;
+}
+
+static int remove_buf_file_handler(struct dentry *dentry)
+{
+ debugfs_remove(dentry);
+
+ return 0;
+}
+
+static struct rchan_callbacks rfs_spec_scan_cb = {
+ .create_buf_file = create_buf_file_handler,
+ .remove_buf_file = remove_buf_file_handler,
+};
+
+int ath10k_spectral_start(struct ath10k *ar)
+{
+ struct ath10k_vif *arvif;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ list_for_each_entry(arvif, &ar->arvifs, list)
+ arvif->spectral_enabled = 0;
+
+ ar->spectral.mode = SPECTRAL_DISABLED;
+ ar->spectral.config.count = WMI_SPECTRAL_COUNT_DEFAULT;
+ ar->spectral.config.fft_size = WMI_SPECTRAL_FFT_SIZE_DEFAULT;
+
+ return 0;
+}
+
+int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
+{
+ if (!arvif->spectral_enabled)
+ return 0;
+
+ return ath10k_spectral_scan_config(arvif->ar, SPECTRAL_DISABLED);
+}
+
+int ath10k_spectral_create(struct ath10k *ar)
+{
+ ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan",
+ ar->debug.debugfs_phy,
+ 1024, 256,
+ &rfs_spec_scan_cb, NULL);
+ debugfs_create_file("spectral_scan_ctl",
+ S_IRUSR | S_IWUSR,
+ ar->debug.debugfs_phy, ar,
+ &fops_spec_scan_ctl);
+ debugfs_create_file("spectral_count",
+ S_IRUSR | S_IWUSR,
+ ar->debug.debugfs_phy, ar,
+ &fops_spectral_count);
+ debugfs_create_file("spectral_bins",
+ S_IRUSR | S_IWUSR,
+ ar->debug.debugfs_phy, ar,
+ &fops_spectral_bins);
+
+ return 0;
+}
+
+void ath10k_spectral_destroy(struct ath10k *ar)
+{
+ if (ar->spectral.rfs_chan_spec_scan) {
+ relay_close(ar->spectral.rfs_chan_spec_scan);
+ ar->spectral.rfs_chan_spec_scan = NULL;
+ }
+}
diff --git a/drivers/net/wireless/ath/ath10k/spectral.h b/drivers/net/wireless/ath/ath10k/spectral.h
new file mode 100644
index 00000000000..ddc57c55727
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/spectral.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2013 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 SPECTRAL_H
+#define SPECTRAL_H
+
+#include "../spectral_common.h"
+
+/**
+ * struct ath10k_spec_scan - parameters for Atheros spectral scan
+ *
+ * @count: number of scan results requested for manual mode
+ * @fft_size: number of bins to be requested = 2^(fft_size - bin_scale)
+ */
+struct ath10k_spec_scan {
+ u8 count;
+ u8 fft_size;
+};
+
+/* enum ath10k_spectral_mode:
+ *
+ * @SPECTRAL_DISABLED: spectral mode is disabled
+ * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
+ * something else.
+ * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
+ * is performed manually.
+ */
+enum ath10k_spectral_mode {
+ SPECTRAL_DISABLED = 0,
+ SPECTRAL_BACKGROUND,
+ SPECTRAL_MANUAL,
+};
+
+#ifdef CONFIG_ATH10K_DEBUGFS
+
+int ath10k_spectral_process_fft(struct ath10k *ar,
+ struct wmi_single_phyerr_rx_event *event,
+ struct phyerr_fft_report *fftr,
+ size_t bin_len, u64 tsf);
+int ath10k_spectral_start(struct ath10k *ar);
+int ath10k_spectral_vif_stop(struct ath10k_vif *arvif);
+int ath10k_spectral_create(struct ath10k *ar);
+void ath10k_spectral_destroy(struct ath10k *ar);
+
+#else
+
+static inline int
+ath10k_spectral_process_fft(struct ath10k *ar,
+ struct wmi_single_phyerr_rx_event *event,
+ struct phyerr_fft_report *fftr,
+ size_t bin_len, u64 tsf)
+{
+ return 0;
+}
+
+static inline int ath10k_spectral_start(struct ath10k *ar)
+{
+ return 0;
+}
+
+static inline int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
+{
+ return 0;
+}
+
+static inline int ath10k_spectral_create(struct ath10k *ar)
+{
+ return 0;
+}
+
+static inline void ath10k_spectral_destroy(struct ath10k *ar)
+{
+}
+
+#endif /* CONFIG_ATH10K_DEBUGFS */
+
+#endif /* SPECTRAL_H */
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index f4fa22d1d59..2eeec8a63d5 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -32,14 +32,14 @@ static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb)
* offchan_tx_skb. */
spin_lock_bh(&ar->data_lock);
if (ar->offchan_tx_skb != skb) {
- ath10k_warn("completed old offchannel frame\n");
+ ath10k_warn(ar, "completed old offchannel frame\n");
goto out;
}
complete(&ar->offchan_tx_completed);
ar->offchan_tx_skb = NULL; /* just for sanity */
- ath10k_dbg(ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb);
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb);
out:
spin_unlock_bh(&ar->data_lock);
}
@@ -47,18 +47,19 @@ out:
void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
const struct htt_tx_done *tx_done)
{
- struct device *dev = htt->ar->dev;
+ struct ath10k *ar = htt->ar;
+ struct device *dev = ar->dev;
struct ieee80211_tx_info *info;
struct ath10k_skb_cb *skb_cb;
struct sk_buff *msdu;
lockdep_assert_held(&htt->tx_lock);
- ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
+ 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);
if (tx_done->msdu_id >= htt->max_num_pending_tx) {
- ath10k_warn("warning: msdu_id %d too big, ignoring\n",
+ ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n",
tx_done->msdu_id);
return;
}
@@ -182,7 +183,7 @@ void ath10k_peer_map_event(struct ath10k_htt *htt,
wake_up(&ar->peer_mapping_wq);
}
- ath10k_dbg(ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
ev->vdev_id, ev->addr, ev->peer_id);
set_bit(ev->peer_id, peer->peer_ids);
@@ -199,12 +200,12 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt,
spin_lock_bh(&ar->data_lock);
peer = ath10k_peer_find_by_id(ar, ev->peer_id);
if (!peer) {
- ath10k_warn("peer-unmap-event: unknown peer id %d\n",
+ ath10k_warn(ar, "peer-unmap-event: unknown peer id %d\n",
ev->peer_id);
goto exit;
}
- ath10k_dbg(ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
peer->vdev_id, peer->addr, ev->peer_id);
clear_bit(ev->peer_id, peer->peer_ids);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c2c87c916b5..e500a3cc905 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -487,6 +487,127 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
.burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE,
};
+/* firmware 10.2 specific mappings */
+static struct wmi_cmd_map wmi_10_2_cmd_map = {
+ .init_cmdid = WMI_10_2_INIT_CMDID,
+ .start_scan_cmdid = WMI_10_2_START_SCAN_CMDID,
+ .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID,
+ .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID,
+ .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED,
+ .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
+ .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID,
+ .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID,
+ .pdev_pktlog_enable_cmdid = WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
+ .pdev_pktlog_disable_cmdid = WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
+ .pdev_set_wmm_params_cmdid = WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
+ .pdev_set_ht_cap_ie_cmdid = WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
+ .pdev_set_vht_cap_ie_cmdid = WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
+ .pdev_set_quiet_mode_cmdid = WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
+ .pdev_green_ap_ps_enable_cmdid = WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+ .pdev_get_tpc_config_cmdid = WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
+ .pdev_set_base_macaddr_cmdid = WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
+ .vdev_create_cmdid = WMI_10_2_VDEV_CREATE_CMDID,
+ .vdev_delete_cmdid = WMI_10_2_VDEV_DELETE_CMDID,
+ .vdev_start_request_cmdid = WMI_10_2_VDEV_START_REQUEST_CMDID,
+ .vdev_restart_request_cmdid = WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
+ .vdev_up_cmdid = WMI_10_2_VDEV_UP_CMDID,
+ .vdev_stop_cmdid = WMI_10_2_VDEV_STOP_CMDID,
+ .vdev_down_cmdid = WMI_10_2_VDEV_DOWN_CMDID,
+ .vdev_set_param_cmdid = WMI_10_2_VDEV_SET_PARAM_CMDID,
+ .vdev_install_key_cmdid = WMI_10_2_VDEV_INSTALL_KEY_CMDID,
+ .peer_create_cmdid = WMI_10_2_PEER_CREATE_CMDID,
+ .peer_delete_cmdid = WMI_10_2_PEER_DELETE_CMDID,
+ .peer_flush_tids_cmdid = WMI_10_2_PEER_FLUSH_TIDS_CMDID,
+ .peer_set_param_cmdid = WMI_10_2_PEER_SET_PARAM_CMDID,
+ .peer_assoc_cmdid = WMI_10_2_PEER_ASSOC_CMDID,
+ .peer_add_wds_entry_cmdid = WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
+ .peer_remove_wds_entry_cmdid = WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
+ .peer_mcast_group_cmdid = WMI_10_2_PEER_MCAST_GROUP_CMDID,
+ .bcn_tx_cmdid = WMI_10_2_BCN_TX_CMDID,
+ .pdev_send_bcn_cmdid = WMI_10_2_PDEV_SEND_BCN_CMDID,
+ .bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
+ .bcn_filter_rx_cmdid = WMI_10_2_BCN_FILTER_RX_CMDID,
+ .prb_req_filter_rx_cmdid = WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
+ .mgmt_tx_cmdid = WMI_10_2_MGMT_TX_CMDID,
+ .prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
+ .addba_clear_resp_cmdid = WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
+ .addba_send_cmdid = WMI_10_2_ADDBA_SEND_CMDID,
+ .addba_status_cmdid = WMI_10_2_ADDBA_STATUS_CMDID,
+ .delba_send_cmdid = WMI_10_2_DELBA_SEND_CMDID,
+ .addba_set_resp_cmdid = WMI_10_2_ADDBA_SET_RESP_CMDID,
+ .send_singleamsdu_cmdid = WMI_10_2_SEND_SINGLEAMSDU_CMDID,
+ .sta_powersave_mode_cmdid = WMI_10_2_STA_POWERSAVE_MODE_CMDID,
+ .sta_powersave_param_cmdid = WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
+ .sta_mimo_ps_mode_cmdid = WMI_10_2_STA_MIMO_PS_MODE_CMDID,
+ .pdev_dfs_enable_cmdid = WMI_10_2_PDEV_DFS_ENABLE_CMDID,
+ .pdev_dfs_disable_cmdid = WMI_10_2_PDEV_DFS_DISABLE_CMDID,
+ .roam_scan_mode = WMI_10_2_ROAM_SCAN_MODE,
+ .roam_scan_rssi_threshold = WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
+ .roam_scan_period = WMI_10_2_ROAM_SCAN_PERIOD,
+ .roam_scan_rssi_change_threshold =
+ WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+ .roam_ap_profile = WMI_10_2_ROAM_AP_PROFILE,
+ .ofl_scan_add_ap_profile = WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
+ .ofl_scan_remove_ap_profile = WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
+ .ofl_scan_period = WMI_10_2_OFL_SCAN_PERIOD,
+ .p2p_dev_set_device_info = WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
+ .p2p_dev_set_discoverability = WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
+ .p2p_go_set_beacon_ie = WMI_10_2_P2P_GO_SET_BEACON_IE,
+ .p2p_go_set_probe_resp_ie = WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
+ .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED,
+ .ap_ps_peer_param_cmdid = WMI_10_2_AP_PS_PEER_PARAM_CMDID,
+ .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
+ .peer_rate_retry_sched_cmdid = WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
+ .wlan_profile_trigger_cmdid = WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
+ .wlan_profile_set_hist_intvl_cmdid =
+ WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+ .wlan_profile_get_profile_data_cmdid =
+ WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+ .wlan_profile_enable_profile_id_cmdid =
+ WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+ .wlan_profile_list_profile_id_cmdid =
+ WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+ .pdev_suspend_cmdid = WMI_10_2_PDEV_SUSPEND_CMDID,
+ .pdev_resume_cmdid = WMI_10_2_PDEV_RESUME_CMDID,
+ .add_bcn_filter_cmdid = WMI_10_2_ADD_BCN_FILTER_CMDID,
+ .rmv_bcn_filter_cmdid = WMI_10_2_RMV_BCN_FILTER_CMDID,
+ .wow_add_wake_pattern_cmdid = WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
+ .wow_del_wake_pattern_cmdid = WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
+ .wow_enable_disable_wake_event_cmdid =
+ WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+ .wow_enable_cmdid = WMI_10_2_WOW_ENABLE_CMDID,
+ .wow_hostwakeup_from_sleep_cmdid =
+ WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+ .rtt_measreq_cmdid = WMI_10_2_RTT_MEASREQ_CMDID,
+ .rtt_tsf_cmdid = WMI_10_2_RTT_TSF_CMDID,
+ .vdev_spectral_scan_configure_cmdid =
+ WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
+ .vdev_spectral_scan_enable_cmdid =
+ WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
+ .request_stats_cmdid = WMI_10_2_REQUEST_STATS_CMDID,
+ .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED,
+ .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED,
+ .gtk_offload_cmdid = WMI_CMD_UNSUPPORTED,
+ .csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED,
+ .csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED,
+ .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED,
+ .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED,
+ .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED,
+ .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED,
+ .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED,
+ .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED,
+ .echo_cmdid = WMI_10_2_ECHO_CMDID,
+ .pdev_utf_cmdid = WMI_10_2_PDEV_UTF_CMDID,
+ .dbglog_cfg_cmdid = WMI_10_2_DBGLOG_CFG_CMDID,
+ .pdev_qvit_cmdid = WMI_10_2_PDEV_QVIT_CMDID,
+ .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED,
+ .vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
+ .vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
+ .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED,
+ .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID,
+ .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
+};
+
int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
{
int ret;
@@ -503,18 +624,18 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar)
return ret;
}
-static struct sk_buff *ath10k_wmi_alloc_skb(u32 len)
+static struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len)
{
struct sk_buff *skb;
u32 round_len = roundup(len, 4);
- skb = ath10k_htc_alloc_skb(WMI_SKB_HEADROOM + round_len);
+ skb = ath10k_htc_alloc_skb(ar, WMI_SKB_HEADROOM + round_len);
if (!skb)
return NULL;
skb_reserve(skb, WMI_SKB_HEADROOM);
if (!IS_ALIGNED((unsigned long)skb->data, 4))
- ath10k_warn("Unaligned WMI skb\n");
+ ath10k_warn(ar, "Unaligned WMI skb\n");
skb_put(skb, round_len);
memset(skb->data, 0, round_len);
@@ -612,7 +733,7 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,
might_sleep();
if (cmd_id == WMI_CMD_UNSUPPORTED) {
- ath10k_warn("wmi command %d is not supported by firmware\n",
+ ath10k_warn(ar, "wmi command %d is not supported by firmware\n",
cmd_id);
return ret;
}
@@ -660,7 +781,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
len = round_up(len, 4);
- wmi_skb = ath10k_wmi_alloc_skb(len);
+ wmi_skb = ath10k_wmi_alloc_skb(ar, len);
if (!wmi_skb)
return -ENOMEM;
@@ -674,7 +795,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
memcpy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr), ETH_ALEN);
memcpy(cmd->buf, skb->data, skb->len);
- ath10k_dbg(ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE,
fc & IEEE80211_FCTL_STYPE);
@@ -690,6 +811,130 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
return ret;
}
+static void ath10k_wmi_event_scan_started(struct ath10k *ar)
+{
+ lockdep_assert_held(&ar->data_lock);
+
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
+ ath10k_warn(ar, "received scan started event in an invalid scan state: %s (%d)\n",
+ ath10k_scan_state_str(ar->scan.state),
+ ar->scan.state);
+ break;
+ case ATH10K_SCAN_STARTING:
+ ar->scan.state = ATH10K_SCAN_RUNNING;
+
+ if (ar->scan.is_roc)
+ ieee80211_ready_on_channel(ar->hw);
+
+ complete(&ar->scan.started);
+ break;
+ }
+}
+
+static void ath10k_wmi_event_scan_completed(struct ath10k *ar)
+{
+ lockdep_assert_held(&ar->data_lock);
+
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ case ATH10K_SCAN_STARTING:
+ /* One suspected reason scan can be completed while starting is
+ * if firmware fails to deliver all scan events to the host,
+ * e.g. when transport pipe is full. This has been observed
+ * with spectral scan phyerr events starving wmi transport
+ * pipe. In such case the "scan completed" event should be (and
+ * is) ignored by the host as it may be just firmware's scan
+ * state machine recovering.
+ */
+ ath10k_warn(ar, "received scan completed event in an invalid scan state: %s (%d)\n",
+ ath10k_scan_state_str(ar->scan.state),
+ ar->scan.state);
+ break;
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
+ __ath10k_scan_finish(ar);
+ break;
+ }
+}
+
+static void ath10k_wmi_event_scan_bss_chan(struct ath10k *ar)
+{
+ lockdep_assert_held(&ar->data_lock);
+
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ case ATH10K_SCAN_STARTING:
+ ath10k_warn(ar, "received scan bss chan event in an invalid scan state: %s (%d)\n",
+ ath10k_scan_state_str(ar->scan.state),
+ ar->scan.state);
+ break;
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
+ ar->scan_channel = NULL;
+ break;
+ }
+}
+
+static void ath10k_wmi_event_scan_foreign_chan(struct ath10k *ar, u32 freq)
+{
+ lockdep_assert_held(&ar->data_lock);
+
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ case ATH10K_SCAN_STARTING:
+ ath10k_warn(ar, "received scan foreign chan event in an invalid scan state: %s (%d)\n",
+ ath10k_scan_state_str(ar->scan.state),
+ ar->scan.state);
+ break;
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
+ ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
+
+ if (ar->scan.is_roc && ar->scan.roc_freq == freq)
+ complete(&ar->scan.on_channel);
+ break;
+ }
+}
+
+static const char *
+ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type,
+ enum wmi_scan_completion_reason reason)
+{
+ switch (type) {
+ case WMI_SCAN_EVENT_STARTED:
+ return "started";
+ case WMI_SCAN_EVENT_COMPLETED:
+ switch (reason) {
+ case WMI_SCAN_REASON_COMPLETED:
+ return "completed";
+ case WMI_SCAN_REASON_CANCELLED:
+ return "completed [cancelled]";
+ case WMI_SCAN_REASON_PREEMPTED:
+ return "completed [preempted]";
+ case WMI_SCAN_REASON_TIMEDOUT:
+ return "completed [timedout]";
+ case WMI_SCAN_REASON_MAX:
+ break;
+ }
+ return "completed [unknown]";
+ case WMI_SCAN_EVENT_BSS_CHANNEL:
+ return "bss channel";
+ case WMI_SCAN_EVENT_FOREIGN_CHANNEL:
+ return "foreign channel";
+ case WMI_SCAN_EVENT_DEQUEUED:
+ return "dequeued";
+ case WMI_SCAN_EVENT_PREEMPTED:
+ return "preempted";
+ case WMI_SCAN_EVENT_START_FAILED:
+ return "start failed";
+ default:
+ return "unknown";
+ }
+}
+
static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data;
@@ -707,81 +952,32 @@ static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
scan_id = __le32_to_cpu(event->scan_id);
vdev_id = __le32_to_cpu(event->vdev_id);
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENTID\n");
- ath10k_dbg(ATH10K_DBG_WMI,
- "scan event type %d reason %d freq %d req_id %d "
- "scan_id %d vdev_id %d\n",
- event_type, reason, freq, req_id, scan_id, vdev_id);
-
spin_lock_bh(&ar->data_lock);
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "scan event %s type %d reason %d freq %d req_id %d scan_id %d vdev_id %d state %s (%d)\n",
+ ath10k_wmi_event_scan_type_str(event_type, reason),
+ event_type, reason, freq, req_id, scan_id, vdev_id,
+ ath10k_scan_state_str(ar->scan.state), ar->scan.state);
+
switch (event_type) {
case WMI_SCAN_EVENT_STARTED:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_STARTED\n");
- if (ar->scan.in_progress && ar->scan.is_roc)
- ieee80211_ready_on_channel(ar->hw);
-
- complete(&ar->scan.started);
+ ath10k_wmi_event_scan_started(ar);
break;
case WMI_SCAN_EVENT_COMPLETED:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_COMPLETED\n");
- switch (reason) {
- case WMI_SCAN_REASON_COMPLETED:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_COMPLETED\n");
- break;
- case WMI_SCAN_REASON_CANCELLED:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_CANCELED\n");
- break;
- case WMI_SCAN_REASON_PREEMPTED:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_PREEMPTED\n");
- break;
- case WMI_SCAN_REASON_TIMEDOUT:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_TIMEDOUT\n");
- break;
- default:
- break;
- }
-
- ar->scan_channel = NULL;
- if (!ar->scan.in_progress) {
- ath10k_warn("no scan requested, ignoring\n");
- break;
- }
-
- if (ar->scan.is_roc) {
- ath10k_offchan_tx_purge(ar);
-
- if (!ar->scan.aborting)
- ieee80211_remain_on_channel_expired(ar->hw);
- } else {
- ieee80211_scan_completed(ar->hw, ar->scan.aborting);
- }
-
- del_timer(&ar->scan.timeout);
- complete_all(&ar->scan.completed);
- ar->scan.in_progress = false;
+ ath10k_wmi_event_scan_completed(ar);
break;
case WMI_SCAN_EVENT_BSS_CHANNEL:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_BSS_CHANNEL\n");
- ar->scan_channel = NULL;
+ ath10k_wmi_event_scan_bss_chan(ar);
break;
case WMI_SCAN_EVENT_FOREIGN_CHANNEL:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_FOREIGN_CHANNEL\n");
- ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
- if (ar->scan.in_progress && ar->scan.is_roc &&
- ar->scan.roc_freq == freq) {
- complete(&ar->scan.on_channel);
- }
- break;
- case WMI_SCAN_EVENT_DEQUEUED:
- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_DEQUEUED\n");
- break;
- case WMI_SCAN_EVENT_PREEMPTED:
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_PREEMPTED\n");
+ ath10k_wmi_event_scan_foreign_chan(ar, freq);
break;
case WMI_SCAN_EVENT_START_FAILED:
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_START_FAILED\n");
+ ath10k_warn(ar, "received scan start failure event\n");
break;
+ case WMI_SCAN_EVENT_DEQUEUED:
+ case WMI_SCAN_EVENT_PREEMPTED:
default:
break;
}
@@ -911,7 +1107,7 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
memset(status, 0, sizeof(*status));
- ath10k_dbg(ATH10K_DBG_MGMT,
+ ath10k_dbg(ar, ATH10K_DBG_MGMT,
"event mgmt rx status %08x\n", rx_status);
if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) {
@@ -947,9 +1143,9 @@ static 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(ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
+ ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
} else {
- ath10k_warn("using (unreliable) phy_mode to extract band for mgmt rx\n");
+ ath10k_warn(ar, "using (unreliable) phy_mode to extract band for mgmt rx\n");
status->band = phy_mode_to_band(phy_mode);
}
@@ -979,12 +1175,12 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
}
}
- ath10k_dbg(ATH10K_DBG_MGMT,
+ ath10k_dbg(ar, ATH10K_DBG_MGMT,
"event mgmt rx skb %p len %d ftype %02x stype %02x\n",
skb, skb->len,
fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE);
- ath10k_dbg(ATH10K_DBG_MGMT,
+ ath10k_dbg(ar, ATH10K_DBG_MGMT,
"event mgmt rx freq %d band %d snr %d, rate_idx %d\n",
status->freq, status->band, status->signal,
status->rate_idx);
@@ -1034,21 +1230,26 @@ static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
rx_clear_count = __le32_to_cpu(ev->rx_clear_count);
cycle_count = __le32_to_cpu(ev->cycle_count);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n",
err_code, freq, cmd_flags, noise_floor, rx_clear_count,
cycle_count);
spin_lock_bh(&ar->data_lock);
- if (!ar->scan.in_progress) {
- ath10k_warn("chan info event without a scan request?\n");
+ switch (ar->scan.state) {
+ case ATH10K_SCAN_IDLE:
+ case ATH10K_SCAN_STARTING:
+ ath10k_warn(ar, "received chan info event without a scan request, ignoring\n");
goto exit;
+ case ATH10K_SCAN_RUNNING:
+ case ATH10K_SCAN_ABORTING:
+ break;
}
idx = freq_to_idx(ar, freq);
if (idx >= ARRAY_SIZE(ar->survey)) {
- ath10k_warn("chan info: invalid frequency %d (idx %d out of bounds)\n",
+ ath10k_warn(ar, "chan info: invalid frequency %d (idx %d out of bounds)\n",
freq, idx);
goto exit;
}
@@ -1079,12 +1280,12 @@ exit:
static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
}
static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
skb->len);
trace_ath10k_wmi_dbglog(skb->data, skb->len);
@@ -1097,7 +1298,7 @@ static void ath10k_wmi_event_update_stats(struct ath10k *ar,
{
struct wmi_stats_event *ev = (struct wmi_stats_event *)skb->data;
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
ath10k_debug_read_target_stats(ar, ev);
}
@@ -1107,7 +1308,7 @@ static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
{
struct wmi_vdev_start_response_event *ev;
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
ev = (struct wmi_vdev_start_response_event *)skb->data;
@@ -1120,7 +1321,7 @@ static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n");
complete(&ar->vdev_setup_done);
}
@@ -1132,14 +1333,14 @@ static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
ev = (struct wmi_peer_sta_kickout_event *)skb->data;
- ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
ev->peer_macaddr.addr);
rcu_read_lock();
sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL);
if (!sta) {
- ath10k_warn("Spurious quick kickout for STA %pM\n",
+ ath10k_warn(ar, "Spurious quick kickout for STA %pM\n",
ev->peer_macaddr.addr);
goto exit;
}
@@ -1216,7 +1417,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
(u8 *)skb_tail_pointer(bcn) - ies);
if (!ie) {
if (arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
- ath10k_warn("no tim ie found;\n");
+ ath10k_warn(ar, "no tim ie found;\n");
return;
}
@@ -1236,12 +1437,12 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
ie_len += expand_size;
pvm_len += expand_size;
} else {
- ath10k_warn("tim expansion failed\n");
+ ath10k_warn(ar, "tim expansion failed\n");
}
}
if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) {
- ath10k_warn("tim pvm length is too great (%d)\n", pvm_len);
+ ath10k_warn(ar, "tim pvm length is too great (%d)\n", pvm_len);
return;
}
@@ -1255,7 +1456,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
}
- ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
tim->dtim_count, tim->dtim_period,
tim->bitmap_ctrl, pvm_len);
}
@@ -1333,7 +1534,7 @@ static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif,
if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
return;
- ath10k_dbg(ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
+ 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)
@@ -1381,7 +1582,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
ev = (struct wmi_host_swba_event *)skb->data;
map = __le32_to_cpu(ev->vdev_map);
- ath10k_dbg(ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
+ ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
ev->vdev_map);
for (; map; map >>= 1, vdev_id++) {
@@ -1391,13 +1592,13 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
i++;
if (i >= WMI_MAX_AP_VDEV) {
- ath10k_warn("swba has corrupted vdev map\n");
+ ath10k_warn(ar, "swba has corrupted vdev map\n");
break;
}
bcn_info = &ev->bcn_info[i];
- ath10k_dbg(ATH10K_DBG_MGMT,
+ ath10k_dbg(ar, ATH10K_DBG_MGMT,
"mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n",
i,
__le32_to_cpu(bcn_info->tim_info.tim_len),
@@ -1411,7 +1612,8 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
arvif = ath10k_get_arvif(ar, vdev_id);
if (arvif == NULL) {
- ath10k_warn("no vif for vdev_id %d found\n", vdev_id);
+ ath10k_warn(ar, "no vif for vdev_id %d found\n",
+ vdev_id);
continue;
}
@@ -1428,7 +1630,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
bcn = ieee80211_beacon_get(ar->hw, arvif->vif);
if (!bcn) {
- ath10k_warn("could not get mac80211 beacon\n");
+ ath10k_warn(ar, "could not get mac80211 beacon\n");
continue;
}
@@ -1440,7 +1642,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
if (arvif->beacon) {
if (!arvif->beacon_sent)
- ath10k_warn("SWBA overrun on vdev %d\n",
+ ath10k_warn(ar, "SWBA overrun on vdev %d\n",
arvif->vdev_id);
dma_unmap_single(arvif->ar->dev,
@@ -1456,7 +1658,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
ret = dma_mapping_error(arvif->ar->dev,
ATH10K_SKB_CB(bcn)->paddr);
if (ret) {
- ath10k_warn("failed to map beacon: %d\n", ret);
+ ath10k_warn(ar, "failed to map beacon: %d\n", ret);
dev_kfree_skb_any(bcn);
goto skip;
}
@@ -1473,7 +1675,7 @@ skip:
static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
}
static void ath10k_dfs_radar_report(struct ath10k *ar,
@@ -1489,20 +1691,20 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
reg0 = __le32_to_cpu(rr->reg0);
reg1 = __le32_to_cpu(rr->reg1);
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi phyerr radar report chirp %d max_width %d agc_total_gain %d pulse_delta_diff %d\n",
MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP),
MS(reg0, RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH),
MS(reg0, RADAR_REPORT_REG0_AGC_TOTAL_GAIN),
MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_DIFF));
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi phyerr radar report pulse_delta_pean %d pulse_sidx %d fft_valid %d agc_mb_gain %d subchan_mask %d\n",
MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_PEAK),
MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX),
MS(reg1, RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID),
MS(reg1, RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN),
MS(reg1, RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK));
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi phyerr radar report pulse_tsf_offset 0x%X pulse_dur: %d\n",
MS(reg1, RADAR_REPORT_REG1_PULSE_TSF_OFFSET),
MS(reg1, RADAR_REPORT_REG1_PULSE_DUR));
@@ -1529,25 +1731,25 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
pe.width = width;
pe.rssi = rssi;
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ 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);
ATH10K_DFS_STAT_INC(ar, pulses_detected);
if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) {
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"dfs no pulse pattern detected, yet\n");
return;
}
- ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n");
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n");
ATH10K_DFS_STAT_INC(ar, radar_detected);
/* Control radar events reporting in debugfs file
dfs_block_radar_events */
if (ar->dfs_block_radar_events) {
- ath10k_info("DFS Radar detected, but ignored as requested\n");
+ ath10k_info(ar, "DFS Radar detected, but ignored as requested\n");
return;
}
@@ -1566,13 +1768,13 @@ static int ath10k_dfs_fft_report(struct ath10k *ar,
reg1 = __le32_to_cpu(fftr->reg1);
rssi = event->hdr.rssi_combined;
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n",
MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB),
MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB),
MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX),
MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX));
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi phyerr fft report rel_pwr_db %d avgpwr_db %d peak_mag %d num_store_bin %d\n",
MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB),
MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB),
@@ -1584,7 +1786,7 @@ static int ath10k_dfs_fft_report(struct ath10k *ar,
/* false event detection */
if (rssi == DFS_RSSI_POSSIBLY_FALSE &&
peak_mag < 2 * DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE) {
- ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs false pulse detected\n");
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs false pulse detected\n");
ATH10K_DFS_STAT_INC(ar, pulses_discarded);
return -EINVAL;
}
@@ -1603,7 +1805,7 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
u8 *tlv_buf;
buf_len = __le32_to_cpu(event->hdr.buf_len);
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n",
event->hdr.phy_err_code, event->hdr.rssi_combined,
__le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len);
@@ -1616,21 +1818,22 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
while (i < buf_len) {
if (i + sizeof(*tlv) > buf_len) {
- ath10k_warn("too short buf for tlv header (%d)\n", i);
+ ath10k_warn(ar, "too short buf for tlv header (%d)\n",
+ i);
return;
}
tlv = (struct phyerr_tlv *)&event->bufp[i];
tlv_len = __le16_to_cpu(tlv->len);
tlv_buf = &event->bufp[i + sizeof(*tlv)];
- ath10k_dbg(ATH10K_DBG_REGULATORY,
+ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
"wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n",
tlv_len, tlv->tag, tlv->sig);
switch (tlv->tag) {
case PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY:
if (i + sizeof(*tlv) + sizeof(*rr) > buf_len) {
- ath10k_warn("too short radar pulse summary (%d)\n",
+ ath10k_warn(ar, "too short radar pulse summary (%d)\n",
i);
return;
}
@@ -1640,7 +1843,8 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
break;
case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) {
- ath10k_warn("too short fft report (%d)\n", i);
+ ath10k_warn(ar, "too short fft report (%d)\n",
+ i);
return;
}
@@ -1659,7 +1863,54 @@ static void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
struct wmi_single_phyerr_rx_event *event,
u64 tsf)
{
- ath10k_dbg(ATH10K_DBG_WMI, "wmi event spectral scan\n");
+ int buf_len, tlv_len, res, i = 0;
+ struct phyerr_tlv *tlv;
+ u8 *tlv_buf;
+ struct phyerr_fft_report *fftr;
+ size_t fftr_len;
+
+ buf_len = __le32_to_cpu(event->hdr.buf_len);
+
+ while (i < buf_len) {
+ if (i + sizeof(*tlv) > buf_len) {
+ ath10k_warn(ar, "failed to parse phyerr tlv header at byte %d\n",
+ i);
+ return;
+ }
+
+ tlv = (struct phyerr_tlv *)&event->bufp[i];
+ tlv_len = __le16_to_cpu(tlv->len);
+ tlv_buf = &event->bufp[i + sizeof(*tlv)];
+
+ if (i + sizeof(*tlv) + tlv_len > buf_len) {
+ ath10k_warn(ar, "failed to parse phyerr tlv payload at byte %d\n",
+ i);
+ return;
+ }
+
+ switch (tlv->tag) {
+ case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
+ if (sizeof(*fftr) > tlv_len) {
+ ath10k_warn(ar, "failed to parse fft report at byte %d\n",
+ i);
+ return;
+ }
+
+ fftr_len = tlv_len - sizeof(*fftr);
+ fftr = (struct phyerr_fft_report *)tlv_buf;
+ res = ath10k_spectral_process_fft(ar, event,
+ fftr, fftr_len,
+ tsf);
+ if (res < 0) {
+ ath10k_warn(ar, "failed to process fft report: %d\n",
+ res);
+ return;
+ }
+ break;
+ }
+
+ i += sizeof(*tlv) + tlv_len;
+ }
}
static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
@@ -1674,7 +1925,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
/* Check if combined event available */
if (left_len < sizeof(*comb_event)) {
- ath10k_warn("wmi phyerr combined event wrong len\n");
+ ath10k_warn(ar, "wmi phyerr combined event wrong len\n");
return;
}
@@ -1688,7 +1939,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
tsf <<= 32;
tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi event phyerr count %d tsf64 0x%llX\n",
count, tsf);
@@ -1696,7 +1947,8 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
for (i = 0; i < count; i++) {
/* Check if we can read event header */
if (left_len < sizeof(*event)) {
- ath10k_warn("single event (%d) wrong head len\n", i);
+ ath10k_warn(ar, "single event (%d) wrong head len\n",
+ i);
return;
}
@@ -1706,7 +1958,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
phy_err_code = event->hdr.phy_err_code;
if (left_len < buf_len) {
- ath10k_warn("single event (%d) wrong buf len\n", i);
+ ath10k_warn(ar, "single event (%d) wrong buf len\n", i);
return;
}
@@ -1733,13 +1985,13 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
}
static void ath10k_wmi_event_profile_match(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n");
}
static void ath10k_wmi_event_debug_print(struct ath10k *ar,
@@ -1764,7 +2016,7 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar,
}
if (i == sizeof(buf) - 1)
- ath10k_warn("wmi debug print truncated: %d\n", skb->len);
+ ath10k_warn(ar, "wmi debug print truncated: %d\n", skb->len);
/* for some reason the debug prints end with \n, remove that */
if (skb->data[i - 1] == '\n')
@@ -1773,108 +2025,108 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar,
/* the last byte is always reserved for the null character */
buf[i] = '\0';
- ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf);
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf);
}
static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n");
}
static void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n");
}
static void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n");
}
static void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n");
}
static void ath10k_wmi_event_rtt_error_report(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n");
}
static void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
}
static void ath10k_wmi_event_dcs_interference(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n");
}
static void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n");
}
static void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
}
static void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n");
}
static void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n");
}
static void ath10k_wmi_event_delba_complete(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n");
}
static void ath10k_wmi_event_addba_complete(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n");
}
static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
}
static void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n");
}
static void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n");
}
static void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar,
struct sk_buff *skb)
{
- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
}
static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
@@ -1894,7 +2146,7 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
&paddr,
GFP_ATOMIC);
if (!ar->wmi.mem_chunks[idx].vaddr) {
- ath10k_warn("failed to allocate memory chunk\n");
+ ath10k_warn(ar, "failed to allocate memory chunk\n");
return -ENOMEM;
}
@@ -1912,9 +2164,10 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
struct sk_buff *skb)
{
struct wmi_service_ready_event *ev = (void *)skb->data;
+ DECLARE_BITMAP(svc_bmap, WMI_SERVICE_BM_SIZE) = {};
if (skb->len < sizeof(*ev)) {
- ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
+ ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
skb->len, sizeof(*ev));
return;
}
@@ -1937,7 +2190,7 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features);
if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
- ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
+ ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
}
@@ -1945,8 +2198,10 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
ar->ath_common.regulatory.current_rd =
__le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
- ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap,
- sizeof(ev->wmi_service_bitmap));
+ wmi_main_svc_map(ev->wmi_service_bitmap, svc_bmap);
+ ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
+ ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
+ ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
if (strlen(ar->hw->wiphy->fw_version) == 0) {
snprintf(ar->hw->wiphy->fw_version,
@@ -1960,11 +2215,11 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
/* FIXME: it probably should be better to support this */
if (__le32_to_cpu(ev->num_mem_reqs) > 0) {
- ath10k_warn("target requested %d memory chunks; ignoring\n",
+ ath10k_warn(ar, "target requested %d memory chunks; ignoring\n",
__le32_to_cpu(ev->num_mem_reqs));
}
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
__le32_to_cpu(ev->sw_version),
__le32_to_cpu(ev->sw_version_1),
@@ -1986,9 +2241,10 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
int ret;
struct wmi_service_ready_event_10x *ev = (void *)skb->data;
+ DECLARE_BITMAP(svc_bmap, WMI_SERVICE_BM_SIZE) = {};
if (skb->len < sizeof(*ev)) {
- ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
+ ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
skb->len, sizeof(*ev));
return;
}
@@ -2004,7 +2260,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
- ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
+ ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
}
@@ -2012,8 +2268,10 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
ar->ath_common.regulatory.current_rd =
__le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
- ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap,
- sizeof(ev->wmi_service_bitmap));
+ wmi_10x_svc_map(ev->wmi_service_bitmap, svc_bmap);
+ ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
+ ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
+ ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
if (strlen(ar->hw->wiphy->fw_version) == 0) {
snprintf(ar->hw->wiphy->fw_version,
@@ -2026,7 +2284,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
num_mem_reqs = __le32_to_cpu(ev->num_mem_reqs);
if (num_mem_reqs > ATH10K_MAX_MEM_REQS) {
- ath10k_warn("requested memory chunks number (%d) exceeds the limit\n",
+ ath10k_warn(ar, "requested memory chunks number (%d) exceeds the limit\n",
num_mem_reqs);
return;
}
@@ -2034,7 +2292,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
if (!num_mem_reqs)
goto exit;
- ath10k_dbg(ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n",
num_mem_reqs);
for (i = 0; i < num_mem_reqs; ++i) {
@@ -2052,7 +2310,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS)
num_units = TARGET_10X_NUM_VDEVS + 1;
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n",
req_id,
__le32_to_cpu(ev->mem_reqs[i].num_units),
@@ -2067,7 +2325,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
}
exit:
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi event service ready sw_ver 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
__le32_to_cpu(ev->sw_version),
__le32_to_cpu(ev->abi_version),
@@ -2091,7 +2349,7 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb)
memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n",
__le32_to_cpu(ev->sw_version),
__le32_to_cpu(ev->abi_version),
@@ -2211,7 +2469,7 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb)
ath10k_wmi_ready_event_rx(ar, skb);
break;
default:
- ath10k_warn("Unknown eventid: %d\n", id);
+ ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
}
@@ -2318,27 +2576,151 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
ath10k_wmi_ready_event_rx(ar, skb);
break;
default:
- ath10k_warn("Unknown eventid: %d\n", id);
+ ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
}
dev_kfree_skb(skb);
}
+static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct wmi_cmd_hdr *cmd_hdr;
+ enum wmi_10_2_event_id id;
+
+ cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
+ 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;
+
+ trace_ath10k_wmi_event(id, skb->data, skb->len);
+
+ switch (id) {
+ case WMI_10_2_MGMT_RX_EVENTID:
+ ath10k_wmi_event_mgmt_rx(ar, skb);
+ /* mgmt_rx() owns the skb now! */
+ return;
+ case WMI_10_2_SCAN_EVENTID:
+ ath10k_wmi_event_scan(ar, skb);
+ break;
+ case WMI_10_2_CHAN_INFO_EVENTID:
+ ath10k_wmi_event_chan_info(ar, skb);
+ break;
+ case WMI_10_2_ECHO_EVENTID:
+ ath10k_wmi_event_echo(ar, skb);
+ break;
+ case WMI_10_2_DEBUG_MESG_EVENTID:
+ ath10k_wmi_event_debug_mesg(ar, skb);
+ break;
+ case WMI_10_2_UPDATE_STATS_EVENTID:
+ ath10k_wmi_event_update_stats(ar, skb);
+ break;
+ case WMI_10_2_VDEV_START_RESP_EVENTID:
+ ath10k_wmi_event_vdev_start_resp(ar, skb);
+ break;
+ case WMI_10_2_VDEV_STOPPED_EVENTID:
+ ath10k_wmi_event_vdev_stopped(ar, skb);
+ break;
+ case WMI_10_2_PEER_STA_KICKOUT_EVENTID:
+ ath10k_wmi_event_peer_sta_kickout(ar, skb);
+ break;
+ case WMI_10_2_HOST_SWBA_EVENTID:
+ ath10k_wmi_event_host_swba(ar, skb);
+ break;
+ case WMI_10_2_TBTTOFFSET_UPDATE_EVENTID:
+ ath10k_wmi_event_tbttoffset_update(ar, skb);
+ break;
+ case WMI_10_2_PHYERR_EVENTID:
+ ath10k_wmi_event_phyerr(ar, skb);
+ break;
+ case WMI_10_2_ROAM_EVENTID:
+ ath10k_wmi_event_roam(ar, skb);
+ break;
+ case WMI_10_2_PROFILE_MATCH:
+ ath10k_wmi_event_profile_match(ar, skb);
+ break;
+ case WMI_10_2_DEBUG_PRINT_EVENTID:
+ ath10k_wmi_event_debug_print(ar, skb);
+ break;
+ case WMI_10_2_PDEV_QVIT_EVENTID:
+ ath10k_wmi_event_pdev_qvit(ar, skb);
+ break;
+ case WMI_10_2_WLAN_PROFILE_DATA_EVENTID:
+ ath10k_wmi_event_wlan_profile_data(ar, skb);
+ break;
+ case WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID:
+ ath10k_wmi_event_rtt_measurement_report(ar, skb);
+ break;
+ case WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID:
+ ath10k_wmi_event_tsf_measurement_report(ar, skb);
+ break;
+ case WMI_10_2_RTT_ERROR_REPORT_EVENTID:
+ ath10k_wmi_event_rtt_error_report(ar, skb);
+ break;
+ case WMI_10_2_WOW_WAKEUP_HOST_EVENTID:
+ ath10k_wmi_event_wow_wakeup_host(ar, skb);
+ break;
+ case WMI_10_2_DCS_INTERFERENCE_EVENTID:
+ ath10k_wmi_event_dcs_interference(ar, skb);
+ break;
+ case WMI_10_2_PDEV_TPC_CONFIG_EVENTID:
+ ath10k_wmi_event_pdev_tpc_config(ar, skb);
+ break;
+ case WMI_10_2_INST_RSSI_STATS_EVENTID:
+ ath10k_wmi_event_inst_rssi_stats(ar, skb);
+ break;
+ case WMI_10_2_VDEV_STANDBY_REQ_EVENTID:
+ ath10k_wmi_event_vdev_standby_req(ar, skb);
+ break;
+ case WMI_10_2_VDEV_RESUME_REQ_EVENTID:
+ ath10k_wmi_event_vdev_resume_req(ar, skb);
+ break;
+ case WMI_10_2_SERVICE_READY_EVENTID:
+ ath10k_wmi_10x_service_ready_event_rx(ar, skb);
+ break;
+ case WMI_10_2_READY_EVENTID:
+ ath10k_wmi_ready_event_rx(ar, skb);
+ break;
+ case WMI_10_2_RTT_KEEPALIVE_EVENTID:
+ case WMI_10_2_GPIO_INPUT_EVENTID:
+ case WMI_10_2_PEER_RATECODE_LIST_EVENTID:
+ case WMI_10_2_GENERIC_BUFFER_EVENTID:
+ case WMI_10_2_MCAST_BUF_RELEASE_EVENTID:
+ case WMI_10_2_MCAST_LIST_AGEOUT_EVENTID:
+ case WMI_10_2_WDS_PEER_EVENTID:
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "received event id %d not implemented\n", id);
+ break;
+ default:
+ ath10k_warn(ar, "Unknown eventid: %d\n", id);
+ break;
+ }
+
+ dev_kfree_skb(skb);
+}
static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)
{
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- ath10k_wmi_10x_process_rx(ar, skb);
- else
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+ ath10k_wmi_10_2_process_rx(ar, skb);
+ else
+ ath10k_wmi_10x_process_rx(ar, skb);
+ } else {
ath10k_wmi_main_process_rx(ar, skb);
+ }
}
/* WMI Initialization functions */
int ath10k_wmi_attach(struct ath10k *ar)
{
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- ar->wmi.cmd = &wmi_10x_cmd_map;
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+ ar->wmi.cmd = &wmi_10_2_cmd_map;
+ else
+ ar->wmi.cmd = &wmi_10x_cmd_map;
+
ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
} else {
@@ -2388,7 +2770,7 @@ int ath10k_wmi_connect(struct ath10k *ar)
status = ath10k_htc_connect_service(&ar->htc, &conn_req, &conn_resp);
if (status) {
- ath10k_warn("failed to connect to WMI CONTROL service status: %d\n",
+ ath10k_warn(ar, "failed to connect to WMI CONTROL service status: %d\n",
status);
return status;
}
@@ -2404,7 +2786,7 @@ static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd,
struct wmi_pdev_set_regdomain_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -2415,7 +2797,7 @@ static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd,
cmd->conformance_test_limit_2G = __cpu_to_le32(ctl2g);
cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x\n",
rd, rd2g, rd5g, ctl2g, ctl5g);
@@ -2431,7 +2813,7 @@ static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd,
struct wmi_pdev_set_regdomain_cmd_10x *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -2443,7 +2825,7 @@ static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd,
cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g);
cmd->dfs_domain = __cpu_to_le32(dfs_reg);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n",
rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg);
@@ -2473,7 +2855,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
if (arg->passive)
return -EINVAL;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -2491,7 +2873,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
cmd->chan.reg_classid = arg->reg_class_id;
cmd->chan.antenna_max = arg->max_antenna_gain;
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi set channel mode %d freq %d\n",
arg->mode, arg->freq);
@@ -2504,7 +2886,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
struct wmi_pdev_suspend_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -2518,7 +2900,7 @@ int ath10k_wmi_pdev_resume_target(struct ath10k *ar)
{
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(0);
+ skb = ath10k_wmi_alloc_skb(ar, 0);
if (skb == NULL)
return -ENOMEM;
@@ -2531,11 +2913,12 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
struct sk_buff *skb;
if (id == WMI_PDEV_PARAM_UNSUPPORTED) {
- ath10k_warn("pdev param %d not supported by firmware\n", id);
+ ath10k_warn(ar, "pdev param %d not supported by firmware\n",
+ id);
return -EOPNOTSUPP;
}
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -2543,7 +2926,7 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
cmd->param_id = __cpu_to_le32(id);
cmd->param_value = __cpu_to_le32(value);
- ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n",
id, value);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);
}
@@ -2610,7 +2993,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
len = sizeof(*cmd) +
(sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
- buf = ath10k_wmi_alloc_skb(len);
+ buf = ath10k_wmi_alloc_skb(ar, len);
if (!buf)
return -ENOMEM;
@@ -2621,7 +3004,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
goto out;
}
- ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
ar->wmi.num_mem_chunks);
cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
@@ -2634,7 +3017,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
cmd->host_mem_chunks[i].req_id =
__cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi chunk %d len %d requested, addr 0x%llx\n",
i,
ar->wmi.mem_chunks[i].len,
@@ -2643,7 +3026,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
out:
memcpy(&cmd->resource_config, &config, sizeof(config));
- ath10k_dbg(ATH10K_DBG_WMI, "wmi init\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n");
return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
}
@@ -2701,7 +3084,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
len = sizeof(*cmd) +
(sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
- buf = ath10k_wmi_alloc_skb(len);
+ buf = ath10k_wmi_alloc_skb(ar, len);
if (!buf)
return -ENOMEM;
@@ -2712,7 +3095,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
goto out;
}
- ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
ar->wmi.num_mem_chunks);
cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
@@ -2725,7 +3108,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
cmd->host_mem_chunks[i].req_id =
__cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi chunk %d len %d requested, addr 0x%llx\n",
i,
ar->wmi.mem_chunks[i].len,
@@ -2734,7 +3117,98 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
out:
memcpy(&cmd->resource_config, &config, sizeof(config));
- ath10k_dbg(ATH10K_DBG_WMI, "wmi init 10x\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n");
+ return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
+}
+
+static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
+{
+ struct wmi_init_cmd_10_2 *cmd;
+ struct sk_buff *buf;
+ struct wmi_resource_config_10x config = {};
+ u32 len, val;
+ int i;
+
+ config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
+ config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
+ config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
+ config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
+ config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT);
+ config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK);
+ config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK);
+ config.rx_timeout_pri_vo = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+ config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+ config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+ config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI);
+ config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE);
+
+ config.scan_max_pending_reqs =
+ __cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS);
+
+ config.bmiss_offload_max_vdev =
+ __cpu_to_le32(TARGET_10X_BMISS_OFFLOAD_MAX_VDEV);
+
+ config.roam_offload_max_vdev =
+ __cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_VDEV);
+
+ config.roam_offload_max_ap_profiles =
+ __cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES);
+
+ config.num_mcast_groups = __cpu_to_le32(TARGET_10X_NUM_MCAST_GROUPS);
+ config.num_mcast_table_elems =
+ __cpu_to_le32(TARGET_10X_NUM_MCAST_TABLE_ELEMS);
+
+ config.mcast2ucast_mode = __cpu_to_le32(TARGET_10X_MCAST2UCAST_MODE);
+ config.tx_dbg_log_size = __cpu_to_le32(TARGET_10X_TX_DBG_LOG_SIZE);
+ config.num_wds_entries = __cpu_to_le32(TARGET_10X_NUM_WDS_ENTRIES);
+ config.dma_burst_size = __cpu_to_le32(TARGET_10X_DMA_BURST_SIZE);
+ config.mac_aggr_delim = __cpu_to_le32(TARGET_10X_MAC_AGGR_DELIM);
+
+ val = TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK;
+ config.rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(val);
+
+ config.vow_config = __cpu_to_le32(TARGET_10X_VOW_CONFIG);
+
+ config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC);
+ config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES);
+
+ len = sizeof(*cmd) +
+ (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
+
+ buf = ath10k_wmi_alloc_skb(ar, len);
+ if (!buf)
+ return -ENOMEM;
+
+ cmd = (struct wmi_init_cmd_10_2 *)buf->data;
+
+ if (ar->wmi.num_mem_chunks == 0) {
+ cmd->num_host_mem_chunks = 0;
+ goto out;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
+ ar->wmi.num_mem_chunks);
+
+ cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
+
+ for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
+ cmd->host_mem_chunks[i].ptr =
+ __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
+ cmd->host_mem_chunks[i].size =
+ __cpu_to_le32(ar->wmi.mem_chunks[i].len);
+ cmd->host_mem_chunks[i].req_id =
+ __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi chunk %d len %d requested, addr 0x%llx\n",
+ i,
+ ar->wmi.mem_chunks[i].len,
+ (unsigned long long)ar->wmi.mem_chunks[i].paddr);
+ }
+out:
+ memcpy(&cmd->resource_config.common, &config, sizeof(config));
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n");
return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
}
@@ -2742,10 +3216,14 @@ int ath10k_wmi_cmd_init(struct ath10k *ar)
{
int ret;
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- ret = ath10k_wmi_10x_cmd_init(ar);
- else
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+ ret = ath10k_wmi_10_2_cmd_init(ar);
+ else
+ ret = ath10k_wmi_10x_cmd_init(ar);
+ } else {
ret = ath10k_wmi_main_cmd_init(ar);
+ }
return ret;
}
@@ -2822,7 +3300,7 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
if (len < 0)
return len; /* len contains error code here */
- skb = ath10k_wmi_alloc_skb(len);
+ skb = ath10k_wmi_alloc_skb(ar, len);
if (!skb)
return -ENOMEM;
@@ -2865,8 +3343,8 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
channels->num_chan = __cpu_to_le32(arg->n_channels);
for (i = 0; i < arg->n_channels; i++)
- channels->channel_list[i] =
- __cpu_to_le32(arg->channels[i]);
+ channels->channel_list[i].freq =
+ __cpu_to_le16(arg->channels[i]);
off += sizeof(*channels);
off += sizeof(__le32) * arg->n_channels;
@@ -2918,7 +3396,7 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
return -EINVAL;
}
- ath10k_dbg(ATH10K_DBG_WMI, "wmi start scan\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n");
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid);
}
@@ -2960,7 +3438,7 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF)
return -EINVAL;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -2976,7 +3454,7 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
cmd->scan_id = __cpu_to_le32(scan_id);
cmd->scan_req_id = __cpu_to_le32(req_id);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi stop scan reqid %d req_type %d vdev/scan_id %d\n",
arg->req_id, arg->req_type, arg->u.scan_id);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid);
@@ -2990,7 +3468,7 @@ int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
struct wmi_vdev_create_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3000,7 +3478,7 @@ int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
cmd->vdev_subtype = __cpu_to_le32(subtype);
memcpy(cmd->vdev_macaddr.addr, macaddr, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"WMI vdev create: id %d type %d subtype %d macaddr %pM\n",
vdev_id, type, subtype, macaddr);
@@ -3012,14 +3490,14 @@ int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id)
struct wmi_vdev_delete_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_vdev_delete_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"WMI vdev delete id %d\n", vdev_id);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid);
@@ -3052,7 +3530,7 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,
else
return -EINVAL; /* should not happen, we already check cmd_id */
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3090,7 +3568,7 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,
cmd->chan.reg_classid = arg->channel.reg_class_id;
cmd->chan.antenna_max = arg->channel.max_antenna_gain;
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, "
"ch_flags: 0x%0X, max_power: %d\n", cmdname, arg->vdev_id,
flags, arg->channel.freq, arg->channel.mode,
@@ -3120,14 +3598,14 @@ int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id)
struct wmi_vdev_stop_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_vdev_stop_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
- ath10k_dbg(ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id);
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid);
}
@@ -3137,7 +3615,7 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
struct wmi_vdev_up_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3146,7 +3624,7 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
cmd->vdev_assoc_id = __cpu_to_le32(aid);
memcpy(&cmd->vdev_bssid.addr, bssid, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi mgmt vdev up id 0x%x assoc id %d bssid %pM\n",
vdev_id, aid, bssid);
@@ -3158,14 +3636,14 @@ int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id)
struct wmi_vdev_down_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_vdev_down_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi mgmt vdev down id 0x%x\n", vdev_id);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid);
@@ -3178,13 +3656,13 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
struct sk_buff *skb;
if (param_id == WMI_VDEV_PARAM_UNSUPPORTED) {
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"vdev param %d not supported by firmware\n",
param_id);
return -EOPNOTSUPP;
}
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3193,7 +3671,7 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
cmd->param_id = __cpu_to_le32(param_id);
cmd->param_value = __cpu_to_le32(param_value);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi vdev id 0x%x set param %d value %d\n",
vdev_id, param_id, param_value);
@@ -3211,7 +3689,7 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar,
if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL)
return -EINVAL;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->key_len);
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + arg->key_len);
if (!skb)
return -ENOMEM;
@@ -3229,20 +3707,76 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar,
if (arg->key_data)
memcpy(cmd->key_data, arg->key_data, arg->key_len);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi vdev install key idx %d cipher %d len %d\n",
arg->key_idx, arg->key_cipher, arg->key_len);
return ath10k_wmi_cmd_send(ar, skb,
ar->wmi.cmd->vdev_install_key_cmdid);
}
+int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
+ const struct wmi_vdev_spectral_conf_arg *arg)
+{
+ struct wmi_vdev_spectral_conf_cmd *cmd;
+ struct sk_buff *skb;
+ u32 cmdid;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_vdev_spectral_conf_cmd *)skb->data;
+ cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+ cmd->scan_count = __cpu_to_le32(arg->scan_count);
+ cmd->scan_period = __cpu_to_le32(arg->scan_period);
+ cmd->scan_priority = __cpu_to_le32(arg->scan_priority);
+ cmd->scan_fft_size = __cpu_to_le32(arg->scan_fft_size);
+ cmd->scan_gc_ena = __cpu_to_le32(arg->scan_gc_ena);
+ cmd->scan_restart_ena = __cpu_to_le32(arg->scan_restart_ena);
+ cmd->scan_noise_floor_ref = __cpu_to_le32(arg->scan_noise_floor_ref);
+ cmd->scan_init_delay = __cpu_to_le32(arg->scan_init_delay);
+ cmd->scan_nb_tone_thr = __cpu_to_le32(arg->scan_nb_tone_thr);
+ cmd->scan_str_bin_thr = __cpu_to_le32(arg->scan_str_bin_thr);
+ cmd->scan_wb_rpt_mode = __cpu_to_le32(arg->scan_wb_rpt_mode);
+ cmd->scan_rssi_rpt_mode = __cpu_to_le32(arg->scan_rssi_rpt_mode);
+ cmd->scan_rssi_thr = __cpu_to_le32(arg->scan_rssi_thr);
+ cmd->scan_pwr_format = __cpu_to_le32(arg->scan_pwr_format);
+ cmd->scan_rpt_mode = __cpu_to_le32(arg->scan_rpt_mode);
+ cmd->scan_bin_scale = __cpu_to_le32(arg->scan_bin_scale);
+ cmd->scan_dbm_adj = __cpu_to_le32(arg->scan_dbm_adj);
+ cmd->scan_chn_mask = __cpu_to_le32(arg->scan_chn_mask);
+
+ cmdid = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmdid);
+}
+
+int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
+ u32 enable)
+{
+ struct wmi_vdev_spectral_enable_cmd *cmd;
+ struct sk_buff *skb;
+ u32 cmdid;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_vdev_spectral_enable_cmd *)skb->data;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->trigger_cmd = __cpu_to_le32(trigger);
+ cmd->enable_cmd = __cpu_to_le32(enable);
+
+ cmdid = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmdid);
+}
+
int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
const u8 peer_addr[ETH_ALEN])
{
struct wmi_peer_create_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3250,7 +3784,7 @@ int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
cmd->vdev_id = __cpu_to_le32(vdev_id);
memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi peer create vdev_id %d peer_addr %pM\n",
vdev_id, peer_addr);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid);
@@ -3262,7 +3796,7 @@ int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
struct wmi_peer_delete_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3270,7 +3804,7 @@ int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
cmd->vdev_id = __cpu_to_le32(vdev_id);
memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi peer delete vdev_id %d peer_addr %pM\n",
vdev_id, peer_addr);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid);
@@ -3282,7 +3816,7 @@ int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
struct wmi_peer_flush_tids_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3291,7 +3825,7 @@ int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap);
memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi peer flush vdev_id %d peer_addr %pM tids %08x\n",
vdev_id, peer_addr, tid_bitmap);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid);
@@ -3304,7 +3838,7 @@ int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
struct wmi_peer_set_param_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3314,7 +3848,7 @@ int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
cmd->param_value = __cpu_to_le32(param_value);
memcpy(&cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi vdev %d peer 0x%pM set param %d value %d\n",
vdev_id, peer_addr, param_id, param_value);
@@ -3327,7 +3861,7 @@ int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
struct wmi_sta_powersave_mode_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3335,7 +3869,7 @@ int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
cmd->vdev_id = __cpu_to_le32(vdev_id);
cmd->sta_ps_mode = __cpu_to_le32(psmode);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi set powersave id 0x%x mode %d\n",
vdev_id, psmode);
@@ -3350,7 +3884,7 @@ int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
struct wmi_sta_powersave_param_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3359,7 +3893,7 @@ int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
cmd->param_id = __cpu_to_le32(param_id);
cmd->param_value = __cpu_to_le32(value);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi sta ps param vdev_id 0x%x param %d value %d\n",
vdev_id, param_id, value);
return ath10k_wmi_cmd_send(ar, skb,
@@ -3375,7 +3909,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
if (!mac)
return -EINVAL;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3385,7 +3919,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
cmd->param_value = __cpu_to_le32(value);
memcpy(&cmd->peer_macaddr, mac, ETH_ALEN);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi ap ps param vdev_id 0x%X param %d value %d mac_addr %pM\n",
vdev_id, param_id, value, mac);
@@ -3405,7 +3939,7 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
len = sizeof(*cmd) + arg->n_channels * sizeof(struct wmi_channel);
- skb = ath10k_wmi_alloc_skb(len);
+ skb = ath10k_wmi_alloc_skb(ar, len);
if (!skb)
return -EINVAL;
@@ -3447,24 +3981,12 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
}
-int ath10k_wmi_peer_assoc(struct ath10k *ar,
- const struct wmi_peer_assoc_complete_arg *arg)
+static void
+ath10k_wmi_peer_assoc_fill(struct ath10k *ar, void *buf,
+ const struct wmi_peer_assoc_complete_arg *arg)
{
- struct wmi_peer_assoc_complete_cmd *cmd;
- struct sk_buff *skb;
+ struct wmi_common_peer_assoc_complete_cmd *cmd = buf;
- if (arg->peer_mpdu_density > 16)
- return -EINVAL;
- if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
- return -EINVAL;
- if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
- return -EINVAL;
-
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- if (!skb)
- return -ENOMEM;
-
- cmd = (struct wmi_peer_assoc_complete_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
cmd->peer_new_assoc = __cpu_to_le32(arg->peer_reassoc ? 0 : 1);
cmd->peer_associd = __cpu_to_le32(arg->peer_aid);
@@ -3499,8 +4021,80 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
__cpu_to_le32(arg->peer_vht_rates.tx_max_rate);
cmd->peer_vht_rates.tx_mcs_set =
__cpu_to_le32(arg->peer_vht_rates.tx_mcs_set);
+}
+
+static void
+ath10k_wmi_peer_assoc_fill_main(struct ath10k *ar, void *buf,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ struct wmi_main_peer_assoc_complete_cmd *cmd = buf;
+
+ ath10k_wmi_peer_assoc_fill(ar, buf, arg);
+ memset(cmd->peer_ht_info, 0, sizeof(cmd->peer_ht_info));
+}
+
+static void
+ath10k_wmi_peer_assoc_fill_10_1(struct ath10k *ar, void *buf,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ ath10k_wmi_peer_assoc_fill(ar, buf, arg);
+}
+
+static void
+ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ struct wmi_10_2_peer_assoc_complete_cmd *cmd = buf;
+ int max_mcs, max_nss;
+ u32 info0;
+
+ /* TODO: Is using max values okay with firmware? */
+ max_mcs = 0xf;
+ max_nss = 0xf;
+
+ info0 = SM(max_mcs, WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX) |
+ SM(max_nss, WMI_PEER_ASSOC_INFO0_MAX_NSS);
+
+ ath10k_wmi_peer_assoc_fill(ar, buf, arg);
+ cmd->info0 = __cpu_to_le32(info0);
+}
+
+int ath10k_wmi_peer_assoc(struct ath10k *ar,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ struct sk_buff *skb;
+ int len;
+
+ if (arg->peer_mpdu_density > 16)
+ return -EINVAL;
+ if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
+ return -EINVAL;
+ if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
+ return -EINVAL;
+
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+ len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd);
+ else
+ len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd);
+ } else {
+ len = sizeof(struct wmi_main_peer_assoc_complete_cmd);
+ }
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return -ENOMEM;
+
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+ ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg);
+ else
+ ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg);
+ } else {
+ ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg);
+ }
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi peer assoc vdev %d addr %pM (%s)\n",
arg->vdev_id, arg->addr,
arg->peer_reassoc ? "reassociate" : "new");
@@ -3518,7 +4112,7 @@ int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
int ret;
u16 fc;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3532,6 +4126,7 @@ int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
cmd->msdu_id = 0;
cmd->frame_control = __cpu_to_le32(fc);
cmd->flags = 0;
+ cmd->antenna_mask = __cpu_to_le32(WMI_BCN_TX_REF_DEF_ANTENNA);
if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero)
cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
@@ -3565,7 +4160,7 @@ int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
struct wmi_pdev_set_wmm_params *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3575,7 +4170,7 @@ int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vi, &arg->ac_vi);
ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo);
- ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set wmm params\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set wmm params\n");
return ath10k_wmi_cmd_send(ar, skb,
ar->wmi.cmd->pdev_set_wmm_params_cmdid);
}
@@ -3585,14 +4180,14 @@ int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
struct wmi_request_stats_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_request_stats_cmd *)skb->data;
cmd->stats_id = __cpu_to_le32(stats_id);
- ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id);
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);
}
@@ -3602,7 +4197,7 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,
struct wmi_force_fw_hang_cmd *cmd;
struct sk_buff *skb;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3610,7 +4205,7 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,
cmd->type = __cpu_to_le32(type);
cmd->delay_ms = __cpu_to_le32(delay_ms);
- ath10k_dbg(ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",
type, delay_ms);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
}
@@ -3621,7 +4216,7 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
struct sk_buff *skb;
u32 cfg;
- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@@ -3642,7 +4237,7 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
cmd->config_enable = __cpu_to_le32(cfg);
cmd->config_valid = __cpu_to_le32(ATH10K_DBGLOG_CFG_LOG_LVL_MASK);
- ath10k_dbg(ATH10K_DBG_WMI,
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi dbglog cfg modules %08x %08x config %08x %08x\n",
__le32_to_cpu(cmd->module_enable),
__le32_to_cpu(cmd->module_valid),
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index e93df2c1041..e7083658675 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -73,116 +73,279 @@ struct wmi_cmd_hdr {
#define HTC_PROTOCOL_VERSION 0x0002
#define WMI_PROTOCOL_VERSION 0x0002
-enum wmi_service_id {
- WMI_SERVICE_BEACON_OFFLOAD = 0, /* beacon offload */
- WMI_SERVICE_SCAN_OFFLOAD, /* scan offload */
- WMI_SERVICE_ROAM_OFFLOAD, /* roam offload */
- WMI_SERVICE_BCN_MISS_OFFLOAD, /* beacon miss offload */
- WMI_SERVICE_STA_PWRSAVE, /* fake sleep + basic power save */
- WMI_SERVICE_STA_ADVANCED_PWRSAVE, /* uapsd, pspoll, force sleep */
- WMI_SERVICE_AP_UAPSD, /* uapsd on AP */
- WMI_SERVICE_AP_DFS, /* DFS on AP */
- WMI_SERVICE_11AC, /* supports 11ac */
- WMI_SERVICE_BLOCKACK, /* Supports triggering ADDBA/DELBA from host*/
- WMI_SERVICE_PHYERR, /* PHY error */
- WMI_SERVICE_BCN_FILTER, /* Beacon filter support */
- WMI_SERVICE_RTT, /* RTT (round trip time) support */
- WMI_SERVICE_RATECTRL, /* Rate-control */
- WMI_SERVICE_WOW, /* WOW Support */
- WMI_SERVICE_RATECTRL_CACHE, /* Rate-control caching */
- WMI_SERVICE_IRAM_TIDS, /* TIDs in IRAM */
- WMI_SERVICE_ARPNS_OFFLOAD, /* ARP NS Offload support */
- WMI_SERVICE_NLO, /* Network list offload service */
- WMI_SERVICE_GTK_OFFLOAD, /* GTK offload */
- WMI_SERVICE_SCAN_SCH, /* Scan Scheduler Service */
- WMI_SERVICE_CSA_OFFLOAD, /* CSA offload service */
- WMI_SERVICE_CHATTER, /* Chatter service */
- WMI_SERVICE_COEX_FREQAVOID, /* FW report freq range to avoid */
- WMI_SERVICE_PACKET_POWER_SAVE, /* packet power save service */
- WMI_SERVICE_FORCE_FW_HANG, /* To test fw recovery mechanism */
- WMI_SERVICE_GPIO, /* GPIO service */
- WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, /* Modulated DTIM support */
- WMI_STA_UAPSD_BASIC_AUTO_TRIG, /* UAPSD AC Trigger Generation */
- WMI_STA_UAPSD_VAR_AUTO_TRIG, /* -do- */
- WMI_SERVICE_STA_KEEP_ALIVE, /* STA keep alive mechanism support */
- WMI_SERVICE_TX_ENCAP, /* Packet type for TX encapsulation */
-
- WMI_SERVICE_LAST,
- WMI_MAX_SERVICE = 64 /* max service */
+enum wmi_service {
+ WMI_SERVICE_BEACON_OFFLOAD = 0,
+ WMI_SERVICE_SCAN_OFFLOAD,
+ WMI_SERVICE_ROAM_OFFLOAD,
+ WMI_SERVICE_BCN_MISS_OFFLOAD,
+ WMI_SERVICE_STA_PWRSAVE,
+ WMI_SERVICE_STA_ADVANCED_PWRSAVE,
+ WMI_SERVICE_AP_UAPSD,
+ WMI_SERVICE_AP_DFS,
+ WMI_SERVICE_11AC,
+ WMI_SERVICE_BLOCKACK,
+ WMI_SERVICE_PHYERR,
+ WMI_SERVICE_BCN_FILTER,
+ WMI_SERVICE_RTT,
+ WMI_SERVICE_RATECTRL,
+ WMI_SERVICE_WOW,
+ WMI_SERVICE_RATECTRL_CACHE,
+ WMI_SERVICE_IRAM_TIDS,
+ WMI_SERVICE_ARPNS_OFFLOAD,
+ WMI_SERVICE_NLO,
+ WMI_SERVICE_GTK_OFFLOAD,
+ WMI_SERVICE_SCAN_SCH,
+ WMI_SERVICE_CSA_OFFLOAD,
+ WMI_SERVICE_CHATTER,
+ WMI_SERVICE_COEX_FREQAVOID,
+ WMI_SERVICE_PACKET_POWER_SAVE,
+ WMI_SERVICE_FORCE_FW_HANG,
+ WMI_SERVICE_GPIO,
+ WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+ WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+ WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+ WMI_SERVICE_STA_KEEP_ALIVE,
+ WMI_SERVICE_TX_ENCAP,
+ WMI_SERVICE_BURST,
+ WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+ WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+};
+
+enum wmi_10x_service {
+ WMI_10X_SERVICE_BEACON_OFFLOAD = 0,
+ WMI_10X_SERVICE_SCAN_OFFLOAD,
+ WMI_10X_SERVICE_ROAM_OFFLOAD,
+ WMI_10X_SERVICE_BCN_MISS_OFFLOAD,
+ WMI_10X_SERVICE_STA_PWRSAVE,
+ WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE,
+ WMI_10X_SERVICE_AP_UAPSD,
+ WMI_10X_SERVICE_AP_DFS,
+ WMI_10X_SERVICE_11AC,
+ WMI_10X_SERVICE_BLOCKACK,
+ WMI_10X_SERVICE_PHYERR,
+ WMI_10X_SERVICE_BCN_FILTER,
+ WMI_10X_SERVICE_RTT,
+ WMI_10X_SERVICE_RATECTRL,
+ WMI_10X_SERVICE_WOW,
+ WMI_10X_SERVICE_RATECTRL_CACHE,
+ WMI_10X_SERVICE_IRAM_TIDS,
+ WMI_10X_SERVICE_BURST,
+
+ /* introduced in 10.2 */
+ WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+ WMI_10X_SERVICE_FORCE_FW_HANG,
+ WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+};
+
+enum wmi_main_service {
+ WMI_MAIN_SERVICE_BEACON_OFFLOAD = 0,
+ WMI_MAIN_SERVICE_SCAN_OFFLOAD,
+ WMI_MAIN_SERVICE_ROAM_OFFLOAD,
+ WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD,
+ WMI_MAIN_SERVICE_STA_PWRSAVE,
+ WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE,
+ WMI_MAIN_SERVICE_AP_UAPSD,
+ WMI_MAIN_SERVICE_AP_DFS,
+ WMI_MAIN_SERVICE_11AC,
+ WMI_MAIN_SERVICE_BLOCKACK,
+ WMI_MAIN_SERVICE_PHYERR,
+ WMI_MAIN_SERVICE_BCN_FILTER,
+ WMI_MAIN_SERVICE_RTT,
+ WMI_MAIN_SERVICE_RATECTRL,
+ WMI_MAIN_SERVICE_WOW,
+ WMI_MAIN_SERVICE_RATECTRL_CACHE,
+ WMI_MAIN_SERVICE_IRAM_TIDS,
+ WMI_MAIN_SERVICE_ARPNS_OFFLOAD,
+ WMI_MAIN_SERVICE_NLO,
+ WMI_MAIN_SERVICE_GTK_OFFLOAD,
+ WMI_MAIN_SERVICE_SCAN_SCH,
+ WMI_MAIN_SERVICE_CSA_OFFLOAD,
+ WMI_MAIN_SERVICE_CHATTER,
+ WMI_MAIN_SERVICE_COEX_FREQAVOID,
+ WMI_MAIN_SERVICE_PACKET_POWER_SAVE,
+ WMI_MAIN_SERVICE_FORCE_FW_HANG,
+ WMI_MAIN_SERVICE_GPIO,
+ WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+ WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+ WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+ WMI_MAIN_SERVICE_STA_KEEP_ALIVE,
+ WMI_MAIN_SERVICE_TX_ENCAP,
};
static inline char *wmi_service_name(int service_id)
{
+#define SVCSTR(x) case x: return #x
+
switch (service_id) {
- case WMI_SERVICE_BEACON_OFFLOAD:
- return "BEACON_OFFLOAD";
- case WMI_SERVICE_SCAN_OFFLOAD:
- return "SCAN_OFFLOAD";
- case WMI_SERVICE_ROAM_OFFLOAD:
- return "ROAM_OFFLOAD";
- case WMI_SERVICE_BCN_MISS_OFFLOAD:
- return "BCN_MISS_OFFLOAD";
- case WMI_SERVICE_STA_PWRSAVE:
- return "STA_PWRSAVE";
- case WMI_SERVICE_STA_ADVANCED_PWRSAVE:
- return "STA_ADVANCED_PWRSAVE";
- case WMI_SERVICE_AP_UAPSD:
- return "AP_UAPSD";
- case WMI_SERVICE_AP_DFS:
- return "AP_DFS";
- case WMI_SERVICE_11AC:
- return "11AC";
- case WMI_SERVICE_BLOCKACK:
- return "BLOCKACK";
- case WMI_SERVICE_PHYERR:
- return "PHYERR";
- case WMI_SERVICE_BCN_FILTER:
- return "BCN_FILTER";
- case WMI_SERVICE_RTT:
- return "RTT";
- case WMI_SERVICE_RATECTRL:
- return "RATECTRL";
- case WMI_SERVICE_WOW:
- return "WOW";
- case WMI_SERVICE_RATECTRL_CACHE:
- return "RATECTRL CACHE";
- case WMI_SERVICE_IRAM_TIDS:
- return "IRAM TIDS";
- case WMI_SERVICE_ARPNS_OFFLOAD:
- return "ARPNS_OFFLOAD";
- case WMI_SERVICE_NLO:
- return "NLO";
- case WMI_SERVICE_GTK_OFFLOAD:
- return "GTK_OFFLOAD";
- case WMI_SERVICE_SCAN_SCH:
- return "SCAN_SCH";
- case WMI_SERVICE_CSA_OFFLOAD:
- return "CSA_OFFLOAD";
- case WMI_SERVICE_CHATTER:
- return "CHATTER";
- case WMI_SERVICE_COEX_FREQAVOID:
- return "COEX_FREQAVOID";
- case WMI_SERVICE_PACKET_POWER_SAVE:
- return "PACKET_POWER_SAVE";
- case WMI_SERVICE_FORCE_FW_HANG:
- return "FORCE FW HANG";
- case WMI_SERVICE_GPIO:
- return "GPIO";
- case WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM:
- return "MODULATED DTIM";
- case WMI_STA_UAPSD_BASIC_AUTO_TRIG:
- return "BASIC UAPSD";
- case WMI_STA_UAPSD_VAR_AUTO_TRIG:
- return "VAR UAPSD";
- case WMI_SERVICE_STA_KEEP_ALIVE:
- return "STA KEEP ALIVE";
- case WMI_SERVICE_TX_ENCAP:
- return "TX ENCAP";
+ SVCSTR(WMI_SERVICE_BEACON_OFFLOAD);
+ SVCSTR(WMI_SERVICE_SCAN_OFFLOAD);
+ SVCSTR(WMI_SERVICE_ROAM_OFFLOAD);
+ SVCSTR(WMI_SERVICE_BCN_MISS_OFFLOAD);
+ SVCSTR(WMI_SERVICE_STA_PWRSAVE);
+ SVCSTR(WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+ SVCSTR(WMI_SERVICE_AP_UAPSD);
+ SVCSTR(WMI_SERVICE_AP_DFS);
+ SVCSTR(WMI_SERVICE_11AC);
+ SVCSTR(WMI_SERVICE_BLOCKACK);
+ SVCSTR(WMI_SERVICE_PHYERR);
+ SVCSTR(WMI_SERVICE_BCN_FILTER);
+ SVCSTR(WMI_SERVICE_RTT);
+ SVCSTR(WMI_SERVICE_RATECTRL);
+ SVCSTR(WMI_SERVICE_WOW);
+ SVCSTR(WMI_SERVICE_RATECTRL_CACHE);
+ SVCSTR(WMI_SERVICE_IRAM_TIDS);
+ SVCSTR(WMI_SERVICE_ARPNS_OFFLOAD);
+ SVCSTR(WMI_SERVICE_NLO);
+ SVCSTR(WMI_SERVICE_GTK_OFFLOAD);
+ SVCSTR(WMI_SERVICE_SCAN_SCH);
+ SVCSTR(WMI_SERVICE_CSA_OFFLOAD);
+ SVCSTR(WMI_SERVICE_CHATTER);
+ SVCSTR(WMI_SERVICE_COEX_FREQAVOID);
+ SVCSTR(WMI_SERVICE_PACKET_POWER_SAVE);
+ SVCSTR(WMI_SERVICE_FORCE_FW_HANG);
+ SVCSTR(WMI_SERVICE_GPIO);
+ SVCSTR(WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM);
+ SVCSTR(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG);
+ SVCSTR(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG);
+ SVCSTR(WMI_SERVICE_STA_KEEP_ALIVE);
+ SVCSTR(WMI_SERVICE_TX_ENCAP);
+ SVCSTR(WMI_SERVICE_BURST);
+ SVCSTR(WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
+ SVCSTR(WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
default:
- return "UNKNOWN SERVICE\n";
+ return NULL;
}
+
+#undef SVCSTR
+}
+
+#define WMI_MAX_SERVICE 64
+
+#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \
+ (__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
+ BIT((svc_id)%(sizeof(u32))))
+
+#define SVCMAP(x, y) \
+ do { \
+ if (WMI_SERVICE_IS_ENABLED((in), (x))) \
+ __set_bit(y, out); \
+ } while (0)
+
+static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out)
+{
+ SVCMAP(WMI_10X_SERVICE_BEACON_OFFLOAD,
+ WMI_SERVICE_BEACON_OFFLOAD);
+ SVCMAP(WMI_10X_SERVICE_SCAN_OFFLOAD,
+ WMI_SERVICE_SCAN_OFFLOAD);
+ SVCMAP(WMI_10X_SERVICE_ROAM_OFFLOAD,
+ WMI_SERVICE_ROAM_OFFLOAD);
+ SVCMAP(WMI_10X_SERVICE_BCN_MISS_OFFLOAD,
+ WMI_SERVICE_BCN_MISS_OFFLOAD);
+ SVCMAP(WMI_10X_SERVICE_STA_PWRSAVE,
+ WMI_SERVICE_STA_PWRSAVE);
+ SVCMAP(WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE,
+ WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+ SVCMAP(WMI_10X_SERVICE_AP_UAPSD,
+ WMI_SERVICE_AP_UAPSD);
+ SVCMAP(WMI_10X_SERVICE_AP_DFS,
+ WMI_SERVICE_AP_DFS);
+ SVCMAP(WMI_10X_SERVICE_11AC,
+ WMI_SERVICE_11AC);
+ SVCMAP(WMI_10X_SERVICE_BLOCKACK,
+ WMI_SERVICE_BLOCKACK);
+ SVCMAP(WMI_10X_SERVICE_PHYERR,
+ WMI_SERVICE_PHYERR);
+ SVCMAP(WMI_10X_SERVICE_BCN_FILTER,
+ WMI_SERVICE_BCN_FILTER);
+ SVCMAP(WMI_10X_SERVICE_RTT,
+ WMI_SERVICE_RTT);
+ SVCMAP(WMI_10X_SERVICE_RATECTRL,
+ WMI_SERVICE_RATECTRL);
+ SVCMAP(WMI_10X_SERVICE_WOW,
+ WMI_SERVICE_WOW);
+ SVCMAP(WMI_10X_SERVICE_RATECTRL_CACHE,
+ WMI_SERVICE_RATECTRL_CACHE);
+ SVCMAP(WMI_10X_SERVICE_IRAM_TIDS,
+ WMI_SERVICE_IRAM_TIDS);
+ SVCMAP(WMI_10X_SERVICE_BURST,
+ WMI_SERVICE_BURST);
+ SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+ WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
+ SVCMAP(WMI_10X_SERVICE_FORCE_FW_HANG,
+ WMI_SERVICE_FORCE_FW_HANG);
+ SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+ WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
+}
+
+static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out)
+{
+ SVCMAP(WMI_MAIN_SERVICE_BEACON_OFFLOAD,
+ WMI_SERVICE_BEACON_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_SCAN_OFFLOAD,
+ WMI_SERVICE_SCAN_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_ROAM_OFFLOAD,
+ WMI_SERVICE_ROAM_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD,
+ WMI_SERVICE_BCN_MISS_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_STA_PWRSAVE,
+ WMI_SERVICE_STA_PWRSAVE);
+ SVCMAP(WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE,
+ WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+ SVCMAP(WMI_MAIN_SERVICE_AP_UAPSD,
+ WMI_SERVICE_AP_UAPSD);
+ SVCMAP(WMI_MAIN_SERVICE_AP_DFS,
+ WMI_SERVICE_AP_DFS);
+ SVCMAP(WMI_MAIN_SERVICE_11AC,
+ WMI_SERVICE_11AC);
+ SVCMAP(WMI_MAIN_SERVICE_BLOCKACK,
+ WMI_SERVICE_BLOCKACK);
+ SVCMAP(WMI_MAIN_SERVICE_PHYERR,
+ WMI_SERVICE_PHYERR);
+ SVCMAP(WMI_MAIN_SERVICE_BCN_FILTER,
+ WMI_SERVICE_BCN_FILTER);
+ SVCMAP(WMI_MAIN_SERVICE_RTT,
+ WMI_SERVICE_RTT);
+ SVCMAP(WMI_MAIN_SERVICE_RATECTRL,
+ WMI_SERVICE_RATECTRL);
+ SVCMAP(WMI_MAIN_SERVICE_WOW,
+ WMI_SERVICE_WOW);
+ SVCMAP(WMI_MAIN_SERVICE_RATECTRL_CACHE,
+ WMI_SERVICE_RATECTRL_CACHE);
+ SVCMAP(WMI_MAIN_SERVICE_IRAM_TIDS,
+ WMI_SERVICE_IRAM_TIDS);
+ SVCMAP(WMI_MAIN_SERVICE_ARPNS_OFFLOAD,
+ WMI_SERVICE_ARPNS_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_NLO,
+ WMI_SERVICE_NLO);
+ SVCMAP(WMI_MAIN_SERVICE_GTK_OFFLOAD,
+ WMI_SERVICE_GTK_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_SCAN_SCH,
+ WMI_SERVICE_SCAN_SCH);
+ SVCMAP(WMI_MAIN_SERVICE_CSA_OFFLOAD,
+ WMI_SERVICE_CSA_OFFLOAD);
+ SVCMAP(WMI_MAIN_SERVICE_CHATTER,
+ WMI_SERVICE_CHATTER);
+ SVCMAP(WMI_MAIN_SERVICE_COEX_FREQAVOID,
+ WMI_SERVICE_COEX_FREQAVOID);
+ SVCMAP(WMI_MAIN_SERVICE_PACKET_POWER_SAVE,
+ WMI_SERVICE_PACKET_POWER_SAVE);
+ SVCMAP(WMI_MAIN_SERVICE_FORCE_FW_HANG,
+ WMI_SERVICE_FORCE_FW_HANG);
+ SVCMAP(WMI_MAIN_SERVICE_GPIO,
+ WMI_SERVICE_GPIO);
+ SVCMAP(WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+ WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM);
+ SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+ WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG);
+ SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+ WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG);
+ SVCMAP(WMI_MAIN_SERVICE_STA_KEEP_ALIVE,
+ WMI_SERVICE_STA_KEEP_ALIVE);
+ SVCMAP(WMI_MAIN_SERVICE_TX_ENCAP,
+ WMI_SERVICE_TX_ENCAP);
}
+#undef SVCMAP
#define WMI_SERVICE_BM_SIZE \
((WMI_MAX_SERVICE + sizeof(u32) - 1)/sizeof(u32))
@@ -803,6 +966,159 @@ enum wmi_10x_event_id {
WMI_10X_PDEV_UTF_EVENTID = WMI_10X_END_EVENTID-1,
};
+enum wmi_10_2_cmd_id {
+ WMI_10_2_START_CMDID = 0x9000,
+ WMI_10_2_END_CMDID = 0x9FFF,
+ WMI_10_2_INIT_CMDID,
+ WMI_10_2_START_SCAN_CMDID = WMI_10_2_START_CMDID,
+ WMI_10_2_STOP_SCAN_CMDID,
+ WMI_10_2_SCAN_CHAN_LIST_CMDID,
+ WMI_10_2_ECHO_CMDID,
+ WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
+ WMI_10_2_PDEV_SET_CHANNEL_CMDID,
+ WMI_10_2_PDEV_SET_PARAM_CMDID,
+ WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
+ WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
+ WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
+ WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
+ WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
+ WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
+ WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
+ WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+ WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
+ WMI_10_2_VDEV_CREATE_CMDID,
+ WMI_10_2_VDEV_DELETE_CMDID,
+ WMI_10_2_VDEV_START_REQUEST_CMDID,
+ WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
+ WMI_10_2_VDEV_UP_CMDID,
+ WMI_10_2_VDEV_STOP_CMDID,
+ WMI_10_2_VDEV_DOWN_CMDID,
+ WMI_10_2_VDEV_STANDBY_RESPONSE_CMDID,
+ WMI_10_2_VDEV_RESUME_RESPONSE_CMDID,
+ WMI_10_2_VDEV_SET_PARAM_CMDID,
+ WMI_10_2_VDEV_INSTALL_KEY_CMDID,
+ WMI_10_2_VDEV_SET_DSCP_TID_MAP_CMDID,
+ WMI_10_2_PEER_CREATE_CMDID,
+ WMI_10_2_PEER_DELETE_CMDID,
+ WMI_10_2_PEER_FLUSH_TIDS_CMDID,
+ WMI_10_2_PEER_SET_PARAM_CMDID,
+ WMI_10_2_PEER_ASSOC_CMDID,
+ WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
+ WMI_10_2_PEER_UPDATE_WDS_ENTRY_CMDID,
+ WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
+ WMI_10_2_PEER_MCAST_GROUP_CMDID,
+ WMI_10_2_BCN_TX_CMDID,
+ WMI_10_2_BCN_PRB_TMPL_CMDID,
+ WMI_10_2_BCN_FILTER_RX_CMDID,
+ WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
+ WMI_10_2_MGMT_TX_CMDID,
+ WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
+ WMI_10_2_ADDBA_SEND_CMDID,
+ WMI_10_2_ADDBA_STATUS_CMDID,
+ WMI_10_2_DELBA_SEND_CMDID,
+ WMI_10_2_ADDBA_SET_RESP_CMDID,
+ WMI_10_2_SEND_SINGLEAMSDU_CMDID,
+ WMI_10_2_STA_POWERSAVE_MODE_CMDID,
+ WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
+ WMI_10_2_STA_MIMO_PS_MODE_CMDID,
+ WMI_10_2_DBGLOG_CFG_CMDID,
+ WMI_10_2_PDEV_DFS_ENABLE_CMDID,
+ WMI_10_2_PDEV_DFS_DISABLE_CMDID,
+ WMI_10_2_PDEV_QVIT_CMDID,
+ WMI_10_2_ROAM_SCAN_MODE,
+ WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
+ WMI_10_2_ROAM_SCAN_PERIOD,
+ WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+ WMI_10_2_ROAM_AP_PROFILE,
+ WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
+ WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
+ WMI_10_2_OFL_SCAN_PERIOD,
+ WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
+ WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
+ WMI_10_2_P2P_GO_SET_BEACON_IE,
+ WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
+ WMI_10_2_AP_PS_PEER_PARAM_CMDID,
+ WMI_10_2_AP_PS_PEER_UAPSD_COEX_CMDID,
+ WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
+ WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
+ WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+ WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+ WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+ WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+ WMI_10_2_PDEV_SUSPEND_CMDID,
+ WMI_10_2_PDEV_RESUME_CMDID,
+ WMI_10_2_ADD_BCN_FILTER_CMDID,
+ WMI_10_2_RMV_BCN_FILTER_CMDID,
+ WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
+ WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
+ WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+ WMI_10_2_WOW_ENABLE_CMDID,
+ WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+ WMI_10_2_RTT_MEASREQ_CMDID,
+ WMI_10_2_RTT_TSF_CMDID,
+ WMI_10_2_RTT_KEEPALIVE_CMDID,
+ WMI_10_2_PDEV_SEND_BCN_CMDID,
+ WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
+ WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
+ WMI_10_2_REQUEST_STATS_CMDID,
+ WMI_10_2_GPIO_CONFIG_CMDID,
+ WMI_10_2_GPIO_OUTPUT_CMDID,
+ WMI_10_2_VDEV_RATEMASK_CMDID,
+ WMI_10_2_PDEV_SMART_ANT_ENABLE_CMDID,
+ WMI_10_2_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID,
+ WMI_10_2_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID,
+ WMI_10_2_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID,
+ WMI_10_2_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID,
+ WMI_10_2_FORCE_FW_HANG_CMDID,
+ WMI_10_2_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID,
+ WMI_10_2_PDEV_SET_CTL_TABLE_CMDID,
+ WMI_10_2_PDEV_SET_MIMOGAIN_TABLE_CMDID,
+ WMI_10_2_PDEV_RATEPWR_TABLE_CMDID,
+ WMI_10_2_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID,
+ WMI_10_2_PDEV_UTF_CMDID = WMI_10_2_END_CMDID - 1,
+};
+
+enum wmi_10_2_event_id {
+ WMI_10_2_SERVICE_READY_EVENTID = 0x8000,
+ WMI_10_2_READY_EVENTID,
+ WMI_10_2_DEBUG_MESG_EVENTID,
+ WMI_10_2_START_EVENTID = 0x9000,
+ WMI_10_2_END_EVENTID = 0x9FFF,
+ WMI_10_2_SCAN_EVENTID = WMI_10_2_START_EVENTID,
+ WMI_10_2_ECHO_EVENTID,
+ WMI_10_2_UPDATE_STATS_EVENTID,
+ WMI_10_2_INST_RSSI_STATS_EVENTID,
+ WMI_10_2_VDEV_START_RESP_EVENTID,
+ WMI_10_2_VDEV_STANDBY_REQ_EVENTID,
+ WMI_10_2_VDEV_RESUME_REQ_EVENTID,
+ WMI_10_2_VDEV_STOPPED_EVENTID,
+ WMI_10_2_PEER_STA_KICKOUT_EVENTID,
+ WMI_10_2_HOST_SWBA_EVENTID,
+ WMI_10_2_TBTTOFFSET_UPDATE_EVENTID,
+ WMI_10_2_MGMT_RX_EVENTID,
+ WMI_10_2_CHAN_INFO_EVENTID,
+ WMI_10_2_PHYERR_EVENTID,
+ WMI_10_2_ROAM_EVENTID,
+ WMI_10_2_PROFILE_MATCH,
+ WMI_10_2_DEBUG_PRINT_EVENTID,
+ WMI_10_2_PDEV_QVIT_EVENTID,
+ WMI_10_2_WLAN_PROFILE_DATA_EVENTID,
+ WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID,
+ WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID,
+ WMI_10_2_RTT_ERROR_REPORT_EVENTID,
+ WMI_10_2_RTT_KEEPALIVE_EVENTID,
+ WMI_10_2_WOW_WAKEUP_HOST_EVENTID,
+ WMI_10_2_DCS_INTERFERENCE_EVENTID,
+ WMI_10_2_PDEV_TPC_CONFIG_EVENTID,
+ WMI_10_2_GPIO_INPUT_EVENTID,
+ WMI_10_2_PEER_RATECODE_LIST_EVENTID,
+ WMI_10_2_GENERIC_BUFFER_EVENTID,
+ WMI_10_2_MCAST_BUF_RELEASE_EVENTID,
+ WMI_10_2_MCAST_LIST_AGEOUT_EVENTID,
+ WMI_10_2_WDS_PEER_EVENTID,
+ WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1,
+};
+
enum wmi_phy_mode {
MODE_11A = 0, /* 11a Mode */
MODE_11G = 1, /* 11b/g Mode */
@@ -1076,10 +1392,6 @@ struct wlan_host_mem_req {
__le32 num_units;
} __packed;
-#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \
- ((((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
- (1 << ((svc_id)%(sizeof(u32))))) != 0)
-
/*
* The following struct holds optional payload for
* wmi_service_ready_event,e.g., 11ac pass some of the
@@ -1551,6 +1863,16 @@ struct wmi_resource_config_10x {
__le32 max_frag_entries;
} __packed;
+struct wmi_resource_config_10_2 {
+ struct wmi_resource_config_10x common;
+ __le32 max_peer_ext_stats;
+ __le32 smart_ant_cap; /* 0-disable, 1-enable */
+ __le32 bk_min_free;
+ __le32 be_min_free;
+ __le32 vi_min_free;
+ __le32 vo_min_free;
+ __le32 rx_batchmode; /* 0-disable, 1-enable */
+} __packed;
#define NUM_UNITS_IS_NUM_VDEVS 0x1
#define NUM_UNITS_IS_NUM_PEERS 0x2
@@ -1588,11 +1910,28 @@ struct wmi_init_cmd_10x {
struct host_memory_chunk host_mem_chunks[1];
} __packed;
+struct wmi_init_cmd_10_2 {
+ struct wmi_resource_config_10_2 resource_config;
+ __le32 num_host_mem_chunks;
+
+ /*
+ * variable number of host memory chunks.
+ * This should be the last element in the structure
+ */
+ struct host_memory_chunk host_mem_chunks[1];
+} __packed;
+
+struct wmi_chan_list_entry {
+ __le16 freq;
+ u8 phy_mode; /* valid for 10.2 only */
+ u8 reserved;
+} __packed;
+
/* TLV for channel list */
struct wmi_chan_list {
__le32 tag; /* WMI_CHAN_LIST_TAG */
__le32 num_chan;
- __le32 channel_list[0];
+ struct wmi_chan_list_entry channel_list[0];
} __packed;
struct wmi_bssid_list {
@@ -1821,7 +2160,7 @@ struct wmi_start_scan_arg {
u32 n_bssids;
u8 ie[WLAN_SCAN_PARAMS_MAX_IE_LEN];
- u32 channels[64];
+ u16 channels[64];
struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID];
struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID];
};
@@ -2067,6 +2406,7 @@ struct wmi_comb_phyerr_rx_event {
#define PHYERR_TLV_SIG 0xBB
#define PHYERR_TLV_TAG_SEARCH_FFT_REPORT 0xFB
#define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY 0xF8
+#define PHYERR_TLV_TAG_SPECTRAL_SUMMARY_REPORT 0xF9
struct phyerr_radar_report {
__le32 reg0; /* RADAR_REPORT_REG0_* */
@@ -2515,6 +2855,19 @@ enum wmi_10x_pdev_param {
WMI_10X_PDEV_PARAM_BURST_DUR,
/* Set Bursting Enable*/
WMI_10X_PDEV_PARAM_BURST_ENABLE,
+
+ /* following are available as of firmware 10.2 */
+ WMI_10X_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA,
+ WMI_10X_PDEV_PARAM_IGMPMLD_OVERRIDE,
+ WMI_10X_PDEV_PARAM_IGMPMLD_TID,
+ WMI_10X_PDEV_PARAM_ANTENNA_GAIN,
+ WMI_10X_PDEV_PARAM_RX_DECAP_MODE,
+ WMI_10X_PDEV_PARAM_RX_FILTER,
+ WMI_10X_PDEV_PARAM_SET_MCAST_TO_UCAST_TID,
+ WMI_10X_PDEV_PARAM_PROXY_STA_MODE,
+ WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_MODE,
+ WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_BUFFER,
+ WMI_10X_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER,
};
struct wmi_pdev_set_param_cmd {
@@ -3387,6 +3740,14 @@ enum wmi_10x_vdev_param {
WMI_10X_VDEV_PARAM_ENABLE_RTSCTS,
WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
+
+ /* following are available as of firmware 10.2 */
+ WMI_10X_VDEV_PARAM_TX_ENCAP_TYPE,
+ WMI_10X_VDEV_PARAM_CABQ_MAXDUR,
+ WMI_10X_VDEV_PARAM_MFPTEST_SET,
+ WMI_10X_VDEV_PARAM_RTS_FIXED_RATE,
+ WMI_10X_VDEV_PARAM_VHT_SGIMASK,
+ WMI_10X_VDEV_PARAM_VHT80_RATEMASK,
};
/* slot time long */
@@ -3444,6 +3805,98 @@ struct wmi_vdev_simple_event {
/* unsupported VDEV combination */
#define WMI_INIFIED_VDEV_START_RESPONSE_NOT_SUPPORTED 0x2
+/* TODO: please add more comments if you have in-depth information */
+struct wmi_vdev_spectral_conf_cmd {
+ __le32 vdev_id;
+
+ /* number of fft samples to send (0 for infinite) */
+ __le32 scan_count;
+ __le32 scan_period;
+ __le32 scan_priority;
+
+ /* number of bins in the FFT: 2^(fft_size - bin_scale) */
+ __le32 scan_fft_size;
+ __le32 scan_gc_ena;
+ __le32 scan_restart_ena;
+ __le32 scan_noise_floor_ref;
+ __le32 scan_init_delay;
+ __le32 scan_nb_tone_thr;
+ __le32 scan_str_bin_thr;
+ __le32 scan_wb_rpt_mode;
+ __le32 scan_rssi_rpt_mode;
+ __le32 scan_rssi_thr;
+ __le32 scan_pwr_format;
+
+ /* rpt_mode: Format of FFT report to software for spectral scan
+ * triggered FFTs:
+ * 0: No FFT report (only spectral scan summary report)
+ * 1: 2-dword summary of metrics for each completed FFT + spectral
+ * scan summary report
+ * 2: 2-dword summary of metrics for each completed FFT +
+ * 1x- oversampled bins(in-band) per FFT + spectral scan summary
+ * report
+ * 3: 2-dword summary of metrics for each completed FFT +
+ * 2x- oversampled bins (all) per FFT + spectral scan summary
+ */
+ __le32 scan_rpt_mode;
+ __le32 scan_bin_scale;
+ __le32 scan_dbm_adj;
+ __le32 scan_chn_mask;
+} __packed;
+
+struct wmi_vdev_spectral_conf_arg {
+ u32 vdev_id;
+ u32 scan_count;
+ u32 scan_period;
+ u32 scan_priority;
+ u32 scan_fft_size;
+ u32 scan_gc_ena;
+ u32 scan_restart_ena;
+ u32 scan_noise_floor_ref;
+ u32 scan_init_delay;
+ u32 scan_nb_tone_thr;
+ u32 scan_str_bin_thr;
+ u32 scan_wb_rpt_mode;
+ u32 scan_rssi_rpt_mode;
+ u32 scan_rssi_thr;
+ u32 scan_pwr_format;
+ u32 scan_rpt_mode;
+ u32 scan_bin_scale;
+ u32 scan_dbm_adj;
+ u32 scan_chn_mask;
+};
+
+#define WMI_SPECTRAL_ENABLE_DEFAULT 0
+#define WMI_SPECTRAL_COUNT_DEFAULT 0
+#define WMI_SPECTRAL_PERIOD_DEFAULT 35
+#define WMI_SPECTRAL_PRIORITY_DEFAULT 1
+#define WMI_SPECTRAL_FFT_SIZE_DEFAULT 7
+#define WMI_SPECTRAL_GC_ENA_DEFAULT 1
+#define WMI_SPECTRAL_RESTART_ENA_DEFAULT 0
+#define WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT -96
+#define WMI_SPECTRAL_INIT_DELAY_DEFAULT 80
+#define WMI_SPECTRAL_NB_TONE_THR_DEFAULT 12
+#define WMI_SPECTRAL_STR_BIN_THR_DEFAULT 8
+#define WMI_SPECTRAL_WB_RPT_MODE_DEFAULT 0
+#define WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT 0
+#define WMI_SPECTRAL_RSSI_THR_DEFAULT 0xf0
+#define WMI_SPECTRAL_PWR_FORMAT_DEFAULT 0
+#define WMI_SPECTRAL_RPT_MODE_DEFAULT 2
+#define WMI_SPECTRAL_BIN_SCALE_DEFAULT 1
+#define WMI_SPECTRAL_DBM_ADJ_DEFAULT 1
+#define WMI_SPECTRAL_CHN_MASK_DEFAULT 1
+
+struct wmi_vdev_spectral_enable_cmd {
+ __le32 vdev_id;
+ __le32 trigger_cmd;
+ __le32 enable_cmd;
+} __packed;
+
+#define WMI_SPECTRAL_TRIGGER_CMD_TRIGGER 1
+#define WMI_SPECTRAL_TRIGGER_CMD_CLEAR 2
+#define WMI_SPECTRAL_ENABLE_CMD_ENABLE 1
+#define WMI_SPECTRAL_ENABLE_CMD_DISABLE 2
+
/* Beacon processing related command and event structures */
struct wmi_bcn_tx_hdr {
__le32 vdev_id;
@@ -3470,6 +3923,11 @@ enum wmi_bcn_tx_ref_flags {
WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2,
};
+/* TODO: It is unclear why "no antenna" works while any other seemingly valid
+ * chainmask yields no beacons on the air at all.
+ */
+#define WMI_BCN_TX_REF_DEF_ANTENNA 0
+
struct wmi_bcn_tx_ref_cmd {
__le32 vdev_id;
__le32 data_len;
@@ -3481,6 +3939,8 @@ struct wmi_bcn_tx_ref_cmd {
__le32 frame_control;
/* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */
__le32 flags;
+ /* introduced in 10.2 */
+ __le32 antenna_mask;
} __packed;
/* Beacon filter */
@@ -4053,7 +4513,7 @@ struct wmi_peer_set_q_empty_callback_cmd {
/* Maximum listen interval supported by hw in units of beacon interval */
#define ATH10K_MAX_HW_LISTEN_INTERVAL 5
-struct wmi_peer_assoc_complete_cmd {
+struct wmi_common_peer_assoc_complete_cmd {
struct wmi_mac_addr peer_macaddr;
__le32 vdev_id;
__le32 peer_new_assoc; /* 1=assoc, 0=reassoc */
@@ -4071,11 +4531,30 @@ struct wmi_peer_assoc_complete_cmd {
__le32 peer_vht_caps;
__le32 peer_phymode;
struct wmi_vht_rate_set peer_vht_rates;
+};
+
+struct wmi_main_peer_assoc_complete_cmd {
+ struct wmi_common_peer_assoc_complete_cmd cmd;
+
/* HT Operation Element of the peer. Five bytes packed in 2
* INT32 array and filled from lsb to msb. */
__le32 peer_ht_info[2];
} __packed;
+struct wmi_10_1_peer_assoc_complete_cmd {
+ struct wmi_common_peer_assoc_complete_cmd cmd;
+} __packed;
+
+#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_LSB 0
+#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_MASK 0x0f
+#define WMI_PEER_ASSOC_INFO0_MAX_NSS_LSB 4
+#define WMI_PEER_ASSOC_INFO0_MAX_NSS_MASK 0xf0
+
+struct wmi_10_2_peer_assoc_complete_cmd {
+ struct wmi_common_peer_assoc_complete_cmd cmd;
+ __le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
+} __packed;
+
struct wmi_peer_assoc_complete_arg {
u8 addr[ETH_ALEN];
u32 vdev_id;
@@ -4290,6 +4769,10 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
u32 param_id, u32 param_value);
int ath10k_wmi_vdev_install_key(struct ath10k *ar,
const struct wmi_vdev_install_key_arg *arg);
+int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
+ const struct wmi_vdev_spectral_conf_arg *arg);
+int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
+ u32 enable);
int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
const u8 peer_addr[ETH_ALEN]);
int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index 7106547a14d..66b6366158b 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -351,8 +351,7 @@ void ath5k_hw_deinit(struct ath5k_hw *ah)
{
__set_bit(ATH_STAT_INVALID, ah->status);
- if (ah->ah_rf_banks != NULL)
- kfree(ah->ah_rf_banks);
+ kfree(ah->ah_rf_banks);
ath5k_eeprom_detach(ah);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 8ad2550bce7..59a87247aac 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1423,7 +1423,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb,
break;
}
- if (rxs->rate_idx >= 0 && rs->rs_rate ==
+ if (rs->rs_rate ==
ah->sbands[ah->curchan->band].bitrates[rxs->rate_idx].hw_value_short)
rxs->flag |= RX_FLAG_SHORTPRE;
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index b8d031ae63c..399728618fb 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -62,6 +62,7 @@
#include <linux/export.h>
#include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
#include <linux/seq_file.h>
#include <linux/list.h>
@@ -894,6 +895,100 @@ static const struct file_operations fops_queue = {
.llseek = default_llseek,
};
+/* debugfs: eeprom */
+
+struct eeprom_private {
+ u16 *buf;
+ int len;
+};
+
+static int open_file_eeprom(struct inode *inode, struct file *file)
+{
+ struct eeprom_private *ep;
+ struct ath5k_hw *ah = inode->i_private;
+ bool res;
+ int i, ret;
+ u32 eesize;
+ u16 val, *buf;
+
+ /* Get eeprom size */
+
+ res = ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_UPPER, &val);
+ if (!res)
+ return -EACCES;
+
+ if (val == 0) {
+ eesize = AR5K_EEPROM_INFO_MAX + AR5K_EEPROM_INFO_BASE;
+ } else {
+ eesize = (val & AR5K_EEPROM_SIZE_UPPER_MASK) <<
+ AR5K_EEPROM_SIZE_ENDLOC_SHIFT;
+ ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_LOWER, &val);
+ eesize = eesize | val;
+ }
+
+ if (eesize > 4096)
+ return -EINVAL;
+
+ /* Create buffer and read in eeprom */
+
+ buf = vmalloc(eesize);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < eesize; ++i) {
+ AR5K_EEPROM_READ(i, val);
+ buf[i] = val;
+ }
+
+ /* Create private struct and assign to file */
+
+ ep = kmalloc(sizeof(*ep), GFP_KERNEL);
+ if (!ep) {
+ ret = -ENOMEM;
+ goto freebuf;
+ }
+
+ ep->buf = buf;
+ ep->len = i;
+
+ file->private_data = (void *)ep;
+
+ return 0;
+
+freebuf:
+ vfree(buf);
+err:
+ return ret;
+
+}
+
+static ssize_t read_file_eeprom(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct eeprom_private *ep = file->private_data;
+
+ return simple_read_from_buffer(user_buf, count, ppos, ep->buf, ep->len);
+}
+
+static int release_file_eeprom(struct inode *inode, struct file *file)
+{
+ struct eeprom_private *ep = file->private_data;
+
+ vfree(ep->buf);
+ kfree(ep);
+
+ return 0;
+}
+
+static const struct file_operations fops_eeprom = {
+ .open = open_file_eeprom,
+ .read = read_file_eeprom,
+ .release = release_file_eeprom,
+ .owner = THIS_MODULE,
+};
+
void
ath5k_debug_init_device(struct ath5k_hw *ah)
@@ -921,6 +1016,8 @@ ath5k_debug_init_device(struct ath5k_hw *ah)
debugfs_create_file("misc", S_IRUSR, phydir, ah, &fops_misc);
+ debugfs_create_file("eeprom", S_IRUSR, phydir, ah, &fops_eeprom);
+
debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, ah,
&fops_frameerrors);
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index 48a6a69b57b..2062d119055 100644
--- a/drivers/net/wireless/ath/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -130,6 +130,7 @@ ath5k_register_led(struct ath5k_hw *ah, struct ath5k_led *led,
led->ah = ah;
strncpy(led->name, name, sizeof(led->name));
+ led->name[sizeof(led->name)-1] = 0;
led->led_dev.name = led->name;
led->led_dev.default_trigger = trigger;
led->led_dev.brightness_set = ath5k_led_brightness_set;
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index b65c38fdaa4..ab2709a4376 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -704,7 +704,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
* reset.
*/
static void
-ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
+ath5k_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
{
struct ath5k_hw *ah = hw->priv;
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index e535807c3d8..ba60e37213e 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -717,6 +717,7 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
memcpy(ie + 2, vif->ssid, vif->ssid_len);
memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
bss = cfg80211_inform_bss(ar->wiphy, chan,
+ CFG80211_BSS_FTYPE_UNKNOWN,
bssid, 0, cap_val, 100,
ie, 2 + vif->ssid_len + beacon_ie_len,
0, GFP_KERNEL);
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index fffd5235512..6e473fa4b13 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -1049,7 +1049,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
ar->hw.reserved_ram_size = le32_to_cpup(val);
ath6kl_dbg(ATH6KL_DBG_BOOT,
- "found reserved ram size ie 0x%d\n",
+ "found reserved ram size ie %d\n",
ar->hw.reserved_ram_size);
break;
case ATH6KL_FW_IE_CAPABILITIES:
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 21516bc6578..933aef02569 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -225,7 +225,7 @@ int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value)
ret = ath6kl_hif_diag_write32(ar, address, value);
if (ret) {
- ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
+ ath6kl_err("failed to write 0x%x during diagnose window to 0x%x\n",
address, value);
return ret;
}
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 339d89f14d3..eab0ab976af 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -1400,6 +1400,7 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = {
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))},
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))},
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))},
+ {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x2))},
{},
};
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
index c44325856b8..a6a5e40b3e9 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -1229,26 +1229,7 @@ static struct usb_driver ath6kl_usb_driver = {
.disable_hub_initiated_lpm = 1,
};
-static int ath6kl_usb_init(void)
-{
- int ret;
-
- ret = usb_register(&ath6kl_usb_driver);
- if (ret) {
- ath6kl_err("usb registration failed: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static void ath6kl_usb_exit(void)
-{
- usb_deregister(&ath6kl_usb_driver);
-}
-
-module_init(ath6kl_usb_init);
-module_exit(ath6kl_usb_exit);
+module_usb_driver(ath6kl_usb_driver);
MODULE_AUTHOR("Atheros Communications, Inc.");
MODULE_DESCRIPTION("Driver support for Atheros AR600x USB devices");
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 94df345d08c..b921005ad7e 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -619,8 +619,7 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,
dlen, freq, vif->probe_req_report);
if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
- cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0,
- GFP_ATOMIC);
+ cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
return 0;
}
@@ -659,7 +658,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
return -EINVAL;
}
ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
- cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0, GFP_ATOMIC);
+ cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
return 0;
}
@@ -1093,7 +1092,6 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
u8 *buf;
struct ieee80211_channel *channel;
struct ath6kl *ar = wmi->parent_dev;
- struct ieee80211_mgmt *mgmt;
struct cfg80211_bss *bss;
if (len <= sizeof(struct wmi_bss_info_hdr2))
@@ -1139,39 +1137,15 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
}
}
- /*
- * In theory, use of cfg80211_inform_bss() would be more natural here
- * since we do not have the full frame. However, at least for now,
- * cfg80211 can only distinguish Beacon and Probe Response frames from
- * each other when using cfg80211_inform_bss_frame(), so let's build a
- * fake IEEE 802.11 header to be able to take benefit of this.
- */
- mgmt = kmalloc(24 + len, GFP_ATOMIC);
- if (mgmt == NULL)
- return -EINVAL;
-
- if (bih->frame_type == BEACON_FTYPE) {
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_BEACON);
- memset(mgmt->da, 0xff, ETH_ALEN);
- } else {
- struct net_device *dev = vif->ndev;
-
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_PROBE_RESP);
- memcpy(mgmt->da, dev->dev_addr, ETH_ALEN);
- }
- mgmt->duration = cpu_to_le16(0);
- memcpy(mgmt->sa, bih->bssid, ETH_ALEN);
- memcpy(mgmt->bssid, bih->bssid, ETH_ALEN);
- mgmt->seq_ctrl = cpu_to_le16(0);
-
- memcpy(&mgmt->u.beacon, buf, len);
-
- bss = cfg80211_inform_bss_frame(ar->wiphy, channel, mgmt,
- 24 + len, (bih->snr - 95) * 100,
- GFP_ATOMIC);
- kfree(mgmt);
+ bss = cfg80211_inform_bss(ar->wiphy, channel,
+ bih->frame_type == BEACON_FTYPE ?
+ CFG80211_BSS_FTYPE_BEACON :
+ CFG80211_BSS_FTYPE_PRESP,
+ bih->bssid, get_unaligned_le64((__le64 *)buf),
+ get_unaligned_le16(((__le16 *)buf) + 5),
+ get_unaligned_le16(((__le16 *)buf) + 4),
+ buf + 8 + 2 + 2, len - 8 - 2 - 2,
+ (bih->snr - 95) * 100, GFP_ATOMIC);
if (bss == NULL)
return -ENOMEM;
cfg80211_put_bss(ar->wiphy, bss);
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 8fcc029a76a..896e63281b3 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -92,6 +92,15 @@ config ATH9K_DFS_CERTIFIED
developed. At this point enabling this option won't do anything
except increase code size.
+config ATH9K_DYNACK
+ bool "Atheros ath9k ACK timeout estimation algorithm (EXPERIMENTAL)"
+ depends on ATH9K
+ default n
+ ---help---
+ This option enables ath9k dynamic ACK timeout estimation algorithm
+ based on ACK frame RX timestamp, TX frame timestamp and frame
+ duration
+
config ATH9K_TX99
bool "Atheros ath9k TX99 testing support"
depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS
@@ -130,6 +139,15 @@ config ATH9K_RFKILL
seconds. Turn off to save power, but enable it if you have
a platform that can toggle the RF-Kill GPIO.
+config ATH9K_CHANNEL_CONTEXT
+ bool "Channel Context support"
+ depends on ATH9K
+ default n
+ ---help---
+ This option enables channel context support in ath9k, which is needed
+ for multi-channel concurrency. Enable this if P2P PowerSave support
+ is required.
+
config ATH9K_HTC
tristate "Atheros HTC based wireless cards support"
depends on USB && MAC80211
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 6b4020a5798..73704c1be73 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -49,6 +49,9 @@ ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o
ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
ar9003_mci.o
+
+ath9k_hw-$(CONFIG_ATH9K_DYNACK) += dynack.o
+
obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
index 59af9f9712d..669cb374720 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
@@ -381,6 +381,13 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds,
ts->evm1 = ads->AR_TxEVM1;
ts->evm2 = ads->AR_TxEVM2;
+ status = ACCESS_ONCE(ads->ds_ctl4);
+ ts->duration[0] = MS(status, AR_PacketDur0);
+ ts->duration[1] = MS(status, AR_PacketDur1);
+ status = ACCESS_ONCE(ads->ds_ctl5);
+ ts->duration[2] = MS(status, AR_PacketDur2);
+ ts->duration[3] = MS(status, AR_PacketDur3);
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 71e38e85aa9..e5f7c11fa14 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -355,9 +355,11 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
struct ath_tx_status *ts)
{
struct ar9003_txs *ads;
+ struct ar9003_txc *adc;
u32 status;
ads = &ah->ts_ring[ah->ts_tail];
+ adc = (struct ar9003_txc *)ads;
status = ACCESS_ONCE(ads->status8);
if ((status & AR_TxDone) == 0)
@@ -426,6 +428,13 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11);
ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12);
+ status = ACCESS_ONCE(adc->ctl15);
+ ts->duration[0] = MS(status, AR_PacketDur0);
+ ts->duration[1] = MS(status, AR_PacketDur1);
+ status = ACCESS_ONCE(adc->ctl16);
+ ts->duration[2] = MS(status, AR_PacketDur2);
+ ts->duration[3] = MS(status, AR_PacketDur3);
+
memset(ads, 0, sizeof(*ads));
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 7fc13a8da67..8cd116efe3e 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -31,6 +31,7 @@
#include "spectral.h"
struct ath_node;
+struct ath_vif;
extern struct ieee80211_ops ath9k_ops;
extern int ath9k_modparam_nohwcrypt;
@@ -273,6 +274,9 @@ struct ath_node {
struct ath_rx_rate_stats rx_rate_stats;
#endif
u8 key_idx[4];
+
+ u32 ackto;
+ struct list_head list;
};
struct ath_tx_control {
@@ -313,7 +317,6 @@ struct ath_rx {
bool discard_next;
u32 *rxlink;
u32 num_pkts;
- unsigned int rxfilter;
struct list_head rxbuf;
struct ath_descdma rxdma;
struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
@@ -324,6 +327,10 @@ struct ath_rx {
u32 ampdu_ref;
};
+/*******************/
+/* Channel Context */
+/*******************/
+
struct ath_chanctx {
struct cfg80211_chan_def chandef;
struct list_head vifs;
@@ -345,6 +352,9 @@ struct ath_chanctx {
bool active;
bool assigned;
bool switch_after_beacon;
+
+ short nvifs;
+ unsigned int rxfilter;
};
enum ath_chanctx_event {
@@ -354,7 +364,9 @@ enum ath_chanctx_event {
ATH_CHANCTX_EVENT_BEACON_RECEIVED,
ATH_CHANCTX_EVENT_ASSOC,
ATH_CHANCTX_EVENT_SWITCH,
+ ATH_CHANCTX_EVENT_ASSIGN,
ATH_CHANCTX_EVENT_UNASSIGN,
+ ATH_CHANCTX_EVENT_CHANGE,
ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL,
};
@@ -369,6 +381,9 @@ enum ath_chanctx_state {
struct ath_chanctx_sched {
bool beacon_pending;
bool offchannel_pending;
+ bool wait_switch;
+ bool force_noa_update;
+ bool extend_absence;
enum ath_chanctx_state state;
u8 beacon_miss;
@@ -403,38 +418,124 @@ struct ath_offchannel {
int roc_duration;
int duration;
};
+
+#define case_rtn_string(val) case val: return #val
+
#define ath_for_each_chanctx(_sc, _ctx) \
for (ctx = &sc->chanctx[0]; \
ctx <= &sc->chanctx[ARRAY_SIZE(sc->chanctx) - 1]; \
ctx++)
-void ath9k_fill_chanctx_ops(void);
-void ath9k_chanctx_force_active(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif);
+void ath_chanctx_init(struct ath_softc *sc);
+void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
+ struct cfg80211_chan_def *chandef);
+
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
static inline struct ath_chanctx *
ath_chanctx_get(struct ieee80211_chanctx_conf *ctx)
{
struct ath_chanctx **ptr = (void *) ctx->drv_priv;
return *ptr;
}
-void ath_chanctx_init(struct ath_softc *sc);
-void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
- struct cfg80211_chan_def *chandef);
-void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
- struct cfg80211_chan_def *chandef);
+
+bool ath9k_is_chanctx_enabled(void);
+void ath9k_fill_chanctx_ops(void);
+void ath9k_init_channel_context(struct ath_softc *sc);
+void ath9k_offchannel_init(struct ath_softc *sc);
+void ath9k_deinit_channel_context(struct ath_softc *sc);
+int ath9k_init_p2p(struct ath_softc *sc);
+void ath9k_deinit_p2p(struct ath_softc *sc);
+void ath9k_p2p_remove_vif(struct ath_softc *sc,
+ struct ieee80211_vif *vif);
+void ath9k_p2p_beacon_sync(struct ath_softc *sc);
+void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
+ struct ieee80211_vif *vif);
+void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
+ struct sk_buff *skb);
+void ath9k_p2p_ps_timer(void *priv);
+void ath9k_chanctx_wake_queues(struct ath_softc *sc);
void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx);
-void ath_offchannel_timer(unsigned long data);
-void ath_offchannel_channel_change(struct ath_softc *sc);
-void ath_chanctx_offchan_switch(struct ath_softc *sc,
- struct ieee80211_channel *chan);
-struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc,
- bool active);
+
+void ath_chanctx_beacon_recv_ev(struct ath_softc *sc,
+ enum ath_chanctx_event ev);
+void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
+ enum ath_chanctx_event ev);
void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
enum ath_chanctx_event ev);
-void ath_chanctx_timer(unsigned long data);
+void ath_chanctx_set_next(struct ath_softc *sc, bool force);
+void ath_offchannel_next(struct ath_softc *sc);
+void ath_scan_complete(struct ath_softc *sc, bool abort);
+void ath_roc_complete(struct ath_softc *sc, bool abort);
+
+#else
+
+static inline bool ath9k_is_chanctx_enabled(void)
+{
+ return false;
+}
+static inline void ath9k_fill_chanctx_ops(void)
+{
+}
+static inline void ath9k_init_channel_context(struct ath_softc *sc)
+{
+}
+static inline void ath9k_offchannel_init(struct ath_softc *sc)
+{
+}
+static inline void ath9k_deinit_channel_context(struct ath_softc *sc)
+{
+}
+static inline void ath_chanctx_beacon_recv_ev(struct ath_softc *sc,
+ enum ath_chanctx_event ev)
+{
+}
+static inline void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
+ enum ath_chanctx_event ev)
+{
+}
+static inline void ath_chanctx_event(struct ath_softc *sc,
+ struct ieee80211_vif *vif,
+ enum ath_chanctx_event ev)
+{
+}
+static inline int ath9k_init_p2p(struct ath_softc *sc)
+{
+ return 0;
+}
+static inline void ath9k_deinit_p2p(struct ath_softc *sc)
+{
+}
+static inline void ath9k_p2p_remove_vif(struct ath_softc *sc,
+ struct ieee80211_vif *vif)
+{
+}
+static inline void ath9k_p2p_beacon_sync(struct ath_softc *sc)
+{
+}
+static inline void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
+ struct ieee80211_vif *vif)
+{
+}
+static inline void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
+ struct sk_buff *skb)
+{
+}
+static inline void ath9k_p2p_ps_timer(struct ath_softc *sc)
+{
+}
+static inline void ath9k_chanctx_wake_queues(struct ath_softc *sc)
+{
+}
+static inline void ath_chanctx_check_active(struct ath_softc *sc,
+ struct ath_chanctx *ctx)
+{
+}
+
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan);
-int ath_startrecv(struct ath_softc *sc);
+void ath_startrecv(struct ath_softc *sc);
bool ath_stoprecv(struct ath_softc *sc);
u32 ath_calcrxfilter(struct ath_softc *sc);
int ath_rx_init(struct ath_softc *sc, int nbufs);
@@ -479,6 +580,8 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
/* VIFs */
/********/
+#define P2P_DEFAULT_CTWIN 10
+
struct ath_vif {
struct list_head list;
@@ -497,8 +600,10 @@ struct ath_vif {
u32 offchannel_start;
u32 offchannel_duration;
- u32 periodic_noa_start;
- u32 periodic_noa_duration;
+ /* These are used for both periodic and one-shot */
+ u32 noa_start;
+ u32 noa_duration;
+ bool periodic_noa;
};
struct ath9k_vif_iter_data {
@@ -583,7 +688,6 @@ void ath9k_csa_update(struct ath_softc *sc);
#define ATH_PAPRD_TIMEOUT 100 /* msecs */
#define ATH_PLL_WORK_INTERVAL 100
-void ath_chanctx_work(struct work_struct *work);
void ath_tx_complete_poll_work(struct work_struct *work);
void ath_reset_work(struct work_struct *work);
bool ath_hw_check(struct ath_softc *sc);
@@ -597,8 +701,6 @@ int ath_update_survey_stats(struct ath_softc *sc);
void ath_update_survey_nf(struct ath_softc *sc, int channel);
void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
void ath_ps_full_sleep(unsigned long data);
-void ath9k_p2p_ps_timer(void *priv);
-void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif);
void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
/**********/
@@ -849,12 +951,17 @@ struct ath_softc {
struct mutex mutex;
struct work_struct paprd_work;
struct work_struct hw_reset_work;
- struct work_struct chanctx_work;
struct completion paprd_complete;
wait_queue_head_t tx_wait;
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+ struct work_struct chanctx_work;
struct ath_gen_timer *p2p_ps_timer;
struct ath_vif *p2p_ps_vif;
+ struct ath_chanctx_sched sched;
+ struct ath_offchannel offchannel;
+ struct ath_chanctx *next_chan;
+#endif
unsigned long driver_data;
@@ -865,7 +972,6 @@ struct ath_softc {
bool ps_enabled;
bool ps_idle;
short nbcnvifs;
- short nvifs;
unsigned long ps_usecount;
struct ath_rx rx;
@@ -875,10 +981,7 @@ struct ath_softc {
struct cfg80211_chan_def cur_chandef;
struct ath_chanctx chanctx[ATH9K_NUM_CHANCTX];
struct ath_chanctx *cur_chan;
- struct ath_chanctx *next_chan;
spinlock_t chan_lock;
- struct ath_offchannel offchannel;
- struct ath_chanctx_sched sched;
#ifdef CONFIG_MAC80211_LEDS
bool led_registered;
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index eaf8f058c15..a6af855ef6e 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -108,55 +108,6 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
}
-static void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
- struct sk_buff *skb)
-{
- static const u8 noa_ie_hdr[] = {
- WLAN_EID_VENDOR_SPECIFIC, /* type */
- 0, /* length */
- 0x50, 0x6f, 0x9a, /* WFA OUI */
- 0x09, /* P2P subtype */
- 0x0c, /* Notice of Absence */
- 0x00, /* LSB of little-endian len */
- 0x00, /* MSB of little-endian len */
- };
-
- struct ieee80211_p2p_noa_attr *noa;
- int noa_len, noa_desc, i = 0;
- u8 *hdr;
-
- if (!avp->offchannel_duration && !avp->periodic_noa_duration)
- return;
-
- noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration;
- noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc;
-
- hdr = skb_put(skb, sizeof(noa_ie_hdr));
- memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr));
- hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2;
- hdr[7] = noa_len;
-
- noa = (void *) skb_put(skb, noa_len);
- memset(noa, 0, noa_len);
-
- noa->index = avp->noa_index;
- if (avp->periodic_noa_duration) {
- u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
-
- noa->desc[i].count = 255;
- noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start);
- noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration);
- noa->desc[i].interval = cpu_to_le32(interval);
- i++;
- }
-
- if (avp->offchannel_duration) {
- noa->desc[i].count = 1;
- noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start);
- noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration);
- }
-}
-
static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -232,7 +183,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
spin_unlock_bh(&cabq->axq_lock);
if (skb && cabq_depth) {
- if (sc->nvifs > 1) {
+ if (sc->cur_chan->nvifs > 1) {
ath_dbg(common, BEACON,
"Flushing previous cabq traffic\n");
ath_draintxq(sc, cabq);
@@ -427,9 +378,10 @@ void ath9k_beacon_tasklet(unsigned long data)
/* EDMA devices check that in the tx completion function. */
if (!edma) {
- if (sc->sched.beacon_pending)
- ath_chanctx_event(sc, NULL,
+ if (ath9k_is_chanctx_enabled()) {
+ ath_chanctx_beacon_sent_ev(sc,
ATH_CHANCTX_EVENT_BEACON_SENT);
+ }
if (ath9k_csa_is_finished(sc, vif))
return;
@@ -438,7 +390,10 @@ void ath9k_beacon_tasklet(unsigned long data)
if (!vif || !vif->bss_conf.enable_beacon)
return;
- ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
+ if (ath9k_is_chanctx_enabled()) {
+ ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
+ }
+
bf = ath9k_beacon_generate(sc->hw, vif);
if (sc->beacon.bmisscnt != 0) {
@@ -559,6 +514,18 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
struct ieee80211_vif *vif)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_vif *avp = (void *)vif->drv_priv;
+
+ if (ath9k_is_chanctx_enabled()) {
+ /*
+ * If the VIF is not present in the current channel context,
+ * then we can't do the usual opmode checks. Allow the
+ * beacon config for the VIF to be updated in this case and
+ * return immediately.
+ */
+ if (sc->cur_chan != avp->chanctx)
+ return true;
+ }
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
if ((vif->type != NL80211_IFTYPE_AP) ||
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index ba214ebdcd1..77c99eb5583 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -83,8 +83,6 @@ static int ath_set_channel(struct ath_softc *sc)
if (hw->conf.radar_enabled) {
u32 rxfilter;
- /* set HW specific DFS configuration */
- ath9k_hw_set_radar_params(ah);
rxfilter = ath9k_hw_getrxfilter(ah);
rxfilter |= ATH9K_RX_FILTER_PHYRADAR |
ATH9K_RX_FILTER_PHYERR;
@@ -101,202 +99,6 @@ static int ath_set_channel(struct ath_softc *sc)
return 0;
}
-static bool
-ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
- bool powersave)
-{
- struct ieee80211_vif *vif = avp->vif;
- struct ieee80211_sta *sta = NULL;
- struct ieee80211_hdr_3addr *nullfunc;
- struct ath_tx_control txctl;
- struct sk_buff *skb;
- int band = sc->cur_chan->chandef.chan->band;
-
- switch (vif->type) {
- case NL80211_IFTYPE_STATION:
- if (!vif->bss_conf.assoc)
- return false;
-
- skb = ieee80211_nullfunc_get(sc->hw, vif);
- if (!skb)
- return false;
-
- nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
- if (powersave)
- nullfunc->frame_control |=
- cpu_to_le16(IEEE80211_FCTL_PM);
-
- skb_set_queue_mapping(skb, IEEE80211_AC_VO);
- if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
- dev_kfree_skb_any(skb);
- return false;
- }
- break;
- default:
- return false;
- }
-
- memset(&txctl, 0, sizeof(txctl));
- txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
- txctl.sta = sta;
- txctl.force_channel = true;
- if (ath_tx_start(sc->hw, skb, &txctl)) {
- ieee80211_free_txskb(sc->hw, skb);
- return false;
- }
-
- return true;
-}
-
-void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
-{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_vif *avp;
- bool active = false;
- u8 n_active = 0;
-
- if (!ctx)
- return;
-
- list_for_each_entry(avp, &ctx->vifs, list) {
- struct ieee80211_vif *vif = avp->vif;
-
- switch (vif->type) {
- case NL80211_IFTYPE_P2P_CLIENT:
- case NL80211_IFTYPE_STATION:
- if (vif->bss_conf.assoc)
- active = true;
- break;
- default:
- active = true;
- break;
- }
- }
- ctx->active = active;
-
- ath_for_each_chanctx(sc, ctx) {
- if (!ctx->assigned || list_empty(&ctx->vifs))
- continue;
- n_active++;
- }
-
- if (n_active <= 1) {
- clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags);
- return;
- }
- if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
- return;
- ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
-}
-
-static bool
-ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave)
-{
- struct ath_vif *avp;
- bool sent = false;
-
- rcu_read_lock();
- list_for_each_entry(avp, &sc->cur_chan->vifs, list) {
- if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave))
- sent = true;
- }
- rcu_read_unlock();
-
- return sent;
-}
-
-static bool ath_chanctx_defer_switch(struct ath_softc *sc)
-{
- if (sc->cur_chan == &sc->offchannel.chan)
- return false;
-
- switch (sc->sched.state) {
- case ATH_CHANCTX_STATE_SWITCH:
- return false;
- case ATH_CHANCTX_STATE_IDLE:
- if (!sc->cur_chan->switch_after_beacon)
- return false;
-
- sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
- break;
- default:
- break;
- }
-
- return true;
-}
-
-static void ath_chanctx_set_next(struct ath_softc *sc, bool force)
-{
- struct timespec ts;
- bool measure_time = false;
- bool send_ps = false;
-
- spin_lock_bh(&sc->chan_lock);
- if (!sc->next_chan) {
- spin_unlock_bh(&sc->chan_lock);
- return;
- }
-
- if (!force && ath_chanctx_defer_switch(sc)) {
- spin_unlock_bh(&sc->chan_lock);
- return;
- }
-
- if (sc->cur_chan != sc->next_chan) {
- sc->cur_chan->stopped = true;
- spin_unlock_bh(&sc->chan_lock);
-
- if (sc->next_chan == &sc->offchannel.chan) {
- getrawmonotonic(&ts);
- measure_time = true;
- }
- __ath9k_flush(sc->hw, ~0, true);
-
- if (ath_chanctx_send_ps_frame(sc, true))
- __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
-
- send_ps = true;
- spin_lock_bh(&sc->chan_lock);
-
- if (sc->cur_chan != &sc->offchannel.chan) {
- getrawmonotonic(&sc->cur_chan->tsf_ts);
- sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah);
- }
- }
- sc->cur_chan = sc->next_chan;
- sc->cur_chan->stopped = false;
- sc->next_chan = NULL;
- sc->sched.offchannel_duration = 0;
- if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE)
- sc->sched.state = ATH_CHANCTX_STATE_IDLE;
-
- spin_unlock_bh(&sc->chan_lock);
-
- if (sc->sc_ah->chip_fullsleep ||
- memcmp(&sc->cur_chandef, &sc->cur_chan->chandef,
- sizeof(sc->cur_chandef))) {
- ath_set_channel(sc);
- if (measure_time)
- sc->sched.channel_switch_time =
- ath9k_hw_get_tsf_offset(&ts, NULL);
- }
- if (send_ps)
- ath_chanctx_send_ps_frame(sc, false);
-
- ath_offchannel_channel_change(sc);
- ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH);
-}
-
-void ath_chanctx_work(struct work_struct *work)
-{
- struct ath_softc *sc = container_of(work, struct ath_softc,
- chanctx_work);
- mutex_lock(&sc->mutex);
- ath_chanctx_set_next(sc, false);
- mutex_unlock(&sc->mutex);
-}
-
void ath_chanctx_init(struct ath_softc *sc)
{
struct ath_chanctx *ctx;
@@ -318,115 +120,124 @@ void ath_chanctx_init(struct ath_softc *sc)
for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
INIT_LIST_HEAD(&ctx->acq[j]);
}
- ctx = &sc->offchannel.chan;
- cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
- INIT_LIST_HEAD(&ctx->vifs);
- ctx->txpower = ATH_TXPOWER_MAX;
- for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
- INIT_LIST_HEAD(&ctx->acq[j]);
- sc->offchannel.chan.offchannel = true;
-
}
-void ath9k_chanctx_force_active(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
+ struct cfg80211_chan_def *chandef)
{
- struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
- bool changed = false;
-
- if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
- return;
-
- if (!avp->chanctx)
- return;
-
- mutex_lock(&sc->mutex);
+ bool cur_chan;
spin_lock_bh(&sc->chan_lock);
- if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
- sc->next_chan = avp->chanctx;
- changed = true;
- }
- sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
+ if (chandef)
+ memcpy(&ctx->chandef, chandef, sizeof(*chandef));
+ cur_chan = sc->cur_chan == ctx;
spin_unlock_bh(&sc->chan_lock);
- if (changed)
- ath_chanctx_set_next(sc, true);
+ if (!cur_chan) {
+ ath_dbg(common, CHAN_CTX,
+ "Current context differs from the new context\n");
+ return;
+ }
- mutex_unlock(&sc->mutex);
+ ath_set_channel(sc);
}
-void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
- struct cfg80211_chan_def *chandef)
-{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
- spin_lock_bh(&sc->chan_lock);
+/**********************************************************/
+/* Functions to handle the channel context state machine. */
+/**********************************************************/
- if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) &&
- (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) {
- sc->sched.offchannel_pending = true;
- spin_unlock_bh(&sc->chan_lock);
- return;
+static const char *offchannel_state_string(enum ath_offchannel_state state)
+{
+ switch (state) {
+ case_rtn_string(ATH_OFFCHANNEL_IDLE);
+ case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND);
+ case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT);
+ case_rtn_string(ATH_OFFCHANNEL_SUSPEND);
+ case_rtn_string(ATH_OFFCHANNEL_ROC_START);
+ case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT);
+ case_rtn_string(ATH_OFFCHANNEL_ROC_DONE);
+ default:
+ return "unknown";
}
+}
- sc->next_chan = ctx;
- if (chandef)
- ctx->chandef = *chandef;
-
- if (sc->next_chan == &sc->offchannel.chan) {
- sc->sched.offchannel_duration =
- TU_TO_USEC(sc->offchannel.duration) +
- sc->sched.channel_switch_time;
+static const char *chanctx_event_string(enum ath_chanctx_event ev)
+{
+ switch (ev) {
+ case_rtn_string(ATH_CHANCTX_EVENT_BEACON_PREPARE);
+ case_rtn_string(ATH_CHANCTX_EVENT_BEACON_SENT);
+ case_rtn_string(ATH_CHANCTX_EVENT_TSF_TIMER);
+ case_rtn_string(ATH_CHANCTX_EVENT_BEACON_RECEIVED);
+ case_rtn_string(ATH_CHANCTX_EVENT_ASSOC);
+ case_rtn_string(ATH_CHANCTX_EVENT_SWITCH);
+ case_rtn_string(ATH_CHANCTX_EVENT_ASSIGN);
+ case_rtn_string(ATH_CHANCTX_EVENT_UNASSIGN);
+ case_rtn_string(ATH_CHANCTX_EVENT_CHANGE);
+ case_rtn_string(ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
+ default:
+ return "unknown";
}
- spin_unlock_bh(&sc->chan_lock);
- ieee80211_queue_work(sc->hw, &sc->chanctx_work);
}
-void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
- struct cfg80211_chan_def *chandef)
+static const char *chanctx_state_string(enum ath_chanctx_state state)
{
- bool cur_chan;
+ switch (state) {
+ case_rtn_string(ATH_CHANCTX_STATE_IDLE);
+ case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_BEACON);
+ case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_TIMER);
+ case_rtn_string(ATH_CHANCTX_STATE_SWITCH);
+ case_rtn_string(ATH_CHANCTX_STATE_FORCE_ACTIVE);
+ default:
+ return "unknown";
+ }
+}
- spin_lock_bh(&sc->chan_lock);
- if (chandef)
- memcpy(&ctx->chandef, chandef, sizeof(*chandef));
- cur_chan = sc->cur_chan == ctx;
- spin_unlock_bh(&sc->chan_lock);
+void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_vif *avp;
+ bool active = false;
+ u8 n_active = 0;
- if (!cur_chan)
+ if (!ctx)
return;
- ath_set_channel(sc);
-}
+ list_for_each_entry(avp, &ctx->vifs, list) {
+ struct ieee80211_vif *vif = avp->vif;
-struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active)
-{
- struct ath_chanctx *ctx;
+ switch (vif->type) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_STATION:
+ if (vif->bss_conf.assoc)
+ active = true;
+ break;
+ default:
+ active = true;
+ break;
+ }
+ }
+ ctx->active = active;
ath_for_each_chanctx(sc, ctx) {
if (!ctx->assigned || list_empty(&ctx->vifs))
continue;
- if (active && !ctx->active)
- continue;
-
- if (ctx->switch_after_beacon)
- return ctx;
+ n_active++;
}
- return &sc->chanctx[0];
-}
-
-void ath_chanctx_offchan_switch(struct ath_softc *sc,
- struct ieee80211_channel *chan)
-{
- struct cfg80211_chan_def chandef;
-
- cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
+ if (n_active <= 1) {
+ clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags);
+ return;
+ }
+ if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+ return;
- ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef);
+ if (ath9k_is_chanctx_enabled()) {
+ ath_chanctx_event(sc, NULL,
+ ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
+ }
}
static struct ath_chanctx *
@@ -449,6 +260,9 @@ static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc)
cur = sc->cur_chan;
prev = ath_chanctx_get_next(sc, cur);
+ if (!prev->switch_after_beacon)
+ return;
+
getrawmonotonic(&ts);
cur_tsf = (u32) cur->tsf_val +
ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts);
@@ -469,25 +283,22 @@ static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc)
prev->tsf_val += offset;
}
-void ath_chanctx_timer(unsigned long data)
-{
- struct ath_softc *sc = (struct ath_softc *) data;
-
- ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
-}
-
/* Configure the TSF based hardware timer for a channel switch.
* Also set up backup software timer, in case the gen timer fails.
* This could be caused by a hardware reset.
*/
static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_hw *ah = sc->sc_ah;
ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000);
tsf_time -= ath9k_hw_gettsf32(ah);
tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1;
- mod_timer(&sc->sched.timer, tsf_time);
+ mod_timer(&sc->sched.timer, jiffies + tsf_time);
+
+ ath_dbg(common, CHAN_CTX,
+ "Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time));
}
void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
@@ -500,40 +311,56 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
struct ath_chanctx *ctx;
u32 tsf_time;
u32 beacon_int;
- bool noa_changed = false;
if (vif)
avp = (struct ath_vif *) vif->drv_priv;
spin_lock_bh(&sc->chan_lock);
+ ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s\n",
+ sc->cur_chan->chandef.center_freq1,
+ chanctx_event_string(ev),
+ chanctx_state_string(sc->sched.state));
+
switch (ev) {
case ATH_CHANCTX_EVENT_BEACON_PREPARE:
if (avp->offchannel_duration)
avp->offchannel_duration = 0;
- if (avp->chanctx != sc->cur_chan)
+ if (avp->chanctx != sc->cur_chan) {
+ ath_dbg(common, CHAN_CTX,
+ "Contexts differ, not preparing beacon\n");
break;
+ }
- if (sc->sched.offchannel_pending) {
+ if (sc->sched.offchannel_pending && !sc->sched.wait_switch) {
sc->sched.offchannel_pending = false;
sc->next_chan = &sc->offchannel.chan;
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+ ath_dbg(common, CHAN_CTX,
+ "Setting offchannel_pending to false\n");
}
ctx = ath_chanctx_get_next(sc, sc->cur_chan);
if (ctx->active && sc->sched.state == ATH_CHANCTX_STATE_IDLE) {
sc->next_chan = ctx;
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+ ath_dbg(common, CHAN_CTX,
+ "Set next context, move chanctx state to WAIT_FOR_BEACON\n");
}
/* if the timer missed its window, use the next interval */
- if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER)
+ if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER) {
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+ ath_dbg(common, CHAN_CTX,
+ "Move chanctx state from WAIT_FOR_TIMER to WAIT_FOR_BEACON\n");
+ }
if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
break;
+ ath_dbg(common, CHAN_CTX, "Preparing beacon for vif: %pM\n", vif->addr);
+
sc->sched.beacon_pending = true;
sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER);
@@ -545,47 +372,107 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
sc->sched.switch_start_time = tsf_time;
sc->cur_chan->last_beacon = sc->sched.next_tbtt;
- /* Prevent wrap-around issues */
- if (avp->periodic_noa_duration &&
- tsf_time - avp->periodic_noa_start > BIT(30))
- avp->periodic_noa_duration = 0;
-
- if (ctx->active && !avp->periodic_noa_duration) {
- avp->periodic_noa_start = tsf_time;
- avp->periodic_noa_duration =
- TU_TO_USEC(cur_conf->beacon_interval) / 2 -
- sc->sched.channel_switch_time;
- noa_changed = true;
- } else if (!ctx->active && avp->periodic_noa_duration) {
- avp->periodic_noa_duration = 0;
- noa_changed = true;
+ /*
+ * If an offchannel switch is scheduled to happen after
+ * a beacon transmission, update the NoA with one-shot
+ * values and increment the index.
+ */
+ if (sc->next_chan == &sc->offchannel.chan) {
+ avp->noa_index++;
+ avp->offchannel_start = tsf_time;
+ avp->offchannel_duration = sc->sched.offchannel_duration;
+
+ ath_dbg(common, CHAN_CTX,
+ "offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
+ avp->offchannel_duration,
+ avp->offchannel_start,
+ avp->noa_index);
+
+ /*
+ * When multiple contexts are active, the NoA
+ * has to be recalculated and advertised after
+ * an offchannel operation.
+ */
+ if (ctx->active && avp->noa_duration)
+ avp->noa_duration = 0;
+
+ break;
+ }
+
+ /*
+ * Clear the extend_absence flag if it had been
+ * set during the previous beacon transmission,
+ * since we need to revert to the normal NoA
+ * schedule.
+ */
+ if (ctx->active && sc->sched.extend_absence) {
+ avp->noa_duration = 0;
+ sc->sched.extend_absence = false;
}
/* If at least two consecutive beacons were missed on the STA
* chanctx, stay on the STA channel for one extra beacon period,
* to resync the timer properly.
*/
- if (ctx->active && sc->sched.beacon_miss >= 2)
- sc->sched.offchannel_duration = 3 * beacon_int / 2;
-
- if (sc->sched.offchannel_duration) {
- noa_changed = true;
- avp->offchannel_start = tsf_time;
- avp->offchannel_duration =
- sc->sched.offchannel_duration;
+ if (ctx->active && sc->sched.beacon_miss >= 2) {
+ avp->noa_duration = 0;
+ sc->sched.extend_absence = true;
}
- if (noa_changed)
+ /* Prevent wrap-around issues */
+ if (avp->noa_duration && tsf_time - avp->noa_start > BIT(30))
+ avp->noa_duration = 0;
+
+ /*
+ * If multiple contexts are active, start periodic
+ * NoA and increment the index for the first
+ * announcement.
+ */
+ if (ctx->active &&
+ (!avp->noa_duration || sc->sched.force_noa_update)) {
avp->noa_index++;
+ avp->noa_start = tsf_time;
+
+ if (sc->sched.extend_absence)
+ avp->noa_duration = (3 * beacon_int / 2) +
+ sc->sched.channel_switch_time;
+ else
+ avp->noa_duration =
+ TU_TO_USEC(cur_conf->beacon_interval) / 2 +
+ sc->sched.channel_switch_time;
+
+ if (test_bit(ATH_OP_SCANNING, &common->op_flags) ||
+ sc->sched.extend_absence)
+ avp->periodic_noa = false;
+ else
+ avp->periodic_noa = true;
+
+ ath_dbg(common, CHAN_CTX,
+ "noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
+ avp->noa_duration,
+ avp->noa_start,
+ avp->noa_index,
+ avp->periodic_noa);
+ }
+
+ if (ctx->active && sc->sched.force_noa_update)
+ sc->sched.force_noa_update = false;
+
break;
case ATH_CHANCTX_EVENT_BEACON_SENT:
- if (!sc->sched.beacon_pending)
+ if (!sc->sched.beacon_pending) {
+ ath_dbg(common, CHAN_CTX,
+ "No pending beacon\n");
break;
+ }
sc->sched.beacon_pending = false;
if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
break;
+ ath_dbg(common, CHAN_CTX,
+ "Move chanctx state to WAIT_FOR_TIMER\n");
+
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
ath_chanctx_setup_timer(sc, sc->sched.switch_start_time);
break;
@@ -597,6 +484,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
sc->sched.beacon_pending)
sc->sched.beacon_miss++;
+ ath_dbg(common, CHAN_CTX,
+ "Move chanctx state to SWITCH\n");
+
sc->sched.state = ATH_CHANCTX_STATE_SWITCH;
ieee80211_queue_work(sc->hw, &sc->chanctx_work);
break;
@@ -625,6 +515,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
avp->chanctx != sc->cur_chan)
break;
+ ath_dbg(common, CHAN_CTX,
+ "Move chanctx state from FORCE_ACTIVE to IDLE\n");
+
sc->sched.state = ATH_CHANCTX_STATE_IDLE;
/* fall through */
case ATH_CHANCTX_EVENT_SWITCH:
@@ -640,10 +533,15 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan);
cur_conf = &sc->cur_chan->beacon;
+ ath_dbg(common, CHAN_CTX,
+ "Move chanctx state to WAIT_FOR_TIMER (event SWITCH)\n");
+
sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
+ sc->sched.wait_switch = false;
tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2;
- if (sc->sched.beacon_miss >= 2) {
+
+ if (sc->sched.extend_absence) {
sc->sched.beacon_miss = 0;
tsf_time *= 3;
}
@@ -679,7 +577,832 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
sc->next_chan = ctx;
ieee80211_queue_work(sc->hw, &sc->chanctx_work);
break;
+ case ATH_CHANCTX_EVENT_ASSIGN:
+ /*
+ * When adding a new channel context, check if a scan
+ * is in progress and abort it since the addition of
+ * a new channel context is usually followed by VIF
+ * assignment, in which case we have to start multi-channel
+ * operation.
+ */
+ if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
+ ath_dbg(common, CHAN_CTX,
+ "Aborting HW scan to add new context\n");
+
+ spin_unlock_bh(&sc->chan_lock);
+ del_timer_sync(&sc->offchannel.timer);
+ ath_scan_complete(sc, true);
+ spin_lock_bh(&sc->chan_lock);
+ }
+ break;
+ case ATH_CHANCTX_EVENT_CHANGE:
+ break;
}
spin_unlock_bh(&sc->chan_lock);
}
+
+void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
+ enum ath_chanctx_event ev)
+{
+ if (sc->sched.beacon_pending)
+ ath_chanctx_event(sc, NULL, ev);
+}
+
+void ath_chanctx_beacon_recv_ev(struct ath_softc *sc,
+ enum ath_chanctx_event ev)
+{
+ ath_chanctx_event(sc, NULL, ev);
+}
+
+static int ath_scan_channel_duration(struct ath_softc *sc,
+ struct ieee80211_channel *chan)
+{
+ struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+
+ if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR))
+ return (HZ / 9); /* ~110 ms */
+
+ return (HZ / 16); /* ~60 ms */
+}
+
+static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
+ struct cfg80211_chan_def *chandef)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ spin_lock_bh(&sc->chan_lock);
+
+ if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) &&
+ (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) {
+ if (chandef)
+ ctx->chandef = *chandef;
+
+ sc->sched.offchannel_pending = true;
+ sc->sched.wait_switch = true;
+ sc->sched.offchannel_duration =
+ jiffies_to_usecs(sc->offchannel.duration) +
+ sc->sched.channel_switch_time;
+
+ spin_unlock_bh(&sc->chan_lock);
+ ath_dbg(common, CHAN_CTX,
+ "Set offchannel_pending to true\n");
+ return;
+ }
+
+ sc->next_chan = ctx;
+ if (chandef) {
+ ctx->chandef = *chandef;
+ ath_dbg(common, CHAN_CTX,
+ "Assigned next_chan to %d MHz\n", chandef->center_freq1);
+ }
+
+ if (sc->next_chan == &sc->offchannel.chan) {
+ sc->sched.offchannel_duration =
+ jiffies_to_usecs(sc->offchannel.duration) +
+ sc->sched.channel_switch_time;
+
+ if (chandef) {
+ ath_dbg(common, CHAN_CTX,
+ "Offchannel duration for chan %d MHz : %u\n",
+ chandef->center_freq1,
+ sc->sched.offchannel_duration);
+ }
+ }
+ spin_unlock_bh(&sc->chan_lock);
+ ieee80211_queue_work(sc->hw, &sc->chanctx_work);
+}
+
+static void ath_chanctx_offchan_switch(struct ath_softc *sc,
+ struct ieee80211_channel *chan)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct cfg80211_chan_def chandef;
+
+ cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
+ ath_dbg(common, CHAN_CTX,
+ "Channel definition created: %d MHz\n", chandef.center_freq1);
+
+ ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef);
+}
+
+static struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc,
+ bool active)
+{
+ struct ath_chanctx *ctx;
+
+ ath_for_each_chanctx(sc, ctx) {
+ if (!ctx->assigned || list_empty(&ctx->vifs))
+ continue;
+ if (active && !ctx->active)
+ continue;
+
+ if (ctx->switch_after_beacon)
+ return ctx;
+ }
+
+ return &sc->chanctx[0];
+}
+
+static void
+ath_scan_next_channel(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+ struct ieee80211_channel *chan;
+
+ if (sc->offchannel.scan_idx >= req->n_channels) {
+ ath_dbg(common, CHAN_CTX,
+ "Moving offchannel state to ATH_OFFCHANNEL_IDLE, "
+ "scan_idx: %d, n_channels: %d\n",
+ sc->offchannel.scan_idx,
+ req->n_channels);
+
+ sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
+ ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
+ NULL);
+ return;
+ }
+
+ ath_dbg(common, CHAN_CTX,
+ "Moving offchannel state to ATH_OFFCHANNEL_PROBE_SEND, scan_idx: %d\n",
+ sc->offchannel.scan_idx);
+
+ chan = req->channels[sc->offchannel.scan_idx++];
+ sc->offchannel.duration = ath_scan_channel_duration(sc, chan);
+ sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND;
+
+ ath_chanctx_offchan_switch(sc, chan);
+}
+
+void ath_offchannel_next(struct ath_softc *sc)
+{
+ struct ieee80211_vif *vif;
+
+ if (sc->offchannel.scan_req) {
+ vif = sc->offchannel.scan_vif;
+ sc->offchannel.chan.txpower = vif->bss_conf.txpower;
+ ath_scan_next_channel(sc);
+ } else if (sc->offchannel.roc_vif) {
+ vif = sc->offchannel.roc_vif;
+ sc->offchannel.chan.txpower = vif->bss_conf.txpower;
+ sc->offchannel.duration =
+ msecs_to_jiffies(sc->offchannel.roc_duration);
+ sc->offchannel.state = ATH_OFFCHANNEL_ROC_START;
+ ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan);
+ } else {
+ ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
+ NULL);
+ sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
+ if (sc->ps_idle)
+ ath_cancel_work(sc);
+ }
+}
+
+void ath_roc_complete(struct ath_softc *sc, bool abort)
+{
+ sc->offchannel.roc_vif = NULL;
+ sc->offchannel.roc_chan = NULL;
+ if (!abort)
+ ieee80211_remain_on_channel_expired(sc->hw);
+ ath_offchannel_next(sc);
+ ath9k_ps_restore(sc);
+}
+
+void ath_scan_complete(struct ath_softc *sc, bool abort)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ if (abort)
+ ath_dbg(common, CHAN_CTX, "HW scan aborted\n");
+ else
+ ath_dbg(common, CHAN_CTX, "HW scan complete\n");
+
+ sc->offchannel.scan_req = NULL;
+ sc->offchannel.scan_vif = NULL;
+ sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
+ ieee80211_scan_completed(sc->hw, abort);
+ clear_bit(ATH_OP_SCANNING, &common->op_flags);
+ spin_lock_bh(&sc->chan_lock);
+ if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+ sc->sched.force_noa_update = true;
+ spin_unlock_bh(&sc->chan_lock);
+ ath_offchannel_next(sc);
+ ath9k_ps_restore(sc);
+}
+
+static void ath_scan_send_probe(struct ath_softc *sc,
+ struct cfg80211_ssid *ssid)
+{
+ struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+ struct ieee80211_vif *vif = sc->offchannel.scan_vif;
+ struct ath_tx_control txctl = {};
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *info;
+ int band = sc->offchannel.chan.chandef.chan->band;
+
+ skb = ieee80211_probereq_get(sc->hw, vif,
+ ssid->ssid, ssid->ssid_len, req->ie_len);
+ if (!skb)
+ return;
+
+ info = IEEE80211_SKB_CB(skb);
+ if (req->no_cck)
+ info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
+
+ if (req->ie_len)
+ memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len);
+
+ skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+
+ if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
+ goto error;
+
+ txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
+ txctl.force_channel = true;
+ if (ath_tx_start(sc->hw, skb, &txctl))
+ goto error;
+
+ return;
+
+error:
+ ieee80211_free_txskb(sc->hw, skb);
+}
+
+static void ath_scan_channel_start(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+ int i;
+
+ if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) &&
+ req->n_ssids) {
+ for (i = 0; i < req->n_ssids; i++)
+ ath_scan_send_probe(sc, &req->ssids[i]);
+
+ }
+
+ ath_dbg(common, CHAN_CTX,
+ "Moving offchannel state to ATH_OFFCHANNEL_PROBE_WAIT\n");
+
+ sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT;
+ mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration);
+}
+
+static void ath_chanctx_timer(unsigned long data)
+{
+ struct ath_softc *sc = (struct ath_softc *) data;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ ath_dbg(common, CHAN_CTX,
+ "Channel context timer invoked\n");
+
+ ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
+}
+
+static void ath_offchannel_timer(unsigned long data)
+{
+ struct ath_softc *sc = (struct ath_softc *)data;
+ struct ath_chanctx *ctx;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n",
+ __func__, offchannel_state_string(sc->offchannel.state));
+
+ switch (sc->offchannel.state) {
+ case ATH_OFFCHANNEL_PROBE_WAIT:
+ if (!sc->offchannel.scan_req)
+ return;
+
+ /* get first active channel context */
+ ctx = ath_chanctx_get_oper_chan(sc, true);
+ if (ctx->active) {
+ ath_dbg(common, CHAN_CTX,
+ "Switch to oper/active context, "
+ "move offchannel state to ATH_OFFCHANNEL_SUSPEND\n");
+
+ sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND;
+ ath_chanctx_switch(sc, ctx, NULL);
+ mod_timer(&sc->offchannel.timer, jiffies + HZ / 10);
+ break;
+ }
+ /* fall through */
+ case ATH_OFFCHANNEL_SUSPEND:
+ if (!sc->offchannel.scan_req)
+ return;
+
+ ath_scan_next_channel(sc);
+ break;
+ case ATH_OFFCHANNEL_ROC_START:
+ case ATH_OFFCHANNEL_ROC_WAIT:
+ ctx = ath_chanctx_get_oper_chan(sc, false);
+ sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE;
+ ath_chanctx_switch(sc, ctx, NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+static bool
+ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
+ bool powersave)
+{
+ struct ieee80211_vif *vif = avp->vif;
+ struct ieee80211_sta *sta = NULL;
+ struct ieee80211_hdr_3addr *nullfunc;
+ struct ath_tx_control txctl;
+ struct sk_buff *skb;
+ int band = sc->cur_chan->chandef.chan->band;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ if (!vif->bss_conf.assoc)
+ return false;
+
+ skb = ieee80211_nullfunc_get(sc->hw, vif);
+ if (!skb)
+ return false;
+
+ nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
+ if (powersave)
+ nullfunc->frame_control |=
+ cpu_to_le16(IEEE80211_FCTL_PM);
+
+ skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+ if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
+ dev_kfree_skb_any(skb);
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+
+ memset(&txctl, 0, sizeof(txctl));
+ txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
+ txctl.sta = sta;
+ txctl.force_channel = true;
+ if (ath_tx_start(sc->hw, skb, &txctl)) {
+ ieee80211_free_txskb(sc->hw, skb);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave)
+{
+ struct ath_vif *avp;
+ bool sent = false;
+
+ rcu_read_lock();
+ list_for_each_entry(avp, &sc->cur_chan->vifs, list) {
+ if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave))
+ sent = true;
+ }
+ rcu_read_unlock();
+
+ return sent;
+}
+
+static bool ath_chanctx_defer_switch(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ if (sc->cur_chan == &sc->offchannel.chan)
+ return false;
+
+ switch (sc->sched.state) {
+ case ATH_CHANCTX_STATE_SWITCH:
+ return false;
+ case ATH_CHANCTX_STATE_IDLE:
+ if (!sc->cur_chan->switch_after_beacon)
+ return false;
+
+ ath_dbg(common, CHAN_CTX,
+ "Defer switch, set chanctx state to WAIT_FOR_BEACON\n");
+
+ sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static void ath_offchannel_channel_change(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n",
+ __func__, offchannel_state_string(sc->offchannel.state));
+
+ switch (sc->offchannel.state) {
+ case ATH_OFFCHANNEL_PROBE_SEND:
+ if (!sc->offchannel.scan_req)
+ return;
+
+ if (sc->cur_chan->chandef.chan !=
+ sc->offchannel.chan.chandef.chan)
+ return;
+
+ ath_scan_channel_start(sc);
+ break;
+ case ATH_OFFCHANNEL_IDLE:
+ if (!sc->offchannel.scan_req)
+ return;
+
+ ath_scan_complete(sc, false);
+ break;
+ case ATH_OFFCHANNEL_ROC_START:
+ if (sc->cur_chan != &sc->offchannel.chan)
+ break;
+
+ sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT;
+ mod_timer(&sc->offchannel.timer,
+ jiffies + sc->offchannel.duration);
+ ieee80211_ready_on_channel(sc->hw);
+ break;
+ case ATH_OFFCHANNEL_ROC_DONE:
+ ath_roc_complete(sc, false);
+ break;
+ default:
+ break;
+ }
+}
+
+void ath_chanctx_set_next(struct ath_softc *sc, bool force)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct timespec ts;
+ bool measure_time = false;
+ bool send_ps = false;
+
+ spin_lock_bh(&sc->chan_lock);
+ if (!sc->next_chan) {
+ spin_unlock_bh(&sc->chan_lock);
+ return;
+ }
+
+ if (!force && ath_chanctx_defer_switch(sc)) {
+ spin_unlock_bh(&sc->chan_lock);
+ return;
+ }
+
+ ath_dbg(common, CHAN_CTX,
+ "%s: current: %d MHz, next: %d MHz\n",
+ __func__,
+ sc->cur_chan->chandef.center_freq1,
+ sc->next_chan->chandef.center_freq1);
+
+ if (sc->cur_chan != sc->next_chan) {
+ ath_dbg(common, CHAN_CTX,
+ "Stopping current chanctx: %d\n",
+ sc->cur_chan->chandef.center_freq1);
+ sc->cur_chan->stopped = true;
+ spin_unlock_bh(&sc->chan_lock);
+
+ if (sc->next_chan == &sc->offchannel.chan) {
+ getrawmonotonic(&ts);
+ measure_time = true;
+ }
+ __ath9k_flush(sc->hw, ~0, true);
+
+ if (ath_chanctx_send_ps_frame(sc, true))
+ __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
+
+ send_ps = true;
+ spin_lock_bh(&sc->chan_lock);
+
+ if (sc->cur_chan != &sc->offchannel.chan) {
+ getrawmonotonic(&sc->cur_chan->tsf_ts);
+ sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah);
+ }
+ }
+ sc->cur_chan = sc->next_chan;
+ sc->cur_chan->stopped = false;
+ sc->next_chan = NULL;
+
+ if (!sc->sched.offchannel_pending)
+ sc->sched.offchannel_duration = 0;
+
+ if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE)
+ sc->sched.state = ATH_CHANCTX_STATE_IDLE;
+
+ spin_unlock_bh(&sc->chan_lock);
+
+ if (sc->sc_ah->chip_fullsleep ||
+ memcmp(&sc->cur_chandef, &sc->cur_chan->chandef,
+ sizeof(sc->cur_chandef))) {
+ ath_dbg(common, CHAN_CTX,
+ "%s: Set channel %d MHz\n",
+ __func__, sc->cur_chan->chandef.center_freq1);
+ ath_set_channel(sc);
+ if (measure_time)
+ sc->sched.channel_switch_time =
+ ath9k_hw_get_tsf_offset(&ts, NULL);
+ }
+ if (send_ps)
+ ath_chanctx_send_ps_frame(sc, false);
+
+ ath_offchannel_channel_change(sc);
+ ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH);
+}
+
+static void ath_chanctx_work(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ chanctx_work);
+ mutex_lock(&sc->mutex);
+ ath_chanctx_set_next(sc, false);
+ mutex_unlock(&sc->mutex);
+}
+
+void ath9k_offchannel_init(struct ath_softc *sc)
+{
+ struct ath_chanctx *ctx;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *chan;
+ int i;
+
+ sband = &common->sbands[IEEE80211_BAND_2GHZ];
+ if (!sband->n_channels)
+ sband = &common->sbands[IEEE80211_BAND_5GHZ];
+
+ chan = &sband->channels[0];
+
+ ctx = &sc->offchannel.chan;
+ INIT_LIST_HEAD(&ctx->vifs);
+ ctx->txpower = ATH_TXPOWER_MAX;
+ cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
+
+ for (i = 0; i < ARRAY_SIZE(ctx->acq); i++)
+ INIT_LIST_HEAD(&ctx->acq[i]);
+
+ sc->offchannel.chan.offchannel = true;
+}
+
+void ath9k_init_channel_context(struct ath_softc *sc)
+{
+ INIT_WORK(&sc->chanctx_work, ath_chanctx_work);
+
+ setup_timer(&sc->offchannel.timer, ath_offchannel_timer,
+ (unsigned long)sc);
+ setup_timer(&sc->sched.timer, ath_chanctx_timer,
+ (unsigned long)sc);
+}
+
+void ath9k_deinit_channel_context(struct ath_softc *sc)
+{
+ cancel_work_sync(&sc->chanctx_work);
+}
+
+bool ath9k_is_chanctx_enabled(void)
+{
+ return (ath9k_use_chanctx == 1);
+}
+
+/********************/
+/* Queue management */
+/********************/
+
+void ath9k_chanctx_wake_queues(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ int i;
+
+ if (sc->cur_chan == &sc->offchannel.chan) {
+ ieee80211_wake_queue(sc->hw,
+ sc->hw->offchannel_tx_hw_queue);
+ } else {
+ for (i = 0; i < IEEE80211_NUM_ACS; i++)
+ ieee80211_wake_queue(sc->hw,
+ sc->cur_chan->hw_queue_base + i);
+ }
+
+ if (ah->opmode == NL80211_IFTYPE_AP)
+ ieee80211_wake_queue(sc->hw, sc->hw->queues - 2);
+}
+
+/*****************/
+/* P2P Powersave */
+/*****************/
+
+static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ s32 tsf, target_tsf;
+
+ if (!avp || !avp->noa.has_next_tsf)
+ return;
+
+ ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer);
+
+ tsf = ath9k_hw_gettsf32(sc->sc_ah);
+
+ target_tsf = avp->noa.next_tsf;
+ if (!avp->noa.absent)
+ target_tsf -= ATH_P2P_PS_STOP_TIME;
+
+ if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
+ target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
+
+ ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
+}
+
+static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
+{
+ struct ath_vif *avp = (void *)vif->drv_priv;
+ u32 tsf;
+
+ if (!sc->p2p_ps_timer)
+ return;
+
+ if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
+ return;
+
+ sc->p2p_ps_vif = avp;
+ tsf = ath9k_hw_gettsf32(sc->sc_ah);
+ ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
+ ath9k_update_p2p_ps_timer(sc, avp);
+}
+
+static u8 ath9k_get_ctwin(struct ath_softc *sc, struct ath_vif *avp)
+{
+ struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
+ u8 switch_time, ctwin;
+
+ /*
+ * Channel switch in multi-channel mode is deferred
+ * by a quarter beacon interval when handling
+ * ATH_CHANCTX_EVENT_BEACON_PREPARE, so the P2P-GO
+ * interface is guaranteed to be discoverable
+ * for that duration after a TBTT.
+ */
+ switch_time = cur_conf->beacon_interval / 4;
+
+ ctwin = avp->vif->bss_conf.p2p_noa_attr.oppps_ctwindow;
+ if (ctwin && (ctwin < switch_time))
+ return ctwin;
+
+ if (switch_time < P2P_DEFAULT_CTWIN)
+ return 0;
+
+ return P2P_DEFAULT_CTWIN;
+}
+
+void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
+ struct sk_buff *skb)
+{
+ static const u8 noa_ie_hdr[] = {
+ WLAN_EID_VENDOR_SPECIFIC, /* type */
+ 0, /* length */
+ 0x50, 0x6f, 0x9a, /* WFA OUI */
+ 0x09, /* P2P subtype */
+ 0x0c, /* Notice of Absence */
+ 0x00, /* LSB of little-endian len */
+ 0x00, /* MSB of little-endian len */
+ };
+
+ struct ieee80211_p2p_noa_attr *noa;
+ int noa_len, noa_desc, i = 0;
+ u8 *hdr;
+
+ if (!avp->offchannel_duration && !avp->noa_duration)
+ return;
+
+ noa_desc = !!avp->offchannel_duration + !!avp->noa_duration;
+ noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc;
+
+ hdr = skb_put(skb, sizeof(noa_ie_hdr));
+ memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr));
+ hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2;
+ hdr[7] = noa_len;
+
+ noa = (void *) skb_put(skb, noa_len);
+ memset(noa, 0, noa_len);
+
+ noa->index = avp->noa_index;
+ noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp);
+
+ if (avp->noa_duration) {
+ if (avp->periodic_noa) {
+ u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
+ noa->desc[i].count = 255;
+ noa->desc[i].interval = cpu_to_le32(interval);
+ } else {
+ noa->desc[i].count = 1;
+ }
+
+ noa->desc[i].start_time = cpu_to_le32(avp->noa_start);
+ noa->desc[i].duration = cpu_to_le32(avp->noa_duration);
+ i++;
+ }
+
+ if (avp->offchannel_duration) {
+ noa->desc[i].count = 1;
+ noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start);
+ noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration);
+ }
+}
+
+void ath9k_p2p_ps_timer(void *priv)
+{
+ struct ath_softc *sc = priv;
+ struct ath_vif *avp = sc->p2p_ps_vif;
+ struct ieee80211_vif *vif;
+ struct ieee80211_sta *sta;
+ struct ath_node *an;
+ u32 tsf;
+
+ del_timer_sync(&sc->sched.timer);
+ ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer);
+ ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
+
+ if (!avp || avp->chanctx != sc->cur_chan)
+ return;
+
+ tsf = ath9k_hw_gettsf32(sc->sc_ah);
+ if (!avp->noa.absent)
+ tsf += ATH_P2P_PS_STOP_TIME;
+
+ if (!avp->noa.has_next_tsf ||
+ avp->noa.next_tsf - tsf > BIT(31))
+ ieee80211_update_p2p_noa(&avp->noa, tsf);
+
+ ath9k_update_p2p_ps_timer(sc, avp);
+
+ rcu_read_lock();
+
+ vif = avp->vif;
+ sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
+ if (!sta)
+ goto out;
+
+ an = (void *) sta->drv_priv;
+ if (an->sleeping == !!avp->noa.absent)
+ goto out;
+
+ an->sleeping = avp->noa.absent;
+ if (an->sleeping)
+ ath_tx_aggr_sleep(sta, sc, an);
+ else
+ ath_tx_aggr_wakeup(sc, an);
+
+out:
+ rcu_read_unlock();
+}
+
+void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
+ struct ieee80211_vif *vif)
+{
+ unsigned long flags;
+
+ spin_lock_bh(&sc->sc_pcu_lock);
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (!(sc->ps_flags & PS_BEACON_SYNC))
+ ath9k_update_p2p_ps(sc, vif);
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+ spin_unlock_bh(&sc->sc_pcu_lock);
+}
+
+void ath9k_p2p_beacon_sync(struct ath_softc *sc)
+{
+ if (sc->p2p_ps_vif)
+ ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
+}
+
+void ath9k_p2p_remove_vif(struct ath_softc *sc,
+ struct ieee80211_vif *vif)
+{
+ struct ath_vif *avp = (void *)vif->drv_priv;
+
+ spin_lock_bh(&sc->sc_pcu_lock);
+ if (avp == sc->p2p_ps_vif) {
+ sc->p2p_ps_vif = NULL;
+ ath9k_update_p2p_ps_timer(sc, NULL);
+ }
+ spin_unlock_bh(&sc->sc_pcu_lock);
+}
+
+int ath9k_init_p2p(struct ath_softc *sc)
+{
+ sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer,
+ NULL, sc, AR_FIRST_NDP_TIMER);
+ if (!sc->p2p_ps_timer)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void ath9k_deinit_p2p(struct ath_softc *sc)
+{
+ if (sc->p2p_ps_timer)
+ ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
+}
+
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c
index 733be517848..6ad44470d0f 100644
--- a/drivers/net/wireless/ath/ath9k/common-beacon.c
+++ b/drivers/net/wireless/ath/ath9k/common-beacon.c
@@ -57,7 +57,7 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah,
struct ath9k_beacon_state *bs)
{
struct ath_common *common = ath9k_hw_common(ah);
- int dtim_intval, sleepduration;
+ int dtim_intval;
u64 tsf;
/* No need to configure beacon if we are not associated */
@@ -75,7 +75,6 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah,
* last beacon we received (which may be none).
*/
dtim_intval = conf->intval * conf->dtim_period;
- sleepduration = ah->hw->conf.listen_interval * conf->intval;
/*
* Pull nexttbtt forward to reflect the current
@@ -113,7 +112,7 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah,
*/
bs->bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
- sleepduration));
+ conf->intval));
if (bs->bs_sleepduration > bs->bs_dtimperiod)
bs->bs_sleepduration = bs->bs_dtimperiod;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index d2279365be6..46f20a309b5 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -838,7 +838,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
iter_data.nmeshes, iter_data.nwds);
len += scnprintf(buf + len, sizeof(buf) - len,
" ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
- iter_data.nadhocs, sc->nvifs, sc->nbcnvifs);
+ iter_data.nadhocs, sc->cur_chan->nvifs, sc->nbcnvifs);
}
if (len > sizeof(buf))
@@ -1169,6 +1169,29 @@ static const struct file_operations fops_btcoex = {
};
#endif
+#ifdef CONFIG_ATH9K_DYNACK
+static ssize_t read_file_ackto(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ struct ath_hw *ah = sc->sc_ah;
+ char buf[32];
+ unsigned int len;
+
+ len = sprintf(buf, "%u %c\n", ah->dynack.ackto,
+ (ah->dynack.enabled) ? 'A' : 'S');
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_ackto = {
+ .read = read_file_ackto,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+#endif
+
/* Ethtool support for get-stats */
#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"
@@ -1374,5 +1397,10 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_btcoex);
#endif
+#ifdef CONFIG_ATH9K_DYNACK
+ debugfs_create_file("ack_to", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+ sc, &fops_ackto);
+#endif
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/dynack.c b/drivers/net/wireless/ath/ath9k/dynack.c
new file mode 100644
index 00000000000..6ae8e0bc9e1
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/dynack.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2014, Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * 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 "ath9k.h"
+#include "hw.h"
+#include "dynack.h"
+
+#define COMPUTE_TO (5 * HZ)
+#define LATEACK_DELAY (10 * HZ)
+#define LATEACK_TO 256
+#define MAX_DELAY 300
+#define EWMA_LEVEL 96
+#define EWMA_DIV 128
+
+/**
+ * ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation
+ *
+ */
+static inline u32 ath_dynack_ewma(u32 old, u32 new)
+{
+ return (new * (EWMA_DIV - EWMA_LEVEL) + old * EWMA_LEVEL) / EWMA_DIV;
+}
+
+/**
+ * ath_dynack_get_sifs - get sifs time based on phy used
+ * @ah: ath hw
+ * @phy: phy used
+ *
+ */
+static inline u32 ath_dynack_get_sifs(struct ath_hw *ah, int phy)
+{
+ u32 sifs = CCK_SIFS_TIME;
+
+ if (phy == WLAN_RC_PHY_OFDM) {
+ if (IS_CHAN_QUARTER_RATE(ah->curchan))
+ sifs = OFDM_SIFS_TIME_QUARTER;
+ else if (IS_CHAN_HALF_RATE(ah->curchan))
+ sifs = OFDM_SIFS_TIME_HALF;
+ else
+ sifs = OFDM_SIFS_TIME;
+ }
+ return sifs;
+}
+
+/**
+ * ath_dynack_bssidmask - filter out ACK frames based on BSSID mask
+ * @ah: ath hw
+ * @mac: receiver address
+ */
+static inline bool ath_dynack_bssidmask(struct ath_hw *ah, const u8 *mac)
+{
+ int i;
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ if ((common->macaddr[i] & common->bssidmask[i]) !=
+ (mac[i] & common->bssidmask[i]))
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * ath_dynack_compute_ackto - compute ACK timeout as the maximum STA timeout
+ * @ah: ath hw
+ *
+ * should be called while holding qlock
+ */
+static void ath_dynack_compute_ackto(struct ath_hw *ah)
+{
+ struct ath_node *an;
+ u32 to = 0;
+ struct ath_dynack *da = &ah->dynack;
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ list_for_each_entry(an, &da->nodes, list)
+ if (an->ackto > to)
+ to = an->ackto;
+
+ if (to && da->ackto != to) {
+ u32 slottime;
+
+ slottime = (to - 3) / 2;
+ da->ackto = to;
+ ath_dbg(common, DYNACK, "ACK timeout %u slottime %u\n",
+ da->ackto, slottime);
+ ath9k_hw_setslottime(ah, slottime);
+ ath9k_hw_set_ack_timeout(ah, da->ackto);
+ ath9k_hw_set_cts_timeout(ah, da->ackto);
+ }
+}
+
+/**
+ * ath_dynack_compute_to - compute STA ACK timeout
+ * @ah: ath hw
+ *
+ * should be called while holding qlock
+ */
+static void ath_dynack_compute_to(struct ath_hw *ah)
+{
+ u32 ackto, ack_ts;
+ u8 *dst, *src;
+ struct ieee80211_sta *sta;
+ struct ath_node *an;
+ struct ts_info *st_ts;
+ struct ath_dynack *da = &ah->dynack;
+
+ rcu_read_lock();
+
+ while (da->st_rbf.h_rb != da->st_rbf.t_rb &&
+ da->ack_rbf.h_rb != da->ack_rbf.t_rb) {
+ ack_ts = da->ack_rbf.tstamp[da->ack_rbf.h_rb];
+ st_ts = &da->st_rbf.ts[da->st_rbf.h_rb];
+ dst = da->st_rbf.addr[da->st_rbf.h_rb].h_dest;
+ src = da->st_rbf.addr[da->st_rbf.h_rb].h_src;
+
+ ath_dbg(ath9k_hw_common(ah), DYNACK,
+ "ack_ts %u st_ts %u st_dur %u [%u-%u]\n",
+ ack_ts, st_ts->tstamp, st_ts->dur,
+ da->ack_rbf.h_rb, da->st_rbf.h_rb);
+
+ if (ack_ts > st_ts->tstamp + st_ts->dur) {
+ ackto = ack_ts - st_ts->tstamp - st_ts->dur;
+
+ if (ackto < MAX_DELAY) {
+ sta = ieee80211_find_sta_by_ifaddr(ah->hw, dst,
+ src);
+ if (sta) {
+ an = (struct ath_node *)sta->drv_priv;
+ an->ackto = ath_dynack_ewma(an->ackto,
+ ackto);
+ ath_dbg(ath9k_hw_common(ah), DYNACK,
+ "%pM to %u\n", dst, an->ackto);
+ if (time_is_before_jiffies(da->lto)) {
+ ath_dynack_compute_ackto(ah);
+ da->lto = jiffies + COMPUTE_TO;
+ }
+ }
+ INCR(da->ack_rbf.h_rb, ATH_DYN_BUF);
+ }
+ INCR(da->st_rbf.h_rb, ATH_DYN_BUF);
+ } else {
+ INCR(da->ack_rbf.h_rb, ATH_DYN_BUF);
+ }
+ }
+
+ rcu_read_unlock();
+}
+
+/**
+ * ath_dynack_sample_tx_ts - status timestamp sampling method
+ * @ah: ath hw
+ * @skb: socket buffer
+ * @ts: tx status info
+ *
+ */
+void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
+ struct ath_tx_status *ts)
+{
+ u8 ridx;
+ struct ieee80211_hdr *hdr;
+ struct ath_dynack *da = &ah->dynack;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !da->enabled)
+ return;
+
+ spin_lock_bh(&da->qlock);
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+
+ /* late ACK */
+ if (ts->ts_status & ATH9K_TXERR_XRETRY) {
+ if (ieee80211_is_assoc_req(hdr->frame_control) ||
+ ieee80211_is_assoc_resp(hdr->frame_control)) {
+ ath_dbg(common, DYNACK, "late ack\n");
+ ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2);
+ ath9k_hw_set_ack_timeout(ah, LATEACK_TO);
+ ath9k_hw_set_cts_timeout(ah, LATEACK_TO);
+ da->lto = jiffies + LATEACK_DELAY;
+ }
+
+ spin_unlock_bh(&da->qlock);
+ return;
+ }
+
+ ridx = ts->ts_rateindex;
+
+ da->st_rbf.ts[da->st_rbf.t_rb].tstamp = ts->ts_tstamp;
+ da->st_rbf.ts[da->st_rbf.t_rb].dur = ts->duration[ts->ts_rateindex];
+ ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_dest, hdr->addr1);
+ ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_src, hdr->addr2);
+
+ if (!(info->status.rates[ridx].flags & IEEE80211_TX_RC_MCS)) {
+ u32 phy, sifs;
+ const struct ieee80211_rate *rate;
+ struct ieee80211_tx_rate *rates = info->status.rates;
+
+ rate = &common->sbands[info->band].bitrates[rates[ridx].idx];
+ if (info->band == IEEE80211_BAND_2GHZ &&
+ !(rate->flags & IEEE80211_RATE_ERP_G))
+ phy = WLAN_RC_PHY_CCK;
+ else
+ phy = WLAN_RC_PHY_OFDM;
+
+ sifs = ath_dynack_get_sifs(ah, phy);
+ da->st_rbf.ts[da->st_rbf.t_rb].dur -= sifs;
+ }
+
+ ath_dbg(common, DYNACK, "{%pM} tx sample %u [dur %u][h %u-t %u]\n",
+ hdr->addr1, da->st_rbf.ts[da->st_rbf.t_rb].tstamp,
+ da->st_rbf.ts[da->st_rbf.t_rb].dur, da->st_rbf.h_rb,
+ (da->st_rbf.t_rb + 1) % ATH_DYN_BUF);
+
+ INCR(da->st_rbf.t_rb, ATH_DYN_BUF);
+ if (da->st_rbf.t_rb == da->st_rbf.h_rb)
+ INCR(da->st_rbf.h_rb, ATH_DYN_BUF);
+
+ ath_dynack_compute_to(ah);
+
+ spin_unlock_bh(&da->qlock);
+}
+EXPORT_SYMBOL(ath_dynack_sample_tx_ts);
+
+/**
+ * ath_dynack_sample_ack_ts - ACK timestamp sampling method
+ * @ah: ath hw
+ * @skb: socket buffer
+ * @ts: rx timestamp
+ *
+ */
+void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb,
+ u32 ts)
+{
+ struct ath_dynack *da = &ah->dynack;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (!ath_dynack_bssidmask(ah, hdr->addr1) || !da->enabled)
+ return;
+
+ spin_lock_bh(&da->qlock);
+ da->ack_rbf.tstamp[da->ack_rbf.t_rb] = ts;
+
+ ath_dbg(common, DYNACK, "rx sample %u [h %u-t %u]\n",
+ da->ack_rbf.tstamp[da->ack_rbf.t_rb],
+ da->ack_rbf.h_rb, (da->ack_rbf.t_rb + 1) % ATH_DYN_BUF);
+
+ INCR(da->ack_rbf.t_rb, ATH_DYN_BUF);
+ if (da->ack_rbf.t_rb == da->ack_rbf.h_rb)
+ INCR(da->ack_rbf.h_rb, ATH_DYN_BUF);
+
+ ath_dynack_compute_to(ah);
+
+ spin_unlock_bh(&da->qlock);
+}
+EXPORT_SYMBOL(ath_dynack_sample_ack_ts);
+
+/**
+ * ath_dynack_node_init - init ath_node related info
+ * @ah: ath hw
+ * @an: ath node
+ *
+ */
+void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an)
+{
+ /* ackto = slottime + sifs + air delay */
+ u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
+ struct ath_dynack *da = &ah->dynack;
+
+ an->ackto = ackto;
+
+ spin_lock(&da->qlock);
+ list_add_tail(&an->list, &da->nodes);
+ spin_unlock(&da->qlock);
+}
+EXPORT_SYMBOL(ath_dynack_node_init);
+
+/**
+ * ath_dynack_node_deinit - deinit ath_node related info
+ * @ah: ath hw
+ * @an: ath node
+ *
+ */
+void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an)
+{
+ struct ath_dynack *da = &ah->dynack;
+
+ spin_lock(&da->qlock);
+ list_del(&an->list);
+ spin_unlock(&da->qlock);
+}
+EXPORT_SYMBOL(ath_dynack_node_deinit);
+
+/**
+ * ath_dynack_reset - reset dynack processing
+ * @ah: ath hw
+ *
+ */
+void ath_dynack_reset(struct ath_hw *ah)
+{
+ /* ackto = slottime + sifs + air delay */
+ u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
+ struct ath_dynack *da = &ah->dynack;
+
+ da->lto = jiffies;
+ da->ackto = ackto;
+
+ da->st_rbf.t_rb = 0;
+ da->st_rbf.h_rb = 0;
+ da->ack_rbf.t_rb = 0;
+ da->ack_rbf.h_rb = 0;
+
+ /* init acktimeout */
+ ath9k_hw_setslottime(ah, (ackto - 3) / 2);
+ ath9k_hw_set_ack_timeout(ah, ackto);
+ ath9k_hw_set_cts_timeout(ah, ackto);
+}
+EXPORT_SYMBOL(ath_dynack_reset);
+
+/**
+ * ath_dynack_init - init dynack data structure
+ * @ah: ath hw
+ *
+ */
+void ath_dynack_init(struct ath_hw *ah)
+{
+ struct ath_dynack *da = &ah->dynack;
+
+ memset(da, 0, sizeof(struct ath_dynack));
+
+ spin_lock_init(&da->qlock);
+ INIT_LIST_HEAD(&da->nodes);
+
+ ah->hw->wiphy->features |= NL80211_FEATURE_ACKTO_ESTIMATION;
+}
diff --git a/drivers/net/wireless/ath/ath9k/dynack.h b/drivers/net/wireless/ath/ath9k/dynack.h
new file mode 100644
index 00000000000..6d7bef97674
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/dynack.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014, Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * 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 DYNACK_H
+#define DYNACK_H
+
+#define ATH_DYN_BUF 64
+
+struct ath_hw;
+struct ath_node;
+
+/**
+ * struct ath_dyn_rxbuf - ACK frame ring buffer
+ * @h_rb: ring buffer head
+ * @t_rb: ring buffer tail
+ * @tstamp: ACK RX timestamp buffer
+ */
+struct ath_dyn_rxbuf {
+ u16 h_rb, t_rb;
+ u32 tstamp[ATH_DYN_BUF];
+};
+
+struct ts_info {
+ u32 tstamp;
+ u32 dur;
+};
+
+struct haddr_pair {
+ u8 h_dest[ETH_ALEN];
+ u8 h_src[ETH_ALEN];
+};
+
+/**
+ * struct ath_dyn_txbuf - tx frame ring buffer
+ * @h_rb: ring buffer head
+ * @t_rb: ring buffer tail
+ * @addr: dest/src address pair for a given TX frame
+ * @ts: TX frame timestamp buffer
+ */
+struct ath_dyn_txbuf {
+ u16 h_rb, t_rb;
+ struct haddr_pair addr[ATH_DYN_BUF];
+ struct ts_info ts[ATH_DYN_BUF];
+};
+
+/**
+ * struct ath_dynack - dynack processing info
+ * @enabled: enable dyn ack processing
+ * @ackto: current ACK timeout
+ * @lto: last ACK timeout computation
+ * @nodes: ath_node linked list
+ * @qlock: ts queue spinlock
+ * @ack_rbf: ACK ts ring buffer
+ * @st_rbf: status ts ring buffer
+ */
+struct ath_dynack {
+ bool enabled;
+ int ackto;
+ unsigned long lto;
+
+ struct list_head nodes;
+
+ /* protect timestamp queue access */
+ spinlock_t qlock;
+ struct ath_dyn_rxbuf ack_rbf;
+ struct ath_dyn_txbuf st_rbf;
+};
+
+#if defined(CONFIG_ATH9K_DYNACK)
+void ath_dynack_reset(struct ath_hw *ah);
+void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an);
+void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an);
+void ath_dynack_init(struct ath_hw *ah);
+void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, u32 ts);
+void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
+ struct ath_tx_status *ts);
+#else
+static inline void ath_dynack_init(struct ath_hw *ah) {}
+static inline void ath_dynack_node_init(struct ath_hw *ah,
+ struct ath_node *an) {}
+static inline void ath_dynack_node_deinit(struct ath_hw *ah,
+ struct ath_node *an) {}
+static inline void ath_dynack_sample_ack_ts(struct ath_hw *ah,
+ struct sk_buff *skb, u32 ts) {}
+static inline void ath_dynack_sample_tx_ts(struct ath_hw *ah,
+ struct sk_buff *skb,
+ struct ath_tx_status *ts) {}
+#endif
+
+#endif /* DYNACK_H */
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 8a3bd5fe3a5..d779f4fa50e 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -592,6 +592,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+
hw->queues = 4;
hw->max_listen_interval = 1;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 5627917c5ff..994fff1ff51 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1722,7 +1722,7 @@ static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
}
static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
- u8 coverage_class)
+ s16 coverage_class)
{
struct ath9k_htc_priv *priv = hw->priv;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index bb86eb2ffc9..f0484b1b617 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -978,7 +978,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
struct ath_hw *ah = common->ah;
struct ath_htc_rx_status *rxstatus;
struct ath_rx_status rx_stats;
- bool decrypt_error;
+ bool decrypt_error = false;
if (skb->len < HTC_RX_FRAME_HEADER_SIZE) {
ath_err(common, "Corrupted RX frame, dropping (len: %d)\n",
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 69bbea1184d..3aed729e4d5 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -647,6 +647,8 @@ int ath9k_hw_init(struct ath_hw *ah)
return ret;
}
+ ath_dynack_init(ah);
+
return 0;
}
EXPORT_SYMBOL(ath9k_hw_init);
@@ -935,21 +937,21 @@ static void ath9k_hw_set_sifs_time(struct ath_hw *ah, u32 us)
REG_WRITE(ah, AR_D_GBL_IFS_SIFS, val);
}
-static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
+void ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
{
u32 val = ath9k_hw_mac_to_clks(ah, us);
val = min(val, (u32) 0xFFFF);
REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val);
}
-static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
+void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
{
u32 val = ath9k_hw_mac_to_clks(ah, us);
val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK));
REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val);
}
-static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
+void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
{
u32 val = ath9k_hw_mac_to_clks(ah, us);
val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS));
@@ -1053,6 +1055,14 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
ctstimeout += 48 - sifstime - ah->slottime;
}
+ if (ah->dynack.enabled) {
+ acktimeout = ah->dynack.ackto;
+ ctstimeout = acktimeout;
+ slottime = (acktimeout - 3) / 2;
+ } else {
+ ah->dynack.ackto = acktimeout;
+ }
+
ath9k_hw_set_sifs_time(ah, sifstime);
ath9k_hw_setslottime(ah, slottime);
ath9k_hw_set_ack_timeout(ah, acktimeout);
@@ -1954,6 +1964,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (AR_SREV_9565(ah) && common->bt_ant_diversity)
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
+ if (ah->hw->conf.radar_enabled) {
+ /* set HW specific DFS configuration */
+ ah->radar_conf.ext_channel = IS_CHAN_HT40(chan);
+ ath9k_hw_set_radar_params(ah);
+ }
+
return 0;
}
EXPORT_SYMBOL(ath9k_hw_reset);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 51b4ebe04c0..b9eef3362fb 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -29,6 +29,7 @@
#include "reg.h"
#include "phy.h"
#include "btcoex.h"
+#include "dynack.h"
#include "../regd.h"
@@ -924,6 +925,8 @@ struct ath_hw {
int (*external_reset)(void);
const struct firmware *eeprom_blob;
+
+ struct ath_dynack dynack;
};
struct ath_bus_ops {
@@ -1080,6 +1083,10 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);
void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning);
void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan);
+void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us);
+void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us);
+void ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
+
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
{
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 39419ea845c..156a944134d 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -61,10 +61,14 @@ static int ath9k_ps_enable;
module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
int ath9k_use_chanctx;
module_param_named(use_chanctx, ath9k_use_chanctx, int, 0444);
MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency");
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
+
bool is_ath9k_unloaded;
#ifdef CONFIG_MAC80211_LEDS
@@ -511,7 +515,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
sc->tx99_power = MAX_RATE_POWER + 1;
init_waitqueue_head(&sc->tx_wait);
sc->cur_chan = &sc->chanctx[0];
- if (!ath9k_use_chanctx)
+ if (!ath9k_is_chanctx_enabled())
sc->cur_chan->hw_queue_base = 0;
if (!pdata || pdata->use_eeprom) {
@@ -567,11 +571,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc);
INIT_WORK(&sc->hw_reset_work, ath_reset_work);
INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
- INIT_WORK(&sc->chanctx_work, ath_chanctx_work);
INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
- setup_timer(&sc->offchannel.timer, ath_offchannel_timer,
- (unsigned long)sc);
- setup_timer(&sc->sched.timer, ath_chanctx_timer, (unsigned long)sc);
+
+ ath9k_init_channel_context(sc);
/*
* Cache line size is used to size and align various
@@ -600,13 +602,15 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
if (ret)
goto err_btcoex;
- sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer,
- NULL, sc, AR_FIRST_NDP_TIMER);
+ ret = ath9k_init_p2p(sc);
+ if (ret)
+ goto err_btcoex;
ath9k_cmn_init_crypto(sc->sc_ah);
ath9k_init_misc(sc);
ath_fill_led_pin(sc);
ath_chanctx_init(sc);
+ ath9k_offchannel_init(sc);
if (common->bus_ops->aspm_init)
common->bus_ops->aspm_init(common);
@@ -672,18 +676,14 @@ static const struct ieee80211_iface_limit wds_limits[] = {
{ .max = 2048, .types = BIT(NL80211_IFTYPE_WDS) },
};
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
static const struct ieee80211_iface_limit if_limits_multi[] = {
- { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) },
- { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) },
-};
-
-static const struct ieee80211_iface_limit if_dfs_limits[] = {
- { .max = 1, .types = BIT(NL80211_IFTYPE_AP) |
-#ifdef CONFIG_MAC80211_MESH
- BIT(NL80211_IFTYPE_MESH_POINT) |
-#endif
- BIT(NL80211_IFTYPE_ADHOC) },
+ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
};
static const struct ieee80211_iface_combination if_comb_multi[] = {
@@ -696,6 +696,16 @@ static const struct ieee80211_iface_combination if_comb_multi[] = {
},
};
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
+
+static const struct ieee80211_iface_limit if_dfs_limits[] = {
+ { .max = 1, .types = BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
+ BIT(NL80211_IFTYPE_ADHOC) },
+};
+
static const struct ieee80211_iface_combination if_comb[] = {
{
.limits = if_limits,
@@ -753,8 +763,9 @@ 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;
- hw->wiphy->features |= (NL80211_FEATURE_ACTIVE_MONITOR |
- NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE);
+ hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
+ NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
+ NL80211_FEATURE_P2P_GO_CTWIN;
if (!config_enabled(CONFIG_ATH9K_TX99)) {
hw->wiphy->interface_modes =
@@ -763,24 +774,31 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_MESH_POINT);
- if (!ath9k_use_chanctx) {
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+ BIT(NL80211_IFTYPE_WDS);
+
hw->wiphy->iface_combinations = if_comb;
hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
- hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS);
- } else {
- hw->wiphy->iface_combinations = if_comb_multi;
- hw->wiphy->n_iface_combinations =
- ARRAY_SIZE(if_comb_multi);
- hw->wiphy->max_scan_ssids = 255;
- hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
- hw->wiphy->max_remain_on_channel_duration = 10000;
- hw->chanctx_data_size = sizeof(void *);
- hw->extra_beacon_tailroom =
- sizeof(struct ieee80211_p2p_noa_attr) + 9;
- }
}
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
+ if (ath9k_is_chanctx_enabled()) {
+ hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS);
+ hw->wiphy->iface_combinations = if_comb_multi;
+ hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi);
+ hw->wiphy->max_scan_ssids = 255;
+ hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+ hw->wiphy->max_remain_on_channel_duration = 10000;
+ hw->chanctx_data_size = sizeof(void *);
+ hw->extra_beacon_tailroom =
+ sizeof(struct ieee80211_p2p_noa_attr) + 9;
+
+ ath_dbg(common, CHAN_CTX, "Use channel contexts\n");
+ }
+
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
+
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
@@ -793,7 +811,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
/* allow 4 queues per channel context +
* 1 cab queue + 1 offchannel tx queue
*/
- hw->queues = 10;
+ hw->queues = ATH9K_NUM_TX_QUEUES;
/* last queue for offchannel */
hw->offchannel_tx_hw_queue = hw->queues - 1;
hw->max_rates = 4;
@@ -915,9 +933,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
{
int i = 0;
- if (sc->p2p_ps_timer)
- ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
-
+ ath9k_deinit_p2p(sc);
ath9k_deinit_btcoex(sc);
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 6c56cafa5ca..cd05a779107 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -121,6 +121,7 @@ struct ath_tx_status {
u32 evm0;
u32 evm1;
u32 evm2;
+ u32 duration[4];
};
struct ath_rx_status {
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index e6ac8d2e610..fbf23ac61c9 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -223,18 +223,12 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
unsigned long flags;
- int i;
-
- if (ath_startrecv(sc) != 0) {
- ath_err(common, "Unable to restart recv logic\n");
- return false;
- }
+ ath9k_calculate_summary_state(sc, sc->cur_chan);
+ ath_startrecv(sc);
ath9k_cmn_update_txpow(ah, sc->curtxpow,
sc->cur_chan->txpower, &sc->curtxpow);
-
clear_bit(ATH_OP_HW_RESET, &common->op_flags);
- ath9k_calculate_summary_state(sc, sc->cur_chan);
if (!sc->cur_chan->offchannel && start) {
/* restore per chanctx TSF timer */
@@ -268,20 +262,10 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
- if (!ath9k_use_chanctx)
+ if (!ath9k_is_chanctx_enabled())
ieee80211_wake_queues(sc->hw);
- else {
- if (sc->cur_chan == &sc->offchannel.chan)
- ieee80211_wake_queue(sc->hw,
- sc->hw->offchannel_tx_hw_queue);
- else {
- for (i = 0; i < IEEE80211_NUM_ACS; i++)
- ieee80211_wake_queue(sc->hw,
- sc->cur_chan->hw_queue_base + i);
- }
- if (ah->opmode == NL80211_IFTYPE_AP)
- ieee80211_wake_queue(sc->hw, sc->hw->queues - 2);
- }
+ else
+ ath9k_chanctx_wake_queues(sc);
ath9k_p2p_ps_timer(sc);
@@ -314,6 +298,9 @@ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
if (!ath_prepare_reset(sc))
fastcc = false;
+ if (ath9k_is_chanctx_enabled())
+ fastcc = false;
+
spin_lock_bh(&sc->chan_lock);
sc->cur_chandef = sc->cur_chan->chandef;
spin_unlock_bh(&sc->chan_lock);
@@ -358,12 +345,16 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
memset(&an->key_idx, 0, sizeof(an->key_idx));
ath_tx_node_init(sc, an);
+
+ ath_dynack_node_init(sc->sc_ah, an);
}
static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
{
struct ath_node *an = (struct ath_node *)sta->drv_priv;
ath_tx_node_cleanup(sc, an);
+
+ ath_dynack_node_deinit(sc->sc_ah, an);
}
void ath9k_tasklet(unsigned long data)
@@ -513,7 +504,7 @@ irqreturn_t ath_isr(int irq, void *dev)
* touch anything. Note this can happen early
* on if the IRQ is shared.
*/
- if (test_bit(ATH_OP_INVALID, &common->op_flags))
+ if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags))
return IRQ_NONE;
/* shared irq, not for us */
@@ -822,7 +813,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
struct ath_common *common = ath9k_hw_common(ah);
bool prev_idle;
- cancel_work_sync(&sc->chanctx_work);
+ ath9k_deinit_channel_context(sc);
+
mutex_lock(&sc->mutex);
ath_cancel_work(sc);
@@ -903,9 +895,9 @@ static bool ath9k_uses_beacons(int type)
}
}
-static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
+ u8 *mac, struct ieee80211_vif *vif)
{
- struct ath9k_vif_iter_data *iter_data = data;
int i;
if (iter_data->has_hw_macaddr) {
@@ -923,8 +915,6 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
switch (vif->type) {
case NL80211_IFTYPE_AP:
iter_data->naps++;
- if (vif->bss_conf.enable_beacon)
- iter_data->beacons = true;
break;
case NL80211_IFTYPE_STATION:
iter_data->nstations++;
@@ -967,19 +957,6 @@ void ath9k_calculate_iter_data(struct ath_softc *sc,
list_for_each_entry(avp, &ctx->vifs, list)
ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif);
-
- if (ctx == &sc->offchannel.chan) {
- struct ieee80211_vif *vif;
-
- if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START)
- vif = sc->offchannel.scan_vif;
- else
- vif = sc->offchannel.roc_vif;
-
- if (vif)
- ath9k_vif_iter(iter_data, vif->addr, vif);
- iter_data->beacons = false;
- }
}
static void ath9k_set_assoc_state(struct ath_softc *sc,
@@ -990,13 +967,6 @@ static void ath9k_set_assoc_state(struct ath_softc *sc,
unsigned long flags;
set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
- /* Set the AID, BSSID and do beacon-sync only when
- * the HW opmode is STATION.
- *
- * But the primary bit is set above in any case.
- */
- if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
- return;
ether_addr_copy(common->curbssid, bss_conf->bssid);
common->curaid = bss_conf->aid;
@@ -1019,6 +989,43 @@ static void ath9k_set_assoc_state(struct ath_softc *sc,
vif->addr, common->curbssid);
}
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+static void ath9k_set_offchannel_state(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_vif *vif = NULL;
+
+ ath9k_ps_wakeup(sc);
+
+ if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START)
+ vif = sc->offchannel.scan_vif;
+ else
+ vif = sc->offchannel.roc_vif;
+
+ if (WARN_ON(!vif))
+ goto exit;
+
+ eth_zero_addr(common->curbssid);
+ eth_broadcast_addr(common->bssidmask);
+ ether_addr_copy(common->macaddr, vif->addr);
+ common->curaid = 0;
+ ah->opmode = vif->type;
+ ah->imask &= ~ATH9K_INT_SWBA;
+ ah->imask &= ~ATH9K_INT_TSFOOR;
+ ah->slottime = ATH9K_SLOT_TIME_9;
+
+ ath_hw_setbssidmask(common);
+ ath9k_hw_setopmode(ah);
+ ath9k_hw_write_associd(sc->sc_ah);
+ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_init_global_settings(ah);
+
+exit:
+ ath9k_ps_restore(sc);
+}
+#endif
+
/* Called with sc->mutex held. */
void ath9k_calculate_summary_state(struct ath_softc *sc,
struct ath_chanctx *ctx)
@@ -1026,12 +1033,18 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_vif_iter_data iter_data;
+ struct ath_beacon_config *cur_conf;
ath_chanctx_check_active(sc, ctx);
if (ctx != sc->cur_chan)
return;
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+ if (ctx == &sc->offchannel.chan)
+ return ath9k_set_offchannel_state(sc);
+#endif
+
ath9k_ps_wakeup(sc);
ath9k_calculate_iter_data(sc, ctx, &iter_data);
@@ -1042,8 +1055,11 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
ath_hw_setbssidmask(common);
if (iter_data.naps > 0) {
+ cur_conf = &ctx->beacon;
ath9k_hw_set_tsfadjust(ah, true);
ah->opmode = NL80211_IFTYPE_AP;
+ if (cur_conf->enable_beacon)
+ iter_data.beacons = true;
} else {
ath9k_hw_set_tsfadjust(ah, false);
@@ -1072,13 +1088,11 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
if (ah->opmode == NL80211_IFTYPE_STATION) {
bool changed = (iter_data.primary_sta != ctx->primary_sta);
- iter_data.beacons = true;
if (iter_data.primary_sta) {
+ iter_data.beacons = true;
ath9k_set_assoc_state(sc, iter_data.primary_sta,
changed);
- if (!ctx->primary_sta ||
- !ctx->primary_sta->bss_conf.assoc)
- ctx->primary_sta = iter_data.primary_sta;
+ ctx->primary_sta = iter_data.primary_sta;
} else {
ctx->primary_sta = NULL;
memset(common->curbssid, 0, ETH_ALEN);
@@ -1107,11 +1121,23 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
else
clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
- ctx->primary_sta = iter_data.primary_sta;
-
ath9k_ps_restore(sc);
}
+static void ath9k_assign_hw_queues(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ int i;
+
+ for (i = 0; i < IEEE80211_NUM_ACS; i++)
+ vif->hw_queue[i] = i;
+
+ if (vif->type == NL80211_IFTYPE_AP)
+ vif->cab_queue = hw->queues - 2;
+ else
+ vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+}
+
static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -1120,12 +1146,11 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_node *an = &avp->mcast_node;
- int i;
mutex_lock(&sc->mutex);
if (config_enabled(CONFIG_ATH9K_TX99)) {
- if (sc->nvifs >= 1) {
+ if (sc->cur_chan->nvifs >= 1) {
mutex_unlock(&sc->mutex);
return -EOPNOTSUPP;
}
@@ -1133,22 +1158,18 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
}
ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
- sc->nvifs++;
+ sc->cur_chan->nvifs++;
if (ath9k_uses_beacons(vif->type))
ath9k_beacon_assign_slot(sc, vif);
avp->vif = vif;
- if (!ath9k_use_chanctx) {
+ if (!ath9k_is_chanctx_enabled()) {
avp->chanctx = sc->cur_chan;
list_add_tail(&avp->list, &avp->chanctx->vifs);
}
- for (i = 0; i < IEEE80211_NUM_ACS; i++)
- vif->hw_queue[i] = i;
- if (vif->type == NL80211_IFTYPE_AP)
- vif->cab_queue = hw->queues - 2;
- else
- vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+
+ ath9k_assign_hw_queues(hw, vif);
an->sc = sc;
an->sta = NULL;
@@ -1168,7 +1189,6 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
- int i;
mutex_lock(&sc->mutex);
@@ -1188,43 +1208,13 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
if (ath9k_uses_beacons(vif->type))
ath9k_beacon_assign_slot(sc, vif);
- for (i = 0; i < IEEE80211_NUM_ACS; i++)
- vif->hw_queue[i] = i;
-
- if (vif->type == NL80211_IFTYPE_AP)
- vif->cab_queue = hw->queues - 2;
- else
- vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
-
+ ath9k_assign_hw_queues(hw, vif);
ath9k_calculate_summary_state(sc, avp->chanctx);
mutex_unlock(&sc->mutex);
return 0;
}
-static void
-ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
-{
- struct ath_hw *ah = sc->sc_ah;
- s32 tsf, target_tsf;
-
- if (!avp || !avp->noa.has_next_tsf)
- return;
-
- ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer);
-
- tsf = ath9k_hw_gettsf32(sc->sc_ah);
-
- target_tsf = avp->noa.next_tsf;
- if (!avp->noa.absent)
- target_tsf -= ATH_P2P_PS_STOP_TIME;
-
- if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
- target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
-
- ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
-}
-
static void ath9k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -1236,16 +1226,11 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex);
- spin_lock_bh(&sc->sc_pcu_lock);
- if (avp == sc->p2p_ps_vif) {
- sc->p2p_ps_vif = NULL;
- ath9k_update_p2p_ps_timer(sc, NULL);
- }
- spin_unlock_bh(&sc->sc_pcu_lock);
+ ath9k_p2p_remove_vif(sc, vif);
- sc->nvifs--;
+ sc->cur_chan->nvifs--;
sc->tx99_vif = NULL;
- if (!ath9k_use_chanctx)
+ if (!ath9k_is_chanctx_enabled())
list_del(&avp->list);
if (ath9k_uses_beacons(vif->type))
@@ -1423,7 +1408,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
}
- if (!ath9k_use_chanctx && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
+ if (!ath9k_is_chanctx_enabled() && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
ctx->offchannel = !!(conf->flags & IEEE80211_CONF_OFFCHANNEL);
ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef);
}
@@ -1463,7 +1448,10 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
changed_flags &= SUPPORTED_FILTERS;
*total_flags &= SUPPORTED_FILTERS;
- sc->rx.rxfilter = *total_flags;
+ spin_lock_bh(&sc->chan_lock);
+ sc->cur_chan->rxfilter = *total_flags;
+ spin_unlock_bh(&sc->chan_lock);
+
ath9k_ps_wakeup(sc);
rfilt = ath_calcrxfilter(sc);
ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
@@ -1687,70 +1675,6 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
return ret;
}
-void ath9k_p2p_ps_timer(void *priv)
-{
- struct ath_softc *sc = priv;
- struct ath_vif *avp = sc->p2p_ps_vif;
- struct ieee80211_vif *vif;
- struct ieee80211_sta *sta;
- struct ath_node *an;
- u32 tsf;
-
- del_timer_sync(&sc->sched.timer);
- ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer);
- ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
-
- if (!avp || avp->chanctx != sc->cur_chan)
- return;
-
- tsf = ath9k_hw_gettsf32(sc->sc_ah);
- if (!avp->noa.absent)
- tsf += ATH_P2P_PS_STOP_TIME;
-
- if (!avp->noa.has_next_tsf ||
- avp->noa.next_tsf - tsf > BIT(31))
- ieee80211_update_p2p_noa(&avp->noa, tsf);
-
- ath9k_update_p2p_ps_timer(sc, avp);
-
- rcu_read_lock();
-
- vif = avp->vif;
- sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
- if (!sta)
- goto out;
-
- an = (void *) sta->drv_priv;
- if (an->sleeping == !!avp->noa.absent)
- goto out;
-
- an->sleeping = avp->noa.absent;
- if (an->sleeping)
- ath_tx_aggr_sleep(sta, sc, an);
- else
- ath_tx_aggr_wakeup(sc, an);
-
-out:
- rcu_read_unlock();
-}
-
-void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
-{
- struct ath_vif *avp = (void *)vif->drv_priv;
- u32 tsf;
-
- if (!sc->p2p_ps_timer)
- return;
-
- if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
- return;
-
- sc->p2p_ps_vif = avp;
- tsf = ath9k_hw_gettsf32(sc->sc_ah);
- ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
- ath9k_update_p2p_ps_timer(sc, avp);
-}
-
static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -1765,7 +1689,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = (void *)vif->drv_priv;
- unsigned long flags;
int slottime;
ath9k_ps_wakeup(sc);
@@ -1776,8 +1699,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
bss_conf->bssid, bss_conf->assoc);
ath9k_calculate_summary_state(sc, avp->chanctx);
- if (bss_conf->assoc)
- ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_ASSOC);
+
+ if (ath9k_is_chanctx_enabled()) {
+ if (bss_conf->assoc)
+ ath_chanctx_event(sc, vif,
+ ATH_CHANCTX_EVENT_ASSOC);
+ }
}
if (changed & BSS_CHANGED_IBSS) {
@@ -1789,9 +1716,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
(changed & BSS_CHANGED_BEACON_INT) ||
(changed & BSS_CHANGED_BEACON_INFO)) {
+ ath9k_beacon_config(sc, vif, changed);
if (changed & BSS_CHANGED_BEACON_ENABLED)
ath9k_calculate_summary_state(sc, avp->chanctx);
- ath9k_beacon_config(sc, vif, changed);
}
if ((avp->chanctx == sc->cur_chan) &&
@@ -1814,14 +1741,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
}
- if (changed & BSS_CHANGED_P2P_PS) {
- spin_lock_bh(&sc->sc_pcu_lock);
- spin_lock_irqsave(&sc->sc_pm_lock, flags);
- if (!(sc->ps_flags & PS_BEACON_SYNC))
- ath9k_update_p2p_ps(sc, vif);
- spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
- spin_unlock_bh(&sc->sc_pcu_lock);
- }
+ if (changed & BSS_CHANGED_P2P_PS)
+ ath9k_p2p_bss_info_changed(sc, vif);
if (changed & CHECK_ANI)
ath_check_ani(sc);
@@ -1959,7 +1880,22 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
return 0;
}
-static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
+static void ath9k_enable_dynack(struct ath_softc *sc)
+{
+#ifdef CONFIG_ATH9K_DYNACK
+ u32 rfilt;
+ struct ath_hw *ah = sc->sc_ah;
+
+ ath_dynack_reset(ah);
+
+ ah->dynack.enabled = true;
+ rfilt = ath_calcrxfilter(sc);
+ ath9k_hw_setrxfilter(ah, rfilt);
+#endif
+}
+
+static void ath9k_set_coverage_class(struct ieee80211_hw *hw,
+ s16 coverage_class)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
@@ -1968,11 +1904,22 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
return;
mutex_lock(&sc->mutex);
- ah->coverage_class = coverage_class;
- ath9k_ps_wakeup(sc);
- ath9k_hw_init_global_settings(ah);
- ath9k_ps_restore(sc);
+ if (coverage_class >= 0) {
+ ah->coverage_class = coverage_class;
+ if (ah->dynack.enabled) {
+ u32 rfilt;
+
+ ah->dynack.enabled = false;
+ rfilt = ath_calcrxfilter(sc);
+ ath9k_hw_setrxfilter(ah, rfilt);
+ }
+ ath9k_ps_wakeup(sc);
+ ath9k_hw_init_global_settings(ah);
+ ath9k_ps_restore(sc);
+ } else if (!ah->dynack.enabled) {
+ ath9k_enable_dynack(sc);
+ }
mutex_unlock(&sc->mutex);
}
@@ -2207,207 +2154,7 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
clear_bit(ATH_OP_SCANNING, &common->op_flags);
}
-static int ath_scan_channel_duration(struct ath_softc *sc,
- struct ieee80211_channel *chan)
-{
- struct cfg80211_scan_request *req = sc->offchannel.scan_req;
-
- if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR))
- return (HZ / 9); /* ~110 ms */
-
- return (HZ / 16); /* ~60 ms */
-}
-
-static void
-ath_scan_next_channel(struct ath_softc *sc)
-{
- struct cfg80211_scan_request *req = sc->offchannel.scan_req;
- struct ieee80211_channel *chan;
-
- if (sc->offchannel.scan_idx >= req->n_channels) {
- sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
- ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
- NULL);
- return;
- }
-
- chan = req->channels[sc->offchannel.scan_idx++];
- sc->offchannel.duration = ath_scan_channel_duration(sc, chan);
- sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND;
- ath_chanctx_offchan_switch(sc, chan);
-}
-
-static void ath_offchannel_next(struct ath_softc *sc)
-{
- struct ieee80211_vif *vif;
-
- if (sc->offchannel.scan_req) {
- vif = sc->offchannel.scan_vif;
- sc->offchannel.chan.txpower = vif->bss_conf.txpower;
- ath_scan_next_channel(sc);
- } else if (sc->offchannel.roc_vif) {
- vif = sc->offchannel.roc_vif;
- sc->offchannel.chan.txpower = vif->bss_conf.txpower;
- sc->offchannel.duration = sc->offchannel.roc_duration;
- sc->offchannel.state = ATH_OFFCHANNEL_ROC_START;
- ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan);
- } else {
- ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
- NULL);
- sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
- if (sc->ps_idle)
- ath_cancel_work(sc);
- }
-}
-
-static void ath_roc_complete(struct ath_softc *sc, bool abort)
-{
- sc->offchannel.roc_vif = NULL;
- sc->offchannel.roc_chan = NULL;
- if (!abort)
- ieee80211_remain_on_channel_expired(sc->hw);
- ath_offchannel_next(sc);
- ath9k_ps_restore(sc);
-}
-
-static void ath_scan_complete(struct ath_softc *sc, bool abort)
-{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
- sc->offchannel.scan_req = NULL;
- sc->offchannel.scan_vif = NULL;
- sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
- ieee80211_scan_completed(sc->hw, abort);
- clear_bit(ATH_OP_SCANNING, &common->op_flags);
- ath_offchannel_next(sc);
- ath9k_ps_restore(sc);
-}
-
-static void ath_scan_send_probe(struct ath_softc *sc,
- struct cfg80211_ssid *ssid)
-{
- struct cfg80211_scan_request *req = sc->offchannel.scan_req;
- struct ieee80211_vif *vif = sc->offchannel.scan_vif;
- struct ath_tx_control txctl = {};
- struct sk_buff *skb;
- struct ieee80211_tx_info *info;
- int band = sc->offchannel.chan.chandef.chan->band;
-
- skb = ieee80211_probereq_get(sc->hw, vif,
- ssid->ssid, ssid->ssid_len, req->ie_len);
- if (!skb)
- return;
-
- info = IEEE80211_SKB_CB(skb);
- if (req->no_cck)
- info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
-
- if (req->ie_len)
- memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len);
-
- skb_set_queue_mapping(skb, IEEE80211_AC_VO);
-
- if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
- goto error;
-
- txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
- txctl.force_channel = true;
- if (ath_tx_start(sc->hw, skb, &txctl))
- goto error;
-
- return;
-
-error:
- ieee80211_free_txskb(sc->hw, skb);
-}
-
-static void ath_scan_channel_start(struct ath_softc *sc)
-{
- struct cfg80211_scan_request *req = sc->offchannel.scan_req;
- int i;
-
- if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) &&
- req->n_ssids) {
- for (i = 0; i < req->n_ssids; i++)
- ath_scan_send_probe(sc, &req->ssids[i]);
-
- }
-
- sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT;
- mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration);
-}
-
-void ath_offchannel_channel_change(struct ath_softc *sc)
-{
- switch (sc->offchannel.state) {
- case ATH_OFFCHANNEL_PROBE_SEND:
- if (!sc->offchannel.scan_req)
- return;
-
- if (sc->cur_chan->chandef.chan !=
- sc->offchannel.chan.chandef.chan)
- return;
-
- ath_scan_channel_start(sc);
- break;
- case ATH_OFFCHANNEL_IDLE:
- if (!sc->offchannel.scan_req)
- return;
-
- ath_scan_complete(sc, false);
- break;
- case ATH_OFFCHANNEL_ROC_START:
- if (sc->cur_chan != &sc->offchannel.chan)
- break;
-
- sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT;
- mod_timer(&sc->offchannel.timer, jiffies +
- msecs_to_jiffies(sc->offchannel.duration));
- ieee80211_ready_on_channel(sc->hw);
- break;
- case ATH_OFFCHANNEL_ROC_DONE:
- ath_roc_complete(sc, false);
- break;
- default:
- break;
- }
-}
-
-void ath_offchannel_timer(unsigned long data)
-{
- struct ath_softc *sc = (struct ath_softc *)data;
- struct ath_chanctx *ctx;
-
- switch (sc->offchannel.state) {
- case ATH_OFFCHANNEL_PROBE_WAIT:
- if (!sc->offchannel.scan_req)
- return;
-
- /* get first active channel context */
- ctx = ath_chanctx_get_oper_chan(sc, true);
- if (ctx->active) {
- sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND;
- ath_chanctx_switch(sc, ctx, NULL);
- mod_timer(&sc->offchannel.timer, jiffies + HZ / 10);
- break;
- }
- /* fall through */
- case ATH_OFFCHANNEL_SUSPEND:
- if (!sc->offchannel.scan_req)
- return;
-
- ath_scan_next_channel(sc);
- break;
- case ATH_OFFCHANNEL_ROC_START:
- case ATH_OFFCHANNEL_ROC_WAIT:
- ctx = ath_chanctx_get_oper_chan(sc, false);
- sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE;
- ath_chanctx_switch(sc, ctx, NULL);
- break;
- default:
- break;
- }
-}
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req)
@@ -2430,8 +2177,13 @@ static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
sc->offchannel.scan_req = req;
sc->offchannel.scan_idx = 0;
- if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE)
+ ath_dbg(common, CHAN_CTX, "HW scan request received on vif: %pM\n",
+ vif->addr);
+
+ if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) {
+ ath_dbg(common, CHAN_CTX, "Starting HW scan\n");
ath_offchannel_next(sc);
+ }
out:
mutex_unlock(&sc->mutex);
@@ -2443,6 +2195,9 @@ static void ath9k_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ ath_dbg(common, CHAN_CTX, "Cancel HW scan on vif: %pM\n", vif->addr);
mutex_lock(&sc->mutex);
del_timer_sync(&sc->offchannel.timer);
@@ -2456,6 +2211,7 @@ static int ath9k_remain_on_channel(struct ieee80211_hw *hw,
enum ieee80211_roc_type type)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int ret = 0;
mutex_lock(&sc->mutex);
@@ -2470,8 +2226,14 @@ static int ath9k_remain_on_channel(struct ieee80211_hw *hw,
sc->offchannel.roc_chan = chan;
sc->offchannel.roc_duration = duration;
- if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE)
+ ath_dbg(common, CHAN_CTX,
+ "RoC request on vif: %pM, type: %d duration: %d\n",
+ vif->addr, type, duration);
+
+ if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) {
+ ath_dbg(common, CHAN_CTX, "Starting RoC period\n");
ath_offchannel_next(sc);
+ }
out:
mutex_unlock(&sc->mutex);
@@ -2482,9 +2244,11 @@ out:
static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
mutex_lock(&sc->mutex);
+ ath_dbg(common, CHAN_CTX, "Cancel RoC\n");
del_timer_sync(&sc->offchannel.timer);
if (sc->offchannel.roc_vif) {
@@ -2501,6 +2265,7 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *conf)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_chanctx *ctx, **ptr;
int pos;
@@ -2515,10 +2280,18 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw,
ctx->assigned = true;
pos = ctx - &sc->chanctx[0];
ctx->hw_queue_base = pos * IEEE80211_NUM_ACS;
+
+ ath_dbg(common, CHAN_CTX,
+ "Add channel context: %d MHz\n",
+ conf->def.chan->center_freq);
+
ath_chanctx_set_channel(sc, ctx, &conf->def);
+ ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ASSIGN);
+
mutex_unlock(&sc->mutex);
return 0;
}
+
mutex_unlock(&sc->mutex);
return -ENOSPC;
}
@@ -2528,12 +2301,19 @@ static void ath9k_remove_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *conf)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_chanctx *ctx = ath_chanctx_get(conf);
mutex_lock(&sc->mutex);
+
+ ath_dbg(common, CHAN_CTX,
+ "Remove channel context: %d MHz\n",
+ conf->def.chan->center_freq);
+
ctx->assigned = false;
ctx->hw_queue_base = -1;
ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN);
+
mutex_unlock(&sc->mutex);
}
@@ -2542,9 +2322,13 @@ static void ath9k_change_chanctx(struct ieee80211_hw *hw,
u32 changed)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_chanctx *ctx = ath_chanctx_get(conf);
mutex_lock(&sc->mutex);
+ ath_dbg(common, CHAN_CTX,
+ "Change channel context: %d MHz\n",
+ conf->def.chan->center_freq);
ath_chanctx_set_channel(sc, ctx, &conf->def);
mutex_unlock(&sc->mutex);
}
@@ -2554,16 +2338,24 @@ static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *conf)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_chanctx *ctx = ath_chanctx_get(conf);
int i;
mutex_lock(&sc->mutex);
+
+ ath_dbg(common, CHAN_CTX,
+ "Assign VIF (addr: %pM, type: %d, p2p: %d) to channel context: %d MHz\n",
+ vif->addr, vif->type, vif->p2p,
+ conf->def.chan->center_freq);
+
avp->chanctx = ctx;
list_add_tail(&avp->list, &ctx->vifs);
ath9k_calculate_summary_state(sc, ctx);
for (i = 0; i < IEEE80211_NUM_ACS; i++)
vif->hw_queue[i] = ctx->hw_queue_base + i;
+
mutex_unlock(&sc->mutex);
return 0;
@@ -2574,36 +2366,79 @@ static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *conf)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_chanctx *ctx = ath_chanctx_get(conf);
int ac;
mutex_lock(&sc->mutex);
+
+ ath_dbg(common, CHAN_CTX,
+ "Remove VIF (addr: %pM, type: %d, p2p: %d) from channel context: %d MHz\n",
+ vif->addr, vif->type, vif->p2p,
+ conf->def.chan->center_freq);
+
avp->chanctx = NULL;
list_del(&avp->list);
ath9k_calculate_summary_state(sc, ctx);
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE;
+
+ mutex_unlock(&sc->mutex);
+}
+
+static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
+ bool changed = false;
+
+ if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+ return;
+
+ if (!avp->chanctx)
+ return;
+
+ mutex_lock(&sc->mutex);
+
+ spin_lock_bh(&sc->chan_lock);
+ if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
+ sc->next_chan = avp->chanctx;
+ changed = true;
+ }
+ ath_dbg(common, CHAN_CTX,
+ "%s: Set chanctx state to FORCE_ACTIVE, changed: %d\n",
+ __func__, changed);
+ sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
+ spin_unlock_bh(&sc->chan_lock);
+
+ if (changed)
+ ath_chanctx_set_next(sc, true);
+
mutex_unlock(&sc->mutex);
}
void ath9k_fill_chanctx_ops(void)
{
- if (!ath9k_use_chanctx)
+ if (!ath9k_is_chanctx_enabled())
return;
- ath9k_ops.hw_scan = ath9k_hw_scan;
- ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan;
- ath9k_ops.remain_on_channel = ath9k_remain_on_channel;
+ ath9k_ops.hw_scan = ath9k_hw_scan;
+ ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan;
+ ath9k_ops.remain_on_channel = ath9k_remain_on_channel;
ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel;
- ath9k_ops.add_chanctx = ath9k_add_chanctx;
- ath9k_ops.remove_chanctx = ath9k_remove_chanctx;
- ath9k_ops.change_chanctx = ath9k_change_chanctx;
- ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx;
- ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx;
- ath9k_ops.mgd_prepare_tx = ath9k_chanctx_force_active;
+ ath9k_ops.add_chanctx = ath9k_add_chanctx;
+ ath9k_ops.remove_chanctx = ath9k_remove_chanctx;
+ ath9k_ops.change_chanctx = ath9k_change_chanctx;
+ ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx;
+ ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx;
+ ath9k_ops.mgd_prepare_tx = ath9k_mgd_prepare_tx;
}
+#endif
+
struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
.start = ath9k_start,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 74ab1d02013..6914e21816e 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -387,7 +387,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (sc->hw->conf.radar_enabled)
rfilt |= ATH9K_RX_FILTER_PHYRADAR | ATH9K_RX_FILTER_PHYERR;
- if (sc->rx.rxfilter & FIF_PROBE_REQ)
+ spin_lock_bh(&sc->chan_lock);
+
+ if (sc->cur_chan->rxfilter & FIF_PROBE_REQ)
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
/*
@@ -398,24 +400,25 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (sc->sc_ah->is_monitoring)
rfilt |= ATH9K_RX_FILTER_PROM;
- if (sc->rx.rxfilter & FIF_CONTROL)
+ if ((sc->cur_chan->rxfilter & FIF_CONTROL) ||
+ sc->sc_ah->dynack.enabled)
rfilt |= ATH9K_RX_FILTER_CONTROL;
if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
- (sc->nvifs <= 1) &&
- !(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC))
+ (sc->cur_chan->nvifs <= 1) &&
+ !(sc->cur_chan->rxfilter & FIF_BCN_PRBRESP_PROMISC))
rfilt |= ATH9K_RX_FILTER_MYBEACON;
else
rfilt |= ATH9K_RX_FILTER_BEACON;
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
- (sc->rx.rxfilter & FIF_PSPOLL))
+ (sc->cur_chan->rxfilter & FIF_PSPOLL))
rfilt |= ATH9K_RX_FILTER_PSPOLL;
- if (conf_is_ht(&sc->hw->conf))
+ if (sc->cur_chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
rfilt |= ATH9K_RX_FILTER_COMP_BAR;
- if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
+ if (sc->cur_chan->nvifs > 1 || (sc->cur_chan->rxfilter & FIF_OTHER_BSS)) {
/* This is needed for older chips */
if (sc->sc_ah->hw_version.macVersion <= AR_SREV_VERSION_9160)
rfilt |= ATH9K_RX_FILTER_PROM;
@@ -425,22 +428,24 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah))
rfilt |= ATH9K_RX_FILTER_4ADDRESS;
- if (ath9k_use_chanctx &&
+ if (ath9k_is_chanctx_enabled() &&
test_bit(ATH_OP_SCANNING, &common->op_flags))
rfilt |= ATH9K_RX_FILTER_BEACON;
+ spin_unlock_bh(&sc->chan_lock);
+
return rfilt;
}
-int ath_startrecv(struct ath_softc *sc)
+void ath_startrecv(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_rxbuf *bf, *tbf;
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
ath_edma_start_recv(sc);
- return 0;
+ return;
}
if (list_empty(&sc->rx.rxbuf))
@@ -463,8 +468,6 @@ int ath_startrecv(struct ath_softc *sc)
start_recv:
ath_opmode_init(sc);
ath9k_hw_startpcureceive(ah, sc->cur_chan->offchannel);
-
- return 0;
}
static void ath_flushrecv(struct ath_softc *sc)
@@ -535,6 +538,7 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ bool skip_beacon = false;
if (skb->len < 24 + 8 + 2 + 2)
return;
@@ -545,10 +549,19 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
sc->ps_flags &= ~PS_BEACON_SYNC;
ath_dbg(common, PS,
"Reconfigure beacon timers based on synchronized timestamp\n");
- if (!(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0)))
+
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+ if (ath9k_is_chanctx_enabled()) {
+ if (sc->cur_chan == &sc->offchannel.chan)
+ skip_beacon = true;
+ }
+#endif
+
+ if (!skip_beacon &&
+ !(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0)))
ath9k_set_beacon(sc);
- if (sc->p2p_ps_vif)
- ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
+
+ ath9k_p2p_beacon_sync(sc);
}
if (ath_beacon_dtim_pending_cab(skb)) {
@@ -867,8 +880,13 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
* everything but the rate is checked here, the rate check is done
* separately to avoid doing two lookups for a rate for each frame.
*/
- if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter))
+ spin_lock_bh(&sc->chan_lock);
+ if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error,
+ sc->cur_chan->rxfilter)) {
+ spin_unlock_bh(&sc->chan_lock);
return -EINVAL;
+ }
+ spin_unlock_bh(&sc->chan_lock);
if (ath_is_mybeacon(common, hdr)) {
RX_STAT_INC(rx_beacons);
@@ -892,9 +910,10 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
return -EINVAL;
}
- if (rx_stats->is_mybeacon) {
- sc->sched.next_tbtt = rx_stats->rs_tstamp;
- ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_BEACON_RECEIVED);
+ if (ath9k_is_chanctx_enabled()) {
+ if (rx_stats->is_mybeacon)
+ ath_chanctx_beacon_recv_ev(sc,
+ ATH_CHANCTX_EVENT_BEACON_RECEIVED);
}
ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status);
@@ -991,6 +1010,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
unsigned long flags;
dma_addr_t new_buf_addr;
unsigned int budget = 512;
+ struct ieee80211_hdr *hdr;
if (edma)
dma_type = DMA_BIDIRECTIONAL;
@@ -1120,6 +1140,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
ath9k_apply_ampdu_details(sc, &rs, rxs);
ath_debug_rate_stats(sc, &rs, skb);
+ hdr = (struct ieee80211_hdr *)skb->data;
+ if (ieee80211_is_ack(hdr->frame_control))
+ ath_dynack_sample_ack_ts(sc->sc_ah, skb, rs.rs_tstamp);
+
ieee80211_rx(hw, skb);
requeue_drop_frag:
diff --git a/drivers/net/wireless/ath/ath9k/spectral.c b/drivers/net/wireless/ath/ath9k/spectral.c
index 5fe29b9f8fa..8f68426ca65 100644
--- a/drivers/net/wireless/ath/ath9k/spectral.c
+++ b/drivers/net/wireless/ath/ath9k/spectral.c
@@ -253,7 +253,7 @@ static ssize_t write_file_spec_scan_ctl(struct file *file,
if (strncmp("trigger", buf, 7) == 0) {
ath9k_spectral_scan_trigger(sc->hw);
- } else if (strncmp("background", buf, 9) == 0) {
+ } else if (strncmp("background", buf, 10) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
} else if (strncmp("chanscan", buf, 8) == 0) {
diff --git a/drivers/net/wireless/ath/ath9k/spectral.h b/drivers/net/wireless/ath/ath9k/spectral.h
index ead63412ee1..7b410c6858b 100644
--- a/drivers/net/wireless/ath/ath9k/spectral.h
+++ b/drivers/net/wireless/ath/ath9k/spectral.h
@@ -17,6 +17,8 @@
#ifndef SPECTRAL_H
#define SPECTRAL_H
+#include "../spectral_common.h"
+
/* enum spectral_mode:
*
* @SPECTRAL_DISABLED: spectral mode is disabled
@@ -54,8 +56,6 @@ struct ath_ht20_mag_info {
u8 max_exp;
} __packed;
-#define SPECTRAL_HT20_NUM_BINS 56
-
/* WARNING: don't actually use this struct! MAC may vary the amount of
* data by -1/+2. This struct is for reference only.
*/
@@ -83,8 +83,6 @@ struct ath_ht20_40_mag_info {
u8 max_exp;
} __packed;
-#define SPECTRAL_HT20_40_NUM_BINS 128
-
/* WARNING: don't actually use this struct! MAC may vary the amount of
* data. This struct is for reference only.
*/
@@ -125,71 +123,6 @@ static inline u8 spectral_bitmap_weight(u8 *bins)
return bins[0] & 0x3f;
}
-/* FFT sample format given to userspace via debugfs.
- *
- * Please keep the type/length at the front position and change
- * other fields after adding another sample type
- *
- * TODO: this might need rework when switching to nl80211-based
- * interface.
- */
-enum ath_fft_sample_type {
- ATH_FFT_SAMPLE_HT20 = 1,
- ATH_FFT_SAMPLE_HT20_40,
-};
-
-struct fft_sample_tlv {
- u8 type; /* see ath_fft_sample */
- __be16 length;
- /* type dependent data follows */
-} __packed;
-
-struct fft_sample_ht20 {
- struct fft_sample_tlv tlv;
-
- u8 max_exp;
-
- __be16 freq;
- s8 rssi;
- s8 noise;
-
- __be16 max_magnitude;
- u8 max_index;
- u8 bitmap_weight;
-
- __be64 tsf;
-
- u8 data[SPECTRAL_HT20_NUM_BINS];
-} __packed;
-
-struct fft_sample_ht20_40 {
- struct fft_sample_tlv tlv;
-
- u8 channel_type;
- __be16 freq;
-
- s8 lower_rssi;
- s8 upper_rssi;
-
- __be64 tsf;
-
- s8 lower_noise;
- s8 upper_noise;
-
- __be16 lower_max_magnitude;
- __be16 upper_max_magnitude;
-
- u8 lower_max_index;
- u8 upper_max_index;
-
- u8 lower_bitmap_weight;
- u8 upper_bitmap_weight;
-
- u8 max_exp;
-
- u8 data[SPECTRAL_HT20_40_NUM_BINS];
-} __packed;
-
void ath9k_spectral_init_debug(struct ath_softc *sc);
void ath9k_spectral_deinit_debug(struct ath_softc *sc);
diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c
index 23972924c77..8a69d08ec55 100644
--- a/drivers/net/wireless/ath/ath9k/tx99.c
+++ b/drivers/net/wireless/ath/ath9k/tx99.c
@@ -174,7 +174,7 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,
ssize_t len;
int r;
- if (sc->nvifs > 1)
+ if (sc->cur_chan->nvifs > 1)
return -EOPNOTSUPP;
len = min(count, sizeof(buf) - 1);
diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c
index a4f4f0da81f..5f30e580d94 100644
--- a/drivers/net/wireless/ath/ath9k/wow.c
+++ b/drivers/net/wireless/ath/ath9k/wow.c
@@ -193,7 +193,8 @@ int ath9k_suspend(struct ieee80211_hw *hw,
u32 wow_triggers_enabled = 0;
int ret = 0;
- cancel_work_sync(&sc->chanctx_work);
+ ath9k_deinit_channel_context(sc);
+
mutex_lock(&sc->mutex);
ath_cancel_work(sc);
@@ -231,7 +232,7 @@ int ath9k_suspend(struct ieee80211_hw *hw,
goto fail_wow;
}
- if (sc->nvifs > 1) {
+ if (sc->cur_chan->nvifs > 1) {
ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
ret = 1;
goto fail_wow;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 704fcbcbe20..93ad31be0ad 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -587,6 +587,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
memcpy(tx_info->control.rates, rates, sizeof(rates));
ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok);
rc_update = false;
+ if (bf == bf->bf_lastbf)
+ ath_dynack_sample_tx_ts(sc->sc_ah,
+ bf->bf_mpdu,
+ ts);
}
ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
@@ -687,6 +691,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
memcpy(info->control.rates, bf->rates,
sizeof(info->control.rates));
ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
+ ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts);
}
ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
} else
@@ -2632,8 +2637,11 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
sc->beacon.tx_processed = true;
sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
- ath_chanctx_event(sc, NULL,
- ATH_CHANCTX_EVENT_BEACON_SENT);
+ if (ath9k_is_chanctx_enabled()) {
+ ath_chanctx_event(sc, NULL,
+ ATH_CHANCTX_EVENT_BEACON_SENT);
+ }
+
ath9k_csa_update(sc);
continue;
}
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index f8ded84b7be..ef5b6dc7b7f 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1430,18 +1430,10 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
if (!sta_info->ht_sta)
return -EOPNOTSUPP;
- rcu_read_lock();
- if (rcu_dereference(sta_info->agg[tid])) {
- rcu_read_unlock();
- return -EBUSY;
- }
-
tid_info = kzalloc(sizeof(struct carl9170_sta_tid),
GFP_ATOMIC);
- if (!tid_info) {
- rcu_read_unlock();
+ if (!tid_info)
return -ENOMEM;
- }
tid_info->hsn = tid_info->bsn = tid_info->snx = (*ssn);
tid_info->state = CARL9170_TID_STATE_PROGRESS;
@@ -1460,7 +1452,6 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
list_add_tail_rcu(&tid_info->list, &ar->tx_ampdu_list);
rcu_assign_pointer(sta_info->agg[tid], tid_info);
spin_unlock_bh(&ar->tx_ampdu_list_lock);
- rcu_read_unlock();
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index 4cadfd48ffd..ae86a600d92 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -1557,7 +1557,7 @@ static struct carl9170_vif_info *carl9170_pick_beaconing_vif(struct ar9170 *ar)
}
out:
- rcu_assign_pointer(ar->beacon_iter, cvif);
+ RCU_INIT_POINTER(ar->beacon_iter, cvif);
return cvif;
}
diff --git a/drivers/net/wireless/ath/spectral_common.h b/drivers/net/wireless/ath/spectral_common.h
new file mode 100644
index 00000000000..0d742acb159
--- /dev/null
+++ b/drivers/net/wireless/ath/spectral_common.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2013 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 SPECTRAL_COMMON_H
+#define SPECTRAL_COMMON_H
+
+#define SPECTRAL_HT20_NUM_BINS 56
+#define SPECTRAL_HT20_40_NUM_BINS 128
+
+/* TODO: could possibly be 512, but no samples this large
+ * could be acquired so far.
+ */
+#define SPECTRAL_ATH10K_MAX_NUM_BINS 256
+
+/* FFT sample format given to userspace via debugfs.
+ *
+ * Please keep the type/length at the front position and change
+ * other fields after adding another sample type
+ *
+ * TODO: this might need rework when switching to nl80211-based
+ * interface.
+ */
+enum ath_fft_sample_type {
+ ATH_FFT_SAMPLE_HT20 = 1,
+ ATH_FFT_SAMPLE_HT20_40,
+ ATH_FFT_SAMPLE_ATH10K,
+};
+
+struct fft_sample_tlv {
+ u8 type; /* see ath_fft_sample */
+ __be16 length;
+ /* type dependent data follows */
+} __packed;
+
+struct fft_sample_ht20 {
+ struct fft_sample_tlv tlv;
+
+ u8 max_exp;
+
+ __be16 freq;
+ s8 rssi;
+ s8 noise;
+
+ __be16 max_magnitude;
+ u8 max_index;
+ u8 bitmap_weight;
+
+ __be64 tsf;
+
+ u8 data[SPECTRAL_HT20_NUM_BINS];
+} __packed;
+
+struct fft_sample_ht20_40 {
+ struct fft_sample_tlv tlv;
+
+ u8 channel_type;
+ __be16 freq;
+
+ s8 lower_rssi;
+ s8 upper_rssi;
+
+ __be64 tsf;
+
+ s8 lower_noise;
+ s8 upper_noise;
+
+ __be16 lower_max_magnitude;
+ __be16 upper_max_magnitude;
+
+ u8 lower_max_index;
+ u8 upper_max_index;
+
+ u8 lower_bitmap_weight;
+ u8 upper_bitmap_weight;
+
+ u8 max_exp;
+
+ u8 data[SPECTRAL_HT20_40_NUM_BINS];
+} __packed;
+
+struct fft_sample_ath10k {
+ struct fft_sample_tlv tlv;
+ u8 chan_width_mhz;
+ __be16 freq1;
+ __be16 freq2;
+ __be16 noise;
+ __be16 max_magnitude;
+ __be16 total_gain_db;
+ __be16 base_pwr_db;
+ __be64 tsf;
+ s8 max_index;
+ u8 rssi;
+ u8 relpwr_db;
+ u8 avgpwr_db;
+ u8 max_exp;
+
+ u8 data[0];
+} __packed;
+
+#endif /* SPECTRAL_COMMON_H */
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig
index ce8c0381825..481680a3aa5 100644
--- a/drivers/net/wireless/ath/wil6210/Kconfig
+++ b/drivers/net/wireless/ath/wil6210/Kconfig
@@ -39,3 +39,12 @@ config WIL6210_TRACING
option if you are interested in debugging the driver.
If unsure, say Y to make it easier to debug problems.
+
+config WIL6210_PLATFORM_MSM
+ bool "wil6210 MSM platform specific support"
+ depends on WIL6210
+ depends on ARCH_MSM
+ default y
+ ---help---
+ Say Y here to enable wil6210 driver support for MSM
+ platform specific features
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index c7a3465fd02..a471d74ae40 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -10,7 +10,10 @@ wil6210-y += interrupt.o
wil6210-y += txrx.o
wil6210-y += debug.o
wil6210-y += rx_reorder.o
+wil6210-y += fw.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
+wil6210-y += wil_platform.o
+wil6210-$(CONFIG_WIL6210_PLATFORM_MSM) += wil_platform_msm.o
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 4ac2c208c9b..f3a31e8c253 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -296,6 +296,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
n = min(request->n_channels, 4U);
for (i = 0; i < n; i++) {
int ch = request->channels[i]->hw_value;
+
if (ch == 0) {
wil_err(wil,
"Scan requested for unknown frequency %dMhz\n",
@@ -308,15 +309,47 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
request->channels[i]->center_freq);
}
+ if (request->ie_len)
+ print_hex_dump_bytes("Scan IE ", DUMP_PREFIX_OFFSET,
+ request->ie, request->ie_len);
+ else
+ wil_dbg_misc(wil, "Scan has no IE's\n");
+
+ rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len,
+ request->ie);
+ if (rc) {
+ wil_err(wil, "Aborting scan, set_ie failed: %d\n", rc);
+ goto out;
+ }
+
rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
- if (rc)
+out:
+ if (rc) {
+ del_timer_sync(&wil->scan_timer);
wil->scan_request = NULL;
+ }
return rc;
}
+static void wil_print_connect_params(struct wil6210_priv *wil,
+ struct cfg80211_connect_params *sme)
+{
+ wil_info(wil, "Connecting to:\n");
+ if (sme->channel) {
+ wil_info(wil, " Channel: %d freq %d\n",
+ sme->channel->hw_value, sme->channel->center_freq);
+ }
+ if (sme->bssid)
+ wil_info(wil, " BSSID: %pM\n", sme->bssid);
+ if (sme->ssid)
+ print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET,
+ 16, 1, sme->ssid, sme->ssid_len, true);
+ wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open");
+}
+
static int wil_cfg80211_connect(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_connect_params *sme)
@@ -333,6 +366,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
test_bit(wil_status_fwconnected, &wil->status))
return -EALREADY;
+ wil_print_connect_params(wil, sme);
+
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
sme->ssid, sme->ssid_len,
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
@@ -358,22 +393,22 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
sme->ie_len);
goto out;
}
- /*
- * For secure assoc, send:
- * (1) WMI_DELETE_CIPHER_KEY_CMD
- * (2) WMI_SET_APPIE_CMD
- */
+ /* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */
rc = wmi_del_cipher_key(wil, 0, bss->bssid);
if (rc) {
wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
goto out;
}
- /* WMI_SET_APPIE_CMD */
- rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
- if (rc) {
- wil_err(wil, "WMI_SET_APPIE_CMD failed\n");
- goto out;
- }
+ }
+
+ /* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info
+ * elements. Send it also in case it's empty, to erase previously set
+ * ies in FW.
+ */
+ rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
+ if (rc) {
+ wil_err(wil, "WMI_SET_APPIE_CMD failed\n");
+ goto out;
}
/* WMI_CONNECT_CMD */
@@ -619,6 +654,45 @@ static int wil_fix_bcon(struct wil6210_priv *wil,
return rc;
}
+static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
+ struct net_device *ndev,
+ struct cfg80211_beacon_data *bcon)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ int rc;
+
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
+ if (wil_fix_bcon(wil, bcon)) {
+ wil_dbg_misc(wil, "Fixed bcon\n");
+ wil_print_bcon_data(bcon);
+ }
+
+ /* FW do not form regular beacon, so bcon IE's are not set
+ * For the DMG bcon, when it will be supported, bcon IE's will
+ * be reused; add something like:
+ * 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);
+ if (rc) {
+ wil_err(wil, "set_ie(PROBE_RESP) failed\n");
+ return rc;
+ }
+
+ rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP,
+ bcon->assocresp_ies_len,
+ bcon->assocresp_ies);
+ if (rc) {
+ wil_err(wil, "set_ie(ASSOC_RESP) failed\n");
+ return rc;
+ }
+
+ return 0;
+}
+
static int wil_cfg80211_start_ap(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_ap_settings *info)
@@ -656,12 +730,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
mutex_lock(&wil->mutex);
- rc = wil_reset(wil);
- if (rc)
- goto out;
-
- /* Rx VRING. */
- rc = wil_rx_init(wil);
+ __wil_down(wil);
+ rc = __wil_up(wil);
if (rc)
goto out;
@@ -669,9 +739,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
if (rc)
goto out;
- /* MAC address - pre-requisite for other commands */
- wmi_set_mac_address(wil, ndev->dev_addr);
-
/* IE's */
/* bcon 'head IE's are not relevant for 60g band */
/*
@@ -693,7 +760,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
if (rc)
goto out;
-
netif_carrier_on(ndev);
out:
@@ -704,7 +770,7 @@ out:
static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
struct net_device *ndev)
{
- int rc = 0;
+ int rc, rc1;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
wil_dbg_misc(wil, "%s()\n", __func__);
@@ -713,8 +779,12 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
rc = wmi_pcp_stop(wil);
+ __wil_down(wil);
+ rc1 = __wil_up(wil);
+
mutex_unlock(&wil->mutex);
- return rc;
+
+ return min(rc, rc1);
}
static int wil_cfg80211_del_station(struct wiphy *wiphy,
@@ -744,6 +814,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
.del_key = wil_cfg80211_del_key,
.set_default_key = wil_cfg80211_set_default_key,
/* AP mode */
+ .change_beacon = wil_cfg80211_change_beacon,
.start_ap = wil_cfg80211_start_ap,
.stop_ap = wil_cfg80211_stop_ap,
.del_station = wil_cfg80211_del_station,
@@ -753,6 +824,7 @@ static void wil_wiphy_init(struct wiphy *wiphy)
{
/* TODO: set real value */
wiphy->max_scan_ssids = 10;
+ wiphy->max_scan_ie_len = WMI_MAX_IE_LEN;
wiphy->max_num_pmkids = 0 /* TODO: */;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
@@ -762,8 +834,8 @@ static void wil_wiphy_init(struct wiphy *wiphy)
*/
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
- dev_warn(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
- __func__, wiphy->flags);
+ dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
+ __func__, wiphy->flags);
wiphy->probe_resp_offload =
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
@@ -784,7 +856,9 @@ struct wireless_dev *wil_cfg80211_init(struct device *dev)
int rc = 0;
struct wireless_dev *wdev;
- wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ dev_dbg(dev, "%s()\n", __func__);
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
if (!wdev)
return ERR_PTR(-ENOMEM);
@@ -816,6 +890,8 @@ void wil_wdev_free(struct wil6210_priv *wil)
{
struct wireless_dev *wdev = wil_to_wdev(wil);
+ dev_dbg(wil_to_dev(wil), "%s()\n", __func__);
+
if (!wdev)
return;
diff --git a/drivers/net/wireless/ath/wil6210/debug.c b/drivers/net/wireless/ath/wil6210/debug.c
index 9eeabf4a587..8d99021d27a 100644
--- a/drivers/net/wireless/ath/wil6210/debug.c
+++ b/drivers/net/wireless/ath/wil6210/debug.c
@@ -17,43 +17,37 @@
#include "wil6210.h"
#include "trace.h"
-int wil_err(struct wil6210_priv *wil, const char *fmt, ...)
+void wil_err(struct wil6210_priv *wil, const char *fmt, ...)
{
struct net_device *ndev = wil_to_ndev(wil);
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
- int ret;
va_start(args, fmt);
vaf.va = &args;
- ret = netdev_err(ndev, "%pV", &vaf);
+ netdev_err(ndev, "%pV", &vaf);
trace_wil6210_log_err(&vaf);
va_end(args);
-
- return ret;
}
-int wil_info(struct wil6210_priv *wil, const char *fmt, ...)
+void wil_info(struct wil6210_priv *wil, const char *fmt, ...)
{
struct net_device *ndev = wil_to_ndev(wil);
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
- int ret;
va_start(args, fmt);
vaf.va = &args;
- ret = netdev_info(ndev, "%pV", &vaf);
+ netdev_info(ndev, "%pV", &vaf);
trace_wil6210_log_info(&vaf);
va_end(args);
-
- return ret;
}
-int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...)
+void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
@@ -64,6 +58,4 @@ int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...)
vaf.va = &args;
trace_wil6210_log_dbg(&vaf);
va_end(args);
-
- return 0;
}
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 8f66186adb8..eb2204e5fdd 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -22,6 +22,7 @@
#include <linux/power_supply.h>
#include "wil6210.h"
+#include "wmi.h"
#include "txrx.h"
/* Nasty hack. Better have per device instances */
@@ -29,6 +30,21 @@ static u32 mem_addr;
static u32 dbg_txdesc_index;
static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
+enum dbg_off_type {
+ doff_u32 = 0,
+ doff_x32 = 1,
+ doff_ulong = 2,
+ doff_io32 = 3,
+};
+
+/* offset to "wil" */
+struct dbg_off {
+ const char *name;
+ umode_t mode;
+ ulong off;
+ enum dbg_off_type type;
+};
+
static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
const char *name, struct vring *vring,
char _s, char _h)
@@ -45,20 +61,22 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
if (x)
seq_printf(s, "0x%08x\n", ioread32(x));
else
- seq_printf(s, "???\n");
+ seq_puts(s, "???\n");
if (vring->va && (vring->size < 1025)) {
uint i;
+
for (i = 0; i < vring->size; i++) {
volatile struct vring_tx_desc *d = &vring->va[i].tx;
+
if ((i % 64) == 0 && (i != 0))
- seq_printf(s, "\n");
+ seq_puts(s, "\n");
seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
_s : (vring->ctx[i].skb ? _h : 'h'));
}
- seq_printf(s, "\n");
+ seq_puts(s, "\n");
}
- seq_printf(s, "}\n");
+ seq_puts(s, "}\n");
}
static int wil_vring_debugfs_show(struct seq_file *s, void *data)
@@ -69,7 +87,7 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
- struct vring *vring = &(wil->vring_tx[i]);
+ struct vring *vring = &wil->vring_tx[i];
struct vring_tx_data *txdata = &wil->vring_tx_data[i];
if (vring->va) {
@@ -147,7 +165,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
if (!wmi_addr(wil, r.base) ||
!wmi_addr(wil, r.tail) ||
!wmi_addr(wil, r.head)) {
- seq_printf(s, " ??? pointers are garbage?\n");
+ seq_puts(s, " ??? pointers are garbage?\n");
goto out;
}
@@ -166,6 +184,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
le32_to_cpu(d.addr));
if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
u16 len = le16_to_cpu(hdr.len);
+
seq_printf(s, " -> %04x %04x %04x %02x\n",
le16_to_cpu(hdr.seq), len,
le16_to_cpu(hdr.type), hdr.flags);
@@ -183,6 +202,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
wil_memcpy_fromio_32(databuf, src, len);
while (n < len) {
int l = min(len - n, 16);
+
hex_dump_to_buffer(databuf + n, l,
16, 1, printbuf,
sizeof(printbuf),
@@ -192,11 +212,11 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
}
}
} else {
- seq_printf(s, "\n");
+ seq_puts(s, "\n");
}
}
out:
- seq_printf(s, "}\n");
+ seq_puts(s, "}\n");
}
static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
@@ -244,9 +264,9 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
umode_t mode,
struct dentry *parent,
- void __iomem *value)
+ void *value)
{
- return debugfs_create_file(name, mode, parent, (void * __force)value,
+ return debugfs_create_file(name, mode, parent, value,
&fops_iomem_x32);
}
@@ -255,11 +275,13 @@ static int wil_debugfs_ulong_set(void *data, u64 val)
*(ulong *)data = val;
return 0;
}
+
static int wil_debugfs_ulong_get(void *data, u64 *val)
{
*val = *(ulong *)data;
return 0;
}
+
DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
wil_debugfs_ulong_set, "%llu\n");
@@ -270,6 +292,62 @@ static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,
return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong);
}
+/**
+ * wil6210_debugfs_init_offset - create set of debugfs files
+ * @wil - driver's context, used for printing
+ * @dbg - directory on the debugfs, where files will be created
+ * @base - base address used in address calculation
+ * @tbl - table with file descriptions. Should be terminated with empty element.
+ *
+ * Creates files accordingly to the @tbl.
+ */
+static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
+ struct dentry *dbg, void *base,
+ const struct dbg_off * const tbl)
+{
+ int i;
+
+ for (i = 0; tbl[i].name; i++) {
+ struct dentry *f;
+
+ switch (tbl[i].type) {
+ case doff_u32:
+ f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
+ base + tbl[i].off);
+ break;
+ case doff_x32:
+ f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
+ base + tbl[i].off);
+ break;
+ case doff_ulong:
+ f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode,
+ dbg, base + tbl[i].off);
+ break;
+ case doff_io32:
+ f = wil_debugfs_create_iomem_x32(tbl[i].name,
+ tbl[i].mode, dbg,
+ base + tbl[i].off);
+ break;
+ default:
+ f = ERR_PTR(-EINVAL);
+ }
+ if (IS_ERR_OR_NULL(f))
+ wil_err(wil, "Create file \"%s\": err %ld\n",
+ tbl[i].name, PTR_ERR(f));
+ }
+}
+
+static const struct dbg_off isr_off[] = {
+ {"ICC", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICC), doff_io32},
+ {"ICR", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICR), doff_io32},
+ {"ICM", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICM), doff_io32},
+ {"ICS", S_IWUSR, offsetof(struct RGF_ICR, ICS), doff_io32},
+ {"IMV", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, IMV), doff_io32},
+ {"IMS", S_IWUSR, offsetof(struct RGF_ICR, IMS), doff_io32},
+ {"IMC", S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32},
+ {},
+};
+
static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
const char *name,
struct dentry *parent, u32 off)
@@ -279,24 +357,19 @@ static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
if (IS_ERR_OR_NULL(d))
return -ENODEV;
- wil_debugfs_create_iomem_x32("ICC", S_IRUGO | S_IWUSR, d,
- wil->csr + off);
- wil_debugfs_create_iomem_x32("ICR", S_IRUGO | S_IWUSR, d,
- wil->csr + off + 4);
- wil_debugfs_create_iomem_x32("ICM", S_IRUGO | S_IWUSR, d,
- wil->csr + off + 8);
- wil_debugfs_create_iomem_x32("ICS", S_IWUSR, d,
- wil->csr + off + 12);
- wil_debugfs_create_iomem_x32("IMV", S_IRUGO | S_IWUSR, d,
- wil->csr + off + 16);
- wil_debugfs_create_iomem_x32("IMS", S_IWUSR, d,
- wil->csr + off + 20);
- wil_debugfs_create_iomem_x32("IMC", S_IWUSR, d,
- wil->csr + off + 24);
+ wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off,
+ isr_off);
return 0;
}
+static const struct dbg_off pseudo_isr_off[] = {
+ {"CAUSE", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
+ {"MASK_SW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
+ {"MASK_FW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
+ {},
+};
+
static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
struct dentry *parent)
{
@@ -305,16 +378,19 @@ static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
if (IS_ERR_OR_NULL(d))
return -ENODEV;
- wil_debugfs_create_iomem_x32("CAUSE", S_IRUGO, d, wil->csr +
- HOSTADDR(RGF_DMA_PSEUDO_CAUSE));
- wil_debugfs_create_iomem_x32("MASK_SW", S_IRUGO, d, wil->csr +
- HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
- wil_debugfs_create_iomem_x32("MASK_FW", S_IRUGO, d, wil->csr +
- HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW));
+ wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
+ pseudo_isr_off);
return 0;
}
+static const struct dbg_off itr_cnt_off[] = {
+ {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
+ {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
+ {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
+ {},
+};
+
static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
struct dentry *parent)
{
@@ -323,12 +399,8 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
if (IS_ERR_OR_NULL(d))
return -ENODEV;
- wil_debugfs_create_iomem_x32("TRSH", S_IRUGO | S_IWUSR, d, wil->csr +
- HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
- wil_debugfs_create_iomem_x32("DATA", S_IRUGO | S_IWUSR, d, wil->csr +
- HOSTADDR(RGF_DMA_ITR_CNT_DATA));
- wil_debugfs_create_iomem_x32("CTL", S_IRUGO | S_IWUSR, d, wil->csr +
- HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+ wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
+ itr_cnt_off);
return 0;
}
@@ -359,7 +431,7 @@ static const struct file_operations fops_memread = {
};
static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
enum { max_count = 4096 };
struct debugfs_blob_wrapper *blob = file->private_data;
@@ -411,6 +483,7 @@ struct dentry *wil_debugfs_create_ioblob(const char *name,
{
return debugfs_create_file(name, mode, parent, blob, &fops_ioblob);
}
+
/*---reset---*/
static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
@@ -436,6 +509,7 @@ static const struct file_operations fops_reset = {
.write = wil_write_file_reset,
.open = simple_open,
};
+
/*---write channel 1..4 to rxon for it, 0 to rxoff---*/
static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
@@ -446,6 +520,7 @@ static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
bool on;
char *kbuf = kmalloc(len + 1, GFP_KERNEL);
+
if (!kbuf)
return -ENOMEM;
if (copy_from_user(kbuf, buf, len)) {
@@ -482,6 +557,7 @@ static const struct file_operations fops_rxon = {
.write = wil_write_file_rxon,
.open = simple_open,
};
+
/*---tx_mgmt---*/
/* Write mgmt frame to this file to send it */
static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
@@ -492,8 +568,8 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
struct wireless_dev *wdev = wil_to_wdev(wil);
struct cfg80211_mgmt_tx_params params;
int rc;
-
void *frame = kmalloc(len, GFP_KERNEL);
+
if (!frame)
return -ENOMEM;
@@ -562,8 +638,10 @@ static void wil_seq_hexdump(struct seq_file *s, void *p, int len,
{
char printbuf[16 * 3 + 2];
int i = 0;
+
while (i < len) {
int l = min(len - i, 16);
+
hex_dump_to_buffer(p + i, l, 16, 1, printbuf,
sizeof(printbuf), false);
seq_printf(s, "%s%s\n", prefix, printbuf);
@@ -601,10 +679,8 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
struct wil6210_priv *wil = s->private;
struct vring *vring;
bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS);
- if (tx)
- vring = &(wil->vring_tx[dbg_vring_index]);
- else
- vring = &wil->vring_rx;
+
+ vring = tx ? &wil->vring_tx[dbg_vring_index] : &wil->vring_rx;
if (!vring->va) {
if (tx)
@@ -619,7 +695,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
* only field used, .dma.length, is the same
*/
volatile struct vring_tx_desc *d =
- &(vring->va[dbg_txdesc_index].tx);
+ &vring->va[dbg_txdesc_index].tx;
volatile u32 *u = (volatile u32 *)d;
struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
@@ -639,7 +715,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
wil_seq_print_skb(s, skb);
kfree_skb(skb);
}
- seq_printf(s, "}\n");
+ seq_puts(s, "}\n");
} else {
if (tx)
seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
@@ -666,16 +742,79 @@ static const struct file_operations fops_txdesc = {
};
/*---------beamforming------------*/
+static char *wil_bfstatus_str(u32 status)
+{
+ switch (status) {
+ case 0:
+ return "Failed";
+ case 1:
+ return "OK";
+ case 2:
+ return "Retrying";
+ default:
+ return "??";
+ }
+}
+
+static bool is_all_zeros(void * const x_, size_t sz)
+{
+ /* if reply is all-0, ignore this CID */
+ u32 *x = x_;
+ int n;
+
+ for (n = 0; n < sz / sizeof(*x); n++)
+ if (x[n])
+ return false;
+
+ return true;
+}
+
static int wil_bf_debugfs_show(struct seq_file *s, void *data)
{
+ int rc;
+ int i;
struct wil6210_priv *wil = s->private;
- seq_printf(s,
- "TSF : 0x%016llx\n"
- "TxMCS : %d\n"
- "Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n",
- wil->stats.tsf, wil->stats.bf_mcs,
- wil->stats.my_rx_sector, wil->stats.my_tx_sector,
- wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
+ struct wmi_notify_req_cmd cmd = {
+ .interval_usec = 0,
+ };
+ struct {
+ struct wil6210_mbox_hdr_wmi wmi;
+ struct wmi_notify_req_done_event evt;
+ } __packed reply;
+
+ for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ u32 status;
+
+ cmd.cid = i;
+ rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
+ WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
+ sizeof(reply), 20);
+ /* if reply is all-0, ignore this CID */
+ if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
+ continue;
+
+ status = le32_to_cpu(reply.evt.status);
+ seq_printf(s, "CID %d {\n"
+ " TSF = 0x%016llx\n"
+ " TxMCS = %2d TxTpt = %4d\n"
+ " SQI = %4d\n"
+ " Status = 0x%08x %s\n"
+ " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
+ " Goodput(rx:tx) %4d:%4d\n"
+ "}\n",
+ i,
+ le64_to_cpu(reply.evt.tsf),
+ le16_to_cpu(reply.evt.bf_mcs),
+ le32_to_cpu(reply.evt.tx_tpt),
+ reply.evt.sqi,
+ status, wil_bfstatus_str(status),
+ le16_to_cpu(reply.evt.my_rx_sector),
+ le16_to_cpu(reply.evt.my_tx_sector),
+ le16_to_cpu(reply.evt.other_rx_sector),
+ le16_to_cpu(reply.evt.other_tx_sector),
+ le32_to_cpu(reply.evt.rx_goodput),
+ le32_to_cpu(reply.evt.tx_goodput));
+ }
return 0;
}
@@ -690,6 +829,7 @@ static const struct file_operations fops_bf = {
.read = seq_read,
.llseek = seq_lseek,
};
+
/*---------SSID------------*/
static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
@@ -752,10 +892,10 @@ static int wil_temp_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
u32 t_m, t_r;
-
int rc = wmi_get_temperature(wil, &t_m, &t_r);
+
if (rc) {
- seq_printf(s, "Failed\n");
+ seq_puts(s, "Failed\n");
return 0;
}
@@ -811,6 +951,7 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
+
switch (p->status) {
case wil_sta_unused:
status = "unused ";
@@ -871,7 +1012,6 @@ static int wil_info_debugfs_show(struct seq_file *s, void *data)
rxf_old = rxf;
txf_old = txf;
-
#define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
" " __stringify(x) : ""
@@ -906,6 +1046,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
{
int i;
u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
+
seq_printf(s, "0x%03x [", r->head_seq_num);
for (i = 0; i < r->buf_size; i++) {
if (i == index)
@@ -920,10 +1061,12 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
int i, tid;
+ unsigned long flags;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
+
switch (p->status) {
case wil_sta_unused:
status = "unused ";
@@ -939,13 +1082,16 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
(p->data_port_open ? " data_port_open" : ""));
if (p->status == wil_sta_connected) {
+ spin_lock_irqsave(&p->tid_rx_lock, flags);
for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
+
if (r) {
seq_printf(s, "[%2d] ", tid);
wil_print_rxtid(s, r);
}
}
+ spin_unlock_irqrestore(&p->tid_rx_lock, flags);
}
}
@@ -985,6 +1131,87 @@ static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
}
}
+/* misc files */
+static const struct {
+ const char *name;
+ umode_t mode;
+ const struct file_operations *fops;
+} dbg_files[] = {
+ {"mbox", S_IRUGO, &fops_mbox},
+ {"vrings", S_IRUGO, &fops_vring},
+ {"stations", S_IRUGO, &fops_sta},
+ {"desc", S_IRUGO, &fops_txdesc},
+ {"bf", S_IRUGO, &fops_bf},
+ {"ssid", S_IRUGO | S_IWUSR, &fops_ssid},
+ {"mem_val", S_IRUGO, &fops_memread},
+ {"reset", S_IWUSR, &fops_reset},
+ {"rxon", S_IWUSR, &fops_rxon},
+ {"tx_mgmt", S_IWUSR, &fops_txmgmt},
+ {"wmi_send", S_IWUSR, &fops_wmi},
+ {"temp", S_IRUGO, &fops_temp},
+ {"freq", S_IRUGO, &fops_freq},
+ {"link", S_IRUGO, &fops_link},
+ {"info", S_IRUGO, &fops_info},
+};
+
+static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
+ struct dentry *dbg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
+ debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
+ wil, dbg_files[i].fops);
+}
+
+/* interrupt control blocks */
+static const struct {
+ const char *name;
+ u32 icr_off;
+} dbg_icr[] = {
+ {"USER_ICR", HOSTADDR(RGF_USER_USER_ICR)},
+ {"DMA_EP_TX_ICR", HOSTADDR(RGF_DMA_EP_TX_ICR)},
+ {"DMA_EP_RX_ICR", HOSTADDR(RGF_DMA_EP_RX_ICR)},
+ {"DMA_EP_MISC_ICR", HOSTADDR(RGF_DMA_EP_MISC_ICR)},
+};
+
+static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
+ struct dentry *dbg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
+ wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
+ dbg_icr[i].icr_off);
+}
+
+#define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
+ offsetof(struct wil6210_priv, name), type}
+
+/* fields in struct wil6210_priv */
+static const struct dbg_off dbg_wil_off[] = {
+ WIL_FIELD(secure_pcp, S_IRUGO | S_IWUSR, doff_u32),
+ WIL_FIELD(status, S_IRUGO | S_IWUSR, doff_ulong),
+ WIL_FIELD(fw_version, S_IRUGO, doff_u32),
+ WIL_FIELD(hw_version, S_IRUGO, doff_x32),
+ {},
+};
+
+static const struct dbg_off dbg_wil_regs[] = {
+ {"RGF_MAC_MTRL_COUNTER_0", S_IRUGO, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
+ doff_io32},
+ {"RGF_USER_USAGE_1", S_IRUGO, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
+ {},
+};
+
+/* static parameters */
+static const struct dbg_off dbg_statics[] = {
+ {"desc_index", S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32},
+ {"vring_index", S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32},
+ {"mem_addr", S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32},
+ {},
+};
+
int wil6210_debugfs_init(struct wil6210_priv *wil)
{
struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
@@ -993,51 +1220,17 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
if (IS_ERR_OR_NULL(dbg))
return -ENODEV;
- debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);
- debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
- debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta);
- debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc);
- debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg,
- &dbg_txdesc_index);
- debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg,
- &dbg_vring_index);
-
- debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf);
- debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
- debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
- &wil->secure_pcp);
- wil_debugfs_create_ulong("status", S_IRUGO | S_IWUSR, dbg,
- &wil->status);
- debugfs_create_u32("fw_version", S_IRUGO, dbg, &wil->fw_version);
- debugfs_create_x32("hw_version", S_IRUGO, dbg, &wil->hw_version);
-
- wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg,
- HOSTADDR(RGF_USER_USER_ICR));
- wil6210_debugfs_create_ISR(wil, "DMA_EP_TX_ICR", dbg,
- HOSTADDR(RGF_DMA_EP_TX_ICR));
- wil6210_debugfs_create_ISR(wil, "DMA_EP_RX_ICR", dbg,
- HOSTADDR(RGF_DMA_EP_RX_ICR));
- wil6210_debugfs_create_ISR(wil, "DMA_EP_MISC_ICR", dbg,
- HOSTADDR(RGF_DMA_EP_MISC_ICR));
- wil6210_debugfs_create_pseudo_ISR(wil, dbg);
- wil6210_debugfs_create_ITR_CNT(wil, dbg);
+ wil6210_debugfs_init_files(wil, dbg);
+ wil6210_debugfs_init_isr(wil, dbg);
+ wil6210_debugfs_init_blobs(wil, dbg);
+ wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
+ wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
+ dbg_wil_regs);
+ wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
- wil_debugfs_create_iomem_x32("RGF_USER_USAGE_1", S_IRUGO, dbg,
- wil->csr +
- HOSTADDR(RGF_USER_USAGE_1));
- debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr);
- debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread);
-
- debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset);
- debugfs_create_file("rxon", S_IWUSR, dbg, wil, &fops_rxon);
- debugfs_create_file("tx_mgmt", S_IWUSR, dbg, wil, &fops_txmgmt);
- debugfs_create_file("wmi_send", S_IWUSR, dbg, wil, &fops_wmi);
- debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp);
- debugfs_create_file("freq", S_IRUGO, dbg, wil, &fops_freq);
- debugfs_create_file("link", S_IRUGO, dbg, wil, &fops_link);
- debugfs_create_file("info", S_IRUGO, dbg, wil, &fops_info);
+ wil6210_debugfs_create_pseudo_ISR(wil, dbg);
- wil6210_debugfs_init_blobs(wil, dbg);
+ wil6210_debugfs_create_ITR_CNT(wil, dbg);
return 0;
}
diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c
new file mode 100644
index 00000000000..8c6f3b041f7
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/fw.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/crc32.h>
+#include "wil6210.h"
+#include "fw.h"
+
+MODULE_FIRMWARE(WIL_FW_NAME);
+
+/* target operations */
+/* register read */
+#define R(a) ioread32(wil->csr + HOSTADDR(a))
+/* register write. wmb() to make sure it is completed */
+#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
+/* register set = read, OR, write */
+#define S(a, v) W(a, R(a) | v)
+/* register clear = read, AND with inverted, write */
+#define C(a, v) W(a, R(a) & ~v)
+
+static
+void wil_memset_toio_32(volatile void __iomem *dst, u32 val,
+ size_t count)
+{
+ volatile u32 __iomem *d = dst;
+
+ for (count += 4; count > 4; count -= 4)
+ __raw_writel(val, d++);
+}
+
+#include "fw_inc.c"
diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h
new file mode 100644
index 00000000000..7a2c6c129ad
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/fw.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define WIL_FW_SIGNATURE (0x36323130) /* '0126' */
+#define WIL_FW_FMT_VERSION (1) /* format version driver supports */
+
+enum wil_fw_record_type {
+ wil_fw_type_comment = 1,
+ wil_fw_type_data = 2,
+ wil_fw_type_fill = 3,
+ wil_fw_type_action = 4,
+ wil_fw_type_verify = 5,
+ wil_fw_type_file_header = 6,
+ wil_fw_type_direct_write = 7,
+ wil_fw_type_gateway_data = 8,
+ wil_fw_type_gateway_data4 = 9,
+};
+
+struct wil_fw_record_head {
+ __le16 type; /* enum wil_fw_record_type */
+ __le16 flags; /* to be defined */
+ __le32 size; /* whole record, bytes after head */
+} __packed;
+
+/* data block. write starting from @addr
+ * data_size inferred from the @head.size. For this case,
+ * data_size = @head.size - offsetof(struct wil_fw_record_data, data)
+ */
+struct wil_fw_record_data { /* type == wil_fw_type_data */
+ __le32 addr;
+ __le32 data[0]; /* [data_size], see above */
+} __packed;
+
+/* fill with constant @value, @size bytes starting from @addr */
+struct wil_fw_record_fill { /* type == wil_fw_type_fill */
+ __le32 addr;
+ __le32 value;
+ __le32 size;
+} __packed;
+
+/* free-form comment
+ * for informational purpose, data_size is @head.size from record header
+ */
+struct wil_fw_record_comment { /* type == wil_fw_type_comment */
+ u8 data[0]; /* free-form data [data_size], see above */
+} __packed;
+
+/* perform action
+ * data_size = @head.size - offsetof(struct wil_fw_record_action, data)
+ */
+struct wil_fw_record_action { /* type == wil_fw_type_action */
+ __le32 action; /* action to perform: reset, wait for fw ready etc. */
+ __le32 data[0]; /* action specific, [data_size], see above */
+} __packed;
+
+/* data block for struct wil_fw_record_direct_write */
+struct wil_fw_data_dwrite {
+ __le32 addr;
+ __le32 value;
+ __le32 mask;
+} __packed;
+
+/* write @value to the @addr,
+ * preserve original bits accordingly to the @mask
+ * data_size is @head.size where @head is record header
+ */
+struct wil_fw_record_direct_write { /* type == wil_fw_type_direct_write */
+ struct wil_fw_data_dwrite data[0];
+} __packed;
+
+/* verify condition: [@addr] & @mask == @value
+ * if condition not met, firmware download fails
+ */
+struct wil_fw_record_verify { /* type == wil_fw_verify */
+ __le32 addr; /* read from this address */
+ __le32 value; /* reference value */
+ __le32 mask; /* mask for verification */
+} __packed;
+
+/* file header
+ * First record of every file
+ */
+struct wil_fw_record_file_header {
+ __le32 signature ; /* Wilocity signature */
+ __le32 reserved;
+ __le32 crc; /* crc32 of the following data */
+ __le32 version; /* format version */
+ __le32 data_len; /* total data in file, including this record */
+ u8 comment[32]; /* short description */
+} __packed;
+
+/* 1-dword gateway */
+/* data block for the struct wil_fw_record_gateway_data */
+struct wil_fw_data_gw {
+ __le32 addr;
+ __le32 value;
+} __packed;
+
+/* gateway write block.
+ * write starting address and values from the data buffer
+ * through the gateway
+ * data_size inferred from the @head.size. For this case,
+ * data_size = @head.size - offsetof(struct wil_fw_record_gateway_data, data)
+ */
+struct wil_fw_record_gateway_data { /* type == wil_fw_type_gateway_data */
+ __le32 gateway_addr_addr;
+ __le32 gateway_value_addr;
+ __le32 gateway_cmd_addr;
+ __le32 gateway_ctrl_address;
+#define WIL_FW_GW_CTL_BUSY BIT(29) /* gateway busy performing operation */
+#define WIL_FW_GW_CTL_RUN BIT(30) /* start gateway operation */
+ __le32 command;
+ struct wil_fw_data_gw data[0]; /* total size [data_size], see above */
+} __packed;
+
+/* 4-dword gateway */
+/* data block for the struct wil_fw_record_gateway_data4 */
+struct wil_fw_data_gw4 {
+ __le32 addr;
+ __le32 value[4];
+} __packed;
+
+/* gateway write block.
+ * write starting address and values from the data buffer
+ * through the gateway
+ * data_size inferred from the @head.size. For this case,
+ * data_size = @head.size - offsetof(struct wil_fw_record_gateway_data4, data)
+ */
+struct wil_fw_record_gateway_data4 { /* type == wil_fw_type_gateway_data4 */
+ __le32 gateway_addr_addr;
+ __le32 gateway_value_addr[4];
+ __le32 gateway_cmd_addr;
+ __le32 gateway_ctrl_address; /* same logic as for 1-dword gw */
+ __le32 command;
+ struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */
+} __packed;
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
new file mode 100644
index 00000000000..44cb71f5ea5
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Algorithmic part of the firmware download.
+ * To be included in the container file providing framework
+ */
+
+#define wil_err_fw(wil, fmt, arg...) wil_err(wil, "ERR[ FW ]" fmt, ##arg)
+#define wil_dbg_fw(wil, fmt, arg...) wil_dbg(wil, "DBG[ FW ]" fmt, ##arg)
+#define wil_hex_dump_fw(prefix_str, prefix_type, rowsize, \
+ groupsize, buf, len, ascii) \
+ print_hex_dump_debug("DBG[ FW ]" prefix_str, \
+ prefix_type, rowsize, \
+ groupsize, buf, len, ascii)
+
+#define FW_ADDR_CHECK(ioaddr, val, msg) do { \
+ ioaddr = wmi_buffer(wil, val); \
+ if (!ioaddr) { \
+ wil_err_fw(wil, "bad " msg ": 0x%08x\n", \
+ le32_to_cpu(val)); \
+ return -EINVAL; \
+ } \
+ } while (0)
+
+/**
+ * wil_fw_verify - verify firmware file validity
+ *
+ * perform various checks for the firmware file header.
+ * records are not validated.
+ *
+ * Return file size or negative error
+ */
+static int wil_fw_verify(struct wil6210_priv *wil, const u8 *data, size_t size)
+{
+ const struct wil_fw_record_head *hdr = (const void *)data;
+ struct wil_fw_record_file_header fh;
+ const struct wil_fw_record_file_header *fh_;
+ u32 crc;
+ u32 dlen;
+
+ if (size % 4) {
+ wil_err_fw(wil, "image size not aligned: %zu\n", size);
+ return -EINVAL;
+ }
+ /* have enough data for the file header? */
+ if (size < sizeof(*hdr) + sizeof(fh)) {
+ wil_err_fw(wil, "file too short: %zu bytes\n", size);
+ return -EINVAL;
+ }
+
+ /* start with the file header? */
+ if (le16_to_cpu(hdr->type) != wil_fw_type_file_header) {
+ wil_err_fw(wil, "no file header\n");
+ return -EINVAL;
+ }
+
+ /* data_len */
+ fh_ = (struct wil_fw_record_file_header *)&hdr[1];
+ dlen = le32_to_cpu(fh_->data_len);
+ if (dlen % 4) {
+ wil_err_fw(wil, "data length not aligned: %lu\n", (ulong)dlen);
+ return -EINVAL;
+ }
+ if (size < dlen) {
+ wil_err_fw(wil, "file truncated at %zu/%lu\n",
+ size, (ulong)dlen);
+ return -EINVAL;
+ }
+ if (dlen < sizeof(*hdr) + sizeof(fh)) {
+ wil_err_fw(wil, "data length too short: %lu\n", (ulong)dlen);
+ return -EINVAL;
+ }
+
+ /* signature */
+ if (le32_to_cpu(fh_->signature) != WIL_FW_SIGNATURE) {
+ wil_err_fw(wil, "bad header signature: 0x%08x\n",
+ le32_to_cpu(fh_->signature));
+ return -EINVAL;
+ }
+
+ /* version */
+ if (le32_to_cpu(fh_->version) > WIL_FW_FMT_VERSION) {
+ wil_err_fw(wil, "unsupported header version: %d\n",
+ le32_to_cpu(fh_->version));
+ return -EINVAL;
+ }
+
+ /* checksum. ~crc32(~0, data, size) when fh.crc set to 0*/
+ fh = *fh_;
+ fh.crc = 0;
+
+ crc = crc32_le(~0, (unsigned char const *)hdr, sizeof(*hdr));
+ crc = crc32_le(crc, (unsigned char const *)&fh, sizeof(fh));
+ crc = crc32_le(crc, (unsigned char const *)&fh_[1],
+ dlen - sizeof(*hdr) - sizeof(fh));
+ crc = ~crc;
+
+ if (crc != le32_to_cpu(fh_->crc)) {
+ wil_err_fw(wil, "checksum mismatch:"
+ " calculated for %lu bytes 0x%08x != 0x%08x\n",
+ (ulong)dlen, crc, le32_to_cpu(fh_->crc));
+ return -EINVAL;
+ }
+
+ return (int)dlen;
+}
+
+static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, data, size, true);
+
+ return 0;
+}
+
+static int fw_handle_data(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ const struct wil_fw_record_data *d = data;
+ void __iomem *dst;
+ size_t s = size - sizeof(*d);
+
+ if (size < sizeof(*d) + sizeof(u32)) {
+ wil_err_fw(wil, "data record too short: %zu\n", size);
+ return -EINVAL;
+ }
+
+ FW_ADDR_CHECK(dst, d->addr, "address");
+ wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr),
+ s);
+ wil_memcpy_toio_32(dst, d->data, s);
+ wmb(); /* finish before processing next record */
+
+ return 0;
+}
+
+static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ const struct wil_fw_record_fill *d = data;
+ void __iomem *dst;
+ u32 v;
+ size_t s = (size_t)le32_to_cpu(d->size);
+
+ if (size != sizeof(*d)) {
+ wil_err_fw(wil, "bad size for fill record: %zu\n", size);
+ return -EINVAL;
+ }
+
+ if (s < sizeof(u32)) {
+ wil_err_fw(wil, "fill size too short: %zu\n", s);
+ return -EINVAL;
+ }
+
+ if (s % sizeof(u32)) {
+ wil_err_fw(wil, "fill size not aligned: %zu\n", s);
+ return -EINVAL;
+ }
+
+ FW_ADDR_CHECK(dst, d->addr, "address");
+
+ v = le32_to_cpu(d->value);
+ wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n",
+ le32_to_cpu(d->addr), v, s);
+ wil_memset_toio_32(dst, v, s);
+ wmb(); /* finish before processing next record */
+
+ return 0;
+}
+
+static int fw_handle_file_header(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ const struct wil_fw_record_file_header *d = data;
+
+ if (size != sizeof(*d)) {
+ wil_err_fw(wil, "file header length incorrect: %zu\n", size);
+ return -EINVAL;
+ }
+
+ wil_dbg_fw(wil, "new file, ver. %d, %i bytes\n",
+ d->version, d->data_len);
+ wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, d->comment,
+ sizeof(d->comment), true);
+
+ return 0;
+}
+
+static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ const struct wil_fw_record_direct_write *d = data;
+ const struct wil_fw_data_dwrite *block = d->data;
+ int n, i;
+
+ if (size % sizeof(*block)) {
+ wil_err_fw(wil, "record size not aligned on %zu: %zu\n",
+ sizeof(*block), size);
+ return -EINVAL;
+ }
+ n = size / sizeof(*block);
+
+ for (i = 0; i < n; i++) {
+ void __iomem *dst;
+ u32 m = le32_to_cpu(block[i].mask);
+ u32 v = le32_to_cpu(block[i].value);
+ u32 x, y;
+
+ FW_ADDR_CHECK(dst, block[i].addr, "address");
+
+ x = ioread32(dst);
+ y = (x & m) | (v & ~m);
+ wil_dbg_fw(wil, "write [0x%08x] <== 0x%08x "
+ "(old 0x%08x val 0x%08x mask 0x%08x)\n",
+ le32_to_cpu(block[i].addr), y, x, v, m);
+ iowrite32(y, dst);
+ wmb(); /* finish before processing next record */
+ }
+
+ return 0;
+}
+
+static int gw_write(struct wil6210_priv *wil, void __iomem *gwa_addr,
+ void __iomem *gwa_cmd, void __iomem *gwa_ctl, u32 gw_cmd,
+ u32 a)
+{
+ unsigned delay = 0;
+
+ iowrite32(a, gwa_addr);
+ iowrite32(gw_cmd, gwa_cmd);
+ wmb(); /* finish before activate gw */
+
+ iowrite32(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */
+ do {
+ udelay(1); /* typical time is few usec */
+ if (delay++ > 100) {
+ wil_err_fw(wil, "gw timeout\n");
+ return -EINVAL;
+ }
+ } while (ioread32(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */
+
+ return 0;
+}
+
+static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ const struct wil_fw_record_gateway_data *d = data;
+ const struct wil_fw_data_gw *block = d->data;
+ void __iomem *gwa_addr;
+ void __iomem *gwa_val;
+ void __iomem *gwa_cmd;
+ void __iomem *gwa_ctl;
+ u32 gw_cmd;
+ int n, i;
+
+ if (size < sizeof(*d) + sizeof(*block)) {
+ wil_err_fw(wil, "gateway record too short: %zu\n", size);
+ return -EINVAL;
+ }
+
+ if ((size - sizeof(*d)) % sizeof(*block)) {
+ wil_err_fw(wil, "gateway record data size"
+ " not aligned on %zu: %zu\n",
+ sizeof(*block), size - sizeof(*d));
+ return -EINVAL;
+ }
+ n = (size - sizeof(*d)) / sizeof(*block);
+
+ gw_cmd = le32_to_cpu(d->command);
+
+ wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n",
+ n, gw_cmd);
+
+ FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
+ FW_ADDR_CHECK(gwa_val, d->gateway_value_addr, "gateway_value_addr");
+ FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
+ FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
+
+ wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x"
+ " cmd 0x%08x ctl 0x%08x\n",
+ le32_to_cpu(d->gateway_addr_addr),
+ le32_to_cpu(d->gateway_value_addr),
+ le32_to_cpu(d->gateway_cmd_addr),
+ le32_to_cpu(d->gateway_ctrl_address));
+
+ for (i = 0; i < n; i++) {
+ int rc;
+ u32 a = le32_to_cpu(block[i].addr);
+ u32 v = le32_to_cpu(block[i].value);
+
+ wil_dbg_fw(wil, " gw write[%3d] [0x%08x] <== 0x%08x\n",
+ i, a, v);
+
+ iowrite32(v, gwa_val);
+ rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ const struct wil_fw_record_gateway_data4 *d = data;
+ const struct wil_fw_data_gw4 *block = d->data;
+ void __iomem *gwa_addr;
+ void __iomem *gwa_val[ARRAY_SIZE(block->value)];
+ void __iomem *gwa_cmd;
+ void __iomem *gwa_ctl;
+ u32 gw_cmd;
+ int n, i, k;
+
+ if (size < sizeof(*d) + sizeof(*block)) {
+ wil_err_fw(wil, "gateway4 record too short: %zu\n", size);
+ return -EINVAL;
+ }
+
+ if ((size - sizeof(*d)) % sizeof(*block)) {
+ wil_err_fw(wil, "gateway4 record data size"
+ " not aligned on %zu: %zu\n",
+ sizeof(*block), size - sizeof(*d));
+ return -EINVAL;
+ }
+ n = (size - sizeof(*d)) / sizeof(*block);
+
+ gw_cmd = le32_to_cpu(d->command);
+
+ wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n",
+ n, gw_cmd);
+
+ FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
+ for (k = 0; k < ARRAY_SIZE(block->value); k++)
+ FW_ADDR_CHECK(gwa_val[k], d->gateway_value_addr[k],
+ "gateway_value_addr");
+ FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
+ FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
+
+ wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n",
+ le32_to_cpu(d->gateway_addr_addr),
+ le32_to_cpu(d->gateway_cmd_addr),
+ le32_to_cpu(d->gateway_ctrl_address));
+ wil_hex_dump_fw("val addresses: ", DUMP_PREFIX_NONE, 16, 4,
+ d->gateway_value_addr, sizeof(d->gateway_value_addr),
+ false);
+
+ for (i = 0; i < n; i++) {
+ int rc;
+ u32 a = le32_to_cpu(block[i].addr);
+ u32 v[ARRAY_SIZE(block->value)];
+
+ for (k = 0; k < ARRAY_SIZE(block->value); k++)
+ v[k] = le32_to_cpu(block[i].value[k]);
+
+ wil_dbg_fw(wil, " gw4 write[%3d] [0x%08x] <==\n", i, a);
+ wil_hex_dump_fw(" val ", DUMP_PREFIX_NONE, 16, 4, v,
+ sizeof(v), false);
+
+ for (k = 0; k < ARRAY_SIZE(block->value); k++)
+ iowrite32(v[k], gwa_val[k]);
+ rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static const struct {
+ int type;
+ int (*handler)(struct wil6210_priv *wil, const void *data, size_t size);
+} wil_fw_handlers[] = {
+ {wil_fw_type_comment, fw_handle_comment},
+ {wil_fw_type_data, fw_handle_data},
+ {wil_fw_type_fill, fw_handle_fill},
+ /* wil_fw_type_action */
+ /* wil_fw_type_verify */
+ {wil_fw_type_file_header, fw_handle_file_header},
+ {wil_fw_type_direct_write, fw_handle_direct_write},
+ {wil_fw_type_gateway_data, fw_handle_gateway_data},
+ {wil_fw_type_gateway_data4, fw_handle_gateway_data4},
+};
+
+static int wil_fw_handle_record(struct wil6210_priv *wil, int type,
+ const void *data, size_t size)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wil_fw_handlers); i++) {
+ if (wil_fw_handlers[i].type == type)
+ return wil_fw_handlers[i].handler(wil, data, size);
+ }
+
+ wil_err_fw(wil, "unknown record type: %d\n", type);
+ return -EINVAL;
+}
+
+/**
+ * wil_fw_load - load FW into device
+ *
+ * Load the FW and uCode code and data to the corresponding device
+ * memory regions
+ *
+ * Return error code
+ */
+static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size)
+{
+ int rc = 0;
+ const struct wil_fw_record_head *hdr;
+ size_t s, hdr_sz;
+
+ for (hdr = data;; hdr = (const void *)hdr + s, size -= s) {
+ if (size < sizeof(*hdr))
+ break;
+ hdr_sz = le32_to_cpu(hdr->size);
+ s = sizeof(*hdr) + hdr_sz;
+ if (s > size)
+ break;
+ if (hdr_sz % 4) {
+ wil_err_fw(wil, "unaligned record size: %zu\n",
+ hdr_sz);
+ return -EINVAL;
+ }
+ rc = wil_fw_handle_record(wil, le16_to_cpu(hdr->type),
+ &hdr[1], hdr_sz);
+ if (rc)
+ return rc;
+ }
+ if (size) {
+ wil_err_fw(wil, "unprocessed bytes: %zu\n", size);
+ if (size >= sizeof(*hdr)) {
+ wil_err_fw(wil, "Stop at offset %ld"
+ " record type %d [%zd bytes]\n",
+ (const void *)hdr - data,
+ le16_to_cpu(hdr->type), hdr_sz);
+ }
+ return -EINVAL;
+ }
+ /* Mark FW as loaded from host */
+ S(RGF_USER_USAGE_6, 1);
+
+ return rc;
+}
+
+/**
+ * wil_request_firmware - Request firmware and load to device
+ *
+ * Request firmware image from the file and load it to device
+ *
+ * Return error code
+ */
+int wil_request_firmware(struct wil6210_priv *wil, const char *name)
+{
+ int rc, rc1;
+ const struct firmware *fw;
+ size_t sz;
+ const void *d;
+
+ rc = request_firmware(&fw, name, wil_to_pcie_dev(wil));
+ if (rc) {
+ wil_err_fw(wil, "Failed to load firmware %s\n", name);
+ return rc;
+ }
+ wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size);
+
+ for (sz = fw->size, d = fw->data; sz; sz -= rc1, d += rc1) {
+ rc1 = wil_fw_verify(wil, d, sz);
+ if (rc1 < 0) {
+ rc = rc1;
+ goto out;
+ }
+ rc = wil_fw_load(wil, d, rc1);
+ if (rc < 0)
+ goto out;
+ }
+
+out:
+ release_firmware(fw);
+ return rc;
+}
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 67f1002a03a..7269bac111b 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -135,7 +135,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
}
-void wil6210_disable_irq(struct wil6210_priv *wil)
+void wil_mask_irq(struct wil6210_priv *wil)
{
wil_dbg_irq(wil, "%s()\n", __func__);
@@ -145,7 +145,7 @@ void wil6210_disable_irq(struct wil6210_priv *wil)
wil6210_mask_irq_pseudo(wil);
}
-void wil6210_enable_irq(struct wil6210_priv *wil)
+void wil_unmask_irq(struct wil6210_priv *wil)
{
wil_dbg_irq(wil, "%s()\n", __func__);
@@ -196,8 +196,13 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
wil_dbg_irq(wil, "RX done\n");
isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
if (test_bit(wil_status_reset_done, &wil->status)) {
- wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
- napi_schedule(&wil->napi_rx);
+ if (test_bit(wil_status_napi_en, &wil->status)) {
+ wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
+ napi_schedule(&wil->napi_rx);
+ } else {
+ wil_err(wil, "Got Rx interrupt while "
+ "stopping interface\n");
+ }
} else {
wil_err(wil, "Got Rx interrupt while in reset\n");
}
@@ -506,7 +511,8 @@ free0:
return rc;
}
-/* can't use wil_ioread32_and_clear because ICC value is not ser yet */
+
+/* can't use wil_ioread32_and_clear because ICC value is not set yet */
static inline void wil_clear32(void __iomem *addr)
{
u32 x = ioread32(addr);
@@ -522,11 +528,15 @@ void wil6210_clear_irq(struct wil6210_priv *wil)
offsetof(struct RGF_ICR, ICR));
wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
offsetof(struct RGF_ICR, ICR));
+ wmb(); /* make sure write completed */
}
int wil6210_init_irq(struct wil6210_priv *wil, int irq)
{
int rc;
+
+ wil_dbg_misc(wil, "%s() n_msi=%d\n", __func__, wil->n_msi);
+
if (wil->n_msi == 3)
rc = wil6210_request_3msi(wil, irq);
else
@@ -534,17 +544,14 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq)
wil6210_thread_irq,
wil->n_msi ? 0 : IRQF_SHARED,
WIL_NAME, wil);
- if (rc)
- return rc;
-
- wil6210_enable_irq(wil);
-
- return 0;
+ return rc;
}
void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
{
- wil6210_disable_irq(wil);
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
+ wil_mask_irq(wil);
free_irq(irq, wil);
if (wil->n_msi == 3) {
free_irq(irq + 1, wil);
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 3704d2a434f..21667e0c3d1 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -20,11 +20,22 @@
#include "wil6210.h"
#include "txrx.h"
+#include "wmi.h"
+
+#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
+#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
static bool no_fw_recovery;
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery");
+static bool no_fw_load = true;
+module_param(no_fw_load, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash.");
+
+#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 */
+
/*
* Due to a hardware issue,
* one has to read/write to/from NIC in 32-bit chunks;
@@ -64,6 +75,7 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
struct wil_sta_info *sta = &wil->sta[cid];
+
wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
sta->status);
@@ -83,9 +95,16 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
}
for (i = 0; i < WIL_STA_TID_NUM; i++) {
- struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
+ struct wil_tid_ampdu_rx *r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sta->tid_rx_lock, flags);
+
+ r = sta->tid_rx[i];
sta->tid_rx[i] = NULL;
wil_tid_ampdu_rx_free(wil, r);
+
+ spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
}
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
if (wil->vring2cid_tid[i][0] == cid)
@@ -202,10 +221,8 @@ static void wil_fw_error_worker(struct work_struct *work)
case NL80211_IFTYPE_MONITOR:
wil_info(wil, "fw error recovery started (try %d)...\n",
wil->recovery_count);
- wil_reset(wil);
-
- /* need to re-allocate Rx ring after reset */
- wil_rx_init(wil);
+ __wil_down(wil);
+ __wil_up(wil);
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
@@ -220,6 +237,7 @@ static void wil_fw_error_worker(struct work_struct *work)
static int wil_find_free_vring(struct wil6210_priv *wil)
{
int i;
+
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
if (!wil->vring_tx[i].va)
return i;
@@ -254,14 +272,19 @@ static void wil_connect_worker(struct work_struct *work)
int wil_priv_init(struct wil6210_priv *wil)
{
+ uint i;
+
wil_dbg_misc(wil, "%s()\n", __func__);
memset(wil->sta, 0, sizeof(wil->sta));
+ for (i = 0; i < WIL6210_MAX_CID; i++)
+ spin_lock_init(&wil->sta[i].tid_rx_lock);
mutex_init(&wil->mutex);
mutex_init(&wil->wmi_mutex);
init_completion(&wil->wmi_ready);
+ init_completion(&wil->wmi_call);
wil->pending_connect_cid = -1;
setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
@@ -292,12 +315,16 @@ int wil_priv_init(struct wil6210_priv *wil)
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
{
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
del_timer_sync(&wil->connect_timer);
_wil6210_disconnect(wil, bssid);
}
void wil_priv_deinit(struct wil6210_priv *wil)
{
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
del_timer_sync(&wil->scan_timer);
cancel_work_sync(&wil->disconnect_worker);
cancel_work_sync(&wil->fw_error_worker);
@@ -309,7 +336,29 @@ void wil_priv_deinit(struct wil6210_priv *wil)
destroy_workqueue(wil->wmi_wq);
}
-static void wil_target_reset(struct wil6210_priv *wil)
+/* target operations */
+/* register read */
+#define R(a) ioread32(wil->csr + HOSTADDR(a))
+/* register write. wmb() to make sure it is completed */
+#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
+/* register set = read, OR, write */
+#define S(a, v) W(a, R(a) | v)
+/* register clear = read, AND with inverted, write */
+#define C(a, v) W(a, R(a) & ~v)
+
+static inline void wil_halt_cpu(struct wil6210_priv *wil)
+{
+ W(RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
+ W(RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST);
+}
+
+static inline void wil_release_cpu(struct wil6210_priv *wil)
+{
+ /* Start CPU */
+ W(RGF_USER_USER_CPU_0, 1);
+}
+
+static int wil_target_reset(struct wil6210_priv *wil)
{
int delay = 0;
u32 hw_state;
@@ -318,57 +367,41 @@ static void wil_target_reset(struct wil6210_priv *wil)
wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name);
- /* register read */
-#define R(a) ioread32(wil->csr + HOSTADDR(a))
- /* register write */
-#define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a))
- /* register set = read, OR, write */
-#define S(a, v) W(a, R(a) | v)
- /* register clear = read, AND with inverted, write */
-#define C(a, v) W(a, R(a) & ~v)
-
wil->hw_version = R(RGF_USER_FW_REV_ID);
rev_id = wil->hw_version & 0xff;
/* Clear MAC link up */
S(RGF_HP_CTRL, BIT(15));
- /* hpal_perst_from_pad_src_n_mask */
- S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6));
- /* car_perst_rst_src_n_mask */
- S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7));
- wmb(); /* order is important here */
+ S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD);
+ S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
+
+ wil_halt_cpu(wil);
+ C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); /* 40 MHz */
if (is_sparrow) {
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
- wmb(); /* order is important here */
+ W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
}
- W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */
- W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
- wmb(); /* order is important here */
-
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000B0 : 0x00000170);
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00);
- wmb(); /* order is important here */
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170);
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
if (is_sparrow) {
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
- wmb(); /* order is important here */
+ W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
}
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
- wmb(); /* order is important here */
if (is_sparrow) {
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
/* reset A2 PCIE AHB */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
-
} else {
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
if (rev_id == 1) {
@@ -378,21 +411,19 @@ static void wil_target_reset(struct wil6210_priv *wil)
W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
}
-
}
/* TODO: check order here!!! Erez code is different */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
- wmb(); /* order is important here */
- /* wait until device ready */
+ /* wait until device ready. typical time is 200..250 msec */
do {
- msleep(1);
+ msleep(RST_DELAY);
hw_state = R(RGF_USER_HW_MACHINE_STATE);
- if (delay++ > 100) {
+ if (delay++ > RST_COUNT) {
wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
hw_state);
- return;
+ return -ETIME;
}
} while (hw_state != HW_MACHINE_BOOT_DONE);
@@ -401,15 +432,15 @@ static void wil_target_reset(struct wil6210_priv *wil)
W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
- wmb(); /* order is important here */
- wil_dbg_misc(wil, "Reset completed in %d ms\n", delay);
+ wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
+ return 0;
+}
#undef R
#undef W
#undef S
#undef C
-}
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
{
@@ -424,6 +455,7 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
{
ulong to = msecs_to_jiffies(1000);
ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
+
if (0 == left) {
wil_err(wil, "Firmware not ready\n");
return -ETIME;
@@ -443,15 +475,15 @@ int wil_reset(struct wil6210_priv *wil)
{
int rc;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
WARN_ON(!mutex_is_locked(&wil->mutex));
+ WARN_ON(test_bit(wil_status_napi_en, &wil->status));
cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL);
wil->status = 0; /* prevent NAPI from being scheduled */
- if (test_bit(wil_status_napi_en, &wil->status)) {
- napi_synchronize(&wil->napi_rx);
- }
if (wil->scan_request) {
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
@@ -461,24 +493,50 @@ int wil_reset(struct wil6210_priv *wil)
wil->scan_request = NULL;
}
- wil6210_disable_irq(wil);
+ wil_mask_irq(wil);
wmi_event_flush(wil);
flush_workqueue(wil->wmi_wq_conn);
flush_workqueue(wil->wmi_wq);
- /* TODO: put MAC in reset */
- wil_target_reset(wil);
-
+ rc = wil_target_reset(wil);
wil_rx_fini(wil);
+ if (rc)
+ return rc;
+
+ if (!no_fw_load) {
+ wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME);
+ wil_halt_cpu(wil);
+ /* Loading f/w from the file */
+ rc = wil_request_firmware(wil, WIL_FW_NAME);
+ if (rc)
+ return rc;
+
+ /* clear any interrupts which on-card-firmware may have set */
+ wil6210_clear_irq(wil);
+ { /* CAF_ICR - clear and mask */
+ u32 a = HOSTADDR(RGF_CAF_ICR) +
+ offsetof(struct RGF_ICR, ICR);
+ u32 m = HOSTADDR(RGF_CAF_ICR) +
+ offsetof(struct RGF_ICR, IMV);
+ u32 icr = ioread32(wil->csr + a);
+
+ iowrite32(icr, wil->csr + a); /* W1C */
+ iowrite32(~0, wil->csr + m);
+ wmb(); /* wait for completion */
+ }
+ wil_release_cpu(wil);
+ } else {
+ wil_info(wil, "Use firmware from on-card flash\n");
+ }
/* init after reset */
wil->pending_connect_cid = -1;
reinit_completion(&wil->wmi_ready);
+ reinit_completion(&wil->wmi_call);
- /* TODO: release MAC reset */
- wil6210_enable_irq(wil);
+ wil_unmask_irq(wil);
/* we just started MAC, wait for FW ready */
rc = wil_wait_for_fw_ready(wil);
@@ -514,7 +572,7 @@ void wil_link_off(struct wil6210_priv *wil)
netif_carrier_off(ndev);
}
-static int __wil_up(struct wil6210_priv *wil)
+int __wil_up(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
@@ -560,11 +618,15 @@ static int __wil_up(struct wil6210_priv *wil)
/* MAC address - pre-requisite for other commands */
wmi_set_mac_address(wil, ndev->dev_addr);
-
+ wil_dbg_misc(wil, "NAPI enable\n");
napi_enable(&wil->napi_rx);
napi_enable(&wil->napi_tx);
set_bit(wil_status_napi_en, &wil->status);
+ if (wil->platform_ops.bus_request)
+ wil->platform_ops.bus_request(wil->platform_handle,
+ WIL_MAX_BUS_REQUEST_KBPS);
+
return 0;
}
@@ -572,6 +634,8 @@ int wil_up(struct wil6210_priv *wil)
{
int rc;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
mutex_lock(&wil->mutex);
rc = __wil_up(wil);
mutex_unlock(&wil->mutex);
@@ -579,13 +643,23 @@ int wil_up(struct wil6210_priv *wil)
return rc;
}
-static int __wil_down(struct wil6210_priv *wil)
+int __wil_down(struct wil6210_priv *wil)
{
+ int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
+ WAIT_FOR_DISCONNECT_INTERVAL_MS;
+
WARN_ON(!mutex_is_locked(&wil->mutex));
- clear_bit(wil_status_napi_en, &wil->status);
- napi_disable(&wil->napi_rx);
- napi_disable(&wil->napi_tx);
+ if (wil->platform_ops.bus_request)
+ wil->platform_ops.bus_request(wil->platform_handle, 0);
+
+ wil_disable_irq(wil);
+ if (test_and_clear_bit(wil_status_napi_en, &wil->status)) {
+ napi_disable(&wil->napi_rx);
+ napi_disable(&wil->napi_tx);
+ wil_dbg_misc(wil, "NAPI disable\n");
+ }
+ wil_enable_irq(wil);
if (wil->scan_request) {
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
@@ -595,7 +669,24 @@ static int __wil_down(struct wil6210_priv *wil)
wil->scan_request = NULL;
}
- wil6210_disconnect(wil, NULL);
+ if (test_bit(wil_status_fwconnected, &wil->status) ||
+ test_bit(wil_status_fwconnecting, &wil->status))
+ wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
+
+ /* make sure wil is idle (not connected) */
+ mutex_unlock(&wil->mutex);
+ while (iter--) {
+ int idle = !test_bit(wil_status_fwconnected, &wil->status) &&
+ !test_bit(wil_status_fwconnecting, &wil->status);
+ if (idle)
+ break;
+ msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS);
+ }
+ mutex_lock(&wil->mutex);
+
+ if (!iter)
+ wil_err(wil, "timeout waiting for idle FW/HW\n");
+
wil_rx_fini(wil);
return 0;
@@ -605,6 +696,8 @@ int wil_down(struct wil6210_priv *wil)
{
int rc;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
mutex_lock(&wil->mutex);
rc = __wil_down(wil);
mutex_unlock(&wil->mutex);
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 7afce6e8c50..1c0c77d9a14 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,11 +17,14 @@
#include <linux/etherdevice.h>
#include "wil6210.h"
+#include "txrx.h"
static int wil_open(struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
return wil_up(wil);
}
@@ -29,6 +32,8 @@ static int wil_stop(struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
return wil_down(wil);
}
@@ -36,8 +41,10 @@ static int wil_change_mtu(struct net_device *ndev, int new_mtu)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
- if (new_mtu < 68 || new_mtu > IEEE80211_MAX_DATA_LEN_DMG)
+ if (new_mtu < 68 || new_mtu > (TX_BUF_LEN - ETH_HLEN)) {
+ wil_err(wil, "invalid MTU %d\n", new_mtu);
return -EINVAL;
+ }
wil_dbg_misc(wil, "change MTU %d -> %d\n", ndev->mtu, new_mtu);
ndev->mtu = new_mtu;
@@ -121,6 +128,8 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
wil->csr = csr;
wil->wdev = wdev;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
rc = wil_priv_init(wil);
if (rc) {
dev_err(dev, "wil_priv_init failed\n");
@@ -168,11 +177,17 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
void wil_if_free(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
+
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
if (!ndev)
return;
- free_netdev(ndev);
wil_priv_deinit(wil);
+
+ wil_to_ndev(wil) = NULL;
+ free_netdev(ndev);
+
wil_wdev_free(wil);
}
@@ -181,6 +196,8 @@ int wil_if_add(struct wil6210_priv *wil)
struct net_device *ndev = wil_to_ndev(wil);
int rc;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
rc = register_netdev(ndev);
if (rc < 0) {
dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
@@ -196,5 +213,7 @@ void wil_if_remove(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
unregister_netdev(ndev);
}
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index d3fbfa28db6..66626a8ee72 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
#include "wil6210.h"
@@ -30,6 +31,28 @@ 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");
+void wil_disable_irq(struct wil6210_priv *wil)
+{
+ int irq = wil->pdev->irq;
+
+ disable_irq(irq);
+ if (wil->n_msi == 3) {
+ disable_irq(irq + 1);
+ disable_irq(irq + 2);
+ }
+}
+
+void wil_enable_irq(struct wil6210_priv *wil)
+{
+ int irq = wil->pdev->irq;
+
+ enable_irq(irq);
+ if (wil->n_msi == 3) {
+ enable_irq(irq + 1);
+ enable_irq(irq + 2);
+ }
+}
+
/* Bus ops */
static int wil_if_pcie_enable(struct wil6210_priv *wil)
{
@@ -41,6 +64,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
*/
int msi_only = pdev->msi_enabled;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
pdev->msi_enabled = 0;
pci_set_master(pdev);
@@ -107,6 +132,8 @@ static int wil_if_pcie_disable(struct wil6210_priv *wil)
{
struct pci_dev *pdev = wil->pdev;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
pci_clear_master(pdev);
/* disable and release IRQ */
wil6210_fini_irq(wil, pdev->irq);
@@ -180,6 +207,10 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
wil->board = board;
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) {
@@ -204,6 +235,8 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
bus_disable:
wil_if_pcie_disable(wil);
if_free:
+ if (wil->platform_ops.uninit)
+ wil->platform_ops.uninit(wil->platform_handle);
wil_if_free(wil);
err_iounmap:
pci_iounmap(pdev, csr);
@@ -218,12 +251,17 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
static void wil_pcie_remove(struct pci_dev *pdev)
{
struct wil6210_priv *wil = pci_get_drvdata(pdev);
+ void __iomem *csr = wil->csr;
+
+ wil_dbg_misc(wil, "%s()\n", __func__);
wil6210_debugfs_remove(wil);
- wil_if_pcie_disable(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, wil->csr);
+ pci_iounmap(pdev, csr);
pci_release_region(pdev, 0);
pci_disable_device(pdev);
}
@@ -243,6 +281,8 @@ static const struct pci_device_id wil6210_pcie_ids[] = {
.driver_data = (kernel_ulong_t)&wil_board_marlon },
{ PCI_DEVICE(0x1ae9, 0x0310),
.driver_data = (kernel_ulong_t)&wil_board_sparrow },
+ { PCI_DEVICE(0x1ae9, 0x0302), /* same as above, firmware broken */
+ .driver_data = (kernel_ulong_t)&wil_board_sparrow },
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 180ca479390..489cb73d139 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -1,3 +1,19 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
#include "wil6210.h"
#include "txrx.h"
@@ -82,22 +98,25 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
int mid = wil_rxdesc_mid(d);
u16 seq = wil_rxdesc_seq(d);
struct wil_sta_info *sta = &wil->sta[cid];
- struct wil_tid_ampdu_rx *r = sta->tid_rx[tid];
+ struct wil_tid_ampdu_rx *r;
u16 hseq;
int index;
+ unsigned long flags;
wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n",
mid, cid, tid, seq);
+ spin_lock_irqsave(&sta->tid_rx_lock, flags);
+
+ r = sta->tid_rx[tid];
if (!r) {
+ spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
wil_netif_rx_any(skb, ndev);
return;
}
hseq = r->head_seq_num;
- spin_lock(&r->reorder_lock);
-
/** Due to the race between WMI events, where BACK establishment
* reported, and data Rx, few packets may be pass up before reorder
* buffer get allocated. Catch up by pretending SSN is what we
@@ -160,13 +179,14 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
wil_reorder_release(wil, r);
out:
- spin_unlock(&r->reorder_lock);
+ spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
}
struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
int size, u16 ssn)
{
struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL);
+
if (!r)
return NULL;
@@ -181,7 +201,6 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
return NULL;
}
- spin_lock_init(&r->reorder_lock);
r->ssn = ssn;
r->head_seq_num = ssn;
r->buf_size = size;
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index d3467943d39..2936ef0c18c 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -52,6 +52,7 @@ static inline int wil_vring_is_full(struct vring *vring)
{
return wil_vring_next_tail(vring) == vring->swhead;
}
+
/*
* Available space in Tx Vring
*/
@@ -86,6 +87,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
size_t sz = vring->size * sizeof(vring->va[0]);
uint i;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
BUILD_BUG_ON(sizeof(vring->va[0]) != 32);
vring->swhead = 0;
@@ -110,7 +113,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
* we can use any
*/
for (i = 0; i < vring->size; i++) {
- volatile struct vring_tx_desc *_d = &(vring->va[i].tx);
+ volatile struct vring_tx_desc *_d = &vring->va[i].tx;
+
_d->dma.status = TX_DMA_STATUS_DU;
}
@@ -125,6 +129,7 @@ static void wil_txdesc_unmap(struct device *dev, struct vring_tx_desc *d,
{
dma_addr_t pa = wil_desc_addr(&d->dma.addr);
u16 dmalen = le16_to_cpu(d->dma.length);
+
switch (ctx->mapped_as) {
case wil_mapped_as_single:
dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
@@ -143,6 +148,18 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
struct device *dev = wil_to_dev(wil);
size_t sz = vring->size * sizeof(vring->va[0]);
+ if (tx) {
+ int vring_index = vring - wil->vring_tx;
+
+ wil_dbg_misc(wil, "free Tx vring %d [%d] 0x%p:%pad 0x%p\n",
+ vring_index, vring->size, vring->va,
+ &vring->pa, vring->ctx);
+ } else {
+ wil_dbg_misc(wil, "free Rx vring [%d] 0x%p:%pad 0x%p\n",
+ vring->size, vring->va,
+ &vring->pa, vring->ctx);
+ }
+
while (!wil_vring_is_empty(vring)) {
dma_addr_t pa;
u16 dmalen;
@@ -191,11 +208,12 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
struct device *dev = wil_to_dev(wil);
unsigned int sz = RX_BUF_LEN;
struct vring_rx_desc dd, *d = &dd;
- volatile struct vring_rx_desc *_d = &(vring->va[i].rx);
+ volatile struct vring_rx_desc *_d = &vring->va[i].rx;
dma_addr_t pa;
/* TODO align */
struct sk_buff *skb = dev_alloc_skb(sz + headroom);
+
if (unlikely(!skb))
return -ENOMEM;
@@ -274,9 +292,11 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
*/
int len = min_t(int, 8 + sizeof(phy_data),
wil_rxdesc_phy_length(d));
+
if (len > 8) {
void *p = skb_tail_pointer(skb);
void *pa = PTR_ALIGN(p, 8);
+
if (skb_tailroom(skb) >= len + (pa - p)) {
phy_length = len - 8;
memcpy(phy_data, pa, phy_length);
@@ -372,13 +392,12 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
int cid;
struct wil_net_stats *stats;
-
BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb));
if (wil_vring_is_empty(vring))
return NULL;
- _d = &(vring->va[vring->swhead].rx);
+ _d = &vring->va[vring->swhead].rx;
if (!(_d->dma.status & RX_DMA_STATUS_DU)) {
/* it is not error, we just reached end of Rx done area */
return NULL;
@@ -414,7 +433,6 @@ 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);
- wil->stats.last_mcs_rx = stats->last_mcs_rx;
/* use radiotap header only if required */
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
@@ -533,7 +551,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
[GRO_NORMAL] = "GRO_NORMAL",
[GRO_DROP] = "GRO_DROP",
};
- wil_dbg_txrx(wil, "Rx complete %d bytes => %s,\n",
+ wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n",
len, gro_res_str[rc]);
}
}
@@ -574,7 +592,6 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
else
wil_netif_rx_any(skb, ndev);
}
-
}
wil_rx_refill(wil, v->size);
}
@@ -584,6 +601,8 @@ int wil_rx_init(struct wil6210_priv *wil)
struct vring *vring = &wil->vring_rx;
int rc;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
if (vring->va) {
wil_err(wil, "Rx ring already allocated\n");
return -EINVAL;
@@ -613,6 +632,8 @@ void wil_rx_fini(struct wil6210_priv *wil)
{
struct vring *vring = &wil->vring_rx;
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
if (vring->va)
wil_vring_free(wil, vring, 0);
}
@@ -647,6 +668,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
struct vring *vring = &wil->vring_tx[id];
struct vring_tx_data *txdata = &wil->vring_tx_data[id];
+ wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__,
+ cmd.vring_cfg.tx_sw_ring.max_mpdu_size);
+
if (vring->va) {
wil_err(wil, "Tx ring [%d] already allocated\n", id);
rc = -EINVAL;
@@ -696,6 +720,8 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
if (!vring->va)
return;
+ wil_dbg_misc(wil, "%s() id=%d\n", __func__, id);
+
/* make sure NAPI won't touch this vring */
wil->vring_tx_data[id].enabled = 0;
if (test_bit(wil_status_napi_en, &wil->status))
@@ -722,6 +748,7 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
if (wil->vring2cid_tid[i][0] == cid) {
struct vring *v = &wil->vring_tx[i];
+
wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
__func__, eth->h_dest, i);
if (v->va) {
@@ -741,6 +768,7 @@ static void wil_set_da_for_vring(struct wil6210_priv *wil,
{
struct ethhdr *eth = (void *)skb->data;
int cid = wil->vring2cid_tid[vring_index][0];
+
memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN);
}
@@ -751,7 +779,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
* duplicate skb and send it to other active vrings
*/
static struct vring *wil_tx_bcast(struct wil6210_priv *wil,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
struct vring *v, *v2;
struct sk_buff *skb2;
@@ -834,8 +862,8 @@ void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags)
}
static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,
- struct vring_tx_desc *d,
- struct sk_buff *skb)
+ struct vring_tx_desc *d,
+ struct sk_buff *skb)
{
int protocol;
@@ -903,10 +931,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
1 + nr_frags);
return -ENOMEM;
}
- _d = &(vring->va[i].tx);
+ _d = &vring->va[i].tx;
- pa = dma_map_single(dev, skb->data,
- skb_headlen(skb), DMA_TO_DEVICE);
+ pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb),
skb->data, &pa);
@@ -935,10 +962,11 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
const struct skb_frag_struct *frag =
&skb_shinfo(skb)->frags[f];
int len = skb_frag_size(frag);
+
i = (swhead + f + 1) % vring->size;
- _d = &(vring->va[i].tx);
+ _d = &vring->va[i].tx;
pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
- DMA_TO_DEVICE);
+ DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dev, pa)))
goto dma_error;
vring->ctx[i].mapped_as = wil_mapped_as_page;
@@ -983,7 +1011,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
i = (swhead + f) % vring->size;
ctx = &vring->ctx[i];
- _d = &(vring->va[i].tx);
+ _d = &vring->va[i].tx;
*d = *_d;
_d->dma.status = TX_DMA_STATUS_DU;
wil_txdesc_unmap(dev, d, ctx);
@@ -997,7 +1025,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
return -EINVAL;
}
-
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
@@ -1025,15 +1052,15 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
pr_once_fw = false;
/* find vring */
- if (is_unicast_ether_addr(eth->h_dest)) {
+ if (is_unicast_ether_addr(eth->h_dest))
vring = wil_find_tx_vring(wil, skb);
- } else {
+ else
vring = wil_tx_bcast(wil, skb);
- }
if (!vring) {
wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest);
goto drop;
}
+
/* set up vring entry */
rc = wil_tx_vring(wil, vring, skb);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index bc5706a4f00..de046716d2b 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -20,9 +20,9 @@
#define BUF_SW_OWNED (1)
#define BUF_HW_OWNED (0)
-/* size of max. Rx packet */
-#define RX_BUF_LEN (2048)
-#define TX_BUF_LEN (2048)
+/* size of max. Tx/Rx buffers, as supported by FW */
+#define RX_BUF_LEN (2242)
+#define TX_BUF_LEN (2242)
/* how many bytes to reserve for rtap header? */
#define WIL6210_RTAP_SIZE (128)
@@ -237,7 +237,6 @@ struct vring_tx_mac {
#define DMA_CFG_DESC_TX_0_L4_TYPE_LEN 2
#define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000 /* L4 type: 0-UDP, 2-TCP */
-
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_POS 0
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_LEN 7
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_MSK 0x7F /* MAC hdr len */
@@ -246,7 +245,6 @@ struct vring_tx_mac {
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_LEN 1
#define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_MSK 0x80 /* 1-IPv4, 0-IPv6 */
-
#define TX_DMA_STATUS_DU BIT(0)
struct vring_tx_dma {
@@ -347,7 +345,6 @@ struct vring_rx_mac {
#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)
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 67e9624f711..41aa7932758 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -21,8 +21,13 @@
#include <linux/wireless.h>
#include <net/cfg80211.h>
#include <linux/timex.h>
+#include "wil_platform.h"
+
#define WIL_NAME "wil6210"
+#define WIL_FW_NAME "wil6210.fw"
+
+#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
struct wil_board {
int board;
@@ -86,22 +91,29 @@ struct RGF_ICR {
/* registers - FW addresses */
#define RGF_USER_USAGE_1 (0x880004)
+#define RGF_USER_USAGE_6 (0x880018)
#define RGF_USER_HW_MACHINE_STATE (0x8801dc)
#define HW_MACHINE_BOOT_DONE (0x3fffffd)
#define RGF_USER_USER_CPU_0 (0x8801e0)
+ #define BIT_USER_USER_CPU_MAN_RST BIT(1) /* user_cpu_man_rst */
#define RGF_USER_MAC_CPU_0 (0x8801fc)
+ #define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */
#define RGF_USER_USER_SCRATCH_PAD (0x8802bc)
#define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */
#define RGF_USER_CLKS_CTL_0 (0x880abc)
+ #define BIT_USER_CLKS_CAR_AHB_SW_SEL BIT(1) /* ref clk/PLL */
#define BIT_USER_CLKS_RST_PWGD BIT(11) /* reset on "power good" */
#define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04)
#define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08)
#define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c)
#define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10)
#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14)
+ #define BIT_HPAL_PERST_FROM_PAD BIT(6)
+ #define BIT_CAR_PERST_RST BIT(7)
#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */
#define BIT_USER_USER_ICR_SW_INT_2 BIT(18)
#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0 (0x880c18)
+#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 (0x880c2c)
#define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */
#define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0)
@@ -133,6 +145,11 @@ struct RGF_ICR {
#define RGF_HP_CTRL (0x88265c)
#define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4)
+/* MAC timer, usec, for packet lifetime */
+#define RGF_MAC_MTRL_COUNTER_0 (0x886aa8)
+
+#define RGF_CAF_ICR (0x88946c) /* struct RGF_ICR */
+
/* popular locations */
#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
@@ -151,6 +168,7 @@ struct fw_map {
u32 host; /* PCI/Host address - BAR0 + 0x880000 */
const char *name; /* for debugfs */
};
+
/* array size should be in sync with actual definition in the wmi.c */
extern const struct fw_map fw_mapping[7];
@@ -300,18 +318,12 @@ struct pci_dev;
* @timeout: reset timer value (in TUs).
* @dialog_token: dialog token for aggregation session
* @rcu_head: RCU head used for freeing this struct
- * @reorder_lock: serializes access to reorder buffer, see below.
*
* This structure's lifetime is managed by RCU, assignments to
* the array holding it must hold the aggregation mutex.
*
- * The @reorder_lock is used to protect the members of this
- * struct, except for @timeout, @buf_size and @dialog_token,
- * which are constant across the lifetime of the struct (the
- * dialog token being used only for debugging).
*/
struct wil_tid_ampdu_rx {
- spinlock_t reorder_lock; /* see above */
struct sk_buff **reorder_buf;
unsigned long *reorder_time;
struct timer_list session_timer;
@@ -327,17 +339,6 @@ struct wil_tid_ampdu_rx {
bool first_time; /* is it 1-st time this buffer used? */
};
-struct wil6210_stats {
- u64 tsf;
- u32 snr;
- u16 last_mcs_rx;
- u16 bf_mcs; /* last BF, used for Tx */
- u16 my_rx_sector;
- u16 my_tx_sector;
- u16 peer_rx_sector;
- u16 peer_tx_sector;
-};
-
enum wil_sta_status {
wil_sta_unused = 0,
wil_sta_conn_pending = 1,
@@ -371,6 +372,7 @@ struct wil_sta_info {
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 */
unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)];
unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)];
};
@@ -397,6 +399,7 @@ struct wil6210_priv {
struct mutex wmi_mutex;
struct wil6210_mbox_ctl mbox_ctl;
struct completion wmi_ready;
+ struct completion wmi_call;
u16 wmi_seq;
u16 reply_id; /**< wait for this WMI event */
void *reply_buf;
@@ -430,11 +433,13 @@ struct wil6210_priv {
struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
/* statistics */
- struct wil6210_stats stats;
atomic_t isr_count_rx, isr_count_tx;
/* debugfs */
struct dentry *debug;
struct debugfs_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)];
+
+ void *platform_handle;
+ struct wil_platform_ops platform_ops;
};
#define wil_to_wiphy(i) (i->wdev->wiphy)
@@ -444,10 +449,11 @@ struct wil6210_priv {
#define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w))
#define wil_to_ndev(i) (wil_to_wdev(i)->netdev)
#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
+#define wil_to_pcie_dev(i) (&i->pdev->dev)
-int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
-int wil_err(struct wil6210_priv *wil, const char *fmt, ...);
-int wil_info(struct wil6210_priv *wil, const char *fmt, ...);
+void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
+void wil_err(struct wil6210_priv *wil, const char *fmt, ...);
+void wil_info(struct wil6210_priv *wil, const char *fmt, ...);
#define wil_dbg(wil, fmt, arg...) do { \
netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \
wil_dbg_trace(wil, fmt, ##arg); \
@@ -458,6 +464,7 @@ int wil_info(struct wil6210_priv *wil, const char *fmt, ...);
#define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
#define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg)
+#if defined(CONFIG_DYNAMIC_DEBUG)
#define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \
groupsize, buf, len, ascii) \
print_hex_dump_debug("DBG[TXRX]" prefix_str,\
@@ -469,6 +476,19 @@ int wil_info(struct wil6210_priv *wil, const char *fmt, ...);
print_hex_dump_debug("DBG[ WMI]" prefix_str,\
prefix_type, rowsize, \
groupsize, buf, len, ascii)
+#else /* defined(CONFIG_DYNAMIC_DEBUG) */
+static inline
+void wil_hex_dump_txrx(const char *prefix_str, int prefix_type, int rowsize,
+ int groupsize, const void *buf, size_t len, bool ascii)
+{
+}
+
+static inline
+void wil_hex_dump_wmi(const char *prefix_str, int prefix_type, int rowsize,
+ int groupsize, const void *buf, size_t len, bool ascii)
+{
+}
+#endif /* defined(CONFIG_DYNAMIC_DEBUG) */
void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
size_t count);
@@ -486,7 +506,9 @@ void wil_fw_error_recovery(struct wil6210_priv *wil);
void wil_link_on(struct wil6210_priv *wil);
void wil_link_off(struct wil6210_priv *wil);
int wil_up(struct wil6210_priv *wil);
+int __wil_up(struct wil6210_priv *wil);
int wil_down(struct wil6210_priv *wil);
+int __wil_down(struct wil6210_priv *wil);
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
@@ -519,8 +541,10 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason);
void wil6210_clear_irq(struct wil6210_priv *wil);
int wil6210_init_irq(struct wil6210_priv *wil, int irq);
void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
-void wil6210_disable_irq(struct wil6210_priv *wil);
-void wil6210_enable_irq(struct wil6210_priv *wil);
+void wil_mask_irq(struct wil6210_priv *wil);
+void wil_unmask_irq(struct wil6210_priv *wil);
+void wil_disable_irq(struct wil6210_priv *wil);
+void wil_enable_irq(struct wil6210_priv *wil);
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params,
u64 *cookie);
@@ -556,4 +580,5 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil);
int wil_iftype_nl2wmi(enum nl80211_iftype type);
+int wil_request_firmware(struct wil6210_priv *wil, const char *name);
#endif /* __WIL6210_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c
new file mode 100644
index 00000000000..8f1d78f8a74
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "linux/device.h"
+#include "wil_platform.h"
+
+#ifdef CONFIG_WIL6210_PLATFORM_MSM
+#include "wil_platform_msm.h"
+#endif
+
+/**
+ * wil_platform_init() - wil6210 platform module init
+ *
+ * The function must be called before all other functions in this module.
+ * It returns a handle which is used with the rest of the API
+ *
+ */
+void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops)
+{
+ void *handle = NULL;
+
+ if (!ops) {
+ dev_err(dev, "Invalid parameter. Cannot init platform module\n");
+ return NULL;
+ }
+
+#ifdef CONFIG_WIL6210_PLATFORM_MSM
+ handle = wil_platform_msm_init(dev, ops);
+ if (handle)
+ return handle;
+#endif
+
+ /* other platform specific init functions should be called here */
+
+ return handle;
+}
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h
new file mode 100644
index 00000000000..158c73b049a
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WIL_PLATFORM_H__
+#define __WIL_PLATFORM_H__
+
+struct device;
+
+/**
+ * struct wil_platform_ops - wil platform module callbacks
+ */
+struct wil_platform_ops {
+ int (*bus_request)(void *handle, uint32_t kbps /* KBytes/Sec */);
+ int (*suspend)(void *handle);
+ int (*resume)(void *handle);
+ void (*uninit)(void *handle);
+};
+
+void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops);
+
+#endif /* __WIL_PLATFORM_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.c b/drivers/net/wireless/ath/wil6210/wil_platform_msm.c
new file mode 100644
index 00000000000..b354a743240
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wil_platform_msm.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/msm-bus.h>
+
+#include "wil_platform.h"
+#include "wil_platform_msm.h"
+
+/**
+ * struct wil_platform_msm - wil6210 msm platform module info
+ *
+ * @dev: device object
+ * @msm_bus_handle: handle for using msm_bus API
+ * @pdata: bus scale info retrieved from DT
+ */
+struct wil_platform_msm {
+ struct device *dev;
+ uint32_t msm_bus_handle;
+ struct msm_bus_scale_pdata *pdata;
+};
+
+#define KBTOB(a) (a * 1000ULL)
+
+/**
+ * wil_platform_get_pdata() - Generate bus client data from device tree
+ * provided by clients.
+ *
+ * dev: device object
+ * of_node: Device tree node to extract information from
+ *
+ * The function returns a valid pointer to the allocated bus-scale-pdata
+ * if the vectors were correctly read from the client's device node.
+ * Any error in reading or parsing the device node will return NULL
+ * to the caller.
+ */
+static struct msm_bus_scale_pdata *wil_platform_get_pdata(
+ struct device *dev,
+ struct device_node *of_node)
+{
+ struct msm_bus_scale_pdata *pdata;
+ struct msm_bus_paths *usecase;
+ int i, j, ret, len;
+ unsigned int num_usecases, num_paths, mem_size;
+ const uint32_t *vec_arr;
+ struct msm_bus_vectors *vectors;
+
+ /* first read num_usecases and num_paths so we can calculate
+ * amount of memory to allocate
+ */
+ ret = of_property_read_u32(of_node, "qcom,msm-bus,num-cases",
+ &num_usecases);
+ if (ret) {
+ dev_err(dev, "Error: num-usecases not found\n");
+ return NULL;
+ }
+
+ ret = of_property_read_u32(of_node, "qcom,msm-bus,num-paths",
+ &num_paths);
+ if (ret) {
+ dev_err(dev, "Error: num_paths not found\n");
+ return NULL;
+ }
+
+ /* pdata memory layout:
+ * msm_bus_scale_pdata
+ * msm_bus_paths[num_usecases]
+ * msm_bus_vectors[num_usecases][num_paths]
+ */
+ mem_size = sizeof(struct msm_bus_scale_pdata) +
+ sizeof(struct msm_bus_paths) * num_usecases +
+ sizeof(struct msm_bus_vectors) * num_usecases * num_paths;
+
+ pdata = kzalloc(mem_size, GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ ret = of_property_read_string(of_node, "qcom,msm-bus,name",
+ &pdata->name);
+ if (ret) {
+ dev_err(dev, "Error: Client name not found\n");
+ goto err;
+ }
+
+ if (of_property_read_bool(of_node, "qcom,msm-bus,active-only")) {
+ pdata->active_only = 1;
+ } else {
+ dev_info(dev, "active_only flag absent.\n");
+ dev_info(dev, "Using dual context by default\n");
+ }
+
+ pdata->num_usecases = num_usecases;
+ pdata->usecase = (struct msm_bus_paths *)(pdata + 1);
+
+ vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len);
+ if (vec_arr == NULL) {
+ dev_err(dev, "Error: Vector array not found\n");
+ goto err;
+ }
+
+ if (len != num_usecases * num_paths * sizeof(uint32_t) * 4) {
+ dev_err(dev, "Error: Length-error on getting vectors\n");
+ goto err;
+ }
+
+ vectors = (struct msm_bus_vectors *)(pdata->usecase + num_usecases);
+ for (i = 0; i < num_usecases; i++) {
+ usecase = &pdata->usecase[i];
+ usecase->num_paths = num_paths;
+ usecase->vectors = &vectors[i];
+
+ for (j = 0; j < num_paths; j++) {
+ int index = ((i * num_paths) + j) * 4;
+
+ usecase->vectors[j].src = be32_to_cpu(vec_arr[index]);
+ usecase->vectors[j].dst =
+ be32_to_cpu(vec_arr[index + 1]);
+ usecase->vectors[j].ab = (uint64_t)
+ KBTOB(be32_to_cpu(vec_arr[index + 2]));
+ usecase->vectors[j].ib = (uint64_t)
+ KBTOB(be32_to_cpu(vec_arr[index + 3]));
+ }
+ }
+
+ return pdata;
+
+err:
+ kfree(pdata);
+
+ return NULL;
+}
+
+/* wil_platform API (callbacks) */
+
+static int wil_platform_bus_request(void *handle,
+ uint32_t kbps /* KBytes/Sec */)
+{
+ int rc, i;
+ struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
+ int vote = 0; /* vote 0 in case requested kbps cannot be satisfied */
+ struct msm_bus_paths *usecase;
+ uint32_t usecase_kbps;
+ uint32_t min_kbps = ~0;
+
+ /* find the lowest usecase that is bigger than requested kbps */
+ for (i = 0; i < msm->pdata->num_usecases; i++) {
+ usecase = &msm->pdata->usecase[i];
+ /* assume we have single path (vectors[0]). If we ever
+ * have multiple paths, need to define the behavior */
+ usecase_kbps = div64_u64(usecase->vectors[0].ib, 1000);
+ if (usecase_kbps >= kbps && usecase_kbps < min_kbps) {
+ min_kbps = usecase_kbps;
+ vote = i;
+ }
+ }
+
+ rc = msm_bus_scale_client_update_request(msm->msm_bus_handle, vote);
+ if (rc)
+ dev_err(msm->dev, "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n",
+ kbps, vote, rc);
+ else
+ /* TOOD: remove */
+ dev_info(msm->dev, "msm_bus_scale_client_update_request succeeded. kbps=%d vote=%d\n",
+ kbps, vote);
+
+ return rc;
+}
+
+static void wil_platform_uninit(void *handle)
+{
+ struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
+
+ dev_info(msm->dev, "wil_platform_uninit\n");
+
+ if (msm->msm_bus_handle)
+ msm_bus_scale_unregister_client(msm->msm_bus_handle);
+
+ kfree(msm->pdata);
+ kfree(msm);
+}
+
+static int wil_platform_msm_bus_register(struct wil_platform_msm *msm,
+ struct device_node *node)
+{
+ msm->pdata = wil_platform_get_pdata(msm->dev, node);
+ if (!msm->pdata) {
+ dev_err(msm->dev, "Failed getting DT info\n");
+ return -EINVAL;
+ }
+
+ msm->msm_bus_handle = msm_bus_scale_register_client(msm->pdata);
+ if (!msm->msm_bus_handle) {
+ dev_err(msm->dev, "Failed msm_bus registration\n");
+ return -EINVAL;
+ }
+
+ dev_info(msm->dev, "msm_bus registration succeeded! handle 0x%x\n",
+ msm->msm_bus_handle);
+
+ return 0;
+}
+
+/**
+ * wil_platform_msm_init() - wil6210 msm platform module init
+ *
+ * The function must be called before all other functions in this module.
+ * It returns a handle which is used with the rest of the API
+ *
+ */
+void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops)
+{
+ struct device_node *of_node;
+ struct wil_platform_msm *msm;
+ int rc;
+
+ of_node = of_find_compatible_node(NULL, NULL, "qcom,wil6210");
+ if (!of_node) {
+ /* this could mean non-msm platform */
+ dev_err(dev, "DT node not found\n");
+ return NULL;
+ }
+
+ msm = kzalloc(sizeof(*msm), GFP_KERNEL);
+ if (!msm)
+ return NULL;
+
+ msm->dev = dev;
+
+ /* register with msm_bus module for scaling requests */
+ rc = wil_platform_msm_bus_register(msm, of_node);
+ if (rc)
+ goto cleanup;
+
+ memset(ops, 0, sizeof(*ops));
+ ops->bus_request = wil_platform_bus_request;
+ ops->uninit = wil_platform_uninit;
+
+ return (void *)msm;
+
+cleanup:
+ kfree(msm);
+ return NULL;
+}
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.h b/drivers/net/wireless/ath/wil6210/wil_platform_msm.h
new file mode 100644
index 00000000000..2f2229edb49
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wil_platform_msm.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WIL_PLATFORM__MSM_H__
+#define __WIL_PLATFORM_MSM_H__
+
+#include "wil_platform.h"
+
+void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops);
+
+#endif /* __WIL_PLATFORM__MSM_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 1d1d0afdd2e..bd781c7adf2 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/moduleparam.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
@@ -22,6 +23,10 @@
#include "wmi.h"
#include "trace.h"
+static uint max_assoc_sta = 1;
+module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
+
/**
* WMI event receiving - theory of operations
*
@@ -152,6 +157,7 @@ int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
struct wil6210_mbox_hdr *hdr)
{
void __iomem *src = wmi_buffer(wil, ptr);
+
if (!src)
return -EINVAL;
@@ -273,6 +279,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
struct wmi_ready_event *evt = d;
+
wil->fw_version = le32_to_cpu(evt->sw_version);
wil->n_mids = evt->numof_additional_mids;
@@ -293,7 +300,7 @@ static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
wil_dbg_wmi(wil, "WMI: got FW ready event\n");
set_bit(wil_status_fwready, &wil->status);
- /* reuse wmi_ready for the firmware ready indication */
+ /* let the reset sequence continue */
complete(&wil->wmi_ready);
}
@@ -346,11 +353,11 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
rx_mgmt_frame->bssid);
cfg80211_put_bss(wiphy, bss);
} else {
- wil_err(wil, "cfg80211_inform_bss() failed\n");
+ wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
}
} else {
cfg80211_rx_mgmt(wil->wdev, freq, signal,
- (void *)rx_mgmt_frame, d_len, 0, GFP_KERNEL);
+ (void *)rx_mgmt_frame, d_len, 0);
}
}
@@ -482,33 +489,6 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
mutex_unlock(&wil->mutex);
}
-static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
-{
- struct wmi_notify_req_done_event *evt = d;
-
- if (len < sizeof(*evt)) {
- wil_err(wil, "Short NOTIFY event\n");
- return;
- }
-
- wil->stats.tsf = le64_to_cpu(evt->tsf);
- wil->stats.snr = le32_to_cpu(evt->snr_val);
- wil->stats.bf_mcs = le16_to_cpu(evt->bf_mcs);
- wil->stats.my_rx_sector = le16_to_cpu(evt->my_rx_sector);
- wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector);
- wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
- wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
- wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n"
- "BF status 0x%08x SNR 0x%08x SQI %d%%\n"
- "Tx Tpt %d goodput %d Rx goodput %d\n"
- "Sectors(rx:tx) my %d:%d peer %d:%d\n",
- wil->stats.bf_mcs, wil->stats.tsf, evt->status,
- wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt),
- le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),
- wil->stats.my_rx_sector, wil->stats.my_tx_sector,
- wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
-}
-
/*
* Firmware reports EAPOL frame using WME event.
* Reconstruct Ethernet frame and deliver it via normal Rx
@@ -617,27 +597,40 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
return;
}
+ mutex_lock(&wil->mutex);
+
cid = wil->vring2cid_tid[evt->ringid][0];
if (cid >= WIL6210_MAX_CID) {
wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid);
- return;
+ goto out;
}
sta = &wil->sta[cid];
if (sta->status == wil_sta_unused) {
wil_err(wil, "CID %d unused\n", cid);
- return;
+ goto out;
}
wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr);
for (i = 0; i < WIL_STA_TID_NUM; i++) {
- struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
+ struct wil_tid_ampdu_rx *r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sta->tid_rx_lock, flags);
+
+ r = sta->tid_rx[i];
sta->tid_rx[i] = NULL;
wil_tid_ampdu_rx_free(wil, r);
+
+ spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+
if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize)
sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil,
evt->agg_wsize, 0);
}
+
+out:
+ mutex_unlock(&wil->mutex);
}
static const struct {
@@ -651,7 +644,6 @@ static const struct {
{WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete},
{WMI_CONNECT_EVENTID, wmi_evt_connect},
{WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
- {WMI_NOTIFY_REQ_DONE_EVENTID, wmi_evt_notify},
{WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
{WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup},
{WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown},
@@ -676,7 +668,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
unsigned n;
if (!test_bit(wil_status_reset_done, &wil->status)) {
- wil_err(wil, "Reset not completed\n");
+ wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
return;
}
@@ -731,6 +723,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi;
u16 id = le16_to_cpu(wmi->id);
u32 tstamp = le32_to_cpu(wmi->timestamp);
+
wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n",
id, wmi->mid, tstamp);
trace_wil6210_wmi_event(wmi, &wmi[1],
@@ -771,8 +764,8 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
wil->reply_id = reply_id;
wil->reply_buf = reply;
wil->reply_size = reply_size;
- remain = wait_for_completion_timeout(&wil->wmi_ready,
- msecs_to_jiffies(to_msec));
+ remain = wait_for_completion_timeout(&wil->wmi_call,
+ msecs_to_jiffies(to_msec));
if (0 == remain) {
wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
cmdid, reply_id, to_msec);
@@ -822,7 +815,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
.network_type = wmi_nettype,
.disable_sec_offload = 1,
.channel = chan - 1,
- .pcp_max_assoc_sta = WIL6210_MAX_CID,
+ .pcp_max_assoc_sta = max_assoc_sta,
};
struct {
struct wil6210_mbox_hdr_wmi wmi;
@@ -832,6 +825,14 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
if (!wil->secure_pcp)
cmd.disable_sec = 1;
+ if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) ||
+ (cmd.pcp_max_assoc_sta <= 0)) {
+ wil_info(wil,
+ "Requested connection limit %u, valid values are 1 - %d. Setting to %d\n",
+ max_assoc_sta, WIL6210_MAX_CID, WIL6210_MAX_CID);
+ cmd.pcp_max_assoc_sta = WIL6210_MAX_CID;
+ }
+
/*
* Processing time may be huge, in case of secure AP it takes about
* 3500ms for FW to start AP
@@ -968,8 +969,11 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
int rc;
u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
+
if (!cmd)
return -ENOMEM;
+ if (!ie)
+ ie_len = 0;
cmd->mgmt_frm_type = type;
/* BUG: FW API define ieLen as u8. Will fix FW */
@@ -1143,6 +1147,9 @@ static void wmi_event_handle(struct wil6210_priv *wil,
struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]);
void *evt_data = (void *)(&wmi[1]);
u16 id = le16_to_cpu(wmi->id);
+
+ wil_dbg_wmi(wil, "Handle WMI 0x%04x (reply_id 0x%04x)\n",
+ id, wil->reply_id);
/* check if someone waits for this event */
if (wil->reply_id && wil->reply_id == id) {
if (wil->reply_buf) {
@@ -1153,7 +1160,7 @@ static void wmi_event_handle(struct wil6210_priv *wil,
len - sizeof(*wmi));
}
wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id);
- complete(&wil->wmi_ready);
+ complete(&wil->wmi_call);
return;
}
/* unsolicited event */
@@ -1199,9 +1206,11 @@ void wmi_event_worker(struct work_struct *work)
struct pending_wmi_event *evt;
struct list_head *lh;
+ wil_dbg_wmi(wil, "Start %s\n", __func__);
while ((lh = next_wmi_ev(wil)) != NULL) {
evt = list_entry(lh, struct pending_wmi_event, list);
wmi_event_handle(wil, &evt->event.hdr);
kfree(evt);
}
+ wil_dbg_wmi(wil, "Finished %s\n", __func__);
}
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 17334c85286..27b97432d1c 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
* Copyright (c) 2006-2012 Wilocity .
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -179,7 +179,6 @@ enum wmi_crypto_type {
WMI_CRYPT_AES_GCMP = 0x20,
};
-
enum wmi_connect_ctrl_flag_bits {
WMI_CONNECT_ASSOC_POLICY_USER = 0x0001,
WMI_CONNECT_SEND_REASSOC = 0x0002,
@@ -219,7 +218,6 @@ struct wmi_disconnect_sta_cmd {
__le16 disconnect_reason;
} __packed;
-
/*
* WMI_SET_PMK_CMDID
*/
@@ -234,7 +232,6 @@ struct wmi_set_pmk_cmd {
u8 pmk[WMI_PMK_LEN];
} __packed;
-
/*
* WMI_SET_PASSPHRASE_CMDID
*/
@@ -273,7 +270,6 @@ struct wmi_delete_cipher_key_cmd {
u8 mac[WMI_MAC_LEN];
} __packed;
-
/*
* WMI_START_SCAN_CMDID
*
@@ -325,7 +321,6 @@ struct wmi_probed_ssid_cmd {
u8 ssid[WMI_MAX_SSID_LEN];
} __packed;
-
/*
* WMI_SET_APPIE_CMDID
* Add Application specified IE to a management frame
@@ -351,7 +346,6 @@ struct wmi_set_appie_cmd {
u8 ie_info[0];
} __packed;
-
/*
* WMI_PXMT_RANGE_CFG_CMDID
*/
@@ -380,7 +374,6 @@ struct wmi_rf_mgmt_cmd {
__le32 rf_mgmt_type;
} __packed;
-
/*
* WMI_RF_RX_TEST_CMDID
*/
@@ -426,7 +419,6 @@ struct wmi_bcon_ctrl_cmd {
u8 disable_sec;
} __packed;
-
/******* P2P ***********/
/*
@@ -797,7 +789,6 @@ struct wmi_temp_sense_cmd {
__le32 measure_marlon_r_en;
} __packed;
-
/*
* WMI Events
*/
@@ -887,7 +878,6 @@ enum wmi_event_id {
* Events data structures
*/
-
enum wmi_fw_status {
WMI_FW_STATUS_SUCCESS,
WMI_FW_STATUS_FAILURE,
@@ -980,7 +970,7 @@ struct wmi_ready_event {
* WMI_NOTIFY_REQ_DONE_EVENTID
*/
struct wmi_notify_req_done_event {
- __le32 status;
+ __le32 status; /* beamforming status, 0: fail; 1: OK; 2: retrying */
__le64 tsf;
__le32 snr_val;
__le32 tx_tpt;
@@ -1038,8 +1028,8 @@ struct wmi_disconnect_event {
__le16 protocol_reason_status; /* reason code, see 802.11 spec. */
u8 bssid[WMI_MAC_LEN]; /* set if known */
u8 disconnect_reason; /* see wmi_disconnect_reason */
- u8 assoc_resp_len; /* not in use */
- u8 assoc_info[0]; /* not in use */
+ u8 assoc_resp_len; /* not used */
+ u8 assoc_info[0]; /* not used */
} __packed;
/*
@@ -1081,7 +1071,6 @@ struct wmi_delba_event {
__le16 reason;
} __packed;
-
/*
* WMI_VRING_CFG_DONE_EVENTID
*/
@@ -1147,7 +1136,6 @@ struct wmi_data_port_open_event {
u8 reserved[3];
} __packed;
-
/*
* WMI_GET_PCP_CHANNEL_EVENTID
*/
@@ -1156,7 +1144,6 @@ struct wmi_get_pcp_channel_event {
u8 reserved[3];
} __packed;
-
/*
* WMI_PORT_ALLOCATED_EVENTID
*/
@@ -1260,7 +1247,6 @@ struct wmi_rx_mgmt_info {
u8 channel; /* From Radio MNGR */
} __packed;
-
/*
* WMI_TX_MGMT_PACKET_EVENTID
*/
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index 4cfb4d99ced..7afc9c5329f 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -66,18 +66,18 @@ static void atmel_release(struct pcmcia_device *link);
static void atmel_detach(struct pcmcia_device *p_dev);
-typedef struct local_info_t {
+struct local_info {
struct net_device *eth_dev;
-} local_info_t;
+};
static int atmel_probe(struct pcmcia_device *p_dev)
{
- local_info_t *local;
+ struct local_info *local;
dev_dbg(&p_dev->dev, "atmel_attach()\n");
/* Allocate space for private device-specific data */
- local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(*local), GFP_KERNEL);
if (!local)
return -ENOMEM;
@@ -117,7 +117,7 @@ static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data)
static int atmel_config(struct pcmcia_device *link)
{
- local_info_t *dev;
+ struct local_info *dev;
int ret;
const struct pcmcia_device_id *did;
@@ -141,14 +141,14 @@ static int atmel_config(struct pcmcia_device *link)
if (ret)
goto failed;
- ((local_info_t*)link->priv)->eth_dev =
+ ((struct local_info *)link->priv)->eth_dev =
init_atmel_card(link->irq,
link->resource[0]->start,
did ? did->driver_info : ATMEL_FW_TYPE_NONE,
&link->dev,
card_present,
link);
- if (!((local_info_t*)link->priv)->eth_dev)
+ if (!((struct local_info *)link->priv)->eth_dev)
goto failed;
@@ -161,20 +161,20 @@ static int atmel_config(struct pcmcia_device *link)
static void atmel_release(struct pcmcia_device *link)
{
- struct net_device *dev = ((local_info_t*)link->priv)->eth_dev;
+ struct net_device *dev = ((struct local_info *)link->priv)->eth_dev;
dev_dbg(&link->dev, "atmel_release\n");
if (dev)
stop_atmel_card(dev);
- ((local_info_t*)link->priv)->eth_dev = NULL;
+ ((struct local_info *)link->priv)->eth_dev = NULL;
pcmcia_disable_device(link);
}
static int atmel_suspend(struct pcmcia_device *link)
{
- local_info_t *local = link->priv;
+ struct local_info *local = link->priv;
netif_device_detach(local->eth_dev);
@@ -183,7 +183,7 @@ static int atmel_suspend(struct pcmcia_device *link)
static int atmel_resume(struct pcmcia_device *link)
{
- local_info_t *local = link->priv;
+ struct local_info *local = link->priv;
atmel_open(local->eth_dev);
netif_device_attach(local->eth_dev);
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
index 6e00b8804ad..9f7965aae93 100644
--- a/drivers/net/wireless/b43/Makefile
+++ b/drivers/net/wireless/b43/Makefile
@@ -18,6 +18,7 @@ b43-y += xmit.o
b43-y += dma.o
b43-y += pio.o
b43-y += rfkill.o
+b43-y += ppr.o
b43-$(CONFIG_B43_LEDS) += leds.o
b43-$(CONFIG_B43_PCMCIA) += pcmcia.o
b43-$(CONFIG_B43_SDIO) += sdio.o
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 4113b693476..bb12586cd7c 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -45,6 +45,7 @@
#define B43_MMIO_RAM_DATA 0x134
#define B43_MMIO_PS_STATUS 0x140
#define B43_MMIO_RADIO_HWENABLED_HI 0x158
+#define B43_MMIO_MAC_HW_CAP 0x15C /* MAC capabilities (corerev >= 13) */
#define B43_MMIO_SHM_CONTROL 0x160
#define B43_MMIO_SHM_DATA 0x164
#define B43_MMIO_SHM_DATA_UNALIGNED 0x166
@@ -253,6 +254,8 @@ enum {
#define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */
#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5 Ghz channel */
#define B43_SHM_SH_CHAN_40MHZ 0x0200 /* Bit set, if 40 Mhz channel width */
+#define B43_SHM_SH_MACHW_L 0x00C0 /* Location where the ucode expects the MAC capabilities */
+#define B43_SHM_SH_MACHW_H 0x00C2 /* Location where the ucode expects the MAC capabilities */
#define B43_SHM_SH_HOSTF5 0x00D4 /* Hostflags 5 for ucode options */
#define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */
/* TSSI information */
@@ -297,6 +300,7 @@ enum {
#define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */
#define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */
#define B43_SHM_SH_EXTNPHYCTL 0x00B0 /* Extended bytes for beacon PHY control (N) */
+#define B43_SHM_SH_BCN_LI 0x00B6 /* beacon listen interval */
/* SHM_SHARED ACK/CTS control */
#define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */
/* SHM_SHARED probe response variables */
@@ -457,6 +461,7 @@ enum {
#define B43_MACCTL_RADIOLOCK 0x00080000 /* Radio lock */
#define B43_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */
#define B43_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep frames with bad PLCP */
+#define B43_MACCTL_PHY_LOCK 0x00200000
#define B43_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */
#define B43_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */
#define B43_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */
@@ -475,6 +480,11 @@ enum {
#define B43_MACCMD_CCA 0x00000008 /* Clear channel assessment */
#define B43_MACCMD_BGNOISE 0x00000010 /* Background noise */
+/* B43_MMIO_PSM_PHY_HDR bits */
+#define B43_PSM_HDR_MAC_PHY_RESET 0x00000001
+#define B43_PSM_HDR_MAC_PHY_CLOCK_EN 0x00000002
+#define B43_PSM_HDR_MAC_PHY_FORCE_CLK 0x00000004
+
/* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */
#define B43_BCMA_CLKCTLST_80211_PLL_REQ 0x00000100
#define B43_BCMA_CLKCTLST_PHY_PLL_REQ 0x00000200
@@ -791,6 +801,13 @@ struct b43_firmware {
bool pcm_request_failed;
};
+enum b43_band {
+ B43_BAND_2G = 0,
+ B43_BAND_5G_LO = 1,
+ B43_BAND_5G_MI = 2,
+ B43_BAND_5G_HI = 3,
+};
+
/* Device (802.11 core) initialization status. */
enum {
B43_STAT_UNINIT = 0, /* Uninitialized. */
@@ -1012,6 +1029,16 @@ static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value)
dev->dev->write16(dev->dev, offset, value);
}
+/* To optimize this check for flush_writes on BCM47XX_BCMA only. */
+static inline void b43_write16f(struct b43_wldev *dev, u16 offset, u16 value)
+{
+ b43_write16(dev, offset, value);
+#if defined(CONFIG_BCM47XX_BCMA)
+ if (dev->dev->flush_writes)
+ b43_read16(dev, offset);
+#endif
+}
+
static inline void b43_maskset16(struct b43_wldev *dev, u16 offset, u16 mask,
u16 set)
{
diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c
index 565fdbdd691..17d16a391fe 100644
--- a/drivers/net/wireless/b43/bus.c
+++ b/drivers/net/wireless/b43/bus.c
@@ -22,6 +22,10 @@
*/
+#ifdef CONFIG_BCM47XX_BCMA
+#include <asm/mach-bcm47xx/bcm47xx.h>
+#endif
+
#include "b43.h"
#include "bus.h"
@@ -102,6 +106,12 @@ struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core)
dev->write32 = b43_bus_bcma_write32;
dev->block_read = b43_bus_bcma_block_read;
dev->block_write = b43_bus_bcma_block_write;
+#ifdef CONFIG_BCM47XX_BCMA
+ if (b43_bus_host_is_pci(dev) &&
+ bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA &&
+ bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4716)
+ dev->flush_writes = true;
+#endif
dev->dev = &core->dev;
dev->dma_dev = core->dma_dev;
diff --git a/drivers/net/wireless/b43/bus.h b/drivers/net/wireless/b43/bus.h
index f3205c6988b..256c2c17939 100644
--- a/drivers/net/wireless/b43/bus.h
+++ b/drivers/net/wireless/b43/bus.h
@@ -33,6 +33,7 @@ struct b43_bus_dev {
size_t count, u16 offset, u8 reg_width);
void (*block_write)(struct b43_bus_dev *dev, const void *buffer,
size_t count, u16 offset, u8 reg_width);
+ bool flush_writes;
struct device *dev;
struct device *dma_dev;
@@ -60,7 +61,21 @@ static inline bool b43_bus_host_is_pcmcia(struct b43_bus_dev *dev)
#else
return false;
#endif
+};
+
+static inline bool b43_bus_host_is_pci(struct b43_bus_dev *dev)
+{
+#ifdef CONFIG_B43_BCMA
+ if (dev->bus_type == B43_BUS_BCMA)
+ return (dev->bdev->bus->hosttype == BCMA_HOSTTYPE_PCI);
+#endif
+#ifdef CONFIG_B43_SSB
+ if (dev->bus_type == B43_BUS_SSB)
+ return (dev->sdev->bus->bustype == SSB_BUSTYPE_PCI);
+#endif
+ return false;
}
+
static inline bool b43_bus_host_is_sdio(struct b43_bus_dev *dev)
{
#ifdef CONFIG_B43_SSB
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 2af1ac396eb..5d4173ee55b 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1204,6 +1204,36 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
}
}
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */
+void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev)
+{
+ struct bcma_drv_cc *bcma_cc __maybe_unused;
+ struct ssb_chipcommon *ssb_cc __maybe_unused;
+
+ switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+ case B43_BUS_BCMA:
+ bcma_cc = &dev->dev->bdev->bus->drv_cc;
+
+ bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0);
+ bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
+ bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4);
+ bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
+ break;
+#endif
+#ifdef CONFIG_B43_SSB
+ case B43_BUS_SSB:
+ ssb_cc = &dev->dev->sdev->bus->chipco;
+
+ chipco_write32(ssb_cc, SSB_CHIPCO_CHIPCTL_ADDR, 0);
+ chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4);
+ chipco_set32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, 0x4);
+ chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4);
+ break;
+#endif
+ }
+}
+
#ifdef CONFIG_B43_BCMA
static void b43_bcma_phy_reset(struct b43_wldev *dev)
{
@@ -2985,7 +3015,22 @@ void b43_mac_switch_freq(struct b43_wldev *dev, u8 spurmode)
{
u16 chip_id = dev->dev->chip_id;
- if (chip_id == BCMA_CHIP_ID_BCM43131 ||
+ if (chip_id == BCMA_CHIP_ID_BCM4331) {
+ switch (spurmode) {
+ case 2: /* 168 Mhz: 2^26/168 = 0x61862 */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x1862);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
+ break;
+ case 1: /* 164 Mhz: 2^26/164 = 0x63e70 */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x3e70);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
+ break;
+ default: /* 160 Mhz: 2^26/160 = 0x66666 */
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x6666);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
+ break;
+ }
+ } else if (chip_id == BCMA_CHIP_ID_BCM43131 ||
chip_id == BCMA_CHIP_ID_BCM43217 ||
chip_id == BCMA_CHIP_ID_BCM43222 ||
chip_id == BCMA_CHIP_ID_BCM43224 ||
@@ -3106,6 +3151,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev)
case B43_PHYTYPE_HT:
case B43_PHYTYPE_LCN:
b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
+ b43_rate_memory_write(dev, B43_OFDM_RATE_9MB, 1);
b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1);
@@ -3884,6 +3930,12 @@ static int b43_switch_band(struct b43_wldev *dev,
return 0;
}
+static void b43_set_beacon_listen_interval(struct b43_wldev *dev, u16 interval)
+{
+ interval = min_t(u16, interval, (u16)0xFF);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BCN_LI, interval);
+}
+
/* Write the short and long frame retry limit values. */
static void b43_set_retry_limits(struct b43_wldev *dev,
unsigned int short_retry,
@@ -3912,6 +3964,9 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&wl->mutex);
b43_mac_suspend(dev);
+ if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL)
+ b43_set_beacon_listen_interval(dev, conf->listen_interval);
+
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
phy->chandef = &conf->chandef;
phy->channel = conf->chandef.chan->hw_value;
@@ -4466,10 +4521,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
if (core_rev == 40 || core_rev == 42) {
radio_manuf = 0x17F;
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 0);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 0);
radio_rev = b43_read16(dev, B43_MMIO_RADIO24_DATA);
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 1);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 1);
radio_id = b43_read16(dev, B43_MMIO_RADIO24_DATA);
radio_ver = 0; /* Is there version somewhere? */
@@ -4477,7 +4532,7 @@ static int b43_phy_versioning(struct b43_wldev *dev)
u16 radio24[3];
for (tmp = 0; tmp < 3; tmp++) {
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, tmp);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, tmp);
radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA);
}
@@ -4494,13 +4549,12 @@ static int b43_phy_versioning(struct b43_wldev *dev)
else
tmp = 0x5205017F;
} else {
- b43_write16(dev, B43_MMIO_RADIO_CONTROL,
- B43_RADIOCTL_ID);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL,
+ B43_RADIOCTL_ID);
tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
- b43_write16(dev, B43_MMIO_RADIO_CONTROL,
- B43_RADIOCTL_ID);
- tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH)
- << 16;
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL,
+ B43_RADIOCTL_ID);
+ tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
}
radio_manuf = (tmp & 0x00000FFF);
radio_id = (tmp & 0x0FFFF000) >> 12;
@@ -4813,6 +4867,16 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
hf &= ~B43_HF_SKCFPUP;
b43_hf_write(dev, hf);
+ /* tell the ucode MAC capabilities */
+ if (dev->dev->core_rev >= 13) {
+ u32 mac_hw_cap = b43_read32(dev, B43_MMIO_MAC_HW_CAP);
+
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_L,
+ mac_hw_cap & 0xffff);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_H,
+ (mac_hw_cap >> 16) & 0xffff);
+ }
+
b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
B43_DEFAULT_LONG_RETRY_LIMIT);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
@@ -4835,6 +4899,10 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
/* Maximum Contention Window */
b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
+ /* write phytype and phyvers */
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYTYPE, phy->type);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYVER, phy->rev);
+
if (b43_bus_host_is_pcmcia(dev->dev) ||
b43_bus_host_is_sdio(dev->dev)) {
dev->__using_pio_transfers = true;
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
index 9f22e4b4c13..c46430cc725 100644
--- a/drivers/net/wireless/b43/main.h
+++ b/drivers/net/wireless/b43/main.h
@@ -96,6 +96,8 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason);
#define B43_PS_ASLEEP (1 << 3) /* Force device asleep */
void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags);
+void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev);
+
void b43_mac_suspend(struct b43_wldev *dev);
void b43_mac_enable(struct b43_wldev *dev);
void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on);
diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c
index 25e40432d68..99c036f5ecb 100644
--- a/drivers/net/wireless/b43/phy_a.c
+++ b/drivers/net/wireless/b43/phy_a.c
@@ -444,14 +444,14 @@ static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset)
static u16 b43_aphy_op_read(struct b43_wldev *dev, u16 reg)
{
reg = adjust_phyreg(dev, reg);
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
return b43_read16(dev, B43_MMIO_PHY_DATA);
}
static void b43_aphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
{
reg = adjust_phyreg(dev, reg);
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 3cbef21b472..1dfc682a805 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -222,12 +222,18 @@ static inline void assert_mac_suspended(struct b43_wldev *dev)
u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
{
assert_mac_suspended(dev);
+ dev->phy.writes_counter = 0;
return dev->phy.ops->radio_read(dev, reg);
}
void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
{
assert_mac_suspended(dev);
+ if (b43_bus_host_is_pci(dev->dev) &&
+ ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) {
+ b43_read32(dev, B43_MMIO_MACCTL);
+ dev->phy.writes_counter = 1;
+ }
dev->phy.ops->radio_write(dev, reg, value);
}
@@ -268,17 +274,28 @@ u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
{
assert_mac_suspended(dev);
dev->phy.writes_counter = 0;
- return dev->phy.ops->phy_read(dev, reg);
+
+ if (dev->phy.ops->phy_read)
+ return dev->phy.ops->phy_read(dev, reg);
+
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
+ return b43_read16(dev, B43_MMIO_PHY_DATA);
}
void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
{
assert_mac_suspended(dev);
- dev->phy.ops->phy_write(dev, reg, value);
- if (++dev->phy.writes_counter == B43_MAX_WRITES_IN_ROW) {
+ if (b43_bus_host_is_pci(dev->dev) &&
+ ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) {
b43_read16(dev, B43_MMIO_PHY_VER);
- dev->phy.writes_counter = 0;
+ dev->phy.writes_counter = 1;
}
+
+ if (dev->phy.ops->phy_write)
+ return dev->phy.ops->phy_write(dev, reg, value);
+
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg)
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c
index 8f5c14bc10e..727ce6edb4b 100644
--- a/drivers/net/wireless/b43/phy_g.c
+++ b/drivers/net/wireless/b43/phy_g.c
@@ -2555,13 +2555,13 @@ static void b43_gphy_op_exit(struct b43_wldev *dev)
static u16 b43_gphy_op_read(struct b43_wldev *dev, u16 reg)
{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
return b43_read16(dev, B43_MMIO_PHY_DATA);
}
static void b43_gphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA, value);
}
@@ -2572,7 +2572,7 @@ static u16 b43_gphy_op_radio_read(struct b43_wldev *dev, u16 reg)
/* G-PHY needs 0x80 for read access. */
reg |= 0x80;
- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
}
@@ -2581,7 +2581,7 @@ static void b43_gphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
}
diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c
index f2974c6b1c0..bd68945965d 100644
--- a/drivers/net/wireless/b43/phy_ht.c
+++ b/drivers/net/wireless/b43/phy_ht.c
@@ -81,80 +81,104 @@ static void b43_radio_2059_channel_setup(struct b43_wldev *dev,
udelay(50);
/* Calibration */
- b43_radio_mask(dev, 0x2b, ~0x1);
- b43_radio_mask(dev, 0x2e, ~0x4);
- b43_radio_set(dev, 0x2e, 0x4);
- b43_radio_set(dev, 0x2b, 0x1);
+ b43_radio_mask(dev, R2059_RFPLL_MISC_EN, ~0x1);
+ b43_radio_mask(dev, R2059_RFPLL_MISC_CAL_RESETN, ~0x4);
+ b43_radio_set(dev, R2059_RFPLL_MISC_CAL_RESETN, 0x4);
+ b43_radio_set(dev, R2059_RFPLL_MISC_EN, 0x1);
udelay(300);
}
-static void b43_radio_2059_init(struct b43_wldev *dev)
+/* Calibrate resistors in LPF of PLL? */
+static void b43_radio_2059_rcal(struct b43_wldev *dev)
+{
+ /* Enable */
+ b43_radio_set(dev, R2059_C3 | R2059_RCAL_CONFIG, 0x1);
+ usleep_range(10, 20);
+
+ b43_radio_set(dev, R2059_C3 | 0x0BF, 0x1);
+ b43_radio_maskset(dev, R2059_C3 | 0x19B, 0x3, 0x2);
+
+ /* Start */
+ b43_radio_set(dev, R2059_C3 | R2059_RCAL_CONFIG, 0x2);
+ usleep_range(100, 200);
+
+ /* Stop */
+ b43_radio_mask(dev, R2059_C3 | R2059_RCAL_CONFIG, ~0x2);
+
+ if (!b43_radio_wait_value(dev, R2059_C3 | R2059_RCAL_STATUS, 1, 1, 100,
+ 1000000))
+ b43err(dev->wl, "Radio 0x2059 rcal timeout\n");
+
+ /* Disable */
+ b43_radio_mask(dev, R2059_C3 | R2059_RCAL_CONFIG, ~0x1);
+
+ b43_radio_set(dev, 0xa, 0x60);
+}
+
+/* Calibrate the internal RC oscillator? */
+static void b43_radio_2057_rccal(struct b43_wldev *dev)
{
- const u16 routing[] = { R2059_C1, R2059_C2, R2059_C3 };
const u16 radio_values[3][2] = {
{ 0x61, 0xE9 }, { 0x69, 0xD5 }, { 0x73, 0x99 },
};
- u16 i, j;
+ int i;
- b43_radio_write(dev, R2059_ALL | 0x51, 0x0070);
- b43_radio_write(dev, R2059_ALL | 0x5a, 0x0003);
+ for (i = 0; i < 3; i++) {
+ b43_radio_write(dev, R2059_RCCAL_MASTER, radio_values[i][0]);
+ b43_radio_write(dev, R2059_RCCAL_X1, 0x6E);
+ b43_radio_write(dev, R2059_RCCAL_TRC0, radio_values[i][1]);
- for (i = 0; i < ARRAY_SIZE(routing); i++)
- b43_radio_set(dev, routing[i] | 0x146, 0x3);
+ /* Start */
+ b43_radio_write(dev, R2059_RCCAL_START_R1_Q1_P1, 0x55);
- b43_radio_set(dev, 0x2e, 0x0078);
- b43_radio_set(dev, 0xc0, 0x0080);
- msleep(2);
- b43_radio_mask(dev, 0x2e, ~0x0078);
- b43_radio_mask(dev, 0xc0, ~0x0080);
+ /* Wait */
+ if (!b43_radio_wait_value(dev, R2059_RCCAL_DONE_OSCCAP, 2, 2,
+ 500, 5000000))
+ b43err(dev->wl, "Radio 0x2059 rccal timeout\n");
- if (1) { /* FIXME */
- b43_radio_set(dev, R2059_C3 | 0x4, 0x1);
- udelay(10);
- b43_radio_set(dev, R2059_C3 | 0x0BF, 0x1);
- b43_radio_maskset(dev, R2059_C3 | 0x19B, 0x3, 0x2);
+ /* Stop */
+ b43_radio_write(dev, R2059_RCCAL_START_R1_Q1_P1, 0x15);
+ }
- b43_radio_set(dev, R2059_C3 | 0x4, 0x2);
- udelay(100);
- b43_radio_mask(dev, R2059_C3 | 0x4, ~0x2);
+ b43_radio_mask(dev, R2059_RCCAL_MASTER, ~0x1);
+}
- for (i = 0; i < 10000; i++) {
- if (b43_radio_read(dev, R2059_C3 | 0x145) & 1) {
- i = 0;
- break;
- }
- udelay(100);
- }
- if (i)
- b43err(dev->wl, "radio 0x945 timeout\n");
-
- b43_radio_mask(dev, R2059_C3 | 0x4, ~0x1);
- b43_radio_set(dev, 0xa, 0x60);
-
- for (i = 0; i < 3; i++) {
- b43_radio_write(dev, 0x17F, radio_values[i][0]);
- b43_radio_write(dev, 0x13D, 0x6E);
- b43_radio_write(dev, 0x13E, radio_values[i][1]);
- b43_radio_write(dev, 0x13C, 0x55);
-
- for (j = 0; j < 10000; j++) {
- if (b43_radio_read(dev, 0x140) & 2) {
- j = 0;
- break;
- }
- udelay(500);
- }
- if (j)
- b43err(dev->wl, "radio 0x140 timeout\n");
+static void b43_radio_2059_init_pre(struct b43_wldev *dev)
+{
+ b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD, ~B43_PHY_HT_RF_CTL_CMD_CHIP0_PU);
+ b43_phy_set(dev, B43_PHY_HT_RF_CTL_CMD, B43_PHY_HT_RF_CTL_CMD_FORCE);
+ b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD, ~B43_PHY_HT_RF_CTL_CMD_FORCE);
+ b43_phy_set(dev, B43_PHY_HT_RF_CTL_CMD, B43_PHY_HT_RF_CTL_CMD_CHIP0_PU);
+}
- b43_radio_write(dev, 0x13C, 0x15);
- }
+static void b43_radio_2059_init(struct b43_wldev *dev)
+{
+ const u16 routing[] = { R2059_C1, R2059_C2, R2059_C3 };
+ int i;
- b43_radio_mask(dev, 0x17F, ~0x1);
+ /* Prepare (reset?) radio */
+ b43_radio_2059_init_pre(dev);
+
+ r2059_upload_inittabs(dev);
+
+ for (i = 0; i < ARRAY_SIZE(routing); i++)
+ b43_radio_set(dev, routing[i] | 0x146, 0x3);
+
+ /* Post init starts below */
+
+ b43_radio_set(dev, R2059_RFPLL_MISC_CAL_RESETN, 0x0078);
+ b43_radio_set(dev, R2059_XTAL_CONFIG2, 0x0080);
+ msleep(2);
+ b43_radio_mask(dev, R2059_RFPLL_MISC_CAL_RESETN, ~0x0078);
+ b43_radio_mask(dev, R2059_XTAL_CONFIG2, ~0x0080);
+
+ if (1) { /* FIXME */
+ b43_radio_2059_rcal(dev);
+ b43_radio_2057_rccal(dev);
}
- b43_radio_mask(dev, 0x11, ~0x0008);
+ b43_radio_mask(dev, R2059_RFPLL_MASTER, ~0x0008);
}
/**************************************************
@@ -297,6 +321,26 @@ static void b43_phy_ht_bphy_init(struct b43_wldev *dev)
b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
}
+static void b43_phy_ht_bphy_reset(struct b43_wldev *dev, bool reset)
+{
+ u16 tmp;
+
+ tmp = b43_read16(dev, B43_MMIO_PSM_PHY_HDR);
+ b43_write16(dev, B43_MMIO_PSM_PHY_HDR,
+ tmp | B43_PSM_HDR_MAC_PHY_FORCE_CLK);
+
+ /* Put BPHY in or take it out of the reset */
+ if (reset)
+ b43_phy_set(dev, B43_PHY_B_BBCFG,
+ B43_PHY_B_BBCFG_RSTCCA | B43_PHY_B_BBCFG_RSTRX);
+ else
+ b43_phy_mask(dev, B43_PHY_B_BBCFG,
+ (u16)~(B43_PHY_B_BBCFG_RSTCCA |
+ B43_PHY_B_BBCFG_RSTRX));
+
+ b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp);
+}
+
/**************************************************
* Samples
**************************************************/
@@ -704,7 +748,6 @@ static void b43_phy_ht_spur_avoid(struct b43_wldev *dev,
{
struct bcma_device *core = dev->dev->bdev;
int spuravoid = 0;
- u16 tmp;
/* Check for 13 and 14 is just a guess, we don't have enough logs. */
if (new_channel->hw_value == 13 || new_channel->hw_value == 14)
@@ -717,22 +760,9 @@ static void b43_phy_ht_spur_avoid(struct b43_wldev *dev,
B43_BCMA_CLKCTLST_80211_PLL_ST |
B43_BCMA_CLKCTLST_PHY_PLL_ST, false);
- /* Values has been taken from wlc_bmac_switch_macfreq comments */
- switch (spuravoid) {
- case 2: /* 126MHz */
- tmp = 0x2082;
- break;
- case 1: /* 123MHz */
- tmp = 0x5341;
- break;
- default: /* 120MHz */
- tmp = 0x8889;
- }
-
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, tmp);
- b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+ b43_mac_switch_freq(dev, spuravoid);
- /* TODO: reset PLL */
+ b43_wireless_core_phy_pll_reset(dev);
if (spuravoid)
b43_phy_set(dev, B43_PHY_HT_BBCFG, B43_PHY_HT_BBCFG_RSTRX);
@@ -747,13 +777,19 @@ static void b43_phy_ht_channel_setup(struct b43_wldev *dev,
const struct b43_phy_ht_channeltab_e_phy *e,
struct ieee80211_channel *new_channel)
{
- bool old_band_5ghz;
+ if (new_channel->band == IEEE80211_BAND_5GHZ) {
+ /* Switch to 2 GHz for a moment to access B-PHY regs */
+ b43_phy_mask(dev, B43_PHY_HT_BANDCTL, ~B43_PHY_HT_BANDCTL_5GHZ);
+
+ b43_phy_ht_bphy_reset(dev, true);
+
+ /* Switch to 5 GHz */
+ b43_phy_set(dev, B43_PHY_HT_BANDCTL, B43_PHY_HT_BANDCTL_5GHZ);
+ } else {
+ /* Switch to 2 GHz */
+ b43_phy_mask(dev, B43_PHY_HT_BANDCTL, ~B43_PHY_HT_BANDCTL_5GHZ);
- old_band_5ghz = b43_phy_read(dev, B43_PHY_HT_BANDCTL) & 0; /* FIXME */
- if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) {
- /* TODO */
- } else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) {
- /* TODO */
+ b43_phy_ht_bphy_reset(dev, false);
}
b43_phy_write(dev, B43_PHY_HT_BW1, e->bw1);
@@ -1002,19 +1038,10 @@ static void b43_phy_ht_op_software_rfkill(struct b43_wldev *dev,
if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
b43err(dev->wl, "MAC not suspended\n");
- /* In the following PHY ops we copy wl's dummy behaviour.
- * TODO: Find out if reads (currently hidden in masks/masksets) are
- * needed and replace following ops with just writes or w&r.
- * Note: B43_PHY_HT_RF_CTL1 register is tricky, wrong operation can
- * cause delayed (!) machine lock up. */
if (blocked) {
- b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
+ b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD,
+ ~B43_PHY_HT_RF_CTL_CMD_CHIP0_PU);
} else {
- b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
- b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x1);
- b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
- b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x2);
-
if (dev->phy.radio_ver == 0x2059)
b43_radio_2059_init(dev);
else
@@ -1071,22 +1098,10 @@ static unsigned int b43_phy_ht_op_get_default_chan(struct b43_wldev *dev)
* R/W ops.
**************************************************/
-static u16 b43_phy_ht_op_read(struct b43_wldev *dev, u16 reg)
-{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_phy_ht_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
static void b43_phy_ht_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
u16 set)
{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA,
(b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
}
@@ -1096,14 +1111,14 @@ static u16 b43_phy_ht_op_radio_read(struct b43_wldev *dev, u16 reg)
/* HT-PHY needs 0x200 for read access */
reg |= 0x200;
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO24_DATA);
}
static void b43_phy_ht_op_radio_write(struct b43_wldev *dev, u16 reg,
u16 value)
{
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
}
@@ -1126,8 +1141,6 @@ const struct b43_phy_operations b43_phyops_ht = {
.free = b43_phy_ht_op_free,
.prepare_structs = b43_phy_ht_op_prepare_structs,
.init = b43_phy_ht_op_init,
- .phy_read = b43_phy_ht_op_read,
- .phy_write = b43_phy_ht_op_write,
.phy_maskset = b43_phy_ht_op_maskset,
.radio_read = b43_phy_ht_op_radio_read,
.radio_write = b43_phy_ht_op_radio_write,
diff --git a/drivers/net/wireless/b43/phy_ht.h b/drivers/net/wireless/b43/phy_ht.h
index 6cae370d101..c086f56ce47 100644
--- a/drivers/net/wireless/b43/phy_ht.h
+++ b/drivers/net/wireless/b43/phy_ht.h
@@ -81,7 +81,9 @@
#define B43_PHY_HT_RF_SEQ_STATUS B43_PHY_EXTG(0x004)
/* Values for the status are the same as for the trigger */
-#define B43_PHY_HT_RF_CTL1 B43_PHY_EXTG(0x010)
+#define B43_PHY_HT_RF_CTL_CMD 0x810
+#define B43_PHY_HT_RF_CTL_CMD_FORCE 0x0001
+#define B43_PHY_HT_RF_CTL_CMD_CHIP0_PU 0x0002
#define B43_PHY_HT_RF_CTL_INT_C1 B43_PHY_EXTG(0x04c)
#define B43_PHY_HT_RF_CTL_INT_C2 B43_PHY_EXTG(0x06c)
@@ -104,6 +106,9 @@
#define B43_PHY_HT_TXPCTL_TARG_PWR2_C3_SHIFT 0
#define B43_PHY_HT_TX_PCTL_STATUS_C3 B43_PHY_EXTG(0x169)
+#define B43_PHY_B_BBCFG B43_PHY_N_BMODE(0x001)
+#define B43_PHY_B_BBCFG_RSTCCA 0x4000 /* Reset CCA */
+#define B43_PHY_B_BBCFG_RSTRX 0x8000 /* Reset RX */
#define B43_PHY_HT_TEST B43_PHY_N_BMODE(0x00A)
diff --git a/drivers/net/wireless/b43/phy_lcn.c b/drivers/net/wireless/b43/phy_lcn.c
index e76bbdf3247..97461ccf3e1 100644
--- a/drivers/net/wireless/b43/phy_lcn.c
+++ b/drivers/net/wireless/b43/phy_lcn.c
@@ -810,22 +810,10 @@ static void b43_phy_lcn_op_adjust_txpower(struct b43_wldev *dev)
* R/W ops.
**************************************************/
-static u16 b43_phy_lcn_op_read(struct b43_wldev *dev, u16 reg)
-{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_phy_lcn_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
u16 set)
{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA,
(b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
}
@@ -835,14 +823,14 @@ static u16 b43_phy_lcn_op_radio_read(struct b43_wldev *dev, u16 reg)
/* LCN-PHY needs 0x200 for read access */
reg |= 0x200;
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO24_DATA);
}
static void b43_phy_lcn_op_radio_write(struct b43_wldev *dev, u16 reg,
u16 value)
{
- b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
}
@@ -855,8 +843,6 @@ const struct b43_phy_operations b43_phyops_lcn = {
.free = b43_phy_lcn_op_free,
.prepare_structs = b43_phy_lcn_op_prepare_structs,
.init = b43_phy_lcn_op_init,
- .phy_read = b43_phy_lcn_op_read,
- .phy_write = b43_phy_lcn_op_write,
.phy_maskset = b43_phy_lcn_op_maskset,
.radio_read = b43_phy_lcn_op_radio_read,
.radio_write = b43_phy_lcn_op_radio_write,
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index 92190dacf68..058a9f23205 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -1985,22 +1985,10 @@ static void lpphy_calibration(struct b43_wldev *dev)
b43_mac_enable(dev);
}
-static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg)
-{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
u16 set)
{
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
b43_write16(dev, B43_MMIO_PHY_DATA,
(b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
}
@@ -2016,7 +2004,7 @@ static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg)
} else
reg |= 0x200;
- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
}
@@ -2025,7 +2013,7 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
/* Register 1 is a 32-bit register. */
B43_WARN_ON(reg == 1);
- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
}
@@ -2713,8 +2701,6 @@ const struct b43_phy_operations b43_phyops_lp = {
.free = b43_lpphy_op_free,
.prepare_structs = b43_lpphy_op_prepare_structs,
.init = b43_lpphy_op_init,
- .phy_read = b43_lpphy_op_read,
- .phy_write = b43_lpphy_op_write,
.phy_maskset = b43_lpphy_op_maskset,
.radio_read = b43_lpphy_op_radio_read,
.radio_write = b43_lpphy_op_radio_write,
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index e2a3f0d5bcc..9f0bcf3b841 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -34,6 +34,7 @@
#include "radio_2056.h"
#include "radio_2057.h"
#include "main.h"
+#include "ppr.h"
struct nphy_txgains {
u16 tx_lpf[2];
@@ -3606,16 +3607,6 @@ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core,
* Tx and Rx
**************************************************/
-static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev)
-{//TODO
-}
-
-static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
- bool ignore_tssi)
-{//TODO
- return B43_TXPWR_RES_DONE;
-}
-
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */
static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
{
@@ -4069,6 +4060,7 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev)
s16 a1[2], b0[2], b1[2];
u8 idle[2];
+ u8 ppr_max;
s8 target[2];
s32 num, den, pwr;
u32 regval[64];
@@ -4147,7 +4139,12 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev)
b1[0] = b1[1] = -1393;
}
}
- /* target[0] = target[1] = nphy->tx_power_max; */
+
+ ppr_max = b43_ppr_get_max(dev, &nphy->tx_pwr_max_ppr);
+ if (ppr_max) {
+ target[0] = ppr_max;
+ target[1] = ppr_max;
+ }
if (dev->phy.rev >= 3) {
if (sprom->fem.ghz2.tssipos)
@@ -4235,8 +4232,9 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev)
const u32 *table = NULL;
u32 rfpwr_offset;
- u8 pga_gain;
+ u8 pga_gain, pad_gain;
int i;
+ const s16 *uninitialized_var(rf_pwr_offset_table);
table = b43_nphy_get_tx_gain_table(dev);
if (!table)
@@ -4252,13 +4250,27 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev)
nphy->gmval = (table[0] >> 16) & 0x7000;
#endif
+ if (phy->rev >= 19) {
+ return;
+ } else if (phy->rev >= 7) {
+ rf_pwr_offset_table = b43_ntab_get_rf_pwr_offset_table(dev);
+ if (!rf_pwr_offset_table)
+ return;
+ /* TODO: Enable this once we have gains configured */
+ return;
+ }
+
for (i = 0; i < 128; i++) {
if (phy->rev >= 19) {
/* TODO */
return;
} else if (phy->rev >= 7) {
- /* TODO */
- return;
+ pga_gain = (table[i] >> 24) & 0xf;
+ pad_gain = (table[i] >> 19) & 0x1f;
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ rfpwr_offset = rf_pwr_offset_table[pad_gain];
+ else
+ rfpwr_offset = rf_pwr_offset_table[pga_gain];
} else {
pga_gain = (table[i] >> 24) & 0xF;
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
@@ -5874,6 +5886,69 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
b43_mac_enable(dev);
}
+static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
+ bool ignore_tssi)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_phy_n *nphy = dev->phy.n;
+ struct ieee80211_channel *channel = dev->wl->hw->conf.chandef.chan;
+ struct b43_ppr *ppr = &nphy->tx_pwr_max_ppr;
+ u8 max; /* qdBm */
+ bool tx_pwr_state;
+
+ if (nphy->tx_pwr_last_recalc_freq == channel->center_freq &&
+ nphy->tx_pwr_last_recalc_limit == phy->desired_txpower)
+ return B43_TXPWR_RES_DONE;
+
+ /* Make sure we have a clean PPR */
+ b43_ppr_clear(dev, ppr);
+
+ /* HW limitations */
+ b43_ppr_load_max_from_sprom(dev, ppr, B43_BAND_2G);
+
+ /* Regulatory & user settings */
+ max = INT_TO_Q52(phy->chandef->chan->max_power);
+ if (phy->desired_txpower)
+ max = min_t(u8, max, INT_TO_Q52(phy->desired_txpower));
+ b43_ppr_apply_max(dev, ppr, max);
+ if (b43_debug(dev, B43_DBG_XMITPOWER))
+ b43dbg(dev->wl, "Calculated TX power: " Q52_FMT "\n",
+ Q52_ARG(b43_ppr_get_max(dev, ppr)));
+
+ /* TODO: Enable this once we get gains working */
+#if 0
+ /* Some extra gains */
+ hw_gain = 6; /* N-PHY specific */
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ hw_gain += sprom->antenna_gain.a0;
+ else
+ hw_gain += sprom->antenna_gain.a1;
+ b43_ppr_add(dev, ppr, -hw_gain);
+#endif
+
+ /* Make sure we didn't go too low */
+ b43_ppr_apply_min(dev, ppr, INT_TO_Q52(8));
+
+ /* Apply */
+ tx_pwr_state = nphy->txpwrctrl;
+ b43_mac_suspend(dev);
+ b43_nphy_tx_power_ctl_setup(dev);
+ if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12) {
+ b43_maskset32(dev, B43_MMIO_MACCTL, ~0, B43_MACCTL_PHY_LOCK);
+ b43_read32(dev, B43_MMIO_MACCTL);
+ udelay(1);
+ }
+ b43_nphy_tx_power_ctrl(dev, nphy->txpwrctrl);
+ if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12)
+ b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_PHY_LOCK, 0);
+ b43_mac_enable(dev);
+
+ nphy->tx_pwr_last_recalc_freq = channel->center_freq;
+ nphy->tx_pwr_last_recalc_limit = phy->desired_txpower;
+
+ return B43_TXPWR_RES_DONE;
+}
+
/**************************************************
* N-PHY init
**************************************************/
@@ -6294,7 +6369,7 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev,
b43_mac_switch_freq(dev, spuravoid);
if (dev->phy.rev == 3 || dev->phy.rev == 4)
- ; /* TODO: reset PLL */
+ b43_wireless_core_phy_pll_reset(dev);
if (spuravoid)
b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTRX);
@@ -6407,6 +6482,7 @@ static int b43_nphy_op_allocate(struct b43_wldev *dev)
nphy = kzalloc(sizeof(*nphy), GFP_KERNEL);
if (!nphy)
return -ENOMEM;
+
dev->phy.n = nphy;
return 0;
@@ -6497,26 +6573,13 @@ static inline void check_phyreg(struct b43_wldev *dev, u16 offset)
#endif /* B43_DEBUG */
}
-static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg)
-{
- check_phyreg(dev, reg);
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
- check_phyreg(dev, reg);
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
- b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
static void b43_nphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
u16 set)
{
check_phyreg(dev, reg);
- b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
b43_maskset16(dev, B43_MMIO_PHY_DATA, mask, set);
+ dev->phy.writes_counter = 1;
}
static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
@@ -6529,7 +6592,7 @@ static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
else
reg |= 0x100;
- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
}
@@ -6538,7 +6601,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
/* Register 1 is a 32-bit register. */
B43_WARN_ON(dev->phy.rev < 7 && reg == 1);
- b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+ b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
}
@@ -6652,8 +6715,6 @@ const struct b43_phy_operations b43_phyops_n = {
.free = b43_nphy_op_free,
.prepare_structs = b43_nphy_op_prepare_structs,
.init = b43_nphy_op_init,
- .phy_read = b43_nphy_op_read,
- .phy_write = b43_nphy_op_write,
.phy_maskset = b43_nphy_op_maskset,
.radio_read = b43_nphy_op_radio_read,
.radio_write = b43_nphy_op_radio_write,
@@ -6662,5 +6723,4 @@ const struct b43_phy_operations b43_phyops_n = {
.switch_channel = b43_nphy_op_switch_channel,
.get_default_chan = b43_nphy_op_get_default_chan,
.recalc_txpower = b43_nphy_op_recalc_txpower,
- .adjust_txpower = b43_nphy_op_adjust_txpower,
};
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h
index 30bec815b96..a6da2c31a99 100644
--- a/drivers/net/wireless/b43/phy_n.h
+++ b/drivers/net/wireless/b43/phy_n.h
@@ -2,6 +2,7 @@
#define B43_NPHY_H_
#include "phy_common.h"
+#include "ppr.h"
/* N-PHY registers. */
@@ -967,6 +968,9 @@ struct b43_phy_n {
struct b43_phy_n_txpwrindex txpwrindex[2];
struct b43_phy_n_pwr_ctl_info pwr_ctl_info[2];
struct b43_chanspec txiqlocal_chanspec;
+ struct b43_ppr tx_pwr_max_ppr;
+ u16 tx_pwr_last_recalc_freq;
+ int tx_pwr_last_recalc_limit;
u8 txrx_chain;
u16 tx_rx_cal_phy_saveregs[11];
diff --git a/drivers/net/wireless/b43/ppr.c b/drivers/net/wireless/b43/ppr.c
new file mode 100644
index 00000000000..9a770279c41
--- /dev/null
+++ b/drivers/net/wireless/b43/ppr.c
@@ -0,0 +1,199 @@
+/*
+ * Broadcom B43 wireless driver
+ * PPR (Power Per Rate) management
+ *
+ * Copyright (c) 2014 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 "ppr.h"
+#include "b43.h"
+
+#define ppr_for_each_entry(ppr, i, entry) \
+ for (i = 0, entry = &(ppr)->__all_rates[i]; \
+ i < B43_PPR_RATES_NUM; \
+ i++, entry++)
+
+void b43_ppr_clear(struct b43_wldev *dev, struct b43_ppr *ppr)
+{
+ memset(ppr, 0, sizeof(*ppr));
+
+ /* Compile-time PPR check */
+ BUILD_BUG_ON(sizeof(struct b43_ppr) != B43_PPR_RATES_NUM * sizeof(u8));
+}
+
+void b43_ppr_add(struct b43_wldev *dev, struct b43_ppr *ppr, int diff)
+{
+ int i;
+ u8 *rate;
+
+ ppr_for_each_entry(ppr, i, rate) {
+ *rate = clamp_val(*rate + diff, 0, 127);
+ }
+}
+
+void b43_ppr_apply_max(struct b43_wldev *dev, struct b43_ppr *ppr, u8 max)
+{
+ int i;
+ u8 *rate;
+
+ ppr_for_each_entry(ppr, i, rate) {
+ *rate = min(*rate, max);
+ }
+}
+
+void b43_ppr_apply_min(struct b43_wldev *dev, struct b43_ppr *ppr, u8 min)
+{
+ int i;
+ u8 *rate;
+
+ ppr_for_each_entry(ppr, i, rate) {
+ *rate = max(*rate, min);
+ }
+}
+
+u8 b43_ppr_get_max(struct b43_wldev *dev, struct b43_ppr *ppr)
+{
+ u8 res = 0;
+ int i;
+ u8 *rate;
+
+ ppr_for_each_entry(ppr, i, rate) {
+ res = max(*rate, res);
+ }
+
+ return res;
+}
+
+bool b43_ppr_load_max_from_sprom(struct b43_wldev *dev, struct b43_ppr *ppr,
+ enum b43_band band)
+{
+ struct b43_ppr_rates *rates = &ppr->rates;
+ struct ssb_sprom *sprom = dev->dev->bus_sprom;
+ struct b43_phy *phy = &dev->phy;
+ u8 maxpwr, off;
+ u32 sprom_ofdm_po;
+ u16 *sprom_mcs_po;
+ u8 extra_cdd_po, extra_stbc_po;
+ int i;
+
+ switch (band) {
+ case B43_BAND_2G:
+ maxpwr = min(sprom->core_pwr_info[0].maxpwr_2g,
+ sprom->core_pwr_info[1].maxpwr_2g);
+ sprom_ofdm_po = sprom->ofdm2gpo;
+ sprom_mcs_po = sprom->mcs2gpo;
+ extra_cdd_po = (sprom->cddpo >> 0) & 0xf;
+ extra_stbc_po = (sprom->stbcpo >> 0) & 0xf;
+ break;
+ case B43_BAND_5G_LO:
+ maxpwr = min(sprom->core_pwr_info[0].maxpwr_5gl,
+ sprom->core_pwr_info[1].maxpwr_5gl);
+ sprom_ofdm_po = sprom->ofdm5glpo;
+ sprom_mcs_po = sprom->mcs5glpo;
+ extra_cdd_po = (sprom->cddpo >> 8) & 0xf;
+ extra_stbc_po = (sprom->stbcpo >> 8) & 0xf;
+ break;
+ case B43_BAND_5G_MI:
+ maxpwr = min(sprom->core_pwr_info[0].maxpwr_5g,
+ sprom->core_pwr_info[1].maxpwr_5g);
+ sprom_ofdm_po = sprom->ofdm5gpo;
+ sprom_mcs_po = sprom->mcs5gpo;
+ extra_cdd_po = (sprom->cddpo >> 4) & 0xf;
+ extra_stbc_po = (sprom->stbcpo >> 4) & 0xf;
+ break;
+ case B43_BAND_5G_HI:
+ maxpwr = min(sprom->core_pwr_info[0].maxpwr_5gh,
+ sprom->core_pwr_info[1].maxpwr_5gh);
+ sprom_ofdm_po = sprom->ofdm5ghpo;
+ sprom_mcs_po = sprom->mcs5ghpo;
+ extra_cdd_po = (sprom->cddpo >> 12) & 0xf;
+ extra_stbc_po = (sprom->stbcpo >> 12) & 0xf;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return false;
+ }
+
+ if (band == B43_BAND_2G) {
+ for (i = 0; i < 4; i++) {
+ off = ((sprom->cck2gpo >> (i * 4)) & 0xf) * 2;
+ rates->cck[i] = maxpwr - off;
+ }
+ }
+
+ /* OFDM */
+ for (i = 0; i < 8; i++) {
+ off = ((sprom_ofdm_po >> (i * 4)) & 0xf) * 2;
+ rates->ofdm[i] = maxpwr - off;
+ }
+
+ /* MCS 20 SISO */
+ rates->mcs_20[0] = rates->ofdm[0];
+ rates->mcs_20[1] = rates->ofdm[2];
+ rates->mcs_20[2] = rates->ofdm[3];
+ rates->mcs_20[3] = rates->ofdm[4];
+ rates->mcs_20[4] = rates->ofdm[5];
+ rates->mcs_20[5] = rates->ofdm[6];
+ rates->mcs_20[6] = rates->ofdm[7];
+ rates->mcs_20[7] = rates->ofdm[7];
+
+ /* MCS 20 CDD */
+ for (i = 0; i < 4; i++) {
+ off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2;
+ rates->mcs_20_cdd[i] = maxpwr - off;
+ if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+ rates->mcs_20_cdd[i] -= extra_cdd_po;
+ }
+ for (i = 0; i < 4; i++) {
+ off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2;
+ rates->mcs_20_cdd[4 + i] = maxpwr - off;
+ if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+ rates->mcs_20_cdd[4 + i] -= extra_cdd_po;
+ }
+
+ /* OFDM 20 CDD */
+ rates->ofdm_20_cdd[0] = rates->mcs_20_cdd[0];
+ rates->ofdm_20_cdd[1] = rates->mcs_20_cdd[0];
+ rates->ofdm_20_cdd[2] = rates->mcs_20_cdd[1];
+ rates->ofdm_20_cdd[3] = rates->mcs_20_cdd[2];
+ rates->ofdm_20_cdd[4] = rates->mcs_20_cdd[3];
+ rates->ofdm_20_cdd[5] = rates->mcs_20_cdd[4];
+ rates->ofdm_20_cdd[6] = rates->mcs_20_cdd[5];
+ rates->ofdm_20_cdd[7] = rates->mcs_20_cdd[6];
+
+ /* MCS 20 STBC */
+ for (i = 0; i < 4; i++) {
+ off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2;
+ rates->mcs_20_stbc[i] = maxpwr - off;
+ if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+ rates->mcs_20_stbc[i] -= extra_stbc_po;
+ }
+ for (i = 0; i < 4; i++) {
+ off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2;
+ rates->mcs_20_stbc[4 + i] = maxpwr - off;
+ if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+ rates->mcs_20_stbc[4 + i] -= extra_stbc_po;
+ }
+
+ /* MCS 20 SDM */
+ for (i = 0; i < 4; i++) {
+ off = ((sprom_mcs_po[2] >> (i * 4)) & 0xf) * 2;
+ rates->mcs_20_sdm[i] = maxpwr - off;
+ }
+ for (i = 0; i < 4; i++) {
+ off = ((sprom_mcs_po[3] >> (i * 4)) & 0xf) * 2;
+ rates->mcs_20_sdm[4 + i] = maxpwr - off;
+ }
+
+ return true;
+}
diff --git a/drivers/net/wireless/b43/ppr.h b/drivers/net/wireless/b43/ppr.h
new file mode 100644
index 00000000000..24d7447e9f0
--- /dev/null
+++ b/drivers/net/wireless/b43/ppr.h
@@ -0,0 +1,45 @@
+#ifndef LINUX_B43_PPR_H_
+#define LINUX_B43_PPR_H_
+
+#include <linux/types.h>
+
+#define B43_PPR_CCK_RATES_NUM 4
+#define B43_PPR_OFDM_RATES_NUM 8
+#define B43_PPR_MCS_RATES_NUM 8
+
+#define B43_PPR_RATES_NUM (B43_PPR_CCK_RATES_NUM + \
+ B43_PPR_OFDM_RATES_NUM * 2 + \
+ B43_PPR_MCS_RATES_NUM * 4)
+
+struct b43_ppr_rates {
+ u8 cck[B43_PPR_CCK_RATES_NUM];
+ u8 ofdm[B43_PPR_OFDM_RATES_NUM];
+ u8 ofdm_20_cdd[B43_PPR_OFDM_RATES_NUM];
+ u8 mcs_20[B43_PPR_MCS_RATES_NUM]; /* SISO */
+ u8 mcs_20_cdd[B43_PPR_MCS_RATES_NUM];
+ u8 mcs_20_stbc[B43_PPR_MCS_RATES_NUM];
+ u8 mcs_20_sdm[B43_PPR_MCS_RATES_NUM];
+};
+
+struct b43_ppr {
+ /* All powers are in qdbm (Q5.2) */
+ union {
+ u8 __all_rates[B43_PPR_RATES_NUM];
+ struct b43_ppr_rates rates;
+ };
+};
+
+struct b43_wldev;
+enum b43_band;
+
+void b43_ppr_clear(struct b43_wldev *dev, struct b43_ppr *ppr);
+
+void b43_ppr_add(struct b43_wldev *dev, struct b43_ppr *ppr, int diff);
+void b43_ppr_apply_max(struct b43_wldev *dev, struct b43_ppr *ppr, u8 max);
+void b43_ppr_apply_min(struct b43_wldev *dev, struct b43_ppr *ppr, u8 min);
+u8 b43_ppr_get_max(struct b43_wldev *dev, struct b43_ppr *ppr);
+
+bool b43_ppr_load_max_from_sprom(struct b43_wldev *dev, struct b43_ppr *ppr,
+ enum b43_band band);
+
+#endif /* LINUX_B43_PPR_H_ */
diff --git a/drivers/net/wireless/b43/radio_2059.c b/drivers/net/wireless/b43/radio_2059.c
index 38e31d857e3..a3cf9efd7e2 100644
--- a/drivers/net/wireless/b43/radio_2059.c
+++ b/drivers/net/wireless/b43/radio_2059.c
@@ -25,6 +25,13 @@
#include "b43.h"
#include "radio_2059.h"
+/* Extracted from MMIO dump of 6.30.223.141 */
+static u16 r2059_phy_rev1_init[][2] = {
+ { 0x051, 0x70 }, { 0x05a, 0x03 }, { 0x079, 0x01 }, { 0x082, 0x70 },
+ { 0x083, 0x00 }, { 0x084, 0x70 }, { 0x09a, 0x7f }, { 0x0b6, 0x10 },
+ { 0x188, 0x05 },
+};
+
#define RADIOREGS(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \
r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \
r20) \
@@ -58,73 +65,87 @@
.phy_regs.bw5 = r4, \
.phy_regs.bw6 = r5
+/* Extracted from MMIO dump of 6.30.223.141
+ * TODO: Values for channels 12 & 13 are outdated (from some old 5.x driver)!
+ */
static const struct b43_phy_ht_channeltab_e_radio2059 b43_phy_ht_channeltab_radio2059[] = {
- { .freq = 2412,
- RADIOREGS(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c,
- 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00),
- PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
- },
- { .freq = 2417,
- RADIOREGS(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71,
- 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00),
- PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
- },
- { .freq = 2422,
- RADIOREGS(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76,
- 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00),
- PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
- },
- { .freq = 2427,
- RADIOREGS(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b,
- 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00),
- PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
- },
- { .freq = 2432,
- RADIOREGS(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80,
- 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00),
- PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
- },
- { .freq = 2437,
- RADIOREGS(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85,
- 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00),
- PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
- },
- { .freq = 2442,
- RADIOREGS(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a,
- 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00),
- PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
- },
- { .freq = 2447,
- RADIOREGS(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f,
- 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00),
- PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
- },
- { .freq = 2452,
- RADIOREGS(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94,
- 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00),
- PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
- },
- { .freq = 2457,
- RADIOREGS(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99,
- 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00),
- PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
- },
- { .freq = 2462,
- RADIOREGS(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e,
- 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00),
- PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
- },
+ {
+ .freq = 2412,
+ RADIOREGS(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c,
+ 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73,
+ 0x00, 0x00, 0x00, 0xd0, 0x00),
+ PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
+ },
+ {
+ .freq = 2417,
+ RADIOREGS(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71,
+ 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73,
+ 0x00, 0x00, 0x00, 0xd0, 0x00),
+ PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
+ },
+ {
+ .freq = 2422,
+ RADIOREGS(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76,
+ 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x73,
+ 0x00, 0x00, 0x00, 0xd0, 0x00),
+ PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
+ },
+ {
+ .freq = 2427,
+ RADIOREGS(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b,
+ 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x73,
+ 0x00, 0x00, 0x00, 0xa0, 0x00),
+ PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
+ },
+ {
+ .freq = 2432,
+ RADIOREGS(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80,
+ 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x73,
+ 0x00, 0x00, 0x00, 0xa0, 0x00),
+ PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
+ },
+ {
+ .freq = 2437,
+ RADIOREGS(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85,
+ 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x73,
+ 0x00, 0x00, 0x00, 0xa0, 0x00),
+ PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
+ },
+ {
+ .freq = 2442,
+ RADIOREGS(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a,
+ 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73,
+ 0x00, 0x00, 0x00, 0x80, 0x00),
+ PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
+ },
+ {
+ .freq = 2447,
+ RADIOREGS(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f,
+ 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73,
+ 0x00, 0x00, 0x00, 0x80, 0x00),
+ PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
+ },
+ {
+ .freq = 2452,
+ RADIOREGS(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94,
+ 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73,
+ 0x00, 0x00, 0x00, 0x80, 0x00),
+ PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
+ },
+ {
+ .freq = 2457,
+ RADIOREGS(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99,
+ 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x73,
+ 0x00, 0x00, 0x00, 0x60, 0x00),
+ PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
+ },
+ {
+ .freq = 2462,
+ RADIOREGS(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e,
+ 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x73,
+ 0x00, 0x00, 0x00, 0x60, 0x00),
+ PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
+ },
{ .freq = 2467,
RADIOREGS(0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3,
0x09, 0x0f, 0x05, 0x00, 0x05, 0x00, 0x61, 0x03,
@@ -137,8 +158,196 @@ static const struct b43_phy_ht_channeltab_e_radio2059 b43_phy_ht_channeltab_radi
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429),
},
+ {
+ .freq = 5180,
+ RADIOREGS(0xbe, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x06,
+ 0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00,
+ 0x0f, 0x4f, 0xa3, 0x00, 0xfc),
+ PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb),
+ },
+ {
+ .freq = 5200,
+ RADIOREGS(0xc5, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x08,
+ 0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00,
+ 0x0f, 0x4f, 0x93, 0x00, 0xfb),
+ PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9),
+ },
+ {
+ .freq = 5220,
+ RADIOREGS(0xcc, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0a,
+ 0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00,
+ 0x0f, 0x4f, 0x93, 0x00, 0xea),
+ PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7),
+ },
+ {
+ .freq = 5240,
+ RADIOREGS(0xd2, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0c,
+ 0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00,
+ 0x0f, 0x4f, 0x93, 0x00, 0xda),
+ PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5),
+ },
+ {
+ .freq = 5260,
+ RADIOREGS(0xd9, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0e,
+ 0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00,
+ 0x0f, 0x4f, 0x93, 0x00, 0xca),
+ PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3),
+ },
+ {
+ .freq = 5280,
+ RADIOREGS(0xe0, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x10,
+ 0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00,
+ 0x0f, 0x4f, 0x93, 0x00, 0xb9),
+ PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1),
+ },
+ {
+ .freq = 5300,
+ RADIOREGS(0xe6, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x12,
+ 0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00,
+ 0x0f, 0x4c, 0x83, 0x00, 0xb8),
+ PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0),
+ },
+ {
+ .freq = 5320,
+ RADIOREGS(0xed, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x14,
+ 0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00,
+ 0x0f, 0x4c, 0x83, 0x00, 0xa8),
+ PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee),
+ },
+ {
+ .freq = 5500,
+ RADIOREGS(0x29, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x26,
+ 0x02, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00,
+ 0x0a, 0x46, 0x43, 0x00, 0x75),
+ PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd),
+ },
+ {
+ .freq = 5520,
+ RADIOREGS(0x30, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x28,
+ 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
+ 0x0a, 0x46, 0x43, 0x00, 0x75),
+ PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc),
+ },
+ {
+ .freq = 5540,
+ RADIOREGS(0x36, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2a,
+ 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
+ 0x0a, 0x46, 0x43, 0x00, 0x75),
+ PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da),
+ },
+ {
+ .freq = 5560,
+ RADIOREGS(0x3d, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2c,
+ 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
+ 0x0a, 0x46, 0x43, 0x00, 0x75),
+ PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8),
+ },
+ {
+ .freq = 5580,
+ RADIOREGS(0x44, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2e,
+ 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
+ 0x0a, 0x46, 0x43, 0x00, 0x74),
+ PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7),
+ },
+ {
+ .freq = 5600,
+ RADIOREGS(0x4a, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x30,
+ 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
+ 0x09, 0x44, 0x23, 0x00, 0x54),
+ PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5),
+ },
+ {
+ .freq = 5620,
+ RADIOREGS(0x51, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x32,
+ 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
+ 0x09, 0x44, 0x23, 0x00, 0x54),
+ PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3),
+ },
+ {
+ .freq = 5640,
+ RADIOREGS(0x58, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x34,
+ 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
+ 0x09, 0x44, 0x23, 0x00, 0x43),
+ PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2),
+ },
+ {
+ .freq = 5660,
+ RADIOREGS(0x5e, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x36,
+ 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
+ 0x09, 0x43, 0x23, 0x00, 0x43),
+ PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0),
+ },
+ {
+ .freq = 5680,
+ RADIOREGS(0x65, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x38,
+ 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
+ 0x09, 0x42, 0x23, 0x00, 0x43),
+ PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce),
+ },
+ {
+ .freq = 5700,
+ RADIOREGS(0x6c, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x3a,
+ 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
+ 0x08, 0x42, 0x13, 0x00, 0x32),
+ PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd),
+ },
+ {
+ .freq = 5745,
+ RADIOREGS(0x7b, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x7d,
+ 0x04, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00,
+ 0x08, 0x42, 0x13, 0x00, 0x21),
+ PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9),
+ },
+ {
+ .freq = 5765,
+ RADIOREGS(0x81, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x81,
+ 0x04, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00,
+ 0x08, 0x42, 0x13, 0x00, 0x11),
+ PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8),
+ },
+ {
+ .freq = 5785,
+ RADIOREGS(0x88, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x85,
+ 0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00,
+ 0x08, 0x42, 0x13, 0x00, 0x00),
+ PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6),
+ },
+ {
+ .freq = 5805,
+ RADIOREGS(0x8f, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x89,
+ 0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00,
+ 0x06, 0x41, 0x03, 0x00, 0x00),
+ PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4),
+ },
+ {
+ .freq = 5825,
+ RADIOREGS(0x95, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x8d,
+ 0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00,
+ 0x06, 0x41, 0x03, 0x00, 0x00),
+ PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3),
+ },
};
+void r2059_upload_inittabs(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 *table = NULL;
+ u16 size, i;
+
+ switch (phy->rev) {
+ case 1:
+ table = r2059_phy_rev1_init[0];
+ size = ARRAY_SIZE(r2059_phy_rev1_init);
+ break;
+ default:
+ B43_WARN_ON(1);
+ return;
+ }
+
+ for (i = 0; i < size; i++, table += 2)
+ b43_radio_write(dev, R2059_ALL | table[0], table[1]);
+}
+
const struct b43_phy_ht_channeltab_e_radio2059
*b43_phy_ht_get_channeltab_e_r2059(struct b43_wldev *dev, u16 freq)
{
diff --git a/drivers/net/wireless/b43/radio_2059.h b/drivers/net/wireless/b43/radio_2059.h
index 40a82d7f510..9e22fb60588 100644
--- a/drivers/net/wireless/b43/radio_2059.h
+++ b/drivers/net/wireless/b43/radio_2059.h
@@ -10,6 +10,18 @@
#define R2059_C3 0x800
#define R2059_ALL 0xC00
+#define R2059_RCAL_CONFIG 0x004
+#define R2059_RFPLL_MASTER 0x011
+#define R2059_RFPLL_MISC_EN 0x02b
+#define R2059_RFPLL_MISC_CAL_RESETN 0x02e
+#define R2059_XTAL_CONFIG2 0x0c0
+#define R2059_RCCAL_START_R1_Q1_P1 0x13c
+#define R2059_RCCAL_X1 0x13d
+#define R2059_RCCAL_TRC0 0x13e
+#define R2059_RCCAL_DONE_OSCCAP 0x140
+#define R2059_RCAL_STATUS 0x145
+#define R2059_RCCAL_MASTER 0x17f
+
/* Values for various registers uploaded on channel switching */
struct b43_phy_ht_channeltab_e_radio2059 {
/* The channel frequency in MHz */
@@ -40,6 +52,8 @@ struct b43_phy_ht_channeltab_e_radio2059 {
struct b43_phy_ht_channeltab_e_phy phy_regs;
};
+void r2059_upload_inittabs(struct b43_wldev *dev);
+
const struct b43_phy_ht_channeltab_e_radio2059
*b43_phy_ht_get_channeltab_e_r2059(struct b43_wldev *dev, u16 freq);
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index 4b5885077b0..25d1cbd3430 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -2878,6 +2878,40 @@ const s8 b43_ntab_papd_pga_gain_delta_ipa_2g[] = {
-54, -46, -39, -31, -23, -15, -8, 0
};
+/* Extracted from MMIO dump of 6.30.223.248
+ * Entries: 0, 15, 17, 21, 24, 26, 27, 29, 30 were guessed
+ */
+static const s16 b43_ntab_rf_pwr_offset_2057_rev9_2g[] = {
+ -133, -133, -107, -92, -81,
+ -73, -66, -61, -56, -52,
+ -48, -44, -41, -37, -34,
+ -31, -28, -25, -22, -19,
+ -17, -14, -12, -10, -9,
+ -7, -5, -4, -3, -2,
+ -1, 0,
+};
+
+/* Extracted from MMIO dump of 6.30.223.248 */
+static const s16 b43_ntab_rf_pwr_offset_2057_rev9_5g[] = {
+ -101, -94, -86, -79, -72,
+ -65, -57, -50, -42, -35,
+ -28, -21, -16, -9, -4,
+ 0,
+};
+
+/* Extracted from MMIO dump of 6.30.223.248
+ * Entries: 0, 26, 28, 29, 30, 31 were guessed
+ */
+static const s16 b43_ntab_rf_pwr_offset_2057_rev14_2g[] = {
+ -111, -111, -111, -84, -70,
+ -59, -52, -45, -40, -36,
+ -32, -29, -26, -23, -21,
+ -18, -16, -15, -13, -11,
+ -10, -8, -7, -6, -5,
+ -4, -4, -3, -3, -2,
+ -2, -1,
+};
+
const u16 tbl_iqcal_gainparams[2][9][8] = {
{
{ 0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69 },
@@ -3197,7 +3231,7 @@ static struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_workaround[2][4] = {
{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
0x527E, /* invalid for external LNA! */
{ 0x513F, 0x513F, 0x513F, 0x513F }, /* invalid for external LNA! */
- 0x1076, 0x0066, 0x0000, /* low is invalid (the last one) */
+ 0x007E, 0x0066, 0x0000, /* low is invalid (the last one) */
0x18, 0x18, 0x18,
0x01D0, 0x5,
},
@@ -3708,9 +3742,43 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev)
}
}
+const s16 *b43_ntab_get_rf_pwr_offset_table(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ switch (phy->rev) {
+ case 17:
+ if (phy->radio_rev == 14)
+ return b43_ntab_rf_pwr_offset_2057_rev14_2g;
+ break;
+ case 16:
+ if (phy->radio_rev == 9)
+ return b43_ntab_rf_pwr_offset_2057_rev9_2g;
+ break;
+ }
+
+ b43err(dev->wl,
+ "No 2GHz RF power table available for this device\n");
+ return NULL;
+ } else {
+ switch (phy->rev) {
+ case 16:
+ if (phy->radio_rev == 9)
+ return b43_ntab_rf_pwr_offset_2057_rev9_5g;
+ break;
+ }
+
+ b43err(dev->wl,
+ "No 5GHz RF power table available for this device\n");
+ return NULL;
+ }
+}
+
struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
struct b43_wldev *dev, bool ghz5, bool ext_lna)
{
+ struct b43_phy *phy = &dev->phy;
struct nphy_gain_ctl_workaround_entry *e;
u8 phy_idx;
@@ -3729,37 +3797,49 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
e = &nphy_gain_ctl_workaround[ghz5][phy_idx];
/* Some workarounds to the workarounds... */
- if (ghz5 && dev->phy.rev >= 6) {
- if (dev->phy.radio_rev == 11 &&
- !b43_is_40mhz(dev))
- e->cliplo_gain = 0x2d;
- } else if (!ghz5 && dev->phy.rev >= 5) {
- static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a,
- 0x106c, 0x1074, 0x107c, 0x207c};
+ if (!ghz5) {
u8 tr_iso = dev->dev->bus_sprom->fem.ghz2.tr_iso;
- if (ext_lna) {
+ if (tr_iso > 7)
+ tr_iso = 3;
+
+ if (phy->rev >= 6) {
+ static const int gain_data[] = { 0x106a, 0x106c, 0x1074,
+ 0x107c, 0x007e, 0x107e,
+ 0x207e, 0x307e, };
+
+ e->cliplo_gain = gain_data[tr_iso];
+ } else if (phy->rev == 5) {
+ static const int gain_data[] = { 0x0062, 0x0064, 0x006a,
+ 0x106a, 0x106c, 0x1074,
+ 0x107c, 0x207c, };
+
+ e->cliplo_gain = gain_data[tr_iso];
+ }
+
+ if (phy->rev >= 5 && ext_lna) {
e->rfseq_init[0] &= ~0x4000;
e->rfseq_init[1] &= ~0x4000;
e->rfseq_init[2] &= ~0x4000;
e->rfseq_init[3] &= ~0x4000;
e->init_gain &= ~0x4000;
}
- if (tr_iso > 7)
- tr_iso = 3;
- e->cliplo_gain = gain_data[tr_iso];
-
- } else if (ghz5 && dev->phy.rev == 4 && ext_lna) {
- e->rfseq_init[0] &= ~0x4000;
- e->rfseq_init[1] &= ~0x4000;
- e->rfseq_init[2] &= ~0x4000;
- e->rfseq_init[3] &= ~0x4000;
- e->init_gain &= ~0x4000;
- e->rfseq_init[0] |= 0x1000;
- e->rfseq_init[1] |= 0x1000;
- e->rfseq_init[2] |= 0x1000;
- e->rfseq_init[3] |= 0x1000;
- e->init_gain |= 0x1000;
+ } else {
+ if (phy->rev >= 6) {
+ if (phy->radio_rev == 11 && !b43_is_40mhz(dev))
+ e->crsminu = 0x2d;
+ } else if (phy->rev == 4 && ext_lna) {
+ e->rfseq_init[0] &= ~0x4000;
+ e->rfseq_init[1] &= ~0x4000;
+ e->rfseq_init[2] &= ~0x4000;
+ e->rfseq_init[3] &= ~0x4000;
+ e->init_gain &= ~0x4000;
+ e->rfseq_init[0] |= 0x1000;
+ e->rfseq_init[1] |= 0x1000;
+ e->rfseq_init[2] |= 0x1000;
+ e->rfseq_init[3] |= 0x1000;
+ e->init_gain |= 0x1000;
+ }
}
return e;
diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h
index 3ce2e6f3a27..b51f386db02 100644
--- a/drivers/net/wireless/b43/tables_nphy.h
+++ b/drivers/net/wireless/b43/tables_nphy.h
@@ -191,6 +191,8 @@ void b43_nphy_tables_init(struct b43_wldev *dev);
const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev);
+const s16 *b43_ntab_get_rf_pwr_offset_table(struct b43_wldev *dev);
+
extern const s8 b43_ntab_papd_pga_gain_delta_ipa_2g[];
extern const u16 tbl_iqcal_gainparams[2][9][8];
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index 98d90747836..ba611530806 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -97,9 +97,13 @@ struct b43_tx_legacy_rate_phy_ctl_entry {
};
/* MAC TX control */
+#define B43_TXH_MAC_RTS_FB_SHORTPRMBL 0x80000000 /* RTS fallback preamble */
+#define B43_TXH_MAC_RTS_SHORTPRMBL 0x40000000 /* RTS main rate preamble */
+#define B43_TXH_MAC_FB_SHORTPRMBL 0x20000000 /* Main fallback preamble */
#define B43_TXH_MAC_USEFBR 0x10000000 /* Use fallback rate for this AMPDU */
#define B43_TXH_MAC_KEYIDX 0x0FF00000 /* Security key index */
#define B43_TXH_MAC_KEYIDX_SHIFT 20
+#define B43_TXH_MAC_ALT_TXPWR 0x00080000 /* Use alternate txpwr defined at loc. M_ALT_TXPWR_IDX */
#define B43_TXH_MAC_KEYALG 0x00070000 /* Security key algorithm */
#define B43_TXH_MAC_KEYALG_SHIFT 16
#define B43_TXH_MAC_AMIC 0x00008000 /* AMIC */
@@ -126,25 +130,25 @@ struct b43_tx_legacy_rate_phy_ctl_entry {
#define B43_TXH_EFT_FB 0x03 /* Data frame fallback encoding */
#define B43_TXH_EFT_FB_CCK 0x00 /* CCK */
#define B43_TXH_EFT_FB_OFDM 0x01 /* OFDM */
-#define B43_TXH_EFT_FB_EWC 0x02 /* EWC */
-#define B43_TXH_EFT_FB_N 0x03 /* N */
+#define B43_TXH_EFT_FB_HT 0x02 /* HT */
+#define B43_TXH_EFT_FB_VHT 0x03 /* VHT */
#define B43_TXH_EFT_RTS 0x0C /* RTS/CTS encoding */
#define B43_TXH_EFT_RTS_CCK 0x00 /* CCK */
#define B43_TXH_EFT_RTS_OFDM 0x04 /* OFDM */
-#define B43_TXH_EFT_RTS_EWC 0x08 /* EWC */
-#define B43_TXH_EFT_RTS_N 0x0C /* N */
+#define B43_TXH_EFT_RTS_HT 0x08 /* HT */
+#define B43_TXH_EFT_RTS_VHT 0x0C /* VHT */
#define B43_TXH_EFT_RTSFB 0x30 /* RTS/CTS fallback encoding */
#define B43_TXH_EFT_RTSFB_CCK 0x00 /* CCK */
#define B43_TXH_EFT_RTSFB_OFDM 0x10 /* OFDM */
-#define B43_TXH_EFT_RTSFB_EWC 0x20 /* EWC */
-#define B43_TXH_EFT_RTSFB_N 0x30 /* N */
+#define B43_TXH_EFT_RTSFB_HT 0x20 /* HT */
+#define B43_TXH_EFT_RTSFB_VHT 0x30 /* VHT */
/* PHY TX control word */
#define B43_TXH_PHY_ENC 0x0003 /* Data frame encoding */
#define B43_TXH_PHY_ENC_CCK 0x0000 /* CCK */
#define B43_TXH_PHY_ENC_OFDM 0x0001 /* OFDM */
-#define B43_TXH_PHY_ENC_EWC 0x0002 /* EWC */
-#define B43_TXH_PHY_ENC_N 0x0003 /* N */
+#define B43_TXH_PHY_ENC_HT 0x0002 /* HT */
+#define B43_TXH_PHY_ENC_VHT 0x0003 /* VHT */
#define B43_TXH_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
#define B43_TXH_PHY_ANT 0x03C0 /* Antenna selection */
#define B43_TXH_PHY_ANT0 0x0000 /* Use antenna 0 */
@@ -162,7 +166,7 @@ struct b43_tx_legacy_rate_phy_ctl_entry {
#define B43_TXH_PHY1_BW_20 0x0002 /* 20 MHz */
#define B43_TXH_PHY1_BW_20U 0x0003 /* 20 MHz upper */
#define B43_TXH_PHY1_BW_40 0x0004 /* 40 MHz */
-#define B43_TXH_PHY1_BW_40DUP 0x0005 /* 50 MHz duplicate */
+#define B43_TXH_PHY1_BW_40DUP 0x0005 /* 40 MHz duplicate */
#define B43_TXH_PHY1_MODE 0x0038 /* Mode */
#define B43_TXH_PHY1_MODE_SISO 0x0000 /* SISO */
#define B43_TXH_PHY1_MODE_CDD 0x0008 /* CDD */
diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig
index b8e2561ea64..fe3dc126b14 100644
--- a/drivers/net/wireless/brcm80211/Kconfig
+++ b/drivers/net/wireless/brcm80211/Kconfig
@@ -27,10 +27,17 @@ config BRCMFMAC
one of the bus interface support. If you choose to build a module,
it'll be called brcmfmac.ko.
+config BRCMFMAC_PROTO_BCDC
+ bool
+
+config BRCMFMAC_PROTO_MSGBUF
+ bool
+
config BRCMFMAC_SDIO
bool "SDIO bus interface support for FullMAC driver"
depends on (MMC = y || MMC = BRCMFMAC)
depends on BRCMFMAC
+ select BRCMFMAC_PROTO_BCDC
select FW_LOADER
default y
---help---
@@ -42,6 +49,7 @@ config BRCMFMAC_USB
bool "USB bus interface support for FullMAC driver"
depends on (USB = y || USB = BRCMFMAC)
depends on BRCMFMAC
+ select BRCMFMAC_PROTO_BCDC
select FW_LOADER
---help---
This option enables the USB bus interface support for Broadcom
@@ -52,6 +60,8 @@ config BRCMFMAC_PCIE
bool "PCIE bus interface support for FullMAC driver"
depends on BRCMFMAC
depends on PCI
+ depends on HAS_DMA
+ select BRCMFMAC_PROTO_MSGBUF
select FW_LOADER
---help---
This option enables the PCIE bus interface support for Broadcom
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
index c35adf4bc70..90a977fe9a6 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -30,16 +30,18 @@ brcmfmac-objs += \
fwsignal.o \
p2p.o \
proto.o \
- bcdc.o \
- commonring.o \
- flowring.o \
- msgbuf.o \
dhd_common.o \
dhd_linux.o \
firmware.o \
feature.o \
btcoex.o \
vendor.o
+brcmfmac-$(CONFIG_BRCMFMAC_PROTO_BCDC) += \
+ bcdc.o
+brcmfmac-$(CONFIG_BRCMFMAC_PROTO_MSGBUF) += \
+ commonring.o \
+ flowring.o \
+ msgbuf.o
brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
dhd_sdio.o \
bcmsdh.o
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.h b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.h
index 17e8c039ff3..6003179c0ce 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.h
@@ -16,9 +16,12 @@
#ifndef BRCMFMAC_BCDC_H
#define BRCMFMAC_BCDC_H
-
+#ifdef CONFIG_BRCMFMAC_PROTO_BCDC
int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr);
void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr);
-
+#else
+static inline int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) { return 0; }
+static inline void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) {}
+#endif
#endif /* BRCMFMAC_BCDC_H */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
index 4f1daabc551..44fc85f68f7 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
@@ -185,7 +185,13 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
ifevent->action, ifevent->ifidx, ifevent->bssidx,
ifevent->flags, ifevent->role);
- if (ifevent->flags & BRCMF_E_IF_FLAG_NOIF) {
+ /* The P2P Device interface event must not be ignored
+ * contrary to what firmware tells us. The only way to
+ * distinguish the P2P Device is by looking at the ifidx
+ * and bssidx received.
+ */
+ if (!(ifevent->ifidx == 0 && ifevent->bssidx == 1) &&
+ (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) {
brcmf_dbg(EVENT, "event can be ignored\n");
return;
}
@@ -210,12 +216,12 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
return;
}
- if (ifevent->action == BRCMF_E_IF_CHANGE)
+ if (ifp && ifevent->action == BRCMF_E_IF_CHANGE)
brcmf_fws_reset_interface(ifp);
err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
- if (ifevent->action == BRCMF_E_IF_DEL) {
+ if (ifp && ifevent->action == BRCMF_E_IF_DEL) {
brcmf_fws_del_interface(ifp);
brcmf_del_if(drvr, ifevent->bssidx);
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
index dd20b1862d4..cbf033f5910 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
@@ -172,6 +172,8 @@ enum brcmf_fweh_event_code {
#define BRCMF_E_IF_ROLE_STA 0
#define BRCMF_E_IF_ROLE_AP 1
#define BRCMF_E_IF_ROLE_WDS 2
+#define BRCMF_E_IF_ROLE_P2P_GO 3
+#define BRCMF_E_IF_ROLE_P2P_CLIENT 4
/**
* definitions for event packet validation.
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h
index f901ae52bf2..77a51b8c1e1 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h
@@ -15,6 +15,7 @@
#ifndef BRCMFMAC_MSGBUF_H
#define BRCMFMAC_MSGBUF_H
+#ifdef CONFIG_BRCMFMAC_PROTO_MSGBUF
#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM 20
#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 256
@@ -32,9 +33,15 @@
int brcmf_proto_msgbuf_rx_trigger(struct device *dev);
+void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid);
int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr);
void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr);
-void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid);
-
+#else
+static inline int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
+{
+ return 0;
+}
+static inline void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr) {}
+#endif
#endif /* BRCMFMAC_MSGBUF_H */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
index 057b982ea8b..1d78a91db59 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -1431,8 +1431,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
IEEE80211_BAND_5GHZ);
wdev = &ifp->vif->wdev;
- cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0,
- GFP_ATOMIC);
+ cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0);
kfree(mgmt_frame);
return 0;
@@ -1896,8 +1895,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
IEEE80211_BAND_2GHZ :
IEEE80211_BAND_5GHZ);
- cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0,
- GFP_ATOMIC);
+ cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
mgmt_frame_len, e->datalen, chanspec, freq);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 02fe706fc9e..1db11b00001 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -497,8 +497,11 @@ brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
static void
brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
{
- struct net_device *ndev = wdev->netdev;
- struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_vif *vif;
+ struct brcmf_if *ifp;
+
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+ ifp = vif->ifp;
if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
(wdev->iftype == NL80211_IFTYPE_AP) ||
@@ -2394,9 +2397,13 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
- bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
- 0, notify_capability, notify_interval, notify_ie,
- notify_ielen, notify_signal, GFP_KERNEL);
+ bss = cfg80211_inform_bss(wiphy, notify_channel,
+ CFG80211_BSS_FTYPE_UNKNOWN,
+ (const u8 *)bi->BSSID,
+ 0, notify_capability,
+ notify_interval, notify_ie,
+ notify_ielen, notify_signal,
+ GFP_KERNEL);
if (!bss)
return -ENOMEM;
@@ -2498,9 +2505,11 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
brcmf_dbg(CONN, "signal: %d\n", notify_signal);
- bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
- 0, notify_capability, notify_interval,
- notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
+ bss = cfg80211_inform_bss(wiphy, notify_channel,
+ CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
+ notify_capability, notify_interval,
+ notify_ie, notify_ielen, notify_signal,
+ GFP_KERNEL);
if (!bss) {
err = -ENOMEM;
@@ -4918,7 +4927,7 @@ static void brcmf_count_20mhz_channels(struct brcmf_cfg80211_info *cfg,
struct brcmu_chan ch;
int i;
- for (i = 0; i <= total; i++) {
+ for (i = 0; i < total; i++) {
ch.chspec = (u16)le32_to_cpu(chlist->element[i]);
cfg->d11inf.decchspec(&ch);
@@ -5143,6 +5152,7 @@ static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
ch.band = BRCMU_CHAN_BAND_2G;
ch.bw = BRCMU_CHAN_BW_40;
+ ch.sb = BRCMU_CHAN_SB_NONE;
ch.chnum = 0;
cfg->d11inf.encchspec(&ch);
@@ -5176,6 +5186,7 @@ static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
}
+ kfree(pbuf);
}
return err;
}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c
index 4fb9635d391..796f5f9d5d5 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c
@@ -746,7 +746,7 @@ dma64_dd_upd(struct dma_info *di, struct dma64desc *ddring,
/* !! may be called with core in reset */
void dma_detach(struct dma_pub *pub)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
brcms_dbg_dma(di->core, "%s:\n", di->name);
@@ -842,7 +842,7 @@ static void _dma_rxenable(struct dma_info *di)
void dma_rxinit(struct dma_pub *pub)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
brcms_dbg_dma(di->core, "%s:\n", di->name);
@@ -924,7 +924,7 @@ static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall)
*/
int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
struct sk_buff_head dma_frames;
struct sk_buff *p, *next;
uint len;
@@ -1022,7 +1022,7 @@ static bool dma64_txidle(struct dma_info *di)
*/
bool dma_rxfill(struct dma_pub *pub)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
struct sk_buff *p;
u16 rxin, rxout;
u32 flags = 0;
@@ -1106,7 +1106,7 @@ bool dma_rxfill(struct dma_pub *pub)
void dma_rxreclaim(struct dma_pub *pub)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
struct sk_buff *p;
brcms_dbg_dma(di->core, "%s:\n", di->name);
@@ -1126,7 +1126,7 @@ void dma_counterreset(struct dma_pub *pub)
/* get the address of the var in order to change later */
unsigned long dma_getvar(struct dma_pub *pub, const char *name)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
if (!strcmp(name, "&txavail"))
return (unsigned long)&(di->dma.txavail);
@@ -1137,7 +1137,7 @@ unsigned long dma_getvar(struct dma_pub *pub, const char *name)
void dma_txinit(struct dma_pub *pub)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
u32 control = D64_XC_XE;
brcms_dbg_dma(di->core, "%s:\n", di->name);
@@ -1170,7 +1170,7 @@ void dma_txinit(struct dma_pub *pub)
void dma_txsuspend(struct dma_pub *pub)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
brcms_dbg_dma(di->core, "%s:\n", di->name);
@@ -1182,7 +1182,7 @@ void dma_txsuspend(struct dma_pub *pub)
void dma_txresume(struct dma_pub *pub)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
brcms_dbg_dma(di->core, "%s:\n", di->name);
@@ -1194,7 +1194,7 @@ void dma_txresume(struct dma_pub *pub)
bool dma_txsuspended(struct dma_pub *pub)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
return (di->ntxd == 0) ||
((bcma_read32(di->core,
@@ -1204,7 +1204,7 @@ bool dma_txsuspended(struct dma_pub *pub)
void dma_txreclaim(struct dma_pub *pub, enum txd_range range)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
struct sk_buff *p;
brcms_dbg_dma(di->core, "%s: %s\n",
@@ -1225,7 +1225,7 @@ void dma_txreclaim(struct dma_pub *pub, enum txd_range range)
bool dma_txreset(struct dma_pub *pub)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
u32 status;
if (di->ntxd == 0)
@@ -1252,7 +1252,7 @@ bool dma_txreset(struct dma_pub *pub)
bool dma_rxreset(struct dma_pub *pub)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
u32 status;
if (di->nrxd == 0)
@@ -1377,7 +1377,7 @@ static void dma_update_txavail(struct dma_info *di)
int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub,
struct sk_buff *p)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
struct brcms_ampdu_session *session = &di->ampdu_session;
struct ieee80211_tx_info *tx_info;
bool is_ampdu;
@@ -1427,7 +1427,7 @@ int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub,
void dma_txflush(struct dma_pub *pub)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
struct brcms_ampdu_session *session = &di->ampdu_session;
if (!skb_queue_empty(&session->skb_list))
@@ -1436,7 +1436,7 @@ void dma_txflush(struct dma_pub *pub)
int dma_txpending(struct dma_pub *pub)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
return ntxdactive(di, di->txin, di->txout);
}
@@ -1446,7 +1446,7 @@ int dma_txpending(struct dma_pub *pub)
*/
void dma_kick_tx(struct dma_pub *pub)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
struct brcms_ampdu_session *session = &di->ampdu_session;
if (!skb_queue_empty(&session->skb_list) && dma64_txidle(di))
@@ -1465,7 +1465,7 @@ void dma_kick_tx(struct dma_pub *pub)
*/
struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
{
- struct dma_info *di = (struct dma_info *)pub;
+ struct dma_info *di = container_of(pub, struct dma_info, dma);
u16 start, end, i;
u16 active_desc;
struct sk_buff *txp;
@@ -1547,7 +1547,7 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc)
(void *pkt, void *arg_a), void *arg_a)
{
- struct dma_info *di = (struct dma_info *) dmah;
+ struct dma_info *di = container_of(dmah, struct dma_info, dma);
uint i = di->txin;
uint end = di->txout;
struct sk_buff *skb;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
index 57ecc05802e..941b1e41f36 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
@@ -128,19 +128,19 @@ static const u8 ofdm_rate_lookup[] = {
void wlc_phyreg_enter(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
}
void wlc_phyreg_exit(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
}
void wlc_radioreg_enter(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
udelay(10);
@@ -148,7 +148,7 @@ void wlc_radioreg_enter(struct brcms_phy_pub *pih)
void wlc_radioreg_exit(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
(void)bcma_read16(pi->d11core, D11REGOFFS(phyversion));
pi->phy_wreg = 0;
@@ -586,7 +586,7 @@ err:
void wlc_phy_detach(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (pih) {
if (--pi->refcnt)
@@ -613,7 +613,7 @@ bool
wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev,
u16 *radioid, u16 *radiover)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
*phytype = (u16) pi->pubpi.phy_type;
*phyrev = (u16) pi->pubpi.phy_rev;
*radioid = pi->pubpi.radioid;
@@ -624,19 +624,19 @@ wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev,
bool wlc_phy_get_encore(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
return pi->pubpi.abgphy_encore;
}
u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
return pi->pubpi.coreflags;
}
void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (ISNPHY(pi)) {
if (on) {
@@ -673,7 +673,7 @@ void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on)
u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
u32 phy_bw_clkbits = 0;
@@ -698,14 +698,14 @@ u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih)
void wlc_phy_por_inform(struct brcms_phy_pub *ppi)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->phy_init_por = true;
}
void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
pi->edcrs_threshold_lock = lock;
@@ -717,14 +717,14 @@ void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock)
void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
pi->do_initcal = initcal;
}
void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (!pi || !pi->sh)
return;
@@ -734,7 +734,7 @@ void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate)
void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (!pi || !pi->sh)
return;
@@ -746,7 +746,7 @@ void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec)
{
u32 mc;
void (*phy_init)(struct brcms_phy *) = NULL;
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (pi->init_in_progress)
return;
@@ -798,7 +798,7 @@ void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec)
void wlc_phy_cal_init(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
void (*cal_init)(struct brcms_phy *) = NULL;
if (WARN((bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
@@ -816,7 +816,7 @@ void wlc_phy_cal_init(struct brcms_phy_pub *pih)
int wlc_phy_down(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
int callbacks = 0;
if (pi->phycal_timer
@@ -1070,7 +1070,7 @@ void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on)
void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (set)
mboolset(pi->measure_hold, id);
@@ -1082,7 +1082,7 @@ void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set)
void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (mute)
mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
@@ -1096,7 +1096,7 @@ void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags)
void wlc_phy_clear_tssi(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (ISNPHY(pi)) {
return;
@@ -1115,7 +1115,7 @@ static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi)
void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
(void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
if (ISNPHY(pi)) {
@@ -1149,35 +1149,35 @@ void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on)
u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
return pi->bw;
}
void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->bw = bw;
}
void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->radio_chanspec = newch;
}
u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
return pi->radio_chanspec;
}
void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
u16 m_cur_channel;
void (*chanspec_set)(struct brcms_phy *, u16) = NULL;
m_cur_channel = CHSPEC_CHANNEL(chanspec);
@@ -1226,7 +1226,7 @@ int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec)
void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi,
bool wide_filter)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->channel_14_wide_filter = wide_filter;
@@ -1246,7 +1246,7 @@ void
wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,
struct brcms_chanvec *channels)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
uint i;
uint channel;
@@ -1267,7 +1267,7 @@ wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,
u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
uint i;
uint channel;
u16 chspec;
@@ -1311,7 +1311,7 @@ u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band)
int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
*qdbm = pi->tx_user_target[0];
if (override != NULL)
@@ -1323,7 +1323,7 @@ void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi,
struct txpwr_limits *txpwr)
{
bool mac_enabled = false;
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
memcpy(&pi->tx_user_target[TXP_FIRST_CCK],
&txpwr->cck[0], BRCMS_NUM_RATES_CCK);
@@ -1371,7 +1371,7 @@ void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi,
int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
int i;
if (qdbm > 127)
@@ -1407,7 +1407,7 @@ void
wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr,
u8 *max_pwr, int txp_rate_idx)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
uint i;
*min_pwr = pi->min_txpower * BRCMS_TXPWR_DB_FACTOR;
@@ -1456,7 +1456,7 @@ void
wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan,
u8 *max_txpwr, u8 *min_txpwr)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
u8 tx_pwr_max = 0;
u8 tx_pwr_min = 255;
u8 max_num_rate;
@@ -1493,14 +1493,14 @@ wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint bandunit,
u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
return pi->tx_power_min;
}
u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
return pi->tx_power_max;
}
@@ -1812,21 +1812,21 @@ wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr,
void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->txpwr_percent = txpwr_percent;
}
void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->sh->machwcap = machwcap;
}
void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
u16 rxc;
rxc = 0;
@@ -1857,7 +1857,7 @@ void
wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr,
u16 chanspec)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
@@ -1881,14 +1881,14 @@ wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr,
void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
pi->ofdm_rateset_war = war;
}
void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
pi->bf_preempt_4306 = bf_preempt;
}
@@ -1945,7 +1945,7 @@ void wlc_phy_txpower_update_shm(struct brcms_phy *pi)
bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
if (ISNPHY(pi))
return pi->nphy_txpwrctrl;
@@ -1955,7 +1955,7 @@ bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi)
void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
bool suspend;
if (!pi->hwpwrctrl_capable)
@@ -2038,7 +2038,7 @@ void
wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power,
uint channel)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
uint rate, num_rates;
u8 min_pwr, max_pwr;
@@ -2136,21 +2136,21 @@ wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power,
void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
pi->antsel_type = antsel_type;
}
bool wlc_phy_test_ison(struct brcms_phy_pub *ppi)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
return pi->phytest_on;
}
void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
bool suspend;
pi->sh->rx_antdiv = val;
@@ -2283,7 +2283,7 @@ static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi)
void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
u16 jssi_aux;
u8 channel = 0;
s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
@@ -2339,7 +2339,7 @@ void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih)
static void
wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
bool sampling_in_progress = (pi->phynoise_state != 0);
bool wait_for_intr = true;
@@ -2531,7 +2531,7 @@ int wlc_phy_rssi_compute(struct brcms_phy_pub *pih,
{
int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK;
uint radioid = pih->radioid;
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if ((pi->sh->corerev >= 11)
&& !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) {
@@ -2591,7 +2591,7 @@ void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag)
void wlc_phy_watchdog(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
bool delay_phy_cal = false;
pi->sh->now++;
@@ -2651,7 +2651,7 @@ void wlc_phy_watchdog(struct brcms_phy_pub *pih)
void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
uint i;
uint k;
@@ -2711,7 +2711,7 @@ void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason)
s16 nphy_currtemp = 0;
s16 delta_temp = 0;
bool do_periodic_cal = true;
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
if (!ISNPHY(pi))
return;
@@ -2804,7 +2804,7 @@ u8 wlc_phy_nbits(s32 value)
void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
pi->sh->hw_phytxchain = txchain;
pi->sh->hw_phyrxchain = rxchain;
@@ -2815,7 +2815,7 @@ void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
pi->sh->phytxchain = txchain;
@@ -2827,7 +2827,7 @@ void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
*txchain = pi->sh->phytxchain;
*rxchain = pi->sh->phyrxchain;
@@ -2837,7 +2837,7 @@ u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih)
{
s16 nphy_currtemp;
u8 active_bitmap;
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
@@ -2867,7 +2867,7 @@ u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih)
s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
u8 siso_mcs_id, cdd_mcs_id;
siso_mcs_id =
@@ -2944,7 +2944,7 @@ s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec)
bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
if (ISNPHY(pi))
return wlc_phy_n_txpower_ipa_ison(pi);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
index b2d6d6da3da..5f1366234a0 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
@@ -2865,7 +2865,7 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
{
bool suspend, tx_gain_override_old;
struct lcnphy_txgains old_gains;
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
idleTssi0_regvalue_2C;
u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
@@ -3084,7 +3084,7 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
s32 a1, b0, b1;
s32 tssi, pwr, maxtargetpwr, mintargetpwr;
bool suspend;
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
MCTL_EN_MAC));
@@ -4348,7 +4348,7 @@ void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
{
s8 index;
u16 index2;
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
index 93869e89aa3..084f18f4f95 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
@@ -14121,7 +14121,7 @@ static u8 ant_sw_ctrl_tbl_rev8_2057v7_core1[] = {
bool wlc_phy_bist_check_phy(struct brcms_phy_pub *pih)
{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
u32 phybist0, phybist1, phybist2, phybist3, phybist4;
if (NREV_GE(pi->pubpi.phy_rev, 16))
@@ -19734,7 +19734,7 @@ void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask)
u16 regval;
u16 tbl_buf[16];
uint i;
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
u16 tbl_opcode;
bool suspend;
@@ -19812,7 +19812,7 @@ void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask)
u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih)
{
u16 regval, rxen_bits;
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
regval = read_phy_reg(pi, 0xa2);
rxen_bits = (regval >> 4) & 0xf;
@@ -21342,7 +21342,7 @@ void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, u16 chanspec)
void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init)
{
- struct brcms_phy *pi = (struct brcms_phy *) ppi;
+ struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
u16 mask = 0xfc00;
u32 mc = 0;
diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c
index 40078f5f932..964b64ab7fe 100644
--- a/drivers/net/wireless/cw1200/cw1200_spi.c
+++ b/drivers/net/wireless/cw1200/cw1200_spi.c
@@ -398,7 +398,7 @@ static int cw1200_spi_probe(struct spi_device *func)
return -1;
}
- self = kzalloc(sizeof(*self), GFP_KERNEL);
+ self = devm_kzalloc(&func->dev, sizeof(*self), GFP_KERNEL);
if (!self) {
pr_err("Can't allocate SPI hwbus_priv.");
return -ENOMEM;
@@ -424,7 +424,6 @@ static int cw1200_spi_probe(struct spi_device *func)
if (status) {
cw1200_spi_irq_unsubscribe(self);
cw1200_spi_off(plat_data);
- kfree(self);
}
return status;
@@ -441,7 +440,6 @@ static int cw1200_spi_disconnect(struct spi_device *func)
cw1200_core_release(self->core);
self->core = NULL;
}
- kfree(self);
}
cw1200_spi_off(dev_get_platdata(&func->dev));
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c
index 4e5c0f8c949..8efd17c52f6 100644
--- a/drivers/net/wireless/hostap/hostap_proc.c
+++ b/drivers/net/wireless/hostap/hostap_proc.c
@@ -186,11 +186,9 @@ static int prism2_bss_list_proc_show(struct seq_file *m, void *v)
bss->ssid[i] : '_');
seq_putc(m, '\t');
- for (i = 0; i < bss->ssid_len; i++)
- seq_printf(m, "%02x", bss->ssid[i]);
+ seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid);
seq_putc(m, '\t');
- for (i = 0; i < bss->wpa_ie_len; i++)
- seq_printf(m, "%02x", bss->wpa_ie[i]);
+ seq_printf(m, "%*phN", (int)bss->wpa_ie_len, bss->wpa_ie);
seq_putc(m, '\n');
return 0;
}
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index a42f9c33509..f0c3c77a48d 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -5552,7 +5552,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
min(network->ssid_len, priv->essid_len)))) {
char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
- strncpy(escaped,
+ strlcpy(escaped,
print_ssid(ssid, network->ssid,
network->ssid_len),
sizeof(escaped));
@@ -5765,7 +5765,7 @@ static int ipw_best_network(struct ipw_priv *priv,
memcmp(network->ssid, priv->essid,
min(network->ssid_len, priv->essid_len)))) {
char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
- strncpy(escaped,
+ strlcpy(escaped,
print_ssid(ssid, network->ssid,
network->ssid_len),
sizeof(escaped));
@@ -5782,7 +5782,7 @@ static int ipw_best_network(struct ipw_priv *priv,
* testing everything else. */
if (match->network && match->network->stats.rssi > network->stats.rssi) {
char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
- strncpy(escaped,
+ strlcpy(escaped,
print_ssid(ssid, network->ssid, network->ssid_len),
sizeof(escaped));
IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because "
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 3dcbe2cd2b2..26fec54dcd0 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -4633,7 +4633,7 @@ il4965_store_tx_power(struct device *d, struct device_attribute *attr,
else {
ret = il_set_tx_power(il, val, false);
if (ret)
- IL_ERR("failed setting tx power (0x%d).\n", ret);
+ IL_ERR("failed setting tx power (0x%08x).\n", ret);
else
ret = count;
}
@@ -5757,9 +5757,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
if (il->cfg->sku & IL_SKU_N)
- hw->flags |=
- IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
- IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+ hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS |
+ NL80211_FEATURE_STATIC_SMPS;
hw->sta_data_size = sizeof(struct il_station_priv);
hw->vif_data_size = sizeof(struct il_vif_priv);
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 6451d2b6abc..267e48a2915 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -51,7 +51,6 @@ config IWLWIFI_LEDS
config IWLDVM
tristate "Intel Wireless WiFi DVM Firmware support"
- depends on m
default IWLWIFI
help
This is the driver that supports the DVM firmware which is
@@ -60,7 +59,6 @@ config IWLDVM
config IWLMVM
tristate "Intel Wireless WiFi MVM Firmware support"
- depends on m
help
This is the driver that supports the MVM firmware which is
currently only available for 7260 and 3160 devices.
@@ -87,6 +85,16 @@ config IWLWIFI_BCAST_FILTERING
If unsure, don't enable this option, as some programs might
expect incoming broadcasts for their normal operations.
+config IWLWIFI_UAPSD
+ bool "enable U-APSD by default"
+ depends on IWLMVM
+ help
+ Say Y here to enable U-APSD by default. This may cause
+ interoperability problems with some APs, manifesting in lower than
+ expected throughput due to those APs not enabling aggregation
+
+ If unsure, say N.
+
menu "Debugging Options"
config IWLWIFI_DEBUG
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index afb98f4fdaf..2364a3c09b9 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -125,8 +125,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
*/
if (priv->nvm_data->sku_cap_11n_enable)
- hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
- IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+ hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS |
+ NL80211_FEATURE_STATIC_SMPS;
/*
* Enable 11w if advertised by firmware and software crypto
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.c b/drivers/net/wireless/iwlwifi/dvm/power.c
index 760c45c34ef..1513dbc79c1 100644
--- a/drivers/net/wireless/iwlwifi/dvm/power.c
+++ b/drivers/net/wireless/iwlwifi/dvm/power.c
@@ -40,7 +40,7 @@
#include "commands.h"
#include "power.h"
-static bool force_cam;
+static bool force_cam = true;
module_param(force_cam, bool, 0644);
MODULE_PARM_DESC(force_cam, "force continuously aware mode (no power saving at all)");
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c
index 6dc5dd3ced4..ed50de6362e 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rxon.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c
@@ -1068,6 +1068,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
/* recalculate basic rates */
iwl_calc_basic_rates(priv, ctx);
+ /*
+ * force CTS-to-self frames protection if RTS-CTS is not preferred
+ * one aggregation protection method
+ */
+ if (!priv->hw_params.use_rts_for_aggregation)
+ ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
+
if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK))
ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
@@ -1473,6 +1480,11 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
else
ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+ if (bss_conf->use_cts_prot)
+ ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
+ else
+ ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
+
memcpy(ctx->staging.bssid_addr, bss_conf->bssid, ETH_ALEN);
if (vif->type == NL80211_IFTYPE_AP ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
index 3255a1723d1..d1ce3ce1359 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tx.c
@@ -580,7 +580,7 @@ turn_off:
* time, or we hadn't time to drain the AC queues.
*/
if (agg_state == IWL_AGG_ON)
- iwl_trans_txq_disable(priv->trans, txq_id);
+ iwl_trans_txq_disable(priv->trans, txq_id, true);
else
IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
agg_state);
@@ -686,7 +686,7 @@ int iwlagn_tx_agg_flush(struct iwl_priv *priv, struct ieee80211_vif *vif,
* time, or we hadn't time to drain the AC queues.
*/
if (agg_state == IWL_AGG_ON)
- iwl_trans_txq_disable(priv->trans, txq_id);
+ iwl_trans_txq_disable(priv->trans, txq_id, true);
else
IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
agg_state);
@@ -781,7 +781,7 @@ static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid)
"Can continue DELBA flow ssn = next_recl = %d\n",
tid_data->next_reclaimed);
iwl_trans_txq_disable(priv->trans,
- tid_data->agg.txq_id);
+ tid_data->agg.txq_id, true);
iwlagn_dealloc_agg_txq(priv, tid_data->agg.txq_id);
tid_data->agg.state = IWL_AGG_OFF;
ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
index 48730064da7..b04b8858c69 100644
--- a/drivers/net/wireless/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -67,8 +69,8 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
-#define IWL7260_UCODE_API_MAX 9
-#define IWL3160_UCODE_API_MAX 9
+#define IWL7260_UCODE_API_MAX 10
+#define IWL3160_UCODE_API_MAX 10
/* Oldest version we won't warn about */
#define IWL7260_UCODE_API_OK 9
@@ -83,6 +85,8 @@
#define IWL7260_TX_POWER_VERSION 0xffff /* meaningless */
#define IWL3160_NVM_VERSION 0x709
#define IWL3160_TX_POWER_VERSION 0xffff /* meaningless */
+#define IWL3165_NVM_VERSION 0x709
+#define IWL3165_TX_POWER_VERSION 0xffff /* meaningless */
#define IWL7265_NVM_VERSION 0x0a1d
#define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */
@@ -92,6 +96,9 @@
#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"
@@ -124,7 +131,8 @@ static const struct iwl_ht_params iwl7000_ht_params = {
.max_data_size = IWL60_RTC_DATA_SIZE, \
.base_params = &iwl7000_base_params, \
.led_mode = IWL_LED_RF_STATE, \
- .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000
+ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \
+ .non_shared_ant = ANT_A
const struct iwl_cfg iwl7260_2ac_cfg = {
@@ -213,11 +221,27 @@ static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = {
{0},
};
+static const struct iwl_ht_params iwl7265_ht_params = {
+ .stbc = true,
+ .ldpc = true,
+ .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
+};
+
+const struct iwl_cfg iwl3165_2ac_cfg = {
+ .name = "Intel(R) Dual Band Wireless AC 3165",
+ .fw_name_pre = IWL3165_FW_PRE,
+ IWL_DEVICE_7000,
+ .ht_params = &iwl7000_ht_params,
+ .nvm_ver = IWL3165_NVM_VERSION,
+ .nvm_calib_ver = IWL3165_TX_POWER_VERSION,
+ .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+};
+
const struct iwl_cfg iwl7265_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 7265",
.fw_name_pre = IWL7265_FW_PRE,
IWL_DEVICE_7000,
- .ht_params = &iwl7000_ht_params,
+ .ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
@@ -227,7 +251,7 @@ const struct iwl_cfg iwl7265_2n_cfg = {
.name = "Intel(R) Dual Band Wireless N 7265",
.fw_name_pre = IWL7265_FW_PRE,
IWL_DEVICE_7000,
- .ht_params = &iwl7000_ht_params,
+ .ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
@@ -237,7 +261,7 @@ const struct iwl_cfg iwl7265_n_cfg = {
.name = "Intel(R) Wireless N 7265",
.fw_name_pre = IWL7265_FW_PRE,
IWL_DEVICE_7000,
- .ht_params = &iwl7000_ht_params,
+ .ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
@@ -245,4 +269,5 @@ const struct iwl_cfg iwl7265_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));
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c
index 44b19e01510..4ae8ba6ccff 100644
--- a/drivers/net/wireless/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-8000.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2014 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) 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -67,7 +69,7 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
-#define IWL8000_UCODE_API_MAX 9
+#define IWL8000_UCODE_API_MAX 10
/* Oldest version we won't warn about */
#define IWL8000_UCODE_API_OK 8
@@ -101,6 +103,7 @@ static const struct iwl_base_params iwl8000_base_params = {
};
static const struct iwl_ht_params iwl8000_ht_params = {
+ .ldpc = true,
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
};
@@ -113,7 +116,17 @@ static const struct iwl_ht_params iwl8000_ht_params = {
.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
+ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \
+ .non_shared_ant = ANT_A
+
+const struct iwl_cfg iwl8260_2n_cfg = {
+ .name = "Intel(R) Dual Band Wireless N 8260",
+ .fw_name_pre = IWL8000_FW_PRE,
+ IWL_DEVICE_8000,
+ .ht_params = &iwl8000_ht_params,
+ .nvm_ver = IWL8000_NVM_VERSION,
+ .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
+};
const struct iwl_cfg iwl8260_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 8260",
@@ -133,6 +146,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
.default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000,
.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
+ .disable_dummy_notification = true,
};
MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 8da596db9ab..2ef83a39ff1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -120,6 +120,8 @@ enum iwl_led_mode {
#define IWL_LONG_WD_TIMEOUT 10000
#define IWL_MAX_WD_TIMEOUT 120000
+#define IWL_DEFAULT_MAX_TX_POWER 22
+
/* Antenna presence definitions */
#define ANT_NONE 0x0
#define ANT_A BIT(0)
@@ -169,6 +171,7 @@ struct iwl_base_params {
/*
* @stbc: support Tx STBC and 1*SS Rx STBC
+ * @ldpc: support Tx/Rx with LDPC
* @use_rts_for_aggregation: use rts/cts protection for HT traffic
* @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40
*/
@@ -176,6 +179,7 @@ struct iwl_ht_params {
enum ieee80211_smps_mode smps_mode;
const bool ht_greenfield_support; /* if used set to true */
const bool stbc;
+ const bool ldpc;
bool use_rts_for_aggregation;
u8 ht40_bands;
};
@@ -226,6 +230,7 @@ struct iwl_pwr_tx_backoff {
* @max_data_size: The maximal length of the fw data section
* @valid_tx_ant: valid transmit antenna
* @valid_rx_ant: valid receive antenna
+ * @non_shared_ant: the antenna that is for WiFi only
* @nvm_ver: NVM version
* @nvm_calib_ver: NVM calibration version
* @lib: pointer to the lib ops
@@ -258,6 +263,7 @@ struct iwl_cfg {
const u32 max_inst_size;
u8 valid_tx_ant;
u8 valid_rx_ant;
+ u8 non_shared_ant;
bool bt_shared_single_ant;
u16 nvm_ver;
u16 nvm_calib_ver;
@@ -278,6 +284,7 @@ struct iwl_cfg {
bool no_power_up_nic_in_init;
const char *default_nvm_file;
unsigned int max_rx_agg_size;
+ bool disable_dummy_notification;
};
/*
@@ -335,9 +342,11 @@ extern const struct iwl_cfg iwl7260_n_cfg;
extern const struct iwl_cfg iwl3160_2ac_cfg;
extern const struct iwl_cfg iwl3160_2n_cfg;
extern const struct iwl_cfg iwl3160_n_cfg;
+extern const struct iwl_cfg iwl3165_2ac_cfg;
extern const struct iwl_cfg iwl7265_2ac_cfg;
extern const struct iwl_cfg iwl7265_2n_cfg;
extern const struct iwl_cfg iwl7265_n_cfg;
+extern const struct iwl_cfg iwl8260_2n_cfg;
extern const struct iwl_cfg iwl8260_2ac_cfg;
extern const struct iwl_cfg iwl8260_2ac_sdio_cfg;
#endif /* CONFIG_IWLMVM */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index fe129c94ae3..3f6f015285e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -293,6 +295,16 @@
#define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0)
#define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2)
+
+/**
+ * hw_rev values
+ */
+enum {
+ SILICON_A_STEP = 0,
+ SILICON_B_STEP,
+};
+
+
#define CSR_HW_REV_TYPE_MSK (0x000FFF0)
#define CSR_HW_REV_TYPE_5300 (0x0000020)
#define CSR_HW_REV_TYPE_5350 (0x0000030)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 295083510e7..0a70bcd241f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -145,6 +145,7 @@ do { \
#define IWL_DL_HCMD 0x00000004
#define IWL_DL_STATE 0x00000008
/* 0x000000F0 - 0x00000010 */
+#define IWL_DL_QUOTA 0x00000010
#define IWL_DL_TE 0x00000020
#define IWL_DL_EEPROM 0x00000040
#define IWL_DL_RADIO 0x00000080
@@ -189,6 +190,7 @@ do { \
#define IWL_DEBUG_LED(p, f, a...) IWL_DEBUG(p, IWL_DL_LED, f, ## a)
#define IWL_DEBUG_WEP(p, f, a...) IWL_DEBUG(p, IWL_DL_WEP, f, ## a)
#define IWL_DEBUG_HC(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD, f, ## a)
+#define IWL_DEBUG_QUOTA(p, f, a...) IWL_DEBUG(p, IWL_DL_QUOTA, f, ## a)
#define IWL_DEBUG_TE(p, f, a...) IWL_DEBUG(p, IWL_DL_TE, f, ## a)
#define IWL_DEBUG_EEPROM(d, f, a...) IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a)
#define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
index 23e7351e02d..90987d6f348 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
@@ -36,15 +36,8 @@
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_tx);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_info);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_warn);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_crit);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_err);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dbg);
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index 77e3178040b..ed673baedfd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -1254,7 +1256,9 @@ struct iwl_mod_params iwlwifi_mod_params = {
.bt_coex_active = true,
.power_level = IWL_POWER_INDEX_1,
.wd_disable = true,
- .uapsd_disable = false,
+#ifndef CONFIG_IWLWIFI_UAPSD
+ .uapsd_disable = true,
+#endif /* CONFIG_IWLWIFI_UAPSD */
/* the rest are 0 by default */
};
IWL_EXPORT_SYMBOL(iwlwifi_mod_params);
@@ -1359,7 +1363,7 @@ MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)")
module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling,
int, S_IRUGO);
MODULE_PARM_DESC(antenna_coupling,
- "specify antenna coupling in dB (defualt: 0 dB)");
+ "specify antenna coupling in dB (default: 0 dB)");
module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO);
MODULE_PARM_DESC(wd_disable,
@@ -1370,7 +1374,11 @@ MODULE_PARM_DESC(nvm_file, "NVM file name");
module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable,
bool, S_IRUGO);
+#ifdef CONFIG_IWLWIFI_UAPSD
MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: N)");
+#else
+MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: Y)");
+#endif
/*
* set bt_coex_active to true, uCode will do kill/defer
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h
index 3c72cb710b0..be4f8972241 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.h
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
index 07ff7e0028e..74b796dc424 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
@@ -758,6 +758,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
}
+ if (cfg->ht_params->ldpc)
+ ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+
if (iwlwifi_mod_params.amsdu_size_8K)
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index de5994a776c..e30a41d04c8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2014 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) 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 929a8063354..401f7be36b9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 1bb5193c5b1..62c46eb8b99 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -125,6 +127,9 @@ enum iwl_ucode_tlv_flag {
* @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA.
* @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit.
* @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API.
+ * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif.
+ * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time
+ * longer than the passive one, which is essential for fragmented scan.
*/
enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0),
@@ -133,6 +138,8 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_CSA_FLOW = BIT(4),
IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5),
IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6),
+ IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7),
+ IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8),
};
/**
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index 5eef4ae7333..7a2cbf6f90d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -193,7 +193,7 @@ void iwl_force_nmi(struct iwl_trans *trans)
* DEVICE_SET_NMI_8000B_REG - is used.
*/
if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) ||
- ((trans->hw_rev & 0xc) == 0x0))
+ (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP))
iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL);
else
iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG,
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index 018af2957d3..c302e746855 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -146,8 +148,6 @@ static const u8 iwl_nvm_channels_family_8000[] = {
#define LAST_2GHZ_HT_PLUS 9
#define LAST_5GHZ_HT 161
-#define DEFAULT_MAX_TX_POWER 16
-
/* rate data (static) */
static struct ieee80211_rate iwl_cfg80211_rates[] = {
{ .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, },
@@ -295,7 +295,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
* Default value - highest tx power value. max_power
* is not used in mvm, and is used for backwards compatibility
*/
- channel->max_power = DEFAULT_MAX_TX_POWER;
+ channel->max_power = IWL_DEFAULT_MAX_TX_POWER;
is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
IWL_DEBUG_EEPROM(dev,
"Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
@@ -334,6 +334,9 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+ if (cfg->ht_params->ldpc)
+ vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
+
if (num_tx_ants > 1)
vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
else
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
index 99785c892f9..b6d666ee835 100644
--- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 47033a35a40..1560f4576c7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -281,6 +283,7 @@
#define SCD_CHAINEXT_EN (SCD_BASE + 0x244)
#define SCD_AGGR_SEL (SCD_BASE + 0x248)
#define SCD_INTERRUPT_MASK (SCD_BASE + 0x108)
+#define SCD_EN_CTRL (SCD_BASE + 0x254)
static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-scd.h b/drivers/net/wireless/iwlwifi/iwl-scd.h
new file mode 100644
index 00000000000..6c622b21bba
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-scd.h
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * 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) 2014 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) 2014 Intel Mobile Communications GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_scd_h__
+#define __iwl_scd_h__
+
+#include "iwl-trans.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
+
+
+static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans,
+ u16 txq_id)
+{
+ iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
+ (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+ (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
+static inline void iwl_scd_txq_set_chain(struct iwl_trans *trans,
+ u16 txq_id)
+{
+ iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
+}
+
+static inline void iwl_scd_txq_enable_agg(struct iwl_trans *trans,
+ u16 txq_id)
+{
+ iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+}
+
+static inline void iwl_scd_txq_disable_agg(struct iwl_trans *trans,
+ u16 txq_id)
+{
+ iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+}
+
+static inline void iwl_scd_disable_agg(struct iwl_trans *trans)
+{
+ iwl_set_bits_prph(trans, SCD_AGGR_SEL, 0);
+}
+
+static inline void iwl_scd_activate_fifos(struct iwl_trans *trans)
+{
+ iwl_write_prph(trans, SCD_TXFACT, IWL_MASK(0, 7));
+}
+
+static inline void iwl_scd_deactivate_fifos(struct iwl_trans *trans)
+{
+ iwl_write_prph(trans, SCD_TXFACT, 0);
+}
+
+static inline void iwl_scd_enable_set_active(struct iwl_trans *trans,
+ u32 value)
+{
+ iwl_write_prph(trans, SCD_EN_CTRL, value);
+}
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 656371a668d..9eb85249e89 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -375,6 +377,7 @@ enum iwl_trans_status {
* if unset 4k will be the RX buffer size
* @bc_table_dword: set to true if the BC table expects the byte count to be
* in DWORD (as opposed to bytes)
+ * @scd_set_active: should the transport configure the SCD for HCMD queue
* @queue_watchdog_timeout: time (in ms) after which queues
* are considered stuck and will trigger device restart
* @command_names: array of command names, must be 256 entries
@@ -390,6 +393,7 @@ struct iwl_trans_config {
bool rx_buf_size_8k;
bool bc_table_dword;
+ bool scd_set_active;
unsigned int queue_watchdog_timeout;
const char *const *command_names;
};
@@ -401,6 +405,14 @@ struct iwl_trans_dump_data {
struct iwl_trans;
+struct iwl_trans_txq_scd_cfg {
+ u8 fifo;
+ s8 sta_id;
+ u8 tid;
+ bool aggregate;
+ int frame_limit;
+};
+
/**
* struct iwl_trans_ops - transport specific operations
*
@@ -437,7 +449,9 @@ struct iwl_trans;
* Must be atomic
* @txq_enable: setup a queue. To setup an AC queue, use the
* iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before
- * this one. The op_mode must not configure the HCMD queue. May sleep.
+ * this one. The op_mode must not configure the HCMD queue. The scheduler
+ * configuration may be %NULL, in which case the hardware will not be
+ * configured. May sleep.
* @txq_disable: de-configure a Tx queue to send AMPDUs
* Must be atomic
* @wait_tx_queue_empty: wait until tx queues are empty. May sleep.
@@ -492,9 +506,10 @@ struct iwl_trans_ops {
void (*reclaim)(struct iwl_trans *trans, int queue, int ssn,
struct sk_buff_head *skbs);
- void (*txq_enable)(struct iwl_trans *trans, int queue, int fifo,
- int sta_id, int tid, int frame_limit, u16 ssn);
- void (*txq_disable)(struct iwl_trans *trans, int queue);
+ void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn,
+ const struct iwl_trans_txq_scd_cfg *cfg);
+ void (*txq_disable)(struct iwl_trans *trans, int queue,
+ bool configure_scd);
int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm);
@@ -766,29 +781,51 @@ static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue,
trans->ops->reclaim(trans, queue, ssn, skbs);
}
-static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue)
+static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue,
+ bool configure_scd)
{
- trans->ops->txq_disable(trans, queue);
+ trans->ops->txq_disable(trans, queue, configure_scd);
}
-static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
- int fifo, int sta_id, int tid,
- int frame_limit, u16 ssn)
+static inline void
+iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn,
+ const struct iwl_trans_txq_scd_cfg *cfg)
{
might_sleep();
if (unlikely((trans->state != IWL_TRANS_FW_ALIVE)))
IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
- trans->ops->txq_enable(trans, queue, fifo, sta_id, tid,
- frame_limit, ssn);
+ trans->ops->txq_enable(trans, queue, ssn, cfg);
+}
+
+static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
+ int fifo, int sta_id, int tid,
+ int frame_limit, u16 ssn)
+{
+ struct iwl_trans_txq_scd_cfg cfg = {
+ .fifo = fifo,
+ .sta_id = sta_id,
+ .tid = tid,
+ .frame_limit = frame_limit,
+ .aggregate = sta_id >= 0,
+ };
+
+ iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg);
}
static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue,
int fifo)
{
- iwl_trans_txq_enable(trans, queue, fifo, -1,
- IWL_MAX_TID_COUNT, IWL_FRAME_LIMIT, 0);
+ struct iwl_trans_txq_scd_cfg cfg = {
+ .fifo = fifo,
+ .sta_id = -1,
+ .tid = IWL_MAX_TID_COUNT,
+ .frame_limit = IWL_FRAME_LIMIT,
+ .aggregate = false,
+ };
+
+ iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg);
}
static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile
index a28235913c2..2d7c3ea3c4f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/Makefile
+++ b/drivers/net/wireless/iwlwifi/mvm/Makefile
@@ -3,7 +3,7 @@ iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o
iwlmvm-y += scan.o time-event.o rs.o
iwlmvm-y += power.o coex.o coex_legacy.o
-iwlmvm-y += tt.o offloading.o
+iwlmvm-y += tt.o offloading.o tdls.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o
iwlmvm-$(CONFIG_PM_SLEEP) += d3.o
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c
index 2291bbcaaea..8df2021f985 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -585,8 +587,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
lockdep_assert_held(&mvm->mutex);
if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) {
- u32 mode;
-
switch (mvm->bt_force_ant_mode) {
case BT_FORCE_ANT_BT:
mode = BT_COEX_BT;
@@ -756,7 +756,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
struct iwl_bt_iterator_data *data = _data;
struct iwl_mvm *mvm = data->mvm;
struct ieee80211_chanctx_conf *chanctx_conf;
- enum ieee80211_smps_mode smps_mode;
+ /* default smps_mode is AUTOMATIC - only used for client modes */
+ enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC;
u32 bt_activity_grading;
int ave_rssi;
@@ -764,8 +765,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
switch (vif->type) {
case NL80211_IFTYPE_STATION:
- /* default smps_mode for BSS / P2P client is AUTOMATIC */
- smps_mode = IEEE80211_SMPS_AUTOMATIC;
break;
case NL80211_IFTYPE_AP:
if (!mvmvif->ap_ibss_active)
@@ -797,7 +796,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
else if (bt_activity_grading >= BT_LOW_TRAFFIC)
smps_mode = IEEE80211_SMPS_DYNAMIC;
- /* relax SMPS contraints for next association */
+ /* relax SMPS constraints for next association */
if (!vif->bss_conf.assoc)
smps_mode = IEEE80211_SMPS_AUTOMATIC;
@@ -1147,6 +1146,10 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
{
+ /* there is no other antenna, shared antenna is always available */
+ if (mvm->cfg->bt_shared_single_ant)
+ return true;
+
if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
index a3be3335992..585c0ab4a3e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h
index ca79f716057..a355788b116 100644
--- a/drivers/net/wireless/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/iwlwifi/mvm/constants.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,12 +65,18 @@
#ifndef __MVM_CONSTANTS_H
#define __MVM_CONSTANTS_H
+#include <linux/ieee80211.h>
+
#define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
#define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
#define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC)
#define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC)
#define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
#define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
+#define IWL_MVM_UAPSD_QUEUES (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\
+ IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\
+ IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\
+ IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
#define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20
#define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 8
#define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30
@@ -84,5 +92,7 @@
#define IWL_MVM_BT_COEX_SYNC2SCO 1
#define IWL_MVM_BT_COEX_CORUNNING 1
#define IWL_MVM_BT_COEX_MPLUT 1
+#define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0
+#define IWL_MVM_QUOTA_THRESHOLD 8
#endif /* __MVM_CONSTANTS_H */
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index 645b3cfc29a..c17be0fb728 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -700,7 +702,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return ret;
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta);
- ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false);
+ ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
if (ret)
return ret;
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
index 2e90ff795c1..9aa2311a776 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -74,8 +76,7 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
switch (param) {
case MVM_DEBUGFS_PM_KEEP_ALIVE: {
- struct ieee80211_hw *hw = mvm->hw;
- int dtimper = hw->conf.ps_dtim_period ?: 1;
+ int dtimper = vif->bss_conf.dtim_period ?: 1;
int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
@@ -119,6 +120,10 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val);
dbgfs_pm->uapsd_misbehaving = val;
break;
+ case MVM_DEBUGFS_PM_USE_PS_POLL:
+ IWL_DEBUG_POWER(mvm, "use_ps_poll=%d\n", val);
+ dbgfs_pm->use_ps_poll = val;
+ break;
}
}
@@ -169,6 +174,10 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
if (sscanf(buf + 18, "%d", &val) != 1)
return -EINVAL;
param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING;
+ } else if (!strncmp("use_ps_poll=", buf, 12)) {
+ if (sscanf(buf + 12, "%d", &val) != 1)
+ return -EINVAL;
+ param = MVM_DEBUGFS_PM_USE_PS_POLL;
} else {
return -EINVAL;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index 7d18f466fbb..95eb9a5ef69 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -257,6 +259,73 @@ static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf,
return count;
}
+static ssize_t iwl_dbgfs_set_nic_temperature_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ char buf[16];
+ int pos;
+
+ if (!mvm->temperature_test)
+ pos = scnprintf(buf , sizeof(buf), "disabled\n");
+ else
+ pos = scnprintf(buf , sizeof(buf), "%d\n", mvm->temperature);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+/*
+ * Set NIC Temperature
+ * Cause the driver to ignore the actual NIC temperature reported by the FW
+ * Enable: any value between IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -
+ * IWL_MVM_DEBUG_SET_TEMPERATURE_MAX
+ * Disable: IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE
+ */
+static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm,
+ char *buf, size_t count,
+ loff_t *ppos)
+{
+ int temperature;
+
+ if (!mvm->ucode_loaded && !mvm->temperature_test)
+ return -EIO;
+
+ if (kstrtoint(buf, 10, &temperature))
+ return -EINVAL;
+ /* not a legal temperature */
+ if ((temperature > IWL_MVM_DEBUG_SET_TEMPERATURE_MAX &&
+ temperature != IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) ||
+ temperature < IWL_MVM_DEBUG_SET_TEMPERATURE_MIN)
+ return -EINVAL;
+
+ mutex_lock(&mvm->mutex);
+ if (temperature == IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) {
+ if (!mvm->temperature_test)
+ goto out;
+
+ mvm->temperature_test = false;
+ /* Since we can't read the temp while awake, just set
+ * it to zero until we get the next RX stats from the
+ * firmware.
+ */
+ mvm->temperature = 0;
+ } else {
+ mvm->temperature_test = true;
+ mvm->temperature = temperature;
+ }
+ IWL_DEBUG_TEMP(mvm, "%sabling debug set temperature (temp = %d)\n",
+ mvm->temperature_test ? "En" : "Dis" ,
+ mvm->temperature);
+ /* handle the temperature change */
+ iwl_mvm_tt_handler(mvm);
+
+out:
+ mutex_unlock(&mvm->mutex);
+
+ return count;
+}
+
static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -1190,6 +1259,18 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT);
PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
PRINT_MVM_REF(IWL_MVM_REF_USER);
+ PRINT_MVM_REF(IWL_MVM_REF_TX);
+ PRINT_MVM_REF(IWL_MVM_REF_TX_AGG);
+ PRINT_MVM_REF(IWL_MVM_REF_ADD_IF);
+ PRINT_MVM_REF(IWL_MVM_REF_START_AP);
+ PRINT_MVM_REF(IWL_MVM_REF_BSS_CHANGED);
+ PRINT_MVM_REF(IWL_MVM_REF_PREPARE_TX);
+ PRINT_MVM_REF(IWL_MVM_REF_PROTECT_TDLS);
+ PRINT_MVM_REF(IWL_MVM_REF_CHECK_CTKILL);
+ PRINT_MVM_REF(IWL_MVM_REF_PRPH_READ);
+ PRINT_MVM_REF(IWL_MVM_REF_PRPH_WRITE);
+ PRINT_MVM_REF(IWL_MVM_REF_NMI);
+ PRINT_MVM_REF(IWL_MVM_REF_TM_CMD);
PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
@@ -1296,6 +1377,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64);
MVM_DEBUGFS_READ_FILE_OPS(stations);
MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
@@ -1336,6 +1418,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir,
+ S_IWUSR | S_IRUSR);
MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
@@ -1380,6 +1464,13 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
goto err;
#endif
+ if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR,
+ mvm->debugfs_dir,
+ &mvm->low_latency_agg_frame_limit))
+ goto err;
+ if (!debugfs_create_u8("ps_disabled", S_IRUSR,
+ mvm->debugfs_dir, &mvm->ps_disabled))
+ goto err;
if (!debugfs_create_blob("nvm_hw", S_IRUSR,
mvm->debugfs_dir, &mvm->nvm_hw_blob))
goto err;
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.h b/drivers/net/wireless/iwlwifi/mvm/debugfs.h
index e3a9774af49..8c4190e7e02 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
index 69875716dcd..816883f9ff9 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
index 13696fe419b..e74cdf2132f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
index c3a8c86b550..27dd86395b3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
index c02a9e45ec5..8f221669400 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
index 47bd0406355..21dd5b77166 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 95f5b3274ef..a2c662808a8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -73,16 +75,20 @@
#include "fw-api-coex.h"
#include "fw-api-scan.h"
-/* maximal number of Tx queues in any platform */
-#define IWL_MVM_MAX_QUEUES 20
-
/* Tx queue numbers */
enum {
IWL_MVM_OFFCHANNEL_QUEUE = 8,
IWL_MVM_CMD_QUEUE = 9,
};
-#define IWL_MVM_CMD_FIFO 7
+enum iwl_mvm_tx_fifo {
+ IWL_MVM_TX_FIFO_BK = 0,
+ IWL_MVM_TX_FIFO_BE,
+ IWL_MVM_TX_FIFO_VI,
+ IWL_MVM_TX_FIFO_VO,
+ IWL_MVM_TX_FIFO_MCAST = 5,
+ IWL_MVM_TX_FIFO_CMD = 7,
+};
#define IWL_MVM_STATION_COUNT 16
@@ -184,6 +190,8 @@ enum {
REPLY_RX_MPDU_CMD = 0xc1,
BA_NOTIF = 0xc5,
+ MARKER_CMD = 0xcb,
+
/* BT Coex */
BT_COEX_PRIO_TABLE = 0xcc,
BT_COEX_PROT_ENV = 0xcd,
@@ -197,6 +205,10 @@ enum {
REPLY_SF_CFG_CMD = 0xd1,
REPLY_BEACON_FILTERING_CMD = 0xd2,
+ /* DTS measurements */
+ CMD_DTS_MEASUREMENT_TRIGGER = 0xdc,
+ DTS_MEASUREMENT_NOTIFICATION = 0xdd,
+
REPLY_DEBUG_CMD = 0xf0,
DEBUG_LOG_MSG = 0xf7,
@@ -542,7 +554,7 @@ enum iwl_time_event_type {
TE_WIDI_TX_SYNC,
/* Channel Switch NoA */
- TE_P2P_GO_CSA_NOA,
+ TE_CHANNEL_SWITCH_PERIOD,
TE_MAX
}; /* MAC_EVENT_TYPE_API_E_VER_1 */
@@ -1307,6 +1319,38 @@ struct iwl_bcast_filter_cmd {
struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER];
} __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */
+/*
+ * enum iwl_mvm_marker_id - maker ids
+ *
+ * The ids for different type of markers to insert into the usniffer logs
+ */
+enum iwl_mvm_marker_id {
+ MARKER_ID_TX_FRAME_LATENCY = 1,
+}; /* MARKER_ID_API_E_VER_1 */
+
+/**
+ * struct iwl_mvm_marker - mark info into the usniffer logs
+ *
+ * (MARKER_CMD = 0xcb)
+ *
+ * Mark the UTC time stamp into the usniffer logs together with additional
+ * metadata, so the usniffer output can be parsed.
+ * In the command response the ucode will return the GP2 time.
+ *
+ * @dw_len: The amount of dwords following this byte including this byte.
+ * @marker_id: A unique marker id (iwl_mvm_marker_id).
+ * @reserved: reserved.
+ * @timestamp: in milliseconds since 1970-01-01 00:00:00 UTC
+ * @metadata: additional meta data that will be written to the unsiffer log
+ */
+struct iwl_mvm_marker {
+ u8 dwLen;
+ u8 markerId;
+ __le16 reserved;
+ __le64 timestamp;
+ __le32 metadata[0];
+} __packed; /* MARKER_API_S_VER_1 */
+
struct mvm_statistics_dbg {
__le32 burst_check;
__le32 burst_count;
@@ -1561,19 +1605,49 @@ enum iwl_sf_scenario {
#define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */
+#define SF_CFG_DUMMY_NOTIF_OFF BIT(16)
+
/**
* Smart Fifo configuration command.
- * @state: smart fifo state, types listed in iwl_sf_sate.
+ * @state: smart fifo state, types listed in enum %iwl_sf_sate.
* @watermark: Minimum allowed availabe free space in RXF for transient state.
* @long_delay_timeouts: aging and idle timer values for each scenario
* in long delay state.
* @full_on_timeouts: timer values for each scenario in full on state.
*/
struct iwl_sf_cfg_cmd {
- enum iwl_sf_state state;
+ __le32 state;
__le32 watermark[SF_TRANSIENT_STATES_NUMBER];
__le32 long_delay_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
__le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
} __packed; /* SF_CFG_API_S_VER_2 */
+/* DTS measurements */
+
+enum iwl_dts_measurement_flags {
+ DTS_TRIGGER_CMD_FLAGS_TEMP = BIT(0),
+ DTS_TRIGGER_CMD_FLAGS_VOLT = BIT(1),
+};
+
+/**
+ * iwl_dts_measurement_cmd - request DTS temperature and/or voltage measurements
+ *
+ * @flags: indicates which measurements we want as specified in &enum
+ * iwl_dts_measurement_flags
+ */
+struct iwl_dts_measurement_cmd {
+ __le32 flags;
+} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_CMD_S */
+
+/**
+ * iwl_dts_measurement_notif - notification received with the measurements
+ *
+ * @temp: the measured temperature
+ * @voltage: the measured voltage
+ */
+struct iwl_dts_measurement_notif {
+ __le32 temp;
+ __le32 voltage;
+} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */
+
#endif /* __fw_api_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index 883e702152d..23fd711a67e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -242,10 +244,10 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
mvm->queue_to_mac80211[i] = i;
else
mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
- atomic_set(&mvm->queue_stop_count[i], 0);
}
- mvm->transport_queue_stop = 0;
+ for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
+ atomic_set(&mvm->mac80211_queue_stop_count[i], 0);
mvm->ucode_loaded = true;
@@ -452,6 +454,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
for (i = 0; i < IWL_MVM_STATION_COUNT; i++)
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
+ /* reset quota debouncing buffer - 0xff will yield invalid data */
+ memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd));
+
/* Add auxiliary station for scanning */
ret = iwl_mvm_add_aux_sta(mvm);
if (ret)
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 0e523e28cab..83426714592 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -81,7 +83,7 @@ struct iwl_mvm_mac_iface_iterator_data {
struct ieee80211_vif *vif;
unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)];
unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)];
- unsigned long used_hw_queues[BITS_TO_LONGS(IWL_MVM_MAX_QUEUES)];
+ u32 used_hw_queues;
enum iwl_tsf_id preferred_tsf;
bool found_vif;
};
@@ -192,12 +194,31 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
data->preferred_tsf = NUM_TSF_IDS;
}
+/*
+ * Get the mask of the queues used by the vif
+ */
+u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ u32 qmask = 0, ac;
+
+ if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
+ return BIT(IWL_MVM_OFFCHANNEL_QUEUE);
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ qmask |= BIT(vif->hw_queue[ac]);
+
+ if (vif->type == NL80211_IFTYPE_AP)
+ qmask |= BIT(vif->cab_queue);
+
+ return qmask;
+}
+
static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm_mac_iface_iterator_data *data = _data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- u32 ac;
/* Iterator may already find the interface being added -- skip it */
if (vif == data->vif) {
@@ -206,12 +227,7 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
}
/* Mark the queues used by the vif */
- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
- if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
- __set_bit(vif->hw_queue[ac], data->used_hw_queues);
-
- if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
- __set_bit(vif->cab_queue, data->used_hw_queues);
+ data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(data->mvm, vif);
/* Mark MAC IDs as used by clearing the available bit, and
* (below) mark TSFs as used if their existing use is not
@@ -225,24 +241,6 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
iwl_mvm_mac_tsf_id_iter(_data, mac, vif);
}
-/*
- * Get the mask of the queus used by the vif
- */
-u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
-{
- u32 qmask = 0, ac;
-
- if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
- return BIT(IWL_MVM_OFFCHANNEL_QUEUE);
-
- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
- if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
- qmask |= BIT(vif->hw_queue[ac]);
-
- return qmask;
-}
-
void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
@@ -277,15 +275,15 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
.available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 },
/* no preference yet */
.preferred_tsf = NUM_TSF_IDS,
- .used_hw_queues = {
+ .used_hw_queues =
BIT(IWL_MVM_OFFCHANNEL_QUEUE) |
BIT(mvm->aux_queue) |
- BIT(IWL_MVM_CMD_QUEUE)
- },
+ BIT(IWL_MVM_CMD_QUEUE),
.found_vif = false,
};
u32 ac;
int ret, i;
+ unsigned long used_hw_queues;
/*
* Allocate a MAC ID and a TSF for this MAC, along with the queues
@@ -368,9 +366,11 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
return 0;
}
+ used_hw_queues = data.used_hw_queues;
+
/* Find available queues, and allocate them to the ACs */
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
- u8 queue = find_first_zero_bit(data.used_hw_queues,
+ u8 queue = find_first_zero_bit(&used_hw_queues,
mvm->first_agg_queue);
if (queue >= mvm->first_agg_queue) {
@@ -379,13 +379,13 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
goto exit_fail;
}
- __set_bit(queue, data.used_hw_queues);
+ __set_bit(queue, &used_hw_queues);
vif->hw_queue[ac] = queue;
}
/* Allocate the CAB queue for softAP and GO interfaces */
if (vif->type == NL80211_IFTYPE_AP) {
- u8 queue = find_first_zero_bit(data.used_hw_queues,
+ u8 queue = find_first_zero_bit(&used_hw_queues,
mvm->first_agg_queue);
if (queue >= mvm->first_agg_queue) {
@@ -452,14 +452,16 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
switch (vif->type) {
case NL80211_IFTYPE_P2P_DEVICE:
- iwl_trans_txq_disable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE);
+ iwl_trans_txq_disable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE,
+ true);
break;
case NL80211_IFTYPE_AP:
- iwl_trans_txq_disable(mvm->trans, vif->cab_queue);
+ iwl_trans_txq_disable(mvm->trans, vif->cab_queue, true);
/* fall through */
default:
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
- iwl_trans_txq_disable(mvm->trans, vif->hw_queue[ac]);
+ iwl_trans_txq_disable(mvm->trans, vif->hw_queue[ac],
+ true);
}
}
@@ -586,6 +588,7 @@ static void iwl_mvm_mac_ctxt_set_ht_flags(struct iwl_mvm *mvm,
static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_ctx_cmd *cmd,
+ const u8 *bssid_override,
u32 action)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -593,6 +596,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
bool ht_enabled = !!(vif->bss_conf.ht_operation_mode &
IEEE80211_HT_OP_MODE_PROTECTION);
u8 cck_ack_rates, ofdm_ack_rates;
+ const u8 *bssid = bssid_override ?: vif->bss_conf.bssid;
int i;
cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
@@ -625,8 +629,9 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cmd->tsf_id = cpu_to_le32(mvmvif->tsf_id);
memcpy(cmd->node_addr, vif->addr, ETH_ALEN);
- if (vif->bss_conf.bssid)
- memcpy(cmd->bssid_addr, vif->bss_conf.bssid, ETH_ALEN);
+
+ if (bssid)
+ memcpy(cmd->bssid_addr, bssid, ETH_ALEN);
else
eth_broadcast_addr(cmd->bssid_addr);
@@ -695,7 +700,8 @@ static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
- u32 action, bool force_assoc_off)
+ u32 action, bool force_assoc_off,
+ const u8 *bssid_override)
{
struct iwl_mac_ctx_cmd cmd = {};
struct iwl_mac_data_sta *ctxt_sta;
@@ -703,7 +709,7 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
WARN_ON(vif->type != NL80211_IFTYPE_STATION);
/* Fill the common data for all mac context types */
- iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, bssid_override, action);
if (vif->p2p) {
struct ieee80211_p2p_noa_attr *noa =
@@ -721,11 +727,6 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
!force_assoc_off) {
u32 dtim_offs;
- /* Allow beacons to pass through as long as we are not
- * associated, or we do not have dtim period information.
- */
- cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
-
/*
* The DTIM count counts down, so when it is N that means N
* more beacon intervals happen until the DTIM TBTT. Therefore
@@ -759,6 +760,11 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
ctxt_sta->is_assoc = cpu_to_le32(1);
} else {
ctxt_sta->is_assoc = cpu_to_le32(0);
+
+ /* Allow beacons to pass through as long as we are not
+ * associated, or we do not have dtim period information.
+ */
+ cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
}
ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int);
@@ -784,7 +790,7 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
- iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC |
MAC_FILTER_IN_CONTROL_AND_MGMT |
@@ -805,7 +811,7 @@ static int iwl_mvm_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm,
WARN_ON(vif->type != NL80211_IFTYPE_ADHOC);
- iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_BEACON |
MAC_FILTER_IN_PROBE_REQUEST);
@@ -844,7 +850,7 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE);
- iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
@@ -1072,7 +1078,7 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p);
/* Fill the common data for all mac context types */
- iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
/*
* pass probe requests and beacons from other APs (needed
@@ -1098,7 +1104,7 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
WARN_ON(vif->type != NL80211_IFTYPE_AP || !vif->p2p);
/* Fill the common data for all mac context types */
- iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
/*
* pass probe requests and beacons from other APs (needed
@@ -1121,12 +1127,14 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
}
static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- u32 action, bool force_assoc_off)
+ u32 action, bool force_assoc_off,
+ const u8 *bssid_override)
{
switch (vif->type) {
case NL80211_IFTYPE_STATION:
return iwl_mvm_mac_ctxt_cmd_sta(mvm, vif, action,
- force_assoc_off);
+ force_assoc_off,
+ bssid_override);
break;
case NL80211_IFTYPE_AP:
if (!vif->p2p)
@@ -1157,7 +1165,7 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
return -EIO;
ret = iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD,
- true);
+ true, NULL);
if (ret)
return ret;
@@ -1169,7 +1177,7 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
}
int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- bool force_assoc_off)
+ bool force_assoc_off, const u8 *bssid_override)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -1178,7 +1186,7 @@ int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return -EIO;
return iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY,
- force_assoc_off);
+ force_assoc_off, bssid_override);
}
int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
@@ -1226,13 +1234,13 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm,
!iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) {
u32 rel_time = (c + 1) *
csa_vif->bss_conf.beacon_int -
- IWL_MVM_CHANNEL_SWITCH_TIME;
+ IWL_MVM_CHANNEL_SWITCH_TIME_GO;
u32 apply_time = gp2 + rel_time * 1024;
- iwl_mvm_schedule_csa_noa(mvm, csa_vif,
- IWL_MVM_CHANNEL_SWITCH_TIME -
- IWL_MVM_CHANNEL_SWITCH_MARGIN,
- apply_time);
+ iwl_mvm_schedule_csa_period(mvm, csa_vif,
+ IWL_MVM_CHANNEL_SWITCH_TIME_GO -
+ IWL_MVM_CHANNEL_SWITCH_MARGIN,
+ apply_time);
}
} else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) {
/* we don't have CSA NoA scheduled yet, switch now */
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 7c8796584c2..4c2121094a0 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -301,9 +303,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_TIMING_BEACON_ONLY |
IEEE80211_HW_CONNECTION_MONITOR |
- IEEE80211_HW_CHANCTX_STA_CSA |
- IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
- IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+ IEEE80211_HW_CHANCTX_STA_CSA;
hw->queues = mvm->first_agg_queue;
hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
@@ -325,7 +325,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
IWL_UCODE_API(mvm->fw->ucode_ver) >= 9 &&
!iwlwifi_mod_params.uapsd_disable) {
hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD;
- hw->uapsd_queues = IWL_UAPSD_AC_INFO;
+ hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
}
@@ -396,16 +396,20 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
else
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
- /* TODO: enable that only for firmwares that don't crash */
- /* 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;
+ 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->features |= NL80211_FEATURE_P2P_GO_CTWIN |
NL80211_FEATURE_LOW_PRIORITY_SCAN |
- NL80211_FEATURE_P2P_GO_OPPPS;
+ NL80211_FEATURE_P2P_GO_OPPPS |
+ NL80211_FEATURE_DYNAMIC_SMPS |
+ NL80211_FEATURE_STATIC_SMPS;
mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
@@ -666,8 +670,9 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
-static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
+void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
{
+ static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL };
struct iwl_fw_error_dump_file *dump_file;
struct iwl_fw_error_dump_data *dump_data;
struct iwl_fw_error_dump_info *dump_info;
@@ -759,23 +764,20 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
file_len += fw_error_dump->trans_ptr->len;
dump_file->file_len = cpu_to_le32(file_len);
mvm->fw_error_dump = fw_error_dump;
+
+ /* notify the userspace about the error we had */
+ kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env);
}
#endif
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
{
-#ifdef CONFIG_IWLWIFI_DEBUGFS
- static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL };
-
iwl_mvm_fw_error_dump(mvm);
- /* notify the userspace about the error we had */
- kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env);
-#endif
-
iwl_trans_stop_device(mvm->trans);
mvm->scan_status = IWL_MVM_SCAN_NONE;
+ mvm->ps_disabled = false;
/* just in case one was running */
ieee80211_remain_on_channel_expired(mvm->hw);
@@ -803,16 +805,18 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
* ucode_down ref until reconfig is complete */
iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN);
+ /* clear any stale d0i3 state */
+ clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
+
mvm->vif_count = 0;
mvm->rx_ba_sessions = 0;
}
-static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
+int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
{
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret;
- mutex_lock(&mvm->mutex);
+ lockdep_assert_held(&mvm->mutex);
/* Clean up some internal and mac80211 state on restart */
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
@@ -829,6 +833,16 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
iwl_mvm_d0i3_enable_tx(mvm, NULL);
}
+ return ret;
+}
+
+static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+ ret = __iwl_mvm_mac_start(mvm);
mutex_unlock(&mvm->mutex);
return ret;
@@ -854,14 +868,9 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw)
mutex_unlock(&mvm->mutex);
}
-static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
+void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
{
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
-
- flush_work(&mvm->d0i3_exit_work);
- flush_work(&mvm->async_handlers_wk);
-
- mutex_lock(&mvm->mutex);
+ lockdep_assert_held(&mvm->mutex);
/* disallow low power states when the FW is down */
iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
@@ -880,8 +889,21 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
/* async_handlers_list is empty and will stay empty: HW is stopped */
/* the fw is stopped, the aux sta is dead: clean up driver state */
- iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
+ iwl_mvm_del_aux_sta(mvm);
+
+ mvm->ucode_loaded = false;
+}
+static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ flush_work(&mvm->d0i3_exit_work);
+ flush_work(&mvm->async_handlers_wk);
+ flush_work(&mvm->fw_error_dump_wk);
+
+ mutex_lock(&mvm->mutex);
+ __iwl_mvm_mac_stop(mvm);
mutex_unlock(&mvm->mutex);
/*
@@ -965,10 +987,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
*/
if (vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_ADHOC) {
- u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
- ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta,
- qmask,
- ieee80211_vif_type_p2p(vif));
+ ret = iwl_mvm_alloc_bcast_sta(mvm, vif);
if (ret) {
IWL_ERR(mvm, "Failed to allocate bcast sta\n");
goto out_release;
@@ -1016,7 +1035,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
if (ret)
goto out_unref_phy;
- ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
+ ret = iwl_mvm_add_bcast_sta(mvm, vif);
if (ret)
goto out_unbind;
@@ -1057,14 +1076,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
- u32 tfd_msk = 0, ac;
-
- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
- if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
- tfd_msk |= BIT(vif->hw_queue[ac]);
-
- if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
- tfd_msk |= BIT(vif->cab_queue);
+ u32 tfd_msk = iwl_mvm_mac_get_queues_mask(mvm, vif);
if (tfd_msk) {
mutex_lock(&mvm->mutex);
@@ -1120,13 +1132,13 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mvm->noa_duration = 0;
}
#endif
- iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
+ iwl_mvm_dealloc_bcast_sta(mvm, vif);
goto out_release;
}
if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
mvm->p2p_device_vif = NULL;
- iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+ iwl_mvm_rm_bcast_sta(mvm, vif);
iwl_mvm_binding_remove_vif(mvm, vif);
iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
mvmvif->phy_ctxt = NULL;
@@ -1200,14 +1212,15 @@ static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw,
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mcast_filter_cmd *cmd;
struct netdev_hw_addr *addr;
- int addr_count = netdev_hw_addr_list_count(mc_list);
- bool pass_all = false;
+ int addr_count;
+ bool pass_all;
int len;
- if (addr_count > MAX_MCAST_FILTERING_ADDRESSES) {
- pass_all = true;
+ addr_count = netdev_hw_addr_list_count(mc_list);
+ pass_all = addr_count > MAX_MCAST_FILTERING_ADDRESSES ||
+ IWL_MVM_FW_MCAST_FILTER_PASS_ALL;
+ if (pass_all)
addr_count = 0;
- }
len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4);
cmd = kzalloc(len, GFP_ATOMIC);
@@ -1407,28 +1420,6 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
}
#endif
-static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)
-{
- struct ieee80211_sta *sta;
- struct iwl_mvm_sta *mvmsta;
- int i;
-
- lockdep_assert_held(&mvm->mutex);
-
- for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
- sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
- lockdep_is_held(&mvm->mutex));
- if (!sta || IS_ERR(sta) || !sta->tdls)
- continue;
-
- mvmsta = iwl_mvm_sta_from_mac80211(sta);
- ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,
- NL80211_TDLS_TEARDOWN,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,
- GFP_KERNEL);
- }
-}
-
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -1445,10 +1436,23 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc)
iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
- ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false);
+ /*
+ * If we're not associated yet, take the (new) BSSID before associating
+ * so the firmware knows. If we're already associated, then use the old
+ * BSSID here, and we'll send a cleared one later in the CHANGED_ASSOC
+ * branch for disassociation below.
+ */
+ if (changes & BSS_CHANGED_BSSID && !mvmvif->associated)
+ memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN);
+
+ ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, mvmvif->bssid);
if (ret)
IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
+ /* after sending it once, adopt mac80211 data */
+ memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN);
+ mvmvif->associated = bss_conf->assoc;
+
if (changes & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
/* add quota for this interface */
@@ -1476,13 +1480,17 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
*/
u32 dur = (11 * vif->bss_conf.beacon_int) / 10;
iwl_mvm_protect_session(mvm, vif, dur, dur,
- 5 * dur);
+ 5 * dur, false);
}
iwl_mvm_sf_update(mvm, vif, false);
iwl_mvm_power_vif_assoc(mvm, vif);
- if (vif->p2p)
+ if (vif->p2p) {
iwl_mvm_ref(mvm, IWL_MVM_REF_P2P_CLIENT);
+ iwl_mvm_update_smps(mvm, vif,
+ IWL_MVM_SMPS_REQ_PROT,
+ IEEE80211_SMPS_DYNAMIC);
+ }
} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
/*
* If update fails - SF might be running in associated
@@ -1506,6 +1514,13 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
if (vif->p2p)
iwl_mvm_unref(mvm, IWL_MVM_REF_P2P_CLIENT);
+
+ /* this will take the cleared BSSID from bss_conf */
+ ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+ if (ret)
+ IWL_ERR(mvm,
+ "failed to update MAC %pM (clear after unassoc)\n",
+ vif->addr);
}
iwl_mvm_recalc_multicast(mvm);
@@ -1524,11 +1539,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
*/
iwl_mvm_remove_time_event(mvm, mvmvif,
&mvmvif->time_event_data);
- } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS |
- BSS_CHANGED_QOS)) {
- ret = iwl_mvm_power_update_mac(mvm);
- if (ret)
- IWL_ERR(mvm, "failed to update power mode\n");
}
if (changes & BSS_CHANGED_BEACON_INFO) {
@@ -1536,6 +1546,12 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
}
+ if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS)) {
+ ret = iwl_mvm_power_update_mac(mvm);
+ if (ret)
+ IWL_ERR(mvm, "failed to update power mode\n");
+ }
+
if (changes & BSS_CHANGED_TXPOWER) {
IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n",
bss_conf->txpower);
@@ -1601,7 +1617,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
/* Send the bcast station. At this stage the TBTT and DTIM time events
* are added and applied to the scheduler */
- ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
+ ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
if (ret)
goto out_unbind;
@@ -1617,7 +1633,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
if (vif->p2p && mvm->p2p_device_vif)
- iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);
+ iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);
iwl_mvm_ref(mvm, IWL_MVM_REF_AP_IBSS);
@@ -1633,7 +1649,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
out_quota_failed:
iwl_mvm_power_update_mac(mvm);
mvmvif->ap_ibss_active = false;
- iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+ iwl_mvm_send_rm_bcast_sta(mvm, vif);
out_unbind:
iwl_mvm_binding_remove_vif(mvm, vif);
out_remove:
@@ -1675,10 +1691,10 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
if (vif->p2p && mvm->p2p_device_vif)
- iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);
+ iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);
iwl_mvm_update_quotas(mvm, NULL);
- iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+ iwl_mvm_send_rm_bcast_sta(mvm, vif);
iwl_mvm_binding_remove_vif(mvm, vif);
iwl_mvm_power_update_mac(mvm);
@@ -1701,8 +1717,8 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
return;
if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT |
- BSS_CHANGED_BANDWIDTH) &&
- iwl_mvm_mac_ctxt_changed(mvm, vif, false))
+ BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS) &&
+ iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL))
IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
/* Need to send a new beacon template to the FW */
@@ -1932,48 +1948,6 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
mutex_unlock(&mvm->mutex);
}
-int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
-{
- struct ieee80211_sta *sta;
- struct iwl_mvm_sta *mvmsta;
- int count = 0;
- int i;
-
- lockdep_assert_held(&mvm->mutex);
-
- for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
- sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
- lockdep_is_held(&mvm->mutex));
- if (!sta || IS_ERR(sta) || !sta->tdls)
- continue;
-
- if (vif) {
- mvmsta = iwl_mvm_sta_from_mac80211(sta);
- if (mvmsta->vif != vif)
- continue;
- }
-
- count++;
- }
-
- return count;
-}
-
-static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- bool sta_added)
-{
- int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif);
-
- /*
- * Disable ps when the first TDLS sta is added and re-enable it
- * when the last TDLS sta is removed
- */
- if ((tdls_sta_cnt == 1 && sta_added) ||
- (tdls_sta_cnt == 0 && !sta_added))
- iwl_mvm_power_update_mac(mvm);
-}
-
static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -2113,7 +2087,7 @@ static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw,
int ret;
mutex_lock(&mvm->mutex);
- ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false);
+ ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
mutex_unlock(&mvm->mutex);
return ret;
}
@@ -2141,33 +2115,12 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex);
/* Try really hard to protect the session and hear a beacon */
- iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500);
+ iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false);
mutex_unlock(&mvm->mutex);
iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX);
}
-static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
-{
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int;
-
- /*
- * iwl_mvm_protect_session() reads directly from the device
- * (the system time), so make sure it is available.
- */
- if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS))
- return;
-
- mutex_lock(&mvm->mutex);
- /* Protect the session to hear the TDLS setup response on the channel */
- iwl_mvm_protect_session(mvm, vif, duration, duration, 100);
- mutex_unlock(&mvm->mutex);
-
- iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS);
-}
-
static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req,
@@ -2700,7 +2653,10 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
ret = 0;
goto out;
case NL80211_IFTYPE_STATION:
+ break;
case NL80211_IFTYPE_MONITOR:
+ /* always disable PS when a monitor interface is active */
+ mvmvif->ps_disabled = true;
break;
default:
ret = -EINVAL;
@@ -2732,7 +2688,20 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
if ((vif->type == NL80211_IFTYPE_AP) ||
(switching_chanctx && (vif->type == NL80211_IFTYPE_STATION))) {
iwl_mvm_update_quotas(mvm, NULL);
- iwl_mvm_mac_ctxt_changed(mvm, vif, false);
+ iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+ }
+
+ if (vif->csa_active && vif->type == NL80211_IFTYPE_STATION) {
+ struct iwl_mvm_sta *mvmsta;
+
+ mvmsta = iwl_mvm_sta_from_staid_protected(mvm,
+ mvmvif->ap_sta_id);
+
+ if (WARN_ON(!mvmsta))
+ goto out;
+
+ /* TODO: only re-enable after the first beacon */
+ iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false);
}
goto out;
@@ -2766,6 +2735,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct ieee80211_vif *disabled_vif = NULL;
+ struct iwl_mvm_sta *mvmsta;
lockdep_assert_held(&mvm->mutex);
@@ -2776,6 +2746,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
goto out;
case NL80211_IFTYPE_MONITOR:
mvmvif->monitor_active = false;
+ mvmvif->ps_disabled = false;
break;
case NL80211_IFTYPE_AP:
/* This part is triggered only during CSA */
@@ -2796,7 +2767,13 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
disabled_vif = vif;
- iwl_mvm_mac_ctxt_changed(mvm, vif, true);
+ mvmsta = iwl_mvm_sta_from_staid_protected(mvm,
+ mvmvif->ap_sta_id);
+
+ if (!WARN_ON(!mvmsta))
+ iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true);
+
+ iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL);
break;
default:
break;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 2e73d3bd775..552995810f9 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -85,11 +87,11 @@
/* A TimeUnit is 1024 microsecond */
#define MSEC_TO_TU(_msec) (_msec*1000/1024)
-/*
- * The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0"
- * TBTT. This value should be big enough to ensure that we switch in time.
+/* This value represents the number of TUs before CSA "beacon 0" TBTT
+ * when the CSA time-event needs to be scheduled to start. It must be
+ * big enough to ensure that we switch in time.
*/
-#define IWL_MVM_CHANNEL_SWITCH_TIME 40
+#define IWL_MVM_CHANNEL_SWITCH_TIME_GO 40
/*
* This value (in TUs) is used to fine tune the CSA NoA end time which should
@@ -103,14 +105,6 @@
*/
#define IWL_MVM_CS_UNBLOCK_TX_TIMEOUT 3
-enum iwl_mvm_tx_fifo {
- IWL_MVM_TX_FIFO_BK = 0,
- IWL_MVM_TX_FIFO_BE,
- IWL_MVM_TX_FIFO_VI,
- IWL_MVM_TX_FIFO_VO,
- IWL_MVM_TX_FIFO_MCAST = 5,
-};
-
extern const struct ieee80211_ops iwl_mvm_hw_ops;
/**
@@ -186,10 +180,6 @@ enum iwl_power_scheme {
};
#define IWL_CONN_MAX_LISTEN_INTERVAL 10
-#define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\
- IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\
- IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\
- IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
#define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2
#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -203,6 +193,7 @@ enum iwl_dbgfs_pm_mask {
MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7),
MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8),
MVM_DEBUGFS_PM_UAPSD_MISBEHAVING = BIT(9),
+ MVM_DEBUGFS_PM_USE_PS_POLL = BIT(10),
};
struct iwl_dbgfs_pm {
@@ -215,6 +206,7 @@ struct iwl_dbgfs_pm {
u32 lprx_rssi_threshold;
bool snooze_ena;
bool uapsd_misbehaving;
+ bool use_ps_poll;
int mask;
};
@@ -253,6 +245,7 @@ struct iwl_dbgfs_bf {
enum iwl_mvm_smps_type_request {
IWL_MVM_SMPS_REQ_BT_COEX,
IWL_MVM_SMPS_REQ_TT,
+ IWL_MVM_SMPS_REQ_PROT,
NUM_IWL_MVM_SMPS_REQ,
};
@@ -277,6 +270,8 @@ enum iwl_mvm_ref_type {
IWL_MVM_REF_TM_CMD,
IWL_MVM_REF_EXIT_WORK,
+ /* update debugfs.c when changing this */
+
IWL_MVM_REF_COUNT,
};
@@ -315,6 +310,9 @@ struct iwl_mvm_vif_bf_data {
* @id: between 0 and 3
* @color: to solve races upon MAC addition and removal
* @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA
+ * @bssid: BSSID for this (client) interface
+ * @associated: indicates that we're currently associated, used only for
+ * managing the firmware state in iwl_mvm_bss_info_changed_station()
* @uploaded: indicates the MAC context has been added to the device
* @ap_ibss_active: indicates that AP/IBSS is configured and that the interface
* should get quota etc.
@@ -323,6 +321,7 @@ struct iwl_mvm_vif_bf_data {
* interface should get quota etc.
* @low_latency: indicates that this interface is in low-latency mode
* (VMACLowLatencyMode)
+ * @ps_disabled: indicates that this interface requires PS to be disabled
* @queue_params: QoS params for this MAC
* @bcast_sta: station used for broadcast packets. Used by the following
* vifs: P2P_DEVICE, GO and AP.
@@ -335,11 +334,15 @@ struct iwl_mvm_vif {
u16 color;
u8 ap_sta_id;
+ u8 bssid[ETH_ALEN];
+ bool associated;
+
bool uploaded;
bool ap_ibss_active;
bool pm_enabled;
bool monitor_active;
bool low_latency;
+ bool ps_disabled;
struct iwl_mvm_vif_bf_data bf_data;
u32 ap_beacon_time;
@@ -512,6 +515,10 @@ enum {
D0I3_PENDING_WAKEUP,
};
+#define IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE 0xff
+#define IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -100
+#define IWL_MVM_DEBUG_SET_TEMPERATURE_MAX 200
+
struct iwl_mvm {
/* for logger access */
struct device *dev;
@@ -553,9 +560,8 @@ struct iwl_mvm {
struct mvm_statistics_rx rx_stats;
- unsigned long transport_queue_stop;
u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
- atomic_t queue_stop_count[IWL_MAX_HW_QUEUES];
+ atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES];
const char *nvm_file_name;
struct iwl_nvm_data *nvm_data;
@@ -641,6 +647,7 @@ struct iwl_mvm {
/* -1 for always, 0 for never, >0 for that many times */
s8 restart_fw;
+ struct work_struct fw_error_dump_wk;
struct iwl_mvm_dump_ptrs *fw_error_dump;
#ifdef CONFIG_IWLWIFI_LEDS
@@ -694,6 +701,14 @@ struct iwl_mvm {
/* Thermal Throttling and CTkill */
struct iwl_mvm_tt_mgmt thermal_throttle;
s32 temperature; /* Celsius */
+ /*
+ * Debug option to set the NIC temperature. This option makes the
+ * driver think this is the actual NIC temperature, and ignore the
+ * real temperature that is received from the fw
+ */
+ bool temperature_test; /* Debug test temperature is enabled */
+
+ struct iwl_time_quota_cmd last_quota_cmd;
#ifdef CONFIG_NL80211_TESTMODE
u32 noa_duration;
@@ -706,7 +721,7 @@ struct iwl_mvm {
u8 last_agg_queue;
/* Indicate if device power save is allowed */
- bool ps_disabled;
+ u8 ps_disabled; /* u8 instead of bool to ease debugfs_create_* usage */
struct ieee80211_vif __rcu *csa_vif;
struct ieee80211_vif __rcu *csa_tx_blocked_vif;
@@ -714,6 +729,8 @@ struct iwl_mvm {
/* system time of last beacon (for AP/GO interface) */
u32 ap_last_beacon_gp2;
+
+ u8 low_latency_agg_frame_limit;
};
/* Extract MVM priv from op_mode and _hw */
@@ -772,6 +789,9 @@ struct iwl_rate_info {
u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */
};
+void __iwl_mvm_mac_stop(struct iwl_mvm *mvm);
+int __iwl_mvm_mac_start(struct iwl_mvm *mvm);
+
/******************
* MVM Methods
******************/
@@ -878,7 +898,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- bool force_assoc_off);
+ bool force_assoc_off, const u8 *bssid_override);
int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
@@ -968,6 +988,7 @@ int rs_pretty_print_rate(char *buf, const u32 rate);
/* power management */
int iwl_mvm_power_update_device(struct iwl_mvm *mvm);
int iwl_mvm_power_update_mac(struct iwl_mvm *mvm);
+int iwl_mvm_power_update_ps(struct iwl_mvm *mvm);
int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
char *buf, int bufsz);
@@ -1136,7 +1157,17 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* TDLS */
int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm);
+void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ bool sta_added);
+void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
+#else
+static inline void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) {}
+#endif
#endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index cfdd314fdd5..af074563e77 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -62,6 +64,7 @@
*****************************************************************************/
#include <linux/firmware.h>
#include "iwl-trans.h"
+#include "iwl-csr.h"
#include "mvm.h"
#include "iwl-eeprom-parse.h"
#include "iwl-eeprom-read.h"
@@ -347,7 +350,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
/* Maximal size depends on HW family and step */
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
max_section_size = IWL_MAX_NVM_SECTION_SIZE;
- else if ((mvm->trans->hw_rev & 0xc) == 0) /* Family 8000 A-step */
+ else if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP)
max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE;
else /* Family 8000 B-step */
max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE;
diff --git a/drivers/net/wireless/iwlwifi/mvm/offloading.c b/drivers/net/wireless/iwlwifi/mvm/offloading.c
index 9bfb95e89cf..adcbf4c8edd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/offloading.c
+++ b/drivers/net/wireless/iwlwifi/mvm/offloading.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 610dbcb0dc2..f887779717d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -330,6 +332,8 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(BCAST_FILTER_CMD),
CMD(REPLY_SF_CFG_CMD),
CMD(REPLY_BEACON_FILTERING_CMD),
+ CMD(CMD_DTS_MEASUREMENT_TRIGGER),
+ CMD(DTS_MEASUREMENT_NOTIFICATION),
CMD(REPLY_THERMAL_MNG_BACKOFF),
CMD(MAC_PM_POWER_TABLE),
CMD(BT_COEX_CI),
@@ -362,6 +366,8 @@ static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg)
return 0;
}
+static void iwl_mvm_fw_error_dump_wk(struct work_struct *work);
+
static struct iwl_op_mode *
iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const struct iwl_fw *fw, struct dentry *dbgfs_dir)
@@ -415,6 +421,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->first_agg_queue = 12;
}
mvm->sf_state = SF_UNINIT;
+ mvm->low_latency_agg_frame_limit = 1;
mutex_init(&mvm->mutex);
mutex_init(&mvm->d0i3_suspend_mutex);
@@ -428,6 +435,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk);
INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk);
INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
+ INIT_WORK(&mvm->fw_error_dump_wk, iwl_mvm_fw_error_dump_wk);
spin_lock_init(&mvm->d0i3_tx_lock);
spin_lock_init(&mvm->refs_lock);
@@ -456,7 +464,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
trans_cfg.command_names = iwl_mvm_cmd_strings;
trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE;
- trans_cfg.cmd_fifo = IWL_MVM_CMD_FIFO;
+ trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD;
+ trans_cfg.scd_set_active = true;
snprintf(mvm->hw->wiphy->fw_version,
sizeof(mvm->hw->wiphy->fw_version),
@@ -494,7 +503,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
goto out_free;
/*
- * Even if nvm exists in the nvm_file driver should read agin the nvm
+ * Even if nvm exists in the nvm_file driver should read again the nvm
* from the nic because there might be entries that exist in the OTP
* and not in the file.
* for nics with no_power_up_nic_in_init: rely completley on nvm_file
@@ -700,14 +709,13 @@ static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
return;
- if (atomic_inc_return(&mvm->queue_stop_count[mq]) > 1) {
+ if (atomic_inc_return(&mvm->mac80211_queue_stop_count[mq]) > 1) {
IWL_DEBUG_TX_QUEUES(mvm,
"queue %d (mac80211 %d) already stopped\n",
queue, mq);
return;
}
- set_bit(mq, &mvm->transport_queue_stop);
ieee80211_stop_queue(mvm->hw, mq);
}
@@ -719,15 +727,13 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
return;
- if (atomic_dec_return(&mvm->queue_stop_count[mq]) > 0) {
+ if (atomic_dec_return(&mvm->mac80211_queue_stop_count[mq]) > 0) {
IWL_DEBUG_TX_QUEUES(mvm,
- "queue %d (mac80211 %d) already awake\n",
+ "queue %d (mac80211 %d) still stopped\n",
queue, mq);
return;
}
- clear_bit(mq, &mvm->transport_queue_stop);
-
ieee80211_wake_queue(mvm->hw, mq);
}
@@ -781,6 +787,16 @@ static void iwl_mvm_reprobe_wk(struct work_struct *wk)
module_put(THIS_MODULE);
}
+static void iwl_mvm_fw_error_dump_wk(struct work_struct *work)
+{
+ struct iwl_mvm *mvm =
+ container_of(work, struct iwl_mvm, fw_error_dump_wk);
+
+ mutex_lock(&mvm->mutex);
+ iwl_mvm_fw_error_dump(mvm);
+ mutex_unlock(&mvm->mutex);
+}
+
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
{
iwl_abort_notification_waits(&mvm->notif_wait);
@@ -846,6 +862,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
if (fw_error && mvm->restart_fw > 0)
mvm->restart_fw--;
ieee80211_restart_hw(mvm->hw);
+ } else if (fw_error) {
+ schedule_work(&mvm->fw_error_dump_wk);
}
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
index 6cc243f7cf6..12283b55ee8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index 2b2d10800a5..5b85b0cc7a2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -198,8 +200,15 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
}
}
- if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))
+ if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ /* set advanced pm flag with no uapsd ACs to enable ps-poll */
+ if (mvmvif->dbgfs_pm.use_ps_poll)
+ cmd->flags |=
+ cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
+#endif
return;
+ }
cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK);
@@ -277,13 +286,28 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
return true;
}
+static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif)
+{
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ struct ieee80211_channel *chan;
+ bool radar_detect = false;
+
+ rcu_read_lock();
+ chanctx_conf = rcu_dereference(vif->chanctx_conf);
+ WARN_ON(!chanctx_conf);
+ if (chanctx_conf) {
+ chan = chanctx_conf->def.chan;
+ radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
+ }
+ rcu_read_unlock();
+
+ return radar_detect;
+}
+
static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_power_cmd *cmd)
{
- struct ieee80211_hw *hw = mvm->hw;
- struct ieee80211_chanctx_conf *chanctx_conf;
- struct ieee80211_channel *chan;
int dtimper, dtimper_msec;
int keep_alive;
bool radar_detect = false;
@@ -292,7 +316,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
mvmvif->color));
- dtimper = hw->conf.ps_dtim_period ?: 1;
+ dtimper = vif->bss_conf.dtim_period;
/*
* Regardless of power management state the driver must set
@@ -312,7 +336,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) ||
- !mvmvif->pm_enabled)
+ !mvmvif->pm_enabled || iwl_mvm_tdls_sta_count(mvm, vif))
return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
@@ -325,14 +349,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
}
/* Check if radar detection is required on current channel */
- rcu_read_lock();
- chanctx_conf = rcu_dereference(vif->chanctx_conf);
- WARN_ON(!chanctx_conf);
- if (chanctx_conf) {
- chan = chanctx_conf->def.chan;
- radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
- }
- rcu_read_unlock();
+ radar_detect = iwl_mvm_power_is_radar(vif);
/* Check skip over DTIM conditions */
if (!radar_detect && (dtimper <= 10) &&
@@ -493,17 +510,33 @@ struct iwl_power_vifs {
bool bss_active;
bool ap_active;
bool monitor_active;
- bool bss_tdls;
- bool p2p_tdls;
};
-static void iwl_mvm_power_iterator(void *_data, u8 *mac,
- struct ieee80211_vif *vif)
+static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac,
+ struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_power_vifs *power_iterator = _data;
mvmvif->pm_enabled = false;
+}
+
+static void iwl_mvm_power_ps_disabled_iterator(void *_data, u8* mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ bool *disable_ps = _data;
+
+ if (mvmvif->phy_ctxt)
+ if (mvmvif->phy_ctxt->id < MAX_PHYS)
+ *disable_ps |= mvmvif->ps_disabled;
+}
+
+static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_power_vifs *power_iterator = _data;
+
switch (ieee80211_vif_type_p2p(vif)) {
case NL80211_IFTYPE_P2P_DEVICE:
break;
@@ -531,8 +564,6 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac,
/* only a single MAC of the same type */
WARN_ON(power_iterator->p2p_vif);
power_iterator->p2p_vif = vif;
- power_iterator->p2p_tdls =
- !!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif);
if (mvmvif->phy_ctxt)
if (mvmvif->phy_ctxt->id < MAX_PHYS)
power_iterator->p2p_active = true;
@@ -542,8 +573,6 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac,
/* only a single MAC of the same type */
WARN_ON(power_iterator->bss_vif);
power_iterator->bss_vif = vif;
- power_iterator->bss_tdls =
- !!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif);
if (mvmvif->phy_ctxt)
if (mvmvif->phy_ctxt->id < MAX_PHYS)
power_iterator->bss_active = true;
@@ -559,9 +588,8 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac,
}
}
-static void
-iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
- struct iwl_power_vifs *vifs)
+static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
+ struct iwl_power_vifs *vifs)
{
struct iwl_mvm_vif *bss_mvmvif = NULL;
struct iwl_mvm_vif *p2p_mvmvif = NULL;
@@ -571,10 +599,11 @@ iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
- /* get vifs info + set pm_enable to false */
+ /* set pm_enable to false */
ieee80211_iterate_active_interfaces_atomic(mvm->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_power_iterator, vifs);
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_power_disable_pm_iterator,
+ NULL);
if (vifs->bss_vif)
bss_mvmvif = iwl_mvm_vif_from_mac80211(vifs->bss_vif);
@@ -586,15 +615,13 @@ iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif);
/* enable PM on bss if bss stand alone */
- if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active &&
- !vifs->bss_tdls) {
+ if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) {
bss_mvmvif->pm_enabled = true;
return;
}
/* enable PM on p2p if p2p stand alone */
- if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active &&
- !vifs->p2p_tdls) {
+ if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) {
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM)
p2p_mvmvif->pm_enabled = true;
return;
@@ -817,32 +844,92 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
return ret;
}
-int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
+static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm)
+{
+ bool disable_ps;
+ int ret;
+
+ /* disable PS if CAM */
+ disable_ps = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM);
+ /* ...or if any of the vifs require PS to be off */
+ ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_power_ps_disabled_iterator,
+ &disable_ps);
+
+ /* update device power state if it has changed */
+ if (mvm->ps_disabled != disable_ps) {
+ bool old_ps_disabled = mvm->ps_disabled;
+
+ mvm->ps_disabled = disable_ps;
+ ret = iwl_mvm_power_update_device(mvm);
+ if (ret) {
+ mvm->ps_disabled = old_ps_disabled;
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm,
+ struct iwl_power_vifs *vifs)
{
struct iwl_mvm_vif *mvmvif;
+ bool ba_enable;
+
+ if (!vifs->bf_vif)
+ return 0;
+
+ mvmvif = iwl_mvm_vif_from_mac80211(vifs->bf_vif);
+
+ ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled ||
+ !vifs->bf_vif->bss_conf.ps ||
+ iwl_mvm_vif_low_latency(mvmvif));
+
+ return iwl_mvm_update_beacon_abort(mvm, vifs->bf_vif, ba_enable);
+}
+
+int iwl_mvm_power_update_ps(struct iwl_mvm *mvm)
+{
+ struct iwl_power_vifs vifs = {
+ .mvm = mvm,
+ };
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ /* get vifs info */
+ ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_power_get_vifs_iterator, &vifs);
+
+ ret = iwl_mvm_power_set_ps(mvm);
+ if (ret)
+ return ret;
+
+ return iwl_mvm_power_set_ba(mvm, &vifs);
+}
+
+int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
+{
struct iwl_power_vifs vifs = {
.mvm = mvm,
};
- bool ba_enable;
int ret;
lockdep_assert_held(&mvm->mutex);
+ /* get vifs info */
+ ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_power_get_vifs_iterator, &vifs);
+
iwl_mvm_power_set_pm(mvm, &vifs);
- /* disable PS if CAM */
- if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) {
- mvm->ps_disabled = true;
- } else {
- /* don't update device power state unless we add / remove monitor */
- if (vifs.monitor_vif) {
- if (vifs.monitor_active)
- mvm->ps_disabled = true;
- ret = iwl_mvm_power_update_device(mvm);
- if (ret)
- return ret;
- }
- }
+ ret = iwl_mvm_power_set_ps(mvm);
+ if (ret)
+ return ret;
if (vifs.bss_vif) {
ret = iwl_mvm_power_send_cmd(mvm, vifs.bss_vif);
@@ -856,16 +943,7 @@ int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
return ret;
}
- if (!vifs.bf_vif)
- return 0;
-
- mvmvif = iwl_mvm_vif_from_mac80211(vifs.bf_vif);
-
- ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled ||
- !vifs.bf_vif->bss_conf.ps ||
- iwl_mvm_vif_low_latency(mvmvif));
-
- return iwl_mvm_update_beacon_abort(mvm, vifs.bf_vif, ba_enable);
+ return iwl_mvm_power_set_ba(mvm, &vifs);
}
int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
@@ -884,17 +962,22 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
iwl_mvm_power_build_cmd(mvm, vif, &cmd);
if (enable) {
- /* configure skip over dtim up to 300 msec */
- int dtimper = mvm->hw->conf.ps_dtim_period ?: 1;
- int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
+ /* configure skip over dtim up to 306TU - 314 msec */
+ int dtimper = vif->bss_conf.dtim_period ?: 1;
+ int dtimper_tu = dtimper * vif->bss_conf.beacon_int;
+ bool radar_detect = iwl_mvm_power_is_radar(vif);
- if (WARN_ON(!dtimper_msec))
+ if (WARN_ON(!dtimper_tu))
return 0;
- cmd.skip_dtim_periods = 300 / dtimper_msec;
- if (cmd.skip_dtim_periods)
- cmd.flags |=
- cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
+ /* Check skip over DTIM conditions */
+ /* TODO: check that multicast wake lock is off */
+ if (!radar_detect && (dtimper < 10)) {
+ cmd.skip_dtim_periods = 306 / dtimper_tu;
+ if (cmd.skip_dtim_periods)
+ cmd.flags |= cpu_to_le16(
+ POWER_FLAGS_SKIP_OVER_DTIM_MSK);
+ }
}
iwl_mvm_power_log(mvm, &cmd);
#ifdef CONFIG_IWLWIFI_DEBUGFS
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c
index 4e20b3ce2b6..dbb2594390e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/quota.c
+++ b/drivers/net/wireless/iwlwifi/mvm/quota.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -161,6 +163,9 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm,
quota *= (beacon_int - mvm->noa_duration);
quota /= beacon_int;
+ IWL_DEBUG_QUOTA(mvm, "quota: adjust for NoA from %d to %d\n",
+ le32_to_cpu(cmd->quotas[i].quota), quota);
+
cmd->quotas[i].quota = cpu_to_le32(quota);
}
#endif
@@ -170,12 +175,14 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
struct ieee80211_vif *disabled_vif)
{
struct iwl_time_quota_cmd cmd = {};
- int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat;
+ int i, idx, err, num_active_macs, quota, quota_rem, n_non_lowlat;
struct iwl_mvm_quota_iterator_data data = {
.n_interfaces = {},
.colors = { -1, -1, -1, -1 },
.disabled_vif = disabled_vif,
};
+ struct iwl_time_quota_cmd *last = &mvm->last_quota_cmd;
+ bool send = false;
lockdep_assert_held(&mvm->mutex);
@@ -222,6 +229,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat;
quota_rem = QUOTA_100 - n_non_lowlat * quota -
QUOTA_LOWLAT_MIN;
+ IWL_DEBUG_QUOTA(mvm,
+ "quota: low-latency binding active, remaining quota per other binding: %d\n",
+ quota);
} else if (num_active_macs) {
/*
* There are 0 or more than 1 low latency bindings, or all the
@@ -230,6 +240,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
*/
quota = QUOTA_100 / num_active_macs;
quota_rem = QUOTA_100 % num_active_macs;
+ IWL_DEBUG_QUOTA(mvm,
+ "quota: splitting evenly per binding: %d\n",
+ quota);
} else {
/* values don't really matter - won't be used */
quota = 0;
@@ -271,6 +284,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
for (i = 0; i < MAX_BINDINGS; i++) {
if (le32_to_cpu(cmd.quotas[i].quota) != 0) {
le32_add_cpu(&cmd.quotas[i].quota, quota_rem);
+ IWL_DEBUG_QUOTA(mvm,
+ "quota: giving remainder of %d to binding %d\n",
+ quota_rem, i);
break;
}
}
@@ -279,15 +295,33 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
/* check that we have non-zero quota for all valid bindings */
for (i = 0; i < MAX_BINDINGS; i++) {
+ if (cmd.quotas[i].id_and_color != last->quotas[i].id_and_color)
+ send = true;
+ if (cmd.quotas[i].max_duration != last->quotas[i].max_duration)
+ send = true;
+ if (abs((int)le32_to_cpu(cmd.quotas[i].quota) -
+ (int)le32_to_cpu(last->quotas[i].quota))
+ > IWL_MVM_QUOTA_THRESHOLD)
+ send = true;
if (cmd.quotas[i].id_and_color == cpu_to_le32(FW_CTXT_INVALID))
continue;
WARN_ONCE(cmd.quotas[i].quota == 0,
"zero quota on binding %d\n", i);
}
- ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0,
- sizeof(cmd), &cmd);
- if (ret)
- IWL_ERR(mvm, "Failed to send quota: %d\n", ret);
- return ret;
+ if (!send) {
+ /* don't send a practically unchanged command, the firmware has
+ * to re-initialize a lot of state and that can have an adverse
+ * impact on it
+ */
+ return 0;
+ }
+
+ err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd);
+
+ if (err)
+ IWL_ERR(mvm, "Failed to send quota: %d\n", err);
+ else
+ mvm->last_quota_cmd = cmd;
+ return err;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index c70e959bf0e..f77dfe4df07 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -1,6 +1,7 @@
/******************************************************************************
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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
@@ -504,10 +505,10 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type)
static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate,
const char *prefix)
{
- IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d\n",
+ IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d\n",
prefix, rs_pretty_lq_type(rate->type),
rate->index, rs_pretty_ant(rate->ant),
- rate->bw, rate->sgi);
+ rate->bw, rate->sgi, rate->ldpc);
}
static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
@@ -671,8 +672,10 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta,
return -EINVAL;
if (tbl->column != RS_COLUMN_INVALID) {
- lq_sta->tx_stats[tbl->column][scale_index].total += attempts;
- lq_sta->tx_stats[tbl->column][scale_index].success += successes;
+ struct lq_sta_pers *pers = &lq_sta->pers;
+
+ pers->tx_stats[tbl->column][scale_index].total += attempts;
+ pers->tx_stats[tbl->column][scale_index].success += successes;
}
/* Select window for current tx bit rate */
@@ -741,6 +744,8 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
ucode_rate |= rate->bw;
if (rate->sgi)
ucode_rate |= RATE_MCS_SGI_MSK;
+ if (rate->ldpc)
+ ucode_rate |= RATE_MCS_LDPC_MSK;
return ucode_rate;
}
@@ -778,6 +783,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
/* HT or VHT */
if (ucode_rate & RATE_MCS_SGI_MSK)
rate->sgi = true;
+ if (ucode_rate & RATE_MCS_LDPC_MSK)
+ rate->ldpc = true;
rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK;
@@ -964,13 +971,13 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
rate->index > IWL_RATE_MCS_9_INDEX);
rate->index = rs_ht_to_legacy[rate->index];
+ rate->ldpc = false;
} else {
/* Downgrade to SISO with same MCS if in MIMO */
rate->type = is_vht_mimo2(rate) ?
LQ_VHT_SISO : LQ_HT_SISO;
}
-
if (num_of_ant(rate->ant) > 1)
rate->ant = first_antenna(mvm->fw->valid_tx_ant);
@@ -1620,6 +1627,7 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
}
rate->bw = rs_bw_from_sta_bw(sta);
+ rate->ldpc = lq_sta->ldpc;
search_tbl->column = col_id;
rs_set_expected_tpt_table(lq_sta, search_tbl);
@@ -2030,18 +2038,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
return;
}
- /* force user max rate if set by user */
- if ((lq_sta->max_rate_idx != -1) &&
- (lq_sta->max_rate_idx < index)) {
- index = lq_sta->max_rate_idx;
- update_lq = 1;
- window = &(tbl->win[index]);
- IWL_DEBUG_RATE(mvm,
- "Forcing user max rate %d\n",
- index);
- goto lq_update;
- }
-
+ /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
window = &(tbl->win[index]);
/*
@@ -2129,10 +2126,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
low = high_low & 0xff;
high = (high_low >> 8) & 0xff;
- /* If user set max rate, dont allow higher than user constrain */
- if ((lq_sta->max_rate_idx != -1) &&
- (lq_sta->max_rate_idx < high))
- high = IWL_RATE_INVALID;
+ /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
sr = window->success_ratio;
@@ -2341,6 +2335,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
rate->index = i;
rate->ant = first_antenna(valid_tx_ant);
rate->sgi = false;
+ rate->ldpc = false;
rate->bw = RATE_MCS_CHAN_WIDTH_20;
if (band == IEEE80211_BAND_5GHZ)
rate->type = LQ_LEGACY_A;
@@ -2363,23 +2358,13 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
struct ieee80211_tx_rate_control *txrc)
{
struct sk_buff *skb = txrc->skb;
- struct ieee80211_supported_band *sband = txrc->sband;
struct iwl_op_mode *op_mode __maybe_unused =
(struct iwl_op_mode *)mvm_r;
struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_lq_sta *lq_sta = mvm_sta;
- /* Get max rate if user set max rate */
- if (lq_sta) {
- lq_sta->max_rate_idx = txrc->max_rate_idx;
- if ((sband->band == IEEE80211_BAND_5GHZ) &&
- (lq_sta->max_rate_idx != -1))
- lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE;
- if ((lq_sta->max_rate_idx < 0) ||
- (lq_sta->max_rate_idx >= IWL_RATE_COUNT))
- lq_sta->max_rate_idx = -1;
- }
+ /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
/* Treat uninitialized rate scaling data same as non-existing. */
if (lq_sta && !lq_sta->pers.drv) {
@@ -2580,7 +2565,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
* previous packets? Need to have IEEE 802.1X auth succeed immediately
* after assoc.. */
- lq_sta->max_rate_idx = -1;
lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
lq_sta->band = sband->band;
/*
@@ -2609,9 +2593,16 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
lq_sta->is_vht = false;
+ if (mvm->cfg->ht_params->ldpc &&
+ (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
+ lq_sta->ldpc = true;
} else {
rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
lq_sta->is_vht = true;
+
+ if (mvm->cfg->ht_params->ldpc &&
+ (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
+ lq_sta->ldpc = true;
}
lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate,
@@ -2621,11 +2612,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate,
BITS_PER_LONG);
- IWL_DEBUG_RATE(mvm, "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d\n",
+ IWL_DEBUG_RATE(mvm,
+ "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d\n",
lq_sta->active_legacy_rate,
lq_sta->active_siso_rate,
lq_sta->active_mimo2_rate,
- lq_sta->is_vht);
+ lq_sta->is_vht, lq_sta->ldpc);
IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n",
lq_sta->max_legacy_rate_idx,
lq_sta->max_siso_rate_idx,
@@ -2678,6 +2670,7 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm,
int i;
int num_rates = ARRAY_SIZE(lq_cmd->rs_table);
__le32 ucode_rate_le32 = cpu_to_le32(ucode_rate);
+ u8 ant = (ucode_rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS;
for (i = 0; i < num_rates; i++)
lq_cmd->rs_table[i] = ucode_rate_le32;
@@ -2688,6 +2681,13 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm,
lq_cmd->mimo_delim = num_rates - 1;
else
lq_cmd->mimo_delim = 0;
+
+ lq_cmd->reduced_tpc = 0;
+
+ if (num_of_ant(ant) == 1)
+ lq_cmd->single_stream_ant_msk = ant;
+
+ lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
}
#endif /* CONFIG_MAC80211_DEBUGFS */
@@ -2811,31 +2811,55 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
const struct rs_rate *initial_rate)
{
struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
- u8 ant = initial_rate->ant;
+ struct iwl_mvm_sta *mvmsta;
+ struct iwl_mvm_vif *mvmvif;
+
+ lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+ lq_cmd->agg_time_limit =
+ cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
#ifdef CONFIG_MAC80211_DEBUGFS
if (lq_sta->pers.dbg_fixed_rate) {
rs_build_rates_table_from_fixed(mvm, lq_cmd,
lq_sta->band,
lq_sta->pers.dbg_fixed_rate);
- lq_cmd->reduced_tpc = 0;
- ant = (lq_sta->pers.dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) >>
- RATE_MCS_ANT_POS;
- } else
+ return;
+ }
#endif
- rs_build_rates_table(mvm, lq_sta, initial_rate);
+ if (WARN_ON_ONCE(!sta || !initial_rate))
+ return;
- if (num_of_ant(ant) == 1)
- lq_cmd->single_stream_ant_msk = ant;
+ rs_build_rates_table(mvm, lq_sta, initial_rate);
- lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
- lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+ if (num_of_ant(initial_rate->ant) == 1)
+ lq_cmd->single_stream_ant_msk = initial_rate->ant;
- lq_cmd->agg_time_limit =
- cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
+ mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
- if (sta)
- lq_cmd->agg_time_limit =
+ if (num_of_ant(initial_rate->ant) == 1)
+ lq_cmd->single_stream_ant_msk = initial_rate->ant;
+
+ lq_cmd->agg_frame_cnt_limit = mvmsta->max_agg_bufsize;
+
+ /*
+ * In case of low latency, tell the firwmare to leave a frame in the
+ * Tx Fifo so that it can start a transaction in the same TxOP. This
+ * basically allows the firmware to send bursts.
+ */
+ if (iwl_mvm_vif_low_latency(mvmvif)) {
+ lq_cmd->agg_frame_cnt_limit--;
+
+ if (mvm->low_latency_agg_frame_limit)
+ lq_cmd->agg_frame_cnt_limit =
+ min(lq_cmd->agg_frame_cnt_limit,
+ mvm->low_latency_agg_frame_limit);
+ }
+
+ if (mvmsta->vif->p2p)
+ lq_cmd->flags |= LQ_FLAG_USE_RTS_MSK;
+
+ lq_cmd->agg_time_limit =
cpu_to_le16(iwl_mvm_coex_agg_time_limit(mvm, sta));
}
@@ -2932,10 +2956,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm,
lq_sta->lq.sta_id, lq_sta->pers.dbg_fixed_rate);
if (lq_sta->pers.dbg_fixed_rate) {
- struct rs_rate rate;
- rs_rate_from_ucode_rate(lq_sta->pers.dbg_fixed_rate,
- lq_sta->band, &rate);
- rs_fill_lq_cmd(mvm, NULL, lq_sta, &rate);
+ rs_fill_lq_cmd(mvm, NULL, lq_sta, NULL);
iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq, false);
}
}
@@ -3002,8 +3023,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
(is_ht20(rate)) ? "20MHz" :
(is_ht40(rate)) ? "40MHz" :
(is_ht80(rate)) ? "80Mhz" : "BAD BW");
- desc += sprintf(buff+desc, " %s %s\n",
+ desc += sprintf(buff+desc, " %s %s %s\n",
(rate->sgi) ? "SGI" : "NGI",
+ (rate->ldpc) ? "LDPC" : "BCC",
(lq_sta->is_agg) ? "AGG on" : "");
}
desc += sprintf(buff+desc, "last tx rate=0x%X\n",
@@ -3151,7 +3173,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_read(struct file *file,
"%s,", column_name[col]);
for (rate = 0; rate < IWL_RATE_COUNT; rate++) {
- stats = &(lq_sta->tx_stats[col][rate]);
+ stats = &(lq_sta->pers.tx_stats[col][rate]);
pos += scnprintf(pos, endpos - pos,
"%llu/%llu,",
stats->success,
@@ -3170,7 +3192,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_write(struct file *file,
size_t count, loff_t *ppos)
{
struct iwl_lq_sta *lq_sta = file->private_data;
- memset(lq_sta->tx_stats, 0, sizeof(lq_sta->tx_stats));
+ memset(lq_sta->pers.tx_stats, 0, sizeof(lq_sta->pers.tx_stats));
return count;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index f27b9d687a2..95c4b960fd7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -207,6 +207,7 @@ struct rs_rate {
u8 ant;
u32 bw;
bool sgi;
+ bool ldpc;
};
@@ -329,10 +330,9 @@ struct iwl_lq_sta {
*/
u64 last_tx;
bool is_vht;
+ bool ldpc; /* LDPC Rx is supported by the STA */
enum ieee80211_band band;
- struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT];
-
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
unsigned long active_legacy_rate;
unsigned long active_siso_rate;
@@ -343,7 +343,6 @@ struct iwl_lq_sta {
u8 max_siso_rate_idx;
u8 max_mimo2_rate_idx;
- s8 max_rate_idx; /* Max rate set by user */
u8 missed_rate_counter;
struct iwl_lq_cmd lq;
@@ -361,11 +360,14 @@ struct iwl_lq_sta {
int tpc_reduce;
/* persistent fields - initialized only once - keep last! */
- struct {
+ struct lq_sta_pers {
#ifdef CONFIG_MAC80211_DEBUGFS
u32 dbg_fixed_rate;
u8 dbg_fixed_txp_reduction;
#endif
+ u8 chains;
+ s8 chain_signal[IEEE80211_MAX_CHAINS];
+ struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT];
struct iwl_mvm *drv;
} pers;
};
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index 4b98987fc41..a6cb84ed653 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -149,13 +151,13 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_ENERGY_ANT_ABC_IDX]);
energy_a = (val & IWL_RX_INFO_ENERGY_ANT_A_MSK) >>
IWL_RX_INFO_ENERGY_ANT_A_POS;
- energy_a = energy_a ? -energy_a : -256;
+ energy_a = energy_a ? -energy_a : S8_MIN;
energy_b = (val & IWL_RX_INFO_ENERGY_ANT_B_MSK) >>
IWL_RX_INFO_ENERGY_ANT_B_POS;
- energy_b = energy_b ? -energy_b : -256;
+ energy_b = energy_b ? -energy_b : S8_MIN;
energy_c = (val & IWL_RX_INFO_ENERGY_ANT_C_MSK) >>
IWL_RX_INFO_ENERGY_ANT_C_POS;
- energy_c = energy_c ? -energy_c : -256;
+ energy_c = energy_c ? -energy_c : S8_MIN;
max_energy = max(energy_a, energy_b);
max_energy = max(max_energy, energy_c);
@@ -491,10 +493,29 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
.mvm = mvm,
};
+ /*
+ * set temperature debug enabled - ignore FW temperature updates
+ * and use the user set temperature.
+ */
+ if (mvm->temperature_test) {
+ if (mvm->temperature < le32_to_cpu(common->temperature))
+ IWL_DEBUG_TEMP(mvm,
+ "Ignoring FW temperature update that is greater than the debug set temperature (debug temp = %d, fw temp = %d)\n",
+ mvm->temperature,
+ le32_to_cpu(common->temperature));
+ /*
+ * skip iwl_mvm_tt_handler since we are in
+ * temperature debug mode and we are ignoring
+ * the new temperature value
+ */
+ goto update;
+ }
+
if (mvm->temperature != le32_to_cpu(common->temperature)) {
mvm->temperature = le32_to_cpu(common->temperature);
iwl_mvm_tt_handler(mvm);
}
+update:
iwl_mvm_update_rx_statistics(mvm, stats);
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 004b1f5d031..09545f23b24 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -158,8 +160,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid,
static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
{
if (band == IEEE80211_BAND_2GHZ)
- return 30 + 3 * (n_ssids + 1);
- return 20 + 2 * (n_ssids + 1);
+ return 20 + 3 * (n_ssids + 1);
+ return 10 + 2 * (n_ssids + 1);
}
static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band)
@@ -279,6 +281,7 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
{
bool global_bound = false;
enum ieee80211_band band;
+ u8 frag_passive_dwell = 0;
ieee80211_iterate_active_interfaces_atomic(mvm->hw,
IEEE80211_IFACE_ITER_NORMAL,
@@ -288,12 +291,36 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
if (!global_bound)
goto not_bound;
- params->suspend_time = 100;
- params->max_out_time = 600;
+ params->suspend_time = 30;
+ params->max_out_time = 170;
if (iwl_mvm_low_latency(mvm)) {
- params->suspend_time = 250;
- params->max_out_time = 250;
+ if (mvm->fw->ucode_capa.api[0] &
+ IWL_UCODE_TLV_API_FRAGMENTED_SCAN) {
+ params->suspend_time = 105;
+ params->max_out_time = 70;
+ frag_passive_dwell = 20;
+ } else {
+ params->suspend_time = 120;
+ params->max_out_time = 120;
+ }
+ }
+
+ if (frag_passive_dwell && (mvm->fw->ucode_capa.api[0] &
+ 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
+ * equal to dwell time on passive channel. Take a longest
+ * possible value, one that corresponds to 2GHz band
+ */
+ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+ u32 passive_dwell =
+ iwl_mvm_get_passive_dwell(IEEE80211_BAND_2GHZ);
+ params->max_out_time = passive_dwell;
+ } else {
+ params->passive_fragmented = true;
+ }
}
if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
@@ -302,7 +329,11 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
not_bound:
for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
- params->dwell[band].passive = iwl_mvm_get_passive_dwell(band);
+ if (params->passive_fragmented)
+ params->dwell[band].passive = frag_passive_dwell;
+ else
+ params->dwell[band].passive =
+ iwl_mvm_get_passive_dwell(band);
params->dwell[band].active = iwl_mvm_get_active_dwell(band,
n_ssids);
}
@@ -1100,10 +1131,11 @@ iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm,
struct iwl_mvm_scan_params *params)
{
memset(cmd, 0, ksize(cmd));
- cmd->active_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].active;
- cmd->passive_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].passive;
- /* TODO: Use params; now fragmented isn't used. */
- cmd->fragmented_dwell = 0;
+ 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].passive;
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);
diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c
index 7edfd15efc9..7eb78e2c240 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sf.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sf.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -172,11 +174,15 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
enum iwl_sf_state new_state)
{
struct iwl_sf_cfg_cmd sf_cmd = {
- .state = new_state,
+ .state = cpu_to_le32(new_state),
};
struct ieee80211_sta *sta;
int ret = 0;
+ if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF &&
+ mvm->cfg->disable_dummy_notification)
+ sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF);
+
/*
* If an associated AP sta changed its antenna configuration, the state
* will remain FULL_ON but SF parameters need to be reconsidered.
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 76354888039..666f16b4bed 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -250,10 +252,14 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
if (ret)
return ret;
- /* The first station added is the AP, the others are TDLS STAs */
- if (vif->type == NL80211_IFTYPE_STATION &&
- mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
- mvmvif->ap_sta_id = sta_id;
+ if (vif->type == NL80211_IFTYPE_STATION) {
+ if (!sta->tdls) {
+ WARN_ON(mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT);
+ mvmvif->ap_sta_id = sta_id;
+ } else {
+ WARN_ON(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT);
+ }
+ }
rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
@@ -458,8 +464,9 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
return ret;
}
-int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
- u32 qmask, enum nl80211_iftype iftype)
+static int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm,
+ struct iwl_mvm_int_sta *sta,
+ u32 qmask, enum nl80211_iftype iftype)
{
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype);
@@ -474,7 +481,8 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
return 0;
}
-void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta)
+static void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm,
+ struct iwl_mvm_int_sta *sta)
{
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL);
memset(sta, 0, sizeof(struct iwl_mvm_int_sta));
@@ -544,6 +552,13 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
return ret;
}
+void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm)
+{
+ lockdep_assert_held(&mvm->mutex);
+
+ iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
+}
+
/*
* Send the add station command for the vif's broadcast station.
* Assumes that the station was already allocated.
@@ -552,10 +567,10 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
* @vif: the interface to which the broadcast station is added
* @bsta: the broadcast station to add.
*/
-int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta;
static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
const u8 *baddr = _baddr;
@@ -573,19 +588,40 @@ int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* Send the FW a request to remove the station from it's internal data
* structures, but DO NOT remove the entry from the local data structures. */
-int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
- struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
lockdep_assert_held(&mvm->mutex);
- ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id);
+ ret = iwl_mvm_rm_sta_common(mvm, mvmvif->bcast_sta.sta_id);
if (ret)
IWL_WARN(mvm, "Failed sending remove station\n");
return ret;
}
+int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ u32 qmask;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
+
+ /*
+ * The firmware defines the TFD queue mask to only be relevant
+ * for *unicast* queues, so the multicast (CAB) queue shouldn't
+ * be included.
+ */
+ if (vif->type == NL80211_IFTYPE_AP)
+ qmask &= ~BIT(vif->cab_queue);
+
+ return iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, qmask,
+ ieee80211_vif_type_p2p(vif));
+}
+
/* Allocate a new station entry for the broadcast station to the given vif,
* and send it to the FW.
* Note that each P2P mac should have its own broadcast station.
@@ -593,45 +629,47 @@ int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
* @mvm: the mvm component
* @vif: the interface to which the broadcast station is added
* @bsta: the broadcast station to add. */
-int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
- u32 qmask;
+ struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta;
int ret;
lockdep_assert_held(&mvm->mutex);
- qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
- ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask,
- ieee80211_vif_type_p2p(vif));
+ ret = iwl_mvm_alloc_bcast_sta(mvm, vif);
if (ret)
return ret;
- ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr,
- mvmvif->id, mvmvif->color);
+ ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
if (ret)
iwl_mvm_dealloc_int_sta(mvm, bsta);
+
return ret;
}
+void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
+}
+
/*
* Send the FW a request to remove the station from it's internal data
* structures, and in addition remove it from the local data structure.
*/
-int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
int ret;
lockdep_assert_held(&mvm->mutex);
- ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id);
- if (ret)
- return ret;
+ ret = iwl_mvm_send_rm_bcast_sta(mvm, vif);
+
+ iwl_mvm_dealloc_bcast_sta(mvm, vif);
- iwl_mvm_dealloc_int_sta(mvm, bsta);
return ret;
}
@@ -910,8 +948,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
}
tid_data->ssn = 0xffff;
- iwl_trans_txq_disable(mvm->trans, txq_id);
- /* fall through */
+ tid_data->state = IWL_AGG_OFF;
+ mvm->queue_to_mac80211[txq_id] = IWL_INVALID_MAC80211_QUEUE;
+ spin_unlock_bh(&mvmsta->lock);
+
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+
+ iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
+
+ iwl_trans_txq_disable(mvm->trans, txq_id, true);
+ return 0;
case IWL_AGG_STARTING:
case IWL_EMPTYING_HW_QUEUE_ADDBA:
/*
@@ -965,7 +1011,9 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
- iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+ iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
+
+ iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true);
}
mvm->queue_to_mac80211[tid_data->txq_id] =
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h
index 3b1c8bd6cb5..aeb3a7f80ce 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -387,17 +389,15 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid);
int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm);
-int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
- u32 qmask, enum nl80211_iftype iftype);
-void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm,
- struct iwl_mvm_int_sta *sta);
-int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct iwl_mvm_int_sta *bsta);
-int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
- struct iwl_mvm_int_sta *bsta);
-int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct iwl_mvm_int_sta *bsta);
-int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta);
+void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm);
+
+int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+
void iwl_mvm_sta_drained_wk(struct work_struct *wk);
void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
struct ieee80211_sta *sta);
diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c
new file mode 100644
index 00000000000..66c82df2d0a
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c
@@ -0,0 +1,149 @@
+/******************************************************************************
+ *
+ * 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) 2014 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) 2014 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 "mvm.h"
+#include "time-event.h"
+
+void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)
+{
+ struct ieee80211_sta *sta;
+ struct iwl_mvm_sta *mvmsta;
+ int i;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
+ lockdep_is_held(&mvm->mutex));
+ if (!sta || IS_ERR(sta) || !sta->tdls)
+ continue;
+
+ mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,
+ NL80211_TDLS_TEARDOWN,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,
+ GFP_KERNEL);
+ }
+}
+
+int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct ieee80211_sta *sta;
+ struct iwl_mvm_sta *mvmsta;
+ int count = 0;
+ int i;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
+ lockdep_is_held(&mvm->mutex));
+ if (!sta || IS_ERR(sta) || !sta->tdls)
+ continue;
+
+ if (vif) {
+ mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ if (mvmsta->vif != vif)
+ continue;
+ }
+
+ count++;
+ }
+
+ return count;
+}
+
+void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ bool sta_added)
+{
+ int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif);
+
+ /*
+ * Disable ps when the first TDLS sta is added and re-enable it
+ * when the last TDLS sta is removed
+ */
+ if ((tdls_sta_cnt == 1 && sta_added) ||
+ (tdls_sta_cnt == 0 && !sta_added))
+ iwl_mvm_power_update_mac(mvm);
+}
+
+void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int;
+
+ /*
+ * iwl_mvm_protect_session() reads directly from the device
+ * (the system time), so make sure it is available.
+ */
+ if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS))
+ return;
+
+ mutex_lock(&mvm->mutex);
+ /* Protect the session to hear the TDLS setup response on the channel */
+ iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true);
+ mutex_unlock(&mvm->mutex);
+
+ iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/testmode.h b/drivers/net/wireless/iwlwifi/mvm/testmode.h
index 0241665925f..79ab6beb6b2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/testmode.h
+++ b/drivers/net/wireless/iwlwifi/mvm/testmode.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index 33e5041f1ef..b7f9e61d14e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -348,6 +350,38 @@ unlock:
return 0;
}
+static bool iwl_mvm_te_notif(struct iwl_notif_wait_data *notif_wait,
+ struct iwl_rx_packet *pkt, void *data)
+{
+ struct iwl_mvm *mvm =
+ container_of(notif_wait, struct iwl_mvm, notif_wait);
+ struct iwl_mvm_time_event_data *te_data = data;
+ struct iwl_time_event_notif *resp;
+ int resp_len = iwl_rx_packet_payload_len(pkt);
+
+ if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_NOTIFICATION))
+ return true;
+
+ if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
+ IWL_ERR(mvm, "Invalid TIME_EVENT_NOTIFICATION response\n");
+ return true;
+ }
+
+ resp = (void *)pkt->data;
+
+ /* te_data->uid is already set in the TIME_EVENT_CMD response */
+ if (le32_to_cpu(resp->unique_id) != te_data->uid)
+ return false;
+
+ IWL_DEBUG_TE(mvm, "TIME_EVENT_NOTIFICATION response - UID = 0x%x\n",
+ te_data->uid);
+ if (!resp->status)
+ IWL_ERR(mvm,
+ "TIME_EVENT_NOTIFICATION received but not executed\n");
+
+ return true;
+}
+
static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait,
struct iwl_rx_packet *pkt, void *data)
{
@@ -441,10 +475,12 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
void iwl_mvm_protect_session(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 duration, u32 min_duration,
- u32 max_delay)
+ u32 max_delay, bool wait_for_notif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
+ const u8 te_notif_response[] = { TIME_EVENT_NOTIFICATION };
+ struct iwl_notification_wait wait_te_notif;
struct iwl_time_event_cmd time_cmd = {};
lockdep_assert_held(&mvm->mutex);
@@ -489,7 +525,28 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
TE_V2_NOTIF_HOST_EVENT_END |
T2_V2_START_IMMEDIATELY);
- iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
+ if (!wait_for_notif) {
+ iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
+ return;
+ }
+
+ /*
+ * Create notification_wait for the TIME_EVENT_NOTIFICATION to use
+ * right after we send the time event
+ */
+ iwl_init_notification_wait(&mvm->notif_wait, &wait_te_notif,
+ te_notif_response,
+ ARRAY_SIZE(te_notif_response),
+ iwl_mvm_te_notif, te_data);
+
+ /* If TE was sent OK - wait for the notification that started */
+ if (iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd)) {
+ IWL_ERR(mvm, "Failed to add TE to protect session\n");
+ iwl_remove_notification(&mvm->notif_wait, &wait_te_notif);
+ } else if (iwl_wait_notification(&mvm->notif_wait, &wait_te_notif,
+ TU_TO_JIFFIES(max_delay))) {
+ IWL_ERR(mvm, "Failed to protect session until TE\n");
+ }
}
/*
@@ -643,9 +700,9 @@ void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm)
iwl_mvm_roc_finished(mvm);
}
-int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- u32 duration, u32 apply_time)
+int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u32 duration, u32 apply_time)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
@@ -654,14 +711,14 @@ int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
if (te_data->running) {
- IWL_DEBUG_TE(mvm, "CS NOA is already scheduled\n");
+ IWL_DEBUG_TE(mvm, "CS period is already scheduled\n");
return -EBUSY;
}
time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
time_cmd.id_and_color =
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
- time_cmd.id = cpu_to_le32(TE_P2P_GO_CSA_NOA);
+ time_cmd.id = cpu_to_le32(TE_CHANNEL_SWITCH_PERIOD);
time_cmd.apply_time = cpu_to_le32(apply_time);
time_cmd.max_frags = TE_V2_FRAG_NONE;
time_cmd.duration = cpu_to_le32(duration);
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h
index 2f48a90d4ad..b350e47e19d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.h
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -124,10 +126,12 @@
* @min_duration: will start a new session if the current session will end
* in less than min_duration.
* @max_delay: maximum delay before starting the time event (in TU)
+ * @wait_for_notif: true if it is required that a time event notification be
+ * waited for (that the time event has been scheduled before returning)
*
* This function can be used to start a session protection which means that the
* fw will stay on the channel for %duration_ms milliseconds. This function
- * will block (sleep) until the session starts. This function can also be used
+ * can block (sleep) until the session starts. This function can also be used
* to extend a currently running session.
* This function is meant to be used for BSS association for example, where we
* want to make sure that the fw stays on the channel during the association.
@@ -135,7 +139,7 @@
void iwl_mvm_protect_session(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 duration, u32 min_duration,
- u32 max_delay);
+ u32 max_delay, bool wait_for_notif);
/**
* iwl_mvm_stop_session_protection - cancel the session protection.
@@ -215,7 +219,7 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
void iwl_mvm_roc_done_wk(struct work_struct *wk);
/**
- * iwl_mvm_schedule_csa_noa - request NoA for channel switch
+ * iwl_mvm_schedule_csa_period - request channel switch absence period
* @mvm: the mvm component
* @vif: the virtual interface for which the channel switch is issued
* @duration: the duration of the NoA in TU.
@@ -224,9 +228,9 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk);
* This function is used to schedule NoA time event and is used to perform
* the channel switch flow.
*/
-int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- u32 duration, u32 apply_time);
+int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u32 duration, u32 apply_time);
/**
* iwl_mvm_te_scheduled - check if the fw received the TE cmd
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c
index 0464599c111..c750ca7b826 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tt.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -67,263 +69,99 @@
#include "iwl-csr.h"
#include "iwl-prph.h"
-#define OTP_DTS_DIODE_DEVIATION 96 /*in words*/
-/* VBG - Voltage Band Gap error data (temperature offset) */
-#define OTP_WP_DTS_VBG (OTP_DTS_DIODE_DEVIATION + 2)
-#define MEAS_VBG_MIN_VAL 2300
-#define MEAS_VBG_MAX_VAL 3000
-#define MEAS_VBG_DEFAULT_VAL 2700
-#define DTS_DIODE_VALID(flags) (flags & DTS_DIODE_REG_FLAGS_PASS_ONCE)
-#define MIN_TEMPERATURE 0
-#define MAX_TEMPERATURE 125
-#define TEMPERATURE_ERROR (MAX_TEMPERATURE + 1)
-#define PTAT_DIGITAL_VALUE_MIN_VALUE 0
-#define PTAT_DIGITAL_VALUE_MAX_VALUE 0xFF
-#define DTS_VREFS_NUM 5
-static inline u32 DTS_DIODE_GET_VREFS_ID(u32 flags)
-{
- return (flags & DTS_DIODE_REG_FLAGS_VREFS_ID) >>
- DTS_DIODE_REG_FLAGS_VREFS_ID_POS;
-}
+#define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ
-#define CALC_VREFS_MIN_DIFF 43
-#define CALC_VREFS_MAX_DIFF 51
-#define CALC_LUT_SIZE (1 + CALC_VREFS_MAX_DIFF - CALC_VREFS_MIN_DIFF)
-#define CALC_LUT_INDEX_OFFSET CALC_VREFS_MIN_DIFF
-#define CALC_TEMPERATURE_RESULT_SHIFT_OFFSET 23
-
-/*
- * @digital_value: The diode's digital-value sampled (temperature/voltage)
- * @vref_low: The lower voltage-reference (the vref just below the diode's
- * sampled digital-value)
- * @vref_high: The higher voltage-reference (the vref just above the diode's
- * sampled digital-value)
- * @flags: bits[1:0]: The ID of the Vrefs pair (lowVref,highVref)
- * bits[6:2]: Reserved.
- * bits[7:7]: Indicates completion of at least 1 successful sample
- * since last DTS reset.
- */
-struct iwl_mvm_dts_diode_bits {
- u8 digital_value;
- u8 vref_low;
- u8 vref_high;
- u8 flags;
-} __packed;
-
-union dts_diode_results {
- u32 reg_value;
- struct iwl_mvm_dts_diode_bits bits;
-} __packed;
-
-static s16 iwl_mvm_dts_get_volt_band_gap(struct iwl_mvm *mvm)
+static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
{
- struct iwl_nvm_section calib_sec;
- const __le16 *calib;
- u16 vbg;
-
- /* TODO: move parsing to NVM code */
- calib_sec = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION];
- calib = (__le16 *)calib_sec.data;
+ u32 duration = mvm->thermal_throttle.params->ct_kill_duration;
- vbg = le16_to_cpu(calib[OTP_WP_DTS_VBG]);
+ if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
+ return;
- if (vbg < MEAS_VBG_MIN_VAL || vbg > MEAS_VBG_MAX_VAL)
- vbg = MEAS_VBG_DEFAULT_VAL;
+ IWL_ERR(mvm, "Enter CT Kill\n");
+ iwl_mvm_set_hw_ctkill_state(mvm, true);
- return vbg;
+ /* Don't schedule an exit work if we're in test mode, since
+ * the temperature will not change unless we manually set it
+ * again (or disable testing).
+ */
+ if (!mvm->temperature_test)
+ schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
+ round_jiffies_relative(duration * HZ));
}
-static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm)
+static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm)
{
- const u8 *calib;
- u8 ptat, pa1, pa2, median;
-
- /* TODO: move parsing to NVM code */
- calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data;
- ptat = calib[OTP_DTS_DIODE_DEVIATION * 2];
- pa1 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 1];
- pa2 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 2];
-
- /* get the median: */
- if (ptat > pa1) {
- if (ptat > pa2)
- median = (pa1 > pa2) ? pa1 : pa2;
- else
- median = ptat;
- } else {
- if (pa1 > pa2)
- median = (ptat > pa2) ? ptat : pa2;
- else
- median = pa1;
- }
+ if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
+ return;
- return ptat - median;
+ IWL_ERR(mvm, "Exit CT Kill\n");
+ iwl_mvm_set_hw_ctkill_state(mvm, false);
}
-static u8 iwl_mvm_dts_calibrate_ptat_deviation(struct iwl_mvm *mvm, u8 value)
+static bool iwl_mvm_temp_notif(struct iwl_notif_wait_data *notif_wait,
+ struct iwl_rx_packet *pkt, void *data)
{
- /* Calibrate the PTAT digital value, based on PTAT deviation data: */
- s16 new_val = value - iwl_mvm_dts_get_ptat_deviation_offset(mvm);
+ struct iwl_mvm *mvm =
+ container_of(notif_wait, struct iwl_mvm, notif_wait);
+ int *temp = data;
+ struct iwl_dts_measurement_notif *notif;
+ int len = iwl_rx_packet_payload_len(pkt);
+
+ if (WARN_ON_ONCE(len != sizeof(*notif))) {
+ IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n");
+ return true;
+ }
- if (new_val > PTAT_DIGITAL_VALUE_MAX_VALUE)
- new_val = PTAT_DIGITAL_VALUE_MAX_VALUE;
- else if (new_val < PTAT_DIGITAL_VALUE_MIN_VALUE)
- new_val = PTAT_DIGITAL_VALUE_MIN_VALUE;
+ notif = (void *)pkt->data;
- return new_val;
-}
+ *temp = le32_to_cpu(notif->temp);
-static bool dts_get_adjacent_vrefs(struct iwl_mvm *mvm,
- union dts_diode_results *avg_ptat)
-{
- u8 vrefs_results[DTS_VREFS_NUM];
- u8 low_vref_index = 0, flags;
- u32 reg;
-
- reg = iwl_read_prph(mvm->trans, DTSC_VREF_AVG);
- memcpy(vrefs_results, &reg, sizeof(reg));
- reg = iwl_read_prph(mvm->trans, DTSC_VREF5_AVG);
- vrefs_results[4] = reg & 0xff;
-
- if (avg_ptat->bits.digital_value < vrefs_results[0] ||
- avg_ptat->bits.digital_value > vrefs_results[4])
- return false;
-
- if (avg_ptat->bits.digital_value > vrefs_results[3])
- low_vref_index = 3;
- else if (avg_ptat->bits.digital_value > vrefs_results[2])
- low_vref_index = 2;
- else if (avg_ptat->bits.digital_value > vrefs_results[1])
- low_vref_index = 1;
-
- avg_ptat->bits.vref_low = vrefs_results[low_vref_index];
- avg_ptat->bits.vref_high = vrefs_results[low_vref_index + 1];
- flags = avg_ptat->bits.flags;
- avg_ptat->bits.flags =
- (flags & ~DTS_DIODE_REG_FLAGS_VREFS_ID) |
- (low_vref_index & DTS_DIODE_REG_FLAGS_VREFS_ID);
- return true;
-}
+ /* shouldn't be negative, but since it's s32, make sure it isn't */
+ if (WARN_ON_ONCE(*temp < 0))
+ *temp = 0;
-/*
- * return true it the results are valid, and false otherwise.
- */
-static bool dts_read_ptat_avg_results(struct iwl_mvm *mvm,
- union dts_diode_results *avg_ptat)
-{
- u32 reg;
- u8 tmp;
-
- /* fill the diode value and pass_once with avg-reg results */
- reg = iwl_read_prph(mvm->trans, DTSC_PTAT_AVG);
- reg &= DTS_DIODE_REG_DIG_VAL | DTS_DIODE_REG_PASS_ONCE;
- avg_ptat->reg_value = reg;
-
- /* calibrate the PTAT digital value */
- tmp = avg_ptat->bits.digital_value;
- tmp = iwl_mvm_dts_calibrate_ptat_deviation(mvm, tmp);
- avg_ptat->bits.digital_value = tmp;
-
- /*
- * fill vrefs fields, based on the avgVrefs results
- * and the diode value
- */
- return dts_get_adjacent_vrefs(mvm, avg_ptat) &&
- DTS_DIODE_VALID(avg_ptat->bits.flags);
+ IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", *temp);
+ return true;
}
-static s32 calculate_nic_temperature(union dts_diode_results avg_ptat,
- u16 volt_band_gap)
+static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
{
- u32 tmp_result;
- u8 vrefs_diff;
- /*
- * For temperature calculation (at the end, shift right by 23)
- * LUT[(D2-D1)] = ROUND{ 2^23 / ((D2-D1)*9*10) }
- * (D2-D1) == 43 44 45 46 47 48 49 50 51
- */
- static const u16 calc_lut[CALC_LUT_SIZE] = {
- 2168, 2118, 2071, 2026, 1983, 1942, 1902, 1864, 1828,
+ struct iwl_dts_measurement_cmd cmd = {
+ .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP),
};
- /*
- * The diff between the high and low voltage-references is assumed
- * to be strictly be in range of [60,68]
- */
- vrefs_diff = avg_ptat.bits.vref_high - avg_ptat.bits.vref_low;
-
- if (vrefs_diff < CALC_VREFS_MIN_DIFF ||
- vrefs_diff > CALC_VREFS_MAX_DIFF)
- return TEMPERATURE_ERROR;
-
- /* calculate the result: */
- tmp_result =
- vrefs_diff * (DTS_DIODE_GET_VREFS_ID(avg_ptat.bits.flags) + 9);
- tmp_result += avg_ptat.bits.digital_value;
- tmp_result -= avg_ptat.bits.vref_high;
-
- /* multiply by the LUT value (based on the diff) */
- tmp_result *= calc_lut[vrefs_diff - CALC_LUT_INDEX_OFFSET];
-
- /*
- * Get the BandGap (the voltage refereces source) error data
- * (temperature offset)
- */
- tmp_result *= volt_band_gap;
-
- /*
- * here, tmp_result value can be up to 32-bits. We want to right-shift
- * it *without* sign-extend.
- */
- tmp_result = tmp_result >> CALC_TEMPERATURE_RESULT_SHIFT_OFFSET;
-
- /*
- * at this point, tmp_result should be in the range:
- * 200 <= tmp_result <= 365
- */
- return (s16)tmp_result - 240;
+ return iwl_mvm_send_cmd_pdu(mvm, CMD_DTS_MEASUREMENT_TRIGGER, 0,
+ sizeof(cmd), &cmd);
}
-static s32 check_nic_temperature(struct iwl_mvm *mvm)
+static int iwl_mvm_get_temp(struct iwl_mvm *mvm)
{
- u16 volt_band_gap;
- union dts_diode_results avg_ptat;
-
- volt_band_gap = iwl_mvm_dts_get_volt_band_gap(mvm);
-
- /* disable DTS */
- iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0);
+ struct iwl_notification_wait wait_temp_notif;
+ static const u8 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION };
+ int ret, temp;
- /* SV initialization */
- iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 1);
- iwl_write_prph(mvm->trans, DTSC_CFG_MODE,
- DTSC_CFG_MODE_PERIODIC);
-
- /* wait for results */
- msleep(100);
- if (!dts_read_ptat_avg_results(mvm, &avg_ptat))
- return TEMPERATURE_ERROR;
-
- /* disable DTS */
- iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0);
+ lockdep_assert_held(&mvm->mutex);
- return calculate_nic_temperature(avg_ptat, volt_band_gap);
-}
+ iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif,
+ temp_notif, ARRAY_SIZE(temp_notif),
+ iwl_mvm_temp_notif, &temp);
-static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
-{
- u32 duration = mvm->thermal_throttle.params->ct_kill_duration;
+ ret = iwl_mvm_get_temp_cmd(mvm);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to get the temperature (err=%d)\n", ret);
+ iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif);
+ return ret;
+ }
- IWL_ERR(mvm, "Enter CT Kill\n");
- iwl_mvm_set_hw_ctkill_state(mvm, true);
- schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
- round_jiffies_relative(duration * HZ));
-}
+ ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif,
+ IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT);
+ if (ret) {
+ IWL_ERR(mvm, "Getting the temperature timed out\n");
+ return ret;
+ }
-static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm)
-{
- IWL_ERR(mvm, "Exit CT Kill\n");
- iwl_mvm_set_hw_ctkill_state(mvm, false);
+ return temp;
}
static void check_exit_ctkill(struct work_struct *work)
@@ -338,28 +176,36 @@ static void check_exit_ctkill(struct work_struct *work)
duration = tt->params->ct_kill_duration;
+ mutex_lock(&mvm->mutex);
+
+ if (__iwl_mvm_mac_start(mvm))
+ goto reschedule;
+
/* make sure the device is available for direct read/writes */
- if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL))
+ if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) {
+ __iwl_mvm_mac_stop(mvm);
goto reschedule;
+ }
- iwl_trans_start_hw(mvm->trans);
- temp = check_nic_temperature(mvm);
- iwl_trans_stop_device(mvm->trans);
+ temp = iwl_mvm_get_temp(mvm);
iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL);
- if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) {
- IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n");
+ __iwl_mvm_mac_stop(mvm);
+
+ if (temp < 0)
goto reschedule;
- }
+
IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
if (temp <= tt->params->ct_kill_exit) {
+ mutex_unlock(&mvm->mutex);
iwl_mvm_exit_ctkill(mvm);
return;
}
reschedule:
+ mutex_unlock(&mvm->mutex);
schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
round_jiffies(duration * HZ));
}
@@ -444,6 +290,12 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
return;
}
+ if (params->support_ct_kill &&
+ temperature <= tt->params->ct_kill_exit) {
+ iwl_mvm_exit_ctkill(mvm);
+ return;
+ }
+
if (params->support_dynamic_smps) {
if (!tt->dynamic_smps &&
temperature >= params->dynamic_smps_entry) {
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index dbc87071388..c67296efa04 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -168,10 +170,14 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
/*
* for data packets, rate info comes from the table inside the fw. This
- * table is controlled by LINK_QUALITY commands
+ * table is controlled by LINK_QUALITY commands. Exclude ctrl port
+ * frames like EAPOLs which should be treated as mgmt frames. This
+ * avoids them being sent initially in high rates which increases the
+ * chances for completion of the 4-Way handshake.
*/
- if (ieee80211_is_data(fc) && sta) {
+ if (ieee80211_is_data(fc) && sta &&
+ !(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) {
tx_cmd->initial_rate_index = 0;
tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
return;
@@ -207,7 +213,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
if (info->band == IEEE80211_BAND_2GHZ &&
!iwl_mvm_bt_coex_is_shared_ant_avail(mvm))
- rate_flags = BIT(ANT_A) << RATE_MCS_ANT_POS;
+ rate_flags = BIT(mvm->cfg->non_shared_ant) << RATE_MCS_ANT_POS;
else
rate_flags =
BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
@@ -482,7 +488,7 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
IWL_DEBUG_TX_QUEUES(mvm,
"Can continue DELBA flow ssn = next_recl = %d\n",
tid_data->next_reclaimed);
- iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+ iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true);
tid_data->state = IWL_AGG_OFF;
/*
* we can't hold the mutex - but since we are after a sequence
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index ac249da8a22..1958f298ac8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -387,15 +389,19 @@ struct iwl_error_event_table {
struct iwl_umac_error_event_table {
u32 valid; /* (nonzero) valid, (0) log is empty */
u32 error_id; /* type of error */
- u32 pc; /* program counter */
u32 blink1; /* branch link */
u32 blink2; /* branch link */
u32 ilink1; /* interrupt link */
u32 ilink2; /* interrupt link */
u32 data1; /* error-specific data */
u32 data2; /* error-specific data */
- u32 line; /* source code line of error */
- u32 umac_ver; /* umac version */
+ u32 data3; /* error-specific data */
+ u32 umac_fw_ver; /* UMAC version */
+ u32 umac_fw_api_ver; /* UMAC FW API ver */
+ u32 frame_pointer; /* core register 27*/
+ u32 stack_pointer; /* core register 28 */
+ u32 cmd_header; /* latest host cmd sent to UMAC */
+ u32 nic_isr_pref; /* ISR status register */
} __packed;
#define ERROR_START_OFFSET (1 * sizeof(u32))
@@ -409,7 +415,7 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
base = mvm->umac_error_event_table;
- if (base < 0x800000 || base >= 0x80C000) {
+ if (base < 0x800000) {
IWL_ERR(mvm,
"Not valid error log pointer 0x%08X for %s uCode\n",
base,
@@ -428,14 +434,19 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id,
desc_lookup(table.error_id));
- IWL_ERR(mvm, "0x%08X | umac uPc\n", table.pc);
IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1);
IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2);
IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1);
IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2);
IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1);
IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2);
- IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_ver);
+ IWL_ERR(mvm, "0x%08X | umac data3\n", table.data3);
+ IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_fw_ver);
+ IWL_ERR(mvm, "0x%08X | umac api version\n", table.umac_fw_api_ver);
+ IWL_ERR(mvm, "0x%08X | frame pointer\n", table.frame_pointer);
+ IWL_ERR(mvm, "0x%08X | stack pointer\n", table.stack_pointer);
+ IWL_ERR(mvm, "0x%08X | last host cmd\n", table.cmd_header);
+ IWL_ERR(mvm, "0x%08X | isr status reg\n", table.nic_isr_pref);
}
void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
index f0e722ced08..ca68c3ccf63 100644
--- a/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -352,11 +354,17 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x08B3, 0x8060, iwl3160_2n_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x8062, iwl3160_n_cfg)},
{IWL_PCI_DEVICE(0x08B4, 0x8270, iwl3160_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x08B4, 0x8370, iwl3160_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x08B4, 0x8272, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x8470, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x8570, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x1070, iwl3160_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x1170, iwl3160_2ac_cfg)},
+/* 3165 Series */
+ {IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x3165, 0x4210, iwl3165_2ac_cfg)},
+
/* 7265 Series */
{IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5110, iwl7265_2ac_cfg)},
@@ -378,6 +386,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x095B, 0x5202, iwl7265_n_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9010, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9012, iwl7265_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x095A, 0x900A, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9210, iwl7265_2ac_cfg)},
@@ -396,6 +405,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
/* 8000 Series */
{IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)},
{IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)},
#endif /* CONFIG_IWLMVM */
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index 78f72c34438..1aea6b66c59 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -1,6 +1,7 @@
/******************************************************************************
*
* Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -256,6 +257,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
* @cmd_queue - command queue number
* @rx_buf_size_8k: 8 kB RX buffer size
* @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
+ * @scd_set_active: should the transport configure the SCD for HCMD queue
* @rx_page_order: page order for receive buffer size
* @wd_timeout: queue watchdog timeout (jiffies)
* @reg_lock: protect hw register access
@@ -305,6 +307,7 @@ struct iwl_trans_pcie {
bool rx_buf_size_8k;
bool bc_table_dword;
+ bool scd_set_active;
u32 rx_page_order;
const char *const *command_names;
@@ -364,9 +367,10 @@ int iwl_pcie_tx_init(struct iwl_trans *trans);
void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr);
int iwl_pcie_tx_stop(struct iwl_trans *trans);
void iwl_pcie_tx_free(struct iwl_trans *trans);
-void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
- int sta_id, int tid, int frame_limit, u16 ssn);
-void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue);
+void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn,
+ const struct iwl_trans_txq_scd_cfg *cfg);
+void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue,
+ bool configure_scd);
int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
struct iwl_device_cmd *dev_cmd, int txq_id);
void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans);
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index a2698e5e062..7b7e2f223fb 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -1,6 +1,7 @@
/******************************************************************************
*
* Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -639,7 +640,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);
if (reclaim) {
- kfree(txq->entries[cmd_index].free_buf);
+ kzfree(txq->entries[cmd_index].free_buf);
txq->entries[cmd_index].free_buf = NULL;
}
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 06e04aaf61e..ae99240dcde 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 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) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -1169,6 +1171,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
trans_pcie->command_names = trans_cfg->command_names;
trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;
+ trans_pcie->scd_set_active = trans_cfg->scd_set_active;
/* Initialize NAPI here - it should be before registering to mac80211
* in the opmode but after the HW struct is allocated.
@@ -2187,7 +2190,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
*/
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
trans->hw_rev = (trans->hw_rev & 0xfff0) |
- ((trans->hw_rev << 2) & 0xc);
+ (CSR_HW_REV_STEP(trans->hw_rev << 2));
trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 6acccb19c4f..eb8e2984c5e 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -1,6 +1,7 @@
/******************************************************************************
*
* Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -34,6 +35,7 @@
#include "iwl-csr.h"
#include "iwl-prph.h"
#include "iwl-io.h"
+#include "iwl-scd.h"
#include "iwl-op-mode.h"
#include "internal.h"
/* FIXME: need to abstract out TX command (once we know what it looks like) */
@@ -618,8 +620,8 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
/* De-alloc array of command/tx buffers */
if (txq_id == trans_pcie->cmd_queue)
for (i = 0; i < txq->q.n_window; i++) {
- kfree(txq->entries[i].cmd);
- kfree(txq->entries[i].free_buf);
+ kzfree(txq->entries[i].cmd);
+ kzfree(txq->entries[i].free_buf);
}
/* De-alloc circular buffer of TFDs */
@@ -644,17 +646,6 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
memset(txq, 0, sizeof(*txq));
}
-/*
- * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
- */
-static void iwl_pcie_txq_set_sched(struct iwl_trans *trans, u32 mask)
-{
- struct iwl_trans_pcie __maybe_unused *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
-
- iwl_write_prph(trans, SCD_TXFACT, mask);
-}
-
void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -692,7 +683,7 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
trans_pcie->cmd_fifo);
/* Activate all Tx DMA/FIFO channels */
- iwl_pcie_txq_set_sched(trans, IWL_MASK(0, 7));
+ iwl_scd_activate_fifos(trans);
/* Enable DMA channel */
for (chan = 0; chan < FH_TCSR_CHNL_NUM; chan++)
@@ -745,7 +736,7 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans)
/* Turn off all Tx DMA fifos */
spin_lock(&trans_pcie->irq_lock);
- iwl_pcie_txq_set_sched(trans, 0);
+ iwl_scd_deactivate_fifos(trans);
/* Stop each Tx DMA channel, and wait for it to be idle */
for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
@@ -886,7 +877,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
spin_lock(&trans_pcie->irq_lock);
/* Turn off all Tx DMA fifos */
- iwl_write_prph(trans, SCD_TXFACT, 0);
+ iwl_scd_deactivate_fifos(trans);
/* Tell NIC where to find the "keep warm" buffer */
iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
@@ -1072,55 +1063,53 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
return 0;
}
-static inline void iwl_pcie_txq_set_inactive(struct iwl_trans *trans,
- u16 txq_id)
-{
- /* Simply stop the queue, but don't change any configuration;
- * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
- iwl_write_prph(trans,
- SCD_QUEUE_STATUS_BITS(txq_id),
- (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
- (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
-}
-
/* Receiver address (actually, Rx station's index into station table),
* combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid))
-void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
- int sta_id, int tid, int frame_limit, u16 ssn)
+void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
+ const struct iwl_trans_txq_scd_cfg *cfg)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ int fifo = -1;
if (test_and_set_bit(txq_id, trans_pcie->queue_used))
WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
- /* Stop this Tx queue before configuring it */
- iwl_pcie_txq_set_inactive(trans, txq_id);
+ if (cfg) {
+ fifo = cfg->fifo;
- /* Set this queue as a chain-building queue unless it is CMD queue */
- if (txq_id != trans_pcie->cmd_queue)
- iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
+ /* Disable the scheduler prior configuring the cmd queue */
+ if (txq_id == trans_pcie->cmd_queue &&
+ trans_pcie->scd_set_active)
+ iwl_scd_enable_set_active(trans, 0);
- /* If this queue is mapped to a certain station: it is an AGG queue */
- if (sta_id >= 0) {
- u16 ra_tid = BUILD_RAxTID(sta_id, tid);
+ /* Stop this Tx queue before configuring it */
+ iwl_scd_txq_set_inactive(trans, txq_id);
- /* Map receiver-address / traffic-ID to this queue */
- iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id);
+ /* Set this queue as a chain-building queue unless it is CMD */
+ if (txq_id != trans_pcie->cmd_queue)
+ iwl_scd_txq_set_chain(trans, txq_id);
- /* enable aggregations for the queue */
- iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
- trans_pcie->txq[txq_id].ampdu = true;
- } else {
- /*
- * disable aggregations for the queue, this will also make the
- * ra_tid mapping configuration irrelevant since it is now a
- * non-AGG queue.
- */
- iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+ if (cfg->aggregate) {
+ u16 ra_tid = BUILD_RAxTID(cfg->sta_id, cfg->tid);
+
+ /* Map receiver-address / traffic-ID to this queue */
+ iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id);
+
+ /* enable aggregations for the queue */
+ iwl_scd_txq_enable_agg(trans, txq_id);
+ trans_pcie->txq[txq_id].ampdu = true;
+ } else {
+ /*
+ * disable aggregations for the queue, this will also
+ * make the ra_tid mapping configuration irrelevant
+ * since it is now a non-AGG queue.
+ */
+ iwl_scd_txq_disable_agg(trans, txq_id);
- ssn = trans_pcie->txq[txq_id].q.read_ptr;
+ ssn = trans_pcie->txq[txq_id].q.read_ptr;
+ }
}
/* Place first TFD at index corresponding to start sequence number.
@@ -1128,32 +1117,44 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff);
trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff);
- iwl_write_direct32(trans, HBUS_TARG_WRPTR,
- (ssn & 0xff) | (txq_id << 8));
- iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
+ if (cfg) {
+ u8 frame_limit = cfg->frame_limit;
+
+ iwl_write_direct32(trans, HBUS_TARG_WRPTR,
+ (ssn & 0xff) | (txq_id << 8));
+ iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
- /* Set up Tx window size and frame limit for this queue */
- iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
- SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
- iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
+ /* Set up Tx window size and frame limit for this queue */
+ iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
+ SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
+ iwl_trans_write_mem32(trans,
+ trans_pcie->scd_base_addr +
SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
- SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+ SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
- SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
-
- /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
- iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
- (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
- (fifo << SCD_QUEUE_STTS_REG_POS_TXF) |
- (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
- SCD_QUEUE_STTS_REG_MSK);
+ SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+
+ /* Set up status area in SRAM, map to Tx DMA/FIFO, activate */
+ iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
+ (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+ (cfg->fifo << SCD_QUEUE_STTS_REG_POS_TXF) |
+ (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
+ SCD_QUEUE_STTS_REG_MSK);
+
+ /* enable the scheduler for this queue (only) */
+ if (txq_id == trans_pcie->cmd_queue &&
+ trans_pcie->scd_set_active)
+ iwl_scd_enable_set_active(trans, BIT(txq_id));
+ }
+
trans_pcie->txq[txq_id].active = true;
IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n",
txq_id, fifo, ssn & 0xff);
}
-void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
+void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id,
+ bool configure_scd)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
u32 stts_addr = trans_pcie->scd_base_addr +
@@ -1172,10 +1173,12 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
return;
}
- iwl_pcie_txq_set_inactive(trans, txq_id);
+ if (configure_scd) {
+ iwl_scd_txq_set_inactive(trans, txq_id);
- iwl_trans_write_mem(trans, stts_addr, (void *)zero_val,
- ARRAY_SIZE(zero_val));
+ iwl_trans_write_mem(trans, stts_addr, (void *)zero_val,
+ ARRAY_SIZE(zero_val));
+ }
iwl_pcie_txq_unmap(trans, txq_id);
trans_pcie->txq[txq_id].ampdu = false;
@@ -1406,7 +1409,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
out_meta->flags = cmd->flags;
if (WARN_ON_ONCE(txq->entries[idx].free_buf))
- kfree(txq->entries[idx].free_buf);
+ kzfree(txq->entries[idx].free_buf);
txq->entries[idx].free_buf = dup_buf;
trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr);
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 47a998d8f99..22884ba7d6c 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -653,6 +653,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
if (channel &&
!(channel->flags & IEEE80211_CHAN_DISABLED)) {
bss = cfg80211_inform_bss(wiphy, channel,
+ CFG80211_BSS_FTYPE_UNKNOWN,
bssid, get_unaligned_le64(tsfdesc),
capa, intvl, ie, ielen,
LBS_SCAN_RSSI_TO_MBM(rssi),
@@ -1754,6 +1755,7 @@ static void lbs_join_post(struct lbs_private *priv,
bss = cfg80211_inform_bss(priv->wdev->wiphy,
params->chandef.chan,
+ CFG80211_BSS_FTYPE_UNKNOWN,
bssid,
0,
capability,
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 1326f612183..babbdc1ce74 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2045,8 +2045,6 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
hw->flags = IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_STATIC_SMPS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_WANT_MONITOR_VIF |
IEEE80211_HW_QUEUE_CONTROL |
@@ -2059,8 +2057,10 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_HAS_CHANNEL_SWITCH;
- hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
- hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
+ hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
+ NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
+ NL80211_FEATURE_STATIC_SMPS |
+ NL80211_FEATURE_DYNAMIC_SMPS;
/* ask mac80211 to reserve space for magic */
hw->vif_data_size = sizeof(struct hwsim_vif_priv);
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index 06a2c215ef5..40057079ffb 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -183,6 +183,15 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
if (!tbl)
return;
+ spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
+ priv->adapter->rx_locked = true;
+ if (priv->adapter->rx_processing) {
+ spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
+ flush_workqueue(priv->adapter->rx_workqueue);
+ } else {
+ spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
+ }
+
start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1);
mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
@@ -194,6 +203,11 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
kfree(tbl->rx_reorder_ptr);
kfree(tbl);
+
+ spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
+ priv->adapter->rx_locked = false;
+ spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
+
}
/*
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index e2e6bf13c2d..0dd672954ad 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -246,7 +246,7 @@ mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
}
if (priv->roc_cfg.cookie) {
- wiphy_dbg(wiphy, "info: ongoing ROC, cookie = 0x%llu\n",
+ wiphy_dbg(wiphy, "info: ongoing ROC, cookie = 0x%llx\n",
priv->roc_cfg.cookie);
return -EBUSY;
}
@@ -1557,6 +1557,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
band));
bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
+ CFG80211_BSS_FTYPE_UNKNOWN,
bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
0, ie_buf, ie_len, 0, GFP_KERNEL);
cfg80211_put_bss(priv->wdev->wiphy, bss);
@@ -1935,13 +1936,6 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name);
- if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
- atomic_read(&priv->wmm.tx_pkts_queued) >=
- MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN) {
- dev_dbg(priv->adapter->dev, "scan rejected due to traffic\n");
- return -EBUSY;
- }
-
/* Block scan request if scan operation or scan cleanup when interface
* is disabled is in process
*/
@@ -1980,7 +1974,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
user_scan_cfg->chan_list[i].radio_type = chan->band;
- if (chan->flags & IEEE80211_CHAN_NO_IR)
+ if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids)
user_scan_cfg->chan_list[i].scan_type =
MWIFIEX_SCAN_TYPE_PASSIVE;
else
@@ -1990,6 +1984,11 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
user_scan_cfg->chan_list[i].scan_time = 0;
}
+ if (priv->adapter->scan_chan_gap_enabled &&
+ mwifiex_is_any_intf_active(priv))
+ user_scan_cfg->scan_chan_gap =
+ priv->adapter->scan_chan_gap_time;
+
ret = mwifiex_scan_networks(priv, user_scan_cfg);
kfree(user_scan_cfg);
if (ret) {
@@ -2914,7 +2913,6 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->features |= NL80211_FEATURE_HT_IBSS |
NL80211_FEATURE_INACTIVITY_TIMER |
- NL80211_FEATURE_LOW_PRIORITY_SCAN |
NL80211_FEATURE_NEED_OBSS_SCAN;
/* Reserve space for mwifiex specific private data for BSS */
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index baf0aab63c0..85597200bad 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -1470,7 +1470,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec;
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_ie_types_header *tlv;
- struct hw_spec_fw_api_rev *api_rev;
+ struct hw_spec_api_rev *api_rev;
u16 resp_size, api_id;
int i, left_len, parsed_len = 0;
@@ -1538,23 +1538,30 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
while (left_len > sizeof(struct mwifiex_ie_types_header)) {
tlv = (void *)&hw_spec->tlvs + parsed_len;
switch (le16_to_cpu(tlv->type)) {
- case TLV_TYPE_FW_API_REV:
- api_rev = (struct hw_spec_fw_api_rev *)tlv;
+ case TLV_TYPE_API_REV:
+ api_rev = (struct hw_spec_api_rev *)tlv;
api_id = le16_to_cpu(api_rev->api_id);
switch (api_id) {
case KEY_API_VER_ID:
- adapter->fw_key_api_major_ver =
+ adapter->key_api_major_ver =
api_rev->major_ver;
- adapter->fw_key_api_minor_ver =
+ adapter->key_api_minor_ver =
api_rev->minor_ver;
dev_dbg(adapter->dev,
- "fw_key_api v%d.%d\n",
- adapter->fw_key_api_major_ver,
- adapter->fw_key_api_minor_ver);
+ "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);
break;
default:
dev_warn(adapter->dev,
- "Unknown FW api_id: %d\n",
+ "Unknown api_id: %d\n",
api_id);
break;
}
@@ -1567,7 +1574,8 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
}
parsed_len += le16_to_cpu(tlv->len) +
sizeof(struct mwifiex_ie_types_header);
- left_len -= parsed_len;
+ left_len -= le16_to_cpu(tlv->len) +
+ sizeof(struct mwifiex_ie_types_header);
}
}
@@ -1605,5 +1613,8 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
adapter->if_ops.update_mp_end_port(adapter,
le16_to_cpu(hw_spec->mp_end_port));
+ if (adapter->fw_api_ver == MWIFIEX_FW_V15)
+ adapter->scan_chan_gap_enabled = true;
+
return 0;
}
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index 0e03fe39fc3..e0d00a7f0ec 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -48,8 +48,8 @@
#define MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE 16
#define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE 64
#define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE 64
-#define MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE 48
-#define MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE 32
+#define MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE 64
+#define MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE 64
#define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 49da2d53d29..1eb61739071 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -83,7 +83,7 @@ enum KEY_TYPE_ID {
#define WPA_PN_SIZE 8
#define KEY_PARAMS_FIXED_LEN 10
#define KEY_INDEX_MASK 0xf
-#define FW_KEY_API_VER_MAJOR_V2 2
+#define KEY_API_VER_MAJOR_V2 2
#define KEY_MCAST BIT(0)
#define KEY_UNICAST BIT(1)
@@ -170,7 +170,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154)
#define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156)
#define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194)
-#define TLV_TYPE_FW_API_REV (PROPRIETARY_TLV_BASE_ID + 199)
+#define TLV_TYPE_SCAN_CHANNEL_GAP (PROPRIETARY_TLV_BASE_ID + 197)
+#define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199)
#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
@@ -653,6 +654,12 @@ struct mwifiex_ie_types_num_probes {
__le16 num_probes;
} __packed;
+struct mwifiex_ie_types_scan_chan_gap {
+ struct mwifiex_ie_types_header header;
+ /* time gap in TUs to be used between two consecutive channels scan */
+ __le16 chan_gap;
+} __packed;
+
struct mwifiex_ie_types_wildcard_ssid_params {
struct mwifiex_ie_types_header header;
u8 max_ssid_length;
@@ -844,11 +851,12 @@ struct host_cmd_ds_802_11_ps_mode_enh {
} params;
} __packed;
-enum FW_API_VER_ID {
+enum API_VER_ID {
KEY_API_VER_ID = 1,
+ FW_API_VER_ID = 2,
};
-struct hw_spec_fw_api_rev {
+struct hw_spec_api_rev {
struct mwifiex_ie_types_header header;
__le16 api_id;
u8 major_ver;
@@ -1248,6 +1256,7 @@ struct mwifiex_user_scan_cfg {
u8 num_ssids;
/* Variable number (fixed maximum) of channels to scan up */
struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX];
+ u16 scan_chan_gap;
} __packed;
struct ie_body {
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 269a277d0a2..f7c97cf3840 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -212,6 +212,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME;
adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME;
adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME;
+ adapter->scan_chan_gap_time = MWIFIEX_DEF_SCAN_CHAN_GAP_TIME;
adapter->scan_probes = 1;
@@ -280,10 +281,9 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
adapter->arp_filter_size = 0;
adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
- adapter->empty_tx_q_cnt = 0;
adapter->ext_scan = true;
- adapter->fw_key_api_major_ver = 0;
- adapter->fw_key_api_minor_ver = 0;
+ adapter->key_api_major_ver = 0;
+ adapter->key_api_minor_ver = 0;
}
/*
@@ -447,8 +447,11 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
spin_lock_init(&adapter->cmd_free_q_lock);
spin_lock_init(&adapter->cmd_pending_q_lock);
spin_lock_init(&adapter->scan_pending_q_lock);
+ spin_lock_init(&adapter->rx_q_lock);
+ spin_lock_init(&adapter->rx_proc_lock);
skb_queue_head_init(&adapter->usb_rx_data_q);
+ skb_queue_head_init(&adapter->rx_data_q);
for (i = 0; i < adapter->priv_num; ++i) {
INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head);
@@ -614,6 +617,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
int ret = -EINPROGRESS;
struct mwifiex_private *priv;
s32 i;
+ unsigned long flags;
struct sk_buff *skb;
/* mwifiex already shutdown */
@@ -648,6 +652,21 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
}
}
+ spin_lock_irqsave(&adapter->rx_proc_lock, flags);
+
+ while ((skb = skb_dequeue(&adapter->rx_data_q))) {
+ struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
+
+ atomic_dec(&adapter->rx_pending);
+ priv = adapter->priv[rx_info->bss_num];
+ if (priv)
+ priv->stats.rx_dropped++;
+
+ dev_kfree_skb_any(skb);
+ }
+
+ spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+
spin_lock(&adapter->mwifiex_lock);
if (adapter->if_ops.data_complete) {
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index dfa37eadc4d..b522f7c3690 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -28,91 +28,6 @@ const char driver_version[] = "mwifiex " VERSION " (%s) ";
static char *cal_data_cfg;
module_param(cal_data_cfg, charp, 0);
-static void scan_delay_timer_fn(unsigned long data)
-{
- struct mwifiex_private *priv = (struct mwifiex_private *)data;
- struct mwifiex_adapter *adapter = priv->adapter;
- struct cmd_ctrl_node *cmd_node, *tmp_node;
- spinlock_t *scan_q_lock = &adapter->scan_pending_q_lock;
- unsigned long flags;
-
- if (adapter->surprise_removed)
- return;
-
- if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT ||
- !adapter->scan_processing) {
- /*
- * Abort scan operation by cancelling all pending scan
- * commands
- */
- spin_lock_irqsave(scan_q_lock, flags);
- list_for_each_entry_safe(cmd_node, tmp_node,
- &adapter->scan_pending_q, list) {
- list_del(&cmd_node->list);
- mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
- }
- spin_unlock_irqrestore(scan_q_lock, flags);
-
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
- adapter->scan_processing = false;
- adapter->scan_delay_cnt = 0;
- adapter->empty_tx_q_cnt = 0;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
-
- if (priv->scan_request) {
- dev_dbg(adapter->dev, "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");
- }
- goto done;
- }
-
- if (!atomic_read(&priv->adapter->is_tx_received)) {
- adapter->empty_tx_q_cnt++;
- if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) {
- /*
- * No Tx traffic for 200msec. Get scan command from
- * scan pending queue and put to cmd pending queue to
- * resume scan operation
- */
- adapter->scan_delay_cnt = 0;
- adapter->empty_tx_q_cnt = 0;
- spin_lock_irqsave(scan_q_lock, flags);
-
- if (list_empty(&adapter->scan_pending_q)) {
- spin_unlock_irqrestore(scan_q_lock, flags);
- goto done;
- }
-
- cmd_node = list_first_entry(&adapter->scan_pending_q,
- struct cmd_ctrl_node, list);
- list_del(&cmd_node->list);
- spin_unlock_irqrestore(scan_q_lock, flags);
-
- mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
- true);
- queue_work(adapter->workqueue, &adapter->main_work);
- goto done;
- }
- } else {
- adapter->empty_tx_q_cnt = 0;
- }
-
- /* Delay scan operation further by 20msec */
- mod_timer(&priv->scan_delay_timer, jiffies +
- msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
- adapter->scan_delay_cnt++;
-
-done:
- if (atomic_read(&priv->adapter->is_tx_received))
- atomic_set(&priv->adapter->is_tx_received, false);
-
- return;
-}
-
/*
* This function registers the device and performs all the necessary
* initializations.
@@ -160,10 +75,6 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
adapter->priv[i]->adapter = adapter;
adapter->priv_num++;
-
- setup_timer(&adapter->priv[i]->scan_delay_timer,
- scan_delay_timer_fn,
- (unsigned long)adapter->priv[i]);
}
mwifiex_init_lock_list(adapter);
@@ -207,7 +118,6 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
for (i = 0; i < adapter->priv_num; i++) {
if (adapter->priv[i]) {
mwifiex_free_curr_bcn(adapter->priv[i]);
- del_timer_sync(&adapter->priv[i]->scan_delay_timer);
kfree(adapter->priv[i]);
}
}
@@ -216,6 +126,42 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
return 0;
}
+static int mwifiex_process_rx(struct mwifiex_adapter *adapter)
+{
+ unsigned long flags;
+ struct sk_buff *skb;
+ bool delay_main_work = adapter->delay_main_work;
+
+ spin_lock_irqsave(&adapter->rx_proc_lock, flags);
+ if (adapter->rx_processing || adapter->rx_locked) {
+ spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+ goto exit_rx_proc;
+ } else {
+ adapter->rx_processing = true;
+ spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+ }
+
+ /* Check for Rx data */
+ while ((skb = skb_dequeue(&adapter->rx_data_q))) {
+ atomic_dec(&adapter->rx_pending);
+ if (adapter->delay_main_work &&
+ (atomic_dec_return(&adapter->rx_pending) <
+ LOW_RX_PENDING)) {
+ adapter->delay_main_work = false;
+ queue_work(adapter->rx_workqueue, &adapter->rx_work);
+ }
+ mwifiex_handle_rx_packet(adapter, skb);
+ }
+ spin_lock_irqsave(&adapter->rx_proc_lock, flags);
+ adapter->rx_processing = false;
+ spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+
+ if (delay_main_work)
+ queue_work(adapter->workqueue, &adapter->main_work);
+exit_rx_proc:
+ return 0;
+}
+
/*
* The main process.
*
@@ -253,6 +199,19 @@ process_start:
(adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY))
break;
+ /* If we process interrupts first, it would increase RX pending
+ * even further. Avoid this by checking if rx_pending has
+ * crossed high threshold and schedule rx work queue
+ * and then process interrupts
+ */
+ if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING) {
+ adapter->delay_main_work = true;
+ if (!adapter->rx_processing)
+ queue_work(adapter->rx_workqueue,
+ &adapter->rx_work);
+ break;
+ }
+
/* Handle pending interrupt if any */
if (adapter->int_status) {
if (adapter->hs_activated)
@@ -261,6 +220,9 @@ process_start:
adapter->if_ops.process_int_status(adapter);
}
+ if (adapter->rx_work_enabled && adapter->data_received)
+ queue_work(adapter->rx_workqueue, &adapter->rx_work);
+
/* Need to wake up the card ? */
if ((adapter->ps_state == PS_STATE_SLEEP) &&
(adapter->pm_wakeup_card_req &&
@@ -273,6 +235,7 @@ process_start:
}
if (IS_CARD_RX_RCVD(adapter)) {
+ adapter->data_received = false;
adapter->pm_wakeup_fw_try = false;
if (adapter->ps_state == PS_STATE_SLEEP)
adapter->ps_state = PS_STATE_AWAKE;
@@ -284,8 +247,8 @@ process_start:
adapter->tx_lock_flag)
break;
- if ((adapter->scan_processing &&
- !adapter->scan_delay_cnt) || adapter->data_sent ||
+ if ((!adapter->scan_chan_gap_enabled &&
+ adapter->scan_processing) || adapter->data_sent ||
mwifiex_wmm_lists_empty(adapter)) {
if (adapter->cmd_sent || adapter->curr_cmd ||
(!is_command_pending(adapter)))
@@ -339,7 +302,8 @@ process_start:
}
}
- if ((!adapter->scan_processing || adapter->scan_delay_cnt) &&
+ if ((adapter->scan_chan_gap_enabled ||
+ !adapter->scan_processing) &&
!adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) {
mwifiex_wmm_process_tx(adapter);
if (adapter->hs_activated) {
@@ -407,6 +371,12 @@ static void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
flush_workqueue(adapter->workqueue);
destroy_workqueue(adapter->workqueue);
adapter->workqueue = NULL;
+
+ if (adapter->rx_workqueue) {
+ flush_workqueue(adapter->rx_workqueue);
+ destroy_workqueue(adapter->rx_workqueue);
+ adapter->rx_workqueue = NULL;
+ }
}
/*
@@ -598,9 +568,6 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
atomic_inc(&priv->adapter->tx_pending);
mwifiex_wmm_add_buf_txqueue(priv, skb);
- if (priv->adapter->scan_delay_cnt)
- atomic_set(&priv->adapter->is_tx_received, true);
-
queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
return 0;
@@ -824,6 +791,21 @@ int is_command_pending(struct mwifiex_adapter *adapter)
}
/*
+ * This is the RX work queue function.
+ *
+ * It handles the RX operations.
+ */
+static void mwifiex_rx_work_queue(struct work_struct *work)
+{
+ struct mwifiex_adapter *adapter =
+ container_of(work, struct mwifiex_adapter, rx_work);
+
+ if (adapter->surprise_removed)
+ return;
+ mwifiex_process_rx(adapter);
+}
+
+/*
* This is the main work queue function.
*
* It handles the main process, which in turn handles the complete
@@ -879,6 +861,11 @@ mwifiex_add_card(void *card, struct semaphore *sem,
adapter->cmd_wait_q.status = 0;
adapter->scan_wait_q_woken = false;
+ if (num_possible_cpus() > 1) {
+ adapter->rx_work_enabled = true;
+ pr_notice("rx work enabled, cpus %d\n", num_possible_cpus());
+ }
+
adapter->workqueue =
alloc_workqueue("MWIFIEX_WORK_QUEUE",
WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
@@ -886,6 +873,18 @@ mwifiex_add_card(void *card, struct semaphore *sem,
goto err_kmalloc;
INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
+
+ if (adapter->rx_work_enabled) {
+ adapter->rx_workqueue = alloc_workqueue("MWIFIEX_RX_WORK_QUEUE",
+ WQ_HIGHPRI |
+ WQ_MEM_RECLAIM |
+ WQ_UNBOUND, 1);
+ if (!adapter->rx_workqueue)
+ goto err_kmalloc;
+
+ INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue);
+ }
+
if (adapter->if_ops.iface_work)
INIT_WORK(&adapter->iface_work, adapter->if_ops.iface_work);
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index a2733b1e63f..1a999999b39 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -58,6 +58,9 @@ enum {
#define MAX_TX_PENDING 100
#define LOW_TX_PENDING 80
+#define HIGH_RX_PENDING 50
+#define LOW_RX_PENDING 20
+
#define MWIFIEX_UPLD_SIZE (2312)
#define MAX_EVENT_SIZE 2048
@@ -84,17 +87,12 @@ enum {
#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 110
#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME 30
#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME 30
+#define MWIFIEX_DEF_SCAN_CHAN_GAP_TIME 50
#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI)))
#define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
-#define MWIFIEX_MAX_SCAN_DELAY_CNT 50
-#define MWIFIEX_MAX_EMPTY_TX_Q_CNT 10
-#define MWIFIEX_SCAN_DELAY_MSEC 20
-
-#define MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN 2
-
#define RSN_GTK_OUI_OFFSET 2
#define MWIFIEX_OUI_NOT_PRESENT 0
@@ -547,7 +545,6 @@ struct mwifiex_private {
u8 nick_name[16];
u16 current_key_index;
struct semaphore async_sem;
- u8 report_scan_result;
struct cfg80211_scan_request *scan_request;
u8 cfg_bssid[6];
struct wps wps;
@@ -561,7 +558,6 @@ struct mwifiex_private {
u16 proberesp_idx;
u16 assocresp_idx;
u16 rsn_idx;
- struct timer_list scan_delay_timer;
u8 ap_11n_enabled;
u8 ap_11ac_enabled;
u32 mgmt_frame_mask;
@@ -721,6 +717,12 @@ struct mwifiex_adapter {
atomic_t cmd_pending;
struct workqueue_struct *workqueue;
struct work_struct main_work;
+ struct workqueue_struct *rx_workqueue;
+ struct work_struct rx_work;
+ bool rx_work_enabled;
+ bool rx_processing;
+ bool delay_main_work;
+ bool rx_locked;
struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM];
/* spin lock for init/shutdown */
spinlock_t mwifiex_lock;
@@ -761,6 +763,10 @@ struct mwifiex_adapter {
struct list_head scan_pending_q;
/* spin lock for scan_pending_q */
spinlock_t scan_pending_q_lock;
+ /* spin lock for RX queue */
+ spinlock_t rx_q_lock;
+ /* spin lock for RX processing routine */
+ spinlock_t rx_proc_lock;
struct sk_buff_head usb_rx_data_q;
u32 scan_processing;
u16 region_code;
@@ -770,6 +776,7 @@ struct mwifiex_adapter {
u16 specific_scan_time;
u16 active_scan_time;
u16 passive_scan_time;
+ u16 scan_chan_gap_time;
u8 fw_bands;
u8 adhoc_start_band;
u8 config_bands;
@@ -815,8 +822,6 @@ struct mwifiex_adapter {
spinlock_t queue_lock; /* lock for tx queues */
u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
u16 max_mgmt_ie_index;
- u8 scan_delay_cnt;
- u8 empty_tx_q_cnt;
const struct firmware *cal_data;
struct device_node *dt_node;
@@ -828,17 +833,18 @@ struct mwifiex_adapter {
u32 usr_dot_11ac_dev_cap_a;
u32 usr_dot_11ac_mcs_support;
- atomic_t is_tx_received;
atomic_t pending_bridged_pkts;
struct semaphore *card_sem;
bool ext_scan;
u8 fw_api_ver;
- u8 fw_key_api_major_ver, fw_key_api_minor_ver;
+ u8 key_api_major_ver, key_api_minor_ver;
struct work_struct iface_work;
unsigned long iface_work_flags;
struct memory_type_mapping *mem_type_mapping_tbl;
u8 num_mem_types;
u8 curr_mem_idx;
+ bool scan_chan_gap_enabled;
+ struct sk_buff_head rx_data_q;
};
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -1139,6 +1145,25 @@ mwifiex_11h_get_csa_closed_channel(struct mwifiex_private *priv)
return priv->csa_chan;
}
+static inline u8 mwifiex_is_any_intf_active(struct mwifiex_private *priv)
+{
+ struct mwifiex_private *priv_num;
+ int i;
+
+ for (i = 0; i < priv->adapter->priv_num; i++) {
+ priv_num = priv->adapter->priv[i];
+ if (priv_num) {
+ if ((GET_BSS_ROLE(priv_num) == MWIFIEX_BSS_ROLE_UAP &&
+ priv_num->bss_started) ||
+ (GET_BSS_ROLE(priv_num) == MWIFIEX_BSS_ROLE_STA &&
+ priv_num->media_connected))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
u32 func_init_shutdown);
int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8);
@@ -1274,6 +1299,7 @@ void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv);
bool mwifiex_is_bss_in_11ac_mode(struct mwifiex_private *priv);
u8 mwifiex_get_center_freq_index(struct mwifiex_private *priv, u8 band,
u32 pri_chan, u8 chan_bw);
+int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter);
#ifdef CONFIG_DEBUG_FS
void mwifiex_debugfs_init(void);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index ff0545888dd..1504b16e248 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -1233,6 +1233,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
struct sk_buff *skb_tmp = NULL;
struct mwifiex_pcie_buf_desc *desc;
struct mwifiex_pfu_buf_desc *desc2;
+ unsigned long flags;
if (!mwifiex_pcie_ok_to_access_hw(adapter))
mwifiex_pm_wakeup_card(adapter);
@@ -1271,12 +1272,29 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
*/
pkt_len = *((__le16 *)skb_data->data);
rx_len = le16_to_cpu(pkt_len);
- 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);
- skb_pull(skb_data, INTF_HEADER_LEN);
- mwifiex_handle_rx_packet(adapter, skb_data);
+ 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);
+ 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);
+ skb_pull(skb_data, INTF_HEADER_LEN);
+ if (adapter->rx_work_enabled) {
+ spin_lock_irqsave(&adapter->rx_q_lock, flags);
+ skb_queue_tail(&adapter->rx_data_q, skb_data);
+ spin_unlock_irqrestore(&adapter->rx_q_lock,
+ flags);
+ adapter->data_received = true;
+ atomic_inc(&adapter->rx_pending);
+ } else {
+ mwifiex_handle_rx_packet(adapter, skb_data);
+ }
+ }
skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
if (!skb_tmp) {
@@ -1718,6 +1736,13 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
buffer is released. This is just to make things simpler,
we need to find a better method of managing these buffers.
*/
+ } else {
+ if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+ CPU_INTR_EVENT_DONE)) {
+ dev_warn(adapter->dev,
+ "Write register failed\n");
+ return -1;
+ }
}
return 0;
diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h
index a1a8fd3bc1b..200e8b0cb58 100644
--- a/drivers/net/wireless/mwifiex/pcie.h
+++ b/drivers/net/wireless/mwifiex/pcie.h
@@ -40,8 +40,8 @@
#define MWIFIEX_TXBD_MASK 0x3F
#define MWIFIEX_RXBD_MASK 0x3F
-#define MWIFIEX_MAX_EVT_BD 0x04
-#define MWIFIEX_EVTBD_MASK 0x07
+#define MWIFIEX_MAX_EVT_BD 0x08
+#define MWIFIEX_EVTBD_MASK 0x0f
/* PCIE INTERNAL REGISTERS */
#define PCIE_SCRATCH_0_REG 0xC10
@@ -69,6 +69,7 @@
#define CPU_INTR_DOOR_BELL BIT(1)
#define CPU_INTR_SLEEP_CFM_DONE BIT(2)
#define CPU_INTR_RESET BIT(3)
+#define CPU_INTR_EVENT_DONE BIT(5)
#define HOST_INTR_DNLD_DONE BIT(0)
#define HOST_INTR_UPLD_RDY BIT(1)
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index dee717a19dd..c09ebeee6dd 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -799,6 +799,7 @@ mwifiex_config_scan(struct mwifiex_private *priv,
{
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_ie_types_num_probes *num_probes_tlv;
+ struct mwifiex_ie_types_scan_chan_gap *chan_gap_tlv;
struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
struct mwifiex_ie_types_bssid_list *bssid_tlv;
u8 *tlv_pos;
@@ -939,6 +940,22 @@ mwifiex_config_scan(struct mwifiex_private *priv,
else
*max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD;
+ if (user_scan_in->scan_chan_gap) {
+ *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+ dev_dbg(adapter->dev, "info: scan: channel gap = %d\n",
+ user_scan_in->scan_chan_gap);
+
+ chan_gap_tlv = (void *)tlv_pos;
+ chan_gap_tlv->header.type =
+ cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP);
+ chan_gap_tlv->header.len =
+ cpu_to_le16(sizeof(chan_gap_tlv->chan_gap));
+ chan_gap_tlv->chan_gap =
+ cpu_to_le16((user_scan_in->scan_chan_gap));
+
+ tlv_pos += sizeof(struct mwifiex_ie_types_scan_chan_gap);
+ }
+
/* If the input config or adapter has the number of Probes set,
add tlv */
if (num_probes) {
@@ -1050,12 +1067,6 @@ mwifiex_config_scan(struct mwifiex_private *priv,
*filtered_scan);
}
- /*
- * In associated state we will reduce the number of channels scanned per
- * scan command to 1 to avoid any traffic delay/loss.
- */
- if (priv->media_connected)
- *max_chan_per_scan = 1;
}
/*
@@ -1719,7 +1730,8 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
bss = cfg80211_inform_bss(priv->wdev->wiphy,
- chan, bssid, timestamp,
+ chan, CFG80211_BSS_FTYPE_UNKNOWN,
+ bssid, timestamp,
cap_info_bitmap, beacon_period,
ie_buf, ie_len, rssi, GFP_KERNEL);
bss_priv = (struct mwifiex_bss_priv *)bss->priv;
@@ -1754,7 +1766,7 @@ static void mwifiex_complete_scan(struct mwifiex_private *priv)
static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
{
struct mwifiex_adapter *adapter = priv->adapter;
- struct cmd_ctrl_node *cmd_node;
+ struct cmd_ctrl_node *cmd_node, *tmp_node;
unsigned long flags;
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
@@ -1767,9 +1779,6 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
if (!adapter->ext_scan)
mwifiex_complete_scan(priv);
- if (priv->report_scan_result)
- priv->report_scan_result = false;
-
if (priv->scan_request) {
dev_dbg(adapter->dev, "info: notifying scan done\n");
cfg80211_scan_done(priv->scan_request, 0);
@@ -1778,37 +1787,36 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
priv->scan_aborting = false;
dev_dbg(adapter->dev, "info: scan already aborted\n");
}
- } else {
- if ((priv->scan_aborting && !priv->scan_request) ||
- priv->scan_block) {
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
- flags);
- adapter->scan_delay_cnt = MWIFIEX_MAX_SCAN_DELAY_CNT;
- mod_timer(&priv->scan_delay_timer, jiffies);
- dev_dbg(priv->adapter->dev,
- "info: %s: triggerring scan abort\n", __func__);
- } else if (!mwifiex_wmm_lists_empty(adapter) &&
- (priv->scan_request && (priv->scan_request->flags &
- NL80211_SCAN_FLAG_LOW_PRIORITY))) {
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
- flags);
- adapter->scan_delay_cnt = 1;
- mod_timer(&priv->scan_delay_timer, jiffies +
- msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
- dev_dbg(priv->adapter->dev,
- "info: %s: deferring scan\n", __func__);
- } else {
- /* Get scan command from scan_pending_q and put to
- * cmd_pending_q
- */
- cmd_node = list_first_entry(&adapter->scan_pending_q,
- struct cmd_ctrl_node, list);
+ } else if ((priv->scan_aborting && !priv->scan_request) ||
+ priv->scan_block) {
+ list_for_each_entry_safe(cmd_node, tmp_node,
+ &adapter->scan_pending_q, list) {
list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
- flags);
- mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
- true);
+ mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
}
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->scan_processing = false;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+ if (priv->scan_request) {
+ dev_dbg(adapter->dev, "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");
+ }
+ } else {
+ /* Get scan command from scan_pending_q and put to
+ * cmd_pending_q
+ */
+ cmd_node = list_first_entry(&adapter->scan_pending_q,
+ struct cmd_ctrl_node, list);
+ list_del(&cmd_node->list);
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+ mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
}
return;
@@ -1970,9 +1978,34 @@ int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
/* This function handles the command response of extended scan */
int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv)
{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct host_cmd_ds_command *cmd_ptr;
+ struct cmd_ctrl_node *cmd_node;
+ unsigned long cmd_flags, scan_flags;
+ bool complete_scan = false;
+
dev_dbg(priv->adapter->dev, "info: EXT scan returns successfully\n");
- mwifiex_complete_scan(priv);
+ spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_flags);
+ spin_lock_irqsave(&adapter->scan_pending_q_lock, scan_flags);
+ if (list_empty(&adapter->scan_pending_q)) {
+ complete_scan = true;
+ list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) {
+ 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");
+ complete_scan = false;
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, scan_flags);
+ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, cmd_flags);
+
+ if (complete_scan)
+ mwifiex_complete_scan(priv);
return 0;
}
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index 1770fa3fc1e..ea8fc587e90 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -622,22 +622,15 @@ static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u32 *port)
dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%08x\n", wr_bitmap);
- if (card->supports_sdio_new_mode &&
- !(wr_bitmap & reg->data_port_mask)) {
+ if (!(wr_bitmap & card->mp_data_port_mask)) {
adapter->data_sent = true;
return -EBUSY;
- } else if (!card->supports_sdio_new_mode &&
- !(wr_bitmap & card->mp_data_port_mask)) {
- return -1;
}
if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) {
card->mp_wr_bitmap &= (u32) (~(1 << card->curr_wr_port));
*port = card->curr_wr_port;
- if (((card->supports_sdio_new_mode) &&
- (++card->curr_wr_port == card->max_ports)) ||
- ((!card->supports_sdio_new_mode) &&
- (++card->curr_wr_port == card->mp_end_port)))
+ if (++card->curr_wr_port == card->mp_end_port)
card->curr_wr_port = reg->start_wr_port;
} else {
adapter->data_sent = true;
@@ -1046,6 +1039,7 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
struct sk_buff *skb, u32 upld_typ)
{
u8 *cmd_buf;
+ unsigned long flags;
__le16 *curr_ptr = (__le16 *)skb->data;
u16 pkt_len = le16_to_cpu(*curr_ptr);
@@ -1055,7 +1049,15 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
switch (upld_typ) {
case MWIFIEX_TYPE_DATA:
dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n");
- mwifiex_handle_rx_packet(adapter, skb);
+ if (adapter->rx_work_enabled) {
+ spin_lock_irqsave(&adapter->rx_q_lock, flags);
+ skb_queue_tail(&adapter->rx_data_q, skb);
+ spin_unlock_irqrestore(&adapter->rx_q_lock, flags);
+ adapter->data_received = true;
+ atomic_inc(&adapter->rx_pending);
+ } else {
+ mwifiex_handle_rx_packet(adapter, skb);
+ }
break;
case MWIFIEX_TYPE_CMD:
@@ -1527,8 +1529,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
__func__);
if (MP_TX_AGGR_IN_PROGRESS(card)) {
- if (!mp_tx_aggr_port_limit_reached(card) &&
- MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) {
+ if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) {
f_precopy_cur_buf = 1;
if (!(card->mp_wr_bitmap &
@@ -1540,8 +1541,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
/* No room in Aggr buf, send it */
f_send_aggr_buf = 1;
- if (mp_tx_aggr_port_limit_reached(card) ||
- !(card->mp_wr_bitmap &
+ if (!(card->mp_wr_bitmap &
(1 << card->curr_wr_port)))
f_send_cur_buf = 1;
else
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 733de92a4c6..225f7498048 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -965,7 +965,7 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
u16 cmd_action, u32 cmd_oid,
struct mwifiex_ds_encrypt_key *enc_key)
{
- if (priv->adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+ if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
return mwifiex_cmd_802_11_key_material_v2(priv, cmd,
cmd_action, cmd_oid,
enc_key);
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 08b78baeb84..4aad44685f8 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -85,8 +85,6 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->scan_processing = false;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
- if (priv->report_scan_result)
- priv->report_scan_result = false;
break;
case HostCmd_CMD_MAC_CONTROL:
@@ -637,7 +635,7 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv,
static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp)
{
- if (priv->adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+ if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
return mwifiex_ret_802_11_key_material_v2(priv, resp);
else
return mwifiex_ret_802_11_key_material_v1(priv, resp);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index caae9738100..92f3eb83986 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -287,10 +287,13 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
return -1;
if (mwifiex_band_to_radio_type(bss_desc->bss_band) ==
- HostCmd_SCAN_RADIO_TYPE_BG)
+ HostCmd_SCAN_RADIO_TYPE_BG) {
config_bands = BAND_B | BAND_G | BAND_GN;
- else
- config_bands = BAND_A | BAND_AN | BAND_AAC;
+ } else {
+ config_bands = BAND_A | BAND_AN;
+ if (adapter->fw_bands & BAND_AAC)
+ config_bands |= BAND_AAC;
+ }
if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands))
adapter->config_bands = config_bands;
@@ -877,7 +880,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
return -1;
}
- if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2) {
+ if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) {
memcpy(encrypt_key->key_material,
wep_key->key_material, wep_key->key_length);
encrypt_key->key_len = wep_key->key_length;
@@ -903,7 +906,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
memset(&priv->wep_key[index], 0,
sizeof(struct mwifiex_wep_key));
- if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+ if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
enc_key = encrypt_key;
else
enc_key = NULL;
diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c
index 4c5fd953893..e2949077f5b 100644
--- a/drivers/net/wireless/mwifiex/tdls.c
+++ b/drivers/net/wireless/mwifiex/tdls.c
@@ -871,7 +871,9 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
break;
case WLAN_EID_RSN:
memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos,
- sizeof(struct ieee_types_header) + pos[1]);
+ sizeof(struct ieee_types_header) +
+ min_t(u8, pos[1], IEEE_MAX_IE_SIZE -
+ sizeof(struct ieee_types_header)));
break;
case WLAN_EID_QOS_CAPA:
sta_ptr->tdls_cap.qos_info = pos[2];
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c
index 7118a18b91b..4371e12b36f 100644
--- a/drivers/net/wireless/mwifiex/usb.c
+++ b/drivers/net/wireless/mwifiex/usb.c
@@ -357,7 +357,7 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
card->usb_boot_state = USB8XXX_FW_READY;
break;
default:
- pr_warning("unknown id_product %#x\n", id_product);
+ pr_warn("unknown id_product %#x\n", id_product);
card->usb_boot_state = USB8XXX_FW_DNLD;
break;
}
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index cee028321a9..ec79c49de09 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -172,7 +172,7 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
cfg80211_rx_mgmt(priv->wdev, priv->roc_cfg.chan.center_freq,
CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len,
- 0, GFP_ATOMIC);
+ 0);
return 0;
}
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index d3cf7c3ebfd..995846422dc 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -534,7 +534,7 @@ static void ezusb_request_out_callback(struct urb *urb)
if (ctx->killed) {
spin_unlock_irqrestore(&upriv->req_lock, flags);
- pr_warning("interrupt called with dead ctx");
+ pr_warn("interrupt called with dead ctx\n");
goto out;
}
@@ -671,8 +671,8 @@ static void ezusb_request_in_callback(struct ezusb_priv *upriv,
default:
spin_unlock_irqrestore(&upriv->req_lock, flags);
- pr_warning("Matched IN URB, unexpected context state(0x%x)",
- state);
+ pr_warn("Matched IN URB, unexpected context state(0x%x)\n",
+ state);
/* Throw this CTX away and try submitting another */
del_timer(&ctx->timer);
ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
@@ -1394,12 +1394,12 @@ static void ezusb_bulk_in_callback(struct urb *urb)
/* When a device gets unplugged we get this every time
* we resubmit, flooding the logs. Since we don't use
* USB timeouts, it shouldn't happen any other time*/
- pr_warning("%s: urb timed out, not resubmiting", __func__);
+ pr_warn("%s: urb timed out, not resubmitting\n", __func__);
return;
}
if (urb->status == -ECONNABORTED) {
- pr_warning("%s: connection abort, resubmiting urb",
- __func__);
+ pr_warn("%s: connection abort, resubmitting urb\n",
+ __func__);
goto resubmit;
}
if ((urb->status == -EILSEQ)
@@ -1605,13 +1605,10 @@ static int ezusb_probe(struct usb_interface *interface,
for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
ep = &interface->altsetting[0].endpoint[i].desc;
- if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_IN) &&
- ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)) {
+ if (usb_endpoint_is_bulk_in(ep)) {
/* we found a bulk in endpoint */
if (upriv->read_urb != NULL) {
- pr_warning("Found a second bulk in ep, ignored");
+ pr_warn("Found a second bulk in ep, ignored\n");
continue;
}
@@ -1621,10 +1618,10 @@ static int ezusb_probe(struct usb_interface *interface,
goto error;
}
if (le16_to_cpu(ep->wMaxPacketSize) != 64)
- pr_warning("bulk in: wMaxPacketSize!= 64");
+ pr_warn("bulk in: wMaxPacketSize!= 64\n");
if (ep->bEndpointAddress != (2 | USB_DIR_IN))
- pr_warning("bulk in: bEndpointAddress: %d",
- ep->bEndpointAddress);
+ pr_warn("bulk in: bEndpointAddress: %d\n",
+ ep->bEndpointAddress);
upriv->read_pipe = usb_rcvbulkpipe(udev,
ep->
bEndpointAddress);
@@ -1636,21 +1633,18 @@ static int ezusb_probe(struct usb_interface *interface,
}
}
- if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_OUT) &&
- ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)) {
+ if (usb_endpoint_is_bulk_out(ep)) {
/* we found a bulk out endpoint */
if (upriv->bap_buf != NULL) {
- pr_warning("Found a second bulk out ep, ignored");
+ pr_warn("Found a second bulk out ep, ignored\n");
continue;
}
if (le16_to_cpu(ep->wMaxPacketSize) != 64)
- pr_warning("bulk out: wMaxPacketSize != 64");
+ pr_warn("bulk out: wMaxPacketSize != 64\n");
if (ep->bEndpointAddress != 2)
- pr_warning("bulk out: bEndpointAddress: %d",
- ep->bEndpointAddress);
+ pr_warn("bulk out: bEndpointAddress: %d\n",
+ ep->bEndpointAddress);
upriv->write_pipe = usb_sndbulkpipe(udev,
ep->
bEndpointAddress);
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
index e175b9b8561..2c66166add7 100644
--- a/drivers/net/wireless/orinoco/scan.c
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -123,9 +123,10 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv,
beacon_interval = le16_to_cpu(bss->a.beacon_interv);
signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
- cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
- capability, beacon_interval, ie_buf, ie_len,
- signal, GFP_KERNEL);
+ cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
+ bss->a.bssid, timestamp, capability,
+ beacon_interval, ie_buf, ie_len, signal,
+ GFP_KERNEL);
cfg80211_put_bss(wiphy, cbss);
}
@@ -156,9 +157,10 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
ie = bss->data;
signal = SIGNAL_TO_MBM(bss->level);
- cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
- capability, beacon_interval, ie, ie_len,
- signal, GFP_KERNEL);
+ cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
+ bss->bssid, timestamp, capability,
+ beacon_interval, ie, ie_len, signal,
+ GFP_KERNEL);
cfg80211_put_bss(wiphy, cbss);
}
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index 7be3a483964..97aeff0edb8 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -696,7 +696,8 @@ static void p54_flush(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
WARN(total, "tx flush timeout, unresponsive firmware");
}
-static void p54_set_coverage_class(struct ieee80211_hw *dev, u8 coverage_class)
+static void p54_set_coverage_class(struct ieee80211_hw *dev,
+ s16 coverage_class)
{
struct p54_common *priv = dev->priv;
diff --git a/drivers/net/wireless/ray_cs.h b/drivers/net/wireless/ray_cs.h
index e79848fbcca..524c2f02dd8 100644
--- a/drivers/net/wireless/ray_cs.h
+++ b/drivers/net/wireless/ray_cs.h
@@ -3,7 +3,8 @@
Written by Corey Thomas
*/
-#ifndef RAYLINK_H
+#ifndef _RAY_CS_H_
+#define _RAY_CS_H_
struct beacon_rx {
struct mac_header mac;
@@ -69,4 +70,4 @@ typedef struct ray_dev_t {
} ray_dev_t;
/*****************************************************************************/
-#endif /* RAYLINK_H */
+#endif /* _RAY_CS_H_ */
diff --git a/drivers/net/wireless/rayctl.h b/drivers/net/wireless/rayctl.h
index 3c3b98b152c..b21ed64e15d 100644
--- a/drivers/net/wireless/rayctl.h
+++ b/drivers/net/wireless/rayctl.h
@@ -1,4 +1,5 @@
-#ifndef RAYLINK_H
+#ifndef _RAYCTL_H_
+#define _RAYCTL_H_
typedef unsigned char UCHAR;
@@ -729,4 +730,4 @@ typedef struct snaphdr_t
#define RAY_IPX_TYPE 0x8137
#define APPLEARP_TYPE 0x80f3
/*****************************************************************************/
-#endif /* #ifndef RAYLINK_H */
+#endif /* _RAYCTL_H_ */
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index d2a9a08210b..1a4facd1fbf 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2022,9 +2022,10 @@ static bool rndis_bss_info_update(struct usbnet *usbdev,
capability = le16_to_cpu(fixed->capabilities);
beacon_interval = le16_to_cpu(fixed->beacon_interval);
- bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
- timestamp, capability, beacon_interval, ie, ie_len, signal,
- GFP_KERNEL);
+ bss = cfg80211_inform_bss(priv->wdev.wiphy, channel,
+ CFG80211_BSS_FTYPE_UNKNOWN, bssid->mac,
+ timestamp, capability, beacon_interval,
+ ie, ie_len, signal, GFP_KERNEL);
cfg80211_put_bss(priv->wdev.wiphy, bss);
return (bss != NULL);
@@ -2711,9 +2712,10 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
bssid, (u32)timestamp, capability, beacon_period, ie_len,
ssid.essid, signal);
- bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
- timestamp, capability, beacon_period, ie_buf, ie_len,
- signal, GFP_KERNEL);
+ bss = cfg80211_inform_bss(priv->wdev.wiphy, channel,
+ CFG80211_BSS_FTYPE_UNKNOWN, bssid,
+ timestamp, capability, beacon_period,
+ ie_buf, ie_len, signal, GFP_KERNEL);
cfg80211_put_bss(priv->wdev.wiphy, bss);
}
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index a394a9a9591..b7434df51e7 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -52,6 +52,7 @@
* RF5592 2.4G/5G 2T2R
* RF3070 2.4G 1T1R
* RF5360 2.4G 1T1R
+ * RF5362 2.4G 1T1R
* RF5370 2.4G 1T1R
* RF5390 2.4G 1T1R
*/
@@ -72,6 +73,7 @@
#define RF3070 0x3070
#define RF3290 0x3290
#define RF5360 0x5360
+#define RF5362 0x5362
#define RF5370 0x5370
#define RF5372 0x5372
#define RF5390 0x5390
@@ -2145,7 +2147,7 @@ struct mac_iveiv_entry {
/* Bits [7-4] for RF3320 (RT3370/RT3390), on other chipsets reserved */
#define RFCSR3_PA1_BIAS_CCK FIELD8(0x70)
#define RFCSR3_PA2_CASCODE_BIAS_CCKK FIELD8(0x80)
-/* Bits for RF3290/RF5360/RF5370/RF5372/RF5390/RF5392 */
+/* Bits for RF3290/RF5360/RF5362/RF5370/RF5372/RF5390/RF5392 */
#define RFCSR3_VCOCAL_EN FIELD8(0x80)
/* Bits for RF3050 */
#define RFCSR3_BIT1 FIELD8(0x02)
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 893c9d5f3d6..9f57a2db791 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -3186,6 +3186,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
break;
case RF3070:
case RF5360:
+ case RF5362:
case RF5370:
case RF5372:
case RF5390:
@@ -3203,6 +3204,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
rt2x00_rf(rt2x00dev, RF3290) ||
rt2x00_rf(rt2x00dev, RF3322) ||
rt2x00_rf(rt2x00dev, RF5360) ||
+ rt2x00_rf(rt2x00dev, RF5362) ||
rt2x00_rf(rt2x00dev, RF5370) ||
rt2x00_rf(rt2x00dev, RF5372) ||
rt2x00_rf(rt2x00dev, RF5390) ||
@@ -4317,6 +4319,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev)
case RF3070:
case RF3290:
case RF5360:
+ case RF5362:
case RF5370:
case RF5372:
case RF5390:
@@ -7095,6 +7098,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
case RF3320:
case RF3322:
case RF5360:
+ case RF5362:
case RF5370:
case RF5372:
case RF5390:
@@ -7551,6 +7555,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
case RF3320:
case RF3322:
case RF5360:
+ case RF5362:
case RF5370:
case RF5372:
case RF5390:
@@ -7680,6 +7685,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
case RF3070:
case RF3290:
case RF5360:
+ case RF5362:
case RF5370:
case RF5372:
case RF5390:
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h
index d76684eb24d..39b9a3309cf 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h
@@ -37,7 +37,13 @@
#include "halbtcoutsrc.h"
+#include "halbtc8192e2ant.h"
+#include "halbtc8723b1ant.h"
#include "halbtc8723b2ant.h"
+#include "halbtc8821a2ant.h"
+#include "halbtc8821a1ant.h"
+
+#define GetDefaultAdapter(padapter) padapter
#define BIT0 0x00000001
#define BIT1 0x00000002
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c
new file mode 100644
index 00000000000..53261d6f857
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c
@@ -0,0 +1,3849 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+/**************************************************************
+ * Description:
+ *
+ * This file is for RTL8192E Co-exist mechanism
+ *
+ * History
+ * 2012/11/15 Cosa first check in.
+ *
+ **************************************************************/
+
+/**************************************************************
+ * include files
+ **************************************************************/
+#include "halbt_precomp.h"
+/**************************************************************
+ * Global variables, these are static variables
+ **************************************************************/
+static struct coex_dm_8192e_2ant glcoex_dm_8192e_2ant;
+static struct coex_dm_8192e_2ant *coex_dm = &glcoex_dm_8192e_2ant;
+static struct coex_sta_8192e_2ant glcoex_sta_8192e_2ant;
+static struct coex_sta_8192e_2ant *coex_sta = &glcoex_sta_8192e_2ant;
+
+static const char *const GLBtInfoSrc8192e2Ant[] = {
+ "BT Info[wifi fw]",
+ "BT Info[bt rsp]",
+ "BT Info[bt auto report]",
+};
+
+static u32 glcoex_ver_date_8192e_2ant = 20130902;
+static u32 glcoex_ver_8192e_2ant = 0x34;
+
+/**************************************************************
+ * local function proto type if needed
+ **************************************************************/
+/**************************************************************
+ * local function start with halbtc8192e2ant_
+ **************************************************************/
+static u8 halbtc8192e2ant_btrssi_state(u8 level_num, u8 rssi_thresh,
+ u8 rssi_thresh1)
+{
+ int btrssi = 0;
+ u8 btrssi_state = coex_sta->pre_bt_rssi_state;
+
+ btrssi = coex_sta->bt_rssi;
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi pre state = LOW\n");
+ if (btrssi >= (rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+ btrssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state switch to High\n");
+ } else {
+ btrssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state stay at Low\n");
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi pre state = HIGH\n");
+ if (btrssi < rssi_thresh) {
+ btrssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state switch to Low\n");
+ } else {
+ btrssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi thresh error!!\n");
+ return coex_sta->pre_bt_rssi_state;
+ }
+
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi pre state = LOW\n");
+ if (btrssi >= (rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+ btrssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state switch to Medium\n");
+ } else {
+ btrssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi pre state = MEDIUM\n");
+ if (btrssi >= (rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+ btrssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state switch to High\n");
+ } else if (btrssi < rssi_thresh) {
+ btrssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state switch to Low\n");
+ } else {
+ btrssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state stay at Medium\n");
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi pre state = HIGH\n");
+ if (btrssi < rssi_thresh1) {
+ btrssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state switch to Medium\n");
+ } else {
+ btrssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "BT Rssi state stay at High\n");
+ }
+ }
+ }
+
+ coex_sta->pre_bt_rssi_state = btrssi_state;
+
+ return btrssi_state;
+}
+
+static u8 halbtc8192e2ant_wifirssi_state(struct btc_coexist *btcoexist,
+ u8 index, u8 level_num, u8 rssi_thresh,
+ u8 rssi_thresh1)
+{
+ int wifirssi = 0;
+ u8 wifirssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi);
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifirssi >= (rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+ wifirssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state switch to High\n");
+ } else {
+ wifirssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state stay at Low\n");
+ }
+ } else {
+ if (wifirssi < rssi_thresh) {
+ wifirssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state switch to Low\n");
+ } else {
+ wifirssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI thresh error!!\n");
+ return coex_sta->pre_wifi_rssi_state[index];
+ }
+
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifirssi >= (rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+ wifirssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state switch to Medium\n");
+ } else {
+ wifirssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (wifirssi >= (rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+ wifirssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state switch to High\n");
+ } else if (wifirssi < rssi_thresh) {
+ wifirssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state switch to Low\n");
+ } else {
+ wifirssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state stay at Medium\n");
+ }
+ } else {
+ if (wifirssi < rssi_thresh1) {
+ wifirssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state switch to Medium\n");
+ } else {
+ wifirssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "wifi RSSI state stay at High\n");
+ }
+ }
+ }
+
+ coex_sta->pre_wifi_rssi_state[index] = wifirssi_state;
+
+ return wifirssi_state;
+}
+
+static void btc8192e2ant_monitor_bt_enable_dis(struct btc_coexist *btcoexist)
+{
+ static bool pre_bt_disabled;
+ static u32 bt_disable_cnt;
+ bool bt_active = true, bt_disabled = false;
+
+ /* This function check if bt is disabled */
+
+ if (coex_sta->high_priority_tx == 0 &&
+ coex_sta->high_priority_rx == 0 &&
+ coex_sta->low_priority_tx == 0 &&
+ coex_sta->low_priority_rx == 0)
+ bt_active = false;
+
+ if (coex_sta->high_priority_tx == 0xffff &&
+ coex_sta->high_priority_rx == 0xffff &&
+ coex_sta->low_priority_tx == 0xffff &&
+ coex_sta->low_priority_rx == 0xffff)
+ bt_active = false;
+
+ if (bt_active) {
+ bt_disable_cnt = 0;
+ bt_disabled = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+ &bt_disabled);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is enabled !!\n");
+ } else {
+ bt_disable_cnt++;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], bt all counters = 0, %d times!!\n",
+ bt_disable_cnt);
+ if (bt_disable_cnt >= 2) {
+ bt_disabled = true;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+ &bt_disabled);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is disabled !!\n");
+ }
+ }
+ if (pre_bt_disabled != bt_disabled) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is from %s to %s!!\n",
+ (pre_bt_disabled ? "disabled" : "enabled"),
+ (bt_disabled ? "disabled" : "enabled"));
+ pre_bt_disabled = bt_disabled;
+ }
+}
+
+static u32 halbtc8192e2ant_decidera_mask(struct btc_coexist *btcoexist,
+ u8 sstype, u32 ra_masktype)
+{
+ u32 disra_mask = 0x0;
+
+ switch (ra_masktype) {
+ case 0: /* normal mode */
+ if (sstype == 2)
+ disra_mask = 0x0; /* enable 2ss */
+ else
+ disra_mask = 0xfff00000;/* disable 2ss */
+ break;
+ case 1: /* disable cck 1/2 */
+ if (sstype == 2)
+ disra_mask = 0x00000003;/* enable 2ss */
+ else
+ disra_mask = 0xfff00003;/* disable 2ss */
+ break;
+ case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */
+ if (sstype == 2)
+ disra_mask = 0x0001f1f7;/* enable 2ss */
+ else
+ disra_mask = 0xfff1f1f7;/* disable 2ss */
+ break;
+ default:
+ break;
+ }
+
+ return disra_mask;
+}
+
+static void halbtc8192e2ant_Updatera_mask(struct btc_coexist *btcoexist,
+ bool force_exec, u32 dis_ratemask)
+{
+ coex_dm->curra_mask = dis_ratemask;
+
+ if (force_exec || (coex_dm->prera_mask != coex_dm->curra_mask))
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask,
+ &coex_dm->curra_mask);
+ coex_dm->prera_mask = coex_dm->curra_mask;
+}
+
+static void btc8192e2ant_autorate_fallback_retry(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ bool wifi_under_bmode = false;
+
+ coex_dm->cur_arfrtype = type;
+
+ if (force_exec || (coex_dm->pre_arfrtype != coex_dm->cur_arfrtype)) {
+ switch (coex_dm->cur_arfrtype) {
+ case 0: /* normal mode */
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ coex_dm->backup_arfr_cnt1);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ coex_dm->backup_arfr_cnt2);
+ break;
+ case 1:
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_UNDER_B_MODE,
+ &wifi_under_bmode);
+ if (wifi_under_bmode) {
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ 0x0);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ 0x01010101);
+ } else {
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ 0x0);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ 0x04030201);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_arfrtype = coex_dm->cur_arfrtype;
+}
+
+static void halbtc8192e2ant_retrylimit(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ coex_dm->cur_retrylimit_type = type;
+
+ if (force_exec || (coex_dm->pre_retrylimit_type !=
+ coex_dm->cur_retrylimit_type)) {
+ switch (coex_dm->cur_retrylimit_type) {
+ case 0: /* normal mode */
+ btcoexist->btc_write_2byte(btcoexist, 0x42a,
+ coex_dm->backup_retrylimit);
+ break;
+ case 1: /* retry limit = 8 */
+ btcoexist->btc_write_2byte(btcoexist, 0x42a,
+ 0x0808);
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_retrylimit_type = coex_dm->cur_retrylimit_type;
+}
+
+static void halbtc8192e2ant_ampdu_maxtime(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ coex_dm->cur_ampdutime_type = type;
+
+ if (force_exec || (coex_dm->pre_ampdutime_type !=
+ coex_dm->cur_ampdutime_type)) {
+ switch (coex_dm->cur_ampdutime_type) {
+ case 0: /* normal mode */
+ btcoexist->btc_write_1byte(btcoexist, 0x456,
+ coex_dm->backup_ampdu_maxtime);
+ break;
+ case 1: /* AMPDU timw = 0x38 * 32us */
+ btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38);
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_ampdutime_type = coex_dm->cur_ampdutime_type;
+}
+
+static void halbtc8192e2ant_limited_tx(struct btc_coexist *btcoexist,
+ bool force_exec, u8 ra_masktype,
+ u8 arfr_type, u8 retrylimit_type,
+ u8 ampdutime_type)
+{
+ u32 disra_mask = 0x0;
+
+ coex_dm->curra_masktype = ra_masktype;
+ disra_mask = halbtc8192e2ant_decidera_mask(btcoexist,
+ coex_dm->cur_sstype,
+ ra_masktype);
+ halbtc8192e2ant_Updatera_mask(btcoexist, force_exec, disra_mask);
+btc8192e2ant_autorate_fallback_retry(btcoexist, force_exec, arfr_type);
+ halbtc8192e2ant_retrylimit(btcoexist, force_exec, retrylimit_type);
+ halbtc8192e2ant_ampdu_maxtime(btcoexist, force_exec, ampdutime_type);
+}
+
+static void halbtc8192e2ant_limited_rx(struct btc_coexist *btcoexist,
+ bool force_exec, bool rej_ap_agg_pkt,
+ bool bt_ctrl_agg_buf_size,
+ u8 agg_buf_size)
+{
+ bool reject_rx_agg = rej_ap_agg_pkt;
+ bool bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size;
+ u8 rx_agg_size = agg_buf_size;
+
+ /*********************************************
+ * Rx Aggregation related setting
+ *********************************************/
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT,
+ &reject_rx_agg);
+ /* decide BT control aggregation buf size or not */
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE,
+ &bt_ctrl_rx_agg_size);
+ /* aggregation buf size, only work
+ * when BT control Rx aggregation size.
+ */
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size);
+ /* real update aggregation setting */
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL);
+}
+
+static void halbtc8192e2ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+ u32 reg_hp_txrx, reg_lp_txrx, u32tmp;
+ u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0;
+
+ reg_hp_txrx = 0x770;
+ reg_lp_txrx = 0x774;
+
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx);
+ reg_hp_tx = u32tmp & MASKLWORD;
+ reg_hp_rx = (u32tmp & MASKHWORD)>>16;
+
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx);
+ reg_lp_tx = u32tmp & MASKLWORD;
+ reg_lp_rx = (u32tmp & MASKHWORD)>>16;
+
+ coex_sta->high_priority_tx = reg_hp_tx;
+ coex_sta->high_priority_rx = reg_hp_rx;
+ coex_sta->low_priority_tx = reg_lp_tx;
+ coex_sta->low_priority_rx = reg_lp_rx;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex] High Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
+ reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex] Low Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
+ reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx);
+
+ /* reset counter */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static void halbtc8192e2ant_querybt_info(struct btc_coexist *btcoexist)
+{
+ u8 h2c_parameter[1] = {0};
+
+ coex_sta->c2h_bt_info_req_sent = true;
+
+ h2c_parameter[0] |= BIT0; /* trigger */
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_update_btlink_info(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool bt_hson = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson);
+
+ bt_link_info->bt_link_exist = coex_sta->bt_link_exist;
+ bt_link_info->sco_exist = coex_sta->sco_exist;
+ bt_link_info->a2dp_exist = coex_sta->a2dp_exist;
+ bt_link_info->pan_exist = coex_sta->pan_exist;
+ bt_link_info->hid_exist = coex_sta->hid_exist;
+
+ /* work around for HS mode. */
+ if (bt_hson) {
+ bt_link_info->pan_exist = true;
+ bt_link_info->bt_link_exist = true;
+ }
+
+ /* check if Sco only */
+ if (bt_link_info->sco_exist &&
+ !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist &&
+ !bt_link_info->hid_exist)
+ bt_link_info->sco_only = true;
+ else
+ bt_link_info->sco_only = false;
+
+ /* check if A2dp only */
+ if (!bt_link_info->sco_exist &&
+ bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist &&
+ !bt_link_info->hid_exist)
+ bt_link_info->a2dp_only = true;
+ else
+ bt_link_info->a2dp_only = false;
+
+ /* check if Pan only */
+ if (!bt_link_info->sco_exist &&
+ !bt_link_info->a2dp_exist &&
+ bt_link_info->pan_exist &&
+ !bt_link_info->hid_exist)
+ bt_link_info->pan_only = true;
+ else
+ bt_link_info->pan_only = false;
+
+ /* check if Hid only */
+ if (!bt_link_info->sco_exist &&
+ !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist &&
+ bt_link_info->hid_exist)
+ bt_link_info->hid_only = true;
+ else
+ bt_link_info->hid_only = false;
+}
+
+static u8 halbtc8192e2ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ bool bt_hson = false;
+ u8 algorithm = BT_8192E_2ANT_COEX_ALGO_UNDEFINED;
+ u8 numdiffprofile = 0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson);
+
+ if (!bt_link_info->bt_link_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "No BT link exists!!!\n");
+ return algorithm;
+ }
+
+ if (bt_link_info->sco_exist)
+ numdiffprofile++;
+ if (bt_link_info->hid_exist)
+ numdiffprofile++;
+ if (bt_link_info->pan_exist)
+ numdiffprofile++;
+ if (bt_link_info->a2dp_exist)
+ numdiffprofile++;
+
+ if (numdiffprofile == 1) {
+ if (bt_link_info->sco_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO only\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+ } else {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID only\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "A2DP only\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_A2DP;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "PAN(HS) only\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "PAN(EDR) only\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_PANEDR;
+ }
+ }
+ }
+ } else if (numdiffprofile == 2) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + HID\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + A2DP ==> SCO\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + PAN(HS)\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_SCO_PAN;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ if (stack_info->num_of_hid >= 2) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID*2 + A2DP\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID + A2DP\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_HID_A2DP;
+ }
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID + PAN(HS)\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_HID;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID + PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "A2DP + PAN(HS)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "A2DP + PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP;
+ }
+ }
+ }
+ } else if (numdiffprofile == 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + HID + A2DP ==> HID\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + HID + PAN(HS)\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + HID + PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_SCO_PAN;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + A2DP + PAN(HS)\n");
+ algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO + A2DP + PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID + A2DP + PAN(HS)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "HID + A2DP + PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+ }
+ }
+ }
+ } else if (numdiffprofile >= 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hson) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "ErrorSCO+HID+A2DP+PAN(HS)\n");
+
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "SCO+HID+A2DP+PAN(EDR)\n");
+ algorithm =
+ BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ }
+ }
+
+ return algorithm;
+}
+
+static void halbtc8192e2ant_setfw_dac_swinglevel(struct btc_coexist *btcoexist,
+ u8 dac_swinglvl)
+{
+ u8 h2c_parameter[1] = {0};
+
+ /* There are several type of dacswing
+ * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6
+ */
+ h2c_parameter[0] = dac_swinglvl;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swinglvl);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x64 = 0x%x\n", h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_set_fwdec_btpwr(struct btc_coexist *btcoexist,
+ u8 dec_btpwr_lvl)
+{
+ u8 h2c_parameter[1] = {0};
+
+ h2c_parameter[0] = dec_btpwr_lvl;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex] decrease Bt Power level = %d, FW write 0x62 = 0x%x\n",
+ dec_btpwr_lvl, h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_dec_btpwr(struct btc_coexist *btcoexist,
+ bool force_exec, u8 dec_btpwr_lvl)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s Dec BT power level = %d\n",
+ (force_exec ? "force to" : ""), dec_btpwr_lvl);
+ coex_dm->cur_dec_bt_pwr = dec_btpwr_lvl;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], preBtDecPwrLvl=%d, curBtDecPwrLvl=%d\n",
+ coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr);
+ }
+ halbtc8192e2ant_set_fwdec_btpwr(btcoexist, coex_dm->cur_dec_bt_pwr);
+
+ coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr;
+}
+
+static void halbtc8192e2ant_set_bt_autoreport(struct btc_coexist *btcoexist,
+ bool enable_autoreport)
+{
+ u8 h2c_parameter[1] = {0};
+
+ h2c_parameter[0] = 0;
+
+ if (enable_autoreport)
+ h2c_parameter[0] |= BIT0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n",
+ (enable_autoreport ? "Enabled!!" : "Disabled!!"),
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_bt_autoreport(struct btc_coexist *btcoexist,
+ bool force_exec,
+ bool enable_autoreport)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s BT Auto report = %s\n",
+ (force_exec ? "force to" : ""),
+ ((enable_autoreport) ? "Enabled" : "Disabled"));
+ coex_dm->cur_bt_auto_report = enable_autoreport;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex] bPreBtAutoReport=%d, bCurBtAutoReport=%d\n",
+ coex_dm->pre_bt_auto_report,
+ coex_dm->cur_bt_auto_report);
+
+ if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report)
+ return;
+ }
+ halbtc8192e2ant_set_bt_autoreport(btcoexist,
+ coex_dm->cur_bt_auto_report);
+
+ coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report;
+}
+
+static void halbtc8192e2ant_fw_dac_swinglvl(struct btc_coexist *btcoexist,
+ bool force_exec, u8 fw_dac_swinglvl)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s set FW Dac Swing level = %d\n",
+ (force_exec ? "force to" : ""), fw_dac_swinglvl);
+ coex_dm->cur_fw_dac_swing_lvl = fw_dac_swinglvl;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex] preFwDacSwingLvl=%d, curFwDacSwingLvl=%d\n",
+ coex_dm->pre_fw_dac_swing_lvl,
+ coex_dm->cur_fw_dac_swing_lvl);
+
+ if (coex_dm->pre_fw_dac_swing_lvl ==
+ coex_dm->cur_fw_dac_swing_lvl)
+ return;
+ }
+
+ halbtc8192e2ant_setfw_dac_swinglevel(btcoexist,
+ coex_dm->cur_fw_dac_swing_lvl);
+
+ coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl;
+}
+
+static void btc8192e2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist,
+ bool rx_rf_shrink_on)
+{
+ if (rx_rf_shrink_on) {
+ /* Shrink RF Rx LPF corner */
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Shrink RF Rx LPF corner!!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e,
+ 0xfffff, 0xffffc);
+ } else {
+ /* Resume RF Rx LPF corner
+ * After initialized, we can use coex_dm->btRf0x1eBackup
+ */
+ if (btcoexist->initilized) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Resume RF Rx LPF corner!!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e,
+ 0xfffff,
+ coex_dm->bt_rf0x1e_backup);
+ }
+ }
+}
+
+static void halbtc8192e2ant_rf_shrink(struct btc_coexist *btcoexist,
+ bool force_exec, bool rx_rf_shrink_on)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn Rx RF Shrink = %s\n",
+ (force_exec ? "force to" : ""),
+ ((rx_rf_shrink_on) ? "ON" : "OFF"));
+ coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex]bPreRfRxLpfShrink=%d,bCurRfRxLpfShrink=%d\n",
+ coex_dm->pre_rf_rx_lpf_shrink,
+ coex_dm->cur_rf_rx_lpf_shrink);
+
+ if (coex_dm->pre_rf_rx_lpf_shrink ==
+ coex_dm->cur_rf_rx_lpf_shrink)
+ return;
+ }
+ btc8192e2ant_set_sw_rf_rx_lpf_corner(btcoexist,
+ coex_dm->cur_rf_rx_lpf_shrink);
+
+ coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink;
+}
+
+static void halbtc8192e2ant_set_dac_swingreg(struct btc_coexist *btcoexist,
+ u32 level)
+{
+ u8 val = (u8)level;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Write SwDacSwing = 0x%x\n", level);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val);
+}
+
+static void btc8192e2ant_setsw_full_swing(struct btc_coexist *btcoexist,
+ bool sw_dac_swingon,
+ u32 sw_dac_swinglvl)
+{
+ if (sw_dac_swingon)
+ halbtc8192e2ant_set_dac_swingreg(btcoexist, sw_dac_swinglvl);
+ else
+ halbtc8192e2ant_set_dac_swingreg(btcoexist, 0x18);
+}
+
+static void halbtc8192e2ant_DacSwing(struct btc_coexist *btcoexist,
+ bool force_exec, bool dac_swingon,
+ u32 dac_swinglvl)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn DacSwing=%s, dac_swinglvl = 0x%x\n",
+ (force_exec ? "force to" : ""),
+ ((dac_swingon) ? "ON" : "OFF"), dac_swinglvl);
+ coex_dm->cur_dac_swing_on = dac_swingon;
+ coex_dm->cur_dac_swing_lvl = dac_swinglvl;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl = 0x%x, ",
+ coex_dm->pre_dac_swing_on,
+ coex_dm->pre_dac_swing_lvl);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "bCurDacSwingOn=%d, curDacSwingLvl = 0x%x\n",
+ coex_dm->cur_dac_swing_on,
+ coex_dm->cur_dac_swing_lvl);
+
+ if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) &&
+ (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl))
+ return;
+ }
+ mdelay(30);
+ btc8192e2ant_setsw_full_swing(btcoexist, dac_swingon, dac_swinglvl);
+
+ coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on;
+ coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl;
+}
+
+static void halbtc8192e2ant_set_agc_table(struct btc_coexist *btcoexist,
+ bool agc_table_en)
+{
+ /* BB AGC Gain Table */
+ if (agc_table_en) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], BB Agc Table On!\n");
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x0a1A0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x091B0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x081C0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x071D0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x061E0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x051F0001);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], BB Agc Table Off!\n");
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001);
+ btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001);
+ }
+}
+
+static void halbtc8192e2ant_AgcTable(struct btc_coexist *btcoexist,
+ bool force_exec, bool agc_table_en)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s %s Agc Table\n",
+ (force_exec ? "force to" : ""),
+ ((agc_table_en) ? "Enable" : "Disable"));
+ coex_dm->cur_agc_table_en = agc_table_en;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n",
+ coex_dm->pre_agc_table_en, coex_dm->cur_agc_table_en);
+
+ if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en)
+ return;
+ }
+ halbtc8192e2ant_set_agc_table(btcoexist, agc_table_en);
+
+ coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en;
+}
+
+static void halbtc8192e2ant_set_coex_table(struct btc_coexist *btcoexist,
+ u32 val0x6c0, u32 val0x6c4,
+ u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc);
+ btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void halbtc8192e2ant_coex_table(struct btc_coexist *btcoexist,
+ bool force_exec,
+ u32 val0x6c0, u32 val0x6c4,
+ u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, ",
+ (force_exec ? "force to" : ""), val0x6c0);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n",
+ val0x6c4, val0x6c8, val0x6cc);
+ coex_dm->cur_val0x6c0 = val0x6c0;
+ coex_dm->cur_val0x6c4 = val0x6c4;
+ coex_dm->cur_val0x6c8 = val0x6c8;
+ coex_dm->cur_val0x6cc = val0x6cc;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], preVal0x6c0 = 0x%x, preVal0x6c4 = 0x%x, ",
+ coex_dm->pre_val0x6c0, coex_dm->pre_val0x6c4);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "preVal0x6c8 = 0x%x, preVal0x6cc = 0x%x !!\n",
+ coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], curVal0x6c0 = 0x%x, curVal0x6c4 = 0x%x,\n",
+ coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "curVal0x6c8 = 0x%x, curVal0x6cc = 0x%x !!\n",
+ coex_dm->cur_val0x6c8, coex_dm->cur_val0x6cc);
+
+ if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) &&
+ (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) &&
+ (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) &&
+ (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc))
+ return;
+ }
+ halbtc8192e2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4,
+ val0x6c8, val0x6cc);
+
+ coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0;
+ coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4;
+ coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8;
+ coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc;
+}
+
+static void btc8192e2ant_coex_tbl_w_type(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ switch (type) {
+ case 0:
+ halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x5a5a5a5a, 0xffffff, 0x3);
+ break;
+ case 1:
+ halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+ 0x5a5a5a5a, 0xffffff, 0x3);
+ break;
+ case 2:
+ halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x5ffb5ffb, 0xffffff, 0x3);
+ break;
+ case 3:
+ halbtc8192e2ant_coex_table(btcoexist, force_exec, 0xdfffdfff,
+ 0x5fdb5fdb, 0xffffff, 0x3);
+ break;
+ case 4:
+ halbtc8192e2ant_coex_table(btcoexist, force_exec, 0xdfffdfff,
+ 0x5ffb5ffb, 0xffffff, 0x3);
+ break;
+ default:
+ break;
+ }
+}
+
+static void halbtc8192e2ant_set_fw_ignore_wlanact(struct btc_coexist *btcoexist,
+ bool enable)
+{
+ u8 h2c_parameter[1] = {0};
+
+ if (enable)
+ h2c_parameter[0] |= BIT0; /* function enable */
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex]set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_IgnoreWlanAct(struct btc_coexist *btcoexist,
+ bool force_exec, bool enable)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn Ignore WlanAct %s\n",
+ (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+ coex_dm->cur_ignore_wlan_act = enable;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], bPreIgnoreWlanAct = %d ",
+ coex_dm->pre_ignore_wlan_act);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "bCurIgnoreWlanAct = %d!!\n",
+ coex_dm->cur_ignore_wlan_act);
+
+ if (coex_dm->pre_ignore_wlan_act ==
+ coex_dm->cur_ignore_wlan_act)
+ return;
+ }
+ halbtc8192e2ant_set_fw_ignore_wlanact(btcoexist, enable);
+
+ coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void halbtc8192e2ant_SetFwPstdma(struct btc_coexist *btcoexist, u8 byte1,
+ u8 byte2, u8 byte3, u8 byte4, u8 byte5)
+{
+ u8 h2c_parameter[5] = {0};
+
+ h2c_parameter[0] = byte1;
+ h2c_parameter[1] = byte2;
+ h2c_parameter[2] = byte3;
+ h2c_parameter[3] = byte4;
+ h2c_parameter[4] = byte5;
+
+ coex_dm->ps_tdma_para[0] = byte1;
+ coex_dm->ps_tdma_para[1] = byte2;
+ coex_dm->ps_tdma_para[2] = byte3;
+ coex_dm->ps_tdma_para[3] = byte4;
+ coex_dm->ps_tdma_para[4] = byte5;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n",
+ h2c_parameter[0],
+ h2c_parameter[1] << 24 | h2c_parameter[2] << 16 |
+ h2c_parameter[3] << 8 | h2c_parameter[4]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void btc8192e2ant_sw_mec1(struct btc_coexist *btcoexist,
+ bool shrink_rx_lpf, bool low_penalty_ra,
+ bool limited_dig, bool btlan_constrain)
+{
+ halbtc8192e2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf);
+}
+
+static void btc8192e2ant_sw_mec2(struct btc_coexist *btcoexist,
+ bool agc_table_shift, bool adc_backoff,
+ bool sw_dac_swing, u32 dac_swinglvl)
+{
+ halbtc8192e2ant_AgcTable(btcoexist, NORMAL_EXEC, agc_table_shift);
+ halbtc8192e2ant_DacSwing(btcoexist, NORMAL_EXEC, sw_dac_swing,
+ dac_swinglvl);
+}
+
+static void halbtc8192e2ant_ps_tdma(struct btc_coexist *btcoexist,
+ bool force_exec, bool turn_on, u8 type)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn %s PS TDMA, type=%d\n",
+ (force_exec ? "force to" : ""),
+ (turn_on ? "ON" : "OFF"), type);
+ coex_dm->cur_ps_tdma_on = turn_on;
+ coex_dm->cur_ps_tdma = type;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n",
+ coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n",
+ coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma);
+
+ if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+ (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+ return;
+ }
+ if (turn_on) {
+ switch (type) {
+ case 1:
+ default:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x90);
+ break;
+ case 2:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0xe1, 0x90);
+ break;
+ case 3:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0xf1, 0x90);
+ break;
+ case 4:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x10,
+ 0x3, 0xf1, 0x90);
+ break;
+ case 5:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0x60, 0x90);
+ break;
+ case 6:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0x60, 0x90);
+ break;
+ case 7:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0x70, 0x90);
+ break;
+ case 8:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xa3, 0x10,
+ 0x3, 0x70, 0x90);
+ break;
+ case 9:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x10);
+ break;
+ case 10:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0xe1, 0x10);
+ break;
+ case 11:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0xf1, 0x10);
+ break;
+ case 12:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x10,
+ 0x3, 0xf1, 0x10);
+ break;
+ case 13:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe0, 0x10);
+ break;
+ case 14:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0xe0, 0x10);
+ break;
+ case 15:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0xf0, 0x10);
+ break;
+ case 16:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+ 0x3, 0xf0, 0x10);
+ break;
+ case 17:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0x61, 0x20,
+ 0x03, 0x10, 0x10);
+ break;
+ case 18:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x5,
+ 0x5, 0xe1, 0x90);
+ break;
+ case 19:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x25,
+ 0x25, 0xe1, 0x90);
+ break;
+ case 20:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x25,
+ 0x25, 0x60, 0x90);
+ break;
+ case 21:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x15,
+ 0x03, 0x70, 0x90);
+ break;
+ case 71:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x90);
+ break;
+ }
+ } else {
+ /* disable PS tdma */
+ switch (type) {
+ default:
+ case 0:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0x8, 0x0, 0x0,
+ 0x0, 0x0);
+ btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x4);
+ break;
+ case 1:
+ halbtc8192e2ant_SetFwPstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x8, 0x0);
+ mdelay(5);
+ btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20);
+ break;
+ }
+ }
+
+ /* update pre state */
+ coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+ coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static void halbtc8192e2ant_set_switch_sstype(struct btc_coexist *btcoexist,
+ u8 sstype)
+{
+ u8 mimops = BTC_MIMO_PS_DYNAMIC;
+ u32 disra_mask = 0x0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], REAL set SS Type = %d\n", sstype);
+
+ disra_mask = halbtc8192e2ant_decidera_mask(btcoexist, sstype,
+ coex_dm->curra_masktype);
+ halbtc8192e2ant_Updatera_mask(btcoexist, FORCE_EXEC, disra_mask);
+
+ if (sstype == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1);
+ /* switch ofdm path */
+ btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x11);
+ btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x1);
+ btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81111111);
+ /* switch cck patch */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x1);
+ btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x81);
+ mimops = BTC_MIMO_PS_STATIC;
+ } else if (sstype == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0);
+ btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x33);
+ btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x3);
+ btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81121313);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x0);
+ btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x41);
+ mimops = BTC_MIMO_PS_DYNAMIC;
+ }
+ /* set rx 1ss or 2ss */
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_SEND_MIMO_PS, &mimops);
+}
+
+static void halbtc8192e2ant_switch_sstype(struct btc_coexist *btcoexist,
+ bool force_exec, u8 new_sstype)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], %s Switch SS Type = %d\n",
+ (force_exec ? "force to" : ""), new_sstype);
+ coex_dm->cur_sstype = new_sstype;
+
+ if (!force_exec) {
+ if (coex_dm->pre_sstype == coex_dm->cur_sstype)
+ return;
+ }
+ halbtc8192e2ant_set_switch_sstype(btcoexist, coex_dm->cur_sstype);
+
+ coex_dm->pre_sstype = coex_dm->cur_sstype;
+}
+
+static void halbtc8192e2ant_coex_alloff(struct btc_coexist *btcoexist)
+{
+ /* fw all off */
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+ /* sw all off */
+ btc8192e2ant_sw_mec1(btcoexist, false, false, false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18);
+
+ /* hw all off */
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 0);
+}
+
+static void halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ /* force to reset coex mechanism */
+
+ halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1);
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, FORCE_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist, FORCE_EXEC, 0);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, FORCE_EXEC, 0);
+ halbtc8192e2ant_switch_sstype(btcoexist, FORCE_EXEC, 2);
+
+ btc8192e2ant_sw_mec1(btcoexist, false, false, false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18);
+}
+
+static void halbtc8192e2ant_action_bt_inquiry(struct btc_coexist *btcoexist)
+{
+ bool low_pwr_disable = true;
+
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+ btc8192e2ant_sw_mec1(btcoexist, false, false, false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18);
+}
+
+static bool halbtc8192e2ant_is_common_action(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool common = false, wifi_connected = false, wifi_busy = false;
+ bool bt_hson = false, low_pwr_disable = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+ if (bt_link_info->sco_exist || bt_link_info->hid_exist)
+ halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 0, 0, 0);
+ else
+ halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+
+ if (!wifi_connected) {
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi non-connected idle!!\n");
+
+ if ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status) ||
+ (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ halbtc8192e2ant_switch_sstype(btcoexist,
+ NORMAL_EXEC, 2);
+ btc8192e2ant_coex_tbl_w_type(btcoexist,
+ NORMAL_EXEC, 1);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0);
+ } else {
+ halbtc8192e2ant_switch_sstype(btcoexist,
+ NORMAL_EXEC, 1);
+ btc8192e2ant_coex_tbl_w_type(btcoexist,
+ NORMAL_EXEC, 0);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ }
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+ btc8192e2ant_sw_mec1(btcoexist, false, false, false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18);
+
+ common = true;
+ } else {
+ if (BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status) {
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Wifi connected + BT non connected-idle!!\n");
+
+ halbtc8192e2ant_switch_sstype(btcoexist,
+ NORMAL_EXEC, 2);
+ btc8192e2ant_coex_tbl_w_type(btcoexist,
+ NORMAL_EXEC, 1);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0);
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist,
+ NORMAL_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+
+ common = true;
+ } else if (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status) {
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ if (bt_hson)
+ return false;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Wifi connected + BT connected-idle!!\n");
+
+ halbtc8192e2ant_switch_sstype(btcoexist,
+ NORMAL_EXEC, 2);
+ btc8192e2ant_coex_tbl_w_type(btcoexist,
+ NORMAL_EXEC, 1);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0);
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist,
+ NORMAL_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+
+ common = true;
+ } else {
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ if (wifi_busy) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Wifi Connected-Busy + BT Busy!!\n");
+ common = false;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Wifi Connected-Idle + BT Busy!!\n");
+
+ halbtc8192e2ant_switch_sstype(btcoexist,
+ NORMAL_EXEC, 1);
+ btc8192e2ant_coex_tbl_w_type(btcoexist,
+ NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 21);
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist,
+ NORMAL_EXEC, 6);
+ halbtc8192e2ant_dec_btpwr(btcoexist,
+ NORMAL_EXEC, 0);
+ btc8192e2ant_sw_mec1(btcoexist, false,
+ false, false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false,
+ false, false, 0x18);
+ common = true;
+ }
+ }
+ }
+ return common;
+}
+
+static void btc8192e_int1(struct btc_coexist *btcoexist, bool tx_pause,
+ int result)
+{
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+
+ if (coex_dm->cur_ps_tdma == 71) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 71);
+ coex_dm->tdma_adj_type = 71;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 71) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 71);
+ coex_dm->tdma_adj_type = 71;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ }
+ }
+ }
+}
+
+static void btc8192e_int2(struct btc_coexist *btcoexist, bool tx_pause,
+ int result)
+{
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ }
+ }
+ }
+}
+
+static void btc8192e_int3(struct btc_coexist *btcoexist, bool tx_pause,
+ int result)
+{
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ }
+ }
+}
+
+static void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist,
+ bool sco_hid, bool tx_pause,
+ u8 max_interval)
+{
+ static int up, dn, m, n, wait_cnt;
+ /* 0: no change, +1: increase WiFi duration,
+ * -1: decrease WiFi duration
+ */
+ int result;
+ u8 retry_cnt = 0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], TdmaDurationAdjust()\n");
+
+ if (!coex_dm->auto_tdma_adjust) {
+ coex_dm->auto_tdma_adjust = true;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], first run TdmaDurationAdjust()!!\n");
+ if (sco_hid) {
+ if (tx_pause) {
+ if (max_interval == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ } else if (max_interval == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (max_interval == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ }
+ } else {
+ if (max_interval == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (max_interval == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (max_interval == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ }
+ } else {
+ if (tx_pause) {
+ if (max_interval == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (max_interval == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (max_interval == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ }
+ } else {
+ if (max_interval == 1) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (max_interval == 2) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (max_interval == 3) {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else {
+ halbtc8192e2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ }
+ }
+ }
+
+ up = 0;
+ dn = 0;
+ m = 1;
+ n = 3;
+ result = 0;
+ wait_cnt = 0;
+ } else {
+ /* accquire the BT TRx retry count from BT_Info byte2 */
+ retry_cnt = coex_sta->bt_retry_cnt;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], retry_cnt = %d\n", retry_cnt);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_cnt=%d\n",
+ up, dn, m, n, wait_cnt);
+ result = 0;
+ wait_cnt++;
+ /* no retry in the last 2-second duration */
+ if (retry_cnt == 0) {
+ up++;
+ dn--;
+
+ if (dn <= 0)
+ dn = 0;
+
+ if (up >= n) {
+ wait_cnt = 0;
+ n = 3;
+ up = 0;
+ dn = 0;
+ result = 1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex]Increase wifi duration!!\n");
+ }
+ } else if (retry_cnt <= 3) {
+ up--;
+ dn++;
+
+ if (up <= 0)
+ up = 0;
+
+ if (dn == 2) {
+ if (wait_cnt <= 2)
+ m++;
+ else
+ m = 1;
+
+ if (m >= 20)
+ m = 20;
+
+ n = 3 * m;
+ up = 0;
+ dn = 0;
+ wait_cnt = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "Reduce wifi duration for retry<3\n");
+ }
+ } else {
+ if (wait_cnt == 1)
+ m++;
+ else
+ m = 1;
+
+ if (m >= 20)
+ m = 20;
+
+ n = 3*m;
+ up = 0;
+ dn = 0;
+ wait_cnt = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "Decrease wifi duration for retryCounter>3!!\n");
+ }
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], max Interval = %d\n", max_interval);
+ if (max_interval == 1)
+ btc8192e_int1(btcoexist, tx_pause, result);
+ else if (max_interval == 2)
+ btc8192e_int2(btcoexist, tx_pause, result);
+ else if (max_interval == 3)
+ btc8192e_int3(btcoexist, tx_pause, result);
+ }
+
+ /* if current PsTdma not match with
+ * the recorded one (when scan, dhcp...),
+ * then we have to adjust it back to the previous record one.
+ */
+ if (coex_dm->cur_ps_tdma != coex_dm->tdma_adj_type) {
+ bool scan = false, link = false, roam = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], PsTdma type dismatch!!!, ");
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "curPsTdma=%d, recordPsTdma=%d\n",
+ coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+ if (!scan && !link && !roam)
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true,
+ coex_dm->tdma_adj_type);
+ else
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n");
+ }
+}
+
+/* SCO only or SCO+PAN(HS) */
+static void halbtc8192e2ant_action_sco(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 4);
+
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x6);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x6);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x6);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x6);
+ }
+ }
+}
+
+static void halbtc8192e2ant_action_sco_pan(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 4);
+
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x6);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x6);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x6);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x6);
+ }
+ }
+}
+
+static void halbtc8192e2ant_action_hid(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+ }
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */
+static void halbtc8192e2ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+ bool long_dist = false;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW ||
+ btrssi_state == BTC_RSSI_STATE_STAY_LOW) &&
+ (wifirssi_state == BTC_RSSI_STATE_LOW ||
+ wifirssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], A2dp, wifi/bt rssi both LOW!!\n");
+ long_dist = true;
+ }
+ if (long_dist) {
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true,
+ 0x4);
+ } else {
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false,
+ 0x8);
+ }
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (long_dist)
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 0);
+ else
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+ if (long_dist) {
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 17);
+ coex_dm->auto_tdma_adjust = false;
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ } else {
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ true, 1);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ false, 1);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ false, 1);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ }
+ }
+
+ /* sw mechanism */
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8192e2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, true, 2);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ false, 2);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ false, 2);
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ }
+
+ /* sw mechanism */
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ true, 0x6);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ true, 0x6);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ true, 0x6);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ true, 0x6);
+ }
+ }
+}
+
+static void halbtc8192e2ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1);
+ }
+
+ /* sw mechanism */
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* PAN(HS) only */
+static void halbtc8192e2ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ }
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* PAN(EDR)+A2DP */
+static void halbtc8192e2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, true, 3);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ false, 3);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+ false, 3);
+ }
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, false,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8192e2ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ }
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* HID+A2DP+PAN(EDR) */
+static void btc8192e2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, true, 3);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 3);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 3);
+ }
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8192e2ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_bw;
+
+ wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+ btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+ halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+ halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3);
+
+ if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, true, 2);
+ } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 2);
+ } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+ (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+ halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 2);
+ }
+
+ /* sw mechanism */
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, true, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8192e2ant_sw_mec1(btcoexist, false, true,
+ false, false);
+ btc8192e2ant_sw_mec2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8192e2ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+ u8 algorithm = 0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism()===>\n");
+
+ if (btcoexist->manual_control) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], return for Manual CTRL <===\n");
+ return;
+ }
+
+ if (coex_sta->under_ips) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], wifi is under IPS !!!\n");
+ return;
+ }
+
+ algorithm = halbtc8192e2ant_action_algorithm(btcoexist);
+ if (coex_sta->c2h_bt_inquiry_page &&
+ (BT_8192E_2ANT_COEX_ALGO_PANHS != algorithm)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT is under inquiry/page scan !!\n");
+ halbtc8192e2ant_action_bt_inquiry(btcoexist);
+ return;
+ }
+
+ coex_dm->cur_algorithm = algorithm;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Algorithm = %d\n", coex_dm->cur_algorithm);
+
+ if (halbtc8192e2ant_is_common_action(btcoexist)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant common.\n");
+ coex_dm->auto_tdma_adjust = false;
+ } else {
+ if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex] preAlgorithm=%d, curAlgorithm=%d\n",
+ coex_dm->pre_algorithm,
+ coex_dm->cur_algorithm);
+ coex_dm->auto_tdma_adjust = false;
+ }
+ switch (coex_dm->cur_algorithm) {
+ case BT_8192E_2ANT_COEX_ALGO_SCO:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = SCO.\n");
+ halbtc8192e2ant_action_sco(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_SCO_PAN:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = SCO+PAN(EDR).\n");
+ halbtc8192e2ant_action_sco_pan(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = HID.\n");
+ halbtc8192e2ant_action_hid(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = A2DP.\n");
+ halbtc8192e2ant_action_a2dp(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = A2DP+PAN(HS).\n");
+ halbtc8192e2ant_action_a2dp_pan_hs(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = PAN(EDR).\n");
+ halbtc8192e2ant_action_pan_edr(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = HS mode.\n");
+ halbtc8192e2ant_action_pan_hs(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = PAN+A2DP.\n");
+ halbtc8192e2ant_action_pan_edr_a2dp(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_PANEDR_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = PAN(EDR)+HID.\n");
+ halbtc8192e2ant_action_pan_edr_hid(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = HID+A2DP+PAN.\n");
+ btc8192e2ant_action_hid_a2dp_pan_edr(btcoexist);
+ break;
+ case BT_8192E_2ANT_COEX_ALGO_HID_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = HID+A2DP.\n");
+ halbtc8192e2ant_action_hid_a2dp(btcoexist);
+ break;
+ default:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "Action 2-Ant, algorithm = unknown!!\n");
+ /* halbtc8192e2ant_coex_alloff(btcoexist); */
+ break;
+ }
+ coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+ }
+}
+
+static void halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist,
+ bool backup)
+{
+ u16 u16tmp = 0;
+ u8 u8tmp = 0;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], 2Ant Init HW Config!!\n");
+
+ if (backup) {
+ /* backup rf 0x1e value */
+ coex_dm->bt_rf0x1e_backup =
+ btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A,
+ 0x1e, 0xfffff);
+
+ coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist,
+ 0x430);
+ coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist,
+ 0x434);
+ coex_dm->backup_retrylimit = btcoexist->btc_read_2byte(
+ btcoexist,
+ 0x42a);
+ coex_dm->backup_ampdu_maxtime = btcoexist->btc_read_1byte(
+ btcoexist,
+ 0x456);
+ }
+
+ /* antenna sw ctrl to bt */
+ btcoexist->btc_write_1byte(btcoexist, 0x4f, 0x6);
+ btcoexist->btc_write_1byte(btcoexist, 0x944, 0x24);
+ btcoexist->btc_write_4byte(btcoexist, 0x930, 0x700700);
+ btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20);
+ if (btcoexist->chip_interface == BTC_INTF_USB)
+ btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30430004);
+ else
+ btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30030004);
+
+ btc8192e2ant_coex_tbl_w_type(btcoexist, FORCE_EXEC, 0);
+
+ /* antenna switch control parameter */
+ btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555);
+
+ /* coex parameters */
+ btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3);
+ /* 0x790[5:0] = 0x5 */
+ u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+ u8tmp &= 0xc0;
+ u8tmp |= 0x5;
+ btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp);
+
+ /* enable counter statistics */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4);
+
+ /* enable PTA */
+ btcoexist->btc_write_1byte(btcoexist, 0x40, 0x20);
+ /* enable mailbox interface */
+ u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x40);
+ u16tmp |= BIT9;
+ btcoexist->btc_write_2byte(btcoexist, 0x40, u16tmp);
+
+ /* enable PTA I2C mailbox */
+ u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x101);
+ u8tmp |= BIT4;
+ btcoexist->btc_write_1byte(btcoexist, 0x101, u8tmp);
+
+ /* enable bt clock when wifi is disabled. */
+ u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x93);
+ u8tmp |= BIT0;
+ btcoexist->btc_write_1byte(btcoexist, 0x93, u8tmp);
+ /* enable bt clock when suspend. */
+ u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x7);
+ u8tmp |= BIT0;
+ btcoexist->btc_write_1byte(btcoexist, 0x7, u8tmp);
+}
+
+/*************************************************************
+ * work around function start with wa_halbtc8192e2ant_
+ *************************************************************/
+
+/************************************************************
+ * extern function start with EXhalbtc8192e2ant_
+ ************************************************************/
+
+void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+ halbtc8192e2ant_init_hwconfig(btcoexist, true);
+}
+
+void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Coex Mechanism Init!!\n");
+ halbtc8192e2ant_init_coex_dm(btcoexist);
+}
+
+void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0;
+ u16 u16tmp[4];
+ u32 u32tmp[4];
+ bool roam = false, scan = false, link = false, wifi_under_5g = false;
+ bool bt_hson = false, wifi_busy = false;
+ int wifirssi = 0, bt_hs_rssi = 0;
+ u32 wifi_bw, wifi_traffic_dir;
+ u8 wifi_dot11_chnl, wifi_hs_chnl;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ============[BT Coexist info]============");
+
+ if (btcoexist->manual_control) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ===========[Under Manual Control]===========");
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ==========================================");
+ }
+
+ if (!board_info->bt_exist) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!");
+ return;
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:",
+ board_info->pg_ant_num, board_info->btdm_ant_num);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %d",
+ "BT stack/ hci ext ver",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)",
+ "CoexVer/ FwVer/ PatchVer",
+ glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant,
+ fw_ver, bt_patch_ver, bt_patch_ver);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL,
+ &wifi_dot11_chnl);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d(%d)",
+ "Dot11 channel / HsMode(HsChnl)",
+ wifi_dot11_chnl, bt_hson, wifi_hs_chnl);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x ",
+ "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0],
+ coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi);
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+ "Wifi rssi/ HS rssi", wifirssi, bt_hs_rssi);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ",
+ "Wifi link/ roam/ scan", link, roam, scan);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
+ &wifi_traffic_dir);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %s/ %s ",
+ "Wifi status", (wifi_under_5g ? "5G" : "2.4G"),
+ ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+ (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+ ((!wifi_busy) ? "idle" :
+ ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+ "uplink" : "downlink")));
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = [%s/ %d/ %d] ",
+ "BT [status/ rssi/ retryCnt]",
+ ((btcoexist->bt_info.bt_disabled) ? ("disabled") :
+ ((coex_sta->c2h_bt_inquiry_page) ?
+ ("inquiry/page scan") :
+ ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status) ? "non-connected idle" :
+ ((BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status) ? "connected-idle" : "busy")))),
+ coex_sta->bt_rssi, coex_sta->bt_retry_cnt);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d / %d / %d",
+ "SCO/HID/PAN/A2DP", stack_info->sco_exist,
+ stack_info->hid_exist, stack_info->pan_exist,
+ stack_info->a2dp_exist);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO);
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s",
+ "BT Info A2DP rate",
+ (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate");
+
+ for (i = 0; i < BT_INFO_SRC_8192E_2ANT_MAX; i++) {
+ if (coex_sta->bt_info_c2h_cnt[i]) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %02x %02x %02x %02x ",
+ GLBtInfoSrc8192e2Ant[i],
+ coex_sta->bt_info_c2h[i][0],
+ coex_sta->bt_info_c2h[i][1],
+ coex_sta->bt_info_c2h[i][2],
+ coex_sta->bt_info_c2h[i][3]);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "%02x %02x %02x(%d)",
+ coex_sta->bt_info_c2h[i][4],
+ coex_sta->bt_info_c2h[i][5],
+ coex_sta->bt_info_c2h[i][6],
+ coex_sta->bt_info_c2h_cnt[i]);
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/%s",
+ "PS state, IPS/LPS",
+ ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+ ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")));
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", "SS Type",
+ coex_dm->cur_sstype);
+
+ /* Sw mechanism */
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+ "============[Sw mechanism]============");
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ",
+ "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink,
+ coex_dm->cur_low_penalty_ra, coex_dm->limited_dig);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d(0x%x) ",
+ "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]",
+ coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off,
+ coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", "Rate Mask",
+ btcoexist->bt_info.ra_mask);
+
+ /* Fw mechanism */
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+ "============[Fw mechanism]============");
+
+ ps_tdma_case = coex_dm->cur_ps_tdma;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)",
+ "PS TDMA", coex_dm->ps_tdma_para[0],
+ coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2],
+ coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4],
+ ps_tdma_case, coex_dm->auto_tdma_adjust);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ",
+ "DecBtPwr/ IgnWlanAct",
+ coex_dm->cur_dec_bt_pwr, coex_dm->cur_ignore_wlan_act);
+
+ /* Hw setting */
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+ "============[Hw setting]============");
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x",
+ "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+ "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1,
+ coex_dm->backup_arfr_cnt2, coex_dm->backup_retrylimit,
+ coex_dm->backup_ampdu_maxtime);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434);
+ u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+ "0x430/0x434/0x42a/0x456",
+ u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc04);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xd04);
+ u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x90c);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0xc04/ 0xd04/ 0x90c", u32tmp[0], u32tmp[1], u32tmp[2]);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "0x778",
+ u8tmp[0]);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x92c);
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x930);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x92c/ 0x930", (u8tmp[0]), u32tmp[0]);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+ u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x4f);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x40/ 0x4f", u8tmp[0], u8tmp[1]);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "0xc50(dig)",
+ u32tmp[0]);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+ u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
+ "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)",
+ u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+ "0x770(hp rx[31:16]/tx[15:0])",
+ coex_sta->high_priority_rx, coex_sta->high_priority_tx);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+ "0x774(lp rx[31:16]/tx[15:0])",
+ coex_sta->low_priority_rx, coex_sta->low_priority_tx);
+#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 1)
+ halbtc8192e2ant_monitor_bt_ctr(btcoexist);
+#endif
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_IPS_ENTER == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS ENTER notify\n");
+ coex_sta->under_ips = true;
+ halbtc8192e2ant_coex_alloff(btcoexist);
+ } else if (BTC_IPS_LEAVE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS LEAVE notify\n");
+ coex_sta->under_ips = false;
+ }
+}
+
+void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_LPS_ENABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS ENABLE notify\n");
+ coex_sta->under_lps = true;
+ } else if (BTC_LPS_DISABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS DISABLE notify\n");
+ coex_sta->under_lps = false;
+ }
+}
+
+void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_SCAN_START == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN START notify\n");
+ else if (BTC_SCAN_FINISH == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN FINISH notify\n");
+}
+
+void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_ASSOCIATE_START == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT START notify\n");
+ else if (BTC_ASSOCIATE_FINISH == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT FINISH notify\n");
+}
+
+void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ u8 h2c_parameter[3] = {0};
+ u32 wifi_bw;
+ u8 wifi_center_chnl;
+
+ if (btcoexist->manual_control ||
+ btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ if (BTC_MEDIA_CONNECT == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA connect notify\n");
+ else
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA disconnect notify\n");
+
+ /* only 2.4G we need to inform bt the chnl mask */
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL,
+ &wifi_center_chnl);
+ if ((BTC_MEDIA_CONNECT == type) &&
+ (wifi_center_chnl <= 14)) {
+ h2c_parameter[0] = 0x1;
+ h2c_parameter[1] = wifi_center_chnl;
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw)
+ h2c_parameter[2] = 0x30;
+ else
+ h2c_parameter[2] = 0x20;
+ }
+
+ coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+ coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+ coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x66 = 0x%x\n",
+ h2c_parameter[0] << 16 | h2c_parameter[1] << 8 |
+ h2c_parameter[2]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ if (type == BTC_PACKET_DHCP)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], DHCP Packet notify\n");
+}
+
+void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmp_buf, u8 length)
+{
+ u8 bt_info = 0;
+ u8 i, rsp_source = 0;
+ bool bt_busy = false, limited_dig = false;
+ bool wifi_connected = false;
+
+ coex_sta->c2h_bt_info_req_sent = false;
+
+ rsp_source = tmp_buf[0] & 0xf;
+ if (rsp_source >= BT_INFO_SRC_8192E_2ANT_MAX)
+ rsp_source = BT_INFO_SRC_8192E_2ANT_WIFI_FW;
+ coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Bt info[%d], length=%d, hex data = [",
+ rsp_source, length);
+ for (i = 0; i < length; i++) {
+ coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i];
+ if (i == 1)
+ bt_info = tmp_buf[i];
+ if (i == length-1)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x]\n", tmp_buf[i]);
+ else
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x, ", tmp_buf[i]);
+ }
+
+ if (BT_INFO_SRC_8192E_2ANT_WIFI_FW != rsp_source) {
+ coex_sta->bt_retry_cnt = /* [3:0] */
+ coex_sta->bt_info_c2h[rsp_source][2] & 0xf;
+
+ coex_sta->bt_rssi =
+ coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10;
+
+ coex_sta->bt_info_ext =
+ coex_sta->bt_info_c2h[rsp_source][4];
+
+ /* Here we need to resend some wifi info to BT
+ * because bt is reset and loss of the info.
+ */
+ if ((coex_sta->bt_info_ext & BIT1)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "bit1, send wifi BW&Chnl to BT!!\n");
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ if (wifi_connected)
+ ex_halbtc8192e2ant_media_status_notify(
+ btcoexist,
+ BTC_MEDIA_CONNECT);
+ else
+ ex_halbtc8192e2ant_media_status_notify(
+ btcoexist,
+ BTC_MEDIA_DISCONNECT);
+ }
+
+ if ((coex_sta->bt_info_ext & BIT3)) {
+ if (!btcoexist->manual_control &&
+ !btcoexist->stop_coex_dm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "bit3, BT NOT ignore Wlan active!\n");
+ halbtc8192e2ant_IgnoreWlanAct(btcoexist,
+ FORCE_EXEC,
+ false);
+ }
+ } else {
+ /* BT already NOT ignore Wlan active,
+ * do nothing here.
+ */
+ }
+
+#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0)
+ if ((coex_sta->bt_info_ext & BIT4)) {
+ /* BT auto report already enabled, do nothing */
+ } else {
+ halbtc8192e2ant_bt_autoreport(btcoexist, FORCE_EXEC,
+ true);
+ }
+#endif
+ }
+
+ /* check BIT2 first ==> check if bt is under inquiry or page scan */
+ if (bt_info & BT_INFO_8192E_2ANT_B_INQ_PAGE)
+ coex_sta->c2h_bt_inquiry_page = true;
+ else
+ coex_sta->c2h_bt_inquiry_page = false;
+
+ /* set link exist status */
+ if (!(bt_info&BT_INFO_8192E_2ANT_B_CONNECTION)) {
+ coex_sta->bt_link_exist = false;
+ coex_sta->pan_exist = false;
+ coex_sta->a2dp_exist = false;
+ coex_sta->hid_exist = false;
+ coex_sta->sco_exist = false;
+ } else {/* connection exists */
+ coex_sta->bt_link_exist = true;
+ if (bt_info & BT_INFO_8192E_2ANT_B_FTP)
+ coex_sta->pan_exist = true;
+ else
+ coex_sta->pan_exist = false;
+ if (bt_info & BT_INFO_8192E_2ANT_B_A2DP)
+ coex_sta->a2dp_exist = true;
+ else
+ coex_sta->a2dp_exist = false;
+ if (bt_info & BT_INFO_8192E_2ANT_B_HID)
+ coex_sta->hid_exist = true;
+ else
+ coex_sta->hid_exist = false;
+ if (bt_info & BT_INFO_8192E_2ANT_B_SCO_ESCO)
+ coex_sta->sco_exist = true;
+ else
+ coex_sta->sco_exist = false;
+ }
+
+ halbtc8192e2ant_update_btlink_info(btcoexist);
+
+ if (!(bt_info&BT_INFO_8192E_2ANT_B_CONNECTION)) {
+ coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Non-Connected idle!!!\n");
+ } else if (bt_info == BT_INFO_8192E_2ANT_B_CONNECTION) {
+ coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], bt_infoNotify(), BT Connected-idle!!!\n");
+ } else if ((bt_info&BT_INFO_8192E_2ANT_B_SCO_ESCO) ||
+ (bt_info&BT_INFO_8192E_2ANT_B_SCO_BUSY)) {
+ coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_SCO_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], bt_infoNotify(), BT SCO busy!!!\n");
+ } else if (bt_info&BT_INFO_8192E_2ANT_B_ACL_BUSY) {
+ coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_ACL_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], bt_infoNotify(), BT ACL busy!!!\n");
+ } else {
+ coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_MAX;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex]bt_infoNotify(), BT Non-Defined state!!!\n");
+ }
+
+ if ((BT_8192E_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+ (BT_8192E_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) {
+ bt_busy = true;
+ limited_dig = true;
+ } else {
+ bt_busy = false;
+ limited_dig = false;
+ }
+
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+ coex_dm->limited_dig = limited_dig;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig);
+
+ halbtc8192e2ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+}
+
+void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n");
+
+ halbtc8192e2ant_IgnoreWlanAct(btcoexist, FORCE_EXEC, true);
+ ex_halbtc8192e2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist)
+{
+ static u8 dis_ver_info_cnt;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "=======================Periodical=======================\n");
+ if (dis_ver_info_cnt <= 5) {
+ dis_ver_info_cnt += 1;
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "************************************************\n");
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n",
+ board_info->pg_ant_num, board_info->btdm_ant_num,
+ board_info->btdm_ant_pos);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "BT stack/ hci ext ver = %s / %d\n",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+ &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
+ glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant,
+ fw_ver, bt_patch_ver, bt_patch_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "************************************************\n");
+ }
+
+#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0)
+ halbtc8192e2ant_querybt_info(btcoexist);
+ halbtc8192e2ant_monitor_bt_ctr(btcoexist);
+ btc8192e2ant_monitor_bt_enable_dis(btcoexist);
+#else
+ if (halbtc8192e2ant_iswifi_status_changed(btcoexist) ||
+ coex_dm->auto_tdma_adjust)
+ halbtc8192e2ant_run_coexist_mechanism(btcoexist);
+#endif
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h
new file mode 100644
index 00000000000..75e1f7d0db0
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h
@@ -0,0 +1,185 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+/*****************************************************************
+ * The following is for 8192E 2Ant BT Co-exist definition
+ *****************************************************************/
+#define BT_AUTO_REPORT_ONLY_8192E_2ANT 0
+
+#define BT_INFO_8192E_2ANT_B_FTP BIT7
+#define BT_INFO_8192E_2ANT_B_A2DP BIT6
+#define BT_INFO_8192E_2ANT_B_HID BIT5
+#define BT_INFO_8192E_2ANT_B_SCO_BUSY BIT4
+#define BT_INFO_8192E_2ANT_B_ACL_BUSY BIT3
+#define BT_INFO_8192E_2ANT_B_INQ_PAGE BIT2
+#define BT_INFO_8192E_2ANT_B_SCO_ESCO BIT1
+#define BT_INFO_8192E_2ANT_B_CONNECTION BIT0
+
+#define BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT 2
+
+enum bt_info_src_8192e_2ant {
+ BT_INFO_SRC_8192E_2ANT_WIFI_FW = 0x0,
+ BT_INFO_SRC_8192E_2ANT_BT_RSP = 0x1,
+ BT_INFO_SRC_8192E_2ANT_BT_ACTIVE_SEND = 0x2,
+ BT_INFO_SRC_8192E_2ANT_MAX
+};
+
+enum bt_8192e_2ant_bt_status {
+ BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0,
+ BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1,
+ BT_8192E_2ANT_BT_STATUS_INQ_PAGE = 0x2,
+ BT_8192E_2ANT_BT_STATUS_ACL_BUSY = 0x3,
+ BT_8192E_2ANT_BT_STATUS_SCO_BUSY = 0x4,
+ BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5,
+ BT_8192E_2ANT_BT_STATUS_MAX
+};
+
+enum bt_8192e_2ant_coex_algo {
+ BT_8192E_2ANT_COEX_ALGO_UNDEFINED = 0x0,
+ BT_8192E_2ANT_COEX_ALGO_SCO = 0x1,
+ BT_8192E_2ANT_COEX_ALGO_SCO_PAN = 0x2,
+ BT_8192E_2ANT_COEX_ALGO_HID = 0x3,
+ BT_8192E_2ANT_COEX_ALGO_A2DP = 0x4,
+ BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS = 0x5,
+ BT_8192E_2ANT_COEX_ALGO_PANEDR = 0x6,
+ BT_8192E_2ANT_COEX_ALGO_PANHS = 0x7,
+ BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP = 0x8,
+ BT_8192E_2ANT_COEX_ALGO_PANEDR_HID = 0x9,
+ BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0xa,
+ BT_8192E_2ANT_COEX_ALGO_HID_A2DP = 0xb,
+ BT_8192E_2ANT_COEX_ALGO_MAX = 0xc
+};
+
+struct coex_dm_8192e_2ant {
+ /* fw mechanism */
+ u8 pre_dec_bt_pwr;
+ u8 cur_dec_bt_pwr;
+ u8 pre_fw_dac_swing_lvl;
+ u8 cur_fw_dac_swing_lvl;
+ bool cur_ignore_wlan_act;
+ bool pre_ignore_wlan_act;
+ u8 pre_ps_tdma;
+ u8 cur_ps_tdma;
+ u8 ps_tdma_para[5];
+ u8 tdma_adj_type;
+ bool reset_tdma_adjust;
+ bool auto_tdma_adjust;
+ bool pre_ps_tdma_on;
+ bool cur_ps_tdma_on;
+ bool pre_bt_auto_report;
+ bool cur_bt_auto_report;
+
+ /* sw mechanism */
+ bool pre_rf_rx_lpf_shrink;
+ bool cur_rf_rx_lpf_shrink;
+ u32 bt_rf0x1e_backup;
+ bool pre_low_penalty_ra;
+ bool cur_low_penalty_ra;
+ bool pre_dac_swing_on;
+ u32 pre_dac_swing_lvl;
+ bool cur_dac_swing_on;
+ u32 cur_dac_swing_lvl;
+ bool pre_adc_back_off;
+ bool cur_adc_back_off;
+ bool pre_agc_table_en;
+ bool cur_agc_table_en;
+ u32 pre_val0x6c0;
+ u32 cur_val0x6c0;
+ u32 pre_val0x6c4;
+ u32 cur_val0x6c4;
+ u32 pre_val0x6c8;
+ u32 cur_val0x6c8;
+ u8 pre_val0x6cc;
+ u8 cur_val0x6cc;
+ bool limited_dig;
+
+ u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */
+ u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */
+ u16 backup_retrylimit;
+ u8 backup_ampdu_maxtime;
+
+ /* algorithm related */
+ u8 pre_algorithm;
+ u8 cur_algorithm;
+ u8 bt_status;
+ u8 wifi_chnl_info[3];
+
+ u8 pre_sstype;
+ u8 cur_sstype;
+
+ u32 prera_mask;
+ u32 curra_mask;
+ u8 curra_masktype;
+ u8 pre_arfrtype;
+ u8 cur_arfrtype;
+ u8 pre_retrylimit_type;
+ u8 cur_retrylimit_type;
+ u8 pre_ampdutime_type;
+ u8 cur_ampdutime_type;
+};
+
+struct coex_sta_8192e_2ant {
+ bool bt_link_exist;
+ bool sco_exist;
+ bool a2dp_exist;
+ bool hid_exist;
+ bool pan_exist;
+
+ bool under_lps;
+ bool under_ips;
+ u32 high_priority_tx;
+ u32 high_priority_rx;
+ u32 low_priority_tx;
+ u32 low_priority_rx;
+ u8 bt_rssi;
+ u8 pre_bt_rssi_state;
+ u8 pre_wifi_rssi_state[4];
+ bool c2h_bt_info_req_sent;
+ u8 bt_info_c2h[BT_INFO_SRC_8192E_2ANT_MAX][10];
+ u32 bt_info_c2h_cnt[BT_INFO_SRC_8192E_2ANT_MAX];
+ bool c2h_bt_inquiry_page;
+ u8 bt_retry_cnt;
+ u8 bt_info_ext;
+};
+
+/****************************************************************
+ * The following is interface which will notify coex module.
+ ****************************************************************/
+void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmpbuf, u8 length);
+void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist);
+void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c
new file mode 100644
index 00000000000..c4acd403e5f
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c
@@ -0,0 +1,3170 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/***************************************************************
+ * Description:
+ *
+ * This file is for RTL8723B Co-exist mechanism
+ *
+ * History
+ * 2012/11/15 Cosa first check in.
+ *
+ ***************************************************************/
+
+/***************************************************************
+ * include files
+ ***************************************************************/
+#include "halbt_precomp.h"
+/***************************************************************
+ * Global variables, these are static variables
+ ***************************************************************/
+static struct coex_dm_8723b_1ant glcoex_dm_8723b_1ant;
+static struct coex_dm_8723b_1ant *coex_dm = &glcoex_dm_8723b_1ant;
+static struct coex_sta_8723b_1ant glcoex_sta_8723b_1ant;
+static struct coex_sta_8723b_1ant *coex_sta = &glcoex_sta_8723b_1ant;
+
+static const char *const GLBtInfoSrc8723b1Ant[] = {
+ "BT Info[wifi fw]",
+ "BT Info[bt rsp]",
+ "BT Info[bt auto report]",
+};
+
+static u32 glcoex_ver_date_8723b_1ant = 20130918;
+static u32 glcoex_ver_8723b_1ant = 0x47;
+
+/***************************************************************
+ * local function proto type if needed
+ ***************************************************************/
+/***************************************************************
+ * local function start with halbtc8723b1ant_
+ ***************************************************************/
+static u8 halbtc8723b1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh,
+ u8 rssi_thresh1)
+{
+ s32 bt_rssi = 0;
+ u8 bt_rssi_state = coex_sta->pre_bt_rssi_state;
+
+ bt_rssi = coex_sta->bt_rssi;
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ if (bt_rssi >= rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to High\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Low\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi thresh error!!\n");
+ return coex_sta->pre_bt_rssi_state;
+ }
+
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ if (bt_rssi >= rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (bt_rssi >= rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to High\n");
+ } else if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Medium\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh1) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at High\n");
+ }
+ }
+ }
+
+ coex_sta->pre_bt_rssi_state = bt_rssi_state;
+
+ return bt_rssi_state;
+}
+
+static u8 halbtc8723b1ant_wifi_rssi_state(struct btc_coexist *btcoexist,
+ u8 index, u8 level_num,
+ u8 rssi_thresh, u8 rssi_thresh1)
+{
+ s32 wifi_rssi = 0;
+ u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >= rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to High\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Low\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI thresh error!!\n");
+ return coex_sta->pre_wifi_rssi_state[index];
+ }
+
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >= rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (wifi_rssi >= rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to High\n");
+ } else if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Medium\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh1) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at High\n");
+ }
+ }
+ }
+
+ coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state;
+
+ return wifi_rssi_state;
+}
+
+static void halbtc8723b1ant_updatera_mask(struct btc_coexist *btcoexist,
+ bool force_exec, u32 dis_rate_mask)
+{
+ coex_dm->curra_mask = dis_rate_mask;
+
+ if (force_exec || (coex_dm->prera_mask != coex_dm->curra_mask))
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask,
+ &coex_dm->curra_mask);
+
+ coex_dm->prera_mask = coex_dm->curra_mask;
+}
+
+static void btc8723b1ant_auto_rate_fb_retry(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ bool wifi_under_bmode = false;
+
+ coex_dm->cur_arfr_type = type;
+
+ if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) {
+ switch (coex_dm->cur_arfr_type) {
+ case 0: /* normal mode */
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ coex_dm->backup_arfr_cnt1);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ coex_dm->backup_arfr_cnt2);
+ break;
+ case 1:
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_UNDER_B_MODE,
+ &wifi_under_bmode);
+ if (wifi_under_bmode) {
+ btcoexist->btc_write_4byte(btcoexist,
+ 0x430, 0x0);
+ btcoexist->btc_write_4byte(btcoexist,
+ 0x434, 0x01010101);
+ } else {
+ btcoexist->btc_write_4byte(btcoexist,
+ 0x430, 0x0);
+ btcoexist->btc_write_4byte(btcoexist,
+ 0x434, 0x04030201);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_arfr_type = coex_dm->cur_arfr_type;
+}
+
+static void halbtc8723b1ant_retry_limit(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ coex_dm->cur_retry_limit_type = type;
+
+ if (force_exec || (coex_dm->pre_retry_limit_type !=
+ coex_dm->cur_retry_limit_type)) {
+ switch (coex_dm->cur_retry_limit_type) {
+ case 0: /* normal mode */
+ btcoexist->btc_write_2byte(btcoexist, 0x42a,
+ coex_dm->backup_retry_limit);
+ break;
+ case 1: /* retry limit = 8 */
+ btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808);
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type;
+}
+
+static void halbtc8723b1ant_ampdu_maxtime(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ coex_dm->cur_ampdu_time_type = type;
+
+ if (force_exec || (coex_dm->pre_ampdu_time_type !=
+ coex_dm->cur_ampdu_time_type)) {
+ switch (coex_dm->cur_ampdu_time_type) {
+ case 0: /* normal mode */
+ btcoexist->btc_write_1byte(btcoexist, 0x456,
+ coex_dm->backup_ampdu_max_time);
+ break;
+ case 1: /* AMPDU timw = 0x38 * 32us */
+ btcoexist->btc_write_1byte(btcoexist,
+ 0x456, 0x38);
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type;
+}
+
+static void halbtc8723b1ant_limited_tx(struct btc_coexist *btcoexist,
+ bool force_exec, u8 ra_masktype,
+ u8 arfr_type, u8 retry_limit_type,
+ u8 ampdu_time_type)
+{
+ switch (ra_masktype) {
+ case 0: /* normal mode */
+ halbtc8723b1ant_updatera_mask(btcoexist, force_exec, 0x0);
+ break;
+ case 1: /* disable cck 1/2 */
+ halbtc8723b1ant_updatera_mask(btcoexist, force_exec,
+ 0x00000003);
+ break;
+ /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4*/
+ case 2:
+ halbtc8723b1ant_updatera_mask(btcoexist, force_exec,
+ 0x0001f1f7);
+ break;
+ default:
+ break;
+ }
+
+ btc8723b1ant_auto_rate_fb_retry(btcoexist, force_exec, arfr_type);
+ halbtc8723b1ant_retry_limit(btcoexist, force_exec, retry_limit_type);
+ halbtc8723b1ant_ampdu_maxtime(btcoexist, force_exec, ampdu_time_type);
+}
+
+static void halbtc8723b1ant_limited_rx(struct btc_coexist *btcoexist,
+ bool force_exec, bool rej_ap_agg_pkt,
+ bool bt_ctrl_agg_buf_size,
+ u8 agg_buf_size)
+{
+ bool reject_rx_agg = rej_ap_agg_pkt;
+ bool bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size;
+ u8 rxaggsize = agg_buf_size;
+
+ /**********************************************
+ * Rx Aggregation related setting
+ **********************************************/
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT,
+ &reject_rx_agg);
+ /* decide BT control aggregation buf size or not */
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE,
+ &bt_ctrl_rx_agg_size);
+ /* aggregation buf size, only work
+ * when BT control Rx aggregation size.
+ */
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rxaggsize);
+ /* real update aggregation setting */
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL);
+}
+
+static void halbtc8723b1ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+ u32 reg_hp_txrx, reg_lp_txrx, u32tmp;
+ u32 reg_hp_tx = 0, reg_hp_rx = 0;
+ u32 reg_lp_tx = 0, reg_lp_rx = 0;
+
+ reg_hp_txrx = 0x770;
+ reg_lp_txrx = 0x774;
+
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx);
+ reg_hp_tx = u32tmp & MASKLWORD;
+ reg_hp_rx = (u32tmp & MASKHWORD) >> 16;
+
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx);
+ reg_lp_tx = u32tmp & MASKLWORD;
+ reg_lp_rx = (u32tmp & MASKHWORD) >> 16;
+
+ coex_sta->high_priority_tx = reg_hp_tx;
+ coex_sta->high_priority_rx = reg_hp_rx;
+ coex_sta->low_priority_tx = reg_lp_tx;
+ coex_sta->low_priority_rx = reg_lp_rx;
+
+ /* reset counter */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static void halbtc8723b1ant_query_bt_info(struct btc_coexist *btcoexist)
+{
+ u8 h2c_parameter[1] = {0};
+
+ coex_sta->c2h_bt_info_req_sent = true;
+
+ h2c_parameter[0] |= BIT0; /* trigger*/
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
+static bool btc8723b1ant_is_wifi_status_changed(struct btc_coexist *btcoexist)
+{
+ static bool pre_wifi_busy;
+ static bool pre_under_4way, pre_bt_hs_on;
+ bool wifi_busy = false, under_4way = false, bt_hs_on = false;
+ bool wifi_connected = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS,
+ &under_4way);
+
+ if (wifi_connected) {
+ if (wifi_busy != pre_wifi_busy) {
+ pre_wifi_busy = wifi_busy;
+ return true;
+ }
+ if (under_4way != pre_under_4way) {
+ pre_under_4way = under_4way;
+ return true;
+ }
+ if (bt_hs_on != pre_bt_hs_on) {
+ pre_bt_hs_on = bt_hs_on;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void halbtc8723b1ant_update_bt_link_info(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool bt_hs_on = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ bt_link_info->bt_link_exist = coex_sta->bt_link_exist;
+ bt_link_info->sco_exist = coex_sta->sco_exist;
+ bt_link_info->a2dp_exist = coex_sta->a2dp_exist;
+ bt_link_info->pan_exist = coex_sta->pan_exist;
+ bt_link_info->hid_exist = coex_sta->hid_exist;
+
+ /* work around for HS mode. */
+ if (bt_hs_on) {
+ bt_link_info->pan_exist = true;
+ bt_link_info->bt_link_exist = true;
+ }
+
+ /* check if Sco only */
+ if (bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist && !bt_link_info->hid_exist)
+ bt_link_info->sco_only = true;
+ else
+ bt_link_info->sco_only = false;
+
+ /* check if A2dp only */
+ if (!bt_link_info->sco_exist && bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist && !bt_link_info->hid_exist)
+ bt_link_info->a2dp_only = true;
+ else
+ bt_link_info->a2dp_only = false;
+
+ /* check if Pan only */
+ if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+ bt_link_info->pan_exist && !bt_link_info->hid_exist)
+ bt_link_info->pan_only = true;
+ else
+ bt_link_info->pan_only = false;
+
+ /* check if Hid only */
+ if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist && bt_link_info->hid_exist)
+ bt_link_info->hid_only = true;
+ else
+ bt_link_info->hid_only = false;
+}
+
+static u8 halbtc8723b1ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool bt_hs_on = false;
+ u8 algorithm = BT_8723B_1ANT_COEX_ALGO_UNDEFINED;
+ u8 numdiffprofile = 0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ if (!bt_link_info->bt_link_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], No BT link exists!!!\n");
+ return algorithm;
+ }
+
+ if (bt_link_info->sco_exist)
+ numdiffprofile++;
+ if (bt_link_info->hid_exist)
+ numdiffprofile++;
+ if (bt_link_info->pan_exist)
+ numdiffprofile++;
+ if (bt_link_info->a2dp_exist)
+ numdiffprofile++;
+
+ if (numdiffprofile == 1) {
+ if (bt_link_info->sco_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO only\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
+ } else {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID only\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = A2DP only\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_A2DP;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = PAN(HS) only\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = PAN(EDR) only\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR;
+ }
+ }
+ }
+ } else if (numdiffprofile == 2) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + PAN(HS)\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + PAN(EDR)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + A2DP\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + PAN(HS)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + PAN(EDR)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = A2DP + PAN(HS)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = A2DP + PAN(EDR)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP;
+ }
+ }
+ }
+ } else if (numdiffprofile == 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n");
+ algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR;
+ }
+ }
+ }
+ } else if (numdiffprofile >= 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n");
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n");
+ algorithm =
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ }
+ }
+
+ return algorithm;
+}
+
+static void btc8723b1ant_set_sw_pen_tx_rate_adapt(struct btc_coexist *btcoexist,
+ bool low_penalty_ra)
+{
+ u8 h2c_parameter[6] = {0};
+
+ h2c_parameter[0] = 0x6; /* opCode, 0x6= Retry_Penalty */
+
+ if (low_penalty_ra) {
+ h2c_parameter[1] |= BIT0;
+ /*normal rate except MCS7/6/5, OFDM54/48/36 */
+ h2c_parameter[2] = 0x00;
+ h2c_parameter[3] = 0xf7; /*MCS7 or OFDM54 */
+ h2c_parameter[4] = 0xf8; /*MCS6 or OFDM48 */
+ h2c_parameter[5] = 0xf9; /*MCS5 or OFDM36 */
+ }
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set WiFi Low-Penalty Retry: %s",
+ (low_penalty_ra ? "ON!!" : "OFF!!"));
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter);
+}
+
+static void halbtc8723b1ant_low_penalty_ra(struct btc_coexist *btcoexist,
+ bool force_exec, bool low_penalty_ra)
+{
+ coex_dm->cur_low_penalty_ra = low_penalty_ra;
+
+ if (!force_exec) {
+ if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra)
+ return;
+ }
+ btc8723b1ant_set_sw_pen_tx_rate_adapt(btcoexist,
+ coex_dm->cur_low_penalty_ra);
+
+ coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra;
+}
+
+static void halbtc8723b1ant_set_coex_table(struct btc_coexist *btcoexist,
+ u32 val0x6c0, u32 val0x6c4,
+ u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc);
+ btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void halbtc8723b1ant_coex_table(struct btc_coexist *btcoexist,
+ bool force_exec, u32 val0x6c0,
+ u32 val0x6c4, u32 val0x6c8,
+ u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6cc = 0x%x\n",
+ (force_exec ? "force to" : ""),
+ val0x6c0, val0x6c4, val0x6cc);
+ coex_dm->cur_val0x6c0 = val0x6c0;
+ coex_dm->cur_val0x6c4 = val0x6c4;
+ coex_dm->cur_val0x6c8 = val0x6c8;
+ coex_dm->cur_val0x6cc = val0x6cc;
+
+ if (!force_exec) {
+ if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) &&
+ (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) &&
+ (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) &&
+ (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc))
+ return;
+ }
+ halbtc8723b1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4,
+ val0x6c8, val0x6cc);
+
+ coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0;
+ coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4;
+ coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8;
+ coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc;
+}
+
+static void halbtc8723b1ant_coex_table_with_type(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ switch (type) {
+ case 0:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x55555555, 0xffffff, 0x3);
+ break;
+ case 1:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x5a5a5a5a, 0xffffff, 0x3);
+ break;
+ case 2:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+ 0x5a5a5a5a, 0xffffff, 0x3);
+ break;
+ case 3:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0xaaaaaaaa, 0xffffff, 0x3);
+ break;
+ case 4:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x5aaa5aaa, 0xffffff, 0x3);
+ break;
+ case 5:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+ 0xaaaa5a5a, 0xffffff, 0x3);
+ break;
+ case 6:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0xaaaa5a5a, 0xffffff, 0x3);
+ break;
+ case 7:
+ halbtc8723b1ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa,
+ 0xaaaaaaaa, 0xffffff, 0x3);
+ break;
+ default:
+ break;
+ }
+}
+
+static void halbtc8723b1ant_SetFwIgnoreWlanAct(struct btc_coexist *btcoexist,
+ bool enable)
+{
+ u8 h2c_parameter[1] = {0};
+
+ if (enable)
+ h2c_parameter[0] |= BIT0; /* function enable */
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter);
+}
+
+static void halbtc8723b1ant_ignore_wlan_act(struct btc_coexist *btcoexist,
+ bool force_exec, bool enable)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn Ignore WlanAct %s\n",
+ (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+ coex_dm->cur_ignore_wlan_act = enable;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n",
+ coex_dm->pre_ignore_wlan_act,
+ coex_dm->cur_ignore_wlan_act);
+
+ if (coex_dm->pre_ignore_wlan_act ==
+ coex_dm->cur_ignore_wlan_act)
+ return;
+ }
+ halbtc8723b1ant_SetFwIgnoreWlanAct(btcoexist, enable);
+
+ coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void halbtc8723b1ant_set_fw_ps_tdma(struct btc_coexist *btcoexist,
+ u8 byte1, u8 byte2, u8 byte3,
+ u8 byte4, u8 byte5)
+{
+ u8 h2c_parameter[5] = {0};
+ u8 real_byte1 = byte1, real_byte5 = byte5;
+ bool ap_enable = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+ &ap_enable);
+
+ if (ap_enable) {
+ if ((byte1 & BIT4) && !(byte1 & BIT5)) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], FW for 1Ant AP mode\n");
+ real_byte1 &= ~BIT4;
+ real_byte1 |= BIT5;
+
+ real_byte5 |= BIT5;
+ real_byte5 &= ~BIT6;
+ }
+ }
+
+ h2c_parameter[0] = real_byte1;
+ h2c_parameter[1] = byte2;
+ h2c_parameter[2] = byte3;
+ h2c_parameter[3] = byte4;
+ h2c_parameter[4] = real_byte5;
+
+ coex_dm->ps_tdma_para[0] = real_byte1;
+ coex_dm->ps_tdma_para[1] = byte2;
+ coex_dm->ps_tdma_para[2] = byte3;
+ coex_dm->ps_tdma_para[3] = byte4;
+ coex_dm->ps_tdma_para[4] = real_byte5;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], PS-TDMA H2C cmd =0x%x%08x\n",
+ h2c_parameter[0],
+ h2c_parameter[1] << 24 |
+ h2c_parameter[2] << 16 |
+ h2c_parameter[3] << 8 |
+ h2c_parameter[4]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void halbtc8723b1ant_set_lps_rpwm(struct btc_coexist *btcoexist,
+ u8 lps_val, u8 rpwm_val)
+{
+ u8 lps = lps_val;
+ u8 rpwm = rpwm_val;
+
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps);
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm);
+}
+
+static void halbtc8723b1ant_LpsRpwm(struct btc_coexist *btcoexist,
+ bool force_exec,
+ u8 lps_val, u8 rpwm_val)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s set lps/rpwm = 0x%x/0x%x\n",
+ (force_exec ? "force to" : ""), lps_val, rpwm_val);
+ coex_dm->cur_lps = lps_val;
+ coex_dm->cur_rpwm = rpwm_val;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], LPS-RxBeaconMode = 0x%x , LPS-RPWM = 0x%x!!\n",
+ coex_dm->cur_lps, coex_dm->cur_rpwm);
+
+ if ((coex_dm->pre_lps == coex_dm->cur_lps) &&
+ (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], LPS-RPWM_Last = 0x%x , LPS-RPWM_Now = 0x%x!!\n",
+ coex_dm->pre_rpwm, coex_dm->cur_rpwm);
+
+ return;
+ }
+ }
+ halbtc8723b1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val);
+
+ coex_dm->pre_lps = coex_dm->cur_lps;
+ coex_dm->pre_rpwm = coex_dm->cur_rpwm;
+}
+
+static void halbtc8723b1ant_sw_mechanism(struct btc_coexist *btcoexist,
+ bool low_penalty_ra)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], SM[LpRA] = %d\n", low_penalty_ra);
+
+ halbtc8723b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra);
+}
+
+static void halbtc8723b1ant_SetAntPath(struct btc_coexist *btcoexist,
+ u8 ant_pos_type, bool init_hw_cfg,
+ bool wifi_off)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ u32 fw_ver = 0, u32tmp = 0;
+ bool pg_ext_switch = false;
+ bool use_ext_switch = false;
+ u8 h2c_parameter[2] = {0};
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch);
+ /* [31:16] = fw ver, [15:0] = fw sub ver */
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+
+ if ((fw_ver < 0xc0000) || pg_ext_switch)
+ use_ext_switch = true;
+
+ if (init_hw_cfg) {
+ /*BT select s0/s1 is controlled by WiFi */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1);
+
+ /*Force GNT_BT to Normal */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0);
+ } else if (wifi_off) {
+ /*Force GNT_BT to High */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3);
+ /*BT select s0/s1 is controlled by BT */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0);
+
+ /* 0x4c[24:23] = 00, Set Antenna control by BT_RFE_CTRL
+ * BT Vendor 0xac = 0xf002
+ */
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u32tmp &= ~BIT23;
+ u32tmp &= ~BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+ }
+
+ if (use_ext_switch) {
+ if (init_hw_cfg) {
+ /* 0x4c[23] = 0, 0x4c[24] = 1
+ * Antenna control by WL/BT
+ */
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u32tmp &= ~BIT23;
+ u32tmp |= BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT) {
+ /* Main Ant to BT for IPS case 0x4c[23] = 1 */
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x64, 0x1,
+ 0x1);
+
+ /*tell firmware "no antenna inverse"*/
+ h2c_parameter[0] = 0;
+ h2c_parameter[1] = 1; /*ext switch type*/
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ } else {
+ /*Aux Ant to BT for IPS case 0x4c[23] = 1 */
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x64, 0x1,
+ 0x0);
+
+ /*tell firmware "antenna inverse"*/
+ h2c_parameter[0] = 1;
+ h2c_parameter[1] = 1; /*ext switch type*/
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ }
+ }
+
+ /* fixed internal switch first*/
+ /* fixed internal switch S1->WiFi, S0->BT*/
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+ else/* fixed internal switch S0->WiFi, S1->BT*/
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
+
+ /* ext switch setting */
+ switch (ant_pos_type) {
+ case BTC_ANT_PATH_WIFI:
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3,
+ 0x1);
+ else
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3,
+ 0x2);
+ break;
+ case BTC_ANT_PATH_BT:
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3,
+ 0x2);
+ else
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3,
+ 0x1);
+ break;
+ default:
+ case BTC_ANT_PATH_PTA:
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3,
+ 0x1);
+ else
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3,
+ 0x2);
+ break;
+ }
+
+ } else {
+ if (init_hw_cfg) {
+ /* 0x4c[23] = 1, 0x4c[24] = 0 Antenna control by 0x64*/
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u32tmp |= BIT23;
+ u32tmp &= ~BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT) {
+ /*Main Ant to WiFi for IPS case 0x4c[23] = 1*/
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x64, 0x1,
+ 0x0);
+
+ /*tell firmware "no antenna inverse"*/
+ h2c_parameter[0] = 0;
+ h2c_parameter[1] = 0; /*internal switch type*/
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ } else {
+ /*Aux Ant to BT for IPS case 0x4c[23] = 1*/
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x64, 0x1,
+ 0x1);
+
+ /*tell firmware "antenna inverse"*/
+ h2c_parameter[0] = 1;
+ h2c_parameter[1] = 0; /*internal switch type*/
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ }
+ }
+
+ /* fixed external switch first*/
+ /*Main->WiFi, Aux->BT*/
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
+ 0x3, 0x1);
+ else/*Main->BT, Aux->WiFi */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
+ 0x3, 0x2);
+
+ /* internal switch setting*/
+ switch (ant_pos_type) {
+ case BTC_ANT_PATH_WIFI:
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_2byte(btcoexist, 0x948,
+ 0x0);
+ else
+ btcoexist->btc_write_2byte(btcoexist, 0x948,
+ 0x280);
+ break;
+ case BTC_ANT_PATH_BT:
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_2byte(btcoexist, 0x948,
+ 0x280);
+ else
+ btcoexist->btc_write_2byte(btcoexist, 0x948,
+ 0x0);
+ break;
+ default:
+ case BTC_ANT_PATH_PTA:
+ if (board_info->btdm_ant_pos ==
+ BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_2byte(btcoexist, 0x948,
+ 0x200);
+ else
+ btcoexist->btc_write_2byte(btcoexist, 0x948,
+ 0x80);
+ break;
+ }
+ }
+}
+
+static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist,
+ bool force_exec, bool turn_on, u8 type)
+{
+ bool wifi_busy = false;
+ u8 rssi_adjust_val = 0;
+
+ coex_dm->cur_ps_tdma_on = turn_on;
+ coex_dm->cur_ps_tdma = type;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+ if (!force_exec) {
+ if (coex_dm->cur_ps_tdma_on)
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], ******** TDMA(on, %d) *********\n",
+ coex_dm->cur_ps_tdma);
+ else
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], ******** TDMA(off, %d) ********\n",
+ coex_dm->cur_ps_tdma);
+
+ if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+ (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+ return;
+ }
+ if (turn_on) {
+ switch (type) {
+ default:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1a,
+ 0x1a, 0x0, 0x50);
+ break;
+ case 1:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x3a,
+ 0x03, 0x10, 0x50);
+
+ rssi_adjust_val = 11;
+ break;
+ case 2:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x2b,
+ 0x03, 0x10, 0x50);
+ rssi_adjust_val = 14;
+ break;
+ case 3:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1d,
+ 0x1d, 0x0, 0x52);
+ break;
+ case 4:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15,
+ 0x3, 0x14, 0x0);
+ rssi_adjust_val = 17;
+ break;
+ case 5:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x15,
+ 0x3, 0x11, 0x10);
+ break;
+ case 6:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x20,
+ 0x3, 0x11, 0x13);
+ break;
+ case 7:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xc,
+ 0x5, 0x0, 0x0);
+ break;
+ case 8:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25,
+ 0x3, 0x10, 0x0);
+ break;
+ case 9:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21,
+ 0x3, 0x10, 0x50);
+ rssi_adjust_val = 18;
+ break;
+ case 10:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa,
+ 0xa, 0x0, 0x40);
+ break;
+ case 11:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15,
+ 0x03, 0x10, 0x50);
+ rssi_adjust_val = 20;
+ break;
+ case 12:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x0a,
+ 0x0a, 0x0, 0x50);
+ break;
+ case 13:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15,
+ 0x15, 0x0, 0x50);
+ break;
+ case 14:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21,
+ 0x3, 0x10, 0x52);
+ break;
+ case 15:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa,
+ 0x3, 0x8, 0x0);
+ break;
+ case 16:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15,
+ 0x3, 0x10, 0x0);
+ rssi_adjust_val = 18;
+ break;
+ case 18:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25,
+ 0x3, 0x10, 0x0);
+ rssi_adjust_val = 14;
+ break;
+ case 20:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x35,
+ 0x03, 0x11, 0x10);
+ break;
+ case 21:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25,
+ 0x03, 0x11, 0x11);
+ break;
+ case 22:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25,
+ 0x03, 0x11, 0x10);
+ break;
+ case 23:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 24:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 25:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 26:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 27:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25,
+ 0x3, 0x31, 0x98);
+ rssi_adjust_val = 22;
+ break;
+ case 28:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x69, 0x25,
+ 0x3, 0x31, 0x0);
+ break;
+ case 29:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xab, 0x1a,
+ 0x1a, 0x1, 0x10);
+ break;
+ case 30:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x14,
+ 0x3, 0x10, 0x50);
+ break;
+ case 31:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x1a,
+ 0x1a, 0, 0x58);
+ break;
+ case 32:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0xa,
+ 0x3, 0x10, 0x0);
+ break;
+ case 33:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x25,
+ 0x3, 0x30, 0x90);
+ break;
+ case 34:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x53, 0x1a,
+ 0x1a, 0x0, 0x10);
+ break;
+ case 35:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x63, 0x1a,
+ 0x1a, 0x0, 0x10);
+ break;
+ case 36:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x12,
+ 0x3, 0x14, 0x50);
+ break;
+ /* SoftAP only with no sta associated,BT disable ,
+ * TDMA mode for power saving
+ * here softap mode screen off will cost 70-80mA for phone
+ */
+ case 40:
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x23, 0x18,
+ 0x00, 0x10, 0x24);
+ break;
+ }
+ } else {
+ switch (type) {
+ case 8: /*PTA Control */
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x8, 0x0,
+ 0x0, 0x0, 0x0);
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_PTA,
+ false, false);
+ break;
+ case 0:
+ default: /*Software control, Antenna at BT side */
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0,
+ 0x0, 0x0, 0x0);
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT,
+ false, false);
+ break;
+ case 9: /*Software control, Antenna at WiFi side */
+ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0,
+ 0x0, 0x0, 0x0);
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_WIFI,
+ false, false);
+ break;
+ }
+ }
+ rssi_adjust_val = 0;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE,
+ &rssi_adjust_val);
+
+ /* update pre state */
+ coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+ coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static bool halbtc8723b1ant_is_common_action(struct btc_coexist *btcoexist)
+{
+ bool commom = false, wifi_connected = false;
+ bool wifi_busy = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+ if (!wifi_connected &&
+ BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n");
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+ commom = true;
+ } else if (wifi_connected &&
+ (BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi connected + BT non connected-idle!!\n");
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+ commom = true;
+ } else if (!wifi_connected &&
+ (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n");
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+ commom = true;
+ } else if (wifi_connected &&
+ (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi connected + BT connected-idle!!\n");
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+ commom = true;
+ } else if (!wifi_connected &&
+ (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE !=
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ ("[BTCoex], Wifi non connected-idle + BT Busy!!\n"));
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+ commom = true;
+ } else {
+ if (wifi_busy)
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Connected-Busy + BT Busy!!\n");
+ else
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Connected-Idle + BT Busy!!\n");
+
+ commom = false;
+ }
+
+ return commom;
+}
+
+static void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist,
+ u8 wifi_status)
+{
+ static s32 up, dn, m, n, wait_count;
+ /* 0: no change, +1: increase WiFi duration,
+ * -1: decrease WiFi duration
+ */
+ s32 result;
+ u8 retry_count = 0, bt_info_ext;
+ bool wifi_busy = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], TdmaDurationAdjustForAcl()\n");
+
+ if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY == wifi_status)
+ wifi_busy = true;
+ else
+ wifi_busy = false;
+
+ if ((BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN ==
+ wifi_status) ||
+ (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifi_status) ||
+ (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifi_status)) {
+ if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 &&
+ coex_dm->cur_ps_tdma != 3 && coex_dm->cur_ps_tdma != 9) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+
+ up = 0;
+ dn = 0;
+ m = 1;
+ n = 3;
+ result = 0;
+ wait_count = 0;
+ }
+ return;
+ }
+
+ if (!coex_dm->auto_tdma_adjust) {
+ coex_dm->auto_tdma_adjust = true;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], first run TdmaDurationAdjust()!!\n");
+
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2);
+ coex_dm->tdma_adj_type = 2;
+
+ up = 0;
+ dn = 0;
+ m = 1;
+ n = 3;
+ result = 0;
+ wait_count = 0;
+ } else {
+ /*accquire the BT TRx retry count from BT_Info byte2 */
+ retry_count = coex_sta->bt_retry_cnt;
+ bt_info_ext = coex_sta->bt_info_ext;
+ result = 0;
+ wait_count++;
+ /* no retry in the last 2-second duration */
+ if (retry_count == 0) {
+ up++;
+ dn--;
+
+ if (dn <= 0)
+ dn = 0;
+
+ if (up >= n) {
+ wait_count = 0;
+ n = 3;
+ up = 0;
+ dn = 0;
+ result = 1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Increase wifi duration!!\n");
+ }
+ } else if (retry_count <= 3) {
+ up--;
+ dn++;
+
+ if (up <= 0)
+ up = 0;
+
+ if (dn == 2) {
+ if (wait_count <= 2)
+ m++;
+ else
+ m = 1;
+
+ if (m >= 20)
+ m = 20;
+
+ n = 3 * m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration for retryCounter<3!!\n");
+ }
+ } else {
+ if (wait_count == 1)
+ m++;
+ else
+ m = 1;
+
+ if (m >= 20)
+ m = 20;
+
+ n = 3 * m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration for retryCounter>3!!\n");
+ }
+
+ if (result == -1) {
+ if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) &&
+ ((coex_dm->cur_ps_tdma == 1) ||
+ (coex_dm->cur_ps_tdma == 2))) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ } else if (result == 1) {
+ if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) &&
+ ((coex_dm->cur_ps_tdma == 1) ||
+ (coex_dm->cur_ps_tdma == 2))) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ }
+ } else { /*no change */
+ /*if busy / idle change */
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex],********* TDMA(on, %d) ********\n",
+ coex_dm->cur_ps_tdma);
+ }
+
+ if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 &&
+ coex_dm->cur_ps_tdma != 9 && coex_dm->cur_ps_tdma != 11) {
+ /* recover to previous adjust type */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true,
+ coex_dm->tdma_adj_type);
+ }
+ }
+}
+
+static void btc8723b1ant_pstdmachkpwrsave(struct btc_coexist *btcoexist,
+ bool new_ps_state)
+{
+ u8 lps_mode = 0x0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode);
+
+ if (lps_mode) { /* already under LPS state */
+ if (new_ps_state) {
+ /* keep state under LPS, do nothing. */
+ } else {
+ /* will leave LPS state, turn off psTdma first */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0);
+ }
+ } else { /* NO PS state */
+ if (new_ps_state) {
+ /* will enter LPS state, turn off psTdma first */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0);
+ } else {
+ /* keep state under NO PS state, do nothing. */
+ }
+ }
+}
+
+static void halbtc8723b1ant_power_save_state(struct btc_coexist *btcoexist,
+ u8 ps_type, u8 lps_val,
+ u8 rpwm_val)
+{
+ bool low_pwr_disable = false;
+
+ switch (ps_type) {
+ case BTC_PS_WIFI_NATIVE:
+ /* recover to original 32k low power setting */
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL);
+ break;
+ case BTC_PS_LPS_ON:
+ btc8723b1ant_pstdmachkpwrsave(btcoexist, true);
+ halbtc8723b1ant_LpsRpwm(btcoexist, NORMAL_EXEC, lps_val,
+ rpwm_val);
+ /* when coex force to enter LPS, do not enter 32k low power. */
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+ /* power save must executed before psTdma. */
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL);
+ break;
+ case BTC_PS_LPS_OFF:
+ btc8723b1ant_pstdmachkpwrsave(btcoexist, false);
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+/***************************************************
+ *
+ * Software Coex Mechanism start
+ *
+ ***************************************************/
+/* SCO only or SCO+PAN(HS) */
+static void halbtc8723b1ant_action_sco(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+static void halbtc8723b1ant_action_hid(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */
+static void halbtc8723b1ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8723b1ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8723b1ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+/* PAN(HS) only */
+static void halbtc8723b1ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+/*PAN(EDR)+A2DP */
+static void halbtc8723b1ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8723b1ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+/* HID+A2DP+PAN(EDR) */
+static void btc8723b1ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+static void halbtc8723b1ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+/*****************************************************
+ *
+ * Non-Software Coex Mechanism start
+ *
+ *****************************************************/
+static void halbtc8723b1ant_action_wifi_multiport(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+}
+
+static void halbtc8723b1ant_action_hs(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+}
+
+static void halbtc8723b1ant_action_bt_inquiry(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool wifi_connected = false, ap_enable = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+ &ap_enable);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+
+ if (!wifi_connected) {
+ halbtc8723b1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+ } else if (bt_link_info->sco_exist || bt_link_info->hid_only) {
+ /* SCO/HID-only busy */
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ } else {
+ if (ap_enable)
+ halbtc8723b1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ else
+ halbtc8723b1ant_power_save_state(btcoexist,
+ BTC_PS_LPS_ON,
+ 0x50, 0x4);
+
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ }
+}
+
+static void btc8723b1ant_act_bt_sco_hid_only_busy(struct btc_coexist *btcoexist,
+ u8 wifi_status)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool wifi_connected = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+
+ /* tdma and coex table */
+
+ if (bt_link_info->sco_exist) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+ } else { /* HID */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5);
+ }
+}
+
+static void halbtc8723b1ant_action_wifi_connected_bt_acl_busy(
+ struct btc_coexist *btcoexist,
+ u8 wifi_status)
+{
+ u8 bt_rssi_state;
+
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+ bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 28, 0);
+
+ if (bt_link_info->hid_only) { /*HID */
+ btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, wifi_status);
+ coex_dm->auto_tdma_adjust = false;
+ return;
+ } else if (bt_link_info->a2dp_only) { /*A2DP */
+ if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 2);
+ coex_dm->auto_tdma_adjust = false;
+ } else if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8723b1ant_tdma_dur_adj_for_acl(btcoexist,
+ wifi_status);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ } else { /*for low BT RSSI */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ coex_dm->auto_tdma_adjust = false;
+ }
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) { /*HID+A2DP */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->auto_tdma_adjust = false;
+ } else { /*for low BT RSSI*/
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->auto_tdma_adjust = false;
+ }
+
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6);
+ /*PAN(OPP,FTP), HID+PAN(OPP,FTP) */
+ } else if (bt_link_info->pan_only ||
+ (bt_link_info->hid_exist && bt_link_info->pan_exist)) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6);
+ coex_dm->auto_tdma_adjust = false;
+ /*A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP)*/
+ } else if ((bt_link_info->a2dp_exist && bt_link_info->pan_exist) ||
+ (bt_link_info->hid_exist && bt_link_info->a2dp_exist &&
+ bt_link_info->pan_exist)) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ coex_dm->auto_tdma_adjust = false;
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ coex_dm->auto_tdma_adjust = false;
+ }
+}
+
+static void btc8723b1ant_action_wifi_not_conn(struct btc_coexist *btcoexist)
+{
+ /* power save state */
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ /* tdma and coex table */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0);
+}
+
+static void btc8723b1ant_action_wifi_not_conn_scan(struct btc_coexist *btcoex)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoex->bt_link_info;
+
+ halbtc8723b1ant_power_save_state(btcoex, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ /* tdma and coex table */
+ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) {
+ halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC,
+ true, 22);
+ halbtc8723b1ant_coex_table_with_type(btcoex,
+ NORMAL_EXEC, 1);
+ } else if (bt_link_info->pan_only) {
+ halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC,
+ true, 20);
+ halbtc8723b1ant_coex_table_with_type(btcoex,
+ NORMAL_EXEC, 2);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC,
+ true, 20);
+ halbtc8723b1ant_coex_table_with_type(btcoex,
+ NORMAL_EXEC, 1);
+ }
+ } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)){
+ btc8723b1ant_act_bt_sco_hid_only_busy(btcoex,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoex, NORMAL_EXEC, 2);
+ }
+}
+
+static void btc8723b1ant_act_wifi_not_conn_asso_auth(struct btc_coexist *btcoex)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoex->bt_link_info;
+
+ halbtc8723b1ant_power_save_state(btcoex, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) ||
+ (bt_link_info->sco_exist) || (bt_link_info->hid_only) ||
+ (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) {
+ halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoex, NORMAL_EXEC, 7);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, true, 20);
+ halbtc8723b1ant_coex_table_with_type(btcoex, NORMAL_EXEC, 1);
+ }
+}
+
+static void btc8723b1ant_action_wifi_conn_scan(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ /* tdma and coex table */
+ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 22);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ } else if (bt_link_info->pan_only) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 20);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 2);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 20);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ }
+ } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)) {
+ btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+ }
+}
+
+static void halbtc8723b1ant_action_wifi_connected_special_packet(
+ struct btc_coexist *btcoexist)
+{
+ bool hs_connecting = false;
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting);
+
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ /* tdma and coex table */
+ if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) ||
+ (bt_link_info->sco_exist) || (bt_link_info->hid_only) ||
+ (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ }
+}
+
+static void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist)
+{
+ bool wifi_busy = false;
+ bool scan = false, link = false, roam = false;
+ bool under_4way = false, ap_enable = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], CoexForWifiConnect()===>\n");
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS,
+ &under_4way);
+ if (under_4way) {
+ halbtc8723b1ant_action_wifi_connected_special_packet(btcoexist);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n");
+ return;
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+ if (scan || link || roam) {
+ if (scan)
+ btc8723b1ant_action_wifi_conn_scan(btcoexist);
+ else
+ halbtc8723b1ant_action_wifi_connected_special_packet(
+ btcoexist);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n");
+ return;
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+ &ap_enable);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ /* power save state */
+ if (!ap_enable &&
+ BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status &&
+ !btcoexist->bt_link_info.hid_only) {
+ if (!wifi_busy && btcoexist->bt_link_info.a2dp_only)
+ halbtc8723b1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ else
+ halbtc8723b1ant_power_save_state(btcoexist,
+ BTC_PS_LPS_ON,
+ 0x50, 0x4);
+ } else {
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ }
+ /* tdma and coex table */
+ if (!wifi_busy) {
+ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE);
+ } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY ==
+ coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)) {
+ btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 2);
+ }
+ } else {
+ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY);
+ } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY ==
+ coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)) {
+ btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY);
+ } else {
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 2);
+ }
+ }
+}
+
+static void btc8723b1ant_run_sw_coex_mech(struct btc_coexist *btcoexist)
+{
+ u8 algorithm = 0;
+
+ algorithm = halbtc8723b1ant_action_algorithm(btcoexist);
+ coex_dm->cur_algorithm = algorithm;
+
+ if (!halbtc8723b1ant_is_common_action(btcoexist)) {
+ switch (coex_dm->cur_algorithm) {
+ case BT_8723B_1ANT_COEX_ALGO_SCO:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = SCO.\n");
+ halbtc8723b1ant_action_sco(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HID.\n");
+ halbtc8723b1ant_action_hid(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = A2DP.\n");
+ halbtc8723b1ant_action_a2dp(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = A2DP+PAN(HS).\n");
+ halbtc8723b1ant_action_a2dp_pan_hs(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = PAN(EDR).\n");
+ halbtc8723b1ant_action_pan_edr(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HS mode.\n");
+ halbtc8723b1ant_action_pan_hs(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = PAN+A2DP.\n");
+ halbtc8723b1ant_action_pan_edr_a2dp(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_PANEDR_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = PAN(EDR)+HID.\n");
+ halbtc8723b1ant_action_pan_edr_hid(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HID+A2DP+PAN.\n");
+ btc8723b1ant_action_hid_a2dp_pan_edr(btcoexist);
+ break;
+ case BT_8723B_1ANT_COEX_ALGO_HID_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HID+A2DP.\n");
+ halbtc8723b1ant_action_hid_a2dp(btcoexist);
+ break;
+ default:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = coexist All Off!!\n");
+ break;
+ }
+ coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+ }
+}
+
+static void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool wifi_connected = false, bt_hs_on = false;
+ bool increase_scan_dev_num = false;
+ bool bt_ctrl_agg_buf_size = false;
+ u8 agg_buf_size = 5;
+ u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ u32 wifi_link_status = 0;
+ u32 num_of_wifi_link = 0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism()===>\n");
+
+ if (btcoexist->manual_control) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n");
+ return;
+ }
+
+ if (btcoexist->stop_coex_dm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n");
+ return;
+ }
+
+ if (coex_sta->under_ips) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], wifi is under IPS !!!\n");
+ return;
+ }
+
+ if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) {
+ increase_scan_dev_num = true;
+ }
+
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM,
+ &increase_scan_dev_num);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+ &wifi_link_status);
+ num_of_wifi_link = wifi_link_status >> 16;
+ if (num_of_wifi_link >= 2) {
+ halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+ halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+ bt_ctrl_agg_buf_size,
+ agg_buf_size);
+ halbtc8723b1ant_action_wifi_multiport(btcoexist);
+ return;
+ }
+
+ if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) {
+ halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+ } else {
+ if (wifi_connected) {
+ wifi_rssi_state =
+ halbtc8723b1ant_wifi_rssi_state(btcoexist,
+ 1, 2, 30, 0);
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8723b1ant_limited_tx(btcoexist,
+ NORMAL_EXEC,
+ 1, 1, 1, 1);
+ } else {
+ halbtc8723b1ant_limited_tx(btcoexist,
+ NORMAL_EXEC,
+ 1, 1, 1, 1);
+ }
+ } else {
+ halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC,
+ 0, 0, 0, 0);
+ }
+ }
+
+ if (bt_link_info->sco_exist) {
+ bt_ctrl_agg_buf_size = true;
+ agg_buf_size = 0x3;
+ } else if (bt_link_info->hid_exist) {
+ bt_ctrl_agg_buf_size = true;
+ agg_buf_size = 0x5;
+ } else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) {
+ bt_ctrl_agg_buf_size = true;
+ agg_buf_size = 0x8;
+ }
+ halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+ bt_ctrl_agg_buf_size, agg_buf_size);
+
+ btc8723b1ant_run_sw_coex_mech(btcoexist);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8723b1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8723b1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (!wifi_connected) {
+ bool scan = false, link = false, roam = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], wifi is non connected-idle !!!\n");
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+ if (scan || link || roam) {
+ if (scan)
+ btc8723b1ant_action_wifi_not_conn_scan(
+ btcoexist);
+ else
+ btc8723b1ant_act_wifi_not_conn_asso_auth(
+ btcoexist);
+ } else {
+ btc8723b1ant_action_wifi_not_conn(btcoexist);
+ }
+ } else { /* wifi LPS/Busy */
+ halbtc8723b1ant_action_wifi_connected(btcoexist);
+ }
+}
+
+static void halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ /* sw all off */
+ halbtc8723b1ant_sw_mechanism(btcoexist, false);
+
+ halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0);
+}
+
+static void halbtc8723b1ant_init_hw_config(struct btc_coexist *btcoexist,
+ bool backup)
+{
+ u32 u32tmp = 0;
+ u8 u8tmp = 0;
+ u32 cnt_bt_cal_chk = 0;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], 1Ant Init HW Config!!\n");
+
+ if (backup) {/* backup rf 0x1e value */
+ coex_dm->backup_arfr_cnt1 =
+ btcoexist->btc_read_4byte(btcoexist, 0x430);
+ coex_dm->backup_arfr_cnt2 =
+ btcoexist->btc_read_4byte(btcoexist, 0x434);
+ coex_dm->backup_retry_limit =
+ btcoexist->btc_read_2byte(btcoexist, 0x42a);
+ coex_dm->backup_ampdu_max_time =
+ btcoexist->btc_read_1byte(btcoexist, 0x456);
+ }
+
+ /* WiFi goto standby while GNT_BT 0-->1 */
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x780);
+ /* BT goto standby while GNT_BT 1-->0 */
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x500);
+
+ btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3);
+ btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77);
+
+ /* BT calibration check */
+ while (cnt_bt_cal_chk <= 20) {
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x49d);
+ cnt_bt_cal_chk++;
+ if (u32tmp & BIT0) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ########### BT calibration(cnt=%d) ###########\n",
+ cnt_bt_cal_chk);
+ mdelay(50);
+ } else {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ********** BT NOT calibration (cnt=%d)**********\n",
+ cnt_bt_cal_chk);
+ break;
+ }
+ }
+
+ /* 0x790[5:0] = 0x5 */
+ u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+ u8tmp &= 0xc0;
+ u8tmp |= 0x5;
+ btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp);
+
+ /* Enable counter statistics */
+ /*0x76e[3] =1, WLAN_Act control by PTA */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+ btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
+
+ /*Antenna config */
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_PTA, true, false);
+ /* PTA parameter */
+ halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0);
+}
+
+static void halbtc8723b1ant_wifi_off_hw_cfg(struct btc_coexist *btcoexist)
+{
+ /* set wlan_act to low */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4);
+}
+
+/**************************************************************
+ * work around function start with wa_halbtc8723b1ant_
+ **************************************************************/
+/**************************************************************
+ * extern function start with EXhalbtc8723b1ant_
+ **************************************************************/
+
+void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+ halbtc8723b1ant_init_hw_config(btcoexist, true);
+}
+
+void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Coex Mechanism Init!!\n");
+
+ btcoexist->stop_coex_dm = false;
+
+ halbtc8723b1ant_init_coex_dm(btcoexist);
+
+ halbtc8723b1ant_query_bt_info(btcoexist);
+}
+
+void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ u8 u8tmp[4], i, bt_info_ext, pstdmacase = 0;
+ u16 u16tmp[4];
+ u32 u32tmp[4];
+ bool roam = false, scan = false;
+ bool link = false, wifi_under_5g = false;
+ bool bt_hs_on = false, wifi_busy = false;
+ s32 wifi_rssi = 0, bt_hs_rssi = 0;
+ u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck, wifi_link_status;
+ u8 wifi_dot11_chnl, wifi_hs_chnl;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ============[BT Coexist info]============");
+
+ if (btcoexist->manual_control) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ============[Under Manual Control]==========");
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ==========================================");
+ }
+ if (btcoexist->stop_coex_dm) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ============[Coex is STOPPED]============");
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ==========================================");
+ }
+
+ if (!board_info->bt_exist) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!");
+ return;
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d",
+ "Ant PG Num/ Ant Mech/ Ant Pos:",
+ board_info->pg_ant_num, board_info->btdm_ant_num,
+ board_info->btdm_ant_pos);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %d",
+ "BT stack/ hci ext ver",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)",
+ "CoexVer/ FwVer/ PatchVer",
+ glcoex_ver_date_8723b_1ant, glcoex_ver_8723b_1ant,
+ fw_ver, bt_patch_ver, bt_patch_ver);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL,
+ &wifi_dot11_chnl);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d(%d)",
+ "Dot11 channel / HsChnl(HsMode)",
+ wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x ",
+ "H2C Wifi inform bt chnl Info",
+ coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1],
+ coex_dm->wifi_chnl_info[2]);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+ "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ",
+ "Wifi link/ roam/ scan", link, roam, scan);
+
+ btcoexist->btc_get(btcoexist , BTC_GET_BL_WIFI_UNDER_5G,
+ &wifi_under_5g);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
+ &wifi_traffic_dir);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %s/ %s ",
+ "Wifi status", (wifi_under_5g ? "5G" : "2.4G"),
+ ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+ (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+ ((!wifi_busy) ? "idle" :
+ ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+ "uplink" : "downlink")));
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+ &wifi_link_status);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d/ %d/ %d",
+ "sta/vwifi/hs/p2pGo/p2pGc",
+ ((wifi_link_status & WIFI_STA_CONNECTED) ? 1 : 0),
+ ((wifi_link_status & WIFI_AP_CONNECTED) ? 1 : 0),
+ ((wifi_link_status & WIFI_HS_CONNECTED) ? 1 : 0),
+ ((wifi_link_status & WIFI_P2P_GO_CONNECTED) ? 1 : 0),
+ ((wifi_link_status & WIFI_P2P_GC_CONNECTED) ? 1 : 0));
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = [%s/ %d/ %d] ",
+ "BT [status/ rssi/ retryCnt]",
+ ((btcoexist->bt_info.bt_disabled) ? ("disabled") :
+ ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") :
+ ((BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status) ?
+ "non-connected idle" :
+ ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status) ?
+ "connected-idle" : "busy")))),
+ coex_sta->bt_rssi, coex_sta->bt_retry_cnt);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d / %d / %d / %d",
+ "SCO/HID/PAN/A2DP", bt_link_info->sco_exist,
+ bt_link_info->hid_exist, bt_link_info->pan_exist,
+ bt_link_info->a2dp_exist);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO);
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s",
+ "BT Info A2DP rate",
+ (bt_info_ext & BIT0) ? "Basic rate" : "EDR rate");
+
+ for (i = 0; i < BT_INFO_SRC_8723B_1ANT_MAX; i++) {
+ if (coex_sta->bt_info_c2h_cnt[i]) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)",
+ GLBtInfoSrc8723b1Ant[i],
+ coex_sta->bt_info_c2h[i][0],
+ coex_sta->bt_info_c2h[i][1],
+ coex_sta->bt_info_c2h[i][2],
+ coex_sta->bt_info_c2h[i][3],
+ coex_sta->bt_info_c2h[i][4],
+ coex_sta->bt_info_c2h[i][5],
+ coex_sta->bt_info_c2h[i][6],
+ coex_sta->bt_info_c2h_cnt[i]);
+ }
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %s/%s, (0x%x/0x%x)",
+ "PS state, IPS/LPS, (lps/rpwm)",
+ ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+ ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")),
+ btcoexist->bt_info.lps_val,
+ btcoexist->bt_info.rpwm_val);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+ if (!btcoexist->manual_control) {
+ /* Sw mechanism */
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+ "============[Sw mechanism]============");
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/",
+ "SM[LowPenaltyRA]", coex_dm->cur_low_penalty_ra);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/ %s/ %d ",
+ "DelBA/ BtCtrlAgg/ AggSize",
+ (btcoexist->bt_info.reject_agg_pkt ? "Yes" : "No"),
+ (btcoexist->bt_info.bt_ctrl_buf_size ? "Yes" : "No"),
+ btcoexist->bt_info.agg_buf_size);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ",
+ "Rate Mask", btcoexist->bt_info.ra_mask);
+
+ /* Fw mechanism */
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+ "============[Fw mechanism]============");
+
+ pstdmacase = coex_dm->cur_ps_tdma;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)",
+ "PS TDMA", coex_dm->ps_tdma_para[0],
+ coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2],
+ coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4],
+ pstdmacase, coex_dm->auto_tdma_adjust);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d ",
+ "IgnWlanAct", coex_dm->cur_ignore_wlan_act);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ",
+ "Latest error condition(should be 0)",
+ coex_dm->error_condition);
+ }
+
+ /* Hw setting */
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+ "============[Hw setting]============");
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+ "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1,
+ coex_dm->backup_arfr_cnt2, coex_dm->backup_retry_limit,
+ coex_dm->backup_ampdu_max_time);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434);
+ u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+ "0x430/0x434/0x42a/0x456",
+ u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x880);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x778/0x6cc/0x880[29:25]", u8tmp[0], u32tmp[0],
+ (u32tmp[1] & 0x3e000000) >> 25);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67);
+ u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x948/ 0x67[5] / 0x765",
+ u32tmp[0], ((u8tmp[0] & 0x20) >> 5), u8tmp[1]);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930);
+ u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]",
+ u32tmp[0] & 0x3, u32tmp[1] & 0xff, u32tmp[2] & 0x3);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39);
+ u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
+ "0x38[11]/0x40/0x4c[24:23]/0x64[0]",
+ ((u8tmp[0] & 0x8)>>3), u8tmp[1],
+ ((u32tmp[0] & 0x01800000) >> 23), u8tmp[2] & 0x1);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+ "0xc50(dig)/0x49c(null-drop)", u32tmp[0] & 0xff, u8tmp[0]);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4);
+ u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0xda8);
+ u32tmp[3] = btcoexist->btc_read_4byte(btcoexist, 0xcf0);
+
+ u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b);
+ u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c);
+
+ fa_ofdm = ((u32tmp[0] & 0xffff0000) >> 16) +
+ ((u32tmp[1] & 0xffff0000) >> 16) +
+ (u32tmp[1] & 0xffff) +
+ (u32tmp[2] & 0xffff) +
+ ((u32tmp[3] & 0xffff0000) >> 16) +
+ (u32tmp[3] & 0xffff);
+ fa_cck = (u8tmp[0] << 8) + u8tmp[1];
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "OFDM-CCA/OFDM-FA/CCK-FA",
+ u32tmp[0] & 0xffff, fa_ofdm, fa_cck);
+
+ u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+ u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+ u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x6c0/0x6c4/0x6c8(coexTable)",
+ u32tmp[0], u32tmp[1], u32tmp[2]);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+ "0x770(high-pri rx/tx)", coex_sta->high_priority_rx,
+ coex_sta->high_priority_tx);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+ "0x774(low-pri rx/tx)", coex_sta->low_priority_rx,
+ coex_sta->low_priority_tx);
+#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 1)
+ halbtc8723b1ant_monitor_bt_ctr(btcoexist);
+#endif
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm)
+ return;
+
+ if (BTC_IPS_ENTER == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS ENTER notify\n");
+ coex_sta->under_ips = true;
+
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT,
+ false, true);
+ /* set PTA control */
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0);
+ halbtc8723b1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 0);
+ halbtc8723b1ant_wifi_off_hw_cfg(btcoexist);
+ } else if (BTC_IPS_LEAVE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS LEAVE notify\n");
+ coex_sta->under_ips = false;
+
+ halbtc8723b1ant_init_hw_config(btcoexist, false);
+ halbtc8723b1ant_init_coex_dm(btcoexist);
+ halbtc8723b1ant_query_bt_info(btcoexist);
+ }
+}
+
+void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm)
+ return;
+
+ if (BTC_LPS_ENABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS ENABLE notify\n");
+ coex_sta->under_lps = true;
+ } else if (BTC_LPS_DISABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS DISABLE notify\n");
+ coex_sta->under_lps = false;
+ }
+}
+
+void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ bool wifi_connected = false, bt_hs_on = false;
+ u32 wifi_link_status = 0;
+ u32 num_of_wifi_link = 0;
+ bool bt_ctrl_agg_buf_size = false;
+ u8 agg_buf_size = 5;
+
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+
+ halbtc8723b1ant_query_bt_info(btcoexist);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+ &wifi_link_status);
+ num_of_wifi_link = wifi_link_status >> 16;
+ if (num_of_wifi_link >= 2) {
+ halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+ halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+ bt_ctrl_agg_buf_size, agg_buf_size);
+ halbtc8723b1ant_action_wifi_multiport(btcoexist);
+ return;
+ }
+
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8723b1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8723b1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (BTC_SCAN_START == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN START notify\n");
+ if (!wifi_connected) /* non-connected scan */
+ btc8723b1ant_action_wifi_not_conn_scan(btcoexist);
+ else /* wifi is connected */
+ btc8723b1ant_action_wifi_conn_scan(btcoexist);
+ } else if (BTC_SCAN_FINISH == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN FINISH notify\n");
+ if (!wifi_connected) /* non-connected scan */
+ btc8723b1ant_action_wifi_not_conn(btcoexist);
+ else
+ halbtc8723b1ant_action_wifi_connected(btcoexist);
+ }
+}
+
+void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ bool wifi_connected = false, bt_hs_on = false;
+ u32 wifi_link_status = 0;
+ u32 num_of_wifi_link = 0;
+ bool bt_ctrl_agg_buf_size = false;
+ u8 agg_buf_size = 5;
+
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+ &wifi_link_status);
+ num_of_wifi_link = wifi_link_status>>16;
+ if (num_of_wifi_link >= 2) {
+ halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+ halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+ bt_ctrl_agg_buf_size, agg_buf_size);
+ halbtc8723b1ant_action_wifi_multiport(btcoexist);
+ return;
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8723b1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8723b1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (BTC_ASSOCIATE_START == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT START notify\n");
+ btc8723b1ant_act_wifi_not_conn_asso_auth(btcoexist);
+ } else if (BTC_ASSOCIATE_FINISH == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT FINISH notify\n");
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ if (!wifi_connected) /* non-connected scan */
+ btc8723b1ant_action_wifi_not_conn(btcoexist);
+ else
+ halbtc8723b1ant_action_wifi_connected(btcoexist);
+ }
+}
+
+void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ u8 h2c_parameter[3] = {0};
+ u32 wifi_bw;
+ u8 wifiCentralChnl;
+
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ if (BTC_MEDIA_CONNECT == type)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA connect notify\n");
+ else
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA disconnect notify\n");
+
+ /* only 2.4G we need to inform bt the chnl mask */
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL,
+ &wifiCentralChnl);
+
+ if ((BTC_MEDIA_CONNECT == type) &&
+ (wifiCentralChnl <= 14)) {
+ h2c_parameter[0] = 0x0;
+ h2c_parameter[1] = wifiCentralChnl;
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw)
+ h2c_parameter[2] = 0x30;
+ else
+ h2c_parameter[2] = 0x20;
+ }
+
+ coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+ coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+ coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x66 = 0x%x\n",
+ h2c_parameter[0] << 16 | h2c_parameter[1] << 8 |
+ h2c_parameter[2]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ bool bt_hs_on = false;
+ u32 wifi_link_status = 0;
+ u32 num_of_wifi_link = 0;
+ bool bt_ctrl_agg_buf_size = false;
+ u8 agg_buf_size = 5;
+
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+ &wifi_link_status);
+ num_of_wifi_link = wifi_link_status >> 16;
+ if (num_of_wifi_link >= 2) {
+ halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+ halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+ bt_ctrl_agg_buf_size, agg_buf_size);
+ halbtc8723b1ant_action_wifi_multiport(btcoexist);
+ return;
+ }
+
+ coex_sta->special_pkt_period_cnt = 0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8723b1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8723b1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (BTC_PACKET_DHCP == type ||
+ BTC_PACKET_EAPOL == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], special Packet(%d) notify\n", type);
+ halbtc8723b1ant_action_wifi_connected_special_packet(btcoexist);
+ }
+}
+
+void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmp_buf, u8 length)
+{
+ u8 bt_info = 0;
+ u8 i, rsp_source = 0;
+ bool wifi_connected = false;
+ bool bt_busy = false;
+
+ coex_sta->c2h_bt_info_req_sent = false;
+
+ rsp_source = tmp_buf[0] & 0xf;
+ if (rsp_source >= BT_INFO_SRC_8723B_1ANT_MAX)
+ rsp_source = BT_INFO_SRC_8723B_1ANT_WIFI_FW;
+ coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Bt info[%d], length=%d, hex data = [",
+ rsp_source, length);
+ for (i = 0; i < length; i++) {
+ coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i];
+ if (i == 1)
+ bt_info = tmp_buf[i];
+ if (i == length - 1)
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x]\n", tmp_buf[i]);
+ else
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x, ", tmp_buf[i]);
+ }
+
+ if (BT_INFO_SRC_8723B_1ANT_WIFI_FW != rsp_source) {
+ coex_sta->bt_retry_cnt = /* [3:0] */
+ coex_sta->bt_info_c2h[rsp_source][2] & 0xf;
+
+ coex_sta->bt_rssi =
+ coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10;
+
+ coex_sta->bt_info_ext =
+ coex_sta->bt_info_c2h[rsp_source][4];
+
+ /* Here we need to resend some wifi info to BT
+ * because bt is reset and loss of the info.
+ */
+ if (coex_sta->bt_info_ext & BIT1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n");
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ if (wifi_connected)
+ ex_halbtc8723b1ant_media_status_notify(btcoexist,
+ BTC_MEDIA_CONNECT);
+ else
+ ex_halbtc8723b1ant_media_status_notify(btcoexist,
+ BTC_MEDIA_DISCONNECT);
+ }
+
+ if (coex_sta->bt_info_ext & BIT3) {
+ if (!btcoexist->manual_control &&
+ !btcoexist->stop_coex_dm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT ext info bit3 check, set BT NOT ignore Wlan active!!\n");
+ halbtc8723b1ant_ignore_wlan_act(btcoexist,
+ FORCE_EXEC,
+ false);
+ }
+ } else {
+ /* BT already NOT ignore Wlan active, do nothing here.*/
+ }
+#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0)
+ if (coex_sta->bt_info_ext & BIT4) {
+ /* BT auto report already enabled, do nothing */
+ } else {
+ halbtc8723b1ant_bt_auto_report(btcoexist, FORCE_EXEC,
+ true);
+ }
+#endif
+ }
+
+ /* check BIT2 first ==> check if bt is under inquiry or page scan */
+ if (bt_info & BT_INFO_8723B_1ANT_B_INQ_PAGE)
+ coex_sta->c2h_bt_inquiry_page = true;
+ else
+ coex_sta->c2h_bt_inquiry_page = false;
+
+ /* set link exist status */
+ if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) {
+ coex_sta->bt_link_exist = false;
+ coex_sta->pan_exist = false;
+ coex_sta->a2dp_exist = false;
+ coex_sta->hid_exist = false;
+ coex_sta->sco_exist = false;
+ } else { /* connection exists */
+ coex_sta->bt_link_exist = true;
+ if (bt_info & BT_INFO_8723B_1ANT_B_FTP)
+ coex_sta->pan_exist = true;
+ else
+ coex_sta->pan_exist = false;
+ if (bt_info & BT_INFO_8723B_1ANT_B_A2DP)
+ coex_sta->a2dp_exist = true;
+ else
+ coex_sta->a2dp_exist = false;
+ if (bt_info & BT_INFO_8723B_1ANT_B_HID)
+ coex_sta->hid_exist = true;
+ else
+ coex_sta->hid_exist = false;
+ if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO)
+ coex_sta->sco_exist = true;
+ else
+ coex_sta->sco_exist = false;
+ }
+
+ halbtc8723b1ant_update_bt_link_info(btcoexist);
+
+ if (!(bt_info&BT_INFO_8723B_1ANT_B_CONNECTION)) {
+ coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT Non-Connected idle!\n");
+ /* connection exists but no busy */
+ } else if (bt_info == BT_INFO_8723B_1ANT_B_CONNECTION) {
+ coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n");
+ } else if ((bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) ||
+ (bt_info & BT_INFO_8723B_1ANT_B_SCO_BUSY)) {
+ coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_SCO_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n");
+ } else if (bt_info & BT_INFO_8723B_1ANT_B_ACL_BUSY) {
+ if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status)
+ coex_dm->auto_tdma_adjust = false;
+
+ coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_ACL_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n");
+ } else {
+ coex_dm->bt_status =
+ BT_8723B_1ANT_BT_STATUS_MAX;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT Non-Defined state!!\n");
+ }
+
+ if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status))
+ bt_busy = true;
+ else
+ bt_busy = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+ halbtc8723b1ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n");
+
+ btcoexist->stop_coex_dm = true;
+
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT, false, true);
+
+ halbtc8723b1ant_wifi_off_hw_cfg(btcoexist);
+ halbtc8723b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0);
+
+ ex_halbtc8723b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Pnp notify\n");
+
+ if (BTC_WIFI_PNP_SLEEP == pnp_state) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Pnp notify to SLEEP\n");
+ btcoexist->stop_coex_dm = true;
+ halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT, false,
+ true);
+ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0);
+ halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+ halbtc8723b1ant_wifi_off_hw_cfg(btcoexist);
+ } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Pnp notify to WAKE UP\n");
+ btcoexist->stop_coex_dm = false;
+ halbtc8723b1ant_init_hw_config(btcoexist, false);
+ halbtc8723b1ant_init_coex_dm(btcoexist);
+ halbtc8723b1ant_query_bt_info(btcoexist);
+ }
+}
+
+void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], *****************Coex DM Reset****************\n");
+
+ halbtc8723b1ant_init_hw_config(btcoexist, false);
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x0);
+ halbtc8723b1ant_init_coex_dm(btcoexist);
+}
+
+void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ static u8 dis_ver_info_cnt;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], ==========================Periodical===========================\n");
+
+ if (dis_ver_info_cnt <= 5) {
+ dis_ver_info_cnt += 1;
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ****************************************************************\n");
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n",
+ board_info->pg_ant_num, board_info->btdm_ant_num,
+ board_info->btdm_ant_pos);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], BT stack/ hci ext ver = %s / %d\n",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+ &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
+ glcoex_ver_date_8723b_1ant,
+ glcoex_ver_8723b_1ant, fw_ver,
+ bt_patch_ver, bt_patch_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ****************************************************************\n");
+ }
+
+#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0)
+ halbtc8723b1ant_query_bt_info(btcoexist);
+ halbtc8723b1ant_monitor_bt_ctr(btcoexist);
+ halbtc8723b1ant_monitor_bt_enable_disable(btcoexist);
+#else
+ if (btc8723b1ant_is_wifi_status_changed(btcoexist) ||
+ coex_dm->auto_tdma_adjust) {
+ halbtc8723b1ant_run_coexist_mechanism(btcoexist);
+ }
+
+ coex_sta->special_pkt_period_cnt++;
+#endif
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h
new file mode 100644
index 00000000000..75f8094b7a3
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h
@@ -0,0 +1,184 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+/**********************************************************************
+ * The following is for 8723B 1ANT BT Co-exist definition
+ **********************************************************************/
+#define BT_AUTO_REPORT_ONLY_8723B_1ANT 1
+
+#define BT_INFO_8723B_1ANT_B_FTP BIT7
+#define BT_INFO_8723B_1ANT_B_A2DP BIT6
+#define BT_INFO_8723B_1ANT_B_HID BIT5
+#define BT_INFO_8723B_1ANT_B_SCO_BUSY BIT4
+#define BT_INFO_8723B_1ANT_B_ACL_BUSY BIT3
+#define BT_INFO_8723B_1ANT_B_INQ_PAGE BIT2
+#define BT_INFO_8723B_1ANT_B_SCO_ESCO BIT1
+#define BT_INFO_8723B_1ANT_B_CONNECTION BIT0
+
+#define BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \
+ (((_BT_INFO_EXT_&BIT0)) ? true : false)
+
+#define BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT 2
+
+enum _BT_INFO_SRC_8723B_1ANT {
+ BT_INFO_SRC_8723B_1ANT_WIFI_FW = 0x0,
+ BT_INFO_SRC_8723B_1ANT_BT_RSP = 0x1,
+ BT_INFO_SRC_8723B_1ANT_BT_ACTIVE_SEND = 0x2,
+ BT_INFO_SRC_8723B_1ANT_MAX
+};
+
+enum _BT_8723B_1ANT_BT_STATUS {
+ BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0,
+ BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1,
+ BT_8723B_1ANT_BT_STATUS_INQ_PAGE = 0x2,
+ BT_8723B_1ANT_BT_STATUS_ACL_BUSY = 0x3,
+ BT_8723B_1ANT_BT_STATUS_SCO_BUSY = 0x4,
+ BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5,
+ BT_8723B_1ANT_BT_STATUS_MAX
+};
+
+enum _BT_8723B_1ANT_WIFI_STATUS {
+ BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0,
+ BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT = 0x3,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4,
+ BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5,
+ BT_8723B_1ANT_WIFI_STATUS_MAX
+};
+
+enum _BT_8723B_1ANT_COEX_ALGO {
+ BT_8723B_1ANT_COEX_ALGO_UNDEFINED = 0x0,
+ BT_8723B_1ANT_COEX_ALGO_SCO = 0x1,
+ BT_8723B_1ANT_COEX_ALGO_HID = 0x2,
+ BT_8723B_1ANT_COEX_ALGO_A2DP = 0x3,
+ BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS = 0x4,
+ BT_8723B_1ANT_COEX_ALGO_PANEDR = 0x5,
+ BT_8723B_1ANT_COEX_ALGO_PANHS = 0x6,
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7,
+ BT_8723B_1ANT_COEX_ALGO_PANEDR_HID = 0x8,
+ BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9,
+ BT_8723B_1ANT_COEX_ALGO_HID_A2DP = 0xa,
+ BT_8723B_1ANT_COEX_ALGO_MAX = 0xb,
+};
+
+struct coex_dm_8723b_1ant {
+ /* fw mechanism */
+ bool cur_ignore_wlan_act;
+ bool pre_ignore_wlan_act;
+ u8 pre_ps_tdma;
+ u8 cur_ps_tdma;
+ u8 ps_tdma_para[5];
+ u8 tdma_adj_type;
+ bool auto_tdma_adjust;
+ bool pre_ps_tdma_on;
+ bool cur_ps_tdma_on;
+ bool pre_bt_auto_report;
+ bool cur_bt_auto_report;
+ u8 pre_lps;
+ u8 cur_lps;
+ u8 pre_rpwm;
+ u8 cur_rpwm;
+
+ /* sw mechanism */
+ bool pre_low_penalty_ra;
+ bool cur_low_penalty_ra;
+ u32 pre_val0x6c0;
+ u32 cur_val0x6c0;
+ u32 pre_val0x6c4;
+ u32 cur_val0x6c4;
+ u32 pre_val0x6c8;
+ u32 cur_val0x6c8;
+ u8 pre_val0x6cc;
+ u8 cur_val0x6cc;
+ bool limited_dig;
+
+ u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */
+ u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */
+ u16 backup_retry_limit;
+ u8 backup_ampdu_max_time;
+
+ /* algorithm related */
+ u8 pre_algorithm;
+ u8 cur_algorithm;
+ u8 bt_status;
+ u8 wifi_chnl_info[3];
+
+ u32 prera_mask;
+ u32 curra_mask;
+ u8 pre_arfr_type;
+ u8 cur_arfr_type;
+ u8 pre_retry_limit_type;
+ u8 cur_retry_limit_type;
+ u8 pre_ampdu_time_type;
+ u8 cur_ampdu_time_type;
+
+ u8 error_condition;
+};
+
+struct coex_sta_8723b_1ant {
+ bool bt_link_exist;
+ bool sco_exist;
+ bool a2dp_exist;
+ bool hid_exist;
+ bool pan_exist;
+
+ bool under_lps;
+ bool under_ips;
+ u32 special_pkt_period_cnt;
+ u32 high_priority_tx;
+ u32 high_priority_rx;
+ u32 low_priority_tx;
+ u32 low_priority_rx;
+ u8 bt_rssi;
+ u8 pre_bt_rssi_state;
+ u8 pre_wifi_rssi_state[4];
+ bool c2h_bt_info_req_sent;
+ u8 bt_info_c2h[BT_INFO_SRC_8723B_1ANT_MAX][10];
+ u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_1ANT_MAX];
+ bool c2h_bt_inquiry_page;
+ u8 bt_retry_cnt;
+ u8 bt_info_ext;
+};
+
+/*************************************************************************
+ * The following is interface which will notify coex module.
+ *************************************************************************/
+void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmpbuf, u8 length);
+void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate);
+void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
index d916ab9f3c3..cefe2699142 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
@@ -49,8 +49,8 @@ static const char *const glbt_info_src_8723b_2ant[] = {
"BT Info[bt auto report]",
};
-static u32 glcoex_ver_date_8723b_2ant = 20130731;
-static u32 glcoex_ver_8723b_2ant = 0x3b;
+static u32 glcoex_ver_date_8723b_2ant = 20131113;
+static u32 glcoex_ver_8723b_2ant = 0x3f;
/**************************************************************
* local function proto type if needed
@@ -303,6 +303,21 @@ static void btc8723b2ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
}
+static void btc8723b2ant_query_bt_info(struct btc_coexist *btcoexist)
+{
+ u8 h2c_parameter[1] = {0};
+
+ coex_sta->c2h_bt_info_req_sent = true;
+
+ h2c_parameter[0] |= BIT0; /* trigger */
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
static bool btc8723b2ant_is_wifi_status_changed(struct btc_coexist *btcoexist)
{
static bool pre_wifi_busy;
@@ -604,7 +619,7 @@ static bool btc8723b_need_dec_pwr(struct btc_coexist *btcoexist)
if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi))
return false;
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
if (wifi_connected) {
if (bt_hs_on) {
@@ -824,7 +839,6 @@ static void btc8723b2ant_set_sw_fulltime_dac_swing(struct btc_coexist *btcoex,
btc8723b2ant_set_dac_swing_reg(btcoex, 0x18);
}
-
static void btc8723b2ant_dac_swing(struct btc_coexist *btcoexist,
bool force_exec, bool dac_swing_on,
u32 dac_swing_lvl)
@@ -884,7 +898,6 @@ static void btc8723b2ant_set_agc_table(struct btc_coexist *btcoexist,
btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa4200001);
}
-
/* RF Gain */
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000);
if (agc_table_en) {
@@ -1160,8 +1173,87 @@ static void btc8723b2ant_sw_mechanism2(struct btc_coexist *btcoexist,
dac_swing_lvl);
}
+static void btc8723b2ant_set_ant_path(struct btc_coexist *btcoexist,
+ u8 antpos_type, bool init_hwcfg,
+ bool wifi_off)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ u32 fw_ver = 0, u32tmp = 0;
+ bool pg_ext_switch = false;
+ bool use_ext_switch = false;
+ u8 h2c_parameter[2] = {0};
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+
+ if ((fw_ver < 0xc0000) || pg_ext_switch)
+ use_ext_switch = true;
+
+ if (init_hwcfg) {
+ /* 0x4c[23] = 0, 0x4c[24] = 1 Antenna control by WL/BT */
+ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u32tmp &= ~BIT23;
+ u32tmp |= BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+
+ btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3);
+ btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1);
+
+ /* Force GNT_BT to low */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0);
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
+ /* tell firmware "no antenna inverse" */
+ h2c_parameter[0] = 0;
+ h2c_parameter[1] = 1; /* ext switch type */
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ } else {
+ /* tell firmware "antenna inverse" */
+ h2c_parameter[0] = 1;
+ h2c_parameter[1] = 1; /* ext switch type */
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ }
+ }
+
+ /* ext switch setting */
+ if (use_ext_switch) {
+ /* fixed internal switch S1->WiFi, S0->BT */
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+ switch (antpos_type) {
+ case BTC_ANT_WIFI_AT_MAIN:
+ /* ext switch main at wifi */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
+ 0x3, 0x1);
+ break;
+ case BTC_ANT_WIFI_AT_AUX:
+ /* ext switch aux at wifi */
+ btcoexist->btc_write_1byte_bitmask(btcoexist,
+ 0x92c, 0x3, 0x2);
+ break;
+ }
+ } else { /* internal switch */
+ /* fixed ext switch */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1);
+ switch (antpos_type) {
+ case BTC_ANT_WIFI_AT_MAIN:
+ /* fixed internal switch S1->WiFi, S0->BT */
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+ break;
+ case BTC_ANT_WIFI_AT_AUX:
+ /* fixed internal switch S0->WiFi, S1->BT */
+ btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
+ break;
+ }
+ }
+}
+
static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec,
- bool turn_on, u8 type)
+ bool turn_on, u8 type)
{
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
"[BTCoex], %s turn %s PS TDMA, type=%d\n",
@@ -1351,7 +1443,8 @@ static void btc8723b2ant_action_bt_inquiry(struct btc_coexist *btcoexist)
coex_dm->need_recover_0x948 = true;
coex_dm->backup_0x948 = btcoexist->btc_read_2byte(btcoexist, 0x948);
- btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
+ btc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_AUX,
+ false, false);
}
static bool btc8723b2ant_is_common_action(struct btc_coexist *btcoexist)
@@ -1520,7 +1613,9 @@ static void set_tdma_int1(struct btc_coexist *btcoexist, bool tx_pause,
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 8);
coex_dm->tdma_adj_type = 8;
- } else if (coex_dm->cur_ps_tdma == 9) {
+ }
+
+ if (coex_dm->cur_ps_tdma == 9) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 13);
coex_dm->tdma_adj_type = 13;
@@ -1607,7 +1702,9 @@ static void set_tdma_int1(struct btc_coexist *btcoexist, bool tx_pause,
} else if (coex_dm->cur_ps_tdma == 8) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
coex_dm->tdma_adj_type = 4;
- } else if (coex_dm->cur_ps_tdma == 13) {
+ }
+
+ if (coex_dm->cur_ps_tdma == 13) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
coex_dm->tdma_adj_type = 9;
} else if (coex_dm->cur_ps_tdma == 14) {
@@ -1652,23 +1749,34 @@ static void set_tdma_int1(struct btc_coexist *btcoexist, bool tx_pause,
coex_dm->tdma_adj_type = 12;
}
} else if (result == 1) {
- int tmp = coex_dm->cur_ps_tdma;
- switch (tmp) {
- case 4:
- case 3:
- case 2:
- case 12:
- case 11:
- case 10:
- btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
- true, tmp - 1);
- coex_dm->tdma_adj_type = tmp - 1;
- break;
- case 1:
+ if (coex_dm->cur_ps_tdma == 4) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (coex_dm->cur_ps_tdma == 1) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 71);
coex_dm->tdma_adj_type = 71;
- break;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
}
}
}
@@ -1694,7 +1802,8 @@ static void set_tdma_int2(struct btc_coexist *btcoexist, bool tx_pause,
} else if (coex_dm->cur_ps_tdma == 4) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8);
coex_dm->tdma_adj_type = 8;
- } else if (coex_dm->cur_ps_tdma == 9) {
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14);
coex_dm->tdma_adj_type = 14;
} else if (coex_dm->cur_ps_tdma == 10) {
@@ -1776,7 +1885,8 @@ static void set_tdma_int2(struct btc_coexist *btcoexist, bool tx_pause,
} else if (coex_dm->cur_ps_tdma == 8) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
coex_dm->tdma_adj_type = 4;
- } else if (coex_dm->cur_ps_tdma == 13) {
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
coex_dm->tdma_adj_type = 10;
} else if (coex_dm->cur_ps_tdma == 14) {
@@ -1865,7 +1975,8 @@ static void set_tdma_int3(struct btc_coexist *btcoexist, bool tx_pause,
} else if (coex_dm->cur_ps_tdma == 4) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8);
coex_dm->tdma_adj_type = 8;
- } else if (coex_dm->cur_ps_tdma == 9) {
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15);
coex_dm->tdma_adj_type = 15;
} else if (coex_dm->cur_ps_tdma == 10) {
@@ -1935,101 +2046,80 @@ static void set_tdma_int3(struct btc_coexist *btcoexist, bool tx_pause,
BTC_PRINT(BTC_MSG_ALGORITHM,
ALGO_TRACE_FW_DETAIL,
"[BTCoex], TxPause = 0\n");
- switch (coex_dm->cur_ps_tdma) {
- case 5:
+ if (coex_dm->cur_ps_tdma == 5) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 6:
+ } else if (coex_dm->cur_ps_tdma == 6) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 7:
+ } else if (coex_dm->cur_ps_tdma == 7) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 8:
+ } else if (coex_dm->cur_ps_tdma == 8) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
coex_dm->tdma_adj_type = 4;
- break;
- case 13:
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 14:
+ } else if (coex_dm->cur_ps_tdma == 14) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 15:
+ } else if (coex_dm->cur_ps_tdma == 15) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 16:
+ } else if (coex_dm->cur_ps_tdma == 16) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12);
coex_dm->tdma_adj_type = 12;
- break;
}
if (result == -1) {
- switch (coex_dm->cur_ps_tdma) {
- case 1:
+ if (coex_dm->cur_ps_tdma == 1) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 2:
+ } else if (coex_dm->cur_ps_tdma == 2) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 3:
+ } else if (coex_dm->cur_ps_tdma == 3) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 4);
coex_dm->tdma_adj_type = 4;
- break;
- case 9:
+ } else if (coex_dm->cur_ps_tdma == 9) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 10:
+ } else if (coex_dm->cur_ps_tdma == 10) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 11:
+ } else if (coex_dm->cur_ps_tdma == 11) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 12);
coex_dm->tdma_adj_type = 12;
- break;
}
} else if (result == 1) {
- switch (coex_dm->cur_ps_tdma) {
- case 4:
+ if (coex_dm->cur_ps_tdma == 4) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 3:
+ } else if (coex_dm->cur_ps_tdma == 3) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 2:
+ } else if (coex_dm->cur_ps_tdma == 2) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 3);
coex_dm->tdma_adj_type = 3;
- break;
- case 12:
+ } else if (coex_dm->cur_ps_tdma == 12) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 11:
+ } else if (coex_dm->cur_ps_tdma == 11) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 11);
coex_dm->tdma_adj_type = 11;
- break;
- case 10:
+ } else if (coex_dm->cur_ps_tdma == 10) {
btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
true, 11);
coex_dm->tdma_adj_type = 11;
@@ -2328,7 +2418,7 @@ static void btc8723b2ant_action_hid(struct btc_coexist *btcoexist)
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -2385,12 +2475,43 @@ static void btc8723b2ant_action_hid(struct btc_coexist *btcoexist)
/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS)*/
static void btc8723b2ant_action_a2dp(struct btc_coexist *btcoexist)
{
- u8 wifi_rssi_state, bt_rssi_state;
+ u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
u32 wifi_bw;
+ u8 ap_num = 0;
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist,
+ 1, 2, 40, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num);
+
+ /* define the office environment */
+ /* driver don't know AP num in Linux, so we will never enter this if */
+ if (ap_num >= 10 && BTC_RSSI_HIGH(wifi_rssi_state1)) {
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff,
+ 0x0);
+ btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+ btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0);
+ btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+
+ /* sw mechanism */
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ true, 0x18);
+ } else {
+ btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+ false, false);
+ btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+ true, 0x18);
+ }
+ return;
+ }
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -2501,7 +2622,7 @@ static void btc8723b2ant_action_pan_edr(struct btc_coexist *btcoexist)
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -2612,7 +2733,7 @@ static void btc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -2676,7 +2797,7 @@ static void btc8723b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
if (btc8723b_need_dec_pwr(btcoexist))
@@ -2746,7 +2867,7 @@ static void btc8723b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -2809,8 +2930,8 @@ static void btc8723b2ant_action_hid_a2dp(struct btc_coexist *btcoexist)
u32 wifi_bw;
wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
- 0, 2, 15, 0);
- bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+ 0, 2, 15, 0);
+ bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -2982,7 +3103,15 @@ static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
}
}
-
+static void btc8723b2ant_wifioff_hwcfg(struct btc_coexist *btcoexist)
+{
+ /* set wlan_act to low */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4);
+ /* Force GNT_BT to High */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3);
+ /* BT select s0/s1 is controlled by BT */
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0);
+}
/*********************************************************************
* work around function start with wa_btc8723b2ant_
@@ -2990,98 +3119,24 @@ static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
/*********************************************************************
* extern function start with EXbtc8723b2ant_
*********************************************************************/
-void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist)
{
- struct btc_board_info *board_info = &btcoexist->board_info;
- u32 u32tmp = 0, fw_ver;
u8 u8tmp = 0;
- u8 h2c_parameter[2] = {0};
-
BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
"[BTCoex], 2Ant Init HW Config!!\n");
+ coex_dm->bt_rf0x1e_backup =
+ btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff);
- /* backup rf 0x1e value */
- coex_dm->bt_rf0x1e_backup = btcoexist->btc_get_rf_reg(btcoexist,
- BTC_RF_A, 0x1e,
- 0xfffff);
-
- /* 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT */
- u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
- u32tmp &= ~BIT23;
- u32tmp |= BIT24;
- btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
-
- btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff);
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3);
- btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77);
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1);
-
- /* Antenna switch control parameter */
- /* btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555);*/
-
- /*Force GNT_BT to low*/
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0);
- btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
-
- /* 0x790[5:0]=0x5 */
+ /* 0x790[5:0] = 0x5 */
u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
u8tmp &= 0xc0;
u8tmp |= 0x5;
btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp);
-
- /*Antenna config */
- btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
-
- /*ext switch for fw ver < 0xc */
- if (fw_ver < 0xc00) {
- if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
- 0x3, 0x1);
- /*Main Ant to BT for IPS case 0x4c[23]=1*/
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1,
- 0x1);
-
- /*tell firmware "no antenna inverse"*/
- h2c_parameter[0] = 0;
- h2c_parameter[1] = 1; /* ext switch type */
- btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
- h2c_parameter);
- } else {
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
- 0x3, 0x2);
- /*Aux Ant to BT for IPS case 0x4c[23]=1*/
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1,
- 0x0);
-
- /*tell firmware "antenna inverse"*/
- h2c_parameter[0] = 1;
- h2c_parameter[1] = 1; /*ext switch type*/
- btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
- h2c_parameter);
- }
- } else {
- /*ext switch always at s1 (if exist) */
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1);
- /*Main Ant to BT for IPS case 0x4c[23]=1*/
- btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, 0x1);
-
- if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
- /*tell firmware "no antenna inverse"*/
- h2c_parameter[0] = 0;
- h2c_parameter[1] = 0; /*ext switch type*/
- btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
- h2c_parameter);
- } else {
- /*tell firmware "antenna inverse"*/
- h2c_parameter[0] = 1;
- h2c_parameter[1] = 0; /*ext switch type*/
- btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
- h2c_parameter);
- }
- }
-
+ /*Antenna config */
+ btc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN,
+ true, false);
/* PTA parameter */
btc8723b_coex_tbl_type(btcoexist, FORCE_EXEC, 0);
@@ -3092,19 +3147,19 @@ void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist)
btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
}
-void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist)
{
BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
"[BTCoex], Coex Mechanism Init!!\n");
btc8723b2ant_init_coex_dm(btcoexist);
}
-void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
{
struct btc_board_info *board_info = &btcoexist->board_info;
struct btc_stack_info *stack_info = &btcoexist->stack_info;
struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
- u8 *cli_buf = btcoexist->cli_buf;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0;
u32 u32tmp[4];
bool roam = false, scan = false;
@@ -3114,106 +3169,93 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck;
u8 wifi_dot11_chnl, wifi_hs_chnl;
u32 fw_ver = 0, bt_patch_ver = 0;
+ u8 ap_num = 0;
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"\r\n ============[BT Coexist info]============");
- CL_PRINTF(cli_buf);
if (btcoexist->manual_control) {
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"\r\n ==========[Under Manual Control]============");
- CL_PRINTF(cli_buf);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"\r\n ==========================================");
- CL_PRINTF(cli_buf);
}
if (!board_info->bt_exist) {
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!");
- CL_PRINTF(cli_buf);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!");
return;
}
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ",
"Ant PG number/ Ant mechanism:",
board_info->pg_ant_num, board_info->btdm_ant_num);
- CL_PRINTF(cli_buf);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %d",
"BT stack/ hci ext ver",
((stack_info->profile_notified) ? "Yes" : "No"),
stack_info->hci_version);
- CL_PRINTF(cli_buf);
btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)",
"CoexVer/ FwVer/ PatchVer",
glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant,
fw_ver, bt_patch_ver, bt_patch_ver);
- CL_PRINTF(cli_buf);
btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL,
&wifi_dot11_chnl);
btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d(%d)",
"Dot11 channel / HsChnl(HsMode)",
wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on);
- CL_PRINTF(cli_buf);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x ",
"H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0],
coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]);
- CL_PRINTF(cli_buf);
btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
- "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi);
- CL_PRINTF(cli_buf);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d",
+ "Wifi rssi/ HS rssi/ AP#", wifi_rssi, bt_hs_rssi, ap_num);
btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ",
"Wifi link/ roam/ scan", link, roam, scan);
- CL_PRINTF(cli_buf);
btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
&wifi_traffic_dir);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %s/ %s ",
"Wifi status", (wifi_under_5g ? "5G" : "2.4G"),
((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
(((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
((!wifi_busy) ? "idle" :
((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
"uplink" : "downlink")));
- CL_PRINTF(cli_buf);
- CL_PRINTF(cli_buf);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d / %d / %d",
"SCO/HID/PAN/A2DP",
bt_link_info->sco_exist, bt_link_info->hid_exist,
bt_link_info->pan_exist, bt_link_info->a2dp_exist);
- CL_PRINTF(cli_buf);
btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO);
bt_info_ext = coex_sta->bt_info_ext;
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s",
"BT Info A2DP rate",
(bt_info_ext&BIT0) ? "Basic rate" : "EDR rate");
- CL_PRINTF(cli_buf);
for (i = 0; i < BT_INFO_SRC_8723B_2ANT_MAX; i++) {
if (coex_sta->bt_info_c2h_cnt[i]) {
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"\r\n %-35s = %02x %02x %02x "
"%02x %02x %02x %02x(%d)",
glbt_info_src_8723b_2ant[i],
@@ -3225,105 +3267,88 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
coex_sta->bt_info_c2h[i][5],
coex_sta->bt_info_c2h[i][6],
coex_sta->bt_info_c2h_cnt[i]);
- CL_PRINTF(cli_buf);
}
}
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/%s",
"PS state, IPS/LPS",
((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
((coex_sta->under_lps ? "LPS ON" : "LPS OFF")));
- CL_PRINTF(cli_buf);
btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
/* Sw mechanism */
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"\r\n %-35s", "============[Sw mechanism]============");
- CL_PRINTF(cli_buf);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ",
"SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink,
coex_dm->cur_low_penalty_ra, coex_dm->limited_dig);
- CL_PRINTF(cli_buf);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d(0x%x) ",
"SM2[AgcT/ AdcB/ SwDacSwing(lvl)]",
coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off,
coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl);
- CL_PRINTF(cli_buf);
/* Fw mechanism */
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
"============[Fw mechanism]============");
- CL_PRINTF(cli_buf);
ps_tdma_case = coex_dm->cur_ps_tdma;
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)",
"PS TDMA", coex_dm->ps_tdma_para[0],
coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2],
coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4],
ps_tdma_case, coex_dm->auto_tdma_adjust);
- CL_PRINTF(cli_buf);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ",
"DecBtPwr/ IgnWlanAct", coex_dm->cur_dec_bt_pwr,
coex_dm->cur_ignore_wlan_act);
- CL_PRINTF(cli_buf);
/* Hw setting */
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
"============[Hw setting]============");
- CL_PRINTF(cli_buf);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x",
"RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup);
- CL_PRINTF(cli_buf);
u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x880);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
"0x778/0x880[29:25]", u8tmp[0],
(u32tmp[0]&0x3e000000) >> 25);
- CL_PRINTF(cli_buf);
u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948);
u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67);
u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
"0x948/ 0x67[5] / 0x765",
u32tmp[0], ((u8tmp[0]&0x20) >> 5), u8tmp[1]);
- CL_PRINTF(cli_buf);
u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c);
u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930);
u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
"0x92c[1:0]/ 0x930[7:0]/0x944[1:0]",
u32tmp[0]&0x3, u32tmp[1]&0xff, u32tmp[2]&0x3);
- CL_PRINTF(cli_buf);
-
u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39);
u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40);
u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
"0x38[11]/0x40/0x4c[24:23]/0x64[0]",
((u8tmp[0] & 0x8)>>3), u8tmp[1],
((u32tmp[0]&0x01800000)>>23), u8tmp[2]&0x1);
- CL_PRINTF(cli_buf);
u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
"0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]);
- CL_PRINTF(cli_buf);
u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
"0xc50(dig)/0x49c(null-drop)", u32tmp[0]&0xff, u8tmp[0]);
- CL_PRINTF(cli_buf);
u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0);
u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4);
@@ -3341,29 +3366,25 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
(u32tmp[3] & 0xffff);
fa_cck = (u8tmp[0] << 8) + u8tmp[1];
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
"OFDM-CCA/OFDM-FA/CCK-FA",
u32tmp[0]&0xffff, fa_ofdm, fa_cck);
- CL_PRINTF(cli_buf);
u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
"0x6c0/0x6c4/0x6c8/0x6cc(coexTable)",
u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]);
- CL_PRINTF(cli_buf);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
"0x770(high-pri rx/tx)",
coex_sta->high_priority_rx, coex_sta->high_priority_tx);
- CL_PRINTF(cli_buf);
- CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
"0x774(low-pri rx/tx)", coex_sta->low_priority_rx,
coex_sta->low_priority_tx);
- CL_PRINTF(cli_buf);
#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1)
btc8723b2ant_monitor_bt_ctr(btcoexist);
#endif
@@ -3371,22 +3392,26 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
BTC_DBG_DISP_COEX_STATISTICS);
}
-
-void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+void ex_btc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
{
if (BTC_IPS_ENTER == type) {
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
"[BTCoex], IPS ENTER notify\n");
coex_sta->under_ips = true;
+ btc8723b2ant_wifioff_hwcfg(btcoexist);
+ btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
btc8723b2ant_coex_alloff(btcoexist);
} else if (BTC_IPS_LEAVE == type) {
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
"[BTCoex], IPS LEAVE notify\n");
coex_sta->under_ips = false;
+ ex_btc8723b2ant_init_hwconfig(btcoexist);
+ btc8723b2ant_init_coex_dm(btcoexist);
+ btc8723b2ant_query_bt_info(btcoexist);
}
}
-void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+void ex_btc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
{
if (BTC_LPS_ENABLE == type) {
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
@@ -3399,7 +3424,7 @@ void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
}
}
-void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+void ex_btc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
{
if (BTC_SCAN_START == type)
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
@@ -3409,7 +3434,7 @@ void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
"[BTCoex], SCAN FINISH notify\n");
}
-void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+void ex_btc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
{
if (BTC_ASSOCIATE_START == type)
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
@@ -3419,8 +3444,8 @@ void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
"[BTCoex], CONNECT FINISH notify\n");
}
-void btc8723b_med_stat_notify(struct btc_coexist *btcoexist,
- u8 type)
+void ex_btc8723b2ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type)
{
u8 h2c_parameter[3] = {0};
u32 wifi_bw;
@@ -3460,16 +3485,16 @@ void btc8723b_med_stat_notify(struct btc_coexist *btcoexist,
btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
}
-void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
- u8 type)
+void ex_btc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type)
{
if (type == BTC_PACKET_DHCP)
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
"[BTCoex], DHCP Packet notify\n");
}
-void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
- u8 *tmpbuf, u8 length)
+void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmpbuf, u8 length)
{
u8 bt_info = 0;
u8 i, rsp_source = 0;
@@ -3516,7 +3541,7 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
coex_sta->bt_info_c2h[rsp_source][4];
/* Here we need to resend some wifi info to BT
- * because bt is reset and loss of the info.
+ because bt is reset and loss of the info.
*/
if ((coex_sta->bt_info_ext & BIT1)) {
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
@@ -3525,11 +3550,13 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
&wifi_connected);
if (wifi_connected)
- btc8723b_med_stat_notify(btcoexist,
- BTC_MEDIA_CONNECT);
+ ex_btc8723b2ant_media_status_notify(
+ btcoexist,
+ BTC_MEDIA_CONNECT);
else
- btc8723b_med_stat_notify(btcoexist,
- BTC_MEDIA_DISCONNECT);
+ ex_btc8723b2ant_media_status_notify(
+ btcoexist,
+ BTC_MEDIA_DISCONNECT);
}
if ((coex_sta->bt_info_ext & BIT3)) {
@@ -3564,7 +3591,7 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
coex_sta->a2dp_exist = false;
coex_sta->hid_exist = false;
coex_sta->sco_exist = false;
- } else { /* connection exists */
+ } else { /* connection exists */
coex_sta->bt_link_exist = true;
if (bt_info & BT_INFO_8723B_2ANT_B_FTP)
coex_sta->pan_exist = true;
@@ -3601,7 +3628,7 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_SCO_BUSY;
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
"[BTCoex], BtInfoNotify(), BT SCO busy!!!\n");
- } else if (bt_info & BT_INFO_8723B_2ANT_B_ACL_BUSY) {
+ } else if (bt_info&BT_INFO_8723B_2ANT_B_ACL_BUSY) {
coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_ACL_BUSY;
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
"[BTCoex], BtInfoNotify(), BT ACL busy!!!\n");
@@ -3630,26 +3657,16 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
btc8723b2ant_run_coexist_mechanism(btcoexist);
}
-void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist,
- u8 type)
-{
- if (BTC_STACK_OP_INQ_PAGE_PAIR_START == type)
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
- "[BTCoex],StackOP Inquiry/page/pair start notify\n");
- else if (BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type)
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
- "[BTCoex],StackOP Inquiry/page/pair finish notify\n");
-}
-
-void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_halt_notify(struct btc_coexist *btcoexist)
{
BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n");
+ btc8723b2ant_wifioff_hwcfg(btcoexist);
btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
- btc8723b_med_stat_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+ ex_btc8723b2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT);
}
-void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist)
{
struct btc_board_info *board_info = &btcoexist->board_info;
struct btc_stack_info *stack_info = &btcoexist->stack_info;
@@ -3677,8 +3694,7 @@ void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist)
&bt_patch_ver);
btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
- "[BTCoex], CoexVer/ FwVer/ PatchVer = "
- "%d_%x/ 0x%x/ 0x%x(%d)\n",
+ "[BTCoex], CoexVer/ fw_ver/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant,
fw_ver, bt_patch_ver, bt_patch_ver);
BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h
index e0ad8e545f8..567f354caf9 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h
@@ -153,21 +153,20 @@ struct coex_sta_8723b_2ant {
/*********************************************************************
* The following is interface which will notify coex module.
*********************************************************************/
-void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist);
-void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist);
-void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
-void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
-void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
-void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
-void btc8723b_med_stat_notify(struct btc_coexist *btcoexist, u8 type);
-void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
- u8 type);
-void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
- u8 *tmpbuf, u8 length);
-void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist,
- u8 type);
-void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist);
-void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist);
-void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_btc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_btc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_btc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_btc8723b2ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_btc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmpbuf, u8 length);
+void ex_btc8723b2ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist);
#endif
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c
new file mode 100644
index 00000000000..b72e5377bdb
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c
@@ -0,0 +1,2970 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/*============================================================
+ * Description:
+ *
+ * This file is for RTL8821A Co-exist mechanism
+ *
+ * History
+ * 2012/11/15 Cosa first check in.
+ *
+ *============================================================
+*/
+/*============================================================
+ * include files
+ *============================================================
+ */
+#include "halbt_precomp.h"
+/*============================================================
+ * Global variables, these are static variables
+ *============================================================
+ */
+static struct coex_dm_8821a_1ant glcoex_dm_8821a_1ant;
+static struct coex_dm_8821a_1ant *coex_dm = &glcoex_dm_8821a_1ant;
+static struct coex_sta_8821a_1ant glcoex_sta_8821a_1ant;
+static struct coex_sta_8821a_1ant *coex_sta = &glcoex_sta_8821a_1ant;
+
+static const char *const glbt_info_src_8821a_1ant[] = {
+ "BT Info[wifi fw]",
+ "BT Info[bt rsp]",
+ "BT Info[bt auto report]",
+};
+
+static u32 glcoex_ver_date_8821a_1ant = 20130816;
+static u32 glcoex_ver_8821a_1ant = 0x41;
+
+/*============================================================
+ * local function proto type if needed
+ *
+ * local function start with halbtc8821a1ant_
+ *============================================================
+ */
+static u8 halbtc8821a1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh,
+ u8 rssi_thresh1)
+{
+ long bt_rssi = 0;
+ u8 bt_rssi_state = coex_sta->pre_bt_rssi_state;
+
+ bt_rssi = coex_sta->bt_rssi;
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ if (bt_rssi >= (rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to High\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Low\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi thresh error!!\n");
+ return coex_sta->pre_bt_rssi_state;
+ }
+
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ if (bt_rssi >= (rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (bt_rssi >= (rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to High\n");
+ } else if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Medium\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh1) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at High\n");
+ }
+ }
+ }
+ coex_sta->pre_bt_rssi_state = bt_rssi_state;
+
+ return bt_rssi_state;
+}
+
+static u8 halbtc8821a1ant_WifiRssiState(struct btc_coexist *btcoexist,
+ u8 index, u8 level_num, u8 rssi_thresh,
+ u8 rssi_thresh1)
+{
+ long wifi_rssi = 0;
+ u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >=
+ (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to High\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Low\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI thresh error!!\n");
+ return coex_sta->pre_wifi_rssi_state[index];
+ }
+
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >=
+ (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (wifi_rssi >=
+ (rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to High\n");
+ } else if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Medium\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh1) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at High\n");
+ }
+ }
+ }
+ coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state;
+
+ return wifi_rssi_state;
+}
+
+static void halbtc8821a1ant_update_ra_mask(struct btc_coexist *btcoexist,
+ bool force_exec, u32 dis_rate_mask)
+{
+ coex_dm->cur_ra_mask = dis_rate_mask;
+
+ if (force_exec ||
+ (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) {
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask,
+ &coex_dm->cur_ra_mask);
+ }
+ coex_dm->pre_ra_mask = coex_dm->cur_ra_mask;
+}
+
+static void btc8821a1ant_auto_rate_fb_retry(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ bool wifi_under_b_mode = false;
+
+ coex_dm->cur_arfr_type = type;
+
+ if (force_exec ||
+ (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) {
+ switch (coex_dm->cur_arfr_type) {
+ case 0: /* normal mode*/
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ coex_dm->backup_arfr_cnt1);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ coex_dm->backup_arfr_cnt2);
+ break;
+ case 1:
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_UNDER_B_MODE,
+ &wifi_under_b_mode);
+ if (wifi_under_b_mode) {
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ 0x0);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ 0x01010101);
+ } else {
+ btcoexist->btc_write_4byte(btcoexist, 0x430,
+ 0x0);
+ btcoexist->btc_write_4byte(btcoexist, 0x434,
+ 0x04030201);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_arfr_type = coex_dm->cur_arfr_type;
+}
+
+static void halbtc8821a1ant_retry_limit(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ coex_dm->cur_retry_limit_type = type;
+
+ if (force_exec ||
+ (coex_dm->pre_retry_limit_type != coex_dm->cur_retry_limit_type)) {
+ switch (coex_dm->cur_retry_limit_type) {
+ case 0: /* normal mode*/
+ btcoexist->btc_write_2byte(btcoexist, 0x42a,
+ coex_dm->backup_retry_limit);
+ break;
+ case 1: /* retry limit = 8*/
+ btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808);
+ break;
+ default:
+ break;
+ }
+ }
+ coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type;
+}
+
+static void halbtc8821a1ant_ampdu_max_time(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ coex_dm->cur_ampdu_time_type = type;
+
+ if (force_exec ||
+ (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) {
+ switch (coex_dm->cur_ampdu_time_type) {
+ case 0: /* normal mode*/
+ btcoexist->btc_write_1byte(btcoexist, 0x456,
+ coex_dm->backup_ampdu_max_time);
+ break;
+ case 1: /* AMPDU timw = 0x38 * 32us*/
+ btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38);
+ break;
+ default:
+ break;
+ }
+ }
+
+ coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type;
+}
+
+static void halbtc8821a1ant_limited_tx(struct btc_coexist *btcoexist,
+ bool force_exec, u8 ra_mask_type,
+ u8 arfr_type, u8 retry_limit_type,
+ u8 ampdu_time_type)
+{
+ switch (ra_mask_type) {
+ case 0: /* normal mode*/
+ halbtc8821a1ant_update_ra_mask(btcoexist, force_exec, 0x0);
+ break;
+ case 1: /* disable cck 1/2*/
+ halbtc8821a1ant_update_ra_mask(btcoexist, force_exec,
+ 0x00000003);
+ break;
+ case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4*/
+ halbtc8821a1ant_update_ra_mask(btcoexist, force_exec,
+ 0x0001f1f7);
+ break;
+ default:
+ break;
+ }
+
+ btc8821a1ant_auto_rate_fb_retry(btcoexist, force_exec, arfr_type);
+ halbtc8821a1ant_retry_limit(btcoexist, force_exec, retry_limit_type);
+ halbtc8821a1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type);
+}
+
+static void halbtc8821a1ant_limited_rx(struct btc_coexist *btcoexist,
+ bool force_exec, bool rej_ap_agg_pkt,
+ bool bt_ctrl_agg_buf_size,
+ u8 agg_buf_size)
+{
+ bool reject_rx_agg = rej_ap_agg_pkt;
+ bool bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size;
+ u8 rx_agg_size = agg_buf_size;
+
+ /*============================================*/
+ /* Rx Aggregation related setting*/
+ /*============================================*/
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_BL_TO_REJ_AP_AGG_PKT, &reject_rx_agg);
+ /* decide BT control aggregation buf size or not*/
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE,
+ &bt_ctrl_rx_agg_size);
+ /* aggregation buf size, only work when BT control Rx agg size.*/
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size);
+ /* real update aggregation setting*/
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL);
+}
+
+static void halbtc8821a1ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+ u32 reg_hp_tx_rx, reg_lp_tx_rx, u4_tmp;
+ u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0;
+
+ reg_hp_tx_rx = 0x770;
+ reg_lp_tx_rx = 0x774;
+
+ u4_tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_tx_rx);
+ reg_hp_tx = u4_tmp & MASKLWORD;
+ reg_hp_rx = (u4_tmp & MASKHWORD)>>16;
+
+ u4_tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_tx_rx);
+ reg_lp_tx = u4_tmp & MASKLWORD;
+ reg_lp_rx = (u4_tmp & MASKHWORD)>>16;
+
+ coex_sta->high_priority_tx = reg_hp_tx;
+ coex_sta->high_priority_rx = reg_hp_rx;
+ coex_sta->low_priority_tx = reg_lp_tx;
+ coex_sta->low_priority_rx = reg_lp_rx;
+
+ /* reset counter*/
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static void halbtc8821a1ant_query_bt_info(struct btc_coexist *btcoexist)
+{
+ u8 h2c_parameter[1] = {0};
+
+ coex_sta->c2h_bt_info_req_sent = true;
+
+ h2c_parameter[0] |= BIT0; /* trigger*/
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
+static void halbtc8821a1ant_update_bt_link_info(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool bt_hs_on = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ bt_link_info->bt_link_exist = coex_sta->bt_link_exist;
+ bt_link_info->sco_exist = coex_sta->sco_exist;
+ bt_link_info->a2dp_exist = coex_sta->a2dp_exist;
+ bt_link_info->pan_exist = coex_sta->pan_exist;
+ bt_link_info->hid_exist = coex_sta->hid_exist;
+
+ /* work around for HS mode.*/
+ if (bt_hs_on) {
+ bt_link_info->pan_exist = true;
+ bt_link_info->bt_link_exist = true;
+ }
+
+ /* check if Sco only*/
+ if (bt_link_info->sco_exist &&
+ !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist &&
+ !bt_link_info->hid_exist)
+ bt_link_info->sco_only = true;
+ else
+ bt_link_info->sco_only = false;
+
+ /* check if A2dp only*/
+ if (!bt_link_info->sco_exist &&
+ bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist &&
+ !bt_link_info->hid_exist)
+ bt_link_info->a2dp_only = true;
+ else
+ bt_link_info->a2dp_only = false;
+
+ /* check if Pan only*/
+ if (!bt_link_info->sco_exist &&
+ !bt_link_info->a2dp_exist &&
+ bt_link_info->pan_exist &&
+ !bt_link_info->hid_exist)
+ bt_link_info->pan_only = true;
+ else
+ bt_link_info->pan_only = false;
+
+ /* check if Hid only*/
+ if (!bt_link_info->sco_exist &&
+ !bt_link_info->a2dp_exist &&
+ !bt_link_info->pan_exist &&
+ bt_link_info->hid_exist)
+ bt_link_info->hid_only = true;
+ else
+ bt_link_info->hid_only = false;
+}
+
+static u8 halbtc8821a1ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool bt_hs_on = false;
+ u8 algorithm = BT_8821A_1ANT_COEX_ALGO_UNDEFINED;
+ u8 num_of_diff_profile = 0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ if (!bt_link_info->bt_link_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], No BT link exists!!!\n");
+ return algorithm;
+ }
+
+ if (bt_link_info->sco_exist)
+ num_of_diff_profile++;
+ if (bt_link_info->hid_exist)
+ num_of_diff_profile++;
+ if (bt_link_info->pan_exist)
+ num_of_diff_profile++;
+ if (bt_link_info->a2dp_exist)
+ num_of_diff_profile++;
+
+ if (num_of_diff_profile == 1) {
+ if (bt_link_info->sco_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO only\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_SCO;
+ } else {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID only\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = A2DP only\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_A2DP;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = PAN(HS) only\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = PAN(EDR) only\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR;
+ }
+ }
+ }
+ } else if (num_of_diff_profile == 2) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_SCO;
+ } else if (bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + PAN(HS)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + PAN(EDR)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + A2DP\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP;
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + PAN(HS)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + PAN(EDR)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = A2DP + PAN(HS)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = A2DP + PAN(EDR)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP;
+ }
+ }
+ }
+ } else if (num_of_diff_profile == 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID;
+ } else if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR;
+ }
+ }
+ }
+ } else if (num_of_diff_profile >= 3) {
+ if (bt_link_info->sco_exist) {
+ if (bt_link_info->hid_exist &&
+ bt_link_info->pan_exist &&
+ bt_link_info->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n");
+
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n");
+ algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ }
+ }
+ return algorithm;
+}
+
+static void halbtc8821a1ant_set_bt_auto_report(struct btc_coexist *btcoexist,
+ bool enable_auto_report)
+{
+ u8 h2c_parameter[1] = {0};
+
+ h2c_parameter[0] = 0;
+
+ if (enable_auto_report)
+ h2c_parameter[0] |= BIT0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n",
+ (enable_auto_report ? "Enabled!!" : "Disabled!!"),
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter);
+}
+
+static void halbtc8821a1ant_bt_auto_report(struct btc_coexist *btcoexist,
+ bool force_exec,
+ bool enable_auto_report)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW, "[BTCoex], %s BT Auto report = %s\n",
+ (force_exec ? "force to" : ""), ((enable_auto_report) ?
+ "Enabled" : "Disabled"));
+ coex_dm->cur_bt_auto_report = enable_auto_report;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_bt_auto_report = %d, cur_bt_auto_report = %d\n",
+ coex_dm->pre_bt_auto_report,
+ coex_dm->cur_bt_auto_report);
+
+ if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report)
+ return;
+ }
+ halbtc8821a1ant_set_bt_auto_report(btcoexist, coex_dm->cur_bt_auto_report);
+
+ coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report;
+}
+
+static void btc8821a1ant_set_sw_pen_tx_rate(struct btc_coexist *btcoexist,
+ bool low_penalty_ra)
+{
+ u8 h2c_parameter[6] = {0};
+
+ h2c_parameter[0] = 0x6; /* opCode, 0x6= Retry_Penalty*/
+
+ if (low_penalty_ra) {
+ h2c_parameter[1] |= BIT0;
+ /*normal rate except MCS7/6/5, OFDM54/48/36*/
+ h2c_parameter[2] = 0x00;
+ h2c_parameter[3] = 0xf7; /*MCS7 or OFDM54*/
+ h2c_parameter[4] = 0xf8; /*MCS6 or OFDM48*/
+ h2c_parameter[5] = 0xf9; /*MCS5 or OFDM36*/
+ }
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set WiFi Low-Penalty Retry: %s",
+ (low_penalty_ra ? "ON!!" : "OFF!!"));
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter);
+}
+
+static void halbtc8821a1ant_low_penalty_ra(struct btc_coexist *btcoexist,
+ bool force_exec, bool low_penalty_ra)
+{
+ coex_dm->cur_low_penalty_ra = low_penalty_ra;
+
+ if (!force_exec) {
+ if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra)
+ return;
+ }
+ btc8821a1ant_set_sw_pen_tx_rate(btcoexist, coex_dm->cur_low_penalty_ra);
+
+ coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra;
+}
+
+static void halbtc8821a1ant_set_coex_table(struct btc_coexist *btcoexist,
+ u32 val0x6c0, u32 val0x6c4,
+ u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc);
+ btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void halbtc8821a1ant_coex_table(struct btc_coexist *btcoexist,
+ bool force_exec, u32 val0x6c0,
+ u32 val0x6c4, u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n",
+ (force_exec ? "force to" : ""), val0x6c0, val0x6c4,
+ val0x6c8, val0x6cc);
+ coex_dm->cur_val_0x6c0 = val0x6c0;
+ coex_dm->cur_val_0x6c4 = val0x6c4;
+ coex_dm->cur_val_0x6c8 = val0x6c8;
+ coex_dm->cur_val_0x6cc = val0x6cc;
+
+ if (!force_exec) {
+ if ((coex_dm->pre_val_0x6c0 == coex_dm->cur_val_0x6c0) &&
+ (coex_dm->pre_val_0x6c4 == coex_dm->cur_val_0x6c4) &&
+ (coex_dm->pre_val_0x6c8 == coex_dm->cur_val_0x6c8) &&
+ (coex_dm->pre_val_0x6cc == coex_dm->cur_val_0x6cc))
+ return;
+ }
+ halbtc8821a1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4,
+ val0x6c8, val0x6cc);
+
+ coex_dm->pre_val_0x6c0 = coex_dm->cur_val_0x6c0;
+ coex_dm->pre_val_0x6c4 = coex_dm->cur_val_0x6c4;
+ coex_dm->pre_val_0x6c8 = coex_dm->cur_val_0x6c8;
+ coex_dm->pre_val_0x6cc = coex_dm->cur_val_0x6cc;
+}
+
+static void halbtc8821a1ant_coex_table_with_type(struct btc_coexist *btcoexist,
+ bool force_exec, u8 type)
+{
+ switch (type) {
+ case 0:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0x55555555, 0xffffff, 0x3);
+ break;
+ case 1:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec,
+ 0x55555555, 0x5a5a5a5a,
+ 0xffffff, 0x3);
+ break;
+ case 2:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+ 0x5a5a5a5a, 0xffffff, 0x3);
+ break;
+ case 3:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x55555555,
+ 0xaaaaaaaa, 0xffffff, 0x3);
+ break;
+ case 4:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0xffffffff,
+ 0xffffffff, 0xffffff, 0x3);
+ break;
+ case 5:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x5fff5fff,
+ 0x5fff5fff, 0xffffff, 0x3);
+ break;
+ case 6:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+ 0x5a5a5a5a, 0xffffff, 0x3);
+ break;
+ case 7:
+ halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x5afa5afa,
+ 0x5afa5afa, 0xffffff, 0x3);
+ break;
+ default:
+ break;
+ }
+}
+
+static void btc8821a1ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoexist,
+ bool enable)
+{
+ u8 h2c_parameter[1] = {0};
+
+ if (enable)
+ h2c_parameter[0] |= BIT0; /* function enable*/
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter);
+}
+
+static void halbtc8821a1ant_ignore_wlan_act(struct btc_coexist *btcoexist,
+ bool force_exec, bool enable)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn Ignore WlanAct %s\n",
+ (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+ coex_dm->cur_ignore_wlan_act = enable;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_ignore_wlan_act = %d, cur_ignore_wlan_act = %d!!\n",
+ coex_dm->pre_ignore_wlan_act,
+ coex_dm->cur_ignore_wlan_act);
+
+ if (coex_dm->pre_ignore_wlan_act ==
+ coex_dm->cur_ignore_wlan_act)
+ return;
+ }
+ btc8821a1ant_set_fw_ignore_wlan_act(btcoexist, enable);
+
+ coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void halbtc8821a1ant_set_fw_pstdma(struct btc_coexist *btcoexist,
+ u8 byte1, u8 byte2, u8 byte3,
+ u8 byte4, u8 byte5)
+{
+ u8 h2c_parameter[5] = {0};
+
+ h2c_parameter[0] = byte1;
+ h2c_parameter[1] = byte2;
+ h2c_parameter[2] = byte3;
+ h2c_parameter[3] = byte4;
+ h2c_parameter[4] = byte5;
+
+ coex_dm->ps_tdma_para[0] = byte1;
+ coex_dm->ps_tdma_para[1] = byte2;
+ coex_dm->ps_tdma_para[2] = byte3;
+ coex_dm->ps_tdma_para[3] = byte4;
+ coex_dm->ps_tdma_para[4] = byte5;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], PS-TDMA H2C cmd =0x%x%08x\n",
+ h2c_parameter[0],
+ h2c_parameter[1]<<24 |
+ h2c_parameter[2]<<16 |
+ h2c_parameter[3]<<8 |
+ h2c_parameter[4]);
+ btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void halbtc8821a1ant_set_lps_rpwm(struct btc_coexist *btcoexist,
+ u8 lps_val, u8 rpwm_val)
+{
+ u8 lps = lps_val;
+ u8 rpwm = rpwm_val;
+
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps);
+ btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm);
+}
+
+static void halbtc8821a1ant_lps_rpwm(struct btc_coexist *btcoexist,
+ bool force_exec, u8 lps_val, u8 rpwm_val)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s set lps/rpwm = 0x%x/0x%x\n",
+ (force_exec ? "force to" : ""), lps_val, rpwm_val);
+ coex_dm->cur_lps = lps_val;
+ coex_dm->cur_rpwm = rpwm_val;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], LPS-RxBeaconMode = 0x%x, LPS-RPWM = 0x%x!!\n",
+ coex_dm->cur_lps, coex_dm->cur_rpwm);
+
+ if ((coex_dm->pre_lps == coex_dm->cur_lps) &&
+ (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], LPS-RPWM_Last = 0x%x, LPS-RPWM_Now = 0x%x!!\n",
+ coex_dm->pre_rpwm, coex_dm->cur_rpwm);
+
+ return;
+ }
+ }
+ halbtc8821a1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val);
+
+ coex_dm->pre_lps = coex_dm->cur_lps;
+ coex_dm->pre_rpwm = coex_dm->cur_rpwm;
+}
+
+static void halbtc8821a1ant_sw_mechanism(struct btc_coexist *btcoexist,
+ bool low_penalty_ra)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], SM[LpRA] = %d\n", low_penalty_ra);
+
+ halbtc8821a1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra);
+}
+
+static void halbtc8821a1ant_set_ant_path(struct btc_coexist *btcoexist,
+ u8 ant_pos_type, bool init_hw_cfg,
+ bool wifi_off)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ u32 u4_tmp = 0;
+ u8 h2c_parameter[2] = {0};
+
+ if (init_hw_cfg) {
+ /* 0x4c[23] = 0, 0x4c[24] = 1 Antenna control by WL/BT*/
+ u4_tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u4_tmp &= ~BIT23;
+ u4_tmp |= BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u4_tmp);
+
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x975, 0x3, 0x3);
+ btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77);
+
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
+ /*tell firmware "antenna inverse" ==>
+ * WRONG firmware antenna control code.==>need fw to fix
+ */
+ h2c_parameter[0] = 1;
+ h2c_parameter[1] = 1;
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ /*Main Ant to BT for IPS case 0x4c[23] = 1*/
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64,
+ 0x1, 0x1);
+ } else {
+ /*tell firmware "no antenna inverse" ==>
+ * WRONG firmware antenna control code.==>need fw to fix
+ */
+ h2c_parameter[0] = 0;
+ h2c_parameter[1] = 1;
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ /*Aux Ant to BT for IPS case 0x4c[23] = 1*/
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64,
+ 0x1, 0x0);
+ }
+ } else if (wifi_off) {
+ /* 0x4c[24:23] = 00, Set Antenna control
+ * by BT_RFE_CTRL BT Vendor 0xac = 0xf002
+ */
+ u4_tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u4_tmp &= ~BIT23;
+ u4_tmp &= ~BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u4_tmp);
+ }
+
+ /* ext switch setting*/
+ switch (ant_pos_type) {
+ case BTC_ANT_PATH_WIFI:
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+ 0x30, 0x1);
+ else
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+ 0x30, 0x2);
+ break;
+ case BTC_ANT_PATH_BT:
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+ 0x30, 0x2);
+ else
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+ 0x30, 0x1);
+ break;
+ default:
+ case BTC_ANT_PATH_PTA:
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+ 0x30, 0x1);
+ else
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+ 0x30, 0x2);
+ break;
+ }
+}
+
+static void halbtc8821a1ant_ps_tdma(struct btc_coexist *btcoexist,
+ bool force_exec, bool turn_on, u8 type)
+{
+ u8 rssi_adjust_val = 0;
+
+ coex_dm->cur_ps_tdma_on = turn_on;
+ coex_dm->cur_ps_tdma = type;
+
+ if (!force_exec) {
+ if (coex_dm->cur_ps_tdma_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], ********** TDMA(on, %d) **********\n",
+ coex_dm->cur_ps_tdma);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], ********** TDMA(off, %d) **********\n",
+ coex_dm->cur_ps_tdma);
+ }
+ if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+ (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+ return;
+ }
+ if (turn_on) {
+ switch (type) {
+ default:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x1a,
+ 0x1a, 0x0, 0x50);
+ break;
+ case 1:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x3a,
+ 0x03, 0x10, 0x50);
+ rssi_adjust_val = 11;
+ break;
+ case 2:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x2b,
+ 0x03, 0x10, 0x50);
+ rssi_adjust_val = 14;
+ break;
+ case 3:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x1d,
+ 0x1d, 0x0, 0x10);
+ break;
+ case 4:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x15,
+ 0x3, 0x14, 0x0);
+ rssi_adjust_val = 17;
+ break;
+ case 5:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x15,
+ 0x3, 0x11, 0x10);
+ break;
+ case 6:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa,
+ 0x3, 0x0, 0x0);
+ break;
+ case 7:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xc,
+ 0x5, 0x0, 0x0);
+ break;
+ case 8:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x25,
+ 0x3, 0x10, 0x0);
+ break;
+ case 9:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x21,
+ 0x3, 0x10, 0x50);
+ rssi_adjust_val = 18;
+ break;
+ case 10:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa,
+ 0xa, 0x0, 0x40);
+ break;
+ case 11:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x14,
+ 0x03, 0x10, 0x10);
+ rssi_adjust_val = 20;
+ break;
+ case 12:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x0a,
+ 0x0a, 0x0, 0x50);
+ break;
+ case 13:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x18,
+ 0x18, 0x0, 0x10);
+ break;
+ case 14:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x21,
+ 0x3, 0x10, 0x10);
+ break;
+ case 15:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa,
+ 0x3, 0x8, 0x0);
+ break;
+ case 16:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x15,
+ 0x3, 0x10, 0x0);
+ rssi_adjust_val = 18;
+ break;
+ case 18:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x25,
+ 0x3, 0x10, 0x0);
+ rssi_adjust_val = 14;
+ break;
+ case 20:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x35,
+ 0x03, 0x11, 0x10);
+ break;
+ case 21:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x15,
+ 0x03, 0x11, 0x10);
+ break;
+ case 22:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x25,
+ 0x03, 0x11, 0x10);
+ break;
+ case 23:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x25,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 24:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x15,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 25:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0xa,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 26:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0xa,
+ 0x3, 0x31, 0x18);
+ rssi_adjust_val = 22;
+ break;
+ case 27:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x25,
+ 0x3, 0x31, 0x98);
+ rssi_adjust_val = 22;
+ break;
+ case 28:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x69, 0x25,
+ 0x3, 0x31, 0x0);
+ break;
+ case 29:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xab, 0x1a,
+ 0x1a, 0x1, 0x10);
+ break;
+ case 30:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x14,
+ 0x3, 0x10, 0x50);
+ break;
+ case 31:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xd3, 0x1a,
+ 0x1a, 0, 0x58);
+ break;
+ case 32:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0xa,
+ 0x3, 0x10, 0x0);
+ break;
+ case 33:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xa3, 0x25,
+ 0x3, 0x30, 0x90);
+ break;
+ case 34:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x53, 0x1a,
+ 0x1a, 0x0, 0x10);
+ break;
+ case 35:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x63, 0x1a,
+ 0x1a, 0x0, 0x10);
+ break;
+ case 36:
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xd3, 0x12,
+ 0x3, 0x14, 0x50);
+ break;
+ }
+ } else {
+ /* disable PS tdma*/
+ switch (type) {
+ case 8: /*PTA Control*/
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x8, 0x0, 0x0,
+ 0x0, 0x0);
+ halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA,
+ false, false);
+ break;
+ case 0:
+ default: /*Software control, Antenna at BT side*/
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x0, 0x0);
+ halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT,
+ false, false);
+ break;
+ case 9: /*Software control, Antenna at WiFi side*/
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x0, 0x0);
+ halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI,
+ false, false);
+ break;
+ case 10: /* under 5G*/
+ halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x8, 0x0);
+ halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT,
+ false, false);
+ break;
+ }
+ }
+ rssi_adjust_val = 0;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssi_adjust_val);
+
+ /* update pre state*/
+ coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+ coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static bool halbtc8821a1ant_is_common_action(struct btc_coexist *btcoexist)
+{
+ bool common = false, wifi_connected = false, wifi_busy = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+ if (!wifi_connected &&
+ BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n");
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+ common = true;
+ } else if (wifi_connected &&
+ (BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi connected + BT non connected-idle!!\n");
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+ common = true;
+ } else if (!wifi_connected &&
+ (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n");
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+ common = true;
+ } else if (wifi_connected &&
+ (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi connected + BT connected-idle!!\n");
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+ common = true;
+ } else if (!wifi_connected &&
+ (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE !=
+ coex_dm->bt_status)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi non connected-idle + BT Busy!!\n");
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+ common = true;
+ } else {
+ if (wifi_busy) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Connected-Busy + BT Busy!!\n");
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Connected-Idle + BT Busy!!\n");
+ }
+
+ common = false;
+ }
+
+ return common;
+}
+
+static void btc8821a1ant_tdma_dur_adj(struct btc_coexist *btcoexist,
+ u8 wifi_status)
+{
+ static long up, dn, m, n, wait_count;
+ /*0: no change, +1: increase WiFi duration, -1: decrease WiFi duration*/
+ long result;
+ u8 retry_count = 0, bt_info_ext;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], TdmaDurationAdjustForAcl()\n");
+
+ if ((BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN ==
+ wifi_status) ||
+ (BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN ==
+ wifi_status) ||
+ (BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT ==
+ wifi_status)) {
+ if (coex_dm->cur_ps_tdma != 1 &&
+ coex_dm->cur_ps_tdma != 2 &&
+ coex_dm->cur_ps_tdma != 3 &&
+ coex_dm->cur_ps_tdma != 9) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+
+ up = 0;
+ dn = 0;
+ m = 1;
+ n = 3;
+ result = 0;
+ wait_count = 0;
+ }
+ return;
+ }
+
+ if (!coex_dm->auto_tdma_adjust) {
+ coex_dm->auto_tdma_adjust = true;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], first run TdmaDurationAdjust()!!\n");
+
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2);
+ coex_dm->tdma_adj_type = 2;
+ /*============*/
+ up = 0;
+ dn = 0;
+ m = 1;
+ n = 3;
+ result = 0;
+ wait_count = 0;
+ } else {
+ /*accquire the BT TRx retry count from BT_Info byte2*/
+ retry_count = coex_sta->bt_retry_cnt;
+ bt_info_ext = coex_sta->bt_info_ext;
+ result = 0;
+ wait_count++;
+
+ if (retry_count == 0) {
+ /* no retry in the last 2-second duration*/
+ up++;
+ dn--;
+
+ if (dn <= 0)
+ dn = 0;
+
+ if (up >= n) {
+ /* if (retry count == 0) for 2*n seconds ,
+ * make WiFi duration wider
+ */
+ wait_count = 0;
+ n = 3;
+ up = 0;
+ dn = 0;
+ result = 1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Increase wifi duration!!\n");
+ }
+ } else if (retry_count <= 3) {
+ /* <=3 retry in the last 2-second duration*/
+ up--;
+ dn++;
+
+ if (up <= 0)
+ up = 0;
+
+ if (dn == 2) {
+ /* if retry count< 3 for 2*2 seconds,
+ * shrink wifi duration
+ */
+ if (wait_count <= 2)
+ m++; /* avoid bounce in two levels */
+ else
+ m = 1;
+
+ if (m >= 20) {
+ /* m max value is 20, max time is 120 s,
+ * recheck if adjust WiFi duration.
+ */
+ m = 20;
+ }
+ n = 3*m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration for retryCounter<3!!\n");
+ }
+ } else {
+ /* retry count > 3, if retry count > 3 happens once,
+ * shrink WiFi duration
+ */
+ if (wait_count == 1)
+ m++; /* avoid bounce in two levels */
+ else
+ m = 1;
+ /* m max value is 20, max time is 120 second,
+ * recheck if adjust WiFi duration.
+ */
+ if (m >= 20)
+ m = 20;
+
+ n = 3*m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration for retryCounter>3!!\n");
+ }
+
+ if (result == -1) {
+ if ((BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) &&
+ ((coex_dm->cur_ps_tdma == 1) ||
+ (coex_dm->cur_ps_tdma == 2))) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ } else if (result == 1) {
+ if ((BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) &&
+ ((coex_dm->cur_ps_tdma == 1) ||
+ (coex_dm->cur_ps_tdma == 2))) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ }
+ } else {
+ /*no change*/
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], ********** TDMA(on, %d) **********\n",
+ coex_dm->cur_ps_tdma);
+ }
+
+ if (coex_dm->cur_ps_tdma != 1 &&
+ coex_dm->cur_ps_tdma != 2 &&
+ coex_dm->cur_ps_tdma != 9 &&
+ coex_dm->cur_ps_tdma != 11) {
+ /* recover to previous adjust type*/
+ halbtc8821a1ant_ps_tdma(btcoexist,
+ NORMAL_EXEC, true,
+ coex_dm->tdma_adj_type);
+ }
+ }
+}
+
+static void btc8821a1ant_ps_tdma_check_for_pwr_save(struct btc_coexist *btcoex,
+ bool new_ps_state)
+{
+ u8 lps_mode = 0x0;
+
+ btcoex->btc_get(btcoex, BTC_GET_U1_LPS_MODE, &lps_mode);
+
+ if (lps_mode) {
+ /* already under LPS state*/
+ if (new_ps_state) {
+ /* keep state under LPS, do nothing.*/
+ } else {
+ /* will leave LPS state, turn off psTdma first*/
+ halbtc8821a1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 0);
+ }
+ } else {
+ /* NO PS state*/
+ if (new_ps_state) {
+ /* will enter LPS state, turn off psTdma first*/
+ halbtc8821a1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 0);
+ } else {
+ /* keep state under NO PS state, do nothing.*/
+ }
+ }
+}
+
+static void halbtc8821a1ant_power_save_state(struct btc_coexist *btcoexist,
+ u8 ps_type, u8 lps_val,
+ u8 rpwm_val)
+{
+ bool low_pwr_disable = false;
+
+ switch (ps_type) {
+ case BTC_PS_WIFI_NATIVE:
+ /* recover to original 32k low power setting*/
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL);
+ break;
+ case BTC_PS_LPS_ON:
+ btc8821a1ant_ps_tdma_check_for_pwr_save(btcoexist,
+ true);
+ halbtc8821a1ant_lps_rpwm(btcoexist,
+ NORMAL_EXEC, lps_val, rpwm_val);
+ /* when coex force to enter LPS, do not enter 32k low power.*/
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+ /* power save must executed before psTdma.*/
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL);
+ break;
+ case BTC_PS_LPS_OFF:
+ btc8821a1ant_ps_tdma_check_for_pwr_save(btcoexist, false);
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+static void halbtc8821a1ant_coex_under_5g(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ halbtc8821a1ant_ignore_wlan_act(btcoexist, NORMAL_EXEC, true);
+
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 10);
+
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0);
+
+ halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+
+ halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 5);
+}
+
+static void halbtc8821a1ant_action_wifi_only(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0);
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9);
+}
+
+static void btc8821a1ant_mon_bt_en_dis(struct btc_coexist *btcoexist)
+{
+ static bool pre_bt_disabled;
+ static u32 bt_disable_cnt;
+ bool bt_active = true, bt_disabled = false;
+
+ /* This function check if bt is disabled*/
+
+ if (coex_sta->high_priority_tx == 0 &&
+ coex_sta->high_priority_rx == 0 &&
+ coex_sta->low_priority_tx == 0 &&
+ coex_sta->low_priority_rx == 0) {
+ bt_active = false;
+ }
+ if (coex_sta->high_priority_tx == 0xffff &&
+ coex_sta->high_priority_rx == 0xffff &&
+ coex_sta->low_priority_tx == 0xffff &&
+ coex_sta->low_priority_rx == 0xffff) {
+ bt_active = false;
+ }
+ if (bt_active) {
+ bt_disable_cnt = 0;
+ bt_disabled = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+ &bt_disabled);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is enabled !!\n");
+ } else {
+ bt_disable_cnt++;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], bt all counters = 0, %d times!!\n",
+ bt_disable_cnt);
+ if (bt_disable_cnt >= 2) {
+ bt_disabled = true;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+ &bt_disabled);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is disabled !!\n");
+ halbtc8821a1ant_action_wifi_only(btcoexist);
+ }
+ }
+ if (pre_bt_disabled != bt_disabled) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is from %s to %s!!\n",
+ (pre_bt_disabled ? "disabled" : "enabled"),
+ (bt_disabled ? "disabled" : "enabled"));
+ pre_bt_disabled = bt_disabled;
+ if (bt_disabled) {
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS,
+ NULL);
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS,
+ NULL);
+ }
+ }
+}
+
+/*=============================================*/
+/**/
+/* Software Coex Mechanism start*/
+/**/
+/*=============================================*/
+
+/* SCO only or SCO+PAN(HS)*/
+static void halbtc8821a1ant_action_sco(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+static void halbtc8821a1ant_action_hid(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS)*/
+static void halbtc8821a1ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8821a1ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8821a1ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+/*PAN(HS) only*/
+static void halbtc8821a1ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+/*PAN(EDR)+A2DP*/
+static void halbtc8821a1ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8821a1ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+/* HID+A2DP+PAN(EDR)*/
+static void btc8821a1ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+static void halbtc8821a1ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+/*=============================================*/
+/**/
+/* Non-Software Coex Mechanism start*/
+/**/
+/*=============================================*/
+
+static void halbtc8821a1ant_action_hs(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 2);
+}
+
+static void halbtc8821a1ant_action_bt_inquiry(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool wifi_connected = false;
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+
+ if (!wifi_connected) {
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ } else if ((bt_link_info->sco_exist) ||
+ (bt_link_info->hid_only)) {
+ /* SCO/HID-only busy*/
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ } else {
+ halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_LPS_ON,
+ 0x50, 0x4);
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ }
+}
+
+static void btc8821a1ant_act_bt_sco_hid_only_busy(struct btc_coexist *btcoexist,
+ u8 wifi_status) {
+ /* tdma and coex table*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+
+ if (BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN ==
+ wifi_status)
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ else
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+}
+
+static void btc8821a1ant_act_wifi_con_bt_acl_busy(struct btc_coexist *btcoexist,
+ u8 wifi_status)
+{
+ u8 bt_rssi_state;
+
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+ bt_rssi_state = halbtc8821a1ant_bt_rssi_state(2, 28, 0);
+
+ if (bt_link_info->hid_only) {
+ /*HID*/
+ btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist,
+ wifi_status);
+ coex_dm->auto_tdma_adjust = false;
+ return;
+ } else if (bt_link_info->a2dp_only) {
+ /*A2DP*/
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a1ant_tdma_dur_adj(btcoexist, wifi_status);
+ } else {
+ /*for low BT RSSI*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->auto_tdma_adjust = false;
+ }
+
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ } else if (bt_link_info->hid_exist && bt_link_info->a2dp_exist) {
+ /*HID+A2DP*/
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->auto_tdma_adjust = false;
+ } else {
+ /*for low BT RSSI*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->auto_tdma_adjust = false;
+ }
+
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ } else if ((bt_link_info->pan_only) ||
+ (bt_link_info->hid_exist && bt_link_info->pan_exist)) {
+ /*PAN(OPP, FTP), HID+PAN(OPP, FTP)*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ coex_dm->auto_tdma_adjust = false;
+ } else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) ||
+ (bt_link_info->hid_exist && bt_link_info->a2dp_exist &&
+ bt_link_info->pan_exist)) {
+ /*A2DP+PAN(OPP, FTP), HID+A2DP+PAN(OPP, FTP)*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ coex_dm->auto_tdma_adjust = false;
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ coex_dm->auto_tdma_adjust = false;
+ }
+}
+
+static void halbtc8821a1ant_action_wifi_not_connected(
+ struct btc_coexist *btcoexist)
+{
+ /* power save state*/
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+
+ /* tdma and coex table*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0);
+}
+
+static void btc8821a1ant_act_wifi_not_conn_scan(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+}
+
+static void halbtc8821a1ant_action_wifi_connected_scan(
+ struct btc_coexist *btcoexist) {
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+ /* power save state*/
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+
+ /* tdma and coex table*/
+ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 22);
+ halbtc8821a1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ }
+ } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY ==
+ coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)) {
+ btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN);
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ }
+}
+
+static void btc8821a1ant_act_wifi_conn_sp_pkt(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool hs_connecting = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting);
+
+ halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ /* tdma and coex table*/
+ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 22);
+ halbtc8821a1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 20);
+ halbtc8821a1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 1);
+ }
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+ }
+}
+
+static void halbtc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist)
+{
+ bool wifi_busy = false;
+ bool scan = false, link = false, roam = false;
+ bool under_4way = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], CoexForWifiConnect()===>\n");
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_4_WAY_PROGRESS, &under_4way);
+ if (under_4way) {
+ btc8821a1ant_act_wifi_conn_sp_pkt(btcoexist);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n");
+ return;
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+ if (scan || link || roam) {
+ halbtc8821a1ant_action_wifi_connected_scan(btcoexist);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n");
+ return;
+ }
+
+ /* power save state*/
+ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY ==
+ coex_dm->bt_status && !btcoexist->bt_link_info.hid_only)
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_LPS_ON, 0x50, 0x4);
+ else
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+
+ /* tdma and coex table*/
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ if (!wifi_busy) {
+ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ btc8821a1ant_act_wifi_con_bt_acl_busy(btcoexist,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE);
+ } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY ==
+ coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)) {
+ btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE);
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ halbtc8821a1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 2);
+ }
+ } else {
+ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+ btc8821a1ant_act_wifi_con_bt_acl_busy(btcoexist,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY);
+ } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY ==
+ coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+ coex_dm->bt_status)) {
+ btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY);
+ } else {
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ halbtc8821a1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 2);
+ }
+ }
+}
+
+static void btc8821a1ant_run_sw_coex_mech(struct btc_coexist *btcoexist)
+{
+ u8 algorithm = 0;
+
+ algorithm = halbtc8821a1ant_action_algorithm(btcoexist);
+ coex_dm->cur_algorithm = algorithm;
+
+ if (!halbtc8821a1ant_is_common_action(btcoexist)) {
+ switch (coex_dm->cur_algorithm) {
+ case BT_8821A_1ANT_COEX_ALGO_SCO:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = SCO.\n");
+ halbtc8821a1ant_action_sco(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HID.\n");
+ halbtc8821a1ant_action_hid(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = A2DP.\n");
+ halbtc8821a1ant_action_a2dp(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = A2DP+PAN(HS).\n");
+ halbtc8821a1ant_action_a2dp_pan_hs(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = PAN(EDR).\n");
+ halbtc8821a1ant_action_pan_edr(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HS mode.\n");
+ halbtc8821a1ant_action_pan_hs(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = PAN+A2DP.\n");
+ halbtc8821a1ant_action_pan_edr_a2dp(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_PANEDR_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = PAN(EDR)+HID.\n");
+ halbtc8821a1ant_action_pan_edr_hid(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HID+A2DP+PAN.\n");
+ btc8821a1ant_action_hid_a2dp_pan_edr(btcoexist);
+ break;
+ case BT_8821A_1ANT_COEX_ALGO_HID_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = HID+A2DP.\n");
+ halbtc8821a1ant_action_hid_a2dp(btcoexist);
+ break;
+ default:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action algorithm = coexist All Off!!\n");
+ /*halbtc8821a1ant_coex_all_off(btcoexist);*/
+ break;
+ }
+ coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+ }
+}
+
+static void halbtc8821a1ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ bool wifi_connected = false, bt_hs_on = false;
+ bool increase_scan_dev_num = false;
+ bool bt_ctrl_agg_buf_size = false;
+ u8 agg_buf_size = 5;
+ u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ bool wifi_under_5g = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism()===>\n");
+
+ if (btcoexist->manual_control) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n");
+ return;
+ }
+
+ if (btcoexist->stop_coex_dm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n");
+ return;
+ }
+
+ if (coex_sta->under_ips) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], wifi is under IPS !!!\n");
+ return;
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+ if (wifi_under_5g) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism(), return for 5G <===\n");
+ halbtc8821a1ant_coex_under_5g(btcoexist);
+ return;
+ }
+
+ if ((BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status))
+ increase_scan_dev_num = true;
+
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM,
+ &increase_scan_dev_num);
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+
+ if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) {
+ halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+ } else {
+ if (wifi_connected) {
+ wifi_rssi_state =
+ halbtc8821a1ant_WifiRssiState(btcoexist, 1, 2,
+ 30, 0);
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a1ant_limited_tx(btcoexist,
+ NORMAL_EXEC, 1, 1,
+ 1, 1);
+ } else {
+ halbtc8821a1ant_limited_tx(btcoexist,
+ NORMAL_EXEC, 1, 1,
+ 1, 1);
+ }
+ } else {
+ halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC,
+ 0, 0, 0, 0);
+ }
+ }
+
+ if (bt_link_info->sco_exist) {
+ bt_ctrl_agg_buf_size = true;
+ agg_buf_size = 0x3;
+ } else if (bt_link_info->hid_exist) {
+ bt_ctrl_agg_buf_size = true;
+ agg_buf_size = 0x5;
+ } else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) {
+ bt_ctrl_agg_buf_size = true;
+ agg_buf_size = 0x8;
+ }
+ halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+ bt_ctrl_agg_buf_size, agg_buf_size);
+
+ btc8821a1ant_run_sw_coex_mech(btcoexist);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8821a1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8821a1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (!wifi_connected) {
+ bool scan = false, link = false, roam = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], wifi is non connected-idle !!!\n");
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+ if (scan || link || roam)
+ btc8821a1ant_act_wifi_not_conn_scan(btcoexist);
+ else
+ halbtc8821a1ant_action_wifi_not_connected(btcoexist);
+ } else {
+ /* wifi LPS/Busy*/
+ halbtc8821a1ant_action_wifi_connected(btcoexist);
+ }
+}
+
+static void halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ /* force to reset coex mechanism*/
+ /* sw all off*/
+ halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+ halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8);
+ halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0);
+}
+
+static void halbtc8821a1ant_init_hw_config(struct btc_coexist *btcoexist,
+ bool back_up)
+{
+ u8 u1_tmp = 0;
+ bool wifi_under_5g = false;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], 1Ant Init HW Config!!\n");
+
+ if (back_up) {
+ coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist,
+ 0x430);
+ coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist,
+ 0x434);
+ coex_dm->backup_retry_limit =
+ btcoexist->btc_read_2byte(btcoexist, 0x42a);
+ coex_dm->backup_ampdu_max_time =
+ btcoexist->btc_read_1byte(btcoexist, 0x456);
+ }
+
+ /* 0x790[5:0] = 0x5*/
+ u1_tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+ u1_tmp &= 0xc0;
+ u1_tmp |= 0x5;
+ btcoexist->btc_write_1byte(btcoexist, 0x790, u1_tmp);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+
+ /*Antenna config*/
+ if (wifi_under_5g)
+ halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT,
+ true, false);
+ else
+ halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA,
+ true, false);
+ /* PTA parameter*/
+ halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0);
+
+ /* Enable counter statistics*/
+ /*0x76e[3] =1, WLAN_Act control by PTA*/
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+ btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
+}
+
+/*============================================================*/
+/* work around function start with wa_halbtc8821a1ant_*/
+/*============================================================*/
+/*============================================================*/
+/* extern function start with EXhalbtc8821a1ant_*/
+/*============================================================*/
+void ex_halbtc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+ halbtc8821a1ant_init_hw_config(btcoexist, true);
+}
+
+void ex_halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Coex Mechanism Init!!\n");
+
+ btcoexist->stop_coex_dm = false;
+
+ halbtc8821a1ant_init_coex_dm(btcoexist);
+
+ halbtc8821a1ant_query_bt_info(btcoexist);
+}
+
+void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ u8 u1_tmp[4], i, bt_info_ext, ps_tdma_case = 0;
+ u16 u2_tmp[4];
+ u32 u4_tmp[4];
+ bool roam = false, scan = false, link = false, wifi_under_5g = false;
+ bool bt_hs_on = false, wifi_busy = false;
+ long wifi_rssi = 0, bt_hs_rssi = 0;
+ u32 wifi_bw, wifi_traffic_dir;
+ u8 wifi_dot11_chnl, wifi_hs_chnl;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ============[BT Coexist info]============");
+
+ if (btcoexist->manual_control) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ============[Under Manual Control]============");
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ==========================================");
+ }
+ if (btcoexist->stop_coex_dm) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ============[Coex is STOPPED]============");
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ==========================================");
+ }
+
+ if (!board_info->bt_exist) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!");
+ return;
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d/ %d/ %d",
+ "Ant PG Num/ Ant Mech/ Ant Pos:",
+ board_info->pg_ant_num,
+ board_info->btdm_ant_num,
+ board_info->btdm_ant_pos);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %s / %d", "BT stack/ hci ext ver",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+ &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)",
+ "CoexVer/ FwVer/ PatchVer",
+ glcoex_ver_date_8821a_1ant,
+ glcoex_ver_8821a_1ant,
+ fw_ver, bt_patch_ver,
+ bt_patch_ver);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION,
+ &bt_hs_on);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL,
+ &wifi_dot11_chnl);
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL,
+ &wifi_hs_chnl);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d / %d(%d)",
+ "Dot11 channel / HsChnl(HsMode)",
+ wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %02x %02x %02x ",
+ "H2C Wifi inform bt chnl Info",
+ coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1],
+ coex_dm->wifi_chnl_info[2]);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi",
+ (int)wifi_rssi, (int)bt_hs_rssi);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan",
+ link, roam, scan);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G,
+ &wifi_under_5g);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW,
+ &wifi_bw);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY,
+ &wifi_busy);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
+ &wifi_traffic_dir);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %s / %s/ %s ", "Wifi status",
+ (wifi_under_5g ? "5G" : "2.4G"),
+ ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+ (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+ ((!wifi_busy) ? "idle" :
+ ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+ "uplink" : "downlink")));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]",
+ ((btcoexist->bt_info.bt_disabled) ? ("disabled") :
+ ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") :
+ ((BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+ coex_dm->bt_status) ?
+ "non-connected idle" :
+ ((BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE ==
+ coex_dm->bt_status) ?
+ "connected-idle" : "busy")))),
+ coex_sta->bt_rssi, coex_sta->bt_retry_cnt);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP",
+ bt_link_info->sco_exist,
+ bt_link_info->hid_exist,
+ bt_link_info->pan_exist,
+ bt_link_info->a2dp_exist);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO);
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %s",
+ "BT Info A2DP rate",
+ (bt_info_ext&BIT0) ?
+ "Basic rate" : "EDR rate");
+
+ for (i = 0; i < BT_INFO_SRC_8821A_1ANT_MAX; i++) {
+ if (coex_sta->bt_info_c2h_cnt[i]) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)",
+ glbt_info_src_8821a_1ant[i],
+ coex_sta->bt_info_c2h[i][0],
+ coex_sta->bt_info_c2h[i][1],
+ coex_sta->bt_info_c2h[i][2],
+ coex_sta->bt_info_c2h[i][3],
+ coex_sta->bt_info_c2h[i][4],
+ coex_sta->bt_info_c2h[i][5],
+ coex_sta->bt_info_c2h[i][6],
+ coex_sta->bt_info_c2h_cnt[i]);
+ }
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %s/%s, (0x%x/0x%x)",
+ "PS state, IPS/LPS, (lps/rpwm)",
+ ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+ ((coex_sta->under_Lps ? "LPS ON" : "LPS OFF")),
+ btcoexist->bt_info.lps_val,
+ btcoexist->bt_info.rpwm_val);
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+ if (!btcoexist->manual_control) {
+ /* Sw mechanism*/
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s", "============[Sw mechanism]============");
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d", "SM[LowPenaltyRA]",
+ coex_dm->cur_low_penalty_ra);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %s/ %s/ %d ",
+ "DelBA/ BtCtrlAgg/ AggSize",
+ (btcoexist->bt_info.reject_agg_pkt ? "Yes" : "No"),
+ (btcoexist->bt_info.bt_ctrl_buf_size ? "Yes" : "No"),
+ btcoexist->bt_info.agg_buf_size);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x ", "Rate Mask",
+ btcoexist->bt_info.ra_mask);
+
+ /* Fw mechanism*/
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+ "============[Fw mechanism]============");
+
+ ps_tdma_case = coex_dm->cur_ps_tdma;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)",
+ "PS TDMA",
+ coex_dm->ps_tdma_para[0],
+ coex_dm->ps_tdma_para[1],
+ coex_dm->ps_tdma_para[2],
+ coex_dm->ps_tdma_para[3],
+ coex_dm->ps_tdma_para[4],
+ ps_tdma_case,
+ coex_dm->auto_tdma_adjust);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x ",
+ "Latest error condition(should be 0)",
+ coex_dm->error_condition);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d ", "IgnWlanAct",
+ coex_dm->cur_ignore_wlan_act);
+ }
+
+ /* Hw setting*/
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s", "============[Hw setting]============");
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+ "backup ARFR1/ARFR2/RL/AMaxTime",
+ coex_dm->backup_arfr_cnt1,
+ coex_dm->backup_arfr_cnt2,
+ coex_dm->backup_retry_limit,
+ coex_dm->backup_ampdu_max_time);
+
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430);
+ u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434);
+ u2_tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a);
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+ "0x430/0x434/0x42a/0x456",
+ u4_tmp[0], u4_tmp[1], u2_tmp[0], u1_tmp[0]);
+
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc58);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x/ 0x%x", "0x778/ 0xc58[29:25]",
+ u1_tmp[0], (u4_tmp[0]&0x3e000000) >> 25);
+
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x", "0x8db[6:5]",
+ ((u1_tmp[0]&0x60)>>5));
+
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x975);
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0xcb4[29:28]/0xcb4[7:0]/0x974[9:8]",
+ (u4_tmp[0] & 0x30000000)>>28,
+ u4_tmp[0] & 0xff,
+ u1_tmp[0] & 0x3);
+
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u1_tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x64);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x40/0x4c[24:23]/0x64[0]",
+ u1_tmp[0], ((u4_tmp[0]&0x01800000)>>23), u1_tmp[1]&0x1);
+
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522",
+ u4_tmp[0], u1_tmp[0]);
+
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x", "0xc50(dig)",
+ u4_tmp[0]&0xff);
+
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48);
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5d);
+ u1_tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x/ 0x%x", "OFDM-FA/ CCK-FA",
+ u4_tmp[0], (u1_tmp[0]<<8) + u1_tmp[1]);
+
+ u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+ u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+ u4_tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+ u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
+ "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)",
+ u4_tmp[0], u4_tmp[1], u4_tmp[2], u1_tmp[0]);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)",
+ coex_sta->high_priority_rx, coex_sta->high_priority_tx);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)",
+ coex_sta->low_priority_rx, coex_sta->low_priority_tx);
+#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 1)
+ halbtc8821a1ant_monitor_bt_ctr(btcoexist);
+#endif
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+void ex_halbtc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm)
+ return;
+
+ if (BTC_IPS_ENTER == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS ENTER notify\n");
+ coex_sta->under_ips = true;
+ halbtc8821a1ant_set_ant_path(btcoexist,
+ BTC_ANT_PATH_BT, false, true);
+ /*set PTA control*/
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+ halbtc8821a1ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 0);
+ } else if (BTC_IPS_LEAVE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS LEAVE notify\n");
+ coex_sta->under_ips = false;
+
+ halbtc8821a1ant_run_coexist_mechanism(btcoexist);
+ }
+}
+
+void ex_halbtc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (btcoexist->manual_control || btcoexist->stop_coex_dm)
+ return;
+
+ if (BTC_LPS_ENABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS ENABLE notify\n");
+ coex_sta->under_Lps = true;
+ } else if (BTC_LPS_DISABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS DISABLE notify\n");
+ coex_sta->under_Lps = false;
+ }
+}
+
+void ex_halbtc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ bool wifi_connected = false, bt_hs_on = false;
+
+ if (btcoexist->manual_control ||
+ btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+
+ halbtc8821a1ant_query_bt_info(btcoexist);
+
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8821a1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8821a1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (BTC_SCAN_START == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN START notify\n");
+ if (!wifi_connected) {
+ /* non-connected scan*/
+ btc8821a1ant_act_wifi_not_conn_scan(btcoexist);
+ } else {
+ /* wifi is connected*/
+ halbtc8821a1ant_action_wifi_connected_scan(btcoexist);
+ }
+ } else if (BTC_SCAN_FINISH == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN FINISH notify\n");
+ if (!wifi_connected) {
+ /* non-connected scan*/
+ halbtc8821a1ant_action_wifi_not_connected(btcoexist);
+ } else {
+ halbtc8821a1ant_action_wifi_connected(btcoexist);
+ }
+ }
+}
+
+void ex_halbtc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ bool wifi_connected = false, bt_hs_on = false;
+
+ if (btcoexist->manual_control ||
+ btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8821a1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8821a1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (BTC_ASSOCIATE_START == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT START notify\n");
+ btc8821a1ant_act_wifi_not_conn_scan(btcoexist);
+ } else if (BTC_ASSOCIATE_FINISH == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT FINISH notify\n");
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+ if (!wifi_connected) {
+ /* non-connected scan*/
+ halbtc8821a1ant_action_wifi_not_connected(btcoexist);
+ } else {
+ halbtc8821a1ant_action_wifi_connected(btcoexist);
+ }
+ }
+}
+
+void ex_halbtc8821a1ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ u8 h2c_parameter[3] = {0};
+ u32 wifi_bw;
+ u8 wifi_central_chnl;
+
+ if (btcoexist->manual_control ||
+ btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ if (BTC_MEDIA_CONNECT == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA connect notify\n");
+ } else {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA disconnect notify\n");
+ }
+
+ /* only 2.4G we need to inform bt the chnl mask*/
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_U1_WIFI_CENTRAL_CHNL,
+ &wifi_central_chnl);
+ if ((BTC_MEDIA_CONNECT == type) &&
+ (wifi_central_chnl <= 14)) {
+ /*h2c_parameter[0] = 0x1;*/
+ h2c_parameter[0] = 0x0;
+ h2c_parameter[1] = wifi_central_chnl;
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw)
+ h2c_parameter[2] = 0x30;
+ else
+ h2c_parameter[2] = 0x20;
+ }
+
+ coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+ coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+ coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x66 = 0x%x\n",
+ h2c_parameter[0]<<16|h2c_parameter[1]<<8|h2c_parameter[2]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ bool bt_hs_on = false;
+
+ if (btcoexist->manual_control ||
+ btcoexist->stop_coex_dm ||
+ btcoexist->bt_info.bt_disabled)
+ return;
+
+ coex_sta->special_pkt_period_cnt = 0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ if (coex_sta->c2h_bt_inquiry_page) {
+ halbtc8821a1ant_action_bt_inquiry(btcoexist);
+ return;
+ } else if (bt_hs_on) {
+ halbtc8821a1ant_action_hs(btcoexist);
+ return;
+ }
+
+ if (BTC_PACKET_DHCP == type ||
+ BTC_PACKET_EAPOL == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], special Packet(%d) notify\n", type);
+ btc8821a1ant_act_wifi_conn_sp_pkt(btcoexist);
+ }
+}
+
+void ex_halbtc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmp_buf, u8 length)
+{
+ u8 bt_info = 0;
+ u8 i, rsp_source = 0;
+ bool wifi_connected = false;
+ bool bt_busy = false;
+ bool wifi_under_5g = false;
+
+ coex_sta->c2h_bt_info_req_sent = false;
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+
+ rsp_source = tmp_buf[0]&0xf;
+ if (rsp_source >= BT_INFO_SRC_8821A_1ANT_MAX)
+ rsp_source = BT_INFO_SRC_8821A_1ANT_WIFI_FW;
+ coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Bt info[%d], length = %d, hex data = [",
+ rsp_source, length);
+ for (i = 0; i < length; i++) {
+ coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i];
+ if (i == 1)
+ bt_info = tmp_buf[i];
+ if (i == length-1) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x]\n", tmp_buf[i]);
+ } else {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x, ", tmp_buf[i]);
+ }
+ }
+
+ if (BT_INFO_SRC_8821A_1ANT_WIFI_FW != rsp_source) {
+ coex_sta->bt_retry_cnt = /* [3:0]*/
+ coex_sta->bt_info_c2h[rsp_source][2]&0xf;
+
+ coex_sta->bt_rssi =
+ coex_sta->bt_info_c2h[rsp_source][3]*2+10;
+
+ coex_sta->bt_info_ext =
+ coex_sta->bt_info_c2h[rsp_source][4];
+
+ /* Here we need to resend some wifi info to BT*/
+ /* because bt is reset and loss of the info.*/
+ if (coex_sta->bt_info_ext & BIT1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n");
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ if (wifi_connected) {
+ ex_halbtc8821a1ant_media_status_notify(btcoexist,
+ BTC_MEDIA_CONNECT);
+ } else {
+ ex_halbtc8821a1ant_media_status_notify(btcoexist,
+ BTC_MEDIA_DISCONNECT);
+ }
+ }
+
+ if ((coex_sta->bt_info_ext & BIT3) && !wifi_under_5g) {
+ if (!btcoexist->manual_control &&
+ !btcoexist->stop_coex_dm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n");
+ halbtc8821a1ant_ignore_wlan_act(btcoexist,
+ FORCE_EXEC,
+ false);
+ }
+ }
+#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0)
+ if (!(coex_sta->bt_info_ext & BIT4)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT ext info bit4 check, set BT to enable Auto Report!!\n");
+ halbtc8821a1ant_bt_auto_report(btcoexist,
+ FORCE_EXEC, true);
+ }
+#endif
+ }
+
+ /* check BIT2 first ==> check if bt is under inquiry or page scan*/
+ if (bt_info & BT_INFO_8821A_1ANT_B_INQ_PAGE)
+ coex_sta->c2h_bt_inquiry_page = true;
+ else
+ coex_sta->c2h_bt_inquiry_page = false;
+
+ /* set link exist status*/
+ if (!(bt_info&BT_INFO_8821A_1ANT_B_CONNECTION)) {
+ coex_sta->bt_link_exist = false;
+ coex_sta->pan_exist = false;
+ coex_sta->a2dp_exist = false;
+ coex_sta->hid_exist = false;
+ coex_sta->sco_exist = false;
+ } else {
+ /* connection exists*/
+ coex_sta->bt_link_exist = true;
+ if (bt_info & BT_INFO_8821A_1ANT_B_FTP)
+ coex_sta->pan_exist = true;
+ else
+ coex_sta->pan_exist = false;
+ if (bt_info & BT_INFO_8821A_1ANT_B_A2DP)
+ coex_sta->a2dp_exist = true;
+ else
+ coex_sta->a2dp_exist = false;
+ if (bt_info & BT_INFO_8821A_1ANT_B_HID)
+ coex_sta->hid_exist = true;
+ else
+ coex_sta->hid_exist = false;
+ if (bt_info & BT_INFO_8821A_1ANT_B_SCO_ESCO)
+ coex_sta->sco_exist = true;
+ else
+ coex_sta->sco_exist = false;
+ }
+
+ halbtc8821a1ant_update_bt_link_info(btcoexist);
+
+ if (!(bt_info&BT_INFO_8821A_1ANT_B_CONNECTION)) {
+ coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n");
+ } else if (bt_info == BT_INFO_8821A_1ANT_B_CONNECTION) {
+ /* connection exists but no busy*/
+ coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n");
+ } else if ((bt_info&BT_INFO_8821A_1ANT_B_SCO_ESCO) ||
+ (bt_info&BT_INFO_8821A_1ANT_B_SCO_BUSY)) {
+ coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_SCO_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n");
+ } else if (bt_info&BT_INFO_8821A_1ANT_B_ACL_BUSY) {
+ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status)
+ coex_dm->auto_tdma_adjust = false;
+ coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_ACL_BUSY;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n");
+ } else {
+ coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_MAX;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n");
+ }
+
+ if ((BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+ (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status))
+ bt_busy = true;
+ else
+ bt_busy = false;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+ halbtc8821a1ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8821a1ant_halt_notify(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Halt notify\n");
+
+ btcoexist->stop_coex_dm = true;
+
+ halbtc8821a1ant_set_ant_path(btcoexist,
+ BTC_ANT_PATH_BT, false, true);
+ halbtc8821a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+
+ halbtc8821a1ant_power_save_state(btcoexist,
+ BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+ halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0);
+
+ ex_halbtc8821a1ant_media_status_notify(btcoexist,
+ BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Pnp notify\n");
+
+ if (BTC_WIFI_PNP_SLEEP == pnp_state) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Pnp notify to SLEEP\n");
+ btcoexist->stop_coex_dm = true;
+ halbtc8821a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+ halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+ 0x0, 0x0);
+ halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9);
+ } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Pnp notify to WAKE UP\n");
+ btcoexist->stop_coex_dm = false;
+ halbtc8821a1ant_init_hw_config(btcoexist, false);
+ halbtc8821a1ant_init_coex_dm(btcoexist);
+ halbtc8821a1ant_query_bt_info(btcoexist);
+ }
+}
+
+void
+ex_halbtc8821a1ant_periodical(
+ struct btc_coexist *btcoexist) {
+ static u8 dis_ver_info_cnt;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], ==========================Periodical===========================\n");
+
+ if (dis_ver_info_cnt <= 5) {
+ dis_ver_info_cnt += 1;
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ****************************************************************\n");
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n",
+ board_info->pg_ant_num,
+ board_info->btdm_ant_num,
+ board_info->btdm_ant_pos);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], BT stack/ hci ext ver = %s / %d\n",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+ &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
+ glcoex_ver_date_8821a_1ant,
+ glcoex_ver_8821a_1ant,
+ fw_ver, bt_patch_ver,
+ bt_patch_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ****************************************************************\n");
+ }
+
+#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0)
+ halbtc8821a1ant_query_bt_info(btcoexist);
+ halbtc8821a1ant_monitor_bt_ctr(btcoexist);
+ btc8821a1ant_mon_bt_en_dis(btcoexist);
+#else
+ if (halbtc8821a1ant_Is_wifi_status_changed(btcoexist) ||
+ coex_dm->auto_tdma_adjust) {
+ if (coex_sta->special_pkt_period_cnt > 2)
+ halbtc8821a1ant_run_coexist_mechanism(btcoexist);
+ }
+
+ coex_sta->special_pkt_period_cnt++;
+#endif
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h
new file mode 100644
index 00000000000..20e904890fc
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h
@@ -0,0 +1,188 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/*===========================================
+ * The following is for 8821A 1ANT BT Co-exist definition
+ *===========================================
+ */
+#define BT_AUTO_REPORT_ONLY_8821A_1ANT 0
+
+#define BT_INFO_8821A_1ANT_B_FTP BIT7
+#define BT_INFO_8821A_1ANT_B_A2DP BIT6
+#define BT_INFO_8821A_1ANT_B_HID BIT5
+#define BT_INFO_8821A_1ANT_B_SCO_BUSY BIT4
+#define BT_INFO_8821A_1ANT_B_ACL_BUSY BIT3
+#define BT_INFO_8821A_1ANT_B_INQ_PAGE BIT2
+#define BT_INFO_8821A_1ANT_B_SCO_ESCO BIT1
+#define BT_INFO_8821A_1ANT_B_CONNECTION BIT0
+
+#define BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \
+ (((_BT_INFO_EXT_&BIT0)) ? true : false)
+
+#define BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT 2
+
+enum _BT_INFO_SRC_8821A_1ANT {
+ BT_INFO_SRC_8821A_1ANT_WIFI_FW = 0x0,
+ BT_INFO_SRC_8821A_1ANT_BT_RSP = 0x1,
+ BT_INFO_SRC_8821A_1ANT_BT_ACTIVE_SEND = 0x2,
+ BT_INFO_SRC_8821A_1ANT_MAX
+};
+
+enum _BT_8821A_1ANT_BT_STATUS {
+ BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0,
+ BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1,
+ BT_8821A_1ANT_BT_STATUS_INQ_PAGE = 0x2,
+ BT_8821A_1ANT_BT_STATUS_ACL_BUSY = 0x3,
+ BT_8821A_1ANT_BT_STATUS_SCO_BUSY = 0x4,
+ BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5,
+ BT_8821A_1ANT_BT_STATUS_MAX
+};
+
+enum _BT_8821A_1ANT_WIFI_STATUS {
+ BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0,
+ BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT = 0x3,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4,
+ BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5,
+ BT_8821A_1ANT_WIFI_STATUS_MAX
+};
+
+enum BT_8821A_1ANT_COEX_ALGO {
+ BT_8821A_1ANT_COEX_ALGO_UNDEFINED = 0x0,
+ BT_8821A_1ANT_COEX_ALGO_SCO = 0x1,
+ BT_8821A_1ANT_COEX_ALGO_HID = 0x2,
+ BT_8821A_1ANT_COEX_ALGO_A2DP = 0x3,
+ BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS = 0x4,
+ BT_8821A_1ANT_COEX_ALGO_PANEDR = 0x5,
+ BT_8821A_1ANT_COEX_ALGO_PANHS = 0x6,
+ BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7,
+ BT_8821A_1ANT_COEX_ALGO_PANEDR_HID = 0x8,
+ BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9,
+ BT_8821A_1ANT_COEX_ALGO_HID_A2DP = 0xa,
+ BT_8821A_1ANT_COEX_ALGO_MAX = 0xb,
+};
+
+struct coex_dm_8821a_1ant {
+ /* fw mechanism */
+ bool cur_ignore_wlan_act;
+ bool pre_ignore_wlan_act;
+ u8 pre_ps_tdma;
+ u8 cur_ps_tdma;
+ u8 ps_tdma_para[5];
+ u8 tdma_adj_type;
+ bool auto_tdma_adjust;
+ bool pre_ps_tdma_on;
+ bool cur_ps_tdma_on;
+ bool pre_bt_auto_report;
+ bool cur_bt_auto_report;
+ u8 pre_lps;
+ u8 cur_lps;
+ u8 pre_rpwm;
+ u8 cur_rpwm;
+
+ /* sw mechanism */
+ bool pre_low_penalty_ra;
+ bool cur_low_penalty_ra;
+ u32 pre_val_0x6c0;
+ u32 cur_val_0x6c0;
+ u32 pre_val_0x6c4;
+ u32 cur_val_0x6c4;
+ u32 pre_val_0x6c8;
+ u32 cur_val_0x6c8;
+ u8 pre_val_0x6cc;
+ u8 cur_val_0x6cc;
+ /* Auto Rate Fallback Retry cnt */
+ u32 backup_arfr_cnt1;
+ /* Auto Rate Fallback Retry cnt */
+ u32 backup_arfr_cnt2;
+ u16 backup_retry_limit;
+ u8 backup_ampdu_max_time;
+
+ /* algorithm related */
+ u8 pre_algorithm;
+ u8 cur_algorithm;
+ u8 bt_status;
+ u8 wifi_chnl_info[3];
+
+ u32 pre_ra_mask;
+ u32 cur_ra_mask;
+ u8 pre_arfr_type;
+ u8 cur_arfr_type;
+ u8 pre_retry_limit_type;
+ u8 cur_retry_limit_type;
+ u8 pre_ampdu_time_type;
+ u8 cur_ampdu_time_type;
+
+ u8 error_condition;
+};
+
+struct coex_sta_8821a_1ant {
+ bool bt_link_exist;
+ bool sco_exist;
+ bool a2dp_exist;
+ bool hid_exist;
+ bool pan_exist;
+
+ bool under_Lps;
+ bool under_ips;
+ u32 special_pkt_period_cnt;
+ u32 high_priority_tx;
+ u32 high_priority_rx;
+ u32 low_priority_tx;
+ u32 low_priority_rx;
+ u8 bt_rssi;
+ u8 pre_bt_rssi_state;
+ u8 pre_wifi_rssi_state[4];
+ bool c2h_bt_info_req_sent;
+ u8 bt_info_c2h[BT_INFO_SRC_8821A_1ANT_MAX][10];
+ u32 bt_info_c2h_cnt[BT_INFO_SRC_8821A_1ANT_MAX];
+ bool c2h_bt_inquiry_page;
+ u8 bt_retry_cnt;
+ u8 bt_info_ext;
+};
+
+/*===========================================
+ * The following is interface which will notify coex module.
+ *===========================================
+ */
+void ex_halbtc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8821a1ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type);
+void ex_halbtc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmpbuf, u8 length);
+void ex_halbtc8821a1ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate);
+void ex_halbtc8821a1ant_periodical(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_dbg_control(struct btc_coexist *btcoexist, u8 op_code,
+ u8 op_len, u8 *data);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c
new file mode 100644
index 00000000000..cf819f02ed2
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c
@@ -0,0 +1,3879 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/*============================================================
+ * Description:
+ *
+ * This file is for RTL8821A Co-exist mechanism
+ *
+ * History
+ * 2012/08/22 Cosa first check in.
+ * 2012/11/14 Cosa Revise for 8821A 2Ant out sourcing.
+ *
+ *============================================================
+ */
+
+/*============================================================
+ * include files
+ *============================================================
+*/
+#include "halbt_precomp.h"
+/*============================================================
+ * Global variables, these are static variables
+ *============================================================
+ */
+static struct coex_dm_8821a_2ant glcoex_dm_8821a_2ant;
+static struct coex_dm_8821a_2ant *coex_dm = &glcoex_dm_8821a_2ant;
+static struct coex_sta_8821a_2ant glcoex_sta_8821a_2ant;
+static struct coex_sta_8821a_2ant *coex_sta = &glcoex_sta_8821a_2ant;
+
+static const char *const glbt_info_src_8821a_2ant[] = {
+ "BT Info[wifi fw]",
+ "BT Info[bt rsp]",
+ "BT Info[bt auto report]",
+};
+
+static u32 glcoex_ver_date_8821a_2ant = 20130618;
+static u32 glcoex_ver_8821a_2ant = 0x5050;
+
+/*============================================================
+ * local function proto type if needed
+ *============================================================
+ *============================================================
+ * local function start with halbtc8821a2ant_
+ *============================================================
+ */
+static u8 halbtc8821a2ant_bt_rssi_state(u8 level_num, u8 rssi_thresh,
+ u8 rssi_thresh1)
+{
+ long bt_rssi = 0;
+ u8 bt_rssi_state = coex_sta->pre_bt_rssi_state;
+
+ bt_rssi = coex_sta->bt_rssi;
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ long tmp = rssi_thresh +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT;
+ if (bt_rssi >= tmp) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to High\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Low\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi thresh error!!\n");
+ return coex_sta->pre_bt_rssi_state;
+ }
+
+ if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+ if (bt_rssi >=
+ (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_bt_rssi_state ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (bt_rssi >=
+ (rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+ bt_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to High\n");
+ } else if (bt_rssi < rssi_thresh) {
+ bt_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Low\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at Medium\n");
+ }
+ } else {
+ if (bt_rssi < rssi_thresh1) {
+ bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state switch to Medium\n");
+ } else {
+ bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+ "[BTCoex], BT Rssi state stay at High\n");
+ }
+ }
+ }
+
+ coex_sta->pre_bt_rssi_state = bt_rssi_state;
+
+ return bt_rssi_state;
+}
+
+static u8 halbtc8821a2ant_wifi_rssi_state(struct btc_coexist *btcoexist,
+ u8 index, u8 level_num,
+ u8 rssi_thresh, u8 rssi_thresh1)
+{
+ long wifi_rssi = 0;
+ u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+
+ if (level_num == 2) {
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >=
+ (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to High\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Low\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at High\n");
+ }
+ }
+ } else if (level_num == 3) {
+ if (rssi_thresh > rssi_thresh1) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI thresh error!!\n");
+ return coex_sta->pre_wifi_rssi_state[index];
+ }
+
+ if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_LOW) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_LOW)) {
+ if (wifi_rssi >=
+ (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Low\n");
+ }
+ } else if ((coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_MEDIUM) ||
+ (coex_sta->pre_wifi_rssi_state[index] ==
+ BTC_RSSI_STATE_STAY_MEDIUM)) {
+ if (wifi_rssi >= (rssi_thresh1 +
+ BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+ wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to High\n");
+ } else if (wifi_rssi < rssi_thresh) {
+ wifi_rssi_state = BTC_RSSI_STATE_LOW;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Low\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at Medium\n");
+ }
+ } else {
+ if (wifi_rssi < rssi_thresh1) {
+ wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state switch to Medium\n");
+ } else {
+ wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_WIFI_RSSI_STATE,
+ "[BTCoex], wifi RSSI state stay at High\n");
+ }
+ }
+ }
+ coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state;
+
+ return wifi_rssi_state;
+}
+
+static void btc8821a2ant_mon_bt_en_dis(struct btc_coexist *btcoexist)
+{
+ static bool pre_bt_disabled;
+ static u32 bt_disable_cnt;
+ bool bt_active = true, bt_disabled = false;
+
+ /* This function check if bt is disabled*/
+
+ if (coex_sta->high_priority_tx == 0 &&
+ coex_sta->high_priority_rx == 0 &&
+ coex_sta->low_priority_tx == 0 &&
+ coex_sta->low_priority_rx == 0)
+ bt_active = false;
+ if (coex_sta->high_priority_tx == 0xffff &&
+ coex_sta->high_priority_rx == 0xffff &&
+ coex_sta->low_priority_tx == 0xffff &&
+ coex_sta->low_priority_rx == 0xffff)
+ bt_active = false;
+ if (bt_active) {
+ bt_disable_cnt = 0;
+ bt_disabled = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+ &bt_disabled);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is enabled !!\n");
+ } else {
+ bt_disable_cnt++;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], bt all counters = 0, %d times!!\n",
+ bt_disable_cnt);
+ if (bt_disable_cnt >= 2) {
+ bt_disabled = true;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+ &bt_disabled);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is disabled !!\n");
+ }
+ }
+ if (pre_bt_disabled != bt_disabled) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], BT is from %s to %s!!\n",
+ (pre_bt_disabled ? "disabled" : "enabled"),
+ (bt_disabled ? "disabled" : "enabled"));
+ pre_bt_disabled = bt_disabled;
+ }
+}
+
+static void halbtc8821a2ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+ u32 reg_hp_txrx, reg_lp_txrx, u4tmp;
+ u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0;
+
+ reg_hp_txrx = 0x770;
+ reg_lp_txrx = 0x774;
+
+ u4tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx);
+ reg_hp_tx = u4tmp & MASKLWORD;
+ reg_hp_rx = (u4tmp & MASKHWORD)>>16;
+
+ u4tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx);
+ reg_lp_tx = u4tmp & MASKLWORD;
+ reg_lp_rx = (u4tmp & MASKHWORD)>>16;
+
+ coex_sta->high_priority_tx = reg_hp_tx;
+ coex_sta->high_priority_rx = reg_hp_rx;
+ coex_sta->low_priority_tx = reg_lp_tx;
+ coex_sta->low_priority_rx = reg_lp_rx;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], High Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
+ reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+ "[BTCoex], Low Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
+ reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx);
+
+ /* reset counter */
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static void halbtc8821a2ant_query_bt_info(struct btc_coexist *btcoexist)
+{
+ u8 h2c_parameter[1] = {0};
+
+ coex_sta->c2h_bt_info_req_sent = true;
+
+ h2c_parameter[0] |= BIT0; /* trigger */
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
+static u8 halbtc8821a2ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ bool bt_hs_on = false;
+ u8 algorithm = BT_8821A_2ANT_COEX_ALGO_UNDEFINED;
+ u8 num_of_diff_profile = 0;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+ /*for win-8 stack HID report error*/
+ /* sync BTInfo with BT firmware and stack */
+ if (!stack_info->hid_exist)
+ stack_info->hid_exist = coex_sta->hid_exist;
+ /* when stack HID report error, here we use the info from bt fw. */
+ if (!stack_info->bt_link_exist)
+ stack_info->bt_link_exist = coex_sta->bt_link_exist;
+
+ if (!coex_sta->bt_link_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], No profile exists!!!\n");
+ return algorithm;
+ }
+
+ if (coex_sta->sco_exist)
+ num_of_diff_profile++;
+ if (coex_sta->hid_exist)
+ num_of_diff_profile++;
+ if (coex_sta->pan_exist)
+ num_of_diff_profile++;
+ if (coex_sta->a2dp_exist)
+ num_of_diff_profile++;
+
+ if (num_of_diff_profile == 1) {
+ if (coex_sta->sco_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO only\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_SCO;
+ } else {
+ if (coex_sta->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID only\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_HID;
+ } else if (coex_sta->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], A2DP only\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP;
+ } else if (coex_sta->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], PAN(HS) only\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], PAN(EDR) only\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR;
+ }
+ }
+ }
+ } else if (num_of_diff_profile == 2) {
+ if (coex_sta->sco_exist) {
+ if (coex_sta->hid_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ } else if (coex_sta->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + A2DP ==> SCO\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ } else if (coex_sta->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + PAN(HS)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_SCO;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + PAN(EDR)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (coex_sta->hid_exist &&
+ coex_sta->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + A2DP\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP;
+ } else if (coex_sta->hid_exist &&
+ coex_sta->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + PAN(HS)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_HID;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + PAN(EDR)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (coex_sta->pan_exist &&
+ coex_sta->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], A2DP + PAN(HS)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], A2DP + PAN(EDR)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP;
+ }
+ }
+ }
+ } else if (num_of_diff_profile == 3) {
+ if (coex_sta->sco_exist) {
+ if (coex_sta->hid_exist &&
+ coex_sta->a2dp_exist) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID + A2DP ==> HID\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ } else if (coex_sta->hid_exist &&
+ coex_sta->pan_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID + PAN(HS)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID + PAN(EDR)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ } else if (coex_sta->pan_exist &&
+ coex_sta->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + A2DP + PAN(HS)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ } else {
+ if (coex_sta->hid_exist &&
+ coex_sta->pan_exist &&
+ coex_sta->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + A2DP + PAN(HS)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], HID + A2DP + PAN(EDR)\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+ }
+ }
+ }
+ } else if (num_of_diff_profile >= 3) {
+ if (coex_sta->sco_exist) {
+ if (coex_sta->hid_exist &&
+ coex_sta->pan_exist &&
+ coex_sta->a2dp_exist) {
+ if (bt_hs_on) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n");
+
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n");
+ algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+ }
+ }
+ }
+ }
+ return algorithm;
+}
+
+static bool halbtc8821a2ant_need_to_dec_bt_pwr(struct btc_coexist *btcoexist)
+{
+ bool ret = false;
+ bool bt_hs_on = false, wifi_connected = false;
+ long bt_hs_rssi = 0;
+ u8 bt_rssi_state;
+
+ if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on))
+ return false;
+ if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected))
+ return false;
+ if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi))
+ return false;
+
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ if (wifi_connected) {
+ if (bt_hs_on) {
+ if (bt_hs_rssi > 37) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], Need to decrease bt power for HS mode!!\n");
+ ret = true;
+ }
+ } else {
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], Need to decrease bt power for Wifi is connected!!\n");
+ ret = true;
+ }
+ }
+ }
+ return ret;
+}
+
+static void btc8821a2ant_set_fw_dac_swing_lev(struct btc_coexist *btcoexist,
+ u8 dac_swing_lvl)
+{
+ u8 h2c_parameter[1] = {0};
+
+ /* There are several type of dacswing
+ * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6
+ */
+ h2c_parameter[0] = dac_swing_lvl;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swing_lvl);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x64 = 0x%x\n", h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter);
+}
+
+static void halbtc8821a2ant_set_fw_dec_bt_pwr(struct btc_coexist *btcoexist,
+ bool dec_bt_pwr)
+{
+ u8 h2c_parameter[1] = {0};
+
+ h2c_parameter[0] = 0;
+
+ if (dec_bt_pwr)
+ h2c_parameter[0] |= BIT1;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], decrease Bt Power : %s, FW write 0x62 = 0x%x\n",
+ (dec_bt_pwr ? "Yes!!" : "No!!"), h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter);
+}
+
+static void halbtc8821a2ant_dec_bt_pwr(struct btc_coexist *btcoexist,
+ bool force_exec, bool dec_bt_pwr)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s Dec BT power = %s\n",
+ (force_exec ? "force to" : ""),
+ ((dec_bt_pwr) ? "ON" : "OFF"));
+ coex_dm->cur_dec_bt_pwr = dec_bt_pwr;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_dec_bt_pwr = %d, cur_dec_bt_pwr = %d\n",
+ coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr);
+
+ if (coex_dm->pre_dec_bt_pwr == coex_dm->cur_dec_bt_pwr)
+ return;
+ }
+ halbtc8821a2ant_set_fw_dec_bt_pwr(btcoexist, coex_dm->cur_dec_bt_pwr);
+
+ coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr;
+}
+
+static void btc8821a2ant_set_fw_bt_lna_constr(struct btc_coexist *btcoexist,
+ bool bt_lna_cons_on)
+{
+ u8 h2c_parameter[2] = {0};
+
+ h2c_parameter[0] = 0x3; /* opCode, 0x3 = BT_SET_LNA_CONSTRAIN */
+
+ if (bt_lna_cons_on)
+ h2c_parameter[1] |= BIT0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set BT LNA Constrain: %s, FW write 0x69 = 0x%x\n",
+ (bt_lna_cons_on ? "ON!!" : "OFF!!"),
+ h2c_parameter[0]<<8|h2c_parameter[1]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x69, 2, h2c_parameter);
+}
+
+static void btc8821a2_set_bt_lna_const(struct btc_coexist *btcoexist,
+ bool force_exec, bool bt_lna_cons_on)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s BT Constrain = %s\n",
+ (force_exec ? "force" : ""),
+ ((bt_lna_cons_on) ? "ON" : "OFF"));
+ coex_dm->cur_bt_lna_constrain = bt_lna_cons_on;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_bt_lna_constrain = %d,cur_bt_lna_constrain = %d\n",
+ coex_dm->pre_bt_lna_constrain,
+ coex_dm->cur_bt_lna_constrain);
+
+ if (coex_dm->pre_bt_lna_constrain ==
+ coex_dm->cur_bt_lna_constrain)
+ return;
+ }
+ btc8821a2ant_set_fw_bt_lna_constr(btcoexist,
+ coex_dm->cur_bt_lna_constrain);
+
+ coex_dm->pre_bt_lna_constrain = coex_dm->cur_bt_lna_constrain;
+}
+
+static void halbtc8821a2ant_set_fw_bt_psd_mode(struct btc_coexist *btcoexist,
+ u8 bt_psd_mode)
+{
+ u8 h2c_parameter[2] = {0};
+
+ h2c_parameter[0] = 0x2; /* opCode, 0x2 = BT_SET_PSD_MODE */
+
+ h2c_parameter[1] = bt_psd_mode;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set BT PSD mode = 0x%x, FW write 0x69 = 0x%x\n",
+ h2c_parameter[1],
+ h2c_parameter[0]<<8|h2c_parameter[1]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x69, 2, h2c_parameter);
+}
+
+static void halbtc8821a2ant_set_bt_psd_mode(struct btc_coexist *btcoexist,
+ bool force_exec, u8 bt_psd_mode)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s BT PSD mode = 0x%x\n",
+ (force_exec ? "force" : ""), bt_psd_mode);
+ coex_dm->cur_bt_psd_mode = bt_psd_mode;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_bt_psd_mode = 0x%x, cur_bt_psd_mode = 0x%x\n",
+ coex_dm->pre_bt_psd_mode, coex_dm->cur_bt_psd_mode);
+
+ if (coex_dm->pre_bt_psd_mode == coex_dm->cur_bt_psd_mode)
+ return;
+ }
+ halbtc8821a2ant_set_fw_bt_psd_mode(btcoexist,
+ coex_dm->cur_bt_psd_mode);
+
+ coex_dm->pre_bt_psd_mode = coex_dm->cur_bt_psd_mode;
+}
+
+static void halbtc8821a2ant_set_bt_auto_report(struct btc_coexist *btcoexist,
+ bool enable_auto_report)
+{
+ u8 h2c_parameter[1] = {0};
+
+ h2c_parameter[0] = 0;
+
+ if (enable_auto_report)
+ h2c_parameter[0] |= BIT0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n",
+ (enable_auto_report ? "Enabled!!" : "Disabled!!"),
+ h2c_parameter[0]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter);
+}
+
+static void halbtc8821a2ant_bt_auto_report(struct btc_coexist *btcoexist,
+ bool force_exec,
+ bool enable_auto_report)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s BT Auto report = %s\n",
+ (force_exec ? "force to" : ""),
+ ((enable_auto_report) ? "Enabled" : "Disabled"));
+ coex_dm->cur_bt_auto_report = enable_auto_report;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_bt_auto_report = %d, cur_bt_auto_report = %d\n",
+ coex_dm->pre_bt_auto_report,
+ coex_dm->cur_bt_auto_report);
+
+ if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report)
+ return;
+ }
+ halbtc8821a2ant_set_bt_auto_report(btcoexist,
+ coex_dm->cur_bt_auto_report);
+
+ coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report;
+}
+
+static void halbtc8821a2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist,
+ bool force_exec,
+ u8 fw_dac_swing_lvl)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s set FW Dac Swing level = %d\n",
+ (force_exec ? "force to" : ""), fw_dac_swing_lvl);
+ coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_fw_dac_swing_lvl = %d, cur_fw_dac_swing_lvl = %d\n",
+ coex_dm->pre_fw_dac_swing_lvl,
+ coex_dm->cur_fw_dac_swing_lvl);
+
+ if (coex_dm->pre_fw_dac_swing_lvl ==
+ coex_dm->cur_fw_dac_swing_lvl)
+ return;
+ }
+
+ btc8821a2ant_set_fw_dac_swing_lev(btcoexist,
+ coex_dm->cur_fw_dac_swing_lvl);
+
+ coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl;
+}
+
+static void btc8821a2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist,
+ bool rx_rf_shrink_on)
+{
+ if (rx_rf_shrink_on) {
+ /* Shrink RF Rx LPF corner */
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Shrink RF Rx LPF corner!!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e,
+ 0xfffff, 0xffffc);
+ } else {
+ /* Resume RF Rx LPF corner
+ * After initialized, we can use coex_dm->bt_rf0x1e_backup
+ */
+ if (btcoexist->initilized) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Resume RF Rx LPF corner!!\n");
+ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A,
+ 0x1e, 0xfffff,
+ coex_dm->bt_rf0x1e_backup);
+ }
+ }
+}
+
+static void halbtc8821a2ant_RfShrink(struct btc_coexist *btcoexist,
+ bool force_exec, bool rx_rf_shrink_on)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn Rx RF Shrink = %s\n",
+ (force_exec ? "force to" : ""),
+ ((rx_rf_shrink_on) ? "ON" : "OFF"));
+ coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], pre_rf_rx_lpf_shrink = %d, cur_rf_rx_lpf_shrink = %d\n",
+ coex_dm->pre_rf_rx_lpf_shrink,
+ coex_dm->cur_rf_rx_lpf_shrink);
+
+ if (coex_dm->pre_rf_rx_lpf_shrink ==
+ coex_dm->cur_rf_rx_lpf_shrink)
+ return;
+ }
+ btc8821a2ant_set_sw_rf_rx_lpf_corner(btcoexist,
+ coex_dm->cur_rf_rx_lpf_shrink);
+
+ coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink;
+}
+
+static void btc8821a2ant_SetSwPenTxRateAdapt(struct btc_coexist *btcoexist,
+ bool low_penalty_ra)
+{
+ u8 h2c_parameter[6] = {0};
+
+ h2c_parameter[0] = 0x6; /* opCode, 0x6 = Retry_Penalty */
+
+ if (low_penalty_ra) {
+ h2c_parameter[1] |= BIT0;
+ /*normal rate except MCS7/6/5, OFDM54/48/36 */
+ h2c_parameter[2] = 0x00;
+ /*MCS7 or OFDM54 */
+ h2c_parameter[3] = 0xf7;
+ /*MCS6 or OFDM48 */
+ h2c_parameter[4] = 0xf8;
+ /*MCS5 or OFDM36 */
+ h2c_parameter[5] = 0xf9;
+ }
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set WiFi Low-Penalty Retry: %s",
+ (low_penalty_ra ? "ON!!" : "OFF!!"));
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter);
+}
+
+static void halbtc8821a2ant_low_penalty_ra(struct btc_coexist *btcoexist,
+ bool force_exec, bool low_penalty_ra)
+{
+ /*return;*/
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn LowPenaltyRA = %s\n",
+ (force_exec ? "force to" : ""),
+ ((low_penalty_ra) ? "ON" : "OFF"));
+ coex_dm->cur_low_penalty_ra = low_penalty_ra;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], pre_low_penalty_ra = %d, cur_low_penalty_ra = %d\n",
+ coex_dm->pre_low_penalty_ra,
+ coex_dm->cur_low_penalty_ra);
+
+ if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra)
+ return;
+ }
+ btc8821a2ant_SetSwPenTxRateAdapt(btcoexist,
+ coex_dm->cur_low_penalty_ra);
+
+ coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra;
+}
+
+static void halbtc8821a2ant_set_dac_swing_reg(struct btc_coexist *btcoexist,
+ u32 level)
+{
+ u8 val = (u8)level;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], Write SwDacSwing = 0x%x\n", level);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc5b, 0x3e, val);
+}
+
+static void btc8821a2ant_set_sw_full_dac_swing(struct btc_coexist *btcoexist,
+ bool sw_dac_swing_on,
+ u32 sw_dac_swing_lvl)
+{
+ if (sw_dac_swing_on)
+ halbtc8821a2ant_set_dac_swing_reg(btcoexist, sw_dac_swing_lvl);
+ else
+ halbtc8821a2ant_set_dac_swing_reg(btcoexist, 0x18);
+}
+
+static void halbtc8821a2ant_dac_swing(struct btc_coexist *btcoexist,
+ bool force_exec, bool dac_swing_on,
+ u32 dac_swing_lvl)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn DacSwing = %s, dac_swing_lvl = 0x%x\n",
+ (force_exec ? "force to" : ""),
+ ((dac_swing_on) ? "ON" : "OFF"),
+ dac_swing_lvl);
+ coex_dm->cur_dac_swing_on = dac_swing_on;
+ coex_dm->cur_dac_swing_lvl = dac_swing_lvl;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], pre_dac_swing_on = %d, pre_dac_swing_lvl = 0x%x, cur_dac_swing_on = %d, cur_dac_swing_lvl = 0x%x\n",
+ coex_dm->pre_dac_swing_on,
+ coex_dm->pre_dac_swing_lvl,
+ coex_dm->cur_dac_swing_on,
+ coex_dm->cur_dac_swing_lvl);
+
+ if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) &&
+ (coex_dm->pre_dac_swing_lvl ==
+ coex_dm->cur_dac_swing_lvl))
+ return;
+ }
+ mdelay(30);
+ btc8821a2ant_set_sw_full_dac_swing(btcoexist, dac_swing_on,
+ dac_swing_lvl);
+
+ coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on;
+ coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl;
+}
+
+static void halbtc8821a2ant_set_adc_back_off(struct btc_coexist *btcoexist,
+ bool adc_back_off)
+{
+ if (adc_back_off) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], BB BackOff Level On!\n");
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x3);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], BB BackOff Level Off!\n");
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x1);
+ }
+}
+
+static void halbtc8821a2ant_adc_back_off(struct btc_coexist *btcoexist,
+ bool force_exec, bool adc_back_off)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s turn AdcBackOff = %s\n",
+ (force_exec ? "force to" : ""),
+ ((adc_back_off) ? "ON" : "OFF"));
+ coex_dm->cur_adc_back_off = adc_back_off;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], pre_adc_back_off = %d, cur_adc_back_off = %d\n",
+ coex_dm->pre_adc_back_off, coex_dm->cur_adc_back_off);
+
+ if (coex_dm->pre_adc_back_off == coex_dm->cur_adc_back_off)
+ return;
+ }
+ halbtc8821a2ant_set_adc_back_off(btcoexist, coex_dm->cur_adc_back_off);
+
+ coex_dm->pre_adc_back_off = coex_dm->cur_adc_back_off;
+}
+
+static void halbtc8821a2ant_set_coex_table(struct btc_coexist *btcoexist,
+ u32 val0x6c0, u32 val0x6c4,
+ u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8);
+ btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+ "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc);
+ btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void halbtc8821a2ant_coex_table(struct btc_coexist *btcoexist,
+ bool force_exec, u32 val0x6c0,
+ u32 val0x6c4, u32 val0x6c8, u8 val0x6cc)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+ "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n",
+ (force_exec ? "force to" : ""),
+ val0x6c0, val0x6c4, val0x6c8, val0x6cc);
+ coex_dm->cur_val0x6c0 = val0x6c0;
+ coex_dm->cur_val0x6c4 = val0x6c4;
+ coex_dm->cur_val0x6c8 = val0x6c8;
+ coex_dm->cur_val0x6cc = val0x6cc;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], pre_val0x6c0 = 0x%x, pre_val0x6c4 = 0x%x, pre_val0x6c8 = 0x%x, pre_val0x6cc = 0x%x !!\n",
+ coex_dm->pre_val0x6c0,
+ coex_dm->pre_val0x6c4,
+ coex_dm->pre_val0x6c8,
+ coex_dm->pre_val0x6cc);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+ "[BTCoex], cur_val0x6c0 = 0x%x, cur_val0x6c4 = 0x%x, cur_val0x6c8 = 0x%x, cur_val0x6cc = 0x%x !!\n",
+ coex_dm->cur_val0x6c0,
+ coex_dm->cur_val0x6c4,
+ coex_dm->cur_val0x6c8,
+ coex_dm->cur_val0x6cc);
+
+ if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) &&
+ (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) &&
+ (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) &&
+ (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc))
+ return;
+ }
+ halbtc8821a2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8,
+ val0x6cc);
+
+ coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0;
+ coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4;
+ coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8;
+ coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc;
+}
+
+static void halbtc8821a2ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoex,
+ bool enable)
+{
+ u8 h2c_parameter[1] = {0};
+
+ if (enable)
+ h2c_parameter[0] |= BIT0;/* function enable */
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
+ h2c_parameter[0]);
+
+ btcoex->btc_fill_h2c(btcoex, 0x63, 1, h2c_parameter);
+}
+
+static void halbtc8821a2ant_ignore_wlan_act(struct btc_coexist *btcoexist,
+ bool force_exec, bool enable)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn Ignore WlanAct %s\n",
+ (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+ coex_dm->cur_ignore_wlan_act = enable;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_ignore_wlan_act = %d, cur_ignore_wlan_act = %d!!\n",
+ coex_dm->pre_ignore_wlan_act,
+ coex_dm->cur_ignore_wlan_act);
+
+ if (coex_dm->pre_ignore_wlan_act ==
+ coex_dm->cur_ignore_wlan_act)
+ return;
+ }
+ halbtc8821a2ant_set_fw_ignore_wlan_act(btcoexist, enable);
+
+ coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void halbtc8821a2ant_set_fw_pstdma(struct btc_coexist *btcoexist,
+ u8 byte1, u8 byte2, u8 byte3,
+ u8 byte4, u8 byte5)
+{
+ u8 h2c_parameter[5];
+
+ h2c_parameter[0] = byte1;
+ h2c_parameter[1] = byte2;
+ h2c_parameter[2] = byte3;
+ h2c_parameter[3] = byte4;
+ h2c_parameter[4] = byte5;
+
+ coex_dm->ps_tdma_para[0] = byte1;
+ coex_dm->ps_tdma_para[1] = byte2;
+ coex_dm->ps_tdma_para[2] = byte3;
+ coex_dm->ps_tdma_para[3] = byte4;
+ coex_dm->ps_tdma_para[4] = byte5;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n",
+ h2c_parameter[0],
+ h2c_parameter[1]<<24|
+ h2c_parameter[2]<<16|
+ h2c_parameter[3]<<8|
+ h2c_parameter[4]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void btc8821a2ant_sw_mech1(struct btc_coexist *btcoexist,
+ bool shrink_rx_lpf,
+ bool low_penalty_ra, bool limited_dig,
+ bool bt_lna_constrain)
+{
+ u32 wifi_bw;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_HT40 != wifi_bw) {
+ /*only shrink RF Rx LPF for HT40*/
+ if (shrink_rx_lpf)
+ shrink_rx_lpf = false;
+ }
+
+ halbtc8821a2ant_RfShrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf);
+ halbtc8821a2ant_low_penalty_ra(btcoexist,
+ NORMAL_EXEC, low_penalty_ra);
+
+ /* no limited DIG
+ * btc8821a2_set_bt_lna_const(btcoexist,
+ NORMAL_EXEC, bBTLNAConstrain);
+ */
+}
+
+static void btc8821a2ant_sw_mech2(struct btc_coexist *btcoexist,
+ bool agc_table_shift,
+ bool adc_back_off, bool sw_dac_swing,
+ u32 dac_swing_lvl)
+{
+ /* halbtc8821a2ant_AgcTable(btcoexist, NORMAL_EXEC, bAGCTableShift); */
+ halbtc8821a2ant_adc_back_off(btcoexist, NORMAL_EXEC, adc_back_off);
+ halbtc8821a2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing,
+ sw_dac_swing);
+}
+
+static void halbtc8821a2ant_set_ant_path(struct btc_coexist *btcoexist,
+ u8 ant_pos_type, bool init_hw_cfg,
+ bool wifi_off)
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ u32 u4tmp = 0;
+ u8 h2c_parameter[2] = {0};
+
+ if (init_hw_cfg) {
+ /* 0x4c[23] = 0, 0x4c[24] = 1 Antenna control by WL/BT */
+ u4tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u4tmp &= ~BIT23;
+ u4tmp |= BIT24;
+ btcoexist->btc_write_4byte(btcoexist, 0x4c, u4tmp);
+
+ btcoexist->btc_write_4byte(btcoexist, 0x974, 0x3ff);
+ btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77);
+
+ if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
+ /* tell firmware "antenna inverse" ==>
+ * WRONG firmware antenna control code.
+ * ==>need fw to fix
+ */
+ h2c_parameter[0] = 1;
+ h2c_parameter[1] = 1;
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ } else {
+ /* tell firmware "no antenna inverse"
+ * ==> WRONG firmware antenna control code.
+ * ==>need fw to fix
+ */
+ h2c_parameter[0] = 0;
+ h2c_parameter[1] = 1;
+ btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+ h2c_parameter);
+ }
+ }
+
+ /* ext switch setting */
+ switch (ant_pos_type) {
+ case BTC_ANT_WIFI_AT_MAIN:
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x1);
+ break;
+ case BTC_ANT_WIFI_AT_AUX:
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x2);
+ break;
+ }
+}
+
+static void halbtc8821a2ant_ps_tdma(struct btc_coexist *btcoexist,
+ bool force_exec, bool turn_on, u8 type)
+{
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], %s turn %s PS TDMA, type = %d\n",
+ (force_exec ? "force to" : ""), (turn_on ? "ON" : "OFF"),
+ type);
+ coex_dm->cur_ps_tdma_on = turn_on;
+ coex_dm->cur_ps_tdma = type;
+
+ if (!force_exec) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_ps_tdma_on = %d, cur_ps_tdma_on = %d!!\n",
+ coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], pre_ps_tdma = %d, cur_ps_tdma = %d!!\n",
+ coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma);
+
+ if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+ (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+ return;
+ }
+ if (turn_on) {
+ switch (type) {
+ case 1:
+ default:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x90);
+ break;
+ case 2:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0xe1, 0x90);
+ break;
+ case 3:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0xf1, 0x90);
+ break;
+ case 4:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x10,
+ 0x03, 0xf1, 0x90);
+ break;
+ case 5:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0x60, 0x90);
+ break;
+ case 6:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0x60, 0x90);
+ break;
+ case 7:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1c,
+ 0x3, 0x70, 0x90);
+ break;
+ case 8:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xa3, 0x10,
+ 0x3, 0x70, 0x90);
+ break;
+ case 9:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x90);
+ break;
+ case 10:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12,
+ 0x12, 0xe1, 0x90);
+ break;
+ case 11:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0xa,
+ 0xa, 0xe1, 0x90);
+ break;
+ case 12:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5,
+ 0x5, 0xe1, 0x90);
+ break;
+ case 13:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0x60, 0x90);
+ break;
+ case 14:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3,
+ 0x12, 0x12, 0x60, 0x90);
+ break;
+ case 15:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0xa,
+ 0xa, 0x60, 0x90);
+ break;
+ case 16:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5,
+ 0x5, 0x60, 0x90);
+ break;
+ case 17:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xa3, 0x2f,
+ 0x2f, 0x60, 0x90);
+ break;
+ case 18:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5,
+ 0x5, 0xe1, 0x90);
+ break;
+ case 19:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x25,
+ 0x25, 0xe1, 0x90);
+ break;
+ case 20:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x25,
+ 0x25, 0x60, 0x90);
+ break;
+ case 21:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x15,
+ 0x03, 0x70, 0x90);
+ break;
+ case 71:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+ 0x1a, 0xe1, 0x90);
+ break;
+ }
+ } else {
+ /* disable PS tdma */
+ switch (type) {
+ case 0:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x40, 0x0);
+ break;
+ case 1:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x48, 0x0);
+ break;
+ default:
+ halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+ 0x40, 0x0);
+ break;
+ }
+ }
+
+ /* update pre state */
+ coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+ coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static void halbtc8821a2ant_coex_all_off(struct btc_coexist *btcoexist)
+{
+ /* fw all off */
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ /* sw all off */
+ btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+
+ /* hw all off */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC,
+ 0x55555555, 0x55555555, 0xffff, 0x3);
+}
+
+static void halbtc8821a2ant_coex_under_5g(struct btc_coexist *btcoexist)
+{
+ halbtc8821a2ant_coex_all_off(btcoexist);
+}
+
+static void halbtc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+ /* force to reset coex mechanism */
+ halbtc8821a2ant_coex_table(btcoexist, FORCE_EXEC, 0x55555555,
+ 0x55555555, 0xffff, 0x3);
+
+ halbtc8821a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1);
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, false);
+
+ btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+}
+
+static void halbtc8821a2ant_bt_inquiry_page(struct btc_coexist *btcoexist)
+{
+ bool low_pwr_disable = true;
+
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5afa5afa, 0xffff, 0x3);
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+}
+
+static bool halbtc8821a2ant_is_common_action(struct btc_coexist *btcoexist)
+{
+ bool common = false, wifi_connected = false, wifi_busy = false;
+ bool low_pwr_disable = false;
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+ &wifi_connected);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5afa5afa, 0xffff, 0x3);
+
+ if (!wifi_connected &&
+ BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status) {
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi IPS + BT IPS!!\n");
+
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+
+ common = true;
+ } else if (wifi_connected &&
+ (BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status)) {
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ if (wifi_busy) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Busy + BT IPS!!\n");
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi LPS + BT IPS!!\n");
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ }
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+
+ common = true;
+ } else if (!wifi_connected &&
+ (BT_8821A_2ANT_BT_STATUS_CON_IDLE == coex_dm->bt_status)) {
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi IPS + BT LPS!!\n");
+
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+ common = true;
+ } else if (wifi_connected &&
+ (BT_8821A_2ANT_BT_STATUS_CON_IDLE == coex_dm->bt_status)) {
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable);
+
+ if (wifi_busy) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Busy + BT LPS!!\n");
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi LPS + BT LPS!!\n");
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ }
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8821a2ant_sw_mech1(btcoexist, true, true, true, true);
+ btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+
+ common = true;
+ } else if (!wifi_connected &&
+ (BT_8821A_2ANT_BT_STATUS_NON_IDLE ==
+ coex_dm->bt_status)) {
+ low_pwr_disable = false;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable);
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi IPS + BT Busy!!\n");
+
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+
+ common = true;
+ } else {
+ low_pwr_disable = true;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_ACT_DISABLE_LOW_POWER,
+ &low_pwr_disable);
+
+ if (wifi_busy) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi Busy + BT Busy!!\n");
+ common = false;
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Wifi LPS + BT Busy!!\n");
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC, true, 21);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist,
+ NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist,
+ NORMAL_EXEC, false);
+
+ common = true;
+ }
+ btc8821a2ant_sw_mech1(btcoexist, true, true, true, true);
+ }
+ return common;
+}
+
+static void btc8821a2_int1(struct btc_coexist *btcoexist, bool tx_pause,
+ int result)
+{
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+
+ if (coex_dm->cur_ps_tdma == 71) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 71);
+ coex_dm->tdma_adj_type = 71;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 71) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 71);
+ coex_dm->tdma_adj_type = 71;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ }
+ }
+ }
+}
+
+static void btc8821a2_int2(struct btc_coexist *btcoexist, bool tx_pause,
+ int result)
+{
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ }
+ }
+ }
+}
+
+static void btc8821a2_int3(struct btc_coexist *btcoexist, bool tx_pause,
+ int result)
+{
+ if (tx_pause) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 1\n");
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ }
+ if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 8);
+ coex_dm->tdma_adj_type = 8;
+ } else if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 16);
+ coex_dm->tdma_adj_type = 16;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ }
+ }
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], TxPause = 0\n");
+ if (coex_dm->cur_ps_tdma == 5) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 6) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 7) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 8) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ }
+ if (coex_dm->cur_ps_tdma == 13) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 14) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 15) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 16) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ if (result == -1) {
+ if (coex_dm->cur_ps_tdma == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 4);
+ coex_dm->tdma_adj_type = 4;
+ } else if (coex_dm->cur_ps_tdma == 9) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 12);
+ coex_dm->tdma_adj_type = 12;
+ }
+ } else if (result == 1) {
+ if (coex_dm->cur_ps_tdma == 4) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else if (coex_dm->cur_ps_tdma == 12) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 11) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else if (coex_dm->cur_ps_tdma == 10) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ }
+ }
+}
+
+static void btc8821a2ant_tdma_dur_adj(struct btc_coexist *btcoexist,
+ bool sco_hid, bool tx_pause,
+ u8 max_interval)
+{
+ static long up, dn, m, n, wait_count;
+ /* 0: no change, +1: increase WiFi duration,
+ * -1: decrease WiFi duration
+ */
+ int result;
+ u8 retry_count = 0;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+ "[BTCoex], TdmaDurationAdjust()\n");
+
+ if (coex_dm->reset_tdma_adjust) {
+ coex_dm->reset_tdma_adjust = false;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], first run TdmaDurationAdjust()!!\n");
+ if (sco_hid) {
+ if (tx_pause) {
+ if (max_interval == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 13);
+ coex_dm->tdma_adj_type = 13;
+ } else if (max_interval == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 14);
+ coex_dm->tdma_adj_type = 14;
+ } else if (max_interval == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 15);
+ coex_dm->tdma_adj_type = 15;
+ }
+ } else {
+ if (max_interval == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 9);
+ coex_dm->tdma_adj_type = 9;
+ } else if (max_interval == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 10);
+ coex_dm->tdma_adj_type = 10;
+ } else if (max_interval == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 11);
+ coex_dm->tdma_adj_type = 11;
+ }
+ }
+ } else {
+ if (tx_pause) {
+ if (max_interval == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 5);
+ coex_dm->tdma_adj_type = 5;
+ } else if (max_interval == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 6);
+ coex_dm->tdma_adj_type = 6;
+ } else if (max_interval == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 7);
+ coex_dm->tdma_adj_type = 7;
+ }
+ } else {
+ if (max_interval == 1) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 1);
+ coex_dm->tdma_adj_type = 1;
+ } else if (max_interval == 2) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 2);
+ coex_dm->tdma_adj_type = 2;
+ } else if (max_interval == 3) {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist,
+ NORMAL_EXEC,
+ true, 3);
+ coex_dm->tdma_adj_type = 3;
+ }
+ }
+ }
+
+ up = 0;
+ dn = 0;
+ m = 1;
+ n = 3;
+ result = 0;
+ wait_count = 0;
+ } else {
+ /* accquire the BT TRx retry count from BT_Info byte2 */
+ retry_count = coex_sta->bt_retry_cnt;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], retry_count = %d\n", retry_count);
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], up = %d, dn = %d, m = %d, n = %d, wait_count = %d\n",
+ (int)up, (int)dn, (int)m, (int)n, (int)wait_count);
+ result = 0;
+ wait_count++;
+
+ if (retry_count == 0) {
+ /* no retry in the last 2-second duration */
+ up++;
+ dn--;
+
+ if (dn <= 0)
+ dn = 0;
+
+ if (up >= n) {
+ /* if (retry count == 0) for 2*n seconds,
+ * make WiFi duration wider
+ */
+ wait_count = 0;
+ n = 3;
+ up = 0;
+ dn = 0;
+ result = 1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Increase wifi duration!!\n");
+ }
+ } else if (retry_count <= 3) {
+ /* <=3 retry in the last 2-second duration */
+ up--;
+ dn++;
+
+ if (up <= 0)
+ up = 0;
+
+ if (dn == 2) {
+ /* if retry count< 3 for 2*2 seconds,
+ * shrink wifi duration
+ */
+ if (wait_count <= 2)
+ m++; /* avoid bounce in two levels */
+ else
+ m = 1;
+ /* m max value is 20, max time is 120 second,
+ * recheck if adjust WiFi duration.
+ */
+ if (m >= 20)
+ m = 20;
+
+ n = 3*m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM,
+ ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration for retryCounter<3!!\n");
+ }
+ } else {
+ /* retry count > 3, if retry count > 3 happens once,
+ * shrink WiFi duration
+ */
+ if (wait_count == 1)
+ m++; /* avoid bounce in two levels */
+ else
+ m = 1;
+ /* m max value is 20, max time is 120 second,
+ * recheck if adjust WiFi duration.
+ */
+ if (m >= 20)
+ m = 20;
+
+ n = 3*m;
+ up = 0;
+ dn = 0;
+ wait_count = 0;
+ result = -1;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], Decrease wifi duration for retryCounter>3!!\n");
+ }
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], max Interval = %d\n", max_interval);
+ if (max_interval == 1)
+ btc8821a2_int1(btcoexist, tx_pause, result);
+ else if (max_interval == 2)
+ btc8821a2_int2(btcoexist, tx_pause, result);
+ else if (max_interval == 3)
+ btc8821a2_int3(btcoexist, tx_pause, result);
+ }
+
+ /* if current PsTdma not match with the recorded one
+ * (when scan, dhcp...), then we have to adjust it back to
+ * the previous recorded one.
+ */
+ if (coex_dm->cur_ps_tdma != coex_dm->tdma_adj_type) {
+ bool scan = false, link = false, roam = false;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], PsTdma type dismatch!!!, cur_ps_tdma = %d, recordPsTdma = %d\n",
+ coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+ if (!scan && !link && !roam) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true,
+ coex_dm->tdma_adj_type);
+ } else {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+ "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n");
+ }
+ }
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6);
+}
+
+/* SCO only or SCO+PAN(HS)*/
+static void halbtc8821a2ant_action_sco(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for SCO quality at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC,
+ 0x5a5a5a5a, 0x5a5a5a5a, 0xffff, 0x3);
+ } else {
+ /* for SCO quality & wifi performance balance at 11n mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC,
+ 0x5aea5aea, 0x5aea5aea, 0xffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism
+ * halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ */
+
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0); /*for voice quality*/
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0); /*for voice quality*/
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism
+ * halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+ */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0); /*for voice quality*/
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 0); /*for voice quality*/
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8821a2ant_action_hid(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for HID at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5a5a5a5a, 0xffff, 0x3);
+ } else {
+ /* for HID quality & wifi performance balance at 11n mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5aea5aea, 0xffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 9);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 13);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */
+static void halbtc8821a2ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ /* fw dac swing is called in btc8821a2ant_tdma_dur_adj()
+ * halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ */
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, false, 1);
+ } else {
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, false, 1);
+ } else {
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8821a2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state, bt_info_ext;
+ u32 wifi_bw;
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ /*fw dac swing is called in btc8821a2ant_tdma_dur_adj()
+ *halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ */
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if (bt_info_ext&BIT0) {
+ /*a2dp basic rate*/
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 2);
+ } else {
+ /*a2dp edr rate*/
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 2);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8821a2ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for HID at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5aff5aff, 0xffff, 0x3);
+ } else {
+ /* for HID quality & wifi performance balance at 11n mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5aff5aff, 0xffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 1);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 5);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* PAN(HS) only */
+static void halbtc8821a2ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC,
+ true);
+ } else {
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC,
+ false);
+ }
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_dec_bt_pwr(btcoexist,
+ NORMAL_EXEC, true);
+ } else {
+ halbtc8821a2ant_dec_bt_pwr(btcoexist,
+ NORMAL_EXEC, false);
+ }
+
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ false, 1);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* PAN(EDR)+A2DP */
+static void halbtc8821a2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state, bt_info_ext;
+ u32 wifi_bw;
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for HID at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5afa5afa, 0xffff, 0x3);
+ } else {
+ /* for HID quality & wifi performance balance at 11n mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5afa5afa, 0xffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ false, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ false, 3);
+ }
+ } else {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ true, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ true, 3);
+ }
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ };
+ } else {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ false, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ false, 3);
+ }
+ } else {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ true, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, false,
+ true, 3);
+ }
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, false,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8821a2ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state;
+ u32 wifi_bw;
+
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for HID at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5a5f5a5f, 0xffff, 0x3);
+ } else {
+ /* for HID quality & wifi performance balance at 11n mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5a5f5a5f, 0xffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 3);
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 10);
+ } else {
+ halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+ true, 14);
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+/* HID+A2DP+PAN(EDR) */
+static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state, bt_info_ext;
+ u32 wifi_bw;
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist,
+ 0, 2, 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for HID at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5a5a5a5a, 0xffff, 0x3);
+ } else {
+ /* for HID quality & wifi performance balance at 11n mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5a5a5a5a, 0xffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ true, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ true, 3);
+ }
+ } else {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ true, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ true, 3);
+ }
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ false, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ false, 3);
+ }
+ } else {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ true, 3);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist, true,
+ true, 3);
+ }
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+ u8 wifi_rssi_state, bt_rssi_state, bt_info_ext;
+ u32 wifi_bw;
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+ 15, 0);
+ bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+ if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+ else
+ halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+ if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+ /* for HID at 11b/g mode */
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5f5b5f5b, 0xffffff, 0x3);
+ } else {
+ /*for HID quality & wifi performance balance at 11n mode*/
+ halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+ 0x5f5b5f5b, 0xffffff, 0x3);
+ }
+
+ if (BTC_WIFI_BW_HT40 == wifi_bw) {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ }
+ } else {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ }
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, true, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ } else {
+ /* fw mechanism */
+ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ if (bt_info_ext&BIT0) {
+ /* a2dp basic rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+
+ } else {
+ /* a2dp edr rate */
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ }
+ } else {
+ if (bt_info_ext&BIT0) {
+ /*a2dp basic rate*/
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ } else {
+ /*a2dp edr rate*/
+ btc8821a2ant_tdma_dur_adj(btcoexist,
+ true, true, 2);
+ }
+ }
+
+ /* sw mechanism */
+ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+ (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, true, false,
+ false, 0x18);
+ } else {
+ btc8821a2ant_sw_mech1(btcoexist, false, true,
+ false, false);
+ btc8821a2ant_sw_mech2(btcoexist, false, false,
+ false, 0x18);
+ }
+ }
+}
+
+static void halbtc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+ bool wifi_under_5g = false;
+ u8 algorithm = 0;
+
+ if (btcoexist->manual_control) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Manual control!!!\n");
+ return;
+ }
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+
+ if (wifi_under_5g) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], RunCoexistMechanism(), run 5G coex setting!!<===\n");
+ halbtc8821a2ant_coex_under_5g(btcoexist);
+ return;
+ }
+
+ algorithm = halbtc8821a2ant_action_algorithm(btcoexist);
+ if (coex_sta->c2h_bt_inquiry_page &&
+ (BT_8821A_2ANT_COEX_ALGO_PANHS != algorithm)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], BT is under inquiry/page scan !!\n");
+ halbtc8821a2ant_bt_inquiry_page(btcoexist);
+ return;
+ }
+
+ coex_dm->cur_algorithm = algorithm;
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Algorithm = %d\n", coex_dm->cur_algorithm);
+
+ if (halbtc8821a2ant_is_common_action(btcoexist)) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant common.\n");
+ coex_dm->reset_tdma_adjust = true;
+ } else {
+ if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) {
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], pre_algorithm = %d, cur_algorithm = %d\n",
+ coex_dm->pre_algorithm, coex_dm->cur_algorithm);
+ coex_dm->reset_tdma_adjust = true;
+ }
+ switch (coex_dm->cur_algorithm) {
+ case BT_8821A_2ANT_COEX_ALGO_SCO:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = SCO.\n");
+ halbtc8821a2ant_action_sco(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = HID.\n");
+ halbtc8821a2ant_action_hid(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = A2DP.\n");
+ halbtc8821a2ant_action_a2dp(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n");
+ halbtc8821a2ant_action_a2dp_pan_hs(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n");
+ halbtc8821a2ant_action_pan_edr(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_PANHS:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = HS mode.\n");
+ halbtc8821a2ant_action_pan_hs(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n");
+ halbtc8821a2ant_action_pan_edr_a2dp(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_PANEDR_HID:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n");
+ halbtc8821a2ant_action_pan_edr_hid(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n");
+ btc8821a2ant_act_hid_a2dp_pan_edr(btcoexist);
+ break;
+ case BT_8821A_2ANT_COEX_ALGO_HID_A2DP:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n");
+ halbtc8821a2ant_action_hid_a2dp(btcoexist);
+ break;
+ default:
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n");
+ halbtc8821a2ant_coex_all_off(btcoexist);
+ break;
+ }
+ coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+ }
+}
+
+/*============================================================
+ *work around function start with wa_halbtc8821a2ant_
+ *============================================================
+ *============================================================
+ * extern function start with EXhalbtc8821a2ant_
+ *============================================================
+ */
+void ex_halbtc8821a2ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+ u8 u1tmp = 0;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], 2Ant Init HW Config!!\n");
+
+ /* backup rf 0x1e value */
+ coex_dm->bt_rf0x1e_backup =
+ btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff);
+
+ /* 0x790[5:0] = 0x5 */
+ u1tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+ u1tmp &= 0xc0;
+ u1tmp |= 0x5;
+ btcoexist->btc_write_1byte(btcoexist, 0x790, u1tmp);
+
+ /*Antenna config */
+ halbtc8821a2ant_set_ant_path(btcoexist,
+ BTC_ANT_WIFI_AT_MAIN, true, false);
+
+ /* PTA parameter */
+ halbtc8821a2ant_coex_table(btcoexist,
+ FORCE_EXEC, 0x55555555, 0x55555555,
+ 0xffff, 0x3);
+
+ /* Enable counter statistics */
+ /*0x76e[3] = 1, WLAN_Act control by PTA*/
+ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+ btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3);
+ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
+}
+
+void
+ex_halbtc8821a2ant_init_coex_dm(
+ struct btc_coexist *btcoexist
+ )
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Coex Mechanism Init!!\n");
+
+ halbtc8821a2ant_init_coex_dm(btcoexist);
+}
+
+void
+ex_halbtc8821a2ant_display_coex_info(
+ struct btc_coexist *btcoexist
+ )
+{
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+ u8 u1tmp[4], i, bt_info_ext, ps_tdma_case = 0;
+ u32 u4tmp[4];
+ bool roam = false, scan = false, link = false, wifi_under_5g = false;
+ bool bt_hs_on = false, wifi_busy = false;
+ long wifi_rssi = 0, bt_hs_rssi = 0;
+ u32 wifi_bw, wifi_traffic_dir;
+ u8 wifi_dot_11_chnl, wifi_hs_chnl;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n ============[BT Coexist info]============");
+
+ if (!board_info->bt_exist) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!");
+ return;
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:",
+ board_info->pg_ant_num, board_info->btdm_ant_num);
+
+ if (btcoexist->manual_control) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s", "[Action Manual control]!!");
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %s / %d", "BT stack/ hci ext ver",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)",
+ "CoexVer/ FwVer/ PatchVer",
+ glcoex_ver_date_8821a_2ant, glcoex_ver_8821a_2ant,
+ fw_ver, bt_patch_ver, bt_patch_ver);
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_U1_WIFI_DOT11_CHNL, &wifi_dot_11_chnl);
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d / %d(%d)",
+ "Dot11 channel / HsMode(HsChnl)",
+ wifi_dot_11_chnl, bt_hs_on, wifi_hs_chnl);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %02x %02x %02x ",
+ "H2C Wifi inform bt chnl Info",
+ coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1],
+ coex_dm->wifi_chnl_info[2]);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+ btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %ld/ %ld", "Wifi rssi/ HS rssi",
+ wifi_rssi, bt_hs_rssi);
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan",
+ link, roam, scan);
+
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_U4_WIFI_BW, &wifi_bw);
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifi_traffic_dir);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %s / %s/ %s ", "Wifi status",
+ (wifi_under_5g ? "5G" : "2.4G"),
+ ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+ (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+ ((!wifi_busy) ? "idle" :
+ ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+ "uplink" : "downlink")));
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]",
+ ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") :
+ ((BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status)
+ ? "idle" : ((BT_8821A_2ANT_BT_STATUS_CON_IDLE ==
+ coex_dm->bt_status) ? "connected-idle" : "busy"))),
+ coex_sta->bt_rssi, coex_sta->bt_retry_cnt);
+
+ if (stack_info->profile_notified) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP",
+ stack_info->sco_exist, stack_info->hid_exist,
+ stack_info->pan_exist, stack_info->a2dp_exist);
+
+ btcoexist->btc_disp_dbg_msg(btcoexist,
+ BTC_DBG_DISP_BT_LINK_INFO);
+ }
+
+ bt_info_ext = coex_sta->bt_info_ext;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s",
+ "BT Info A2DP rate",
+ (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate");
+
+ for (i = 0; i < BT_INFO_SRC_8821A_2ANT_MAX; i++) {
+ if (coex_sta->bt_info_c2h_cnt[i]) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)",
+ glbt_info_src_8821a_2ant[i],
+ coex_sta->bt_info_c2h[i][0],
+ coex_sta->bt_info_c2h[i][1],
+ coex_sta->bt_info_c2h[i][2],
+ coex_sta->bt_info_c2h[i][3],
+ coex_sta->bt_info_c2h[i][4],
+ coex_sta->bt_info_c2h[i][5],
+ coex_sta->bt_info_c2h[i][6],
+ coex_sta->bt_info_c2h_cnt[i]);
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/%s",
+ "PS state, IPS/LPS",
+ ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+ ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")));
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+ /* Sw mechanism*/
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+ "============[Sw mechanism]============");
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d/ %d/ %d/ %d ",
+ "SM1[ShRf/ LpRA/ LimDig/ btLna]",
+ coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra,
+ coex_dm->limited_dig, coex_dm->cur_bt_lna_constrain);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d/ %d/ %d(0x%x) ",
+ "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]",
+ coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off,
+ coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl);
+
+ /* Fw mechanism*/
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+ "============[Fw mechanism]============");
+
+ if (!btcoexist->manual_control) {
+ ps_tdma_case = coex_dm->cur_ps_tdma;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %02x %02x %02x %02x %02x case-%d",
+ "PS TDMA",
+ coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1],
+ coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3],
+ coex_dm->ps_tdma_para[4], ps_tdma_case);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct",
+ coex_dm->cur_dec_bt_pwr,
+ coex_dm->cur_ignore_wlan_act);
+ }
+
+ /* Hw setting*/
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s", "============[Hw setting]============");
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal",
+ coex_dm->bt_rf0x1e_backup);
+
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+ u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x6cc);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x ",
+ "0x778 (W_Act)/ 0x6cc (CoTab Sel)",
+ u1tmp[0], u1tmp[1]);
+
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db);
+ u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xc5b);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x8db(ADC)/0xc5b[29:25](DAC)",
+ ((u1tmp[0]&0x60)>>5), ((u1tmp[1]&0x3e)>>1));
+
+ u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+ "0xcb4[7:0](ctrl)/ 0xcb4[29:28](val)",
+ u4tmp[0]&0xff, ((u4tmp[0]&0x30000000)>>28));
+
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+ u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+ u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x974);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x40/ 0x4c[24:23]/ 0x974",
+ u1tmp[0], ((u4tmp[0]&0x01800000)>>23), u4tmp[1]);
+
+ u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+ "0x550(bcn ctrl)/0x522",
+ u4tmp[0], u1tmp[0]);
+
+ u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa0a);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+ "0xc50(DIG)/0xa0a(CCK-TH)",
+ u4tmp[0], u1tmp[0]);
+
+ u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48);
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b);
+ u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+ "OFDM-FA/ CCK-FA",
+ u4tmp[0], (u1tmp[0]<<8) + u1tmp[1]);
+
+ u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+ u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+ u4tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+ "0x6c0/0x6c4/0x6c8",
+ u4tmp[0], u4tmp[1], u4tmp[2]);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+ "0x770 (hi-pri Rx/Tx)",
+ coex_sta->high_priority_rx, coex_sta->high_priority_tx);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+ "0x774(low-pri Rx/Tx)",
+ coex_sta->low_priority_rx, coex_sta->low_priority_tx);
+
+ /* Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang*/
+ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x41b);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x",
+ "0x41b (mgntQ hang chk == 0xf)",
+ u1tmp[0]);
+
+ btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+void ex_halbtc8821a2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_IPS_ENTER == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS ENTER notify\n");
+ coex_sta->under_ips = true;
+ halbtc8821a2ant_coex_all_off(btcoexist);
+ } else if (BTC_IPS_LEAVE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], IPS LEAVE notify\n");
+ coex_sta->under_ips = false;
+ /*halbtc8821a2ant_init_coex_dm(btcoexist);*/
+ }
+}
+
+void ex_halbtc8821a2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_LPS_ENABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS ENABLE notify\n");
+ coex_sta->under_lps = true;
+ } else if (BTC_LPS_DISABLE == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], LPS DISABLE notify\n");
+ coex_sta->under_lps = false;
+ }
+}
+
+void ex_halbtc8821a2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_SCAN_START == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN START notify\n");
+ } else if (BTC_SCAN_FINISH == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], SCAN FINISH notify\n");
+ }
+}
+
+void ex_halbtc8821a2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+ if (BTC_ASSOCIATE_START == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT START notify\n");
+ } else if (BTC_ASSOCIATE_FINISH == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], CONNECT FINISH notify\n");
+ }
+}
+
+void ex_halbtc8821a2ant_media_status_notify(struct btc_coexist *btcoexist,
+ u8 type)
+{
+ u8 h2c_parameter[3] = {0};
+ u32 wifi_bw;
+ u8 wifi_central_chnl;
+
+ if (BTC_MEDIA_CONNECT == type) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA connect notify\n");
+ } else {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], MEDIA disconnect notify\n");
+ }
+
+ /* only 2.4G we need to inform bt the chnl mask*/
+ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL,
+ &wifi_central_chnl);
+ if ((BTC_MEDIA_CONNECT == type) &&
+ (wifi_central_chnl <= 14)) {
+ h2c_parameter[0] = 0x1;
+ h2c_parameter[1] = wifi_central_chnl;
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ if (BTC_WIFI_BW_HT40 == wifi_bw)
+ h2c_parameter[2] = 0x30;
+ else
+ h2c_parameter[2] = 0x20;
+ }
+
+ coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+ coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+ coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+ "[BTCoex], FW write 0x66 = 0x%x\n",
+ h2c_parameter[0]<<16|h2c_parameter[1]<<8|h2c_parameter[2]);
+
+ btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8821a2ant_special_packet_notify(struct btc_coexist *btcoexist,
+ u8 type) {
+ if (type == BTC_PACKET_DHCP) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], DHCP Packet notify\n");
+ }
+}
+
+void ex_halbtc8821a2ant_bt_info_notify(struct btc_coexist *btcoexist,
+ u8 *tmp_buf, u8 length)
+{
+ u8 bt_info = 0;
+ u8 i, rsp_source = 0;
+ static u32 set_bt_lna_cnt, set_bt_psd_mode;
+ bool bt_busy = false, limited_dig = false;
+ bool wifi_connected = false, bt_hs_on = false;
+
+ coex_sta->c2h_bt_info_req_sent = false;
+
+ rsp_source = tmp_buf[0]&0xf;
+ if (rsp_source >= BT_INFO_SRC_8821A_2ANT_MAX)
+ rsp_source = BT_INFO_SRC_8821A_2ANT_WIFI_FW;
+ coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Bt info[%d], length = %d, hex data = [",
+ rsp_source, length);
+ for (i = 0; i < length; i++) {
+ coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i];
+ if (i == 1)
+ bt_info = tmp_buf[i];
+ if (i == length-1) {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x]\n", tmp_buf[i]);
+ } else {
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "0x%02x, ", tmp_buf[i]);
+ }
+ }
+
+ if (BT_INFO_SRC_8821A_2ANT_WIFI_FW != rsp_source) {
+ coex_sta->bt_retry_cnt = /* [3:0]*/
+ coex_sta->bt_info_c2h[rsp_source][2]&0xf;
+
+ coex_sta->bt_rssi =
+ coex_sta->bt_info_c2h[rsp_source][3]*2+10;
+
+ coex_sta->bt_info_ext =
+ coex_sta->bt_info_c2h[rsp_source][4];
+
+ /* Here we need to resend some wifi info to BT*/
+ /* because bt is reset and loss of the info.*/
+ if ((coex_sta->bt_info_ext & BIT1)) {
+ btcoexist->btc_get(btcoexist,
+ BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+ if (wifi_connected) {
+ ex_halbtc8821a2ant_media_status_notify(btcoexist,
+ BTC_MEDIA_CONNECT);
+ } else {
+ ex_halbtc8821a2ant_media_status_notify(btcoexist,
+ BTC_MEDIA_DISCONNECT);
+ }
+
+ set_bt_psd_mode = 0;
+ }
+ if (set_bt_psd_mode <= 3) {
+ halbtc8821a2ant_set_bt_psd_mode(btcoexist, FORCE_EXEC,
+ 0x0); /*fix CH-BW mode*/
+ set_bt_psd_mode++;
+ }
+
+ if (coex_dm->cur_bt_lna_constrain) {
+ if (!(coex_sta->bt_info_ext & BIT2)) {
+ if (set_bt_lna_cnt <= 3) {
+ btc8821a2_set_bt_lna_const(btcoexist,
+ FORCE_EXEC,
+ true);
+ set_bt_lna_cnt++;
+ }
+ }
+ } else {
+ set_bt_lna_cnt = 0;
+ }
+
+ if ((coex_sta->bt_info_ext & BIT3)) {
+ halbtc8821a2ant_ignore_wlan_act(btcoexist,
+ FORCE_EXEC, false);
+ } else {
+ /* BT already NOT ignore Wlan active, do nothing here.*/
+ }
+
+ if ((coex_sta->bt_info_ext & BIT4)) {
+ /* BT auto report already enabled, do nothing*/
+ } else {
+ halbtc8821a2ant_bt_auto_report(btcoexist,
+ FORCE_EXEC, true);
+ }
+ }
+
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+ /* check BIT2 first ==> check if bt is under inquiry or page scan*/
+ if (bt_info & BT_INFO_8821A_2ANT_B_INQ_PAGE) {
+ coex_sta->c2h_bt_inquiry_page = true;
+ coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE;
+ } else {
+ coex_sta->c2h_bt_inquiry_page = false;
+ if (bt_info == 0x1) {
+ /* connection exists but not busy*/
+ coex_sta->bt_link_exist = true;
+ coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_CON_IDLE;
+ } else if (bt_info & BT_INFO_8821A_2ANT_B_CONNECTION) {
+ /* connection exists and some link is busy*/
+ coex_sta->bt_link_exist = true;
+ if (bt_info & BT_INFO_8821A_2ANT_B_FTP)
+ coex_sta->pan_exist = true;
+ else
+ coex_sta->pan_exist = false;
+ if (bt_info & BT_INFO_8821A_2ANT_B_A2DP)
+ coex_sta->a2dp_exist = true;
+ else
+ coex_sta->a2dp_exist = false;
+ if (bt_info & BT_INFO_8821A_2ANT_B_HID)
+ coex_sta->hid_exist = true;
+ else
+ coex_sta->hid_exist = false;
+ if (bt_info & BT_INFO_8821A_2ANT_B_SCO_ESCO)
+ coex_sta->sco_exist = true;
+ else
+ coex_sta->sco_exist = false;
+ coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE;
+ } else {
+ coex_sta->bt_link_exist = false;
+ coex_sta->pan_exist = false;
+ coex_sta->a2dp_exist = false;
+ coex_sta->hid_exist = false;
+ coex_sta->sco_exist = false;
+ coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_IDLE;
+ }
+
+ if (bt_hs_on)
+ coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE;
+ }
+
+ if (BT_8821A_2ANT_BT_STATUS_NON_IDLE == coex_dm->bt_status)
+ bt_busy = true;
+ else
+ bt_busy = false;
+ btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+ if (BT_8821A_2ANT_BT_STATUS_IDLE != coex_dm->bt_status)
+ limited_dig = true;
+ else
+ limited_dig = false;
+ coex_dm->limited_dig = limited_dig;
+ btcoexist->btc_set(btcoexist,
+ BTC_SET_BL_BT_LIMITED_DIG, &limited_dig);
+
+ halbtc8821a2ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8821a2ant_halt_notify(struct btc_coexist *btcoexist)
+{
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+ "[BTCoex], Halt notify\n");
+
+ halbtc8821a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+ ex_halbtc8821a2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8821a2ant_periodical(struct btc_coexist *btcoexist)
+{
+ static u8 dis_ver_info_cnt;
+ u32 fw_ver = 0, bt_patch_ver = 0;
+ struct btc_board_info *board_info = &btcoexist->board_info;
+ struct btc_stack_info *stack_info = &btcoexist->stack_info;
+
+ BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+ "[BTCoex], ==========================Periodical===========================\n");
+
+ if (dis_ver_info_cnt <= 5) {
+ dis_ver_info_cnt += 1;
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ****************************************************************\n");
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n",
+ board_info->pg_ant_num,
+ board_info->btdm_ant_num,
+ board_info->btdm_ant_pos);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], BT stack/ hci ext ver = %s / %d\n",
+ ((stack_info->profile_notified) ? "Yes" : "No"),
+ stack_info->hci_version);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+ &bt_patch_ver);
+ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
+ glcoex_ver_date_8821a_2ant, glcoex_ver_8821a_2ant,
+ fw_ver, bt_patch_ver, bt_patch_ver);
+ BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+ "[BTCoex], ****************************************************************\n");
+ }
+
+ halbtc8821a2ant_query_bt_info(btcoexist);
+ halbtc8821a2ant_monitor_bt_ctr(btcoexist);
+ btc8821a2ant_mon_bt_en_dis(btcoexist);
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h
new file mode 100644
index 00000000000..b4cf1f53d51
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h
@@ -0,0 +1,205 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012 Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/*===========================================
+ * The following is for 8821A 2Ant BT Co-exist definition
+ *===========================================
+*/
+#define BT_INFO_8821A_2ANT_B_FTP BIT7
+#define BT_INFO_8821A_2ANT_B_A2DP BIT6
+#define BT_INFO_8821A_2ANT_B_HID BIT5
+#define BT_INFO_8821A_2ANT_B_SCO_BUSY BIT4
+#define BT_INFO_8821A_2ANT_B_ACL_BUSY BIT3
+#define BT_INFO_8821A_2ANT_B_INQ_PAGE BIT2
+#define BT_INFO_8821A_2ANT_B_SCO_ESCO BIT1
+#define BT_INFO_8821A_2ANT_B_CONNECTION BIT0
+
+#define BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT 2
+
+enum _BT_INFO_SRC_8821A_2ANT {
+ BT_INFO_SRC_8821A_2ANT_WIFI_FW = 0x0,
+ BT_INFO_SRC_8821A_2ANT_BT_RSP = 0x1,
+ BT_INFO_SRC_8821A_2ANT_BT_ACTIVE_SEND = 0x2,
+ BT_INFO_SRC_8821A_2ANT_MAX
+};
+
+enum _BT_8821A_2ANT_BT_STATUS {
+ BT_8821A_2ANT_BT_STATUS_IDLE = 0x0,
+ BT_8821A_2ANT_BT_STATUS_CON_IDLE = 0x1,
+ BT_8821A_2ANT_BT_STATUS_NON_IDLE = 0x2,
+ BT_8821A_2ANT_BT_STATUS_MAX
+};
+
+enum _BT_8821A_2ANT_COEX_ALGO {
+ BT_8821A_2ANT_COEX_ALGO_UNDEFINED = 0x0,
+ BT_8821A_2ANT_COEX_ALGO_SCO = 0x1,
+ BT_8821A_2ANT_COEX_ALGO_HID = 0x2,
+ BT_8821A_2ANT_COEX_ALGO_A2DP = 0x3,
+ BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS = 0x4,
+ BT_8821A_2ANT_COEX_ALGO_PANEDR = 0x5,
+ BT_8821A_2ANT_COEX_ALGO_PANHS = 0x6,
+ BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7,
+ BT_8821A_2ANT_COEX_ALGO_PANEDR_HID = 0x8,
+ BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9,
+ BT_8821A_2ANT_COEX_ALGO_HID_A2DP = 0xa,
+ BT_8821A_2ANT_COEX_ALGO_MAX = 0xb,
+};
+
+struct coex_dm_8821a_2ant {
+ /* fw mechanism */
+ bool pre_dec_bt_pwr;
+ bool cur_dec_bt_pwr;
+ bool pre_bt_lna_constrain;
+ bool cur_bt_lna_constrain;
+ u8 pre_bt_psd_mode;
+ u8 cur_bt_psd_mode;
+ u8 pre_fw_dac_swing_lvl;
+ u8 cur_fw_dac_swing_lvl;
+ bool cur_ignore_wlan_act;
+ bool pre_ignore_wlan_act;
+ u8 pre_ps_tdma;
+ u8 cur_ps_tdma;
+ u8 ps_tdma_para[5];
+ u8 tdma_adj_type;
+ bool reset_tdma_adjust;
+ bool pre_ps_tdma_on;
+ bool cur_ps_tdma_on;
+ bool pre_bt_auto_report;
+ bool cur_bt_auto_report;
+
+ /* sw mechanism */
+ bool pre_rf_rx_lpf_shrink;
+ bool cur_rf_rx_lpf_shrink;
+ u32 bt_rf0x1e_backup;
+ bool pre_low_penalty_ra;
+ bool cur_low_penalty_ra;
+ bool pre_dac_swing_on;
+ u32 pre_dac_swing_lvl;
+ bool cur_dac_swing_on;
+ u32 cur_dac_swing_lvl;
+ bool pre_adc_back_off;
+ bool cur_adc_back_off;
+ bool pre_agc_table_en;
+ bool cur_agc_table_en;
+ u32 pre_val0x6c0;
+ u32 cur_val0x6c0;
+ u32 pre_val0x6c4;
+ u32 cur_val0x6c4;
+ u32 pre_val0x6c8;
+ u32 cur_val0x6c8;
+ u8 pre_val0x6cc;
+ u8 cur_val0x6cc;
+ bool limited_dig;
+
+ /* algorithm related */
+ u8 pre_algorithm;
+ u8 cur_algorithm;
+ u8 bt_status;
+ u8 wifi_chnl_info[3];
+};
+
+struct coex_sta_8821a_2ant {
+ bool bt_link_exist;
+ bool sco_exist;
+ bool a2dp_exist;
+ bool hid_exist;
+ bool pan_exist;
+ bool under_lps;
+ bool under_ips;
+ u32 high_priority_tx;
+ u32 high_priority_rx;
+ u32 low_priority_tx;
+ u32 low_priority_rx;
+ u8 bt_rssi;
+ u8 pre_bt_rssi_state;
+ u8 pre_wifi_rssi_state[4];
+ bool c2h_bt_info_req_sent;
+ u8 bt_info_c2h[BT_INFO_SRC_8821A_2ANT_MAX][10];
+ u32 bt_info_c2h_cnt[BT_INFO_SRC_8821A_2ANT_MAX];
+ bool c2h_bt_inquiry_page;
+ u8 bt_retry_cnt;
+ u8 bt_info_ext;
+};
+
+/*===========================================
+ * The following is interface which will notify coex module.
+ *===========================================
+ */
+void
+ex_halbtc8821a2ant_init_hwconfig(
+ struct btc_coexist *btcoexist
+ );
+void
+ex_halbtc8821a2ant_init_coex_dm(
+ struct btc_coexist *btcoexist
+ );
+void
+ex_halbtc8821a2ant_ips_notify(
+ struct btc_coexist *btcoexist,
+ u8 type
+ );
+void
+ex_halbtc8821a2ant_lps_notify(
+ struct btc_coexist *btcoexist,
+ u8 type
+ );
+void
+ex_halbtc8821a2ant_scan_notify(
+ struct btc_coexist *btcoexist,
+ u8 type
+ );
+void
+ex_halbtc8821a2ant_connect_notify(
+ struct btc_coexist *btcoexist,
+ u8 type
+ );
+void
+ex_halbtc8821a2ant_media_status_notify(
+ struct btc_coexist *btcoexist,
+ u8 type
+ );
+void
+ex_halbtc8821a2ant_special_packet_notify(
+ struct btc_coexist *btcoexist,
+ u8 type
+ );
+void
+ex_halbtc8821a2ant_bt_info_notify(
+ struct btc_coexist *btcoexist,
+ u8 *tmp_buf,
+ u8 length
+ );
+void
+ex_halbtc8821a2ant_halt_notify(
+ struct btc_coexist *btcoexist
+ );
+void
+ex_halbtc8821a2ant_periodical(
+ struct btc_coexist *btcoexist
+ );
+void
+ex_halbtc8821a2ant_display_coex_info(
+ struct btc_coexist *btcoexist
+ );
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c
index 33da3dfcfa4..fcf7459b5d6 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c
@@ -32,7 +32,6 @@
struct btc_coexist gl_bt_coexist;
u32 btc_dbg_type[BTC_MSG_MAX];
-static u8 btc_dbg_buf[100];
/***************************************************
* Debug related function
@@ -101,7 +100,7 @@ static bool halbtc_legacy(struct rtl_priv *adapter)
bool is_legacy = false;
- if ((mac->mode == WIRELESS_MODE_B) || (mac->mode == WIRELESS_MODE_B))
+ if ((mac->mode == WIRELESS_MODE_B) || (mac->mode == WIRELESS_MODE_G))
is_legacy = true;
return is_legacy;
@@ -389,7 +388,7 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf)
btcoexist->bt_info.reject_agg_pkt = *bool_tmp;
break;
case BTC_SET_BL_BT_CTRL_AGG_SIZE:
- btcoexist->bt_info.b_bt_ctrl_buf_size = *bool_tmp;
+ btcoexist->bt_info.bt_ctrl_buf_size = *bool_tmp;
break;
case BTC_SET_BL_INC_SCAN_DEV_NUM:
btcoexist->bt_info.increase_scan_dev_num = *bool_tmp;
@@ -417,10 +416,10 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf)
/* rtlpriv->mlmepriv.scan_compensation = *u8_tmp; */
break;
case BTC_SET_U1_1ANT_LPS:
- btcoexist->bt_info.lps_1ant = *u8_tmp;
+ btcoexist->bt_info.lps_val = *u8_tmp;
break;
case BTC_SET_U1_1ANT_RPWM:
- btcoexist->bt_info.rpwm_1ant = *u8_tmp;
+ btcoexist->bt_info.rpwm_val = *u8_tmp;
break;
/* the following are some action which will be triggered */
case BTC_SET_ACT_LEAVE_LPS:
@@ -497,7 +496,7 @@ static u32 halbtc_read_4byte(void *bt_context, u32 reg_addr)
return rtl_read_dword(rtlpriv, reg_addr);
}
-static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u8 data)
+static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u32 data)
{
struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
struct rtl_priv *rtlpriv = btcoexist->adapter;
@@ -506,7 +505,7 @@ static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u8 data)
}
static void halbtc_bitmask_write_1byte(void *bt_context, u32 reg_addr,
- u32 bit_mask, u8 data)
+ u8 bit_mask, u8 data)
{
struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
struct rtl_priv *rtlpriv = btcoexist->adapter;
@@ -652,9 +651,7 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter)
btcoexist->btc_get = halbtc_get;
btcoexist->btc_set = halbtc_set;
- btcoexist->cli_buf = &btc_dbg_buf[0];
-
- btcoexist->bt_info.b_bt_ctrl_buf_size = false;
+ btcoexist->bt_info.bt_ctrl_buf_size = false;
btcoexist->bt_info.agg_buf_size = 5;
btcoexist->bt_info.increase_scan_dev_num = false;
@@ -672,7 +669,7 @@ void exhalbtc_init_hw_config(struct btc_coexist *btcoexist)
btcoexist->statistics.cnt_init_hw_config++;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_init_hwconfig(btcoexist);
+ ex_btc8723b2ant_init_hwconfig(btcoexist);
}
void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist)
@@ -686,7 +683,7 @@ void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist)
btcoexist->statistics.cnt_init_coex_dm++;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_init_coex_dm(btcoexist);
+ ex_btc8723b2ant_init_coex_dm(btcoexist);
btcoexist->initilized = true;
}
@@ -711,7 +708,7 @@ void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type)
halbtc_leave_low_power();
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_ips_notify(btcoexist, ips_type);
+ ex_btc8723b2ant_ips_notify(btcoexist, ips_type);
halbtc_nomal_low_power();
}
@@ -734,7 +731,7 @@ void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type)
lps_type = BTC_LPS_ENABLE;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_lps_notify(btcoexist, lps_type);
+ ex_btc8723b2ant_lps_notify(btcoexist, lps_type);
}
void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type)
@@ -757,7 +754,7 @@ void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type)
halbtc_leave_low_power();
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_scan_notify(btcoexist, scan_type);
+ ex_btc8723b2ant_scan_notify(btcoexist, scan_type);
halbtc_nomal_low_power();
}
@@ -782,14 +779,12 @@ void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action)
halbtc_leave_low_power();
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_connect_notify(btcoexist, asso_type);
+ ex_btc8723b2ant_connect_notify(btcoexist, asso_type);
}
void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
- enum _RT_MEDIA_STATUS media_status)
+ enum rt_media_status media_status)
{
- struct rtl_priv *rtlpriv = btcoexist->adapter;
- struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
u8 status;
if (!halbtc_is_bt_coexist_available(btcoexist))
@@ -805,9 +800,6 @@ void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
halbtc_leave_low_power();
- if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- btc8723b_med_stat_notify(btcoexist, status);
-
halbtc_nomal_low_power();
}
@@ -828,8 +820,8 @@ void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type)
halbtc_leave_low_power();
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_special_packet_notify(btcoexist,
- packet_type);
+ ex_btc8723b2ant_special_packet_notify(btcoexist,
+ packet_type);
halbtc_nomal_low_power();
}
@@ -844,13 +836,11 @@ void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist,
btcoexist->statistics.cnt_bt_info_notify++;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length);
+ ex_btc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length);
}
void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type)
{
- struct rtl_priv *rtlpriv = btcoexist->adapter;
- struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
u8 stack_op_type;
if (!halbtc_is_bt_coexist_available(btcoexist))
@@ -863,10 +853,6 @@ void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type)
halbtc_leave_low_power();
- if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_stack_operation_notify(btcoexist,
- stack_op_type);
-
halbtc_nomal_low_power();
}
@@ -878,7 +864,7 @@ void exhalbtc_halt_notify(struct btc_coexist *btcoexist)
return;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_halt_notify(btcoexist);
+ ex_btc8723b2ant_halt_notify(btcoexist);
}
void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state)
@@ -898,7 +884,7 @@ void exhalbtc_periodical(struct btc_coexist *btcoexist)
halbtc_leave_low_power();
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_periodical(btcoexist);
+ ex_btc8723b2ant_periodical(btcoexist);
halbtc_nomal_low_power();
}
@@ -997,5 +983,5 @@ void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist)
return;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
- ex_halbtc8723b2ant_display_coex_info(btcoexist);
+ ex_btc8723b2ant_display_coex_info(btcoexist);
}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h
index 049f4c8d98a..1345545f66b 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h
@@ -55,9 +55,16 @@
#define BTC_RATE_DISABLE 0
#define BTC_RATE_ENABLE 1
+/* single Antenna definition */
#define BTC_ANT_PATH_WIFI 0
#define BTC_ANT_PATH_BT 1
#define BTC_ANT_PATH_PTA 2
+/* dual Antenna definition */
+#define BTC_ANT_WIFI_AT_MAIN 0
+#define BTC_ANT_WIFI_AT_AUX 1
+/* coupler Antenna definition */
+#define BTC_ANT_WIFI_AT_CPL_MAIN 0
+#define BTC_ANT_WIFI_AT_CPL_AUX 1
enum btc_chip_interface {
BTC_INTF_UNKNOWN = 0,
@@ -68,7 +75,7 @@ enum btc_chip_interface {
BTC_INTF_MAX
};
-enum BTC_CHIP_TYPE {
+enum btc_chip_type {
BTC_CHIP_UNDEF = 0,
BTC_CHIP_CSR_BC4 = 1,
BTC_CHIP_CSR_BC8 = 2,
@@ -78,11 +85,12 @@ enum BTC_CHIP_TYPE {
BTC_CHIP_MAX
};
-enum BTC_MSG_TYPE {
+enum btc_msg_type {
BTC_MSG_INTERFACE = 0x0,
BTC_MSG_ALGORITHM = 0x1,
BTC_MSG_MAX
};
+
extern u32 btc_dbg_type[];
/* following is for BTC_MSG_INTERFACE */
@@ -101,20 +109,12 @@ extern u32 btc_dbg_type[];
#define ALGO_TRACE_SW_DETAIL BIT8
#define ALGO_TRACE_SW_EXEC BIT9
-#define BT_COEX_ANT_TYPE_PG 0
-#define BT_COEX_ANT_TYPE_ANTDIV 1
-#define BT_COEX_ANT_TYPE_DETECTED 2
-#define BTC_MIMO_PS_STATIC 0
-#define BTC_MIMO_PS_DYNAMIC 1
-#define BTC_RATE_DISABLE 0
-#define BTC_RATE_ENABLE 1
-#define BTC_ANT_PATH_WIFI 0
-#define BTC_ANT_PATH_BT 1
-#define BTC_ANT_PATH_PTA 2
-
-
-#define CL_SPRINTF snprintf
-#define CL_PRINTF(buf) printk("%s", buf)
+/* following is for wifi link status */
+#define WIFI_STA_CONNECTED BIT0
+#define WIFI_AP_CONNECTED BIT1
+#define WIFI_HS_CONNECTED BIT2
+#define WIFI_P2P_GO_CONNECTED BIT3
+#define WIFI_P2P_GC_CONNECTED BIT4
#define BTC_PRINT(dbgtype, dbgflag, printstr, ...) \
do { \
@@ -123,46 +123,15 @@ extern u32 btc_dbg_type[];
} \
} while (0)
-#define BTC_PRINT_F(dbgtype, dbgflag, printstr, ...) \
- do { \
- if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {\
- pr_info("%s: ", __func__); \
- printk(printstr, ##__VA_ARGS__); \
- } \
- } while (0)
-
-#define BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _ptr) \
- do { \
- if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) { \
- int __i; \
- u8 *__ptr = (u8 *)_ptr; \
- printk printstr; \
- for (__i = 0; __i < 6; __i++) \
- printk("%02X%s", __ptr[__i], (__i == 5) ? \
- "" : "-"); \
- pr_info("\n"); \
- } \
- } while (0)
-
-#define BTC_PRINT_DATA(dbgtype, dbgflag, _titlestring, _hexdata, _hexdatalen) \
- do { \
- if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) { \
- int __i; \
- u8 *__ptr = (u8 *)_hexdata; \
- printk(_titlestring); \
- for (__i = 0; __i < (int)_hexdatalen; __i++) { \
- printk("%02X%s", __ptr[__i], (((__i + 1) % 4) \
- == 0) ? " " : " ");\
- if (((__i + 1) % 16) == 0) \
- printk("\n"); \
- } \
- pr_debug("\n"); \
- } \
- } while (0)
-
-#define BTC_ANT_PATH_WIFI 0
-#define BTC_ANT_PATH_BT 1
-#define BTC_ANT_PATH_PTA 2
+#define BTC_RSSI_HIGH(_rssi_) \
+ ((_rssi_ == BTC_RSSI_STATE_HIGH || \
+ _rssi_ == BTC_RSSI_STATE_STAY_HIGH) ? true : false)
+#define BTC_RSSI_MEDIUM(_rssi_) \
+ ((_rssi_ == BTC_RSSI_STATE_MEDIUM || \
+ _rssi_ == BTC_RSSI_STATE_STAY_MEDIUM) ? true : false)
+#define BTC_RSSI_LOW(_rssi_) \
+ ((_rssi_ == BTC_RSSI_STATE_LOW || \
+ _rssi_ == BTC_RSSI_STATE_STAY_LOW) ? true : false)
enum btc_power_save_type {
BTC_PS_WIFI_NATIVE = 0,
@@ -224,7 +193,6 @@ enum btc_wifi_pnp {
BTC_WIFI_PNP_MAX
};
-
enum btc_get_type {
/* type bool */
BTC_GET_BL_HS_OPERATION,
@@ -253,6 +221,7 @@ enum btc_get_type {
BTC_GET_U4_WIFI_BW,
BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
BTC_GET_U4_WIFI_FW_VER,
+ BTC_GET_U4_WIFI_LINK_STATUS,
BTC_GET_U4_BT_PATCH_VER,
/* type u1Byte */
@@ -260,6 +229,7 @@ enum btc_get_type {
BTC_GET_U1_WIFI_CENTRAL_CHNL,
BTC_GET_U1_WIFI_HS_CHNL,
BTC_GET_U1_MAC_PHY_MODE,
+ BTC_GET_U1_AP_NUM,
/* for 1Ant */
BTC_GET_U1_LPS_MODE,
@@ -270,7 +240,6 @@ enum btc_get_type {
BTC_GET_MAX
};
-
enum btc_set_type {
/* type bool */
BTC_SET_BL_BT_DISABLE,
@@ -283,7 +252,6 @@ enum btc_set_type {
/* type u1Byte */
BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON,
- BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE,
BTC_SET_UI_SCAN_SIG_COMPENSATION,
BTC_SET_U1_AGG_BUF_SIZE,
@@ -295,6 +263,9 @@ enum btc_set_type {
/* type bool */
BTC_SET_BL_BT_SCO_BUSY,
/* type u1Byte */
+ BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE,
+ BTC_SET_U1_LPS_VAL,
+ BTC_SET_U1_RPWM_VAL,
BTC_SET_U1_1ANT_LPS,
BTC_SET_U1_1ANT_RPWM,
/* type trigger some action */
@@ -358,6 +329,20 @@ enum btc_notify_type_special_packet {
BTC_PACKET_MAX
};
+enum hci_ext_bt_operation {
+ HCI_BT_OP_NONE = 0x0,
+ HCI_BT_OP_INQUIRY_START = 0x1,
+ HCI_BT_OP_INQUIRY_FINISH = 0x2,
+ HCI_BT_OP_PAGING_START = 0x3,
+ HCI_BT_OP_PAGING_SUCCESS = 0x4,
+ HCI_BT_OP_PAGING_UNSUCCESS = 0x5,
+ HCI_BT_OP_PAIRING_START = 0x6,
+ HCI_BT_OP_PAIRING_FINISH = 0x7,
+ HCI_BT_OP_BT_DEV_ENABLE = 0x8,
+ HCI_BT_OP_BT_DEV_DISABLE = 0x9,
+ HCI_BT_OP_MAX
+};
+
enum btc_notify_type_stack_operation {
BTC_STACK_OP_NONE = 0x0,
BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1,
@@ -365,17 +350,16 @@ enum btc_notify_type_stack_operation {
BTC_STACK_OP_MAX
};
-
typedef u8 (*bfp_btc_r1)(void *btc_context, u32 reg_addr);
typedef u16 (*bfp_btc_r2)(void *btc_context, u32 reg_addr);
typedef u32 (*bfp_btc_r4)(void *btc_context, u32 reg_addr);
-typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u8 data);
+typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u32 data);
typedef void (*bfp_btc_w1_bit_mak)(void *btc_context, u32 reg_addr,
- u32 bit_mask, u8 data1b);
+ u8 bit_mask, u8 data1b);
typedef void (*bfp_btc_w2)(void *btc_context, u32 reg_addr, u16 data);
@@ -413,20 +397,22 @@ struct btc_bt_info {
u8 agg_buf_size;
bool limited_dig;
bool reject_agg_pkt;
- bool b_bt_ctrl_buf_size;
+ bool bt_ctrl_buf_size;
bool increase_scan_dev_num;
u16 bt_hci_ver;
u16 bt_real_fw_ver;
u8 bt_fw_ver;
+ bool bt_disable_low_pwr;
+
/* the following is for 1Ant solution */
bool bt_ctrl_lps;
bool bt_pwr_save_mode;
bool bt_lps_on;
bool force_to_roam;
u8 force_exec_pwr_cmd_cnt;
- u8 lps_1ant;
- u8 rpwm_1ant;
+ u8 lps_val;
+ u8 rpwm_val;
u32 ra_mask;
};
@@ -457,6 +443,7 @@ struct btc_statistics {
u32 cnt_special_packet_notify;
u32 cnt_bt_info_notify;
u32 cnt_periodical;
+ u32 cnt_coex_dm_switch;
u32 cnt_stack_operation_notify;
u32 cnt_dbg_ctrl;
};
@@ -493,7 +480,6 @@ struct btc_coexist {
bool initilized;
bool stop_coex_dm;
bool manual_control;
- u8 *cli_buf;
struct btc_statistics statistics;
u8 pwr_mode_val[10];
@@ -509,7 +495,6 @@ struct btc_coexist {
bfp_btc_set_bb_reg btc_set_bb_reg;
bfp_btc_get_bb_reg btc_get_bb_reg;
-
bfp_btc_set_rf_reg btc_set_rf_reg;
bfp_btc_get_rf_reg btc_get_rf_reg;
@@ -533,13 +518,14 @@ void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type);
void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type);
void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action);
void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
- enum _RT_MEDIA_STATUS media_status);
+ enum rt_media_status media_status);
void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type);
void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf,
u8 length);
void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type);
void exhalbtc_halt_notify(struct btc_coexist *btcoexist);
void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state);
+void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist);
void exhalbtc_periodical(struct btc_coexist *btcoexist);
void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len,
u8 *data);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c
index 0ab94fe4cbb..b9b0cb7af8e 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c
+++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c
@@ -22,19 +22,19 @@
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
-
#include "../wifi.h"
-#include "rtl_btc.h"
-#include "halbt_precomp.h"
-
#include <linux/vmalloc.h>
#include <linux/module.h>
+#include "rtl_btc.h"
+#include "halbt_precomp.h"
+
static struct rtl_btc_ops rtl_btc_operation = {
.btc_init_variables = rtl_btc_init_variables,
.btc_init_hal_vars = rtl_btc_init_hal_vars,
.btc_init_hw_config = rtl_btc_init_hw_config,
.btc_ips_notify = rtl_btc_ips_notify,
+ .btc_lps_notify = rtl_btc_lps_notify,
.btc_scan_notify = rtl_btc_scan_notify,
.btc_connect_notify = rtl_btc_connect_notify,
.btc_mediastatus_notify = rtl_btc_mediastatus_notify,
@@ -44,6 +44,7 @@ static struct rtl_btc_ops rtl_btc_operation = {
.btc_is_limited_dig = rtl_btc_is_limited_dig,
.btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo,
.btc_is_bt_disabled = rtl_btc_is_bt_disabled,
+ .btc_special_packet_notify = rtl_btc_special_packet_notify,
};
void rtl_btc_init_variables(struct rtl_priv *rtlpriv)
@@ -85,6 +86,11 @@ void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type)
exhalbtc_ips_notify(&gl_bt_coexist, type);
}
+void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type)
+{
+ exhalbtc_lps_notify(&gl_bt_coexist, type);
+}
+
void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype)
{
exhalbtc_scan_notify(&gl_bt_coexist, scantype);
@@ -96,13 +102,14 @@ void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action)
}
void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
- enum _RT_MEDIA_STATUS mstatus)
+ enum rt_media_status mstatus)
{
exhalbtc_mediastatus_notify(&gl_bt_coexist, mstatus);
}
void rtl_btc_periodical(struct rtl_priv *rtlpriv)
{
+ /*rtl_bt_dm_monitor();*/
exhalbtc_periodical(&gl_bt_coexist);
}
@@ -150,12 +157,18 @@ bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv)
bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv)
{
+ /* It seems 'bt_disabled' is never be initialized or set. */
if (gl_bt_coexist.bt_info.bt_disabled)
return true;
else
return false;
}
+void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type)
+{
+ return exhalbtc_special_packet_notify(&gl_bt_coexist, pkt_type);
+}
+
struct rtl_btc_ops *rtl_btc_get_ops_pointer(void)
{
return &rtl_btc_operation;
@@ -174,11 +187,11 @@ u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv)
return num;
}
-enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw)
+enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- enum _RT_MEDIA_STATUS m_status = RT_MEDIA_DISCONNECT;
+ enum rt_media_status m_status = RT_MEDIA_DISCONNECT;
u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h
index 805b22cc8fc..ccd5a0f91e3 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h
+++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h
@@ -31,22 +31,24 @@ void rtl_btc_init_variables(struct rtl_priv *rtlpriv);
void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv);
void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv);
void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type);
+void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type);
void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype);
void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action);
void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
- enum _RT_MEDIA_STATUS mstatus);
+ enum rt_media_status mstatus);
void rtl_btc_periodical(struct rtl_priv *rtlpriv);
void rtl_btc_halt_notify(void);
void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmpbuf, u8 length);
bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv);
bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv);
bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv);
+void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type);
struct rtl_btc_ops *rtl_btc_get_ops_pointer(void);
u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv);
u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv);
u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv);
-enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw);
+enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw);
#endif
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 67d1ee6edca..74a8ba4b884 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -646,7 +646,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
== 2) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
- "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%d\n",
+ "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%x\n",
prio, ring->idx,
skb_queue_len(&ring->queue));
@@ -1469,7 +1469,7 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
if ((own == 1) && (hw_queue != BEACON_QUEUE)) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
- "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
+ "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%x\n",
hw_queue, ring->idx, idx,
skb_queue_len(&ring->queue));
@@ -1511,7 +1511,7 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
if ((ring->entries - skb_queue_len(&ring->queue)) < 2 &&
hw_queue != BEACON_QUEUE) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
- "less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
+ "less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%x\n",
hw_queue, ring->idx, idx,
skb_queue_len(&ring->queue));
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index 361435f8608..1ac6383e794 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -317,6 +317,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
{RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/
{RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
{RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
+ {RTL_USB_DEVICE(0x0df6, 0x0070, rtl92cu_hal_cfg)}, /*Sitecom - 150N */
{RTL_USB_DEVICE(0x0df6, 0x0077, rtl92cu_hal_cfg)}, /*Sitecom-WLA2100V2*/
{RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/
{RTL_USB_DEVICE(0x4856, 0x0091, rtl92cu_hal_cfg)}, /*NetweeN - Feixun*/
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
index 592125a5f19..1961b8e28dc 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
@@ -677,7 +677,7 @@ static void _rtl92d_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw,
rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index] = data;
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
- "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%ulx\n",
+ "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n",
rtlphy->pwrgroup_cnt, index,
rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index]);
if (index == 13)
@@ -2531,7 +2531,7 @@ static void _rtl92d_phy_reload_lck_setting(struct ieee80211_hw *hw,
if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) {/* Path-A for 5G */
u4tmp = curveindex_5g[channel-1];
RTPRINT(rtlpriv, FINIT, INIT_IQK,
- "ver 1 set RF-A, 5G, 0x28 = 0x%ulx !!\n", u4tmp);
+ "ver 1 set RF-A, 5G, 0x28 = 0x%x !!\n", u4tmp);
if (rtlpriv->rtlhal.macphymode == DUALMAC_DUALPHY &&
rtlpriv->rtlhal.interfaceindex == 1) {
bneed_powerdown_radio =
@@ -2550,7 +2550,7 @@ static void _rtl92d_phy_reload_lck_setting(struct ieee80211_hw *hw,
} else if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) {
u4tmp = curveindex_2g[channel-1];
RTPRINT(rtlpriv, FINIT, INIT_IQK,
- "ver 3 set RF-B, 2G, 0x28 = 0x%ulx !!\n", u4tmp);
+ "ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n", u4tmp);
if (rtlpriv->rtlhal.macphymode == DUALMAC_DUALPHY &&
rtlpriv->rtlhal.interfaceindex == 0) {
bneed_powerdown_radio =
@@ -2562,7 +2562,7 @@ static void _rtl92d_phy_reload_lck_setting(struct ieee80211_hw *hw,
}
rtl_set_rfreg(hw, erfpath, RF_SYN_G4, 0x3f800, u4tmp);
RTPRINT(rtlpriv, FINIT, INIT_IQK,
- "ver 3 set RF-B, 2G, 0x28 = 0x%ulx !!\n",
+ "ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n",
rtl_get_rfreg(hw, erfpath, RF_SYN_G4, 0x3f800));
if (bneed_powerdown_radio)
_rtl92d_phy_restore_rf_env(hw, erfpath, &u4regvalue);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
index 5d534df8d90..f76c50f5ab8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
@@ -56,11 +56,11 @@ void rtl8723ae_bt_coex_off_before_lps(struct ieee80211_hw *hw)
}
}
-static enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw)
+static enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- enum _RT_MEDIA_STATUS m_status = RT_MEDIA_DISCONNECT;
+ enum rt_media_status m_status = RT_MEDIA_DISCONNECT;
u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 407a7936d36..541b077ae86 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -170,6 +170,11 @@ enum rf_tx_num {
RF_TX_NUM_NONIMPLEMENT,
};
+#define PACKET_NORMAL 0
+#define PACKET_DHCP 1
+#define PACKET_ARP 2
+#define PACKET_EAPOL 3
+
struct txpower_info_2g {
u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
@@ -234,8 +239,9 @@ enum hardware_type {
HARDWARE_TYPE_RTL8192DU,
HARDWARE_TYPE_RTL8723AE,
HARDWARE_TYPE_RTL8723U,
- HARDWARE_TYPE_RTL8723BE,
HARDWARE_TYPE_RTL8188EE,
+ HARDWARE_TYPE_RTL8723BE,
+ HARDWARE_TYPE_RTL8192EE,
HARDWARE_TYPE_RTL8821AE,
HARDWARE_TYPE_RTL8812AE,
@@ -428,7 +434,7 @@ enum hw_variables {
HW_VAR_DATA_FILTER,
};
-enum _RT_MEDIA_STATUS {
+enum rt_media_status {
RT_MEDIA_DISCONNECT = 0,
RT_MEDIA_CONNECT = 1
};
@@ -2312,10 +2318,11 @@ struct rtl_btc_ops {
void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv);
void (*btc_init_hw_config) (struct rtl_priv *rtlpriv);
void (*btc_ips_notify) (struct rtl_priv *rtlpriv, u8 type);
+ void (*btc_lps_notify)(struct rtl_priv *rtlpriv, u8 type);
void (*btc_scan_notify) (struct rtl_priv *rtlpriv, u8 scantype);
void (*btc_connect_notify) (struct rtl_priv *rtlpriv, u8 action);
void (*btc_mediastatus_notify) (struct rtl_priv *rtlpriv,
- enum _RT_MEDIA_STATUS mstatus);
+ enum rt_media_status mstatus);
void (*btc_periodical) (struct rtl_priv *rtlpriv);
void (*btc_halt_notify) (void);
void (*btc_btinfo_notify) (struct rtl_priv *rtlpriv,
@@ -2323,6 +2330,8 @@ struct rtl_btc_ops {
bool (*btc_is_limited_dig) (struct rtl_priv *rtlpriv);
bool (*btc_is_disable_edca_turbo) (struct rtl_priv *rtlpriv);
bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv);
+ void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv,
+ u8 pkt_type);
};
struct proxim {
diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c
index a0aa8fa7239..735be535214 100644
--- a/drivers/net/wireless/ti/wl1251/spi.c
+++ b/drivers/net/wireless/ti/wl1251/spi.c
@@ -345,7 +345,6 @@ static int wl1251_spi_remove(struct spi_device *spi)
{
struct wl1251 *wl = spi_get_drvdata(spi);
- free_irq(wl->irq, wl);
wl1251_free_hw(wl);
regulator_disable(wl->vio);
diff --git a/drivers/net/wireless/ti/wlcore/debug.h b/drivers/net/wireless/ti/wlcore/debug.h
index 0420bd45e4e..27bfb7c11e7 100644
--- a/drivers/net/wireless/ti/wlcore/debug.h
+++ b/drivers/net/wireless/ti/wlcore/debug.h
@@ -65,7 +65,7 @@ extern u32 wl12xx_debug_level;
pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
#define wl1271_warning(fmt, arg...) \
- pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
+ pr_warn(DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
#define wl1271_notice(fmt, arg...) \
pr_info(DRIVER_PREFIX fmt "\n", ##arg)
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c
index 392c882b28f..69601f6741d 100644
--- a/drivers/net/wireless/ti/wlcore/spi.c
+++ b/drivers/net/wireless/ti/wlcore/spi.c
@@ -327,23 +327,22 @@ static int wl1271_probe(struct spi_device *spi)
struct wl12xx_spi_glue *glue;
struct wlcore_platdev_data pdev_data;
struct resource res[1];
- int ret = -ENOMEM;
+ int ret;
memset(&pdev_data, 0x00, sizeof(pdev_data));
pdev_data.pdata = dev_get_platdata(&spi->dev);
if (!pdev_data.pdata) {
dev_err(&spi->dev, "no platform data\n");
- ret = -ENODEV;
- goto out;
+ return -ENODEV;
}
pdev_data.if_ops = &spi_ops;
- glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ glue = devm_kzalloc(&spi->dev, sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&spi->dev, "can't allocate glue\n");
- goto out;
+ return -ENOMEM;
}
glue->dev = &spi->dev;
@@ -357,14 +356,13 @@ static int wl1271_probe(struct spi_device *spi)
ret = spi_setup(spi);
if (ret < 0) {
dev_err(glue->dev, "spi_setup failed\n");
- goto out_free_glue;
+ return ret;
}
glue->core = platform_device_alloc("wl12xx", PLATFORM_DEVID_AUTO);
if (!glue->core) {
dev_err(glue->dev, "can't allocate platform_device\n");
- ret = -ENOMEM;
- goto out_free_glue;
+ return -ENOMEM;
}
glue->core->dev.parent = &spi->dev;
@@ -398,11 +396,6 @@ static int wl1271_probe(struct spi_device *spi)
out_dev_put:
platform_device_put(glue->core);
-
-out_free_glue:
- kfree(glue);
-
-out:
return ret;
}
@@ -411,7 +404,6 @@ static int wl1271_remove(struct spi_device *spi)
struct wl12xx_spi_glue *glue = spi_get_drvdata(spi);
platform_device_unregister(glue->core);
- kfree(glue);
return 0;
}