Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Fri, 6 Dec 2013 15:37:24 +0000 (10:37 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 6 Dec 2013 15:37:24 +0000 (10:37 -0500)
161 files changed:
Documentation/networking/regulatory.txt
MAINTAINERS
drivers/bcma/host_pci.c
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_wow.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9340_initvals.h
drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h
drivers/net/wireless/ath/ath9k/ar9565_1p1_initvals.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/tx99.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/wow.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/regd.c
drivers/net/wireless/ath/wcn36xx/hal.h
drivers/net/wireless/ath/wcn36xx/main.c
drivers/net/wireless/ath/wcn36xx/smd.c
drivers/net/wireless/ath/wcn36xx/wcn36xx.h
drivers/net/wireless/brcm80211/Kconfig
drivers/net/wireless/brcm80211/brcmfmac/Makefile
drivers/net/wireless/brcm80211/brcmfmac/bcdc.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/bcdc.h [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c [deleted file]
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h [deleted file]
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/fweh.h
drivers/net/wireless/brcm80211/brcmfmac/fwil.c
drivers/net/wireless/brcm80211/brcmfmac/fwil.h
drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
drivers/net/wireless/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/brcm80211/brcmfmac/proto.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/proto.h [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h
drivers/net/wireless/brcm80211/brcmfmac/usb.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmsmac/channel.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/cw1200/cw1200_sdio.c
drivers/net/wireless/cw1200/scan.c
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlegacy/3945-mac.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlegacy/debug.c
drivers/net/wireless/iwlwifi/dvm/debugfs.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/scan.c
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sta_cmdresp.c
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/prism54/islpci_hotplug.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rtl818x/rtl8187/dev.c
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/regd.c
drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h
drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
drivers/net/wireless/rtlwifi/rtl8192cu/dm.c
drivers/net/wireless/rtlwifi/rtl8192cu/dm.h
drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
drivers/net/wireless/rtlwifi/rtl8192cu/table.c
drivers/net/wireless/rtlwifi/stats.c
drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/wireless/ti/wl1251/acx.c
drivers/net/wireless/ti/wl12xx/scan.c
drivers/net/wireless/ti/wlcore/cmd.c
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/scan.c
include/linux/ieee80211.h
include/net/cfg80211.h
include/net/mac80211.h
include/net/regulatory.h
include/uapi/linux/nl80211.h
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debugfs.c
net/mac80211/debugfs_sta.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mesh_plink.c
net/mac80211/mesh_ps.c
net/mac80211/mesh_sync.c
net/mac80211/mlme.c
net/mac80211/rate.h
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rc80211_minstrel_ht_debugfs.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/vht.c
net/mac80211/wpa.c
net/mac80211/wpa.h
net/wireless/chan.c
net/wireless/core.c
net/wireless/core.h
net/wireless/genregdb.awk
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/rdev-ops.h
net/wireless/reg.c
net/wireless/reg.h
net/wireless/trace.h

index 9551622d0a7b845fe982076b3657ef59ef1ed6b7..356f791af5747fe4a2e1f25dea588d8b371d3d5b 100644 (file)
@@ -159,10 +159,10 @@ struct ieee80211_regdomain mydriver_jp_regdom = {
                REG_RULE(2412-20, 2484+20, 40, 6, 20, 0),
                /* IEEE 802.11a, channels 34..48 */
                REG_RULE(5170-20, 5240+20, 40, 6, 20,
-                       NL80211_RRF_PASSIVE_SCAN),
+                       NL80211_RRF_NO_IR),
                /* IEEE 802.11a, channels 52..64 */
                REG_RULE(5260-20, 5320+20, 40, 6, 20,
-                       NL80211_RRF_NO_IBSS |
+                       NL80211_RRF_NO_IR|
                        NL80211_RRF_DFS),
        }
 };
index 4afcfb4c892b76551630b3919aeed9efaedde9ed..b9ea9321adde8a58722e4b3154ee50b6395d4747 100644 (file)
@@ -1458,17 +1458,6 @@ T:       git git://github.com/kvalo/ath.git
 S:     Supported
 F:     drivers/net/wireless/ath/ath6kl/
 
-ATHEROS ATH9K WIRELESS DRIVER
-M:     "Luis R. Rodriguez" <mcgrof@qca.qualcomm.com>
-M:     Jouni Malinen <jouni@qca.qualcomm.com>
-M:     Vasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>
-M:     Senthil Balasubramanian <senthilb@qca.qualcomm.com>
-L:     linux-wireless@vger.kernel.org
-L:     ath9k-devel@lists.ath9k.org
-W:     http://wireless.kernel.org/en/users/Drivers/ath9k
-S:     Supported
-F:     drivers/net/wireless/ath/ath9k/
-
 WILOCITY WIL6210 WIRELESS DRIVER
 M:     Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
 L:     linux-wireless@vger.kernel.org
@@ -6928,6 +6917,14 @@ T:       git git://linuxtv.org/anttip/media_tree.git
 S:     Maintained
 F:     drivers/media/tuners/qt1010*
 
+QUALCOMM ATHEROS ATH9K WIRELESS DRIVER
+M:     QCA ath9k Development <ath9k-devel@qca.qualcomm.com>
+L:     linux-wireless@vger.kernel.org
+L:     ath9k-devel@lists.ath9k.org
+W:     http://wireless.kernel.org/en/users/Drivers/ath9k
+S:     Supported
+F:     drivers/net/wireless/ath/ath9k/
+
 QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
 M:     Kalle Valo <kvalo@qca.qualcomm.com>
 L:     ath10k@lists.infradead.org
index 6fb98b53533f9d708dfc2a530e1033f3f09008b9..12a4ff7513595d5b9a567d11267c625d4d9a67e0 100644 (file)
@@ -238,7 +238,6 @@ static void bcma_host_pci_remove(struct pci_dev *dev)
        pci_release_regions(dev);
        pci_disable_device(dev);
        kfree(bus);
-       pci_set_drvdata(dev, NULL);
 }
 
 #ifdef CONFIG_PM_SLEEP
index 97ac8c87cba232646f5f82617ea396b8c2573870..06fe2b8fa22dd40a0817b1f38725d6106491fa34 100644 (file)
@@ -1351,12 +1351,12 @@ static int ath10k_update_channel_list(struct ath10k *ar)
                        ch->allow_vht = true;
 
                        ch->allow_ibss =
-                               !(channel->flags & IEEE80211_CHAN_NO_IBSS);
+                               !(channel->flags & IEEE80211_CHAN_NO_IR);
 
                        ch->ht40plus =
                                !(channel->flags & IEEE80211_CHAN_NO_HT40PLUS);
 
-                       passive = channel->flags & IEEE80211_CHAN_PASSIVE_SCAN;
+                       passive = channel->flags & IEEE80211_CHAN_NO_IR;
                        ch->passive = passive;
 
                        ch->freq = channel->center_freq;
index 2437ad26949d1c43617204fc7c887bf196a1e2f5..fd4c89df67e1658ae404686a911fc62607cee1cd 100644 (file)
@@ -1109,7 +1109,9 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
                                (mode == WMI_11G_HT20) ?
                                        NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
 
+       mutex_lock(&vif->wdev.mtx);
        cfg80211_ch_switch_notify(vif->ndev, &chandef);
+       mutex_unlock(&vif->wdev.mtx);
 }
 
 static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
@@ -3169,12 +3171,15 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
 }
 
 static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
-                         struct ieee80211_channel *chan, bool offchan,
-                         unsigned int wait, const u8 *buf, size_t len,
-                         bool no_cck, bool dont_wait_for_ack, u64 *cookie)
+                         struct cfg80211_mgmt_tx_params *params, u64 *cookie)
 {
        struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
        struct ath6kl *ar = ath6kl_priv(vif->ndev);
+       struct ieee80211_channel *chan = params->chan;
+       const u8 *buf = params->buf;
+       size_t len = params->len;
+       unsigned int wait = params->wait;
+       bool no_cck = params->no_cck;
        u32 id, freq;
        const struct ieee80211_mgmt *mgmt;
        bool more_data, queued;
index 32f139e2e897e255b4c378c33c6d99df8abd51e0..30d273c61bffb8f4e040e5f2eaddd37154f439f7 100644 (file)
@@ -86,7 +86,7 @@ config ATH9K_DFS_CERTIFIED
 
 config ATH9K_TX99
        bool "Atheros ath9k TX99 testing support"
-       depends on CFG80211_CERTIFICATION_ONUS
+       depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS
        default n
        ---help---
          Say N. This should only be enabled on systems undergoing
@@ -104,6 +104,14 @@ config ATH9K_TX99
          be evaluated to meet the RF exposure limits set forth in the
          governmental SAR regulations.
 
+config ATH9K_WOW
+       bool "Wake on Wireless LAN support (EXPERIMENTAL)"
+       depends on ATH9K && PM
+       default n
+       ---help---
+         This option enables Wake on Wireless LAN support for certain cards.
+         Currently, AR9462 is supported.
+
 config ATH9K_LEGACY_RATE_CONTROL
        bool "Atheros ath9k rate control"
        depends on ATH9K
index 6205ef5a9321e8072c283d24e8e7814b2a8392df..337c459eda284770c61dbb654b1762aac3965e9b 100644 (file)
@@ -13,9 +13,9 @@ ath9k-$(CONFIG_ATH9K_PCI) += pci.o
 ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
 ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
 ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o
-ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += \
-               dfs.o
-ath9k-$(CONFIG_PM_SLEEP) += wow.o
+ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o
+ath9k-$(CONFIG_ATH9K_TX99) += tx99.o
+ath9k-$(CONFIG_ATH9K_WOW) += wow.o
 
 obj-$(CONFIG_ATH9K) += ath9k.o
 
@@ -41,6 +41,8 @@ ath9k_hw-y:=  \
                ar9003_eeprom.o \
                ar9003_paprd.o
 
+ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o
+
 ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
                                           ar9003_mci.o
 obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
index 7546b9a7dcbfa2252bf896e70fe48ad38b3b4646..e7cdf1100f56bc1ea52273c6b756779e1a3b2ff2 100644 (file)
@@ -352,7 +352,7 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = {
        {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
        {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
        {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
-       {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
+       {0x0000a2d0, 0x00041983, 0x00041983, 0x00041981, 0x00041982},
        {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
        {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
@@ -378,9 +378,9 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
        {0x00009814, 0x9280c00a},
        {0x00009818, 0x00000000},
        {0x0000981c, 0x00020028},
-       {0x00009834, 0x6400a290},
+       {0x00009834, 0x6400a190},
        {0x00009838, 0x0108ecff},
-       {0x0000983c, 0x0d000600},
+       {0x0000983c, 0x14000600},
        {0x00009880, 0x201fff00},
        {0x00009884, 0x00001042},
        {0x000098a4, 0x00200400},
@@ -401,7 +401,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
        {0x00009d04, 0x40206c10},
        {0x00009d08, 0x009c4060},
        {0x00009d0c, 0x9883800a},
-       {0x00009d10, 0x01834061},
+       {0x00009d10, 0x01884061},
        {0x00009d14, 0x00c0040b},
        {0x00009d18, 0x00000000},
        {0x00009e08, 0x0038230c},
@@ -459,7 +459,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
        {0x0000a3e8, 0x20202020},
        {0x0000a3ec, 0x20202020},
        {0x0000a3f0, 0x00000000},
-       {0x0000a3f4, 0x00000246},
+       {0x0000a3f4, 0x00000000},
        {0x0000a3f8, 0x0c9bd380},
        {0x0000a3fc, 0x000f0f01},
        {0x0000a400, 0x8fa91f01},
@@ -644,7 +644,7 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
        {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
        {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
        {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
+       {0x0000a410, 0x000050d4, 0x000050d4, 0x000050d9, 0x000050d9},
        {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
        {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
        {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
@@ -1086,8 +1086,8 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
        {0x0000b074, 0x00000000},
        {0x0000b078, 0x00000000},
        {0x0000b07c, 0x00000000},
-       {0x0000b080, 0x2a2d2f32},
-       {0x0000b084, 0x21232328},
+       {0x0000b080, 0x23232323},
+       {0x0000b084, 0x21232323},
        {0x0000b088, 0x19191c1e},
        {0x0000b08c, 0x12141417},
        {0x0000b090, 0x07070e0e},
@@ -1385,9 +1385,9 @@ static const u32 ar9300_2p2_mac_core[][2] = {
        {0x000081f8, 0x00000000},
        {0x000081fc, 0x00000000},
        {0x00008240, 0x00100000},
-       {0x00008244, 0x0010f424},
+       {0x00008244, 0x0010f400},
        {0x00008248, 0x00000800},
-       {0x0000824c, 0x0001e848},
+       {0x0000824c, 0x0001e800},
        {0x00008250, 0x00000000},
        {0x00008254, 0x00000000},
        {0x00008258, 0x00000000},
@@ -1726,16 +1726,23 @@ static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2[][2] = {
 
 static const u32 ar9300PciePhy_clkreq_enable_L1_2p2[][2] = {
        /* Addr      allmodes  */
-       {0x00004040, 0x08253e5e},
+       {0x00004040, 0x0825365e},
        {0x00004040, 0x0008003b},
        {0x00004044, 0x00000000},
 };
 
 static const u32 ar9300PciePhy_clkreq_disable_L1_2p2[][2] = {
        /* Addr      allmodes  */
-       {0x00004040, 0x08213e5e},
+       {0x00004040, 0x0821365e},
        {0x00004040, 0x0008003b},
        {0x00004044, 0x00000000},
 };
 
+static const u32 ar9300_2p2_baseband_core_txfir_coeff_japan_2484[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a398, 0x00000000},
+       {0x0000a39c, 0x6f7f0301},
+       {0x0000a3a0, 0xca9228ee},
+};
+
 #endif /* INITVALS_9003_2P2_H */
index 22934d3ca54413fa9558a928fdccbc4ab108131a..aa0127265746941e473263d84e4b57d8177d0608 100644 (file)
@@ -1040,14 +1040,14 @@ static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
        }
 }
 
-static bool ar9003_hw_init_cal(struct ath_hw *ah,
-                              struct ath9k_channel *chan)
+static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah,
+                                    struct ath9k_channel *chan)
 {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_cal_data *caldata = ah->caldata;
        bool txiqcal_done = false;
        bool is_reusable = true, status = true;
-       bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false;
+       bool run_rtt_cal = false, run_agc_cal;
        bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
        u32 rx_delay = 0;
        u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
@@ -1119,22 +1119,12 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
                        REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
                                    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
                txiqcal_done = run_agc_cal = true;
-       } else if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags)) {
-               run_agc_cal = true;
-               sep_iq_cal = true;
        }
 
 skip_tx_iqcal:
        if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
                ar9003_mci_init_cal_req(ah, &is_reusable);
 
-       if (sep_iq_cal) {
-               txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
-               REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
-               udelay(5);
-               REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
-       }
-
        if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) {
                rx_delay = REG_READ(ah, AR_PHY_RX_DELAY);
                /* Disable BB_active */
@@ -1228,13 +1218,109 @@ skip_tx_iqcal:
        return true;
 }
 
+static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
+                                  struct ath9k_channel *chan)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_cal_data *caldata = ah->caldata;
+       bool txiqcal_done = false;
+       bool is_reusable = true, status = true;
+       bool run_agc_cal = false, sep_iq_cal = false;
+
+       /* Use chip chainmask only for calibration */
+       ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
+
+       if (ah->enabled_cals & TX_CL_CAL) {
+               REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
+               run_agc_cal = true;
+       }
+
+       if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))
+               goto skip_tx_iqcal;
+
+       /* Do Tx IQ Calibration */
+       REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
+                     AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
+                     DELPT);
+
+       /*
+        * For AR9485 or later chips, TxIQ cal runs as part of
+        * AGC calibration. Specifically, AR9550 in SoC chips.
+        */
+       if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {
+               txiqcal_done = true;
+               run_agc_cal = true;
+       } else {
+               sep_iq_cal = true;
+               run_agc_cal = true;
+       }
+
+       /*
+        * In the SoC family, this will run for AR9300, AR9331 and AR9340.
+        */
+       if (sep_iq_cal) {
+               txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
+               REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+               udelay(5);
+               REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+       }
+
+skip_tx_iqcal:
+       if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
+               /* Calibrate the AGC */
+               REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+                         REG_READ(ah, AR_PHY_AGC_CONTROL) |
+                         AR_PHY_AGC_CONTROL_CAL);
+
+               /* Poll for offset calibration complete */
+               status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+                                      AR_PHY_AGC_CONTROL_CAL,
+                                      0, AH_WAIT_TIMEOUT);
+       }
+
+       if (!status) {
+               ath_dbg(common, CALIBRATE,
+                       "offset calibration failed to complete in %d ms; noisy environment?\n",
+                       AH_WAIT_TIMEOUT / 1000);
+               return false;
+       }
+
+       if (txiqcal_done)
+               ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
+
+       /* Revert chainmask to runtime parameters */
+       ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
+
+       /* Initialize list pointers */
+       ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
+
+       INIT_CAL(&ah->iq_caldata);
+       INSERT_CAL(ah, &ah->iq_caldata);
+       ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
+
+       /* Initialize current pointer to first element in list */
+       ah->cal_list_curr = ah->cal_list;
+
+       if (ah->cal_list_curr)
+               ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
+
+       if (caldata)
+               caldata->CalValid = 0;
+
+       return true;
+}
+
 void ar9003_hw_attach_calib_ops(struct ath_hw *ah)
 {
        struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
        struct ath_hw_ops *ops = ath9k_hw_ops(ah);
 
+       if (AR_SREV_9485(ah) || AR_SREV_9462(ah) || AR_SREV_9565(ah))
+               priv_ops->init_cal = ar9003_hw_init_cal_pcoem;
+       else
+               priv_ops->init_cal = ar9003_hw_init_cal_soc;
+
        priv_ops->init_cal_settings = ar9003_hw_init_cal_settings;
-       priv_ops->init_cal = ar9003_hw_init_cal;
        priv_ops->setup_calibration = ar9003_hw_setup_calibration;
 
        ops->calibrate = ar9003_hw_calibrate;
index 20e49095db2ae2ba0c2d7d83071aa2a14a81252d..d8c1eee8ea53014dfde6536d507ec36862b0062f 100644 (file)
@@ -26,6 +26,7 @@
 #include "ar9462_2p0_initvals.h"
 #include "ar9462_2p1_initvals.h"
 #include "ar9565_1p0_initvals.h"
+#include "ar9565_1p1_initvals.h"
 
 /* General hardware code for the AR9003 hadware family */
 
@@ -148,7 +149,9 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                                ar9340Modes_high_ob_db_tx_gain_table_1p0);
 
                INIT_INI_ARRAY(&ah->iniModesFastClock,
-                               ar9340Modes_fast_clock_1p0);
+                              ar9340Modes_fast_clock_1p0);
+               INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+                              ar9340_1p0_baseband_core_txfir_coeff_japan_2484);
 
                if (!ah->is_clk_25mhz)
                        INIT_INI_ARRAY(&ah->iniAdditional,
@@ -223,6 +226,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                               ar9462_2p1_modes_fast_clock);
                INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
                               ar9462_2p1_baseband_core_txfir_coeff_japan_2484);
+               INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                              ar9462_2p1_pciephy_clkreq_disable_L1);
+               INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
+                              ar9462_2p1_pciephy_clkreq_disable_L1);
        } else if (AR_SREV_9462_20(ah)) {
 
                INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_2p0_mac_core);
@@ -247,18 +254,18 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                                ar9462_2p0_soc_postamble);
 
                INIT_INI_ARRAY(&ah->iniModesRxGain,
-                               ar9462_common_rx_gain_table_2p0);
+                               ar9462_2p0_common_rx_gain);
 
                /* Awake -> Sleep Setting */
                INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                              ar9462_pciephy_clkreq_disable_L1_2p0);
+                              ar9462_2p0_pciephy_clkreq_disable_L1);
                /* Sleep -> Awake Setting */
                INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
-                              ar9462_pciephy_clkreq_disable_L1_2p0);
+                              ar9462_2p0_pciephy_clkreq_disable_L1);
 
                /* Fast clock modal settings */
                INIT_INI_ARRAY(&ah->iniModesFastClock,
-                               ar9462_modes_fast_clock_2p0);
+                               ar9462_2p0_modes_fast_clock);
 
                INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
                               ar9462_2p0_baseband_core_txfir_coeff_japan_2484);
@@ -330,7 +337,44 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                                ar9580_1p0_low_ob_db_tx_gain_table);
 
                INIT_INI_ARRAY(&ah->iniModesFastClock,
-                               ar9580_1p0_modes_fast_clock);
+                              ar9580_1p0_modes_fast_clock);
+               INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+                              ar9580_1p0_baseband_core_txfir_coeff_japan_2484);
+       } else if (AR_SREV_9565_11_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+                              ar9565_1p1_mac_core);
+               INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+                              ar9565_1p1_mac_postamble);
+
+               INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+                              ar9565_1p1_baseband_core);
+               INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+                              ar9565_1p1_baseband_postamble);
+
+               INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+                              ar9565_1p1_radio_core);
+               INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+                              ar9565_1p1_radio_postamble);
+
+               INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+                              ar9565_1p1_soc_preamble);
+               INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+                              ar9565_1p1_soc_postamble);
+
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+                              ar9565_1p1_Common_rx_gain_table);
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                              ar9565_1p1_Modes_lowest_ob_db_tx_gain_table);
+
+               INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                              ar9565_1p1_pciephy_clkreq_disable_L1);
+               INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
+                              ar9565_1p1_pciephy_clkreq_disable_L1);
+
+               INIT_INI_ARRAY(&ah->iniModesFastClock,
+                               ar9565_1p1_modes_fast_clock);
+               INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+                              ar9565_1p1_baseband_core_txfir_coeff_japan_2484);
        } else if (AR_SREV_9565(ah)) {
                INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
                               ar9565_1p0_mac_core);
@@ -411,7 +455,9 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
 
                /* Fast clock modal settings */
                INIT_INI_ARRAY(&ah->iniModesFastClock,
-                               ar9300Modes_fast_clock_2p2);
+                              ar9300Modes_fast_clock_2p2);
+               INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+                              ar9300_2p2_baseband_core_txfir_coeff_japan_2484);
        }
 }
 
@@ -440,7 +486,10 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah)
                        ar9462_2p1_modes_low_ob_db_tx_gain);
        else if (AR_SREV_9462_20(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
-                       ar9462_modes_low_ob_db_tx_gain_table_2p0);
+                       ar9462_2p0_modes_low_ob_db_tx_gain);
+       else if (AR_SREV_9565_11(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                              ar9565_1p1_modes_low_ob_db_tx_gain_table);
        else if (AR_SREV_9565(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                               ar9565_1p0_modes_low_ob_db_tx_gain_table);
@@ -474,7 +523,10 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah)
                        ar9462_2p1_modes_high_ob_db_tx_gain);
        else if (AR_SREV_9462_20(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
-                       ar9462_modes_high_ob_db_tx_gain_table_2p0);
+                       ar9462_2p0_modes_high_ob_db_tx_gain);
+       else if (AR_SREV_9565_11(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                              ar9565_1p1_modes_high_ob_db_tx_gain_table);
        else if (AR_SREV_9565(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                               ar9565_1p0_modes_high_ob_db_tx_gain_table);
@@ -500,6 +552,9 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah)
        else if (AR_SREV_9580(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9580_1p0_low_ob_db_tx_gain_table);
+       else if (AR_SREV_9565_11(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                              ar9565_1p1_modes_low_ob_db_tx_gain_table);
        else if (AR_SREV_9565(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                               ar9565_1p0_modes_low_ob_db_tx_gain_table);
@@ -525,6 +580,9 @@ static void ar9003_tx_gain_table_mode3(struct ath_hw *ah)
        else if (AR_SREV_9580(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9580_1p0_high_power_tx_gain_table);
+       else if (AR_SREV_9565_11(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                              ar9565_1p1_modes_high_power_tx_gain_table);
        else if (AR_SREV_9565(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                               ar9565_1p0_modes_high_power_tx_gain_table);
@@ -546,7 +604,7 @@ static void ar9003_tx_gain_table_mode4(struct ath_hw *ah)
                       ar9462_2p1_modes_mix_ob_db_tx_gain);
        else if (AR_SREV_9462_20(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
-                      ar9462_modes_mix_ob_db_tx_gain_table_2p0);
+                      ar9462_2p0_modes_mix_ob_db_tx_gain);
        else
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9300Modes_mixed_ob_db_tx_gain_table_2p2);
@@ -581,6 +639,13 @@ static void ar9003_tx_gain_table_mode6(struct ath_hw *ah)
                        ar9580_1p0_type6_tx_gain_table);
 }
 
+static void ar9003_tx_gain_table_mode7(struct ath_hw *ah)
+{
+       if (AR_SREV_9340(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                              ar9340_cus227_tx_gain_table_1p0);
+}
+
 typedef void (*ath_txgain_tab)(struct ath_hw *ah);
 
 static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
@@ -593,6 +658,7 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
                ar9003_tx_gain_table_mode4,
                ar9003_tx_gain_table_mode5,
                ar9003_tx_gain_table_mode6,
+               ar9003_tx_gain_table_mode7,
        };
        int idx = ar9003_hw_get_tx_gain_idx(ah);
 
@@ -629,7 +695,10 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
                                ar9462_2p1_common_rx_gain);
        else if (AR_SREV_9462_20(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
-                               ar9462_common_rx_gain_table_2p0);
+                               ar9462_2p0_common_rx_gain);
+       else if (AR_SREV_9565_11(ah))
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+                              ar9565_1p1_Common_rx_gain_table);
        else if (AR_SREV_9565(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                               ar9565_1p0_Common_rx_gain_table);
@@ -657,7 +726,7 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah)
                        ar9462_2p1_common_wo_xlna_rx_gain);
        else if (AR_SREV_9462_20(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
-                       ar9462_common_wo_xlna_rx_gain_table_2p0);
+                       ar9462_2p0_common_wo_xlna_rx_gain);
        else if (AR_SREV_9550(ah)) {
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                        ar955x_1p0_common_wo_xlna_rx_gain_table);
@@ -666,6 +735,9 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah)
        } else if (AR_SREV_9580(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                        ar9580_1p0_wo_xlna_rx_gain_table);
+       else if (AR_SREV_9565_11(ah))
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+                              ar9565_1p1_common_wo_xlna_rx_gain_table);
        else if (AR_SREV_9565(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                               ar9565_1p0_common_wo_xlna_rx_gain_table);
@@ -687,7 +759,7 @@ static void ar9003_rx_gain_table_mode2(struct ath_hw *ah)
                               ar9462_2p1_baseband_postamble_5g_xlna);
        } else if (AR_SREV_9462_20(ah)) {
                INIT_INI_ARRAY(&ah->iniModesRxGain,
-                              ar9462_common_mixed_rx_gain_table_2p0);
+                              ar9462_2p0_common_mixed_rx_gain);
                INIT_INI_ARRAY(&ah->ini_modes_rxgain_bb_core,
                               ar9462_2p0_baseband_core_mix_rxgain);
                INIT_INI_ARRAY(&ah->ini_modes_rxgain_bb_postamble,
@@ -701,12 +773,12 @@ static void ar9003_rx_gain_table_mode3(struct ath_hw *ah)
 {
        if (AR_SREV_9462_21(ah)) {
                INIT_INI_ARRAY(&ah->iniModesRxGain,
-                              ar9462_2p1_common_5g_xlna_only_rx_gain);
+                              ar9462_2p1_common_5g_xlna_only_rxgain);
                INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna,
                               ar9462_2p1_baseband_postamble_5g_xlna);
        } else if (AR_SREV_9462_20(ah)) {
                INIT_INI_ARRAY(&ah->iniModesRxGain,
-                              ar9462_2p0_5g_xlna_only_rxgain);
+                              ar9462_2p0_common_5g_xlna_only_rxgain);
                INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna,
                               ar9462_2p0_baseband_postamble_5g_xlna);
        }
@@ -750,6 +822,9 @@ static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah)
 static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
                                         bool power_off)
 {
+       unsigned int i;
+       struct ar5416IniArray *array;
+
        /*
         * Increase L1 Entry Latency. Some WB222 boards don't have
         * this change in eeprom/OTP.
@@ -775,18 +850,13 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
         * Configire PCIE after Ini init. SERDES values now come from ini file
         * This enables PCIe low power mode.
         */
-       if (ah->config.pcieSerDesWrite) {
-               unsigned int i;
-               struct ar5416IniArray *array;
+       array = power_off ? &ah->iniPcieSerdes :
+               &ah->iniPcieSerdesLowPower;
 
-               array = power_off ? &ah->iniPcieSerdes :
-                                   &ah->iniPcieSerdesLowPower;
-
-               for (i = 0; i < array->ia_rows; i++) {
-                       REG_WRITE(ah,
-                                 INI_RA(array, i, 0),
-                                 INI_RA(array, i, 1));
-               }
+       for (i = 0; i < array->ia_rows; i++) {
+               REG_WRITE(ah,
+                         INI_RA(array, i, 0),
+                         INI_RA(array, i, 1));
        }
 }
 
index d39b79f5e841ada25c0e1bf435e7c7fd926c15ea..39b71b3d6919da5e59fcaa772f53aaf007ba870f 100644 (file)
@@ -641,11 +641,12 @@ static void ar9003_hw_override_ini(struct ath_hw *ah)
                else
                        ah->enabled_cals &= ~TX_IQ_CAL;
 
-               if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE)
-                       ah->enabled_cals |= TX_CL_CAL;
-               else
-                       ah->enabled_cals &= ~TX_CL_CAL;
        }
+
+       if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE)
+               ah->enabled_cals |= TX_CL_CAL;
+       else
+               ah->enabled_cals &= ~TX_CL_CAL;
 }
 
 static void ar9003_hw_prog_ini(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c
new file mode 100644 (file)
index 0000000..81c88dd
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/export.h>
+#include "ath9k.h"
+#include "reg.h"
+#include "hw-ops.h"
+
+const char *ath9k_hw_wow_event_to_string(u32 wow_event)
+{
+       if (wow_event & AH_WOW_MAGIC_PATTERN_EN)
+               return "Magic pattern";
+       if (wow_event & AH_WOW_USER_PATTERN_EN)
+               return "User pattern";
+       if (wow_event & AH_WOW_LINK_CHANGE)
+               return "Link change";
+       if (wow_event & AH_WOW_BEACON_MISS)
+               return "Beacon miss";
+
+       return  "unknown reason";
+}
+EXPORT_SYMBOL(ath9k_hw_wow_event_to_string);
+
+static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+
+       /* set rx disable bit */
+       REG_WRITE(ah, AR_CR, AR_CR_RXD);
+
+       if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) {
+               ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
+                       REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
+               return;
+       }
+
+       REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);
+}
+
+static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       u8 sta_mac_addr[ETH_ALEN], ap_mac_addr[ETH_ALEN];
+       u32 ctl[13] = {0};
+       u32 data_word[KAL_NUM_DATA_WORDS];
+       u8 i;
+       u32 wow_ka_data_word0;
+
+       memcpy(sta_mac_addr, common->macaddr, ETH_ALEN);
+       memcpy(ap_mac_addr, common->curbssid, ETH_ALEN);
+
+       /* set the transmit buffer */
+       ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16));
+       ctl[1] = 0;
+       ctl[3] = 0xb;   /* OFDM_6M hardware value for this rate */
+       ctl[4] = 0;
+       ctl[7] = (ah->txchainmask) << 2;
+       ctl[2] = 0xf << 16; /* tx_tries 0 */
+
+       for (i = 0; i < KAL_NUM_DESC_WORDS; i++)
+               REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
+
+       REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
+
+       data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) |
+                      (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16);
+       data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) |
+                      (ap_mac_addr[1] << 8) | (ap_mac_addr[0]);
+       data_word[2] = (sta_mac_addr[1] << 24) | (sta_mac_addr[0] << 16) |
+                      (ap_mac_addr[5] << 8) | (ap_mac_addr[4]);
+       data_word[3] = (sta_mac_addr[5] << 24) | (sta_mac_addr[4] << 16) |
+                      (sta_mac_addr[3] << 8) | (sta_mac_addr[2]);
+       data_word[4] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) |
+                      (ap_mac_addr[1] << 8) | (ap_mac_addr[0]);
+       data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]);
+
+       if (AR_SREV_9462_20(ah)) {
+               /* AR9462 2.0 has an extra descriptor word (time based
+                * discard) compared to other chips */
+               REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0);
+               wow_ka_data_word0 = AR_WOW_TXBUF(13);
+       } else {
+               wow_ka_data_word0 = AR_WOW_TXBUF(12);
+       }
+
+       for (i = 0; i < KAL_NUM_DATA_WORDS; i++)
+               REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]);
+
+}
+
+void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
+                               u8 *user_mask, int pattern_count,
+                               int pattern_len)
+{
+       int i;
+       u32 pattern_val, mask_val;
+       u32 set, clr;
+
+       /* FIXME: should check count by querying the hardware capability */
+       if (pattern_count >= MAX_NUM_PATTERN)
+               return;
+
+       REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count));
+
+       /* set the registers for pattern */
+       for (i = 0; i < MAX_PATTERN_SIZE; i += 4) {
+               memcpy(&pattern_val, user_pattern, 4);
+               REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i),
+                         pattern_val);
+               user_pattern += 4;
+       }
+
+       /* set the registers for mask */
+       for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) {
+               memcpy(&mask_val, user_mask, 4);
+               REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val);
+               user_mask += 4;
+       }
+
+       /* set the pattern length to be matched
+        *
+        * AR_WOW_LENGTH1_REG1
+        * bit 31:24 pattern 0 length
+        * bit 23:16 pattern 1 length
+        * bit 15:8 pattern 2 length
+        * bit 7:0 pattern 3 length
+        *
+        * AR_WOW_LENGTH1_REG2
+        * bit 31:24 pattern 4 length
+        * bit 23:16 pattern 5 length
+        * bit 15:8 pattern 6 length
+        * bit 7:0 pattern 7 length
+        *
+        * the below logic writes out the new
+        * pattern length for the corresponding
+        * pattern_count, while masking out the
+        * other fields
+        */
+
+       ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT);
+
+       if (pattern_count < 4) {
+               /* Pattern 0-3 uses AR_WOW_LENGTH1 register */
+               set = (pattern_len & AR_WOW_LENGTH_MAX) <<
+                      AR_WOW_LEN1_SHIFT(pattern_count);
+               clr = AR_WOW_LENGTH1_MASK(pattern_count);
+               REG_RMW(ah, AR_WOW_LENGTH1, set, clr);
+       } else {
+               /* Pattern 4-7 uses AR_WOW_LENGTH2 register */
+               set = (pattern_len & AR_WOW_LENGTH_MAX) <<
+                      AR_WOW_LEN2_SHIFT(pattern_count);
+               clr = AR_WOW_LENGTH2_MASK(pattern_count);
+               REG_RMW(ah, AR_WOW_LENGTH2, set, clr);
+       }
+
+}
+EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern);
+
+u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
+{
+       u32 wow_status = 0;
+       u32 val = 0, rval;
+
+       /*
+        * read the WoW status register to know
+        * the wakeup reason
+        */
+       rval = REG_READ(ah, AR_WOW_PATTERN);
+       val = AR_WOW_STATUS(rval);
+
+       /*
+        * mask only the WoW events that we have enabled. Sometimes
+        * we have spurious WoW events from the AR_WOW_PATTERN
+        * register. This mask will clean it up.
+        */
+
+       val &= ah->wow_event_mask;
+
+       if (val) {
+               if (val & AR_WOW_MAGIC_PAT_FOUND)
+                       wow_status |= AH_WOW_MAGIC_PATTERN_EN;
+               if (AR_WOW_PATTERN_FOUND(val))
+                       wow_status |= AH_WOW_USER_PATTERN_EN;
+               if (val & AR_WOW_KEEP_ALIVE_FAIL)
+                       wow_status |= AH_WOW_LINK_CHANGE;
+               if (val & AR_WOW_BEACON_FAIL)
+                       wow_status |= AH_WOW_BEACON_MISS;
+       }
+
+       /*
+        * set and clear WOW_PME_CLEAR registers for the chip to
+        * generate next wow signal.
+        * disable D3 before accessing other registers ?
+        */
+
+       /* do we need to check the bit value 0x01000000 (7-10) ?? */
+       REG_RMW(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR,
+               AR_PMCTRL_PWR_STATE_D1D3);
+
+       /*
+        * clear all events
+        */
+       REG_WRITE(ah, AR_WOW_PATTERN,
+                 AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN)));
+
+       /*
+        * restore the beacon threshold to init value
+        */
+       REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
+
+       /*
+        * Restore the way the PCI-E reset, Power-On-Reset, external
+        * PCIE_POR_SHORT pins are tied to its original value.
+        * Previously just before WoW sleep, we untie the PCI-E
+        * reset to our Chip's Power On Reset so that any PCI-E
+        * reset from the bus will not reset our chip
+        */
+       if (ah->is_pciexpress)
+               ath9k_hw_configpcipowersave(ah, false);
+
+       ah->wow_event_mask = 0;
+
+       return wow_status;
+}
+EXPORT_SYMBOL(ath9k_hw_wow_wakeup);
+
+void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
+{
+       u32 wow_event_mask;
+       u32 set, clr;
+
+       /*
+        * wow_event_mask is a mask to the AR_WOW_PATTERN register to
+        * indicate which WoW events we have enabled. The WoW events
+        * are from the 'pattern_enable' in this function and
+        * 'pattern_count' of ath9k_hw_wow_apply_pattern()
+        */
+       wow_event_mask = ah->wow_event_mask;
+
+       /*
+        * Untie Power-on-Reset from the PCI-E-Reset. When we are in
+        * WOW sleep, we do want the Reset from the PCI-E to disturb
+        * our hw state
+        */
+       if (ah->is_pciexpress) {
+               /*
+                * we need to untie the internal POR (power-on-reset)
+                * to the external PCI-E reset. We also need to tie
+                * the PCI-E Phy reset to the PCI-E reset.
+                */
+               set = AR_WA_RESET_EN | AR_WA_POR_SHORT;
+               clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;
+               REG_RMW(ah, AR_WA, set, clr);
+       }
+
+       /*
+        * set the power states appropriately and enable PME
+        */
+       set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA |
+             AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR;
+
+       /*
+        * set and clear WOW_PME_CLEAR registers for the chip
+        * to generate next wow signal.
+        */
+       REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
+       clr = AR_PMCTRL_WOW_PME_CLR;
+       REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
+
+       /*
+        * Setup for:
+        *      - beacon misses
+        *      - magic pattern
+        *      - keep alive timeout
+        *      - pattern matching
+        */
+
+       /*
+        * Program default values for pattern backoff, aifs/slot/KAL count,
+        * beacon miss timeout, KAL timeout, etc.
+        */
+       set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF);
+       REG_SET_BIT(ah, AR_WOW_PATTERN, set);
+
+       set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) |
+             AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) |
+             AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT);
+       REG_SET_BIT(ah, AR_WOW_COUNT, set);
+
+       if (pattern_enable & AH_WOW_BEACON_MISS)
+               set = AR_WOW_BEACON_TIMO;
+       /* We are not using beacon miss, program a large value */
+       else
+               set = AR_WOW_BEACON_TIMO_MAX;
+
+       REG_WRITE(ah, AR_WOW_BCN_TIMO, set);
+
+       /*
+        * Keep alive timo in ms except AR9280
+        */
+       if (!pattern_enable)
+               set = AR_WOW_KEEP_ALIVE_NEVER;
+       else
+               set = KAL_TIMEOUT * 32;
+
+       REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set);
+
+       /*
+        * Keep alive delay in us. based on 'power on clock',
+        * therefore in usec
+        */
+       set = KAL_DELAY * 1000;
+       REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set);
+
+       /*
+        * Create keep alive pattern to respond to beacons
+        */
+       ath9k_wow_create_keep_alive_pattern(ah);
+
+       /*
+        * Configure MAC WoW Registers
+        */
+       set = 0;
+       /* Send keep alive timeouts anyway */
+       clr = AR_WOW_KEEP_ALIVE_AUTO_DIS;
+
+       if (pattern_enable & AH_WOW_LINK_CHANGE)
+               wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL;
+       else
+               set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
+
+       set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
+       REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr);
+
+       /*
+        * we are relying on a bmiss failure. ensure we have
+        * enough threshold to prevent false positives
+        */
+       REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR,
+                     AR_WOW_BMISSTHRESHOLD);
+
+       set = 0;
+       clr = 0;
+
+       if (pattern_enable & AH_WOW_BEACON_MISS) {
+               set = AR_WOW_BEACON_FAIL_EN;
+               wow_event_mask |= AR_WOW_BEACON_FAIL;
+       } else {
+               clr = AR_WOW_BEACON_FAIL_EN;
+       }
+
+       REG_RMW(ah, AR_WOW_BCN_EN, set, clr);
+
+       set = 0;
+       clr = 0;
+       /*
+        * Enable the magic packet registers
+        */
+       if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) {
+               set = AR_WOW_MAGIC_EN;
+               wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND;
+       } else {
+               clr = AR_WOW_MAGIC_EN;
+       }
+       set |= AR_WOW_MAC_INTR_EN;
+       REG_RMW(ah, AR_WOW_PATTERN, set, clr);
+
+       REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,
+                 AR_WOW_PATTERN_SUPPORTED);
+
+       /*
+        * Set the power states appropriately and enable PME
+        */
+       clr = 0;
+       set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN |
+             AR_PMCTRL_PWR_PM_CTRL_ENA;
+
+       clr = AR_PCIE_PM_CTRL_ENA;
+       REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr);
+
+       /*
+        * this is needed to prevent the chip waking up
+        * the host within 3-4 seconds with certain
+        * platform/BIOS. The fix is to enable
+        * D1 & D3 to match original definition and
+        * also match the OTP value. Anyway this
+        * is more related to SW WOW.
+        */
+       clr = AR_PMCTRL_PWR_STATE_D1D3;
+       REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
+
+       set = AR_PMCTRL_PWR_STATE_D1D3_REAL;
+       REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
+
+       REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
+
+       /* to bring down WOW power low margin */
+       set = BIT(13);
+       REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);
+       /* HW WoW */
+       clr = BIT(5);
+       REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
+
+       ath9k_hw_set_powermode_wow_sleep(ah);
+       ah->wow_event_mask = wow_event_mask;
+}
+EXPORT_SYMBOL(ath9k_hw_wow_enable);
index 25db9215985aa1519e0901cb698b312811d6dc91..7f22cb2a494113f8575c326bcf19405febc6d7d1 100644 (file)
 #ifndef INITVALS_9340_H
 #define INITVALS_9340_H
 
+#define ar9340_1p0_mac_postamble ar9300_2p2_mac_postamble
+
+#define ar9340_1p0_soc_postamble ar9300_2p2_soc_postamble
+
+#define ar9340Modes_fast_clock_1p0 ar9300Modes_fast_clock_2p2
+
+#define ar9340Common_rx_gain_table_1p0 ar9300Common_rx_gain_table_2p2
+
+#define ar9340Common_wo_xlna_rx_gain_table_1p0 ar9300Common_wo_xlna_rx_gain_table_2p2
+
+#define ar9340_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484
+
 static const u32 ar9340_1p0_radio_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800},
@@ -100,8 +112,6 @@ static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = {
        {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
 };
 
-#define ar9340Modes_fast_clock_1p0 ar9300Modes_fast_clock_2p2
-
 static const u32 ar9340_1p0_radio_core[][2] = {
        /* Addr      allmodes  */
        {0x00016000, 0x36db6db6},
@@ -215,16 +225,12 @@ static const u32 ar9340_1p0_radio_core_40M[][2] = {
        {0x0000824c, 0x0001e800},
 };
 
-#define ar9340_1p0_mac_postamble ar9300_2p2_mac_postamble
-
-#define ar9340_1p0_soc_postamble ar9300_2p2_soc_postamble
-
 static const u32 ar9340_1p0_baseband_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
        {0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e},
        {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
-       {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+       {0x00009828, 0x06903081, 0x06903081, 0x09103881, 0x09103881},
        {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
        {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
        {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
@@ -340,9 +346,9 @@ static const u32 ar9340_1p0_baseband_core[][2] = {
        {0x0000a370, 0x00000000},
        {0x0000a390, 0x00000001},
        {0x0000a394, 0x00000444},
-       {0x0000a398, 0x001f0e0f},
-       {0x0000a39c, 0x0075393f},
-       {0x0000a3a0, 0xb79f6427},
+       {0x0000a398, 0x00000000},
+       {0x0000a39c, 0x210d0401},
+       {0x0000a3a0, 0xab9a7144},
        {0x0000a3a4, 0x00000000},
        {0x0000a3a8, 0xaaaaaaaa},
        {0x0000a3ac, 0x3c466478},
@@ -714,266 +720,6 @@ static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = {
        {0x0000b2e8, 0xfffe0000, 0xfffe0000, 0xfffc0000, 0xfffc0000},
 };
 
-static const u32 ar9340Common_rx_gain_table_1p0[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x00010000},
-       {0x0000a004, 0x00030002},
-       {0x0000a008, 0x00050004},
-       {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x00830082},
-       {0x0000a014, 0x01810180},
-       {0x0000a018, 0x01830182},
-       {0x0000a01c, 0x01850184},
-       {0x0000a020, 0x01890188},
-       {0x0000a024, 0x018b018a},
-       {0x0000a028, 0x018d018c},
-       {0x0000a02c, 0x01910190},
-       {0x0000a030, 0x01930192},
-       {0x0000a034, 0x01950194},
-       {0x0000a038, 0x038a0196},
-       {0x0000a03c, 0x038c038b},
-       {0x0000a040, 0x0390038d},
-       {0x0000a044, 0x03920391},
-       {0x0000a048, 0x03940393},
-       {0x0000a04c, 0x03960395},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x22222229},
-       {0x0000a084, 0x1d1d1d1d},
-       {0x0000a088, 0x1d1d1d1d},
-       {0x0000a08c, 0x1d1d1d1d},
-       {0x0000a090, 0x171d1d1d},
-       {0x0000a094, 0x11111717},
-       {0x0000a098, 0x00030311},
-       {0x0000a09c, 0x00000000},
-       {0x0000a0a0, 0x00000000},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x01000101},
-       {0x0000a0c8, 0x011e011f},
-       {0x0000a0cc, 0x011c011d},
-       {0x0000a0d0, 0x02030204},
-       {0x0000a0d4, 0x02010202},
-       {0x0000a0d8, 0x021f0200},
-       {0x0000a0dc, 0x0302021e},
-       {0x0000a0e0, 0x03000301},
-       {0x0000a0e4, 0x031e031f},
-       {0x0000a0e8, 0x0402031d},
-       {0x0000a0ec, 0x04000401},
-       {0x0000a0f0, 0x041e041f},
-       {0x0000a0f4, 0x0502041d},
-       {0x0000a0f8, 0x05000501},
-       {0x0000a0fc, 0x051e051f},
-       {0x0000a100, 0x06010602},
-       {0x0000a104, 0x061f0600},
-       {0x0000a108, 0x061d061e},
-       {0x0000a10c, 0x07020703},
-       {0x0000a110, 0x07000701},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x01000101},
-       {0x0000a148, 0x011e011f},
-       {0x0000a14c, 0x011c011d},
-       {0x0000a150, 0x02030204},
-       {0x0000a154, 0x02010202},
-       {0x0000a158, 0x021f0200},
-       {0x0000a15c, 0x0302021e},
-       {0x0000a160, 0x03000301},
-       {0x0000a164, 0x031e031f},
-       {0x0000a168, 0x0402031d},
-       {0x0000a16c, 0x04000401},
-       {0x0000a170, 0x041e041f},
-       {0x0000a174, 0x0502041d},
-       {0x0000a178, 0x05000501},
-       {0x0000a17c, 0x051e051f},
-       {0x0000a180, 0x06010602},
-       {0x0000a184, 0x061f0600},
-       {0x0000a188, 0x061d061e},
-       {0x0000a18c, 0x07020703},
-       {0x0000a190, 0x07000701},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000196},
-       {0x0000b000, 0x00010000},
-       {0x0000b004, 0x00030002},
-       {0x0000b008, 0x00050004},
-       {0x0000b00c, 0x00810080},
-       {0x0000b010, 0x00830082},
-       {0x0000b014, 0x01810180},
-       {0x0000b018, 0x01830182},
-       {0x0000b01c, 0x01850184},
-       {0x0000b020, 0x02810280},
-       {0x0000b024, 0x02830282},
-       {0x0000b028, 0x02850284},
-       {0x0000b02c, 0x02890288},
-       {0x0000b030, 0x028b028a},
-       {0x0000b034, 0x0388028c},
-       {0x0000b038, 0x038a0389},
-       {0x0000b03c, 0x038c038b},
-       {0x0000b040, 0x0390038d},
-       {0x0000b044, 0x03920391},
-       {0x0000b048, 0x03940393},
-       {0x0000b04c, 0x03960395},
-       {0x0000b050, 0x00000000},
-       {0x0000b054, 0x00000000},
-       {0x0000b058, 0x00000000},
-       {0x0000b05c, 0x00000000},
-       {0x0000b060, 0x00000000},
-       {0x0000b064, 0x00000000},
-       {0x0000b068, 0x00000000},
-       {0x0000b06c, 0x00000000},
-       {0x0000b070, 0x00000000},
-       {0x0000b074, 0x00000000},
-       {0x0000b078, 0x00000000},
-       {0x0000b07c, 0x00000000},
-       {0x0000b080, 0x23232323},
-       {0x0000b084, 0x21232323},
-       {0x0000b088, 0x19191c1e},
-       {0x0000b08c, 0x12141417},
-       {0x0000b090, 0x07070e0e},
-       {0x0000b094, 0x03030305},
-       {0x0000b098, 0x00000003},
-       {0x0000b09c, 0x00000000},
-       {0x0000b0a0, 0x00000000},
-       {0x0000b0a4, 0x00000000},
-       {0x0000b0a8, 0x00000000},
-       {0x0000b0ac, 0x00000000},
-       {0x0000b0b0, 0x00000000},
-       {0x0000b0b4, 0x00000000},
-       {0x0000b0b8, 0x00000000},
-       {0x0000b0bc, 0x00000000},
-       {0x0000b0c0, 0x003f0020},
-       {0x0000b0c4, 0x00400041},
-       {0x0000b0c8, 0x0140005f},
-       {0x0000b0cc, 0x0160015f},
-       {0x0000b0d0, 0x017e017f},
-       {0x0000b0d4, 0x02410242},
-       {0x0000b0d8, 0x025f0240},
-       {0x0000b0dc, 0x027f0260},
-       {0x0000b0e0, 0x0341027e},
-       {0x0000b0e4, 0x035f0340},
-       {0x0000b0e8, 0x037f0360},
-       {0x0000b0ec, 0x04400441},
-       {0x0000b0f0, 0x0460045f},
-       {0x0000b0f4, 0x0541047f},
-       {0x0000b0f8, 0x055f0540},
-       {0x0000b0fc, 0x057f0560},
-       {0x0000b100, 0x06400641},
-       {0x0000b104, 0x0660065f},
-       {0x0000b108, 0x067e067f},
-       {0x0000b10c, 0x07410742},
-       {0x0000b110, 0x075f0740},
-       {0x0000b114, 0x077f0760},
-       {0x0000b118, 0x07800781},
-       {0x0000b11c, 0x07a0079f},
-       {0x0000b120, 0x07c107bf},
-       {0x0000b124, 0x000007c0},
-       {0x0000b128, 0x00000000},
-       {0x0000b12c, 0x00000000},
-       {0x0000b130, 0x00000000},
-       {0x0000b134, 0x00000000},
-       {0x0000b138, 0x00000000},
-       {0x0000b13c, 0x00000000},
-       {0x0000b140, 0x003f0020},
-       {0x0000b144, 0x00400041},
-       {0x0000b148, 0x0140005f},
-       {0x0000b14c, 0x0160015f},
-       {0x0000b150, 0x017e017f},
-       {0x0000b154, 0x02410242},
-       {0x0000b158, 0x025f0240},
-       {0x0000b15c, 0x027f0260},
-       {0x0000b160, 0x0341027e},
-       {0x0000b164, 0x035f0340},
-       {0x0000b168, 0x037f0360},
-       {0x0000b16c, 0x04400441},
-       {0x0000b170, 0x0460045f},
-       {0x0000b174, 0x0541047f},
-       {0x0000b178, 0x055f0540},
-       {0x0000b17c, 0x057f0560},
-       {0x0000b180, 0x06400641},
-       {0x0000b184, 0x0660065f},
-       {0x0000b188, 0x067e067f},
-       {0x0000b18c, 0x07410742},
-       {0x0000b190, 0x075f0740},
-       {0x0000b194, 0x077f0760},
-       {0x0000b198, 0x07800781},
-       {0x0000b19c, 0x07a0079f},
-       {0x0000b1a0, 0x07c107bf},
-       {0x0000b1a4, 0x000007c0},
-       {0x0000b1a8, 0x00000000},
-       {0x0000b1ac, 0x00000000},
-       {0x0000b1b0, 0x00000000},
-       {0x0000b1b4, 0x00000000},
-       {0x0000b1b8, 0x00000000},
-       {0x0000b1bc, 0x00000000},
-       {0x0000b1c0, 0x00000000},
-       {0x0000b1c4, 0x00000000},
-       {0x0000b1c8, 0x00000000},
-       {0x0000b1cc, 0x00000000},
-       {0x0000b1d0, 0x00000000},
-       {0x0000b1d4, 0x00000000},
-       {0x0000b1d8, 0x00000000},
-       {0x0000b1dc, 0x00000000},
-       {0x0000b1e0, 0x00000000},
-       {0x0000b1e4, 0x00000000},
-       {0x0000b1e8, 0x00000000},
-       {0x0000b1ec, 0x00000000},
-       {0x0000b1f0, 0x00000396},
-       {0x0000b1f4, 0x00000396},
-       {0x0000b1f8, 0x00000396},
-       {0x0000b1fc, 0x00000196},
-};
-
 static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
@@ -1437,8 +1183,6 @@ static const u32 ar9340_1p0_mac_core[][2] = {
        {0x000083d0, 0x000101ff},
 };
 
-#define ar9340Common_wo_xlna_rx_gain_table_1p0 ar9300Common_wo_xlna_rx_gain_table_2p2
-
 static const u32 ar9340_1p0_soc_preamble[][2] = {
        /* Addr      allmodes  */
        {0x00007008, 0x00000000},
@@ -1447,4 +1191,106 @@ static const u32 ar9340_1p0_soc_preamble[][2] = {
        {0x00007038, 0x000004c2},
 };
 
+static const u32 ar9340_cus227_tx_gain_table_1p0[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+       {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+       {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+       {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+       {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+       {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+       {0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400},
+       {0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402},
+       {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+       {0x0000a520, 0x2c022220, 0x2c022220, 0x1b000603, 0x1b000603},
+       {0x0000a524, 0x30022222, 0x30022222, 0x1f000a02, 0x1f000a02},
+       {0x0000a528, 0x35022225, 0x35022225, 0x23000a04, 0x23000a04},
+       {0x0000a52c, 0x3b02222a, 0x3b02222a, 0x26000a20, 0x26000a20},
+       {0x0000a530, 0x3f02222c, 0x3f02222c, 0x2a000e20, 0x2a000e20},
+       {0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22},
+       {0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24},
+       {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640},
+       {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660},
+       {0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861},
+       {0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81},
+       {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x61024a6c, 0x61024a6c, 0x44001c84, 0x44001c84},
+       {0x0000a554, 0x66026a6c, 0x66026a6c, 0x48001ce3, 0x48001ce3},
+       {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c001ce5, 0x4c001ce5},
+       {0x0000a55c, 0x7002708c, 0x7002708c, 0x50001ce9, 0x50001ce9},
+       {0x0000a560, 0x7302b08a, 0x7302b08a, 0x54001ceb, 0x54001ceb},
+       {0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+       {0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+       {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+       {0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+       {0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+       {0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+       {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+       {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+       {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+       {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+       {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+       {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+       {0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400},
+       {0x0000a598, 0x21820220, 0x21820220, 0x15800402, 0x15800402},
+       {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404},
+       {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603},
+       {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02},
+       {0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04},
+       {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20},
+       {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20},
+       {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22},
+       {0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24},
+       {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640},
+       {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660},
+       {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b801861, 0x3b801861},
+       {0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e801a81, 0x3e801a81},
+       {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42801a83, 0x42801a83},
+       {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x44801c84, 0x44801c84},
+       {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x48801ce3, 0x48801ce3},
+       {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c801ce5, 0x4c801ce5},
+       {0x0000a5dc, 0x7086308c, 0x7086308c, 0x50801ce9, 0x50801ce9},
+       {0x0000a5e0, 0x738a308a, 0x738a308a, 0x54801ceb, 0x54801ceb},
+       {0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+       {0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+       {0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+       {0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+       {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+       {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+       {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
+       {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
+       {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
+       {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
+       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+       {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
+       {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
+       {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+       {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+       {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4},
+       {0x00016048, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266},
+       {0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015},
+       {0x00016288, 0x30318000, 0x30318000, 0x00318000, 0x00318000},
+       {0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4},
+       {0x00016448, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266},
+       {0x0000a3a4, 0x00000011, 0x00000011, 0x00000011, 0x00000011},
+       {0x0000a3a8, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c},
+       {0x0000a3ac, 0x30303030, 0x30303030, 0x30303030, 0x30303030},
+};
+
 #endif /* INITVALS_9340_H */
index 092b9d412e7fd7f70b5f1996b94a66703325f830..739094384369c863390d567df5ecfb8a801af8be 100644 (file)
@@ -20,7 +20,7 @@
 
 /* AR9462 2.0 */
 
-static const u32 ar9462_modes_fast_clock_2p0[][3] = {
+static const u32 ar9462_2p0_modes_fast_clock[][3] = {
        /* Addr      5G_HT20     5G_HT40   */
        {0x00001030, 0x00000268, 0x000004d0},
        {0x00001070, 0x0000018c, 0x00000318},
@@ -33,13 +33,6 @@ static const u32 ar9462_modes_fast_clock_2p0[][3] = {
        {0x0000a254, 0x00000898, 0x00001130},
 };
 
-static const u32 ar9462_pciephy_clkreq_enable_L1_2p0[][2] = {
-       /* Addr      allmodes  */
-       {0x00018c00, 0x18253ede},
-       {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0003780c},
-};
-
 static const u32 ar9462_2p0_baseband_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d},
@@ -99,7 +92,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},
 };
 
-static const u32 ar9462_common_rx_gain_table_2p0[][2] = {
+static const u32 ar9462_2p0_common_rx_gain[][2] = {
        /* Addr      allmodes  */
        {0x0000a000, 0x00010000},
        {0x0000a004, 0x00030002},
@@ -359,20 +352,13 @@ static const u32 ar9462_common_rx_gain_table_2p0[][2] = {
        {0x0000b1fc, 0x00000196},
 };
 
-static const u32 ar9462_pciephy_clkreq_disable_L1_2p0[][2] = {
+static const u32 ar9462_2p0_pciephy_clkreq_disable_L1[][2] = {
        /* Addr      allmodes  */
        {0x00018c00, 0x18213ede},
        {0x00018c04, 0x000801d8},
        {0x00018c08, 0x0003780c},
 };
 
-static const u32 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0[][2] = {
-       /* Addr      allmodes  */
-       {0x00018c00, 0x18212ede},
-       {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0003780c},
-};
-
 static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
@@ -380,7 +366,7 @@ static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {
        {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
 };
 
-static const u32 ar9462_common_wo_xlna_rx_gain_table_2p0[][2] = {
+static const u32 ar9462_2p0_common_wo_xlna_rx_gain[][2] = {
        /* Addr      allmodes  */
        {0x0000a000, 0x00010000},
        {0x0000a004, 0x00030002},
@@ -647,7 +633,7 @@ static const u32 ar9462_2p0_baseband_core_txfir_coeff_japan_2484[][2] = {
        {0x0000a3a0, 0xca9228ee},
 };
 
-static const u32 ar9462_modes_low_ob_db_tx_gain_table_2p0[][5] = {
+static const u32 ar9462_2p0_modes_low_ob_db_tx_gain[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
        {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
@@ -879,7 +865,7 @@ static const u32 ar9462_2p0_radio_postamble[][5] = {
        {0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000},
 };
 
-static const u32 ar9462_modes_mix_ob_db_tx_gain_table_2p0[][5] = {
+static const u32 ar9462_2p0_modes_mix_ob_db_tx_gain[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
        {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
@@ -942,7 +928,7 @@ static const u32 ar9462_modes_mix_ob_db_tx_gain_table_2p0[][5] = {
        {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
 };
 
-static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = {
+static const u32 ar9462_2p0_modes_high_ob_db_tx_gain[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
        {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
@@ -1252,7 +1238,7 @@ static const u32 ar9462_2p0_mac_postamble[][5] = {
        {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
 };
 
-static const u32 ar9462_common_mixed_rx_gain_table_2p0[][2] = {
+static const u32 ar9462_2p0_common_mixed_rx_gain[][2] = {
        /* Addr      allmodes  */
        {0x0000a000, 0x00010000},
        {0x0000a004, 0x00030002},
@@ -1517,7 +1503,7 @@ static const u32 ar9462_2p0_baseband_postamble_5g_xlna[][5] = {
        {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
 };
 
-static const u32 ar9462_2p0_5g_xlna_only_rxgain[][2] = {
+static const u32 ar9462_2p0_common_5g_xlna_only_rxgain[][2] = {
        /* Addr      allmodes  */
        {0x0000a000, 0x00010000},
        {0x0000a004, 0x00030002},
index 57fc5f459d0aa6a40719407b8c287ac7f3786d00..dc3adda46e8b92700ee1c274ba734fc2c4ec7a4f 100644 (file)
 
 /* AR9462 2.1 */
 
+#define ar9462_2p1_mac_postamble ar9462_2p0_mac_postamble
+
+#define ar9462_2p1_baseband_core ar9462_2p0_baseband_core
+
+#define ar9462_2p1_radio_core ar9462_2p0_radio_core
+
+#define ar9462_2p1_radio_postamble ar9462_2p0_radio_postamble
+
+#define ar9462_2p1_soc_postamble ar9462_2p0_soc_postamble
+
+#define ar9462_2p1_radio_postamble_sys2ant ar9462_2p0_radio_postamble_sys2ant
+
+#define ar9462_2p1_common_rx_gain ar9462_2p0_common_rx_gain
+
+#define ar9462_2p1_common_mixed_rx_gain ar9462_2p0_common_mixed_rx_gain
+
+#define ar9462_2p1_common_5g_xlna_only_rxgain ar9462_2p0_common_5g_xlna_only_rxgain
+
+#define ar9462_2p1_baseband_core_mix_rxgain ar9462_2p0_baseband_core_mix_rxgain
+
+#define ar9462_2p1_baseband_postamble_mix_rxgain ar9462_2p0_baseband_postamble_mix_rxgain
+
+#define ar9462_2p1_baseband_postamble_5g_xlna ar9462_2p0_baseband_postamble_5g_xlna
+
+#define ar9462_2p1_common_wo_xlna_rx_gain ar9462_2p0_common_wo_xlna_rx_gain
+
+#define ar9462_2p1_modes_low_ob_db_tx_gain ar9462_2p0_modes_low_ob_db_tx_gain
+
+#define ar9462_2p1_modes_high_ob_db_tx_gain ar9462_2p0_modes_high_ob_db_tx_gain
+
+#define ar9462_2p1_modes_mix_ob_db_tx_gain ar9462_2p0_modes_mix_ob_db_tx_gain
+
+#define ar9462_2p1_modes_fast_clock ar9462_2p0_modes_fast_clock
+
+#define ar9462_2p1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484
+
+#define ar9462_2p1_pciephy_clkreq_disable_L1 ar9462_2p0_pciephy_clkreq_disable_L1
+
 static const u32 ar9462_2p1_mac_core[][2] = {
        /* Addr      allmodes  */
        {0x00000008, 0x00000000},
@@ -183,168 +221,6 @@ static const u32 ar9462_2p1_mac_core[][2] = {
        {0x000083d0, 0x000301ff},
 };
 
-static const u32 ar9462_2p1_mac_postamble[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
-       {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
-       {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
-       {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
-       {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
-       {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
-       {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
-       {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
-};
-
-static const u32 ar9462_2p1_baseband_core[][2] = {
-       /* Addr      allmodes  */
-       {0x00009800, 0xafe68e30},
-       {0x00009804, 0xfd14e000},
-       {0x00009808, 0x9c0a9f6b},
-       {0x0000980c, 0x04900000},
-       {0x00009814, 0x9280c00a},
-       {0x00009818, 0x00000000},
-       {0x0000981c, 0x00020028},
-       {0x00009834, 0x6400a290},
-       {0x00009838, 0x0108ecff},
-       {0x0000983c, 0x0d000600},
-       {0x00009880, 0x201fff00},
-       {0x00009884, 0x00001042},
-       {0x000098a4, 0x00200400},
-       {0x000098b0, 0x32440bbe},
-       {0x000098d0, 0x004b6a8e},
-       {0x000098d4, 0x00000820},
-       {0x000098dc, 0x00000000},
-       {0x000098e4, 0x01ffffff},
-       {0x000098e8, 0x01ffffff},
-       {0x000098ec, 0x01ffffff},
-       {0x000098f0, 0x00000000},
-       {0x000098f4, 0x00000000},
-       {0x00009bf0, 0x80000000},
-       {0x00009c04, 0xff55ff55},
-       {0x00009c08, 0x0320ff55},
-       {0x00009c0c, 0x00000000},
-       {0x00009c10, 0x00000000},
-       {0x00009c14, 0x00046384},
-       {0x00009c18, 0x05b6b440},
-       {0x00009c1c, 0x00b6b440},
-       {0x00009d00, 0xc080a333},
-       {0x00009d04, 0x40206c10},
-       {0x00009d08, 0x009c4060},
-       {0x00009d0c, 0x9883800a},
-       {0x00009d10, 0x01834061},
-       {0x00009d14, 0x00c0040b},
-       {0x00009d18, 0x00000000},
-       {0x00009e08, 0x0038230c},
-       {0x00009e24, 0x990bb515},
-       {0x00009e28, 0x0c6f0000},
-       {0x00009e30, 0x06336f77},
-       {0x00009e34, 0x6af6532f},
-       {0x00009e38, 0x0cc80c00},
-       {0x00009e40, 0x15262820},
-       {0x00009e4c, 0x00001004},
-       {0x00009e50, 0x00ff03f1},
-       {0x00009e54, 0xe4c555c2},
-       {0x00009e58, 0xfd857722},
-       {0x00009e5c, 0xe9198724},
-       {0x00009fc0, 0x803e4788},
-       {0x00009fc4, 0x0001efb5},
-       {0x00009fcc, 0x40000014},
-       {0x00009fd0, 0x0a193b93},
-       {0x0000a20c, 0x00000000},
-       {0x0000a220, 0x00000000},
-       {0x0000a224, 0x00000000},
-       {0x0000a228, 0x10002310},
-       {0x0000a23c, 0x00000000},
-       {0x0000a244, 0x0c000000},
-       {0x0000a2a0, 0x00000001},
-       {0x0000a2c0, 0x00000001},
-       {0x0000a2c8, 0x00000000},
-       {0x0000a2cc, 0x18c43433},
-       {0x0000a2d4, 0x00000000},
-       {0x0000a2ec, 0x00000000},
-       {0x0000a2f0, 0x00000000},
-       {0x0000a2f4, 0x00000000},
-       {0x0000a2f8, 0x00000000},
-       {0x0000a344, 0x00000000},
-       {0x0000a34c, 0x00000000},
-       {0x0000a350, 0x0000a000},
-       {0x0000a364, 0x00000000},
-       {0x0000a370, 0x00000000},
-       {0x0000a390, 0x00000001},
-       {0x0000a394, 0x00000444},
-       {0x0000a398, 0x001f0e0f},
-       {0x0000a39c, 0x0075393f},
-       {0x0000a3a0, 0xb79f6427},
-       {0x0000a3c0, 0x20202020},
-       {0x0000a3c4, 0x22222220},
-       {0x0000a3c8, 0x20200020},
-       {0x0000a3cc, 0x20202020},
-       {0x0000a3d0, 0x20202020},
-       {0x0000a3d4, 0x20202020},
-       {0x0000a3d8, 0x20202020},
-       {0x0000a3dc, 0x20202020},
-       {0x0000a3e0, 0x20202020},
-       {0x0000a3e4, 0x20202020},
-       {0x0000a3e8, 0x20202020},
-       {0x0000a3ec, 0x20202020},
-       {0x0000a3f0, 0x00000000},
-       {0x0000a3f4, 0x00000006},
-       {0x0000a3f8, 0x0c9bd380},
-       {0x0000a3fc, 0x000f0f01},
-       {0x0000a400, 0x8fa91f01},
-       {0x0000a404, 0x00000000},
-       {0x0000a408, 0x0e79e5c6},
-       {0x0000a40c, 0x00820820},
-       {0x0000a414, 0x1ce739ce},
-       {0x0000a418, 0x2d001dce},
-       {0x0000a434, 0x00000000},
-       {0x0000a438, 0x00001801},
-       {0x0000a43c, 0x00100000},
-       {0x0000a444, 0x00000000},
-       {0x0000a448, 0x05000080},
-       {0x0000a44c, 0x00000001},
-       {0x0000a450, 0x00010000},
-       {0x0000a454, 0x07000000},
-       {0x0000a644, 0xbfad9d74},
-       {0x0000a648, 0x0048060a},
-       {0x0000a64c, 0x00002037},
-       {0x0000a670, 0x03020100},
-       {0x0000a674, 0x09080504},
-       {0x0000a678, 0x0d0c0b0a},
-       {0x0000a67c, 0x13121110},
-       {0x0000a680, 0x31301514},
-       {0x0000a684, 0x35343332},
-       {0x0000a688, 0x00000036},
-       {0x0000a690, 0x00000838},
-       {0x0000a6b0, 0x0000000a},
-       {0x0000a6b4, 0x00512c01},
-       {0x0000a7c0, 0x00000000},
-       {0x0000a7c4, 0xfffffffc},
-       {0x0000a7c8, 0x00000000},
-       {0x0000a7cc, 0x00000000},
-       {0x0000a7d0, 0x00000000},
-       {0x0000a7d4, 0x00000004},
-       {0x0000a7dc, 0x00000000},
-       {0x0000a7f0, 0x80000000},
-       {0x0000a8d0, 0x004b6a8e},
-       {0x0000a8d4, 0x00000820},
-       {0x0000a8dc, 0x00000000},
-       {0x0000a8f0, 0x00000000},
-       {0x0000a8f4, 0x00000000},
-       {0x0000abf0, 0x80000000},
-       {0x0000b2d0, 0x00000080},
-       {0x0000b2d4, 0x00000000},
-       {0x0000b2ec, 0x00000000},
-       {0x0000b2f0, 0x00000000},
-       {0x0000b2f4, 0x00000000},
-       {0x0000b2f8, 0x00000000},
-       {0x0000b408, 0x0e79e5c0},
-       {0x0000b40c, 0x00820820},
-       {0x0000b420, 0x00000000},
-       {0x0000b6b0, 0x0000000a},
-       {0x0000b6b4, 0x00000001},
-};
-
 static const u32 ar9462_2p1_baseband_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d},
@@ -404,72 +280,6 @@ static const u32 ar9462_2p1_baseband_postamble[][5] = {
        {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},
 };
 
-static const u32 ar9462_2p1_radio_core[][2] = {
-       /* Addr      allmodes  */
-       {0x00016000, 0x36db6db6},
-       {0x00016004, 0x6db6db40},
-       {0x00016008, 0x73f00000},
-       {0x0001600c, 0x00000000},
-       {0x00016010, 0x6d820001},
-       {0x00016040, 0x7f80fff8},
-       {0x0001604c, 0x2699e04f},
-       {0x00016050, 0x6db6db6c},
-       {0x00016058, 0x6c200000},
-       {0x00016080, 0x000c0000},
-       {0x00016084, 0x9a68048c},
-       {0x00016088, 0x54214514},
-       {0x0001608c, 0x1203040b},
-       {0x00016090, 0x24926490},
-       {0x00016098, 0xd2888888},
-       {0x000160a0, 0x0a108ffe},
-       {0x000160a4, 0x812fc491},
-       {0x000160a8, 0x423c8000},
-       {0x000160b4, 0x92000000},
-       {0x000160b8, 0x0285dddc},
-       {0x000160bc, 0x02908888},
-       {0x000160c0, 0x00adb6d0},
-       {0x000160c4, 0x6db6db60},
-       {0x000160c8, 0x6db6db6c},
-       {0x000160cc, 0x0de6c1b0},
-       {0x00016100, 0x3fffbe04},
-       {0x00016104, 0xfff80000},
-       {0x00016108, 0x00200400},
-       {0x00016110, 0x00000000},
-       {0x00016144, 0x02084080},
-       {0x00016148, 0x000080c0},
-       {0x00016280, 0x050a0001},
-       {0x00016284, 0x3d841418},
-       {0x00016288, 0x00000000},
-       {0x0001628c, 0xe3000000},
-       {0x00016290, 0xa1005080},
-       {0x00016294, 0x00000020},
-       {0x00016298, 0x54a82900},
-       {0x00016340, 0x121e4276},
-       {0x00016344, 0x00300000},
-       {0x00016400, 0x36db6db6},
-       {0x00016404, 0x6db6db40},
-       {0x00016408, 0x73f00000},
-       {0x0001640c, 0x00000000},
-       {0x00016410, 0x6c800001},
-       {0x00016440, 0x7f80fff8},
-       {0x0001644c, 0x4699e04f},
-       {0x00016450, 0x6db6db6c},
-       {0x00016500, 0x3fffbe04},
-       {0x00016504, 0xfff80000},
-       {0x00016508, 0x00200400},
-       {0x00016510, 0x00000000},
-       {0x00016544, 0x02084080},
-       {0x00016548, 0x000080c0},
-};
-
-static const u32 ar9462_2p1_radio_postamble[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524},
-       {0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70},
-       {0x0001610c, 0x48000000, 0x40000000, 0x40000000, 0x40000000},
-       {0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000},
-};
-
 static const u32 ar9462_2p1_soc_preamble[][2] = {
        /* Addr      allmodes  */
        {0x000040a4, 0x00a0c9c9},
@@ -478,1297 +288,4 @@ static const u32 ar9462_2p1_soc_preamble[][2] = {
        {0x00007038, 0x000004c2},
 };
 
-static const u32 ar9462_2p1_soc_postamble[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00007010, 0x00000033, 0x00000033, 0x00000033, 0x00000033},
-};
-
-static const u32 ar9462_2p1_radio_postamble_sys2ant[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
-       {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
-       {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
-};
-
-static const u32 ar9462_2p1_common_rx_gain[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x00010000},
-       {0x0000a004, 0x00030002},
-       {0x0000a008, 0x00050004},
-       {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x00830082},
-       {0x0000a014, 0x01810180},
-       {0x0000a018, 0x01830182},
-       {0x0000a01c, 0x01850184},
-       {0x0000a020, 0x01890188},
-       {0x0000a024, 0x018b018a},
-       {0x0000a028, 0x018d018c},
-       {0x0000a02c, 0x01910190},
-       {0x0000a030, 0x01930192},
-       {0x0000a034, 0x01950194},
-       {0x0000a038, 0x038a0196},
-       {0x0000a03c, 0x038c038b},
-       {0x0000a040, 0x0390038d},
-       {0x0000a044, 0x03920391},
-       {0x0000a048, 0x03940393},
-       {0x0000a04c, 0x03960395},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x22222229},
-       {0x0000a084, 0x1d1d1d1d},
-       {0x0000a088, 0x1d1d1d1d},
-       {0x0000a08c, 0x1d1d1d1d},
-       {0x0000a090, 0x171d1d1d},
-       {0x0000a094, 0x11111717},
-       {0x0000a098, 0x00030311},
-       {0x0000a09c, 0x00000000},
-       {0x0000a0a0, 0x00000000},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x01000101},
-       {0x0000a0c8, 0x011e011f},
-       {0x0000a0cc, 0x011c011d},
-       {0x0000a0d0, 0x02030204},
-       {0x0000a0d4, 0x02010202},
-       {0x0000a0d8, 0x021f0200},
-       {0x0000a0dc, 0x0302021e},
-       {0x0000a0e0, 0x03000301},
-       {0x0000a0e4, 0x031e031f},
-       {0x0000a0e8, 0x0402031d},
-       {0x0000a0ec, 0x04000401},
-       {0x0000a0f0, 0x041e041f},
-       {0x0000a0f4, 0x0502041d},
-       {0x0000a0f8, 0x05000501},
-       {0x0000a0fc, 0x051e051f},
-       {0x0000a100, 0x06010602},
-       {0x0000a104, 0x061f0600},
-       {0x0000a108, 0x061d061e},
-       {0x0000a10c, 0x07020703},
-       {0x0000a110, 0x07000701},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x01000101},
-       {0x0000a148, 0x011e011f},
-       {0x0000a14c, 0x011c011d},
-       {0x0000a150, 0x02030204},
-       {0x0000a154, 0x02010202},
-       {0x0000a158, 0x021f0200},
-       {0x0000a15c, 0x0302021e},
-       {0x0000a160, 0x03000301},
-       {0x0000a164, 0x031e031f},
-       {0x0000a168, 0x0402031d},
-       {0x0000a16c, 0x04000401},
-       {0x0000a170, 0x041e041f},
-       {0x0000a174, 0x0502041d},
-       {0x0000a178, 0x05000501},
-       {0x0000a17c, 0x051e051f},
-       {0x0000a180, 0x06010602},
-       {0x0000a184, 0x061f0600},
-       {0x0000a188, 0x061d061e},
-       {0x0000a18c, 0x07020703},
-       {0x0000a190, 0x07000701},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000196},
-       {0x0000b000, 0x00010000},
-       {0x0000b004, 0x00030002},
-       {0x0000b008, 0x00050004},
-       {0x0000b00c, 0x00810080},
-       {0x0000b010, 0x00830082},
-       {0x0000b014, 0x01810180},
-       {0x0000b018, 0x01830182},
-       {0x0000b01c, 0x01850184},
-       {0x0000b020, 0x02810280},
-       {0x0000b024, 0x02830282},
-       {0x0000b028, 0x02850284},
-       {0x0000b02c, 0x02890288},
-       {0x0000b030, 0x028b028a},
-       {0x0000b034, 0x0388028c},
-       {0x0000b038, 0x038a0389},
-       {0x0000b03c, 0x038c038b},
-       {0x0000b040, 0x0390038d},
-       {0x0000b044, 0x03920391},
-       {0x0000b048, 0x03940393},
-       {0x0000b04c, 0x03960395},
-       {0x0000b050, 0x00000000},
-       {0x0000b054, 0x00000000},
-       {0x0000b058, 0x00000000},
-       {0x0000b05c, 0x00000000},
-       {0x0000b060, 0x00000000},
-       {0x0000b064, 0x00000000},
-       {0x0000b068, 0x00000000},
-       {0x0000b06c, 0x00000000},
-       {0x0000b070, 0x00000000},
-       {0x0000b074, 0x00000000},
-       {0x0000b078, 0x00000000},
-       {0x0000b07c, 0x00000000},
-       {0x0000b080, 0x2a2d2f32},
-       {0x0000b084, 0x21232328},
-       {0x0000b088, 0x19191c1e},
-       {0x0000b08c, 0x12141417},
-       {0x0000b090, 0x07070e0e},
-       {0x0000b094, 0x03030305},
-       {0x0000b098, 0x00000003},
-       {0x0000b09c, 0x00000000},
-       {0x0000b0a0, 0x00000000},
-       {0x0000b0a4, 0x00000000},
-       {0x0000b0a8, 0x00000000},
-       {0x0000b0ac, 0x00000000},
-       {0x0000b0b0, 0x00000000},
-       {0x0000b0b4, 0x00000000},
-       {0x0000b0b8, 0x00000000},
-       {0x0000b0bc, 0x00000000},
-       {0x0000b0c0, 0x003f0020},
-       {0x0000b0c4, 0x00400041},
-       {0x0000b0c8, 0x0140005f},
-       {0x0000b0cc, 0x0160015f},
-       {0x0000b0d0, 0x017e017f},
-       {0x0000b0d4, 0x02410242},
-       {0x0000b0d8, 0x025f0240},
-       {0x0000b0dc, 0x027f0260},
-       {0x0000b0e0, 0x0341027e},
-       {0x0000b0e4, 0x035f0340},
-       {0x0000b0e8, 0x037f0360},
-       {0x0000b0ec, 0x04400441},
-       {0x0000b0f0, 0x0460045f},
-       {0x0000b0f4, 0x0541047f},
-       {0x0000b0f8, 0x055f0540},
-       {0x0000b0fc, 0x057f0560},
-       {0x0000b100, 0x06400641},
-       {0x0000b104, 0x0660065f},
-       {0x0000b108, 0x067e067f},
-       {0x0000b10c, 0x07410742},
-       {0x0000b110, 0x075f0740},
-       {0x0000b114, 0x077f0760},
-       {0x0000b118, 0x07800781},
-       {0x0000b11c, 0x07a0079f},
-       {0x0000b120, 0x07c107bf},
-       {0x0000b124, 0x000007c0},
-       {0x0000b128, 0x00000000},
-       {0x0000b12c, 0x00000000},
-       {0x0000b130, 0x00000000},
-       {0x0000b134, 0x00000000},
-       {0x0000b138, 0x00000000},
-       {0x0000b13c, 0x00000000},
-       {0x0000b140, 0x003f0020},
-       {0x0000b144, 0x00400041},
-       {0x0000b148, 0x0140005f},
-       {0x0000b14c, 0x0160015f},
-       {0x0000b150, 0x017e017f},
-       {0x0000b154, 0x02410242},
-       {0x0000b158, 0x025f0240},
-       {0x0000b15c, 0x027f0260},
-       {0x0000b160, 0x0341027e},
-       {0x0000b164, 0x035f0340},
-       {0x0000b168, 0x037f0360},
-       {0x0000b16c, 0x04400441},
-       {0x0000b170, 0x0460045f},
-       {0x0000b174, 0x0541047f},
-       {0x0000b178, 0x055f0540},
-       {0x0000b17c, 0x057f0560},
-       {0x0000b180, 0x06400641},
-       {0x0000b184, 0x0660065f},
-       {0x0000b188, 0x067e067f},
-       {0x0000b18c, 0x07410742},
-       {0x0000b190, 0x075f0740},
-       {0x0000b194, 0x077f0760},
-       {0x0000b198, 0x07800781},
-       {0x0000b19c, 0x07a0079f},
-       {0x0000b1a0, 0x07c107bf},
-       {0x0000b1a4, 0x000007c0},
-       {0x0000b1a8, 0x00000000},
-       {0x0000b1ac, 0x00000000},
-       {0x0000b1b0, 0x00000000},
-       {0x0000b1b4, 0x00000000},
-       {0x0000b1b8, 0x00000000},
-       {0x0000b1bc, 0x00000000},
-       {0x0000b1c0, 0x00000000},
-       {0x0000b1c4, 0x00000000},
-       {0x0000b1c8, 0x00000000},
-       {0x0000b1cc, 0x00000000},
-       {0x0000b1d0, 0x00000000},
-       {0x0000b1d4, 0x00000000},
-       {0x0000b1d8, 0x00000000},
-       {0x0000b1dc, 0x00000000},
-       {0x0000b1e0, 0x00000000},
-       {0x0000b1e4, 0x00000000},
-       {0x0000b1e8, 0x00000000},
-       {0x0000b1ec, 0x00000000},
-       {0x0000b1f0, 0x00000396},
-       {0x0000b1f4, 0x00000396},
-       {0x0000b1f8, 0x00000396},
-       {0x0000b1fc, 0x00000196},
-};
-
-static const u32 ar9462_2p1_common_mixed_rx_gain[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x00010000},
-       {0x0000a004, 0x00030002},
-       {0x0000a008, 0x00050004},
-       {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x00830082},
-       {0x0000a014, 0x01810180},
-       {0x0000a018, 0x01830182},
-       {0x0000a01c, 0x01850184},
-       {0x0000a020, 0x01890188},
-       {0x0000a024, 0x018b018a},
-       {0x0000a028, 0x018d018c},
-       {0x0000a02c, 0x03820190},
-       {0x0000a030, 0x03840383},
-       {0x0000a034, 0x03880385},
-       {0x0000a038, 0x038a0389},
-       {0x0000a03c, 0x038c038b},
-       {0x0000a040, 0x0390038d},
-       {0x0000a044, 0x03920391},
-       {0x0000a048, 0x03940393},
-       {0x0000a04c, 0x03960395},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x29292929},
-       {0x0000a084, 0x29292929},
-       {0x0000a088, 0x29292929},
-       {0x0000a08c, 0x29292929},
-       {0x0000a090, 0x22292929},
-       {0x0000a094, 0x1d1d2222},
-       {0x0000a098, 0x0c111117},
-       {0x0000a09c, 0x00030303},
-       {0x0000a0a0, 0x00000000},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x01000101},
-       {0x0000a0c8, 0x011e011f},
-       {0x0000a0cc, 0x011c011d},
-       {0x0000a0d0, 0x02030204},
-       {0x0000a0d4, 0x02010202},
-       {0x0000a0d8, 0x021f0200},
-       {0x0000a0dc, 0x0302021e},
-       {0x0000a0e0, 0x03000301},
-       {0x0000a0e4, 0x031e031f},
-       {0x0000a0e8, 0x0402031d},
-       {0x0000a0ec, 0x04000401},
-       {0x0000a0f0, 0x041e041f},
-       {0x0000a0f4, 0x0502041d},
-       {0x0000a0f8, 0x05000501},
-       {0x0000a0fc, 0x051e051f},
-       {0x0000a100, 0x06010602},
-       {0x0000a104, 0x061f0600},
-       {0x0000a108, 0x061d061e},
-       {0x0000a10c, 0x07020703},
-       {0x0000a110, 0x07000701},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x01000101},
-       {0x0000a148, 0x011e011f},
-       {0x0000a14c, 0x011c011d},
-       {0x0000a150, 0x02030204},
-       {0x0000a154, 0x02010202},
-       {0x0000a158, 0x021f0200},
-       {0x0000a15c, 0x0302021e},
-       {0x0000a160, 0x03000301},
-       {0x0000a164, 0x031e031f},
-       {0x0000a168, 0x0402031d},
-       {0x0000a16c, 0x04000401},
-       {0x0000a170, 0x041e041f},
-       {0x0000a174, 0x0502041d},
-       {0x0000a178, 0x05000501},
-       {0x0000a17c, 0x051e051f},
-       {0x0000a180, 0x06010602},
-       {0x0000a184, 0x061f0600},
-       {0x0000a188, 0x061d061e},
-       {0x0000a18c, 0x07020703},
-       {0x0000a190, 0x07000701},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000196},
-       {0x0000b000, 0x00010000},
-       {0x0000b004, 0x00030002},
-       {0x0000b008, 0x00050004},
-       {0x0000b00c, 0x00810080},
-       {0x0000b010, 0x00830082},
-       {0x0000b014, 0x01810180},
-       {0x0000b018, 0x01830182},
-       {0x0000b01c, 0x01850184},
-       {0x0000b020, 0x02810280},
-       {0x0000b024, 0x02830282},
-       {0x0000b028, 0x02850284},
-       {0x0000b02c, 0x02890288},
-       {0x0000b030, 0x028b028a},
-       {0x0000b034, 0x0388028c},
-       {0x0000b038, 0x038a0389},
-       {0x0000b03c, 0x038c038b},
-       {0x0000b040, 0x0390038d},
-       {0x0000b044, 0x03920391},
-       {0x0000b048, 0x03940393},
-       {0x0000b04c, 0x03960395},
-       {0x0000b050, 0x00000000},
-       {0x0000b054, 0x00000000},
-       {0x0000b058, 0x00000000},
-       {0x0000b05c, 0x00000000},
-       {0x0000b060, 0x00000000},
-       {0x0000b064, 0x00000000},
-       {0x0000b068, 0x00000000},
-       {0x0000b06c, 0x00000000},
-       {0x0000b070, 0x00000000},
-       {0x0000b074, 0x00000000},
-       {0x0000b078, 0x00000000},
-       {0x0000b07c, 0x00000000},
-       {0x0000b080, 0x2a2d2f32},
-       {0x0000b084, 0x21232328},
-       {0x0000b088, 0x19191c1e},
-       {0x0000b08c, 0x12141417},
-       {0x0000b090, 0x07070e0e},
-       {0x0000b094, 0x03030305},
-       {0x0000b098, 0x00000003},
-       {0x0000b09c, 0x00000000},
-       {0x0000b0a0, 0x00000000},
-       {0x0000b0a4, 0x00000000},
-       {0x0000b0a8, 0x00000000},
-       {0x0000b0ac, 0x00000000},
-       {0x0000b0b0, 0x00000000},
-       {0x0000b0b4, 0x00000000},
-       {0x0000b0b8, 0x00000000},
-       {0x0000b0bc, 0x00000000},
-       {0x0000b0c0, 0x003f0020},
-       {0x0000b0c4, 0x00400041},
-       {0x0000b0c8, 0x0140005f},
-       {0x0000b0cc, 0x0160015f},
-       {0x0000b0d0, 0x017e017f},
-       {0x0000b0d4, 0x02410242},
-       {0x0000b0d8, 0x025f0240},
-       {0x0000b0dc, 0x027f0260},
-       {0x0000b0e0, 0x0341027e},
-       {0x0000b0e4, 0x035f0340},
-       {0x0000b0e8, 0x037f0360},
-       {0x0000b0ec, 0x04400441},
-       {0x0000b0f0, 0x0460045f},
-       {0x0000b0f4, 0x0541047f},
-       {0x0000b0f8, 0x055f0540},
-       {0x0000b0fc, 0x057f0560},
-       {0x0000b100, 0x06400641},
-       {0x0000b104, 0x0660065f},
-       {0x0000b108, 0x067e067f},
-       {0x0000b10c, 0x07410742},
-       {0x0000b110, 0x075f0740},
-       {0x0000b114, 0x077f0760},
-       {0x0000b118, 0x07800781},
-       {0x0000b11c, 0x07a0079f},
-       {0x0000b120, 0x07c107bf},
-       {0x0000b124, 0x000007c0},
-       {0x0000b128, 0x00000000},
-       {0x0000b12c, 0x00000000},
-       {0x0000b130, 0x00000000},
-       {0x0000b134, 0x00000000},
-       {0x0000b138, 0x00000000},
-       {0x0000b13c, 0x00000000},
-       {0x0000b140, 0x003f0020},
-       {0x0000b144, 0x00400041},
-       {0x0000b148, 0x0140005f},
-       {0x0000b14c, 0x0160015f},
-       {0x0000b150, 0x017e017f},
-       {0x0000b154, 0x02410242},
-       {0x0000b158, 0x025f0240},
-       {0x0000b15c, 0x027f0260},
-       {0x0000b160, 0x0341027e},
-       {0x0000b164, 0x035f0340},
-       {0x0000b168, 0x037f0360},
-       {0x0000b16c, 0x04400441},
-       {0x0000b170, 0x0460045f},
-       {0x0000b174, 0x0541047f},
-       {0x0000b178, 0x055f0540},
-       {0x0000b17c, 0x057f0560},
-       {0x0000b180, 0x06400641},
-       {0x0000b184, 0x0660065f},
-       {0x0000b188, 0x067e067f},
-       {0x0000b18c, 0x07410742},
-       {0x0000b190, 0x075f0740},
-       {0x0000b194, 0x077f0760},
-       {0x0000b198, 0x07800781},
-       {0x0000b19c, 0x07a0079f},
-       {0x0000b1a0, 0x07c107bf},
-       {0x0000b1a4, 0x000007c0},
-       {0x0000b1a8, 0x00000000},
-       {0x0000b1ac, 0x00000000},
-       {0x0000b1b0, 0x00000000},
-       {0x0000b1b4, 0x00000000},
-       {0x0000b1b8, 0x00000000},
-       {0x0000b1bc, 0x00000000},
-       {0x0000b1c0, 0x00000000},
-       {0x0000b1c4, 0x00000000},
-       {0x0000b1c8, 0x00000000},
-       {0x0000b1cc, 0x00000000},
-       {0x0000b1d0, 0x00000000},
-       {0x0000b1d4, 0x00000000},
-       {0x0000b1d8, 0x00000000},
-       {0x0000b1dc, 0x00000000},
-       {0x0000b1e0, 0x00000000},
-       {0x0000b1e4, 0x00000000},
-       {0x0000b1e8, 0x00000000},
-       {0x0000b1ec, 0x00000000},
-       {0x0000b1f0, 0x00000396},
-       {0x0000b1f4, 0x00000396},
-       {0x0000b1f8, 0x00000396},
-       {0x0000b1fc, 0x00000196},
-};
-
-static const u32 ar9462_2p1_baseband_core_mix_rxgain[][2] = {
-       /* Addr      allmodes  */
-       {0x00009fd0, 0x0a2d6b93},
-};
-
-static const u32 ar9462_2p1_baseband_postamble_mix_rxgain[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae},
-       {0x00009824, 0x63c640de, 0x5ac640d0, 0x63c640da, 0x63c640da},
-       {0x00009828, 0x0796be89, 0x0696b081, 0x0916be81, 0x0916be81},
-       {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000d8, 0x6c4000d8},
-       {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec86d2e, 0x7ec86d2e},
-       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32395c5e},
-};
-
-static const u32 ar9462_2p1_baseband_postamble_5g_xlna[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
-};
-
-static const u32 ar9462_2p1_common_wo_xlna_rx_gain[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x00010000},
-       {0x0000a004, 0x00030002},
-       {0x0000a008, 0x00050004},
-       {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x00830082},
-       {0x0000a014, 0x01810180},
-       {0x0000a018, 0x01830182},
-       {0x0000a01c, 0x01850184},
-       {0x0000a020, 0x01890188},
-       {0x0000a024, 0x018b018a},
-       {0x0000a028, 0x018d018c},
-       {0x0000a02c, 0x03820190},
-       {0x0000a030, 0x03840383},
-       {0x0000a034, 0x03880385},
-       {0x0000a038, 0x038a0389},
-       {0x0000a03c, 0x038c038b},
-       {0x0000a040, 0x0390038d},
-       {0x0000a044, 0x03920391},
-       {0x0000a048, 0x03940393},
-       {0x0000a04c, 0x03960395},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x29292929},
-       {0x0000a084, 0x29292929},
-       {0x0000a088, 0x29292929},
-       {0x0000a08c, 0x29292929},
-       {0x0000a090, 0x22292929},
-       {0x0000a094, 0x1d1d2222},
-       {0x0000a098, 0x0c111117},
-       {0x0000a09c, 0x00030303},
-       {0x0000a0a0, 0x00000000},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x01000101},
-       {0x0000a0c8, 0x011e011f},
-       {0x0000a0cc, 0x011c011d},
-       {0x0000a0d0, 0x02030204},
-       {0x0000a0d4, 0x02010202},
-       {0x0000a0d8, 0x021f0200},
-       {0x0000a0dc, 0x0302021e},
-       {0x0000a0e0, 0x03000301},
-       {0x0000a0e4, 0x031e031f},
-       {0x0000a0e8, 0x0402031d},
-       {0x0000a0ec, 0x04000401},
-       {0x0000a0f0, 0x041e041f},
-       {0x0000a0f4, 0x0502041d},
-       {0x0000a0f8, 0x05000501},
-       {0x0000a0fc, 0x051e051f},
-       {0x0000a100, 0x06010602},
-       {0x0000a104, 0x061f0600},
-       {0x0000a108, 0x061d061e},
-       {0x0000a10c, 0x07020703},
-       {0x0000a110, 0x07000701},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x01000101},
-       {0x0000a148, 0x011e011f},
-       {0x0000a14c, 0x011c011d},
-       {0x0000a150, 0x02030204},
-       {0x0000a154, 0x02010202},
-       {0x0000a158, 0x021f0200},
-       {0x0000a15c, 0x0302021e},
-       {0x0000a160, 0x03000301},
-       {0x0000a164, 0x031e031f},
-       {0x0000a168, 0x0402031d},
-       {0x0000a16c, 0x04000401},
-       {0x0000a170, 0x041e041f},
-       {0x0000a174, 0x0502041d},
-       {0x0000a178, 0x05000501},
-       {0x0000a17c, 0x051e051f},
-       {0x0000a180, 0x06010602},
-       {0x0000a184, 0x061f0600},
-       {0x0000a188, 0x061d061e},
-       {0x0000a18c, 0x07020703},
-       {0x0000a190, 0x07000701},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000196},
-       {0x0000b000, 0x00010000},
-       {0x0000b004, 0x00030002},
-       {0x0000b008, 0x00050004},
-       {0x0000b00c, 0x00810080},
-       {0x0000b010, 0x00830082},
-       {0x0000b014, 0x01810180},
-       {0x0000b018, 0x01830182},
-       {0x0000b01c, 0x01850184},
-       {0x0000b020, 0x02810280},
-       {0x0000b024, 0x02830282},
-       {0x0000b028, 0x02850284},
-       {0x0000b02c, 0x02890288},
-       {0x0000b030, 0x028b028a},
-       {0x0000b034, 0x0388028c},
-       {0x0000b038, 0x038a0389},
-       {0x0000b03c, 0x038c038b},
-       {0x0000b040, 0x0390038d},
-       {0x0000b044, 0x03920391},
-       {0x0000b048, 0x03940393},
-       {0x0000b04c, 0x03960395},
-       {0x0000b050, 0x00000000},
-       {0x0000b054, 0x00000000},
-       {0x0000b058, 0x00000000},
-       {0x0000b05c, 0x00000000},
-       {0x0000b060, 0x00000000},
-       {0x0000b064, 0x00000000},
-       {0x0000b068, 0x00000000},
-       {0x0000b06c, 0x00000000},
-       {0x0000b070, 0x00000000},
-       {0x0000b074, 0x00000000},
-       {0x0000b078, 0x00000000},
-       {0x0000b07c, 0x00000000},
-       {0x0000b080, 0x32323232},
-       {0x0000b084, 0x2f2f3232},
-       {0x0000b088, 0x23282a2d},
-       {0x0000b08c, 0x1c1e2123},
-       {0x0000b090, 0x14171919},
-       {0x0000b094, 0x0e0e1214},
-       {0x0000b098, 0x03050707},
-       {0x0000b09c, 0x00030303},
-       {0x0000b0a0, 0x00000000},
-       {0x0000b0a4, 0x00000000},
-       {0x0000b0a8, 0x00000000},
-       {0x0000b0ac, 0x00000000},
-       {0x0000b0b0, 0x00000000},
-       {0x0000b0b4, 0x00000000},
-       {0x0000b0b8, 0x00000000},
-       {0x0000b0bc, 0x00000000},
-       {0x0000b0c0, 0x003f0020},
-       {0x0000b0c4, 0x00400041},
-       {0x0000b0c8, 0x0140005f},
-       {0x0000b0cc, 0x0160015f},
-       {0x0000b0d0, 0x017e017f},
-       {0x0000b0d4, 0x02410242},
-       {0x0000b0d8, 0x025f0240},
-       {0x0000b0dc, 0x027f0260},
-       {0x0000b0e0, 0x0341027e},
-       {0x0000b0e4, 0x035f0340},
-       {0x0000b0e8, 0x037f0360},
-       {0x0000b0ec, 0x04400441},
-       {0x0000b0f0, 0x0460045f},
-       {0x0000b0f4, 0x0541047f},
-       {0x0000b0f8, 0x055f0540},
-       {0x0000b0fc, 0x057f0560},
-       {0x0000b100, 0x06400641},
-       {0x0000b104, 0x0660065f},
-       {0x0000b108, 0x067e067f},
-       {0x0000b10c, 0x07410742},
-       {0x0000b110, 0x075f0740},
-       {0x0000b114, 0x077f0760},
-       {0x0000b118, 0x07800781},
-       {0x0000b11c, 0x07a0079f},
-       {0x0000b120, 0x07c107bf},
-       {0x0000b124, 0x000007c0},
-       {0x0000b128, 0x00000000},
-       {0x0000b12c, 0x00000000},
-       {0x0000b130, 0x00000000},
-       {0x0000b134, 0x00000000},
-       {0x0000b138, 0x00000000},
-       {0x0000b13c, 0x00000000},
-       {0x0000b140, 0x003f0020},
-       {0x0000b144, 0x00400041},
-       {0x0000b148, 0x0140005f},
-       {0x0000b14c, 0x0160015f},
-       {0x0000b150, 0x017e017f},
-       {0x0000b154, 0x02410242},
-       {0x0000b158, 0x025f0240},
-       {0x0000b15c, 0x027f0260},
-       {0x0000b160, 0x0341027e},
-       {0x0000b164, 0x035f0340},
-       {0x0000b168, 0x037f0360},
-       {0x0000b16c, 0x04400441},
-       {0x0000b170, 0x0460045f},
-       {0x0000b174, 0x0541047f},
-       {0x0000b178, 0x055f0540},
-       {0x0000b17c, 0x057f0560},
-       {0x0000b180, 0x06400641},
-       {0x0000b184, 0x0660065f},
-       {0x0000b188, 0x067e067f},
-       {0x0000b18c, 0x07410742},
-       {0x0000b190, 0x075f0740},
-       {0x0000b194, 0x077f0760},
-       {0x0000b198, 0x07800781},
-       {0x0000b19c, 0x07a0079f},
-       {0x0000b1a0, 0x07c107bf},
-       {0x0000b1a4, 0x000007c0},
-       {0x0000b1a8, 0x00000000},
-       {0x0000b1ac, 0x00000000},
-       {0x0000b1b0, 0x00000000},
-       {0x0000b1b4, 0x00000000},
-       {0x0000b1b8, 0x00000000},
-       {0x0000b1bc, 0x00000000},
-       {0x0000b1c0, 0x00000000},
-       {0x0000b1c4, 0x00000000},
-       {0x0000b1c8, 0x00000000},
-       {0x0000b1cc, 0x00000000},
-       {0x0000b1d0, 0x00000000},
-       {0x0000b1d4, 0x00000000},
-       {0x0000b1d8, 0x00000000},
-       {0x0000b1dc, 0x00000000},
-       {0x0000b1e0, 0x00000000},
-       {0x0000b1e4, 0x00000000},
-       {0x0000b1e8, 0x00000000},
-       {0x0000b1ec, 0x00000000},
-       {0x0000b1f0, 0x00000396},
-       {0x0000b1f4, 0x00000396},
-       {0x0000b1f8, 0x00000396},
-       {0x0000b1fc, 0x00000196},
-};
-
-static const u32 ar9462_2p1_common_5g_xlna_only_rx_gain[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x00010000},
-       {0x0000a004, 0x00030002},
-       {0x0000a008, 0x00050004},
-       {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x00830082},
-       {0x0000a014, 0x01810180},
-       {0x0000a018, 0x01830182},
-       {0x0000a01c, 0x01850184},
-       {0x0000a020, 0x01890188},
-       {0x0000a024, 0x018b018a},
-       {0x0000a028, 0x018d018c},
-       {0x0000a02c, 0x03820190},
-       {0x0000a030, 0x03840383},
-       {0x0000a034, 0x03880385},
-       {0x0000a038, 0x038a0389},
-       {0x0000a03c, 0x038c038b},
-       {0x0000a040, 0x0390038d},
-       {0x0000a044, 0x03920391},
-       {0x0000a048, 0x03940393},
-       {0x0000a04c, 0x03960395},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x29292929},
-       {0x0000a084, 0x29292929},
-       {0x0000a088, 0x29292929},
-       {0x0000a08c, 0x29292929},
-       {0x0000a090, 0x22292929},
-       {0x0000a094, 0x1d1d2222},
-       {0x0000a098, 0x0c111117},
-       {0x0000a09c, 0x00030303},
-       {0x0000a0a0, 0x00000000},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x01000101},
-       {0x0000a0c8, 0x011e011f},
-       {0x0000a0cc, 0x011c011d},
-       {0x0000a0d0, 0x02030204},
-       {0x0000a0d4, 0x02010202},
-       {0x0000a0d8, 0x021f0200},
-       {0x0000a0dc, 0x0302021e},
-       {0x0000a0e0, 0x03000301},
-       {0x0000a0e4, 0x031e031f},
-       {0x0000a0e8, 0x0402031d},
-       {0x0000a0ec, 0x04000401},
-       {0x0000a0f0, 0x041e041f},
-       {0x0000a0f4, 0x0502041d},
-       {0x0000a0f8, 0x05000501},
-       {0x0000a0fc, 0x051e051f},
-       {0x0000a100, 0x06010602},
-       {0x0000a104, 0x061f0600},
-       {0x0000a108, 0x061d061e},
-       {0x0000a10c, 0x07020703},
-       {0x0000a110, 0x07000701},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x01000101},
-       {0x0000a148, 0x011e011f},
-       {0x0000a14c, 0x011c011d},
-       {0x0000a150, 0x02030204},
-       {0x0000a154, 0x02010202},
-       {0x0000a158, 0x021f0200},
-       {0x0000a15c, 0x0302021e},
-       {0x0000a160, 0x03000301},
-       {0x0000a164, 0x031e031f},
-       {0x0000a168, 0x0402031d},
-       {0x0000a16c, 0x04000401},
-       {0x0000a170, 0x041e041f},
-       {0x0000a174, 0x0502041d},
-       {0x0000a178, 0x05000501},
-       {0x0000a17c, 0x051e051f},
-       {0x0000a180, 0x06010602},
-       {0x0000a184, 0x061f0600},
-       {0x0000a188, 0x061d061e},
-       {0x0000a18c, 0x07020703},
-       {0x0000a190, 0x07000701},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000196},
-       {0x0000b000, 0x00010000},
-       {0x0000b004, 0x00030002},
-       {0x0000b008, 0x00050004},
-       {0x0000b00c, 0x00810080},
-       {0x0000b010, 0x00830082},
-       {0x0000b014, 0x01810180},
-       {0x0000b018, 0x01830182},
-       {0x0000b01c, 0x01850184},
-       {0x0000b020, 0x02810280},
-       {0x0000b024, 0x02830282},
-       {0x0000b028, 0x02850284},
-       {0x0000b02c, 0x02890288},
-       {0x0000b030, 0x028b028a},
-       {0x0000b034, 0x0388028c},
-       {0x0000b038, 0x038a0389},
-       {0x0000b03c, 0x038c038b},
-       {0x0000b040, 0x0390038d},
-       {0x0000b044, 0x03920391},
-       {0x0000b048, 0x03940393},
-       {0x0000b04c, 0x03960395},
-       {0x0000b050, 0x00000000},
-       {0x0000b054, 0x00000000},
-       {0x0000b058, 0x00000000},
-       {0x0000b05c, 0x00000000},
-       {0x0000b060, 0x00000000},
-       {0x0000b064, 0x00000000},
-       {0x0000b068, 0x00000000},
-       {0x0000b06c, 0x00000000},
-       {0x0000b070, 0x00000000},
-       {0x0000b074, 0x00000000},
-       {0x0000b078, 0x00000000},
-       {0x0000b07c, 0x00000000},
-       {0x0000b080, 0x2a2d2f32},
-       {0x0000b084, 0x21232328},
-       {0x0000b088, 0x19191c1e},
-       {0x0000b08c, 0x12141417},
-       {0x0000b090, 0x07070e0e},
-       {0x0000b094, 0x03030305},
-       {0x0000b098, 0x00000003},
-       {0x0000b09c, 0x00000000},
-       {0x0000b0a0, 0x00000000},
-       {0x0000b0a4, 0x00000000},
-       {0x0000b0a8, 0x00000000},
-       {0x0000b0ac, 0x00000000},
-       {0x0000b0b0, 0x00000000},
-       {0x0000b0b4, 0x00000000},
-       {0x0000b0b8, 0x00000000},
-       {0x0000b0bc, 0x00000000},
-       {0x0000b0c0, 0x003f0020},
-       {0x0000b0c4, 0x00400041},
-       {0x0000b0c8, 0x0140005f},
-       {0x0000b0cc, 0x0160015f},
-       {0x0000b0d0, 0x017e017f},
-       {0x0000b0d4, 0x02410242},
-       {0x0000b0d8, 0x025f0240},
-       {0x0000b0dc, 0x027f0260},
-       {0x0000b0e0, 0x0341027e},
-       {0x0000b0e4, 0x035f0340},
-       {0x0000b0e8, 0x037f0360},
-       {0x0000b0ec, 0x04400441},
-       {0x0000b0f0, 0x0460045f},
-       {0x0000b0f4, 0x0541047f},
-       {0x0000b0f8, 0x055f0540},
-       {0x0000b0fc, 0x057f0560},
-       {0x0000b100, 0x06400641},
-       {0x0000b104, 0x0660065f},
-       {0x0000b108, 0x067e067f},
-       {0x0000b10c, 0x07410742},
-       {0x0000b110, 0x075f0740},
-       {0x0000b114, 0x077f0760},
-       {0x0000b118, 0x07800781},
-       {0x0000b11c, 0x07a0079f},
-       {0x0000b120, 0x07c107bf},
-       {0x0000b124, 0x000007c0},
-       {0x0000b128, 0x00000000},
-       {0x0000b12c, 0x00000000},
-       {0x0000b130, 0x00000000},
-       {0x0000b134, 0x00000000},
-       {0x0000b138, 0x00000000},
-       {0x0000b13c, 0x00000000},
-       {0x0000b140, 0x003f0020},
-       {0x0000b144, 0x00400041},
-       {0x0000b148, 0x0140005f},
-       {0x0000b14c, 0x0160015f},
-       {0x0000b150, 0x017e017f},
-       {0x0000b154, 0x02410242},
-       {0x0000b158, 0x025f0240},
-       {0x0000b15c, 0x027f0260},
-       {0x0000b160, 0x0341027e},
-       {0x0000b164, 0x035f0340},
-       {0x0000b168, 0x037f0360},
-       {0x0000b16c, 0x04400441},
-       {0x0000b170, 0x0460045f},
-       {0x0000b174, 0x0541047f},
-       {0x0000b178, 0x055f0540},
-       {0x0000b17c, 0x057f0560},
-       {0x0000b180, 0x06400641},
-       {0x0000b184, 0x0660065f},
-       {0x0000b188, 0x067e067f},
-       {0x0000b18c, 0x07410742},
-       {0x0000b190, 0x075f0740},
-       {0x0000b194, 0x077f0760},
-       {0x0000b198, 0x07800781},
-       {0x0000b19c, 0x07a0079f},
-       {0x0000b1a0, 0x07c107bf},
-       {0x0000b1a4, 0x000007c0},
-       {0x0000b1a8, 0x00000000},
-       {0x0000b1ac, 0x00000000},
-       {0x0000b1b0, 0x00000000},
-       {0x0000b1b4, 0x00000000},
-       {0x0000b1b8, 0x00000000},
-       {0x0000b1bc, 0x00000000},
-       {0x0000b1c0, 0x00000000},
-       {0x0000b1c4, 0x00000000},
-       {0x0000b1c8, 0x00000000},
-       {0x0000b1cc, 0x00000000},
-       {0x0000b1d0, 0x00000000},
-       {0x0000b1d4, 0x00000000},
-       {0x0000b1d8, 0x00000000},
-       {0x0000b1dc, 0x00000000},
-       {0x0000b1e0, 0x00000000},
-       {0x0000b1e4, 0x00000000},
-       {0x0000b1e8, 0x00000000},
-       {0x0000b1ec, 0x00000000},
-       {0x0000b1f0, 0x00000396},
-       {0x0000b1f4, 0x00000396},
-       {0x0000b1f8, 0x00000396},
-       {0x0000b1fc, 0x00000196},
-};
-
-static const u32 ar9462_2p1_modes_low_ob_db_tx_gain[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
-       {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-       {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-       {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
-       {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
-       {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
-       {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
-       {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
-       {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404},
-       {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
-       {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
-       {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
-       {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
-       {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
-       {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
-       {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
-       {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
-       {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
-       {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
-       {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
-       {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
-       {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
-       {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
-       {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
-       {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
-       {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
-       {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
-       {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
-       {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
-       {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
-       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
-       {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
-       {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
-       {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-       {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-       {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-       {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-       {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-       {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-       {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x00016044, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4},
-       {0x00016048, 0x64992060, 0x64992060, 0x64992060, 0x64992060},
-       {0x00016054, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000},
-       {0x00016444, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4},
-       {0x00016448, 0x64992000, 0x64992000, 0x64992000, 0x64992000},
-       {0x00016454, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000},
-};
-
-static const u32 ar9462_2p1_modes_high_ob_db_tx_gain[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
-       {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-       {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-       {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x0000a410, 0x000050da, 0x000050da, 0x000050de, 0x000050de},
-       {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-       {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
-       {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
-       {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
-       {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
-       {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
-       {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
-       {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
-       {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
-       {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
-       {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
-       {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
-       {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
-       {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
-       {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
-       {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
-       {0x0000a548, 0x55025eb3, 0x55025eb3, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x58025ef3, 0x58025ef3, 0x42001a83, 0x42001a83},
-       {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001a84, 0x44001a84},
-       {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
-       {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
-       {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
-       {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
-       {0x0000a564, 0x751ffff6, 0x751ffff6, 0x56001eec, 0x56001eec},
-       {0x0000a568, 0x751ffff6, 0x751ffff6, 0x58001ef0, 0x58001ef0},
-       {0x0000a56c, 0x751ffff6, 0x751ffff6, 0x5a001ef4, 0x5a001ef4},
-       {0x0000a570, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
-       {0x0000a574, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
-       {0x0000a578, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
-       {0x0000a57c, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
-       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
-       {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
-       {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
-       {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
-       {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
-       {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
-       {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
-       {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-       {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-       {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x00016044, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4},
-       {0x00016048, 0x8db49060, 0x8db49060, 0x8db49060, 0x8db49060},
-       {0x00016054, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000},
-       {0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4},
-       {0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000},
-       {0x00016454, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000},
-};
-
-static const u32 ar9462_2p1_modes_mix_ob_db_tx_gain[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
-       {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-       {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-       {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x0000a410, 0x0000d0da, 0x0000d0da, 0x0000d0de, 0x0000d0de},
-       {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-       {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
-       {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
-       {0x0000a514, 0x18022622, 0x18022622, 0x12000400, 0x12000400},
-       {0x0000a518, 0x1b022822, 0x1b022822, 0x16000402, 0x16000402},
-       {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
-       {0x0000a520, 0x22022c41, 0x22022c41, 0x1c000603, 0x1c000603},
-       {0x0000a524, 0x28023042, 0x28023042, 0x21000a02, 0x21000a02},
-       {0x0000a528, 0x2c023044, 0x2c023044, 0x25000a04, 0x25000a04},
-       {0x0000a52c, 0x2f023644, 0x2f023644, 0x28000a20, 0x28000a20},
-       {0x0000a530, 0x34025643, 0x34025643, 0x2c000e20, 0x2c000e20},
-       {0x0000a534, 0x38025a44, 0x38025a44, 0x30000e22, 0x30000e22},
-       {0x0000a538, 0x3b025e45, 0x3b025e45, 0x34000e24, 0x34000e24},
-       {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x38001640, 0x38001640},
-       {0x0000a540, 0x48025e6c, 0x48025e6c, 0x3c001660, 0x3c001660},
-       {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3f001861, 0x3f001861},
-       {0x0000a548, 0x55025eb3, 0x55025eb3, 0x43001a81, 0x43001a81},
-       {0x0000a54c, 0x58025ef3, 0x58025ef3, 0x47001a83, 0x47001a83},
-       {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x4a001c84, 0x4a001c84},
-       {0x0000a554, 0x62025f56, 0x62025f56, 0x4e001ce3, 0x4e001ce3},
-       {0x0000a558, 0x66027f56, 0x66027f56, 0x52001ce5, 0x52001ce5},
-       {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x56001ce9, 0x56001ce9},
-       {0x0000a560, 0x70049f56, 0x70049f56, 0x5a001ceb, 0x5a001ceb},
-       {0x0000a564, 0x751ffff6, 0x751ffff6, 0x5c001eec, 0x5c001eec},
-       {0x0000a568, 0x751ffff6, 0x751ffff6, 0x5e001ef0, 0x5e001ef0},
-       {0x0000a56c, 0x751ffff6, 0x751ffff6, 0x60001ef4, 0x60001ef4},
-       {0x0000a570, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6},
-       {0x0000a574, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6},
-       {0x0000a578, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6},
-       {0x0000a57c, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6},
-       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
-       {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
-       {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
-       {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
-       {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
-       {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
-       {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
-       {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-       {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-       {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-};
-
-static const u32 ar9462_2p1_modes_fast_clock[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
-       {0x00001030, 0x00000268, 0x000004d0},
-       {0x00001070, 0x0000018c, 0x00000318},
-       {0x000010b0, 0x00000fd0, 0x00001fa0},
-       {0x00008014, 0x044c044c, 0x08980898},
-       {0x0000801c, 0x148ec02b, 0x148ec057},
-       {0x00008318, 0x000044c0, 0x00008980},
-       {0x00009e00, 0x0372131c, 0x0372131c},
-       {0x0000a230, 0x0000400b, 0x00004016},
-       {0x0000a254, 0x00000898, 0x00001130},
-};
-
-static const u32 ar9462_2p1_baseband_core_txfir_coeff_japan_2484[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a398, 0x00000000},
-       {0x0000a39c, 0x6f7f0301},
-       {0x0000a3a0, 0xca9228ee},
-};
-
 #endif /* INITVALS_9462_2P1_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9565_1p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9565_1p1_initvals.h
new file mode 100644 (file)
index 0000000..5681053
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INITVALS_9565_1P1_H
+#define INITVALS_9565_1P1_H
+
+/* AR9565 1.1 */
+
+#define ar9565_1p1_mac_core ar9565_1p0_mac_core
+
+#define ar9565_1p1_mac_postamble ar9565_1p0_mac_postamble
+
+#define ar9565_1p1_baseband_core ar9565_1p0_baseband_core
+
+#define ar9565_1p1_baseband_postamble ar9565_1p0_baseband_postamble
+
+#define ar9565_1p1_radio_core ar9565_1p0_radio_core
+
+#define ar9565_1p1_soc_preamble ar9565_1p0_soc_preamble
+
+#define ar9565_1p1_soc_postamble ar9565_1p0_soc_postamble
+
+#define ar9565_1p1_Common_rx_gain_table ar9565_1p0_Common_rx_gain_table
+
+#define ar9565_1p1_Modes_lowest_ob_db_tx_gain_table ar9565_1p0_Modes_lowest_ob_db_tx_gain_table
+
+#define ar9565_1p1_pciephy_clkreq_disable_L1 ar9565_1p0_pciephy_clkreq_disable_L1
+
+#define ar9565_1p1_modes_fast_clock ar9565_1p0_modes_fast_clock
+
+#define ar9565_1p1_common_wo_xlna_rx_gain_table ar9565_1p0_common_wo_xlna_rx_gain_table
+
+#define ar9565_1p1_modes_low_ob_db_tx_gain_table ar9565_1p0_modes_low_ob_db_tx_gain_table
+
+#define ar9565_1p1_modes_high_ob_db_tx_gain_table ar9565_1p0_modes_high_ob_db_tx_gain_table
+
+#define ar9565_1p1_modes_high_power_tx_gain_table ar9565_1p0_modes_high_power_tx_gain_table
+
+#define ar9565_1p1_baseband_core_txfir_coeff_japan_2484 ar9565_1p0_baseband_core_txfir_coeff_japan_2484
+
+static const u32 ar9565_1p1_radio_postamble[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524},
+       {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
+       {0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70},
+       {0x0001610c, 0x40000000, 0x40000000, 0x40000000, 0x40000000},
+       {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+};
+
+#endif /* INITVALS_9565_1P1_H */
index bdee2ed67219b6e1c56a0f03a6a28391ba3283aa..75bef1179d0d674f857b61f455f1ba045a44e35a 100644 (file)
 
 /* AR9580 1.0 */
 
+#define ar9580_1p0_soc_preamble ar9300_2p2_soc_preamble
+
+#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble
+
+#define ar9580_1p0_radio_core ar9300_2p2_radio_core
+
+#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble
+
+#define ar9580_1p0_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2
+
+#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2
+
+#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2
+
 #define ar9580_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2
 
+#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484
+
 static const u32 ar9580_1p0_radio_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31},
        {0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800},
        {0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20},
-       {0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0001610c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000},
        {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
-       {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0001650c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000},
        {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
-       {0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0001690c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000},
        {0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
 };
 
@@ -44,9 +60,9 @@ static const u32 ar9580_1p0_baseband_core[][2] = {
        {0x00009814, 0x3280c00a},
        {0x00009818, 0x00000000},
        {0x0000981c, 0x00020028},
-       {0x00009834, 0x6400a290},
+       {0x00009834, 0x6400a190},
        {0x00009838, 0x0108ecff},
-       {0x0000983c, 0x0d000600},
+       {0x0000983c, 0x14000600},
        {0x00009880, 0x201fff00},
        {0x00009884, 0x00001042},
        {0x000098a4, 0x00200400},
@@ -67,7 +83,7 @@ static const u32 ar9580_1p0_baseband_core[][2] = {
        {0x00009d04, 0x40206c10},
        {0x00009d08, 0x009c4060},
        {0x00009d0c, 0x9883800a},
-       {0x00009d10, 0x01834061},
+       {0x00009d10, 0x01884061},
        {0x00009d14, 0x00c0040b},
        {0x00009d18, 0x00000000},
        {0x00009e08, 0x0038230c},
@@ -198,8 +214,6 @@ static const u32 ar9580_1p0_baseband_core[][2] = {
        {0x0000c420, 0x00000000},
 };
 
-#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble
-
 static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
@@ -306,7 +320,112 @@ static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = {
        {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
-#define ar9580_1p0_high_power_tx_gain_table ar9580_1p0_low_ob_db_tx_gain_table
+static const u32 ar9580_1p0_high_power_tx_gain_table[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+       {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+       {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+       {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+       {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+       {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
+       {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
+       {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
+       {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
+       {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
+       {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
+       {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
+       {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
+       {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
+       {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
+       {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
+       {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
+       {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
+       {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
+       {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
+       {0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83},
+       {0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84},
+       {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
+       {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
+       {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
+       {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
+       {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+       {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+       {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+       {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+       {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+       {0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202},
+       {0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400},
+       {0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402},
+       {0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404},
+       {0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603},
+       {0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02},
+       {0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04},
+       {0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20},
+       {0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20},
+       {0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22},
+       {0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24},
+       {0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640},
+       {0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660},
+       {0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861},
+       {0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81},
+       {0x0000a5cc, 0x5a88442e, 0x5a88442e, 0x47801a83, 0x47801a83},
+       {0x0000a5d0, 0x5e8a4431, 0x5e8a4431, 0x4a801c84, 0x4a801c84},
+       {0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3},
+       {0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5},
+       {0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9},
+       {0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb},
+       {0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+       {0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+       {0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+       {0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+       {0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+       {0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+       {0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+       {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+       {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+       {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
+       {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
+       {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
+       {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
+       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+       {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
+       {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+       {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+       {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+       {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+       {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+       {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+       {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016048, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
+       {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016288, 0x05a2040a, 0x05a2040a, 0x05a20408, 0x05a20408},
+       {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016448, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
+       {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016848, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
+       {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
 
 static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
@@ -414,8 +533,6 @@ static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = {
        {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
-#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484
-
 static const u32 ar9580_1p0_mac_core[][2] = {
        /* Addr      allmodes  */
        {0x00000008, 0x00000000},
@@ -679,14 +796,6 @@ static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][5] = {
        {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
-#define ar9580_1p0_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2
-
-#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble
-
-#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2
-
-#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2
-
 static const u32 ar9580_1p0_type6_tx_gain_table[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
@@ -761,160 +870,264 @@ static const u32 ar9580_1p0_type6_tx_gain_table[][5] = {
        {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
-static const u32 ar9580_1p0_soc_preamble[][2] = {
-       /* Addr      allmodes  */
-       {0x000040a4, 0x00a0c1c9},
-       {0x00007008, 0x00000000},
-       {0x00007020, 0x00000000},
-       {0x00007034, 0x00000002},
-       {0x00007038, 0x000004c2},
-       {0x00007048, 0x00000008},
-};
-
-#define ar9580_1p0_rx_gain_table ar9462_common_rx_gain_table_2p0
-
-static const u32 ar9580_1p0_radio_core[][2] = {
+static const u32 ar9580_1p0_rx_gain_table[][2] = {
        /* Addr      allmodes  */
-       {0x00016000, 0x36db6db6},
-       {0x00016004, 0x6db6db40},
-       {0x00016008, 0x73f00000},
-       {0x0001600c, 0x00000000},
-       {0x00016040, 0x7f80fff8},
-       {0x0001604c, 0x76d005b5},
-       {0x00016050, 0x556cf031},
-       {0x00016054, 0x13449440},
-       {0x00016058, 0x0c51c92c},
-       {0x0001605c, 0x3db7fffc},
-       {0x00016060, 0xfffffffc},
-       {0x00016064, 0x000f0278},
-       {0x0001606c, 0x6db60000},
-       {0x00016080, 0x00000000},
-       {0x00016084, 0x0e48048c},
-       {0x00016088, 0x54214514},
-       {0x0001608c, 0x119f481e},
-       {0x00016090, 0x24926490},
-       {0x00016098, 0xd2888888},
-       {0x000160a0, 0x0a108ffe},
-       {0x000160a4, 0x812fc370},
-       {0x000160a8, 0x423c8000},
-       {0x000160b4, 0x92480080},
-       {0x000160c0, 0x00adb6d0},
-       {0x000160c4, 0x6db6db60},
-       {0x000160c8, 0x6db6db6c},
-       {0x000160cc, 0x01e6c000},
-       {0x00016100, 0x3fffbe01},
-       {0x00016104, 0xfff80000},
-       {0x00016108, 0x00080010},
-       {0x00016144, 0x02084080},
-       {0x00016148, 0x00000000},
-       {0x00016280, 0x058a0001},
-       {0x00016284, 0x3d840208},
-       {0x00016288, 0x05a20408},
-       {0x0001628c, 0x00038c07},
-       {0x00016290, 0x00000004},
-       {0x00016294, 0x458aa14f},
-       {0x00016380, 0x00000000},
-       {0x00016384, 0x00000000},
-       {0x00016388, 0x00800700},
-       {0x0001638c, 0x00800700},
-       {0x00016390, 0x00800700},
-       {0x00016394, 0x00000000},
-       {0x00016398, 0x00000000},
-       {0x0001639c, 0x00000000},
-       {0x000163a0, 0x00000001},
-       {0x000163a4, 0x00000001},
-       {0x000163a8, 0x00000000},
-       {0x000163ac, 0x00000000},
-       {0x000163b0, 0x00000000},
-       {0x000163b4, 0x00000000},
-       {0x000163b8, 0x00000000},
-       {0x000163bc, 0x00000000},
-       {0x000163c0, 0x000000a0},
-       {0x000163c4, 0x000c0000},
-       {0x000163c8, 0x14021402},
-       {0x000163cc, 0x00001402},
-       {0x000163d0, 0x00000000},
-       {0x000163d4, 0x00000000},
-       {0x00016400, 0x36db6db6},
-       {0x00016404, 0x6db6db40},
-       {0x00016408, 0x73f00000},
-       {0x0001640c, 0x00000000},
-       {0x00016440, 0x7f80fff8},
-       {0x0001644c, 0x76d005b5},
-       {0x00016450, 0x556cf031},
-       {0x00016454, 0x13449440},
-       {0x00016458, 0x0c51c92c},
-       {0x0001645c, 0x3db7fffc},
-       {0x00016460, 0xfffffffc},
-       {0x00016464, 0x000f0278},
-       {0x0001646c, 0x6db60000},
-       {0x00016500, 0x3fffbe01},
-       {0x00016504, 0xfff80000},
-       {0x00016508, 0x00080010},
-       {0x00016544, 0x02084080},
-       {0x00016548, 0x00000000},
-       {0x00016780, 0x00000000},
-       {0x00016784, 0x00000000},
-       {0x00016788, 0x00800700},
-       {0x0001678c, 0x00800700},
-       {0x00016790, 0x00800700},
-       {0x00016794, 0x00000000},
-       {0x00016798, 0x00000000},
-       {0x0001679c, 0x00000000},
-       {0x000167a0, 0x00000001},
-       {0x000167a4, 0x00000001},
-       {0x000167a8, 0x00000000},
-       {0x000167ac, 0x00000000},
-       {0x000167b0, 0x00000000},
-       {0x000167b4, 0x00000000},
-       {0x000167b8, 0x00000000},
-       {0x000167bc, 0x00000000},
-       {0x000167c0, 0x000000a0},
-       {0x000167c4, 0x000c0000},
-       {0x000167c8, 0x14021402},
-       {0x000167cc, 0x00001402},
-       {0x000167d0, 0x00000000},
-       {0x000167d4, 0x00000000},
-       {0x00016800, 0x36db6db6},
-       {0x00016804, 0x6db6db40},
-       {0x00016808, 0x73f00000},
-       {0x0001680c, 0x00000000},
-       {0x00016840, 0x7f80fff8},
-       {0x0001684c, 0x76d005b5},
-       {0x00016850, 0x556cf031},
-       {0x00016854, 0x13449440},
-       {0x00016858, 0x0c51c92c},
-       {0x0001685c, 0x3db7fffc},
-       {0x00016860, 0xfffffffc},
-       {0x00016864, 0x000f0278},
-       {0x0001686c, 0x6db60000},
-       {0x00016900, 0x3fffbe01},
-       {0x00016904, 0xfff80000},
-       {0x00016908, 0x00080010},
-       {0x00016944, 0x02084080},
-       {0x00016948, 0x00000000},
-       {0x00016b80, 0x00000000},
-       {0x00016b84, 0x00000000},
-       {0x00016b88, 0x00800700},
-       {0x00016b8c, 0x00800700},
-       {0x00016b90, 0x00800700},
-       {0x00016b94, 0x00000000},
-       {0x00016b98, 0x00000000},
-       {0x00016b9c, 0x00000000},
-       {0x00016ba0, 0x00000001},
-       {0x00016ba4, 0x00000001},
-       {0x00016ba8, 0x00000000},
-       {0x00016bac, 0x00000000},
-       {0x00016bb0, 0x00000000},
-       {0x00016bb4, 0x00000000},
-       {0x00016bb8, 0x00000000},
-       {0x00016bbc, 0x00000000},
-       {0x00016bc0, 0x000000a0},
-       {0x00016bc4, 0x000c0000},
-       {0x00016bc8, 0x14021402},
-       {0x00016bcc, 0x00001402},
-       {0x00016bd0, 0x00000000},
-       {0x00016bd4, 0x00000000},
+       {0x0000a000, 0x00010000},
+       {0x0000a004, 0x00030002},
+       {0x0000a008, 0x00050004},
+       {0x0000a00c, 0x00810080},
+       {0x0000a010, 0x00830082},
+       {0x0000a014, 0x01810180},
+       {0x0000a018, 0x01830182},
+       {0x0000a01c, 0x01850184},
+       {0x0000a020, 0x01890188},
+       {0x0000a024, 0x018b018a},
+       {0x0000a028, 0x018d018c},
+       {0x0000a02c, 0x01910190},
+       {0x0000a030, 0x01930192},
+       {0x0000a034, 0x01950194},
+       {0x0000a038, 0x038a0196},
+       {0x0000a03c, 0x038c038b},
+       {0x0000a040, 0x0390038d},
+       {0x0000a044, 0x03920391},
+       {0x0000a048, 0x03940393},
+       {0x0000a04c, 0x03960395},
+       {0x0000a050, 0x00000000},
+       {0x0000a054, 0x00000000},
+       {0x0000a058, 0x00000000},
+       {0x0000a05c, 0x00000000},
+       {0x0000a060, 0x00000000},
+       {0x0000a064, 0x00000000},
+       {0x0000a068, 0x00000000},
+       {0x0000a06c, 0x00000000},
+       {0x0000a070, 0x00000000},
+       {0x0000a074, 0x00000000},
+       {0x0000a078, 0x00000000},
+       {0x0000a07c, 0x00000000},
+       {0x0000a080, 0x22222229},
+       {0x0000a084, 0x1d1d1d1d},
+       {0x0000a088, 0x1d1d1d1d},
+       {0x0000a08c, 0x1d1d1d1d},
+       {0x0000a090, 0x171d1d1d},
+       {0x0000a094, 0x11111717},
+       {0x0000a098, 0x00030311},
+       {0x0000a09c, 0x00000000},
+       {0x0000a0a0, 0x00000000},
+       {0x0000a0a4, 0x00000000},
+       {0x0000a0a8, 0x00000000},
+       {0x0000a0ac, 0x00000000},
+       {0x0000a0b0, 0x00000000},
+       {0x0000a0b4, 0x00000000},
+       {0x0000a0b8, 0x00000000},
+       {0x0000a0bc, 0x00000000},
+       {0x0000a0c0, 0x001f0000},
+       {0x0000a0c4, 0x01000101},
+       {0x0000a0c8, 0x011e011f},
+       {0x0000a0cc, 0x011c011d},
+       {0x0000a0d0, 0x02030204},
+       {0x0000a0d4, 0x02010202},
+       {0x0000a0d8, 0x021f0200},
+       {0x0000a0dc, 0x0302021e},
+       {0x0000a0e0, 0x03000301},
+       {0x0000a0e4, 0x031e031f},
+       {0x0000a0e8, 0x0402031d},
+       {0x0000a0ec, 0x04000401},
+       {0x0000a0f0, 0x041e041f},
+       {0x0000a0f4, 0x0502041d},
+       {0x0000a0f8, 0x05000501},
+       {0x0000a0fc, 0x051e051f},
+       {0x0000a100, 0x06010602},
+       {0x0000a104, 0x061f0600},
+       {0x0000a108, 0x061d061e},
+       {0x0000a10c, 0x07020703},
+       {0x0000a110, 0x07000701},
+       {0x0000a114, 0x00000000},
+       {0x0000a118, 0x00000000},
+       {0x0000a11c, 0x00000000},
+       {0x0000a120, 0x00000000},
+       {0x0000a124, 0x00000000},
+       {0x0000a128, 0x00000000},
+       {0x0000a12c, 0x00000000},
+       {0x0000a130, 0x00000000},
+       {0x0000a134, 0x00000000},
+       {0x0000a138, 0x00000000},
+       {0x0000a13c, 0x00000000},
+       {0x0000a140, 0x001f0000},
+       {0x0000a144, 0x01000101},
+       {0x0000a148, 0x011e011f},
+       {0x0000a14c, 0x011c011d},
+       {0x0000a150, 0x02030204},
+       {0x0000a154, 0x02010202},
+       {0x0000a158, 0x021f0200},
+       {0x0000a15c, 0x0302021e},
+       {0x0000a160, 0x03000301},
+       {0x0000a164, 0x031e031f},
+       {0x0000a168, 0x0402031d},
+       {0x0000a16c, 0x04000401},
+       {0x0000a170, 0x041e041f},
+       {0x0000a174, 0x0502041d},
+       {0x0000a178, 0x05000501},
+       {0x0000a17c, 0x051e051f},
+       {0x0000a180, 0x06010602},
+       {0x0000a184, 0x061f0600},
+       {0x0000a188, 0x061d061e},
+       {0x0000a18c, 0x07020703},
+       {0x0000a190, 0x07000701},
+       {0x0000a194, 0x00000000},
+       {0x0000a198, 0x00000000},
+       {0x0000a19c, 0x00000000},
+       {0x0000a1a0, 0x00000000},
+       {0x0000a1a4, 0x00000000},
+       {0x0000a1a8, 0x00000000},
+       {0x0000a1ac, 0x00000000},
+       {0x0000a1b0, 0x00000000},
+       {0x0000a1b4, 0x00000000},
+       {0x0000a1b8, 0x00000000},
+       {0x0000a1bc, 0x00000000},
+       {0x0000a1c0, 0x00000000},
+       {0x0000a1c4, 0x00000000},
+       {0x0000a1c8, 0x00000000},
+       {0x0000a1cc, 0x00000000},
+       {0x0000a1d0, 0x00000000},
+       {0x0000a1d4, 0x00000000},
+       {0x0000a1d8, 0x00000000},
+       {0x0000a1dc, 0x00000000},
+       {0x0000a1e0, 0x00000000},
+       {0x0000a1e4, 0x00000000},
+       {0x0000a1e8, 0x00000000},
+       {0x0000a1ec, 0x00000000},
+       {0x0000a1f0, 0x00000396},
+       {0x0000a1f4, 0x00000396},
+       {0x0000a1f8, 0x00000396},
+       {0x0000a1fc, 0x00000196},
+       {0x0000b000, 0x00010000},
+       {0x0000b004, 0x00030002},
+       {0x0000b008, 0x00050004},
+       {0x0000b00c, 0x00810080},
+       {0x0000b010, 0x00830082},
+       {0x0000b014, 0x01810180},
+       {0x0000b018, 0x01830182},
+       {0x0000b01c, 0x01850184},
+       {0x0000b020, 0x02810280},
+       {0x0000b024, 0x02830282},
+       {0x0000b028, 0x02850284},
+       {0x0000b02c, 0x02890288},
+       {0x0000b030, 0x028b028a},
+       {0x0000b034, 0x0388028c},
+       {0x0000b038, 0x038a0389},
+       {0x0000b03c, 0x038c038b},
+       {0x0000b040, 0x0390038d},
+       {0x0000b044, 0x03920391},
+       {0x0000b048, 0x03940393},
+       {0x0000b04c, 0x03960395},
+       {0x0000b050, 0x00000000},
+       {0x0000b054, 0x00000000},
+       {0x0000b058, 0x00000000},
+       {0x0000b05c, 0x00000000},
+       {0x0000b060, 0x00000000},
+       {0x0000b064, 0x00000000},
+       {0x0000b068, 0x00000000},
+       {0x0000b06c, 0x00000000},
+       {0x0000b070, 0x00000000},
+       {0x0000b074, 0x00000000},
+       {0x0000b078, 0x00000000},
+       {0x0000b07c, 0x00000000},
+       {0x0000b080, 0x23232323},
+       {0x0000b084, 0x21232323},
+       {0x0000b088, 0x19191c1e},
+       {0x0000b08c, 0x12141417},
+       {0x0000b090, 0x07070e0e},
+       {0x0000b094, 0x03030305},
+       {0x0000b098, 0x00000003},
+       {0x0000b09c, 0x00000000},
+       {0x0000b0a0, 0x00000000},
+       {0x0000b0a4, 0x00000000},
+       {0x0000b0a8, 0x00000000},
+       {0x0000b0ac, 0x00000000},
+       {0x0000b0b0, 0x00000000},
+       {0x0000b0b4, 0x00000000},
+       {0x0000b0b8, 0x00000000},
+       {0x0000b0bc, 0x00000000},
+       {0x0000b0c0, 0x003f0020},
+       {0x0000b0c4, 0x00400041},
+       {0x0000b0c8, 0x0140005f},
+       {0x0000b0cc, 0x0160015f},
+       {0x0000b0d0, 0x017e017f},
+       {0x0000b0d4, 0x02410242},
+       {0x0000b0d8, 0x025f0240},
+       {0x0000b0dc, 0x027f0260},
+       {0x0000b0e0, 0x0341027e},
+       {0x0000b0e4, 0x035f0340},
+       {0x0000b0e8, 0x037f0360},
+       {0x0000b0ec, 0x04400441},
+       {0x0000b0f0, 0x0460045f},
+       {0x0000b0f4, 0x0541047f},
+       {0x0000b0f8, 0x055f0540},
+       {0x0000b0fc, 0x057f0560},
+       {0x0000b100, 0x06400641},
+       {0x0000b104, 0x0660065f},
+       {0x0000b108, 0x067e067f},
+       {0x0000b10c, 0x07410742},
+       {0x0000b110, 0x075f0740},
+       {0x0000b114, 0x077f0760},
+       {0x0000b118, 0x07800781},
+       {0x0000b11c, 0x07a0079f},
+       {0x0000b120, 0x07c107bf},
+       {0x0000b124, 0x000007c0},
+       {0x0000b128, 0x00000000},
+       {0x0000b12c, 0x00000000},
+       {0x0000b130, 0x00000000},
+       {0x0000b134, 0x00000000},
+       {0x0000b138, 0x00000000},
+       {0x0000b13c, 0x00000000},
+       {0x0000b140, 0x003f0020},
+       {0x0000b144, 0x00400041},
+       {0x0000b148, 0x0140005f},
+       {0x0000b14c, 0x0160015f},
+       {0x0000b150, 0x017e017f},
+       {0x0000b154, 0x02410242},
+       {0x0000b158, 0x025f0240},
+       {0x0000b15c, 0x027f0260},
+       {0x0000b160, 0x0341027e},
+       {0x0000b164, 0x035f0340},
+       {0x0000b168, 0x037f0360},
+       {0x0000b16c, 0x04400441},
+       {0x0000b170, 0x0460045f},
+       {0x0000b174, 0x0541047f},
+       {0x0000b178, 0x055f0540},
+       {0x0000b17c, 0x057f0560},
+       {0x0000b180, 0x06400641},
+       {0x0000b184, 0x0660065f},
+       {0x0000b188, 0x067e067f},
+       {0x0000b18c, 0x07410742},
+       {0x0000b190, 0x075f0740},
+       {0x0000b194, 0x077f0760},
+       {0x0000b198, 0x07800781},
+       {0x0000b19c, 0x07a0079f},
+       {0x0000b1a0, 0x07c107bf},
+       {0x0000b1a4, 0x000007c0},
+       {0x0000b1a8, 0x00000000},
+       {0x0000b1ac, 0x00000000},
+       {0x0000b1b0, 0x00000000},
+       {0x0000b1b4, 0x00000000},
+       {0x0000b1b8, 0x00000000},
+       {0x0000b1bc, 0x00000000},
+       {0x0000b1c0, 0x00000000},
+       {0x0000b1c4, 0x00000000},
+       {0x0000b1c8, 0x00000000},
+       {0x0000b1cc, 0x00000000},
+       {0x0000b1d0, 0x00000000},
+       {0x0000b1d4, 0x00000000},
+       {0x0000b1d8, 0x00000000},
+       {0x0000b1dc, 0x00000000},
+       {0x0000b1e0, 0x00000000},
+       {0x0000b1e4, 0x00000000},
+       {0x0000b1e8, 0x00000000},
+       {0x0000b1ec, 0x00000000},
+       {0x0000b1f0, 0x00000396},
+       {0x0000b1f4, 0x00000396},
+       {0x0000b1f8, 0x00000396},
+       {0x0000b1fc, 0x00000196},
 };
 
 static const u32 ar9580_1p0_baseband_postamble[][5] = {
@@ -956,7 +1169,7 @@ static const u32 ar9580_1p0_baseband_postamble[][5] = {
        {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
        {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
        {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
-       {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
+       {0x0000a2d0, 0x00041983, 0x00041983, 0x00041981, 0x00041982},
        {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
        {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
index 60a5da53668f54f9987692ccf7389794d13ea851..5e5d5cb2458c0a9c492b8ea74aaf83bcc91a4568 100644 (file)
@@ -459,6 +459,7 @@ void ath_check_ani(struct ath_softc *sc);
 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);
 
 /**********/
 /* BTCOEX */
@@ -570,6 +571,34 @@ static inline void ath_fill_led_pin(struct ath_softc *sc)
 }
 #endif
 
+/************************/
+/* Wake on Wireless LAN */
+/************************/
+
+#ifdef CONFIG_ATH9K_WOW
+void ath9k_init_wow(struct ieee80211_hw *hw);
+int ath9k_suspend(struct ieee80211_hw *hw,
+                 struct cfg80211_wowlan *wowlan);
+int ath9k_resume(struct ieee80211_hw *hw);
+void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled);
+#else
+static inline void ath9k_init_wow(struct ieee80211_hw *hw)
+{
+}
+static inline int ath9k_suspend(struct ieee80211_hw *hw,
+                               struct cfg80211_wowlan *wowlan)
+{
+       return 0;
+}
+static inline int ath9k_resume(struct ieee80211_hw *hw)
+{
+       return 0;
+}
+static inline void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
+{
+}
+#endif /* CONFIG_ATH9K_WOW */
+
 /*******************************/
 /* Antenna diversity/combining */
 /*******************************/
@@ -642,6 +671,7 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
 #define ATH9K_PCI_AR9565_1ANT     0x0080
 #define ATH9K_PCI_AR9565_2ANT     0x0100
 #define ATH9K_PCI_NO_PLL_PWRSAVE  0x0200
+#define ATH9K_PCI_KILLER          0x0400
 
 /*
  * Default cache line size, in bytes.
@@ -724,6 +754,7 @@ struct ath_softc {
        struct work_struct hw_check_work;
        struct work_struct hw_reset_work;
        struct completion paprd_complete;
+       wait_queue_head_t tx_wait;
 
        unsigned int hw_busy_count;
        unsigned long sc_flags;
@@ -760,6 +791,7 @@ struct ath_softc {
        struct delayed_work tx_complete_work;
        struct delayed_work hw_pll_work;
        struct timer_list rx_poll_timer;
+       struct timer_list sleep_timer;
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
        struct ath_btcoex btcoex;
@@ -784,7 +816,7 @@ struct ath_softc {
        bool tx99_state;
        s16 tx99_power;
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ATH9K_WOW
        atomic_t wow_got_bmiss_intr;
        atomic_t wow_sleep_proc_intr; /* in the middle of WoW sleep ? */
        u32 wow_intr_before_sleep;
@@ -947,10 +979,25 @@ struct fft_sample_ht20_40 {
        u8 data[SPECTRAL_HT20_40_NUM_BINS];
 } __packed;
 
-int ath9k_tx99_init(struct ath_softc *sc);
-void ath9k_tx99_deinit(struct ath_softc *sc);
+/********/
+/* TX99 */
+/********/
+
+#ifdef CONFIG_ATH9K_TX99
+void ath9k_tx99_init_debug(struct ath_softc *sc);
 int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
                    struct ath_tx_control *txctl);
+#else
+static inline void ath9k_tx99_init_debug(struct ath_softc *sc)
+{
+}
+static inline int ath9k_tx99_send(struct ath_softc *sc,
+                                 struct sk_buff *skb,
+                                 struct ath_tx_control *txctl)
+{
+       return 0;
+}
+#endif /* CONFIG_ATH9K_TX99 */
 
 void ath9k_tasklet(unsigned long data);
 int ath_cabq_update(struct ath_softc *);
@@ -967,6 +1014,9 @@ extern bool is_ath9k_unloaded;
 
 u8 ath9k_parse_mpdudensity(u8 mpdudensity);
 irqreturn_t ath_isr(int irq, void *dev);
+int ath_reset(struct ath_softc *sc);
+void ath_cancel_work(struct ath_softc *sc);
+void ath_restart_work(struct ath_softc *sc);
 int ath9k_init_device(u16 devid, struct ath_softc *sc,
                    const struct ath_bus_ops *bus_ops);
 void ath9k_deinit_device(struct ath_softc *sc);
index 83a2c59f680b0445173d25cc5ebccc2f7eb5777e..2f7dccfdb72784bf5c098a72ed703cf3abc0f2a2 100644 (file)
@@ -1778,111 +1778,6 @@ void ath9k_deinit_debug(struct ath_softc *sc)
        }
 }
 
-static ssize_t read_file_tx99(struct file *file, char __user *user_buf,
-                             size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       char buf[3];
-       unsigned int len;
-
-       len = sprintf(buf, "%d\n", sc->tx99_state);
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,
-                              size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       char buf[32];
-       bool start;
-       ssize_t len;
-       int r;
-
-       if (sc->nvifs > 1)
-               return -EOPNOTSUPP;
-
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-
-       if (strtobool(buf, &start))
-               return -EINVAL;
-
-       if (start == sc->tx99_state) {
-               if (!start)
-                       return count;
-               ath_dbg(common, XMIT, "Resetting TX99\n");
-               ath9k_tx99_deinit(sc);
-       }
-
-       if (!start) {
-               ath9k_tx99_deinit(sc);
-               return count;
-       }
-
-       r = ath9k_tx99_init(sc);
-       if (r)
-               return r;
-
-       return count;
-}
-
-static const struct file_operations fops_tx99 = {
-       .read = read_file_tx99,
-       .write = write_file_tx99,
-       .open = simple_open,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
-};
-
-static ssize_t read_file_tx99_power(struct file *file,
-                                   char __user *user_buf,
-                                   size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       char buf[32];
-       unsigned int len;
-
-       len = sprintf(buf, "%d (%d dBm)\n",
-                     sc->tx99_power,
-                     sc->tx99_power / 2);
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static ssize_t write_file_tx99_power(struct file *file,
-                                    const char __user *user_buf,
-                                    size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       int r;
-       u8 tx_power;
-
-       r = kstrtou8_from_user(user_buf, count, 0, &tx_power);
-       if (r)
-               return r;
-
-       if (tx_power > MAX_RATE_POWER)
-               return -EINVAL;
-
-       sc->tx99_power = tx_power;
-
-       ath9k_ps_wakeup(sc);
-       ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power);
-       ath9k_ps_restore(sc);
-
-       return count;
-}
-
-static const struct file_operations fops_tx99_power = {
-       .read = read_file_tx99_power,
-       .write = write_file_tx99_power,
-       .open = simple_open,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
-};
-
 int ath9k_init_debug(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -1899,6 +1794,7 @@ int ath9k_init_debug(struct ath_hw *ah)
 #endif
 
        ath9k_dfs_init_debug(sc);
+       ath9k_tx99_init_debug(sc);
 
        debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_dma);
@@ -1974,15 +1870,6 @@ int ath9k_init_debug(struct ath_hw *ah)
        debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_btcoex);
 #endif
-       if (config_enabled(CONFIG_ATH9K_TX99) &&
-           AR_SREV_9300_20_OR_LATER(ah)) {
-               debugfs_create_file("tx99", S_IRUSR | S_IWUSR,
-                                   sc->debug.debugfs_phy, sc,
-                                   &fops_tx99);
-               debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR,
-                                   sc->debug.debugfs_phy, sc,
-                                   &fops_tx99_power);
-       }
 
        return 0;
 }
index 8918035da3a3510c04ad45e106cebd3d267ad6e8..779d38a98a0e82c4a2e64cf676afef01fcbd1d59 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/time.h>
 #include <asm/unaligned.h>
 
 #include "hw.h"
@@ -453,7 +454,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
        }
 
        ah->config.rx_intr_mitigation = true;
-       ah->config.pcieSerDesWrite = true;
 
        /*
         * We need this for PCI devices only (Cardbus, PCI, miniPCI)
@@ -1501,8 +1501,9 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
        int r;
 
        if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) {
-               band_switch = IS_CHAN_5GHZ(ah->curchan) != IS_CHAN_5GHZ(chan);
-               mode_diff = (chan->channelFlags != ah->curchan->channelFlags);
+               u32 flags_diff = chan->channelFlags ^ ah->curchan->channelFlags;
+               band_switch = !!(flags_diff & CHANNEL_5GHZ);
+               mode_diff = !!(flags_diff & ~CHANNEL_HT);
        }
 
        for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
@@ -1814,7 +1815,7 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
         * If cross-band fcc is not supoprted, bail out if channelFlags differ.
         */
        if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) &&
-           chan->channelFlags != ah->curchan->channelFlags)
+           ((chan->channelFlags ^ ah->curchan->channelFlags) & ~CHANNEL_HT))
                goto fail;
 
        if (!ath9k_hw_check_alive(ah))
@@ -1855,10 +1856,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                   struct ath9k_hw_cal_data *caldata, bool fastcc)
 {
        struct ath_common *common = ath9k_hw_common(ah);
+       struct timespec ts;
        u32 saveLedState;
        u32 saveDefAntenna;
        u32 macStaId1;
        u64 tsf = 0;
+       s64 usec = 0;
        int r;
        bool start_mci_reset = false;
        bool save_fullsleep = ah->chip_fullsleep;
@@ -1901,10 +1904,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
 
-       /* For chips on which RTC reset is done, save TSF before it gets cleared */
-       if (AR_SREV_9100(ah) ||
-           (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)))
-               tsf = ath9k_hw_gettsf64(ah);
+       /* Save TSF before chip reset, a cold reset clears it */
+       tsf = ath9k_hw_gettsf64(ah);
+       getrawmonotonic(&ts);
+       usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000;
 
        saveLedState = REG_READ(ah, AR_CFG_LED) &
                (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
@@ -1937,8 +1940,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        }
 
        /* Restore TSF */
-       if (tsf)
-               ath9k_hw_settsf64(ah, tsf);
+       getrawmonotonic(&ts);
+       usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000 - usec;
+       ath9k_hw_settsf64(ah, tsf + usec);
 
        if (AR_SREV_9280_20_OR_LATER(ah))
                REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
index a2c9a5dbac6b0317fba5131ee212d3ef9292c77a..e50843600989342d6c778f361e82fd1efaa212e0 100644 (file)
@@ -283,7 +283,6 @@ struct ath9k_ops_config {
        int additional_swba_backoff;
        int ack_6mb;
        u32 cwm_ignore_extcca;
-       bool pcieSerDesWrite;
        u8 pcie_clock_req;
        u32 pcie_waen;
        u8 analog_shiftreg;
@@ -921,7 +920,7 @@ struct ath_hw {
        /* Enterprise mode cap */
        u32 ent_mode;
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ATH9K_WOW
        u32 wow_event_mask;
 #endif
        bool is_clk_25mhz;
@@ -1127,7 +1126,7 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah)
 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ATH9K_WOW
 const char *ath9k_hw_wow_event_to_string(u32 wow_event);
 void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
                                u8 *user_mask, int pattern_count,
index 710192ed27ed3118656f1a3b08bc41ec92c649a1..8f4c1674b76e2a2f1c301d9e3796a4d3ffea1906 100644 (file)
@@ -589,6 +589,9 @@ static void ath9k_init_platform(struct ath_softc *sc)
        if (sc->driver_data & ATH9K_PCI_AR9565_2ANT)
                ath_info(common, "WB335 2-ANT card detected\n");
 
+       if (sc->driver_data & ATH9K_PCI_KILLER)
+               ath_info(common, "Killer Wireless card detected\n");
+
        /*
         * Some WB335 cards do not support antenna diversity. Since
         * we use a hardcoded value for AR9565 instead of using the
@@ -688,6 +691,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        common = ath9k_hw_common(ah);
        sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET);
        sc->tx99_power = MAX_RATE_POWER + 1;
+       init_waitqueue_head(&sc->tx_wait);
 
        if (!pdata) {
                ah->ah_flags |= AH_USE_EEPROM;
@@ -735,6 +739,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
                     (unsigned long)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->hw_check_work, ath_hw_check);
        INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
@@ -873,15 +878,6 @@ static const struct ieee80211_iface_combination if_comb[] = {
        }
 };
 
-#ifdef CONFIG_PM
-static const struct wiphy_wowlan_support ath9k_wowlan_support = {
-       .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
-       .n_patterns = MAX_NUM_USER_PATTERN,
-       .pattern_min_len = 1,
-       .pattern_max_len = MAX_PATTERN_SIZE,
-};
-#endif
-
 void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 {
        struct ath_hw *ah = sc->sc_ah;
@@ -931,16 +927,6 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
        hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ;
        hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
 
-#ifdef CONFIG_PM_SLEEP
-       if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) &&
-           (sc->driver_data & ATH9K_PCI_WOW) &&
-           device_can_wakeup(sc->dev))
-               hw->wiphy->wowlan = &ath9k_wowlan_support;
-
-       atomic_set(&sc->wow_sleep_proc_intr, -1);
-       atomic_set(&sc->wow_got_bmiss_intr, -1);
-#endif
-
        hw->queues = 4;
        hw->max_rates = 4;
        hw->channel_change_time = 5000;
@@ -966,6 +952,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
                hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
                        &sc->sbands[IEEE80211_BAND_5GHZ];
 
+       ath9k_init_wow(hw);
        ath9k_reload_chainmask_settings(sc);
 
        SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
@@ -1064,6 +1051,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
                if (ATH_TXQ_SETUP(sc, i))
                        ath_tx_cleanupq(sc, &sc->tx.txq[i]);
 
+       del_timer_sync(&sc->sleep_timer);
        ath9k_hw_deinit(sc->sc_ah);
        if (sc->dfs_detector != NULL)
                sc->dfs_detector->exit(sc->dfs_detector);
index 74f452c7b1667c47a65506a077042f2b0668c3a8..b1dcf89138d30d4ce8899e9a117ee96ac29212e5 100644 (file)
@@ -82,6 +82,22 @@ static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
        return ret;
 }
 
+void ath_ps_full_sleep(unsigned long data)
+{
+       struct ath_softc *sc = (struct ath_softc *) data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       bool reset;
+
+       spin_lock(&common->cc_lock);
+       ath_hw_cycle_counters_update(common);
+       spin_unlock(&common->cc_lock);
+
+       ath9k_hw_setrxabort(sc->sc_ah, 1);
+       ath9k_hw_stopdmarecv(sc->sc_ah, &reset);
+
+       ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
+}
+
 void ath9k_ps_wakeup(struct ath_softc *sc)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -92,6 +108,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
        if (++sc->ps_usecount != 1)
                goto unlock;
 
+       del_timer_sync(&sc->sleep_timer);
        power_mode = sc->sc_ah->power_mode;
        ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
 
@@ -117,17 +134,17 @@ void ath9k_ps_restore(struct ath_softc *sc)
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        enum ath9k_power_mode mode;
        unsigned long flags;
-       bool reset;
 
        spin_lock_irqsave(&sc->sc_pm_lock, flags);
        if (--sc->ps_usecount != 0)
                goto unlock;
 
        if (sc->ps_idle) {
-               ath9k_hw_setrxabort(sc->sc_ah, 1);
-               ath9k_hw_stopdmarecv(sc->sc_ah, &reset);
-               mode = ATH9K_PM_FULL_SLEEP;
-       } else if (sc->ps_enabled &&
+               mod_timer(&sc->sleep_timer, jiffies + HZ / 10);
+               goto unlock;
+       }
+
+       if (sc->ps_enabled &&
                   !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
                                     PS_WAIT_FOR_CAB |
                                     PS_WAIT_FOR_PSPOLL_DATA |
@@ -163,13 +180,13 @@ static void __ath_cancel_work(struct ath_softc *sc)
 #endif
 }
 
-static void ath_cancel_work(struct ath_softc *sc)
+void ath_cancel_work(struct ath_softc *sc)
 {
        __ath_cancel_work(sc);
        cancel_work_sync(&sc->hw_reset_work);
 }
 
-static void ath_restart_work(struct ath_softc *sc)
+void ath_restart_work(struct ath_softc *sc)
 {
        ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
 
@@ -487,6 +504,8 @@ void ath9k_tasklet(unsigned long data)
                        ath_tx_edma_tasklet(sc);
                else
                        ath_tx_tasklet(sc);
+
+               wake_up(&sc->tx_wait);
        }
 
        ath9k_btcoex_handle_interrupt(sc, status);
@@ -579,7 +598,8 @@ irqreturn_t ath_isr(int irq, void *dev)
 
                goto chip_reset;
        }
-#ifdef CONFIG_PM_SLEEP
+
+#ifdef CONFIG_ATH9K_WOW
        if (status & ATH9K_INT_BMISS) {
                if (atomic_read(&sc->wow_sleep_proc_intr) == 0) {
                        ath_dbg(common, ANY, "during WoW we got a BMISS\n");
@@ -588,6 +608,8 @@ irqreturn_t ath_isr(int irq, void *dev)
                }
        }
 #endif
+
+
        if (status & ATH9K_INT_SWBA)
                tasklet_schedule(&sc->bcon_tasklet);
 
@@ -627,7 +649,7 @@ chip_reset:
 #undef SCHED_INTR
 }
 
-static int ath_reset(struct ath_softc *sc)
+int ath_reset(struct ath_softc *sc)
 {
        int r;
 
@@ -1817,13 +1839,31 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
        mutex_unlock(&sc->mutex);
 }
 
+static bool ath9k_has_tx_pending(struct ath_softc *sc)
+{
+       int i, npend;
+
+       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+               if (!ATH_TXQ_SETUP(sc, i))
+                       continue;
+
+               if (!sc->tx.txq[i].axq_depth)
+                       continue;
+
+               npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
+               if (npend)
+                       break;
+       }
+
+       return !!npend;
+}
+
 static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
 {
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
-       int timeout = 200; /* ms */
-       int i, j;
+       int timeout = HZ / 5; /* 200 ms */
        bool drain_txq;
 
        mutex_lock(&sc->mutex);
@@ -1841,25 +1881,9 @@ static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
                return;
        }
 
-       for (j = 0; j < timeout; j++) {
-               bool npend = false;
-
-               if (j)
-                       usleep_range(1000, 2000);
-
-               for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-                       if (!ATH_TXQ_SETUP(sc, i))
-                               continue;
-
-                       npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
-
-                       if (npend)
-                               break;
-               }
-
-               if (!npend)
-                   break;
-       }
+       if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc),
+                              timeout) > 0)
+               drop = false;
 
        if (drop) {
                ath9k_ps_wakeup(sc);
@@ -2021,333 +2045,6 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-
-static void ath9k_wow_map_triggers(struct ath_softc *sc,
-                                  struct cfg80211_wowlan *wowlan,
-                                  u32 *wow_triggers)
-{
-       if (wowlan->disconnect)
-               *wow_triggers |= AH_WOW_LINK_CHANGE |
-                                AH_WOW_BEACON_MISS;
-       if (wowlan->magic_pkt)
-               *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
-
-       if (wowlan->n_patterns)
-               *wow_triggers |= AH_WOW_USER_PATTERN_EN;
-
-       sc->wow_enabled = *wow_triggers;
-
-}
-
-static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
-{
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       int pattern_count = 0;
-       int i, byte_cnt;
-       u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
-       u8 dis_deauth_mask[MAX_PATTERN_SIZE];
-
-       memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE);
-       memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE);
-
-       /*
-        * Create Dissassociate / Deauthenticate packet filter
-        *
-        *     2 bytes        2 byte    6 bytes   6 bytes  6 bytes
-        *  +--------------+----------+---------+--------+--------+----
-        *  + Frame Control+ Duration +   DA    +  SA    +  BSSID +
-        *  +--------------+----------+---------+--------+--------+----
-        *
-        * The above is the management frame format for disassociate/
-        * deauthenticate pattern, from this we need to match the first byte
-        * of 'Frame Control' and DA, SA, and BSSID fields
-        * (skipping 2nd byte of FC and Duration feild.
-        *
-        * Disassociate pattern
-        * --------------------
-        * Frame control = 00 00 1010
-        * DA, SA, BSSID = x:x:x:x:x:x
-        * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x
-        *                          | x:x:x:x:x:x  -- 22 bytes
-        *
-        * Deauthenticate pattern
-        * ----------------------
-        * Frame control = 00 00 1100
-        * DA, SA, BSSID = x:x:x:x:x:x
-        * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x
-        *                          | x:x:x:x:x:x  -- 22 bytes
-        */
-
-       /* Create Disassociate Pattern first */
-
-       byte_cnt = 0;
-
-       /* Fill out the mask with all FF's */
-
-       for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++)
-               dis_deauth_mask[i] = 0xff;
-
-       /* copy the first byte of frame control field */
-       dis_deauth_pattern[byte_cnt] = 0xa0;
-       byte_cnt++;
-
-       /* skip 2nd byte of frame control and Duration field */
-       byte_cnt += 3;
-
-       /*
-        * need not match the destination mac address, it can be a broadcast
-        * mac address or an unicast to this station
-        */
-       byte_cnt += 6;
-
-       /* copy the source mac address */
-       memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
-
-       byte_cnt += 6;
-
-       /* copy the bssid, its same as the source mac address */
-
-       memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
-
-       /* Create Disassociate pattern mask */
-
-       dis_deauth_mask[0] = 0xfe;
-       dis_deauth_mask[1] = 0x03;
-       dis_deauth_mask[2] = 0xc0;
-
-       ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");
-
-       ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
-                                  pattern_count, byte_cnt);
-
-       pattern_count++;
-       /*
-        * for de-authenticate pattern, only the first byte of the frame
-        * control field gets changed from 0xA0 to 0xC0
-        */
-       dis_deauth_pattern[0] = 0xC0;
-
-       ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
-                                  pattern_count, byte_cnt);
-
-}
-
-static void ath9k_wow_add_pattern(struct ath_softc *sc,
-                                 struct cfg80211_wowlan *wowlan)
-{
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath9k_wow_pattern *wow_pattern = NULL;
-       struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
-       int mask_len;
-       s8 i = 0;
-
-       if (!wowlan->n_patterns)
-               return;
-
-       /*
-        * Add the new user configured patterns
-        */
-       for (i = 0; i < wowlan->n_patterns; i++) {
-
-               wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL);
-
-               if (!wow_pattern)
-                       return;
-
-               /*
-                * TODO: convert the generic user space pattern to
-                * appropriate chip specific/802.11 pattern.
-                */
-
-               mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
-               memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE);
-               memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE);
-               memcpy(wow_pattern->pattern_bytes, patterns[i].pattern,
-                      patterns[i].pattern_len);
-               memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len);
-               wow_pattern->pattern_len = patterns[i].pattern_len;
-
-               /*
-                * just need to take care of deauth and disssoc pattern,
-                * make sure we don't overwrite them.
-                */
-
-               ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes,
-                                          wow_pattern->mask_bytes,
-                                          i + 2,
-                                          wow_pattern->pattern_len);
-               kfree(wow_pattern);
-
-       }
-
-}
-
-static int ath9k_suspend(struct ieee80211_hw *hw,
-                        struct cfg80211_wowlan *wowlan)
-{
-       struct ath_softc *sc = hw->priv;
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       u32 wow_triggers_enabled = 0;
-       int ret = 0;
-
-       mutex_lock(&sc->mutex);
-
-       ath_cancel_work(sc);
-       ath_stop_ani(sc);
-       del_timer_sync(&sc->rx_poll_timer);
-
-       if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
-               ath_dbg(common, ANY, "Device not present\n");
-               ret = -EINVAL;
-               goto fail_wow;
-       }
-
-       if (WARN_ON(!wowlan)) {
-               ath_dbg(common, WOW, "None of the WoW triggers enabled\n");
-               ret = -EINVAL;
-               goto fail_wow;
-       }
-
-       if (!device_can_wakeup(sc->dev)) {
-               ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n");
-               ret = 1;
-               goto fail_wow;
-       }
-
-       /*
-        * none of the sta vifs are associated
-        * and we are not currently handling multivif
-        * cases, for instance we have to seperately
-        * configure 'keep alive frame' for each
-        * STA.
-        */
-
-       if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
-               ath_dbg(common, WOW, "None of the STA vifs are associated\n");
-               ret = 1;
-               goto fail_wow;
-       }
-
-       if (sc->nvifs > 1) {
-               ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
-               ret = 1;
-               goto fail_wow;
-       }
-
-       ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled);
-
-       ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n",
-               wow_triggers_enabled);
-
-       ath9k_ps_wakeup(sc);
-
-       ath9k_stop_btcoex(sc);
-
-       /*
-        * Enable wake up on recieving disassoc/deauth
-        * frame by default.
-        */
-       ath9k_wow_add_disassoc_deauth_pattern(sc);
-
-       if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN)
-               ath9k_wow_add_pattern(sc, wowlan);
-
-       spin_lock_bh(&sc->sc_pcu_lock);
-       /*
-        * To avoid false wake, we enable beacon miss interrupt only
-        * when we go to sleep. We save the current interrupt mask
-        * so we can restore it after the system wakes up
-        */
-       sc->wow_intr_before_sleep = ah->imask;
-       ah->imask &= ~ATH9K_INT_GLOBAL;
-       ath9k_hw_disable_interrupts(ah);
-       ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL;
-       ath9k_hw_set_interrupts(ah);
-       ath9k_hw_enable_interrupts(ah);
-
-       spin_unlock_bh(&sc->sc_pcu_lock);
-
-       /*
-        * we can now sync irq and kill any running tasklets, since we already
-        * disabled interrupts and not holding a spin lock
-        */
-       synchronize_irq(sc->irq);
-       tasklet_kill(&sc->intr_tq);
-
-       ath9k_hw_wow_enable(ah, wow_triggers_enabled);
-
-       ath9k_ps_restore(sc);
-       ath_dbg(common, ANY, "WoW enabled in ath9k\n");
-       atomic_inc(&sc->wow_sleep_proc_intr);
-
-fail_wow:
-       mutex_unlock(&sc->mutex);
-       return ret;
-}
-
-static int ath9k_resume(struct ieee80211_hw *hw)
-{
-       struct ath_softc *sc = hw->priv;
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       u32 wow_status;
-
-       mutex_lock(&sc->mutex);
-
-       ath9k_ps_wakeup(sc);
-
-       spin_lock_bh(&sc->sc_pcu_lock);
-
-       ath9k_hw_disable_interrupts(ah);
-       ah->imask = sc->wow_intr_before_sleep;
-       ath9k_hw_set_interrupts(ah);
-       ath9k_hw_enable_interrupts(ah);
-
-       spin_unlock_bh(&sc->sc_pcu_lock);
-
-       wow_status = ath9k_hw_wow_wakeup(ah);
-
-       if (atomic_read(&sc->wow_got_bmiss_intr) == 0) {
-               /*
-                * some devices may not pick beacon miss
-                * as the reason they woke up so we add
-                * that here for that shortcoming.
-                */
-               wow_status |= AH_WOW_BEACON_MISS;
-               atomic_dec(&sc->wow_got_bmiss_intr);
-               ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n");
-       }
-
-       atomic_dec(&sc->wow_sleep_proc_intr);
-
-       if (wow_status) {
-               ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n",
-                       ath9k_hw_wow_event_to_string(wow_status), wow_status);
-       }
-
-       ath_restart_work(sc);
-       ath9k_start_btcoex(sc);
-
-       ath9k_ps_restore(sc);
-       mutex_unlock(&sc->mutex);
-
-       return 0;
-}
-
-static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
-{
-       struct ath_softc *sc = hw->priv;
-
-       mutex_lock(&sc->mutex);
-       device_init_wakeup(sc->dev, 1);
-       device_set_wakeup_enable(sc->dev, enabled);
-       mutex_unlock(&sc->mutex);
-}
-
-#endif
 static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 {
        struct ath_softc *sc = hw->priv;
@@ -2373,134 +2070,6 @@ static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw,
        sc->csa_vif = vif;
 }
 
-static void ath9k_tx99_stop(struct ath_softc *sc)
-{
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       ath_drain_all_txq(sc);
-       ath_startrecv(sc);
-
-       ath9k_hw_set_interrupts(ah);
-       ath9k_hw_enable_interrupts(ah);
-
-       ieee80211_wake_queues(sc->hw);
-
-       kfree_skb(sc->tx99_skb);
-       sc->tx99_skb = NULL;
-       sc->tx99_state = false;
-
-       ath9k_hw_tx99_stop(sc->sc_ah);
-       ath_dbg(common, XMIT, "TX99 stopped\n");
-}
-
-static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
-{
-       static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24,
-                              0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50,
-                              0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1,
-                              0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18,
-                              0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8,
-                              0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84,
-                              0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,
-                              0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};
-       u32 len = 1200;
-       struct ieee80211_hw *hw = sc->hw;
-       struct ieee80211_hdr *hdr;
-       struct ieee80211_tx_info *tx_info;
-       struct sk_buff *skb;
-
-       skb = alloc_skb(len, GFP_KERNEL);
-       if (!skb)
-               return NULL;
-
-       skb_put(skb, len);
-
-       memset(skb->data, 0, len);
-
-       hdr = (struct ieee80211_hdr *)skb->data;
-       hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA);
-       hdr->duration_id = 0;
-
-       memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
-       memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
-       memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
-
-       hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
-
-       tx_info = IEEE80211_SKB_CB(skb);
-       memset(tx_info, 0, sizeof(*tx_info));
-       tx_info->band = hw->conf.chandef.chan->band;
-       tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
-       tx_info->control.vif = sc->tx99_vif;
-
-       memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data));
-
-       return skb;
-}
-
-void ath9k_tx99_deinit(struct ath_softc *sc)
-{
-       ath_reset(sc);
-
-       ath9k_ps_wakeup(sc);
-       ath9k_tx99_stop(sc);
-       ath9k_ps_restore(sc);
-}
-
-int ath9k_tx99_init(struct ath_softc *sc)
-{
-       struct ieee80211_hw *hw = sc->hw;
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_tx_control txctl;
-       int r;
-
-       if (sc->sc_flags & SC_OP_INVALID) {
-               ath_err(common,
-                       "driver is in invalid state unable to use TX99");
-               return -EINVAL;
-       }
-
-       sc->tx99_skb = ath9k_build_tx99_skb(sc);
-       if (!sc->tx99_skb)
-               return -ENOMEM;
-
-       memset(&txctl, 0, sizeof(txctl));
-       txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
-
-       ath_reset(sc);
-
-       ath9k_ps_wakeup(sc);
-
-       ath9k_hw_disable_interrupts(ah);
-       atomic_set(&ah->intr_ref_cnt, -1);
-       ath_drain_all_txq(sc);
-       ath_stoprecv(sc);
-
-       sc->tx99_state = true;
-
-       ieee80211_stop_queues(hw);
-
-       if (sc->tx99_power == MAX_RATE_POWER + 1)
-               sc->tx99_power = MAX_RATE_POWER;
-
-       ath9k_hw_tx99_set_txpower(ah, sc->tx99_power);
-       r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl);
-       if (r) {
-               ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n");
-               return r;
-       }
-
-       ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n",
-               sc->tx99_power,
-               sc->tx99_power / 2);
-
-       /* We leave the harware awake as it will be chugging on */
-
-       return 0;
-}
-
 struct ieee80211_ops ath9k_ops = {
        .tx                 = ath9k_tx,
        .start              = ath9k_start,
@@ -2531,7 +2100,7 @@ struct ieee80211_ops ath9k_ops = {
        .set_antenna        = ath9k_set_antenna,
        .get_antenna        = ath9k_get_antenna,
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ATH9K_WOW
        .suspend            = ath9k_suspend,
        .resume             = ath9k_resume,
        .set_wakeup         = ath9k_set_wakeup,
index b5656fce4ff5f042b9053258e31c9b503802d217..e9a585758941fc9305fa859bab091992eb9946a8 100644 (file)
@@ -87,6 +87,19 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
        { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
        { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI   */
        { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
+
+       /* Killer Wireless (3x3) */
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0030,
+                        0x1A56,
+                        0x2000),
+         .driver_data = ATH9K_PCI_KILLER },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0030,
+                        0x1A56,
+                        0x2001),
+         .driver_data = ATH9K_PCI_KILLER },
+
        { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E  AR9300 */
 
        /* PCI-E CUS198 */
@@ -354,6 +367,13 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
                         0x1783),
          .driver_data = ATH9K_PCI_WOW },
 
+       /* Killer Wireless (2x2) */
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0030,
+                        0x1A56,
+                        0x2003),
+         .driver_data = ATH9K_PCI_KILLER },
+
        { PCI_VDEVICE(ATHEROS, 0x0034) }, /* PCI-E  AR9462 */
        { PCI_VDEVICE(ATHEROS, 0x0037) }, /* PCI-E  AR1111/AR9485 */
 
@@ -446,6 +466,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
                         0x11AD, /* LITEON */
                         0x0662),
          .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x0682),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_AZWAVE,
@@ -456,6 +481,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
                         PCI_VENDOR_ID_LENOVO,
                         0x3026),
          .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_LENOVO,
+                        0x4026),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_HP,
@@ -466,6 +496,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
                         PCI_VENDOR_ID_HP,
                         0x217F),
          .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_HP,
+                        0x2005),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_DELL,
@@ -545,6 +580,16 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
                         0x185F, /* WNC */
                         0x3027),
          .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x185F, /* WNC */
+                        0xA120),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_FOXCONN,
+                        0xE07F),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
 
        /* PCI-E AR9565 (WB335) */
        { PCI_VDEVICE(ATHEROS, 0x0036),
index a13b2d143d9eb31411fcb0f504a91c1ba1026e21..259a4b3077077fa8d4e90625ea6a7fb362990489 100644 (file)
 #define AR_SREV_REVISION_9462_21       3
 #define AR_SREV_VERSION_9565            0x2C0
 #define AR_SREV_REVISION_9565_10        0
+#define AR_SREV_REVISION_9565_101       1
+#define AR_SREV_REVISION_9565_11        2
 #define AR_SREV_VERSION_9550           0x400
 
 #define AR_SREV_5416(_ah) \
 
 #define AR_SREV_9565(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565))
-
 #define AR_SREV_9565_10(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
         ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_10))
+#define AR_SREV_9565_101(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
+        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_101))
+#define AR_SREV_9565_11(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
+        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_11))
+#define AR_SREV_9565_11_OR_LATER(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
+        ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9565_11))
 
 #define AR_SREV_9550(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9550))
diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c
new file mode 100644 (file)
index 0000000..57d7757
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * 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 "ath9k.h"
+
+static void ath9k_tx99_stop(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       ath_drain_all_txq(sc);
+       ath_startrecv(sc);
+
+       ath9k_hw_set_interrupts(ah);
+       ath9k_hw_enable_interrupts(ah);
+
+       ieee80211_wake_queues(sc->hw);
+
+       kfree_skb(sc->tx99_skb);
+       sc->tx99_skb = NULL;
+       sc->tx99_state = false;
+
+       ath9k_hw_tx99_stop(sc->sc_ah);
+       ath_dbg(common, XMIT, "TX99 stopped\n");
+}
+
+static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
+{
+       static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24,
+                              0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50,
+                              0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1,
+                              0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18,
+                              0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8,
+                              0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84,
+                              0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,
+                              0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};
+       u32 len = 1200;
+       struct ieee80211_hw *hw = sc->hw;
+       struct ieee80211_hdr *hdr;
+       struct ieee80211_tx_info *tx_info;
+       struct sk_buff *skb;
+
+       skb = alloc_skb(len, GFP_KERNEL);
+       if (!skb)
+               return NULL;
+
+       skb_put(skb, len);
+
+       memset(skb->data, 0, len);
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA);
+       hdr->duration_id = 0;
+
+       memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
+       memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
+       memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
+
+       hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
+
+       tx_info = IEEE80211_SKB_CB(skb);
+       memset(tx_info, 0, sizeof(*tx_info));
+       tx_info->band = hw->conf.chandef.chan->band;
+       tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
+       tx_info->control.vif = sc->tx99_vif;
+       tx_info->control.rates[0].count = 1;
+
+       memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data));
+
+       return skb;
+}
+
+static void ath9k_tx99_deinit(struct ath_softc *sc)
+{
+       ath_reset(sc);
+
+       ath9k_ps_wakeup(sc);
+       ath9k_tx99_stop(sc);
+       ath9k_ps_restore(sc);
+}
+
+static int ath9k_tx99_init(struct ath_softc *sc)
+{
+       struct ieee80211_hw *hw = sc->hw;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath_tx_control txctl;
+       int r;
+
+       if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
+               ath_err(common,
+                       "driver is in invalid state unable to use TX99");
+               return -EINVAL;
+       }
+
+       sc->tx99_skb = ath9k_build_tx99_skb(sc);
+       if (!sc->tx99_skb)
+               return -ENOMEM;
+
+       memset(&txctl, 0, sizeof(txctl));
+       txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
+
+       ath_reset(sc);
+
+       ath9k_ps_wakeup(sc);
+
+       ath9k_hw_disable_interrupts(ah);
+       atomic_set(&ah->intr_ref_cnt, -1);
+       ath_drain_all_txq(sc);
+       ath_stoprecv(sc);
+
+       sc->tx99_state = true;
+
+       ieee80211_stop_queues(hw);
+
+       if (sc->tx99_power == MAX_RATE_POWER + 1)
+               sc->tx99_power = MAX_RATE_POWER;
+
+       ath9k_hw_tx99_set_txpower(ah, sc->tx99_power);
+       r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl);
+       if (r) {
+               ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n");
+               return r;
+       }
+
+       ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n",
+               sc->tx99_power,
+               sc->tx99_power / 2);
+
+       /* We leave the harware awake as it will be chugging on */
+
+       return 0;
+}
+
+static ssize_t read_file_tx99(struct file *file, char __user *user_buf,
+                             size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char buf[3];
+       unsigned int len;
+
+       len = sprintf(buf, "%d\n", sc->tx99_state);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,
+                              size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       char buf[32];
+       bool start;
+       ssize_t len;
+       int r;
+
+       if (sc->nvifs > 1)
+               return -EOPNOTSUPP;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+
+       if (strtobool(buf, &start))
+               return -EINVAL;
+
+       if (start == sc->tx99_state) {
+               if (!start)
+                       return count;
+               ath_dbg(common, XMIT, "Resetting TX99\n");
+               ath9k_tx99_deinit(sc);
+       }
+
+       if (!start) {
+               ath9k_tx99_deinit(sc);
+               return count;
+       }
+
+       r = ath9k_tx99_init(sc);
+       if (r)
+               return r;
+
+       return count;
+}
+
+static const struct file_operations fops_tx99 = {
+       .read = read_file_tx99,
+       .write = write_file_tx99,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t read_file_tx99_power(struct file *file,
+                                   char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char buf[32];
+       unsigned int len;
+
+       len = sprintf(buf, "%d (%d dBm)\n",
+                     sc->tx99_power,
+                     sc->tx99_power / 2);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_tx99_power(struct file *file,
+                                    const char __user *user_buf,
+                                    size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       int r;
+       u8 tx_power;
+
+       r = kstrtou8_from_user(user_buf, count, 0, &tx_power);
+       if (r)
+               return r;
+
+       if (tx_power > MAX_RATE_POWER)
+               return -EINVAL;
+
+       sc->tx99_power = tx_power;
+
+       ath9k_ps_wakeup(sc);
+       ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power);
+       ath9k_ps_restore(sc);
+
+       return count;
+}
+
+static const struct file_operations fops_tx99_power = {
+       .read = read_file_tx99_power,
+       .write = write_file_tx99_power,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+void ath9k_tx99_init_debug(struct ath_softc *sc)
+{
+       if (!AR_SREV_9300_20_OR_LATER(sc->sc_ah))
+               return;
+
+       debugfs_create_file("tx99", S_IRUSR | S_IWUSR,
+                           sc->debug.debugfs_phy, sc,
+                           &fops_tx99);
+       debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR,
+                           sc->debug.debugfs_phy, sc,
+                           &fops_tx99_power);
+}
index 81c88dd606dcd960f43e740b9af8cffcdc25778a..f1cde81bb7a2573f1905c2725c29c176da7013f0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * 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
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/export.h>
 #include "ath9k.h"
-#include "reg.h"
-#include "hw-ops.h"
 
-const char *ath9k_hw_wow_event_to_string(u32 wow_event)
-{
-       if (wow_event & AH_WOW_MAGIC_PATTERN_EN)
-               return "Magic pattern";
-       if (wow_event & AH_WOW_USER_PATTERN_EN)
-               return "User pattern";
-       if (wow_event & AH_WOW_LINK_CHANGE)
-               return "Link change";
-       if (wow_event & AH_WOW_BEACON_MISS)
-               return "Beacon miss";
-
-       return  "unknown reason";
-}
-EXPORT_SYMBOL(ath9k_hw_wow_event_to_string);
+static const struct wiphy_wowlan_support ath9k_wowlan_support = {
+       .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
+       .n_patterns = MAX_NUM_USER_PATTERN,
+       .pattern_min_len = 1,
+       .pattern_max_len = MAX_PATTERN_SIZE,
+};
 
-static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
+static void ath9k_wow_map_triggers(struct ath_softc *sc,
+                                  struct cfg80211_wowlan *wowlan,
+                                  u32 *wow_triggers)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
+       if (wowlan->disconnect)
+               *wow_triggers |= AH_WOW_LINK_CHANGE |
+                                AH_WOW_BEACON_MISS;
+       if (wowlan->magic_pkt)
+               *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
 
-       REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+       if (wowlan->n_patterns)
+               *wow_triggers |= AH_WOW_USER_PATTERN_EN;
 
-       /* set rx disable bit */
-       REG_WRITE(ah, AR_CR, AR_CR_RXD);
-
-       if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) {
-               ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
-                       REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
-               return;
-       }
+       sc->wow_enabled = *wow_triggers;
 
-       REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);
 }
 
-static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
+static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
 {
+       struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
-       u8 sta_mac_addr[ETH_ALEN], ap_mac_addr[ETH_ALEN];
-       u32 ctl[13] = {0};
-       u32 data_word[KAL_NUM_DATA_WORDS];
-       u8 i;
-       u32 wow_ka_data_word0;
-
-       memcpy(sta_mac_addr, common->macaddr, ETH_ALEN);
-       memcpy(ap_mac_addr, common->curbssid, ETH_ALEN);
-
-       /* set the transmit buffer */
-       ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16));
-       ctl[1] = 0;
-       ctl[3] = 0xb;   /* OFDM_6M hardware value for this rate */
-       ctl[4] = 0;
-       ctl[7] = (ah->txchainmask) << 2;
-       ctl[2] = 0xf << 16; /* tx_tries 0 */
-
-       for (i = 0; i < KAL_NUM_DESC_WORDS; i++)
-               REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
-
-       REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
-
-       data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) |
-                      (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16);
-       data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) |
-                      (ap_mac_addr[1] << 8) | (ap_mac_addr[0]);
-       data_word[2] = (sta_mac_addr[1] << 24) | (sta_mac_addr[0] << 16) |
-                      (ap_mac_addr[5] << 8) | (ap_mac_addr[4]);
-       data_word[3] = (sta_mac_addr[5] << 24) | (sta_mac_addr[4] << 16) |
-                      (sta_mac_addr[3] << 8) | (sta_mac_addr[2]);
-       data_word[4] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) |
-                      (ap_mac_addr[1] << 8) | (ap_mac_addr[0]);
-       data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]);
-
-       if (AR_SREV_9462_20(ah)) {
-               /* AR9462 2.0 has an extra descriptor word (time based
-                * discard) compared to other chips */
-               REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0);
-               wow_ka_data_word0 = AR_WOW_TXBUF(13);
-       } else {
-               wow_ka_data_word0 = AR_WOW_TXBUF(12);
-       }
-
-       for (i = 0; i < KAL_NUM_DATA_WORDS; i++)
-               REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]);
-
-}
-
-void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
-                               u8 *user_mask, int pattern_count,
-                               int pattern_len)
-{
-       int i;
-       u32 pattern_val, mask_val;
-       u32 set, clr;
+       int pattern_count = 0;
+       int i, byte_cnt;
+       u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
+       u8 dis_deauth_mask[MAX_PATTERN_SIZE];
 
-       /* FIXME: should check count by querying the hardware capability */
-       if (pattern_count >= MAX_NUM_PATTERN)
-               return;
-
-       REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count));
-
-       /* set the registers for pattern */
-       for (i = 0; i < MAX_PATTERN_SIZE; i += 4) {
-               memcpy(&pattern_val, user_pattern, 4);
-               REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i),
-                         pattern_val);
-               user_pattern += 4;
-       }
-
-       /* set the registers for mask */
-       for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) {
-               memcpy(&mask_val, user_mask, 4);
-               REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val);
-               user_mask += 4;
-       }
+       memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE);
+       memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE);
 
-       /* set the pattern length to be matched
+       /*
+        * Create Dissassociate / Deauthenticate packet filter
+        *
+        *     2 bytes        2 byte    6 bytes   6 bytes  6 bytes
+        *  +--------------+----------+---------+--------+--------+----
+        *  + Frame Control+ Duration +   DA    +  SA    +  BSSID +
+        *  +--------------+----------+---------+--------+--------+----
         *
-        * AR_WOW_LENGTH1_REG1
-        * bit 31:24 pattern 0 length
-        * bit 23:16 pattern 1 length
-        * bit 15:8 pattern 2 length
-        * bit 7:0 pattern 3 length
+        * The above is the management frame format for disassociate/
+        * deauthenticate pattern, from this we need to match the first byte
+        * of 'Frame Control' and DA, SA, and BSSID fields
+        * (skipping 2nd byte of FC and Duration feild.
         *
-        * AR_WOW_LENGTH1_REG2
-        * bit 31:24 pattern 4 length
-        * bit 23:16 pattern 5 length
-        * bit 15:8 pattern 6 length
-        * bit 7:0 pattern 7 length
+        * Disassociate pattern
+        * --------------------
+        * Frame control = 00 00 1010
+        * DA, SA, BSSID = x:x:x:x:x:x
+        * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x
+        *                          | x:x:x:x:x:x  -- 22 bytes
         *
-        * the below logic writes out the new
-        * pattern length for the corresponding
-        * pattern_count, while masking out the
-        * other fields
+        * Deauthenticate pattern
+        * ----------------------
+        * Frame control = 00 00 1100
+        * DA, SA, BSSID = x:x:x:x:x:x
+        * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x
+        *                          | x:x:x:x:x:x  -- 22 bytes
         */
 
-       ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT);
-
-       if (pattern_count < 4) {
-               /* Pattern 0-3 uses AR_WOW_LENGTH1 register */
-               set = (pattern_len & AR_WOW_LENGTH_MAX) <<
-                      AR_WOW_LEN1_SHIFT(pattern_count);
-               clr = AR_WOW_LENGTH1_MASK(pattern_count);
-               REG_RMW(ah, AR_WOW_LENGTH1, set, clr);
-       } else {
-               /* Pattern 4-7 uses AR_WOW_LENGTH2 register */
-               set = (pattern_len & AR_WOW_LENGTH_MAX) <<
-                      AR_WOW_LEN2_SHIFT(pattern_count);
-               clr = AR_WOW_LENGTH2_MASK(pattern_count);
-               REG_RMW(ah, AR_WOW_LENGTH2, set, clr);
-       }
+       /* Create Disassociate Pattern first */
 
-}
-EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern);
+       byte_cnt = 0;
 
-u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
-{
-       u32 wow_status = 0;
-       u32 val = 0, rval;
+       /* Fill out the mask with all FF's */
 
-       /*
-        * read the WoW status register to know
-        * the wakeup reason
-        */
-       rval = REG_READ(ah, AR_WOW_PATTERN);
-       val = AR_WOW_STATUS(rval);
+       for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++)
+               dis_deauth_mask[i] = 0xff;
 
-       /*
-        * mask only the WoW events that we have enabled. Sometimes
-        * we have spurious WoW events from the AR_WOW_PATTERN
-        * register. This mask will clean it up.
-        */
+       /* copy the first byte of frame control field */
+       dis_deauth_pattern[byte_cnt] = 0xa0;
+       byte_cnt++;
 
-       val &= ah->wow_event_mask;
-
-       if (val) {
-               if (val & AR_WOW_MAGIC_PAT_FOUND)
-                       wow_status |= AH_WOW_MAGIC_PATTERN_EN;
-               if (AR_WOW_PATTERN_FOUND(val))
-                       wow_status |= AH_WOW_USER_PATTERN_EN;
-               if (val & AR_WOW_KEEP_ALIVE_FAIL)
-                       wow_status |= AH_WOW_LINK_CHANGE;
-               if (val & AR_WOW_BEACON_FAIL)
-                       wow_status |= AH_WOW_BEACON_MISS;
-       }
+       /* skip 2nd byte of frame control and Duration field */
+       byte_cnt += 3;
 
        /*
-        * set and clear WOW_PME_CLEAR registers for the chip to
-        * generate next wow signal.
-        * disable D3 before accessing other registers ?
+        * need not match the destination mac address, it can be a broadcast
+        * mac address or an unicast to this station
         */
+       byte_cnt += 6;
 
-       /* do we need to check the bit value 0x01000000 (7-10) ?? */
-       REG_RMW(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR,
-               AR_PMCTRL_PWR_STATE_D1D3);
+       /* copy the source mac address */
+       memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
 
-       /*
-        * clear all events
-        */
-       REG_WRITE(ah, AR_WOW_PATTERN,
-                 AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN)));
+       byte_cnt += 6;
 
-       /*
-        * restore the beacon threshold to init value
-        */
-       REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
+       /* copy the bssid, its same as the source mac address */
+
+       memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
+
+       /* Create Disassociate pattern mask */
+
+       dis_deauth_mask[0] = 0xfe;
+       dis_deauth_mask[1] = 0x03;
+       dis_deauth_mask[2] = 0xc0;
+
+       ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");
 
+       ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
+                                  pattern_count, byte_cnt);
+
+       pattern_count++;
        /*
-        * Restore the way the PCI-E reset, Power-On-Reset, external
-        * PCIE_POR_SHORT pins are tied to its original value.
-        * Previously just before WoW sleep, we untie the PCI-E
-        * reset to our Chip's Power On Reset so that any PCI-E
-        * reset from the bus will not reset our chip
+        * for de-authenticate pattern, only the first byte of the frame
+        * control field gets changed from 0xA0 to 0xC0
         */
-       if (ah->is_pciexpress)
-               ath9k_hw_configpcipowersave(ah, false);
+       dis_deauth_pattern[0] = 0xC0;
 
-       ah->wow_event_mask = 0;
+       ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
+                                  pattern_count, byte_cnt);
 
-       return wow_status;
 }
-EXPORT_SYMBOL(ath9k_hw_wow_wakeup);
 
-void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
+static void ath9k_wow_add_pattern(struct ath_softc *sc,
+                                 struct cfg80211_wowlan *wowlan)
 {
-       u32 wow_event_mask;
-       u32 set, clr;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath9k_wow_pattern *wow_pattern = NULL;
+       struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
+       int mask_len;
+       s8 i = 0;
 
-       /*
-        * wow_event_mask is a mask to the AR_WOW_PATTERN register to
-        * indicate which WoW events we have enabled. The WoW events
-        * are from the 'pattern_enable' in this function and
-        * 'pattern_count' of ath9k_hw_wow_apply_pattern()
-        */
-       wow_event_mask = ah->wow_event_mask;
+       if (!wowlan->n_patterns)
+               return;
 
        /*
-        * Untie Power-on-Reset from the PCI-E-Reset. When we are in
-        * WOW sleep, we do want the Reset from the PCI-E to disturb
-        * our hw state
+        * Add the new user configured patterns
         */
-       if (ah->is_pciexpress) {
+       for (i = 0; i < wowlan->n_patterns; i++) {
+
+               wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL);
+
+               if (!wow_pattern)
+                       return;
+
+               /*
+                * TODO: convert the generic user space pattern to
+                * appropriate chip specific/802.11 pattern.
+                */
+
+               mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
+               memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE);
+               memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE);
+               memcpy(wow_pattern->pattern_bytes, patterns[i].pattern,
+                      patterns[i].pattern_len);
+               memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len);
+               wow_pattern->pattern_len = patterns[i].pattern_len;
+
                /*
-                * we need to untie the internal POR (power-on-reset)
-                * to the external PCI-E reset. We also need to tie
-                * the PCI-E Phy reset to the PCI-E reset.
+                * just need to take care of deauth and disssoc pattern,
+                * make sure we don't overwrite them.
                 */
-               set = AR_WA_RESET_EN | AR_WA_POR_SHORT;
-               clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;
-               REG_RMW(ah, AR_WA, set, clr);
+
+               ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes,
+                                          wow_pattern->mask_bytes,
+                                          i + 2,
+                                          wow_pattern->pattern_len);
+               kfree(wow_pattern);
+
        }
 
-       /*
-        * set the power states appropriately and enable PME
-        */
-       set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA |
-             AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR;
+}
 
-       /*
-        * set and clear WOW_PME_CLEAR registers for the chip
-        * to generate next wow signal.
-        */
-       REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
-       clr = AR_PMCTRL_WOW_PME_CLR;
-       REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
+int ath9k_suspend(struct ieee80211_hw *hw,
+                 struct cfg80211_wowlan *wowlan)
+{
+       struct ath_softc *sc = hw->priv;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 wow_triggers_enabled = 0;
+       int ret = 0;
 
-       /*
-        * Setup for:
-        *      - beacon misses
-        *      - magic pattern
-        *      - keep alive timeout
-        *      - pattern matching
-        */
+       mutex_lock(&sc->mutex);
 
-       /*
-        * Program default values for pattern backoff, aifs/slot/KAL count,
-        * beacon miss timeout, KAL timeout, etc.
-        */
-       set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF);
-       REG_SET_BIT(ah, AR_WOW_PATTERN, set);
+       ath_cancel_work(sc);
+       ath_stop_ani(sc);
+       del_timer_sync(&sc->rx_poll_timer);
 
-       set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) |
-             AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) |
-             AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT);
-       REG_SET_BIT(ah, AR_WOW_COUNT, set);
+       if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
+               ath_dbg(common, ANY, "Device not present\n");
+               ret = -EINVAL;
+               goto fail_wow;
+       }
 
-       if (pattern_enable & AH_WOW_BEACON_MISS)
-               set = AR_WOW_BEACON_TIMO;
-       /* We are not using beacon miss, program a large value */
-       else
-               set = AR_WOW_BEACON_TIMO_MAX;
+       if (WARN_ON(!wowlan)) {
+               ath_dbg(common, WOW, "None of the WoW triggers enabled\n");
+               ret = -EINVAL;
+               goto fail_wow;
+       }
 
-       REG_WRITE(ah, AR_WOW_BCN_TIMO, set);
+       if (!device_can_wakeup(sc->dev)) {
+               ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n");
+               ret = 1;
+               goto fail_wow;
+       }
 
        /*
-        * Keep alive timo in ms except AR9280
+        * none of the sta vifs are associated
+        * and we are not currently handling multivif
+        * cases, for instance we have to seperately
+        * configure 'keep alive frame' for each
+        * STA.
         */
-       if (!pattern_enable)
-               set = AR_WOW_KEEP_ALIVE_NEVER;
-       else
-               set = KAL_TIMEOUT * 32;
 
-       REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set);
+       if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
+               ath_dbg(common, WOW, "None of the STA vifs are associated\n");
+               ret = 1;
+               goto fail_wow;
+       }
+
+       if (sc->nvifs > 1) {
+               ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
+               ret = 1;
+               goto fail_wow;
+       }
+
+       ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled);
+
+       ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n",
+               wow_triggers_enabled);
+
+       ath9k_ps_wakeup(sc);
+
+       ath9k_stop_btcoex(sc);
 
        /*
-        * Keep alive delay in us. based on 'power on clock',
-        * therefore in usec
+        * Enable wake up on recieving disassoc/deauth
+        * frame by default.
         */
-       set = KAL_DELAY * 1000;
-       REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set);
+       ath9k_wow_add_disassoc_deauth_pattern(sc);
+
+       if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN)
+               ath9k_wow_add_pattern(sc, wowlan);
 
+       spin_lock_bh(&sc->sc_pcu_lock);
        /*
-        * Create keep alive pattern to respond to beacons
+        * To avoid false wake, we enable beacon miss interrupt only
+        * when we go to sleep. We save the current interrupt mask
+        * so we can restore it after the system wakes up
         */
-       ath9k_wow_create_keep_alive_pattern(ah);
+       sc->wow_intr_before_sleep = ah->imask;
+       ah->imask &= ~ATH9K_INT_GLOBAL;
+       ath9k_hw_disable_interrupts(ah);
+       ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL;
+       ath9k_hw_set_interrupts(ah);
+       ath9k_hw_enable_interrupts(ah);
+
+       spin_unlock_bh(&sc->sc_pcu_lock);
 
        /*
-        * Configure MAC WoW Registers
+        * we can now sync irq and kill any running tasklets, since we already
+        * disabled interrupts and not holding a spin lock
         */
-       set = 0;
-       /* Send keep alive timeouts anyway */
-       clr = AR_WOW_KEEP_ALIVE_AUTO_DIS;
+       synchronize_irq(sc->irq);
+       tasklet_kill(&sc->intr_tq);
 
-       if (pattern_enable & AH_WOW_LINK_CHANGE)
-               wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL;
-       else
-               set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
+       ath9k_hw_wow_enable(ah, wow_triggers_enabled);
 
-       set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
-       REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr);
+       ath9k_ps_restore(sc);
+       ath_dbg(common, ANY, "WoW enabled in ath9k\n");
+       atomic_inc(&sc->wow_sleep_proc_intr);
 
-       /*
-        * we are relying on a bmiss failure. ensure we have
-        * enough threshold to prevent false positives
-        */
-       REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR,
-                     AR_WOW_BMISSTHRESHOLD);
+fail_wow:
+       mutex_unlock(&sc->mutex);
+       return ret;
+}
+
+int ath9k_resume(struct ieee80211_hw *hw)
+{
+       struct ath_softc *sc = hw->priv;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 wow_status;
 
-       set = 0;
-       clr = 0;
+       mutex_lock(&sc->mutex);
 
-       if (pattern_enable & AH_WOW_BEACON_MISS) {
-               set = AR_WOW_BEACON_FAIL_EN;
-               wow_event_mask |= AR_WOW_BEACON_FAIL;
-       } else {
-               clr = AR_WOW_BEACON_FAIL_EN;
+       ath9k_ps_wakeup(sc);
+
+       spin_lock_bh(&sc->sc_pcu_lock);
+
+       ath9k_hw_disable_interrupts(ah);
+       ah->imask = sc->wow_intr_before_sleep;
+       ath9k_hw_set_interrupts(ah);
+       ath9k_hw_enable_interrupts(ah);
+
+       spin_unlock_bh(&sc->sc_pcu_lock);
+
+       wow_status = ath9k_hw_wow_wakeup(ah);
+
+       if (atomic_read(&sc->wow_got_bmiss_intr) == 0) {
+               /*
+                * some devices may not pick beacon miss
+                * as the reason they woke up so we add
+                * that here for that shortcoming.
+                */
+               wow_status |= AH_WOW_BEACON_MISS;
+               atomic_dec(&sc->wow_got_bmiss_intr);
+               ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n");
        }
 
-       REG_RMW(ah, AR_WOW_BCN_EN, set, clr);
+       atomic_dec(&sc->wow_sleep_proc_intr);
 
-       set = 0;
-       clr = 0;
-       /*
-        * Enable the magic packet registers
-        */
-       if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) {
-               set = AR_WOW_MAGIC_EN;
-               wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND;
-       } else {
-               clr = AR_WOW_MAGIC_EN;
+       if (wow_status) {
+               ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n",
+                       ath9k_hw_wow_event_to_string(wow_status), wow_status);
        }
-       set |= AR_WOW_MAC_INTR_EN;
-       REG_RMW(ah, AR_WOW_PATTERN, set, clr);
 
-       REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,
-                 AR_WOW_PATTERN_SUPPORTED);
+       ath_restart_work(sc);
+       ath9k_start_btcoex(sc);
 
-       /*
-        * Set the power states appropriately and enable PME
-        */
-       clr = 0;
-       set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN |
-             AR_PMCTRL_PWR_PM_CTRL_ENA;
+       ath9k_ps_restore(sc);
+       mutex_unlock(&sc->mutex);
 
-       clr = AR_PCIE_PM_CTRL_ENA;
-       REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr);
+       return 0;
+}
 
-       /*
-        * this is needed to prevent the chip waking up
-        * the host within 3-4 seconds with certain
-        * platform/BIOS. The fix is to enable
-        * D1 & D3 to match original definition and
-        * also match the OTP value. Anyway this
-        * is more related to SW WOW.
-        */
-       clr = AR_PMCTRL_PWR_STATE_D1D3;
-       REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
+void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
+{
+       struct ath_softc *sc = hw->priv;
 
-       set = AR_PMCTRL_PWR_STATE_D1D3_REAL;
-       REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
+       mutex_lock(&sc->mutex);
+       device_init_wakeup(sc->dev, 1);
+       device_set_wakeup_enable(sc->dev, enabled);
+       mutex_unlock(&sc->mutex);
+}
 
-       REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
+void ath9k_init_wow(struct ieee80211_hw *hw)
+{
+       struct ath_softc *sc = hw->priv;
 
-       /* to bring down WOW power low margin */
-       set = BIT(13);
-       REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);
-       /* HW WoW */
-       clr = BIT(5);
-       REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
+       if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) &&
+           (sc->driver_data & ATH9K_PCI_WOW) &&
+           device_can_wakeup(sc->dev))
+               hw->wiphy->wowlan = &ath9k_wowlan_support;
 
-       ath9k_hw_set_powermode_wow_sleep(ah);
-       ah->wow_event_mask = wow_event_mask;
+       atomic_set(&sc->wow_sleep_proc_intr, -1);
+       atomic_set(&sc->wow_got_bmiss_intr, -1);
 }
-EXPORT_SYMBOL(ath9k_hw_wow_enable);
index 09cdbcd097394a3a2c324230c2743f5d181b0900..24846d91554b98f56fb07caed59a4ccfb5ff8684 100644 (file)
@@ -1786,6 +1786,9 @@ bool ath_drain_all_txq(struct ath_softc *sc)
                if (!ATH_TXQ_SETUP(sc, i))
                        continue;
 
+               if (!sc->tx.txq[i].axq_depth)
+                       continue;
+
                if (ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum))
                        npend |= BIT(i);
        }
@@ -2749,6 +2752,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
        }
 }
 
+#ifdef CONFIG_ATH9K_TX99
+
 int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
                    struct ath_tx_control *txctl)
 {
@@ -2791,3 +2796,5 @@ int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
 
        return 0;
 }
+
+#endif /* CONFIG_ATH9K_TX99 */
index 1217c52ab28e6b07847217890bb6f1d9840a84b1..9e154732afaacfefe661befa0053e881ba083106 100644 (file)
@@ -37,17 +37,18 @@ static int __ath_regd_init(struct ath_regulatory *reg);
 
 /* We enable active scan on these a case by case basis by regulatory domain */
 #define ATH9K_2GHZ_CH12_13     REG_RULE(2467-10, 2472+10, 40, 0, 20,\
-                                       NL80211_RRF_PASSIVE_SCAN)
+                                        NL80211_RRF_NO_IR)
 #define ATH9K_2GHZ_CH14                REG_RULE(2484-10, 2484+10, 40, 0, 20,\
-                               NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
+                                        NL80211_RRF_NO_IR | \
+                                        NL80211_RRF_NO_OFDM)
 
 /* We allow IBSS on these on a case by case basis by regulatory domain */
 #define ATH9K_5GHZ_5150_5350   REG_RULE(5150-10, 5350+10, 80, 0, 30,\
-                               NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 #define ATH9K_5GHZ_5470_5850   REG_RULE(5470-10, 5850+10, 80, 0, 30,\
-                               NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 #define ATH9K_5GHZ_5725_5850   REG_RULE(5725-10, 5850+10, 80, 0, 30,\
-                               NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 
 #define ATH9K_2GHZ_ALL         ATH9K_2GHZ_CH01_11, \
                                ATH9K_2GHZ_CH12_13, \
@@ -113,6 +114,87 @@ static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {
        }
 };
 
+static bool dynamic_country_user_possible(struct ath_regulatory *reg)
+{
+       if (config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING))
+               return true;
+
+       switch (reg->country_code) {
+       case CTRY_UNITED_STATES:
+       case CTRY_JAPAN1:
+       case CTRY_JAPAN2:
+       case CTRY_JAPAN3:
+       case CTRY_JAPAN4:
+       case CTRY_JAPAN5:
+       case CTRY_JAPAN6:
+       case CTRY_JAPAN7:
+       case CTRY_JAPAN8:
+       case CTRY_JAPAN9:
+       case CTRY_JAPAN10:
+       case CTRY_JAPAN11:
+       case CTRY_JAPAN12:
+       case CTRY_JAPAN13:
+       case CTRY_JAPAN14:
+       case CTRY_JAPAN15:
+       case CTRY_JAPAN16:
+       case CTRY_JAPAN17:
+       case CTRY_JAPAN18:
+       case CTRY_JAPAN19:
+       case CTRY_JAPAN20:
+       case CTRY_JAPAN21:
+       case CTRY_JAPAN22:
+       case CTRY_JAPAN23:
+       case CTRY_JAPAN24:
+       case CTRY_JAPAN25:
+       case CTRY_JAPAN26:
+       case CTRY_JAPAN27:
+       case CTRY_JAPAN28:
+       case CTRY_JAPAN29:
+       case CTRY_JAPAN30:
+       case CTRY_JAPAN31:
+       case CTRY_JAPAN32:
+       case CTRY_JAPAN33:
+       case CTRY_JAPAN34:
+       case CTRY_JAPAN35:
+       case CTRY_JAPAN36:
+       case CTRY_JAPAN37:
+       case CTRY_JAPAN38:
+       case CTRY_JAPAN39:
+       case CTRY_JAPAN40:
+       case CTRY_JAPAN41:
+       case CTRY_JAPAN42:
+       case CTRY_JAPAN43:
+       case CTRY_JAPAN44:
+       case CTRY_JAPAN45:
+       case CTRY_JAPAN46:
+       case CTRY_JAPAN47:
+       case CTRY_JAPAN48:
+       case CTRY_JAPAN49:
+       case CTRY_JAPAN50:
+       case CTRY_JAPAN51:
+       case CTRY_JAPAN52:
+       case CTRY_JAPAN53:
+       case CTRY_JAPAN54:
+       case CTRY_JAPAN55:
+       case CTRY_JAPAN56:
+       case CTRY_JAPAN57:
+       case CTRY_JAPAN58:
+       case CTRY_JAPAN59:
+               return false;
+       }
+
+       return true;
+}
+
+static bool ath_reg_dyn_country_user_allow(struct ath_regulatory *reg)
+{
+       if (!config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS))
+               return false;
+       if (!dynamic_country_user_possible(reg))
+               return false;
+       return true;
+}
+
 static inline bool is_wwr_sku(u16 regd)
 {
        return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) &&
@@ -177,118 +259,139 @@ static bool ath_is_radar_freq(u16 center_freq)
        return (center_freq >= 5260 && center_freq <= 5700);
 }
 
+static void ath_force_clear_no_ir_chan(struct wiphy *wiphy,
+                                      struct ieee80211_channel *ch)
+{
+       const struct ieee80211_reg_rule *reg_rule;
+
+       reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq));
+       if (IS_ERR(reg_rule))
+               return;
+
+       if (!(reg_rule->flags & NL80211_RRF_NO_IR))
+               if (ch->flags & IEEE80211_CHAN_NO_IR)
+                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
+}
+
+static void ath_force_clear_no_ir_freq(struct wiphy *wiphy, u16 center_freq)
+{
+       struct ieee80211_channel *ch;
+
+       ch = ieee80211_get_channel(wiphy, center_freq);
+       if (!ch)
+               return;
+
+       ath_force_clear_no_ir_chan(wiphy, ch);
+}
+
+static void ath_force_no_ir_chan(struct ieee80211_channel *ch)
+{
+       ch->flags |= IEEE80211_CHAN_NO_IR;
+}
+
+static void ath_force_no_ir_freq(struct wiphy *wiphy, u16 center_freq)
+{
+       struct ieee80211_channel *ch;
+
+       ch = ieee80211_get_channel(wiphy, center_freq);
+       if (!ch)
+               return;
+
+       ath_force_no_ir_chan(ch);
+}
+
+static void
+__ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
+                               struct ath_regulatory *reg,
+                               enum nl80211_reg_initiator initiator,
+                               struct ieee80211_channel *ch)
+{
+       if (ath_is_radar_freq(ch->center_freq) ||
+           (ch->flags & IEEE80211_CHAN_RADAR))
+               return;
+
+       switch (initiator) {
+       case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+               ath_force_clear_no_ir_chan(wiphy, ch);
+               break;
+       case NL80211_REGDOM_SET_BY_USER:
+               if (ath_reg_dyn_country_user_allow(reg))
+                       ath_force_clear_no_ir_chan(wiphy, ch);
+               break;
+       default:
+               if (ch->beacon_found)
+                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
+       }
+}
+
 /*
- * N.B: These exception rules do not apply radar freqs.
+ * These exception rules do not apply radar frequencies.
  *
- * - We enable adhoc (or beaconing) if allowed by 11d
- * - We enable active scan if the channel is allowed by 11d
+ * - We enable initiating radiation if the country IE says its fine:
  * - If no country IE has been processed and a we determine we have
- *   received a beacon on a channel we can enable active scan and
- *   adhoc (or beaconing).
+ *   received a beacon on a channel we can enable initiating radiation.
  */
 static void
 ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
+                             struct ath_regulatory *reg,
                              enum nl80211_reg_initiator initiator)
 {
        enum ieee80211_band band;
        struct ieee80211_supported_band *sband;
-       const struct ieee80211_reg_rule *reg_rule;
        struct ieee80211_channel *ch;
        unsigned int i;
 
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
-
                if (!wiphy->bands[band])
                        continue;
-
                sband = wiphy->bands[band];
-
                for (i = 0; i < sband->n_channels; i++) {
-
                        ch = &sband->channels[i];
-
-                       if (ath_is_radar_freq(ch->center_freq) ||
-                           (ch->flags & IEEE80211_CHAN_RADAR))
-                               continue;
-
-                       if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-                               reg_rule = freq_reg_info(wiphy, ch->center_freq);
-                               if (IS_ERR(reg_rule))
-                                       continue;
-                               /*
-                                * If 11d had a rule for this channel ensure
-                                * we enable adhoc/beaconing if it allows us to
-                                * use it. Note that we would have disabled it
-                                * by applying our static world regdomain by
-                                * default during init, prior to calling our
-                                * regulatory_hint().
-                                */
-                               if (!(reg_rule->flags &
-                                   NL80211_RRF_NO_IBSS))
-                                       ch->flags &=
-                                         ~IEEE80211_CHAN_NO_IBSS;
-                               if (!(reg_rule->flags &
-                                   NL80211_RRF_PASSIVE_SCAN))
-                                       ch->flags &=
-                                         ~IEEE80211_CHAN_PASSIVE_SCAN;
-                       } else {
-                               if (ch->beacon_found)
-                                       ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
-                                         IEEE80211_CHAN_PASSIVE_SCAN);
-                       }
+                       __ath_reg_apply_beaconing_flags(wiphy, reg,
+                                                       initiator, ch);
                }
        }
-
 }
 
-/* Allows active scan scan on Ch 12 and 13 */
+/**
+ * ath_reg_apply_ir_flags()
+ * @wiphy: the wiphy to use
+ * @initiator: the regulatory hint initiator
+ *
+ * If no country IE has been received always enable passive scan
+ * and no-ibss on these channels. This is only done for specific
+ * regulatory SKUs.
+ *
+ * If a country IE has been received check its rule for this
+ * channel first before enabling active scan. The passive scan
+ * would have been enforced by the initial processing of our
+ * custom regulatory domain.
+ */
 static void
-ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
-                               enum nl80211_reg_initiator initiator)
+ath_reg_apply_ir_flags(struct wiphy *wiphy,
+                      struct ath_regulatory *reg,
+                      enum nl80211_reg_initiator initiator)
 {
        struct ieee80211_supported_band *sband;
-       struct ieee80211_channel *ch;
-       const struct ieee80211_reg_rule *reg_rule;
 
        sband = wiphy->bands[IEEE80211_BAND_2GHZ];
        if (!sband)
                return;
 
-       /*
-        * If no country IE has been received always enable active scan
-        * on these channels. This is only done for specific regulatory SKUs
-        */
-       if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-               ch = &sband->channels[11]; /* CH 12 */
-               if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                       ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
-               ch = &sband->channels[12]; /* CH 13 */
-               if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                       ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
-               return;
-       }
-
-       /*
-        * If a country IE has been received check its rule for this
-        * channel first before enabling active scan. The passive scan
-        * would have been enforced by the initial processing of our
-        * custom regulatory domain.
-        */
-
-       ch = &sband->channels[11]; /* CH 12 */
-       reg_rule = freq_reg_info(wiphy, ch->center_freq);
-       if (!IS_ERR(reg_rule)) {
-               if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
-                       if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                               ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
-       }
-
-       ch = &sband->channels[12]; /* CH 13 */
-       reg_rule = freq_reg_info(wiphy, ch->center_freq);
-       if (!IS_ERR(reg_rule)) {
-               if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
-                       if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                               ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+       switch(initiator) {
+       case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+               ath_force_clear_no_ir_freq(wiphy, 2467);
+               ath_force_clear_no_ir_freq(wiphy, 2472);
+               break;
+       case NL80211_REGDOM_SET_BY_USER:
+               if (!ath_reg_dyn_country_user_allow(reg))
+                       break;
+               ath_force_clear_no_ir_freq(wiphy, 2467);
+               ath_force_clear_no_ir_freq(wiphy, 2472);
+               break;
+       default:
+               ath_force_no_ir_freq(wiphy, 2467);
+               ath_force_no_ir_freq(wiphy, 2472);
        }
 }
 
@@ -320,8 +423,7 @@ static void ath_reg_apply_radar_flags(struct wiphy *wiphy)
                 */
                if (!(ch->flags & IEEE80211_CHAN_DISABLED))
                        ch->flags |= IEEE80211_CHAN_RADAR |
-                                    IEEE80211_CHAN_NO_IBSS |
-                                    IEEE80211_CHAN_PASSIVE_SCAN;
+                                    IEEE80211_CHAN_NO_IR;
        }
 }
 
@@ -335,12 +437,15 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy,
        case 0x66:
        case 0x67:
        case 0x6C:
-               ath_reg_apply_beaconing_flags(wiphy, initiator);
+               ath_reg_apply_beaconing_flags(wiphy, reg, initiator);
                break;
        case 0x68:
-               ath_reg_apply_beaconing_flags(wiphy, initiator);
-               ath_reg_apply_active_scan_flags(wiphy, initiator);
+               ath_reg_apply_beaconing_flags(wiphy, reg, initiator);
+               ath_reg_apply_ir_flags(wiphy, reg, initiator);
                break;
+       default:
+               if (ath_reg_dyn_country_user_allow(reg))
+                       ath_reg_apply_beaconing_flags(wiphy, reg, initiator);
        }
 }
 
@@ -393,89 +498,6 @@ static void ath_reg_dyn_country(struct wiphy *wiphy,
               reg_initiator_name(request->initiator));
 }
 
-static bool dynamic_country_user_possible(struct ath_regulatory *reg)
-{
-       if (config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING))
-               return true;
-
-       switch (reg->country_code) {
-       case CTRY_UNITED_STATES:
-       case CTRY_JAPAN1:
-       case CTRY_JAPAN2:
-       case CTRY_JAPAN3:
-       case CTRY_JAPAN4:
-       case CTRY_JAPAN5:
-       case CTRY_JAPAN6:
-       case CTRY_JAPAN7:
-       case CTRY_JAPAN8:
-       case CTRY_JAPAN9:
-       case CTRY_JAPAN10:
-       case CTRY_JAPAN11:
-       case CTRY_JAPAN12:
-       case CTRY_JAPAN13:
-       case CTRY_JAPAN14:
-       case CTRY_JAPAN15:
-       case CTRY_JAPAN16:
-       case CTRY_JAPAN17:
-       case CTRY_JAPAN18:
-       case CTRY_JAPAN19:
-       case CTRY_JAPAN20:
-       case CTRY_JAPAN21:
-       case CTRY_JAPAN22:
-       case CTRY_JAPAN23:
-       case CTRY_JAPAN24:
-       case CTRY_JAPAN25:
-       case CTRY_JAPAN26:
-       case CTRY_JAPAN27:
-       case CTRY_JAPAN28:
-       case CTRY_JAPAN29:
-       case CTRY_JAPAN30:
-       case CTRY_JAPAN31:
-       case CTRY_JAPAN32:
-       case CTRY_JAPAN33:
-       case CTRY_JAPAN34:
-       case CTRY_JAPAN35:
-       case CTRY_JAPAN36:
-       case CTRY_JAPAN37:
-       case CTRY_JAPAN38:
-       case CTRY_JAPAN39:
-       case CTRY_JAPAN40:
-       case CTRY_JAPAN41:
-       case CTRY_JAPAN42:
-       case CTRY_JAPAN43:
-       case CTRY_JAPAN44:
-       case CTRY_JAPAN45:
-       case CTRY_JAPAN46:
-       case CTRY_JAPAN47:
-       case CTRY_JAPAN48:
-       case CTRY_JAPAN49:
-       case CTRY_JAPAN50:
-       case CTRY_JAPAN51:
-       case CTRY_JAPAN52:
-       case CTRY_JAPAN53:
-       case CTRY_JAPAN54:
-       case CTRY_JAPAN55:
-       case CTRY_JAPAN56:
-       case CTRY_JAPAN57:
-       case CTRY_JAPAN58:
-       case CTRY_JAPAN59:
-               return false;
-       }
-
-       return true;
-}
-
-static void ath_reg_dyn_country_user(struct wiphy *wiphy,
-                                    struct ath_regulatory *reg,
-                                    struct regulatory_request *request)
-{
-       if (!config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS))
-               return;
-       if (!dynamic_country_user_possible(reg))
-               return;
-       ath_reg_dyn_country(wiphy, reg, request);
-}
-
 void ath_reg_notifier_apply(struct wiphy *wiphy,
                            struct regulatory_request *request,
                            struct ath_regulatory *reg)
@@ -508,7 +530,8 @@ void ath_reg_notifier_apply(struct wiphy *wiphy,
        case NL80211_REGDOM_SET_BY_DRIVER:
                break;
        case NL80211_REGDOM_SET_BY_USER:
-               ath_reg_dyn_country_user(wiphy, reg, request);
+               if (ath_reg_dyn_country_user_allow(reg))
+                       ath_reg_dyn_country(wiphy, reg, request);
                break;
        case NL80211_REGDOM_SET_BY_COUNTRY_IE:
                ath_reg_dyn_country(wiphy, reg, request);
@@ -609,7 +632,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
        const struct ieee80211_regdomain *regd;
 
        wiphy->reg_notifier = reg_notifier;
-       wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
+       wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
 
        if (ath_is_world_regd(reg)) {
                /*
@@ -617,7 +640,8 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
                 * saved on the wiphy orig_* parameters
                 */
                regd = ath_world_regdomain(reg);
-               wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+               wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+                                          REGULATORY_COUNTRY_IE_FOLLOW_POWER;
        } else {
                /*
                 * This gets applied in the case of the absence of CRDA,
index c02dbc618724720cee3c97a3fa86a249188fff5b..3c2ef0c32f72c7ef37b9b032e3b66ec3ab9619d6 100644 (file)
@@ -2644,7 +2644,7 @@ struct wcn36xx_hal_trigger_ba_rsp_candidate {
        struct add_ba_info ba_info[STACFG_MAX_TC];
 } __packed;
 
-struct wcn36xx_hal_trigget_ba_req_candidate {
+struct wcn36xx_hal_trigger_ba_req_candidate {
        u8 sta_index;
        u8 tid_bitmap;
 } __packed;
index 7839b31e4826e5013a391b94f405483f6c4e977f..e64a6784079e20446ad57078f607e0f01b7565a1 100644 (file)
@@ -641,7 +641,8 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
                dev_kfree_skb(skb);
        }
 
-       if (changed & BSS_CHANGED_BEACON_ENABLED) {
+       if (changed & BSS_CHANGED_BEACON_ENABLED ||
+           changed & BSS_CHANGED_BEACON) {
                wcn36xx_dbg(WCN36XX_DBG_MAC,
                            "mac bss changed beacon enabled %d\n",
                            bss_conf->enable_beacon);
index 366339421d4f1c924e4e1e69c34ce88bce9ab028..823631cdb872bc8799229a9d91388d377a5511fc 100644 (file)
@@ -115,6 +115,22 @@ static void wcn36xx_smd_set_sta_ht_params(struct ieee80211_sta *sta,
        }
 }
 
+static void wcn36xx_smd_set_sta_default_ht_params(
+               struct wcn36xx_hal_config_sta_params *sta_params)
+{
+       sta_params->ht_capable = 1;
+       sta_params->tx_channel_width_set = 1;
+       sta_params->lsig_txop_protection = 1;
+       sta_params->max_ampdu_size = 3;
+       sta_params->max_ampdu_density = 5;
+       sta_params->max_amsdu_size = 0;
+       sta_params->sgi_20Mhz = 1;
+       sta_params->sgi_40mhz = 1;
+       sta_params->green_field_capable = 1;
+       sta_params->delayed_ba_support = 0;
+       sta_params->dsss_cck_mode_40mhz = 1;
+}
+
 static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
                struct ieee80211_vif *vif,
                struct ieee80211_sta *sta,
@@ -172,6 +188,7 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
                        sizeof(priv_sta->supported_rates));
        } else {
                wcn36xx_set_default_rates(&sta_params->supported_rates);
+               wcn36xx_smd_set_sta_default_ht_params(sta_params);
        }
 }
 
@@ -1838,7 +1855,7 @@ out:
 int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index)
 {
        struct wcn36xx_hal_trigger_ba_req_msg msg_body;
-       struct wcn36xx_hal_trigget_ba_req_candidate *candidate;
+       struct wcn36xx_hal_trigger_ba_req_candidate *candidate;
        int ret = 0;
 
        mutex_lock(&wcn->hal_mutex);
@@ -1849,7 +1866,7 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index)
        msg_body.header.len += sizeof(*candidate);
        PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
 
-       candidate = (struct wcn36xx_hal_trigget_ba_req_candidate *)
+       candidate = (struct wcn36xx_hal_trigger_ba_req_candidate *)
                (wcn->hal_buf + sizeof(msg_body));
        candidate->sta_index = sta_index;
        candidate->tid_bitmap = 1;
index 58b63833e8e72d1d8dee64b31c14374369ecb072..8fa5cbace5abba1e027954a64b312bdc37f7b13c 100644 (file)
@@ -54,7 +54,7 @@ enum wcn36xx_debug_mask {
 };
 
 #define wcn36xx_err(fmt, arg...)                               \
-       printk(KERN_ERR pr_fmt("ERROR " fmt), ##arg);
+       printk(KERN_ERR pr_fmt("ERROR " fmt), ##arg)
 
 #define wcn36xx_warn(fmt, arg...)                              \
        printk(KERN_WARNING pr_fmt("WARNING " fmt), ##arg)
index 54e36fcb39542e8361dfdc019134f3ba1538de8f..fcfed6b99a62d6e16e66634df2df85198cbb64da 100644 (file)
@@ -4,13 +4,12 @@ config BRCMUTIL
 config BRCMSMAC
        tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver"
        depends on MAC80211
-       depends on BCMA
+       depends on BCMA_POSSIBLE
+       select BCMA
        select NEW_LEDS if BCMA_DRIVER_GPIO
        select LEDS_CLASS if BCMA_DRIVER_GPIO
        select BRCMUTIL
        select FW_LOADER
-       select CRC_CCITT
-       select CRC8
        select CORDIC
        ---help---
          This module adds support for PCIe wireless adapters based on Broadcom
index 8e9b1221b32c1918f7981cf2d4228b44684ac091..2082402d4b6364e03424f4ef00161b0fae9c298b 100644 (file)
@@ -28,7 +28,8 @@ brcmfmac-objs += \
                fweh.o \
                fwsignal.o \
                p2p.o \
-               dhd_cdc.o \
+               proto.o \
+               bcdc.o \
                dhd_common.o \
                dhd_linux.o \
                btcoex.o
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
new file mode 100644 (file)
index 0000000..06848e4
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * 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.
+ */
+
+/*******************************************************************************
+ * Communicates with the dongle by using dcmd codes.
+ * For certain dcmd codes, the dongle interprets string data from the host.
+ ******************************************************************************/
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+
+#include "dhd.h"
+#include "dhd_bus.h"
+#include "fwsignal.h"
+#include "dhd_dbg.h"
+#include "tracepoint.h"
+#include "proto.h"
+#include "bcdc.h"
+
+struct brcmf_proto_bcdc_dcmd {
+       __le32 cmd;     /* dongle command value */
+       __le32 len;     /* lower 16: output buflen;
+                        * upper 16: input buflen (excludes header) */
+       __le32 flags;   /* flag defns given below */
+       __le32 status;  /* status code returned from the device */
+};
+
+/* Max valid buffer size that can be sent to the dongle */
+#define BCDC_MAX_MSG_SIZE      (ETH_FRAME_LEN+ETH_FCS_LEN)
+
+/* BCDC flag definitions */
+#define BCDC_DCMD_ERROR                0x01            /* 1=cmd failed */
+#define BCDC_DCMD_SET          0x02            /* 0=get, 1=set cmd */
+#define BCDC_DCMD_IF_MASK      0xF000          /* I/F index */
+#define BCDC_DCMD_IF_SHIFT     12
+#define BCDC_DCMD_ID_MASK      0xFFFF0000      /* id an cmd pairing */
+#define BCDC_DCMD_ID_SHIFT     16              /* ID Mask shift bits */
+#define BCDC_DCMD_ID(flags)    \
+       (((flags) & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT)
+
+/*
+ * BCDC header - Broadcom specific extension of CDC.
+ * Used on data packets to convey priority across USB.
+ */
+#define        BCDC_HEADER_LEN         4
+#define BCDC_PROTO_VER         2       /* Protocol version */
+#define BCDC_FLAG_VER_MASK     0xf0    /* Protocol version mask */
+#define BCDC_FLAG_VER_SHIFT    4       /* Protocol version shift */
+#define BCDC_FLAG_SUM_GOOD     0x04    /* Good RX checksums */
+#define BCDC_FLAG_SUM_NEEDED   0x08    /* Dongle needs to do TX checksums */
+#define BCDC_PRIORITY_MASK     0x7
+#define BCDC_FLAG2_IF_MASK     0x0f    /* packet rx interface in APSTA */
+#define BCDC_FLAG2_IF_SHIFT    0
+
+#define BCDC_GET_IF_IDX(hdr) \
+       ((int)((((hdr)->flags2) & BCDC_FLAG2_IF_MASK) >> BCDC_FLAG2_IF_SHIFT))
+#define BCDC_SET_IF_IDX(hdr, idx) \
+       ((hdr)->flags2 = (((hdr)->flags2 & ~BCDC_FLAG2_IF_MASK) | \
+       ((idx) << BCDC_FLAG2_IF_SHIFT)))
+
+/**
+ * struct brcmf_proto_bcdc_header - BCDC header format
+ *
+ * @flags: flags contain protocol and checksum info.
+ * @priority: 802.1d priority and USB flow control info (bit 4:7).
+ * @flags2: additional flags containing dongle interface index.
+ * @data_offset: start of packet data. header is following by firmware signals.
+ */
+struct brcmf_proto_bcdc_header {
+       u8 flags;
+       u8 priority;
+       u8 flags2;
+       u8 data_offset;
+};
+
+/*
+ * maximum length of firmware signal data between
+ * the BCDC header and packet data in the tx path.
+ */
+#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES       12
+
+#define RETRIES 2 /* # of retries to retrieve matching dcmd response */
+#define BUS_HEADER_LEN (16+64)         /* Must be atleast SDPCM_RESERVE
+                                        * (amount of header tha might be added)
+                                        * plus any space that might be needed
+                                        * for bus alignment padding.
+                                        */
+#define ROUND_UP_MARGIN        2048    /* Biggest bus block size possible for
+                                * round off at the end of buffer
+                                * Currently is SDIO
+                                */
+
+struct brcmf_bcdc {
+       u16 reqid;
+       u8 bus_header[BUS_HEADER_LEN];
+       struct brcmf_proto_bcdc_dcmd msg;
+       unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];
+};
+
+static int brcmf_proto_bcdc_msg(struct brcmf_pub *drvr)
+{
+       struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
+       int len = le32_to_cpu(bcdc->msg.len) +
+                       sizeof(struct brcmf_proto_bcdc_dcmd);
+
+       brcmf_dbg(BCDC, "Enter\n");
+
+       /* NOTE : bcdc->msg.len holds the desired length of the buffer to be
+        *        returned. Only up to BCDC_MAX_MSG_SIZE of this buffer area
+        *        is actually sent to the dongle
+        */
+       if (len > BCDC_MAX_MSG_SIZE)
+               len = BCDC_MAX_MSG_SIZE;
+
+       /* Send request */
+       return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len);
+}
+
+static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
+{
+       int ret;
+       struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
+
+       brcmf_dbg(BCDC, "Enter\n");
+       len += sizeof(struct brcmf_proto_bcdc_dcmd);
+       do {
+               ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&bcdc->msg,
+                                     len);
+               if (ret < 0)
+                       break;
+       } while (BCDC_DCMD_ID(le32_to_cpu(bcdc->msg.flags)) != id);
+
+       return ret;
+}
+
+static int
+brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
+                           void *buf, uint len)
+{
+       struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
+       struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
+       void *info;
+       int ret = 0, retries = 0;
+       u32 id, flags;
+
+       brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
+
+       memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));
+
+       msg->cmd = cpu_to_le32(cmd);
+       msg->len = cpu_to_le32(len);
+       flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT);
+       flags = (flags & ~BCDC_DCMD_IF_MASK) |
+               (ifidx << BCDC_DCMD_IF_SHIFT);
+       msg->flags = cpu_to_le32(flags);
+
+       if (buf)
+               memcpy(bcdc->buf, buf, len);
+
+       ret = brcmf_proto_bcdc_msg(drvr);
+       if (ret < 0) {
+               brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n",
+                         ret);
+               goto done;
+       }
+
+retry:
+       /* wait for interrupt and get first fragment */
+       ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len);
+       if (ret < 0)
+               goto done;
+
+       flags = le32_to_cpu(msg->flags);
+       id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT;
+
+       if ((id < bcdc->reqid) && (++retries < RETRIES))
+               goto retry;
+       if (id != bcdc->reqid) {
+               brcmf_err("%s: unexpected request id %d (expected %d)\n",
+                         brcmf_ifname(drvr, ifidx), id, bcdc->reqid);
+               ret = -EINVAL;
+               goto done;
+       }
+
+       /* Check info buffer */
+       info = (void *)&msg[1];
+
+       /* Copy info buffer */
+       if (buf) {
+               if (ret < (int)len)
+                       len = ret;
+               memcpy(buf, info, len);
+       }
+
+       /* Check the ERROR flag */
+       if (flags & BCDC_DCMD_ERROR)
+               ret = le32_to_cpu(msg->status);
+
+done:
+       return ret;
+}
+
+static int
+brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
+                         void *buf, uint len)
+{
+       struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
+       struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
+       int ret = 0;
+       u32 flags, id;
+
+       brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
+
+       memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));
+
+       msg->cmd = cpu_to_le32(cmd);
+       msg->len = cpu_to_le32(len);
+       flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT) | BCDC_DCMD_SET;
+       flags = (flags & ~BCDC_DCMD_IF_MASK) |
+               (ifidx << BCDC_DCMD_IF_SHIFT);
+       msg->flags = cpu_to_le32(flags);
+
+       if (buf)
+               memcpy(bcdc->buf, buf, len);
+
+       ret = brcmf_proto_bcdc_msg(drvr);
+       if (ret < 0)
+               goto done;
+
+       ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len);
+       if (ret < 0)
+               goto done;
+
+       flags = le32_to_cpu(msg->flags);
+       id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT;
+
+       if (id != bcdc->reqid) {
+               brcmf_err("%s: unexpected request id %d (expected %d)\n",
+                         brcmf_ifname(drvr, ifidx), id, bcdc->reqid);
+               ret = -EINVAL;
+               goto done;
+       }
+
+       /* Check the ERROR flag */
+       if (flags & BCDC_DCMD_ERROR)
+               ret = le32_to_cpu(msg->status);
+
+done:
+       return ret;
+}
+
+static void
+brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset,
+                        struct sk_buff *pktbuf)
+{
+       struct brcmf_proto_bcdc_header *h;
+
+       brcmf_dbg(BCDC, "Enter\n");
+
+       /* Push BDC header used to convey priority for buses that don't */
+       skb_push(pktbuf, BCDC_HEADER_LEN);
+
+       h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);
+
+       h->flags = (BCDC_PROTO_VER << BCDC_FLAG_VER_SHIFT);
+       if (pktbuf->ip_summed == CHECKSUM_PARTIAL)
+               h->flags |= BCDC_FLAG_SUM_NEEDED;
+
+       h->priority = (pktbuf->priority & BCDC_PRIORITY_MASK);
+       h->flags2 = 0;
+       h->data_offset = offset;
+       BCDC_SET_IF_IDX(h, ifidx);
+       trace_brcmf_bcdchdr(pktbuf->data);
+}
+
+static int
+brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
+                        struct sk_buff *pktbuf)
+{
+       struct brcmf_proto_bcdc_header *h;
+
+       brcmf_dbg(BCDC, "Enter\n");
+
+       /* Pop BCDC header used to convey priority for buses that don't */
+       if (pktbuf->len <= BCDC_HEADER_LEN) {
+               brcmf_dbg(INFO, "rx data too short (%d <= %d)\n",
+                         pktbuf->len, BCDC_HEADER_LEN);
+               return -EBADE;
+       }
+
+       trace_brcmf_bcdchdr(pktbuf->data);
+       h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);
+
+       *ifidx = BCDC_GET_IF_IDX(h);
+       if (*ifidx >= BRCMF_MAX_IFS) {
+               brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);
+               return -EBADE;
+       }
+       /* The ifidx is the idx to map to matching netdev/ifp. When receiving
+        * events this is easy because it contains the bssidx which maps
+        * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
+        * bssidx 1 is used for p2p0 and no data can be received or
+        * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
+        */
+       if (*ifidx)
+               (*ifidx)++;
+
+       if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) !=
+           BCDC_PROTO_VER) {
+               brcmf_err("%s: non-BCDC packet received, flags 0x%x\n",
+                         brcmf_ifname(drvr, *ifidx), h->flags);
+               return -EBADE;
+       }
+
+       if (h->flags & BCDC_FLAG_SUM_GOOD) {
+               brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
+                         brcmf_ifname(drvr, *ifidx), h->flags);
+               pktbuf->ip_summed = CHECKSUM_UNNECESSARY;
+       }
+
+       pktbuf->priority = h->priority & BCDC_PRIORITY_MASK;
+
+       skb_pull(pktbuf, BCDC_HEADER_LEN);
+       if (do_fws)
+               brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf);
+       else
+               skb_pull(pktbuf, h->data_offset << 2);
+
+       if (pktbuf->len == 0)
+               return -ENODATA;
+       return 0;
+}
+
+int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
+{
+       struct brcmf_bcdc *bcdc;
+
+       bcdc = kzalloc(sizeof(*bcdc), GFP_ATOMIC);
+       if (!bcdc)
+               goto fail;
+
+       /* ensure that the msg buf directly follows the cdc msg struct */
+       if ((unsigned long)(&bcdc->msg + 1) != (unsigned long)bcdc->buf) {
+               brcmf_err("struct brcmf_proto_bcdc is not correctly defined\n");
+               goto fail;
+       }
+
+       drvr->proto->hdrpush = brcmf_proto_bcdc_hdrpush;
+       drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull;
+       drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd;
+       drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd;
+       drvr->proto->pd = bcdc;
+
+       drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
+       drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN +
+                       sizeof(struct brcmf_proto_bcdc_dcmd) + ROUND_UP_MARGIN;
+       return 0;
+
+fail:
+       kfree(bcdc);
+       return -ENOMEM;
+}
+
+void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr)
+{
+       kfree(drvr->proto->pd);
+       drvr->proto->pd = NULL;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.h b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.h
new file mode 100644 (file)
index 0000000..17e8c03
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013 Broadcom Corporation
+ *
+ * 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 BRCMFMAC_BCDC_H
+#define BRCMFMAC_BCDC_H
+
+
+int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr);
+void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr);
+
+
+#endif /* BRCMFMAC_BCDC_H */
index 3e10b801eee84bc420867815ced96a3fca3428b4..91651ec7f13fedddaa7c18cce14c7654eb77404e 100644 (file)
@@ -17,7 +17,6 @@
 
 #include <linux/types.h>
 #include <linux/netdevice.h>
-#include <linux/export.h>
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/sched.h>
@@ -774,7 +773,6 @@ out:
 
        return ret;
 }
-EXPORT_SYMBOL(brcmf_sdio_probe);
 
 int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
 {
@@ -791,7 +789,6 @@ int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
 
        return 0;
 }
-EXPORT_SYMBOL(brcmf_sdio_remove);
 
 void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable)
 {
index abc9ceca70f3630251ad077fe307f05a8a979adc..a511c27122b8c01da665a586675fb10a74a19bfc 100644 (file)
@@ -158,10 +158,21 @@ int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func,
                }
        }
 
-       if (err_ret)
-               brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
-                         rw ? "write" : "read", func, regaddr, *byte, err_ret);
-
+       if (err_ret) {
+               /*
+                * SleepCSR register access can fail when
+                * waking up the device so reduce this noise
+                * in the logs.
+                */
+               if (regaddr != SBSDIO_FUNC1_SLEEPCSR)
+                       brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
+                                 rw ? "write" : "read", func, regaddr, *byte,
+                                 err_ret);
+               else
+                       brcmf_dbg(SDIO, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
+                                 rw ? "write" : "read", func, regaddr, *byte,
+                                 err_ret);
+       }
        return err_ret;
 }
 
@@ -269,6 +280,9 @@ static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
 int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
 {
        int err_ret = 0;
+       struct mmc_host *host;
+       struct sdio_func *func;
+       uint max_blocks;
 
        brcmf_dbg(SDIO, "\n");
 
@@ -290,6 +304,20 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
 
        brcmf_sdioh_enablefuncs(sdiodev);
 
+       /*
+        * determine host related variables after brcmf_sdio_probe()
+        * as func->cur_blksize is properly set and F2 init has been
+        * completed successfully.
+        */
+       func = sdiodev->func[2];
+       host = func->card->host;
+       sdiodev->sg_support = host->max_segs > 1;
+       max_blocks = min_t(uint, host->max_blk_count, 511u);
+       sdiodev->max_request_size = min_t(uint, host->max_req_size,
+                                         max_blocks * func->cur_blksize);
+       sdiodev->max_segment_count = min_t(uint, host->max_segs,
+                                          SG_MAX_SINGLE_ALLOC);
+       sdiodev->max_segment_size = host->max_seg_size;
 out:
        sdio_release_host(sdiodev->func[1]);
        brcmf_dbg(SDIO, "Done\n");
@@ -318,8 +346,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
        int err;
        struct brcmf_sdio_dev *sdiodev;
        struct brcmf_bus *bus_if;
-       struct mmc_host *host;
-       uint max_blocks;
 
        brcmf_dbg(SDIO, "Enter\n");
        brcmf_dbg(SDIO, "Class=%x\n", func->class);
@@ -367,19 +393,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
                goto fail;
        }
 
-       /*
-        * determine host related variables after brcmf_sdio_probe()
-        * as func->cur_blksize is properly set and F2 init has been
-        * completed successfully.
-        */
-       host = func->card->host;
-       sdiodev->sg_support = host->max_segs > 1;
-       max_blocks = min_t(uint, host->max_blk_count, 511u);
-       sdiodev->max_request_size = min_t(uint, host->max_req_size,
-                                         max_blocks * func->cur_blksize);
-       sdiodev->max_segment_count = min_t(uint, host->max_segs,
-                                          SG_MAX_SINGLE_ALLOC);
-       sdiodev->max_segment_size = host->max_seg_size;
        brcmf_dbg(SDIO, "F2 init completed...\n");
        return 0;
 
index 899a2ada5b8212f28e30632551910b67474e6080..252024bcbc3ba736c65d18975f2b5106e026737a 100644 (file)
 
 #include "fweh.h"
 
-/*******************************************************************************
- * IO codes that are interpreted by dongle firmware
- ******************************************************************************/
-#define BRCMF_C_GET_VERSION                    1
-#define BRCMF_C_UP                             2
-#define BRCMF_C_DOWN                           3
-#define BRCMF_C_SET_PROMISC                    10
-#define BRCMF_C_GET_RATE                       12
-#define BRCMF_C_GET_INFRA                      19
-#define BRCMF_C_SET_INFRA                      20
-#define BRCMF_C_GET_AUTH                       21
-#define BRCMF_C_SET_AUTH                       22
-#define BRCMF_C_GET_BSSID                      23
-#define BRCMF_C_GET_SSID                       25
-#define BRCMF_C_SET_SSID                       26
-#define BRCMF_C_TERMINATED                     28
-#define BRCMF_C_GET_CHANNEL                    29
-#define BRCMF_C_SET_CHANNEL                    30
-#define BRCMF_C_GET_SRL                                31
-#define BRCMF_C_SET_SRL                                32
-#define BRCMF_C_GET_LRL                                33
-#define BRCMF_C_SET_LRL                                34
-#define BRCMF_C_GET_RADIO                      37
-#define BRCMF_C_SET_RADIO                      38
-#define BRCMF_C_GET_PHYTYPE                    39
-#define BRCMF_C_SET_KEY                                45
-#define BRCMF_C_SET_PASSIVE_SCAN               49
-#define BRCMF_C_SCAN                           50
-#define BRCMF_C_SCAN_RESULTS                   51
-#define BRCMF_C_DISASSOC                       52
-#define BRCMF_C_REASSOC                                53
-#define BRCMF_C_SET_ROAM_TRIGGER               55
-#define BRCMF_C_SET_ROAM_DELTA                 57
-#define BRCMF_C_GET_BCNPRD                     75
-#define BRCMF_C_SET_BCNPRD                     76
-#define BRCMF_C_GET_DTIMPRD                    77
-#define BRCMF_C_SET_DTIMPRD                    78
-#define BRCMF_C_SET_COUNTRY                    84
-#define BRCMF_C_GET_PM                         85
-#define BRCMF_C_SET_PM                         86
-#define BRCMF_C_GET_CURR_RATESET               114
-#define BRCMF_C_GET_AP                         117
-#define BRCMF_C_SET_AP                         118
-#define BRCMF_C_GET_RSSI                       127
-#define BRCMF_C_GET_WSEC                       133
-#define BRCMF_C_SET_WSEC                       134
-#define BRCMF_C_GET_PHY_NOISE                  135
-#define BRCMF_C_GET_BSS_INFO                   136
-#define BRCMF_C_GET_BANDLIST                   140
-#define BRCMF_C_SET_SCB_TIMEOUT                        158
-#define BRCMF_C_GET_PHYLIST                    180
-#define BRCMF_C_SET_SCAN_CHANNEL_TIME          185
-#define BRCMF_C_SET_SCAN_UNASSOC_TIME          187
-#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON  201
-#define BRCMF_C_GET_VALID_CHANNELS             217
-#define BRCMF_C_GET_KEY_PRIMARY                        235
-#define BRCMF_C_SET_KEY_PRIMARY                        236
-#define BRCMF_C_SET_SCAN_PASSIVE_TIME          258
-#define BRCMF_C_GET_VAR                                262
-#define BRCMF_C_SET_VAR                                263
-
-/* phy types (returned by WLC_GET_PHYTPE) */
-#define        WLC_PHY_TYPE_A          0
-#define        WLC_PHY_TYPE_B          1
-#define        WLC_PHY_TYPE_G          2
-#define        WLC_PHY_TYPE_N          4
-#define        WLC_PHY_TYPE_LP         5
-#define        WLC_PHY_TYPE_SSN        6
-#define        WLC_PHY_TYPE_HT         7
-#define        WLC_PHY_TYPE_LCN        8
-#define        WLC_PHY_TYPE_NULL       0xf
-
 #define TOE_TX_CSUM_OL         0x00000001
 #define TOE_RX_CSUM_OL         0x00000002
 
-#define        BRCMF_BSS_INFO_VERSION  109 /* curr ver of brcmf_bss_info_le struct */
-
-/* size of brcmf_scan_params not including variable length array */
-#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
-
-/* masks for channel and ssid count */
-#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff
-#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16
-
-/* primary (ie tx) key */
-#define BRCMF_PRIMARY_KEY      (1 << 1)
-
 /* For supporting multiple interfaces */
 #define BRCMF_MAX_IFS  16
 
-#define DOT11_BSSTYPE_ANY                      2
 #define DOT11_MAX_DEFAULT_KEYS 4
 
-#define BRCMF_ESCAN_REQ_VERSION 1
-
-#define WLC_BSS_RSSI_ON_CHANNEL                0x0002
-
-#define BRCMF_MAXRATES_IN_SET          16      /* max # of rates in rateset */
-#define BRCMF_STA_ASSOC                        0x10            /* Associated */
-
-#define BRCMF_E_STATUS_SUCCESS                 0
-#define BRCMF_E_STATUS_FAIL                    1
-#define BRCMF_E_STATUS_TIMEOUT                 2
-#define BRCMF_E_STATUS_NO_NETWORKS             3
-#define BRCMF_E_STATUS_ABORT                   4
-#define BRCMF_E_STATUS_NO_ACK                  5
-#define BRCMF_E_STATUS_UNSOLICITED             6
-#define BRCMF_E_STATUS_ATTEMPT                 7
-#define BRCMF_E_STATUS_PARTIAL                 8
-#define BRCMF_E_STATUS_NEWSCAN                 9
-#define BRCMF_E_STATUS_NEWASSOC                        10
-#define BRCMF_E_STATUS_11HQUIET                        11
-#define BRCMF_E_STATUS_SUPPRESS                        12
-#define BRCMF_E_STATUS_NOCHANS                 13
-#define BRCMF_E_STATUS_CS_ABORT                        15
-#define BRCMF_E_STATUS_ERROR                   16
-
-#define BRCMF_E_REASON_INITIAL_ASSOC           0
-#define BRCMF_E_REASON_LOW_RSSI                        1
-#define BRCMF_E_REASON_DEAUTH                  2
-#define BRCMF_E_REASON_DISASSOC                        3
-#define BRCMF_E_REASON_BCNS_LOST               4
-#define BRCMF_E_REASON_MINTXRATE               9
-#define BRCMF_E_REASON_TXFAIL                  10
-
-#define BRCMF_E_REASON_LINK_BSSCFG_DIS         4
-#define BRCMF_E_REASON_FAST_ROAM_FAILED                5
-#define BRCMF_E_REASON_DIRECTED_ROAM           6
-#define BRCMF_E_REASON_TSPEC_REJECTED          7
-#define BRCMF_E_REASON_BETTER_AP               8
-
-#define BRCMF_E_PRUNE_ENCR_MISMATCH            1
-#define BRCMF_E_PRUNE_BCAST_BSSID              2
-#define BRCMF_E_PRUNE_MAC_DENY                 3
-#define BRCMF_E_PRUNE_MAC_NA                   4
-#define BRCMF_E_PRUNE_REG_PASSV                        5
-#define BRCMF_E_PRUNE_SPCT_MGMT                        6
-#define BRCMF_E_PRUNE_RADAR                    7
-#define BRCMF_E_RSN_MISMATCH                   8
-#define BRCMF_E_PRUNE_NO_COMMON_RATES          9
-#define BRCMF_E_PRUNE_BASIC_RATES              10
-#define BRCMF_E_PRUNE_CIPHER_NA                        12
-#define BRCMF_E_PRUNE_KNOWN_STA                        13
-#define BRCMF_E_PRUNE_WDS_PEER                 15
-#define BRCMF_E_PRUNE_QBSS_LOAD                        16
-#define BRCMF_E_PRUNE_HOME_AP                  17
-
-#define BRCMF_E_SUP_OTHER                      0
-#define BRCMF_E_SUP_DECRYPT_KEY_DATA           1
-#define BRCMF_E_SUP_BAD_UCAST_WEP128           2
-#define BRCMF_E_SUP_BAD_UCAST_WEP40            3
-#define BRCMF_E_SUP_UNSUP_KEY_LEN              4
-#define BRCMF_E_SUP_PW_KEY_CIPHER              5
-#define BRCMF_E_SUP_MSG3_TOO_MANY_IE           6
-#define BRCMF_E_SUP_MSG3_IE_MISMATCH           7
-#define BRCMF_E_SUP_NO_INSTALL_FLAG            8
-#define BRCMF_E_SUP_MSG3_NO_GTK                        9
-#define BRCMF_E_SUP_GRP_KEY_CIPHER             10
-#define BRCMF_E_SUP_GRP_MSG1_NO_GTK            11
-#define BRCMF_E_SUP_GTK_DECRYPT_FAIL           12
-#define BRCMF_E_SUP_SEND_FAIL                  13
-#define BRCMF_E_SUP_DEAUTH                     14
-
-#define BRCMF_E_IF_ADD                         1
-#define BRCMF_E_IF_DEL                         2
-#define BRCMF_E_IF_CHANGE                      3
-
-#define BRCMF_E_IF_FLAG_NOIF                   1
-
-#define BRCMF_E_IF_ROLE_STA                    0
-#define BRCMF_E_IF_ROLE_AP                     1
-#define BRCMF_E_IF_ROLE_WDS                    2
-
-#define BRCMF_E_LINK_BCN_LOSS                  1
-#define BRCMF_E_LINK_DISASSOC                  2
-#define BRCMF_E_LINK_ASSOC_REC                 3
-#define BRCMF_E_LINK_BSSCFG_DIS                        4
-
 /* Small, medium and maximum buffer size for dcmd
  */
 #define BRCMF_DCMD_SMLEN       256
 
 #define BRCMF_AMPDU_RX_REORDER_MAXFLOWS                256
 
-/* Pattern matching filter. Specifies an offset within received packets to
- * start matching, the pattern to match, the size of the pattern, and a bitmask
- * that indicates which bits within the pattern should be matched.
- */
-struct brcmf_pkt_filter_pattern_le {
-       /*
-        * Offset within received packet to start pattern matching.
-        * Offset '0' is the first byte of the ethernet header.
-        */
-       __le32 offset;
-       /* Size of the pattern.  Bitmask must be the same size.*/
-       __le32 size_bytes;
-       /*
-        * Variable length mask and pattern data. mask starts at offset 0.
-        * Pattern immediately follows mask.
-        */
-       u8 mask_and_pattern[1];
-};
-
-/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */
-struct brcmf_pkt_filter_le {
-       __le32 id;              /* Unique filter id, specified by app. */
-       __le32 type;            /* Filter type (WL_PKT_FILTER_TYPE_xxx). */
-       __le32 negate_match;    /* Negate the result of filter matches */
-       union {                 /* Filter definitions */
-               struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */
-       } u;
-};
-
-/* IOVAR "pkt_filter_enable" parameter. */
-struct brcmf_pkt_filter_enable_le {
-       __le32 id;              /* Unique filter id */
-       __le32 enable;          /* Enable/disable bool */
-};
-
-/* BSS info structure
- * Applications MUST CHECK ie_offset field and length field to access IEs and
- * next bss_info structure in a vector (in struct brcmf_scan_results)
- */
-struct brcmf_bss_info_le {
-       __le32 version;         /* version field */
-       __le32 length;          /* byte length of data in this record,
-                                * starting at version and including IEs
-                                */
-       u8 BSSID[ETH_ALEN];
-       __le16 beacon_period;   /* units are Kusec */
-       __le16 capability;      /* Capability information */
-       u8 SSID_len;
-       u8 SSID[32];
-       struct {
-               __le32 count;   /* # rates in this set */
-               u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */
-       } rateset;              /* supported rates */
-       __le16 chanspec;        /* chanspec for bss */
-       __le16 atim_window;     /* units are Kusec */
-       u8 dtim_period; /* DTIM period */
-       __le16 RSSI;            /* receive signal strength (in dBm) */
-       s8 phy_noise;           /* noise (in dBm) */
-
-       u8 n_cap;               /* BSS is 802.11N Capable */
-       /* 802.11N BSS Capabilities (based on HT_CAP_*): */
-       __le32 nbss_cap;
-       u8 ctl_ch;              /* 802.11N BSS control channel number */
-       __le32 reserved32[1];   /* Reserved for expansion of BSS properties */
-       u8 flags;               /* flags */
-       u8 reserved[3]; /* Reserved for expansion of BSS properties */
-       u8 basic_mcs[MCSSET_LEN];       /* 802.11N BSS required MCS set */
-
-       __le16 ie_offset;       /* offset at which IEs start, from beginning */
-       __le32 ie_length;       /* byte length of Information Elements */
-       __le16 SNR;             /* average SNR of during frame reception */
-       /* Add new fields here */
-       /* variable length Information Elements */
-};
-
-struct brcm_rateset_le {
-       /* # rates in this set */
-       __le32 count;
-       /* rates in 500kbps units w/hi bit set if basic */
-       u8 rates[BRCMF_MAXRATES_IN_SET];
-};
-
-struct brcmf_ssid {
-       u32 SSID_len;
-       unsigned char SSID[32];
-};
-
-struct brcmf_ssid_le {
-       __le32 SSID_len;
-       unsigned char SSID[32];
-};
-
-struct brcmf_scan_params_le {
-       struct brcmf_ssid_le ssid_le;   /* default: {0, ""} */
-       u8 bssid[ETH_ALEN];     /* default: bcast */
-       s8 bss_type;            /* default: any,
-                                * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT
-                                */
-       u8 scan_type;   /* flags, 0 use default */
-       __le32 nprobes;   /* -1 use default, number of probes per channel */
-       __le32 active_time;     /* -1 use default, dwell time per channel for
-                                * active scanning
-                                */
-       __le32 passive_time;    /* -1 use default, dwell time per channel
-                                * for passive scanning
-                                */
-       __le32 home_time;       /* -1 use default, dwell time for the
-                                * home channel between channel scans
-                                */
-       __le32 channel_num;     /* count of channels and ssids that follow
-                                *
-                                * low half is count of channels in
-                                * channel_list, 0 means default (use all
-                                * available channels)
-                                *
-                                * high half is entries in struct brcmf_ssid
-                                * array that follows channel_list, aligned for
-                                * s32 (4 bytes) meaning an odd channel count
-                                * implies a 2-byte pad between end of
-                                * channel_list and first ssid
-                                *
-                                * if ssid count is zero, single ssid in the
-                                * fixed parameter portion is assumed, otherwise
-                                * ssid in the fixed portion is ignored
-                                */
-       __le16 channel_list[1]; /* list of chanspecs */
-};
-
-struct brcmf_scan_results {
-       u32 buflen;
-       u32 version;
-       u32 count;
-       struct brcmf_bss_info_le bss_info_le[];
-};
-
-struct brcmf_escan_params_le {
-       __le32 version;
-       __le16 action;
-       __le16 sync_id;
-       struct brcmf_scan_params_le params_le;
-};
-
-struct brcmf_escan_result_le {
-       __le32 buflen;
-       __le32 version;
-       __le16 sync_id;
-       __le16 bss_count;
-       struct brcmf_bss_info_le bss_info_le;
-};
-
-#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(struct brcmf_escan_result_le) - \
-       sizeof(struct brcmf_bss_info_le))
-
-/* used for association with a specific BSSID and chanspec list */
-struct brcmf_assoc_params_le {
-       /* 00:00:00:00:00:00: broadcast scan */
-       u8 bssid[ETH_ALEN];
-       /* 0: all available channels, otherwise count of chanspecs in
-        * chanspec_list */
-       __le32 chanspec_num;
-       /* list of chanspecs */
-       __le16 chanspec_list[1];
-};
-
-/* used for join with or without a specific bssid and channel list */
-struct brcmf_join_params {
-       struct brcmf_ssid_le ssid_le;
-       struct brcmf_assoc_params_le params_le;
-};
-
-/* scan params for extended join */
-struct brcmf_join_scan_params_le {
-       u8 scan_type;           /* 0 use default, active or passive scan */
-       __le32 nprobes;         /* -1 use default, nr of probes per channel */
-       __le32 active_time;     /* -1 use default, dwell time per channel for
-                                * active scanning
-                                */
-       __le32 passive_time;    /* -1 use default, dwell time per channel
-                                * for passive scanning
-                                */
-       __le32 home_time;       /* -1 use default, dwell time for the home
-                                * channel between channel scans
-                                */
-};
-
-/* extended join params */
-struct brcmf_ext_join_params_le {
-       struct brcmf_ssid_le ssid_le;   /* {0, ""}: wildcard scan */
-       struct brcmf_join_scan_params_le scan_le;
-       struct brcmf_assoc_params_le assoc_le;
-};
-
-struct brcmf_wsec_key {
-       u32 index;              /* key index */
-       u32 len;                /* key length */
-       u8 data[WLAN_MAX_KEY_LEN];      /* key data */
-       u32 pad_1[18];
-       u32 algo;       /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
-       u32 flags;      /* misc flags */
-       u32 pad_2[3];
-       u32 iv_initialized;     /* has IV been initialized already? */
-       u32 pad_3;
-       /* Rx IV */
-       struct {
-               u32 hi; /* upper 32 bits of IV */
-               u16 lo; /* lower 16 bits of IV */
-       } rxiv;
-       u32 pad_4[2];
-       u8 ea[ETH_ALEN];        /* per station */
-};
-
-/*
- * dongle requires same struct as above but with fields in little endian order
+/* Length of firmware version string stored for
+ * ethtool driver info which uses 32 bytes as well.
  */
-struct brcmf_wsec_key_le {
-       __le32 index;           /* key index */
-       __le32 len;             /* key length */
-       u8 data[WLAN_MAX_KEY_LEN];      /* key data */
-       __le32 pad_1[18];
-       __le32 algo;    /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
-       __le32 flags;   /* misc flags */
-       __le32 pad_2[3];
-       __le32 iv_initialized;  /* has IV been initialized already? */
-       __le32 pad_3;
-       /* Rx IV */
-       struct {
-               __le32 hi;      /* upper 32 bits of IV */
-               __le16 lo;      /* lower 16 bits of IV */
-       } rxiv;
-       __le32 pad_4[2];
-       u8 ea[ETH_ALEN];        /* per station */
-};
-
-/* Used to get specific STA parameters */
-struct brcmf_scb_val_le {
-       __le32 val;
-       u8 ea[ETH_ALEN];
-};
-
-/* channel encoding */
-struct brcmf_channel_info_le {
-       __le32 hw_channel;
-       __le32 target_channel;
-       __le32 scan_channel;
-};
-
-struct brcmf_sta_info_le {
-       __le16  ver;            /* version of this struct */
-       __le16  len;            /* length in bytes of this structure */
-       __le16  cap;            /* sta's advertised capabilities */
-       __le32  flags;          /* flags defined below */
-       __le32  idle;           /* time since data pkt rx'd from sta */
-       u8      ea[ETH_ALEN];           /* Station address */
-       __le32  count;                  /* # rates in this set */
-       u8      rates[BRCMF_MAXRATES_IN_SET];   /* rates in 500kbps units */
-                                               /* w/hi bit set if basic */
-       __le32  in;             /* seconds elapsed since associated */
-       __le32  listen_interval_inms; /* Min Listen interval in ms for STA */
-       __le32  tx_pkts;        /* # of packets transmitted */
-       __le32  tx_failures;    /* # of packets failed */
-       __le32  rx_ucast_pkts;  /* # of unicast packets received */
-       __le32  rx_mcast_pkts;  /* # of multicast packets received */
-       __le32  tx_rate;        /* Rate of last successful tx frame */
-       __le32  rx_rate;        /* Rate of last successful rx frame */
-       __le32  rx_decrypt_succeeds;    /* # of packet decrypted successfully */
-       __le32  rx_decrypt_failures;    /* # of packet decrypted failed */
-};
-
-struct brcmf_chanspec_list {
-       __le32  count;          /* # of entries */
-       __le32  element[1];     /* variable length uint32 list */
-};
-
-/*
- * WLC_E_PROBRESP_MSG
- * WLC_E_P2P_PROBREQ_MSG
- * WLC_E_ACTION_FRAME_RX
- */
-struct brcmf_rx_mgmt_data {
-       __be16  version;
-       __be16  chanspec;
-       __be32  rssi;
-       __be32  mactime;
-       __be32  rate;
-};
+#define BRCMF_DRIVER_FIRMWARE_VERSION_LEN      32
 
 /* Bus independent dongle command */
 struct brcmf_dcmd {
@@ -535,7 +84,7 @@ struct brcmf_fws_info; /* firmware signalling info */
 struct brcmf_pub {
        /* Linkage ponters */
        struct brcmf_bus *bus_if;
-       struct brcmf_proto *prot;
+       struct brcmf_proto *proto;
        struct brcmf_cfg80211_info *config;
 
        /* Internal brcmf items */
@@ -544,7 +93,7 @@ struct brcmf_pub {
        u8 wme_dp;              /* wme discard priority */
 
        /* Dongle media info */
-       unsigned long drv_version;      /* Version of dongle-resident driver */
+       char fwver[BRCMF_DRIVER_FIRMWARE_VERSION_LEN];
        u8 mac[ETH_ALEN];               /* MAC address obtained from dongle */
 
        /* Multicast data packets sent to dongle */
@@ -566,14 +115,6 @@ struct brcmf_pub {
 #endif
 };
 
-struct brcmf_if_event {
-       u8 ifidx;
-       u8 action;
-       u8 flags;
-       u8 bssidx;
-       u8 role;
-};
-
 /* forward declarations */
 struct brcmf_cfg80211_vif;
 struct brcmf_fws_mac_descriptor;
@@ -635,16 +176,6 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
 /* Return pointer to interface name */
 char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
 
-/* Query dongle */
-int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
-                              void *buf, uint len);
-int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
-                            void *buf, uint len);
-
-/* Remove any protocol-specific data header. */
-int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
-                       struct sk_buff *rxp);
-
 int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
 struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
                              char *name, u8 *mac_addr);
@@ -655,4 +186,7 @@ u32 brcmf_get_chip_info(struct brcmf_if *ifp);
 void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp,
                      bool success);
 
+/* Sets dongle media info (drv_version, mac address). */
+int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
+
 #endif                         /* _BRCMF_H_ */
index a6eb09e5d46f408acf9205937ebffd772b15846d..6a54905528befd0238ce198acdbd6f9d642d1340 100644 (file)
@@ -34,6 +34,7 @@ struct brcmf_bus_dcmd {
 /**
  * struct brcmf_bus_ops - bus callback operations.
  *
+ * @preinit: execute bus/device specific dongle init commands (optional).
  * @init: prepare for communication with dongle.
  * @stop: clear pending frames, disable data flow.
  * @txdata: send a data frame to the dongle. When the data
@@ -51,6 +52,7 @@ struct brcmf_bus_dcmd {
  * indicated otherwise these callbacks are mandatory.
  */
 struct brcmf_bus_ops {
+       int (*preinit)(struct device *dev);
        int (*init)(struct device *dev);
        void (*stop)(struct device *dev);
        int (*txdata)(struct device *dev, struct sk_buff *skb);
@@ -85,7 +87,6 @@ struct brcmf_bus {
        unsigned long tx_realloc;
        u32 chip;
        u32 chiprev;
-       struct list_head dcmd_list;
 
        struct brcmf_bus_ops *ops;
 };
@@ -93,6 +94,13 @@ struct brcmf_bus {
 /*
  * callback wrappers
  */
+static inline int brcmf_bus_preinit(struct brcmf_bus *bus)
+{
+       if (!bus->ops->preinit)
+               return 0;
+       return bus->ops->preinit(bus->dev);
+}
+
 static inline int brcmf_bus_init(struct brcmf_bus *bus)
 {
        return bus->ops->init(bus->dev);
@@ -139,7 +147,7 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt,
 void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
 
 /* Indication from bus module regarding presence/insertion of dongle. */
-int brcmf_attach(uint bus_hdrlen, struct device *dev);
+int brcmf_attach(struct device *dev);
 /* Indication from bus module regarding removal/absence of dongle */
 void brcmf_detach(struct device *dev);
 /* Indication from bus module that dongle should be reset */
@@ -151,6 +159,9 @@ void brcmf_txflowblock(struct device *dev, bool state);
 void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success);
 
 int brcmf_bus_start(struct device *dev);
+s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data,
+                               u32 len);
+void brcmf_bus_add_txhdrlen(struct device *dev, uint len);
 
 #ifdef CONFIG_BRCMFMAC_SDIO
 void brcmf_sdio_exit(void);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
deleted file mode 100644 (file)
index dd85401..0000000
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * 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.
- */
-
-/*******************************************************************************
- * Communicates with the dongle by using dcmd codes.
- * For certain dcmd codes, the dongle interprets string data from the host.
- ******************************************************************************/
-
-#include <linux/types.h>
-#include <linux/netdevice.h>
-
-#include <brcmu_utils.h>
-#include <brcmu_wifi.h>
-
-#include "dhd.h"
-#include "dhd_proto.h"
-#include "dhd_bus.h"
-#include "fwsignal.h"
-#include "dhd_dbg.h"
-#include "tracepoint.h"
-
-struct brcmf_proto_cdc_dcmd {
-       __le32 cmd;     /* dongle command value */
-       __le32 len;     /* lower 16: output buflen;
-                        * upper 16: input buflen (excludes header) */
-       __le32 flags;   /* flag defns given below */
-       __le32 status;  /* status code returned from the device */
-};
-
-/* Max valid buffer size that can be sent to the dongle */
-#define CDC_MAX_MSG_SIZE       (ETH_FRAME_LEN+ETH_FCS_LEN)
-
-/* CDC flag definitions */
-#define CDC_DCMD_ERROR         0x01    /* 1=cmd failed */
-#define CDC_DCMD_SET           0x02    /* 0=get, 1=set cmd */
-#define CDC_DCMD_IF_MASK       0xF000          /* I/F index */
-#define CDC_DCMD_IF_SHIFT      12
-#define CDC_DCMD_ID_MASK       0xFFFF0000      /* id an cmd pairing */
-#define CDC_DCMD_ID_SHIFT      16              /* ID Mask shift bits */
-#define CDC_DCMD_ID(flags)     \
-       (((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT)
-
-/*
- * BDC header - Broadcom specific extension of CDC.
- * Used on data packets to convey priority across USB.
- */
-#define        BDC_HEADER_LEN          4
-#define BDC_PROTO_VER          2       /* Protocol version */
-#define BDC_FLAG_VER_MASK      0xf0    /* Protocol version mask */
-#define BDC_FLAG_VER_SHIFT     4       /* Protocol version shift */
-#define BDC_FLAG_SUM_GOOD      0x04    /* Good RX checksums */
-#define BDC_FLAG_SUM_NEEDED    0x08    /* Dongle needs to do TX checksums */
-#define BDC_PRIORITY_MASK      0x7
-#define BDC_FLAG2_IF_MASK      0x0f    /* packet rx interface in APSTA */
-#define BDC_FLAG2_IF_SHIFT     0
-
-#define BDC_GET_IF_IDX(hdr) \
-       ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT))
-#define BDC_SET_IF_IDX(hdr, idx) \
-       ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \
-       ((idx) << BDC_FLAG2_IF_SHIFT)))
-
-/**
- * struct brcmf_proto_bdc_header - BDC header format
- *
- * @flags: flags contain protocol and checksum info.
- * @priority: 802.1d priority and USB flow control info (bit 4:7).
- * @flags2: additional flags containing dongle interface index.
- * @data_offset: start of packet data. header is following by firmware signals.
- */
-struct brcmf_proto_bdc_header {
-       u8 flags;
-       u8 priority;
-       u8 flags2;
-       u8 data_offset;
-};
-
-/*
- * maximum length of firmware signal data between
- * the BDC header and packet data in the tx path.
- */
-#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES       12
-
-#define RETRIES 2 /* # of retries to retrieve matching dcmd response */
-#define BUS_HEADER_LEN (16+64)         /* Must be atleast SDPCM_RESERVE
-                                        * (amount of header tha might be added)
-                                        * plus any space that might be needed
-                                        * for bus alignment padding.
-                                        */
-#define ROUND_UP_MARGIN        2048    /* Biggest bus block size possible for
-                                * round off at the end of buffer
-                                * Currently is SDIO
-                                */
-
-struct brcmf_proto {
-       u16 reqid;
-       u8 bus_header[BUS_HEADER_LEN];
-       struct brcmf_proto_cdc_dcmd msg;
-       unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];
-};
-
-static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr)
-{
-       struct brcmf_proto *prot = drvr->prot;
-       int len = le32_to_cpu(prot->msg.len) +
-                       sizeof(struct brcmf_proto_cdc_dcmd);
-
-       brcmf_dbg(CDC, "Enter\n");
-
-       /* NOTE : cdc->msg.len holds the desired length of the buffer to be
-        *        returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
-        *        is actually sent to the dongle
-        */
-       if (len > CDC_MAX_MSG_SIZE)
-               len = CDC_MAX_MSG_SIZE;
-
-       /* Send request */
-       return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&prot->msg, len);
-}
-
-static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
-{
-       int ret;
-       struct brcmf_proto *prot = drvr->prot;
-
-       brcmf_dbg(CDC, "Enter\n");
-       len += sizeof(struct brcmf_proto_cdc_dcmd);
-       do {
-               ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&prot->msg,
-                                     len);
-               if (ret < 0)
-                       break;
-       } while (CDC_DCMD_ID(le32_to_cpu(prot->msg.flags)) != id);
-
-       return ret;
-}
-
-int
-brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
-                              void *buf, uint len)
-{
-       struct brcmf_proto *prot = drvr->prot;
-       struct brcmf_proto_cdc_dcmd *msg = &prot->msg;
-       void *info;
-       int ret = 0, retries = 0;
-       u32 id, flags;
-
-       brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);
-
-       memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
-
-       msg->cmd = cpu_to_le32(cmd);
-       msg->len = cpu_to_le32(len);
-       flags = (++prot->reqid << CDC_DCMD_ID_SHIFT);
-       flags = (flags & ~CDC_DCMD_IF_MASK) |
-               (ifidx << CDC_DCMD_IF_SHIFT);
-       msg->flags = cpu_to_le32(flags);
-
-       if (buf)
-               memcpy(prot->buf, buf, len);
-
-       ret = brcmf_proto_cdc_msg(drvr);
-       if (ret < 0) {
-               brcmf_err("brcmf_proto_cdc_msg failed w/status %d\n",
-                         ret);
-               goto done;
-       }
-
-retry:
-       /* wait for interrupt and get first fragment */
-       ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len);
-       if (ret < 0)
-               goto done;
-
-       flags = le32_to_cpu(msg->flags);
-       id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT;
-
-       if ((id < prot->reqid) && (++retries < RETRIES))
-               goto retry;
-       if (id != prot->reqid) {
-               brcmf_err("%s: unexpected request id %d (expected %d)\n",
-                         brcmf_ifname(drvr, ifidx), id, prot->reqid);
-               ret = -EINVAL;
-               goto done;
-       }
-
-       /* Check info buffer */
-       info = (void *)&msg[1];
-
-       /* Copy info buffer */
-       if (buf) {
-               if (ret < (int)len)
-                       len = ret;
-               memcpy(buf, info, len);
-       }
-
-       /* Check the ERROR flag */
-       if (flags & CDC_DCMD_ERROR)
-               ret = le32_to_cpu(msg->status);
-
-done:
-       return ret;
-}
-
-int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
-                                void *buf, uint len)
-{
-       struct brcmf_proto *prot = drvr->prot;
-       struct brcmf_proto_cdc_dcmd *msg = &prot->msg;
-       int ret = 0;
-       u32 flags, id;
-
-       brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);
-
-       memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
-
-       msg->cmd = cpu_to_le32(cmd);
-       msg->len = cpu_to_le32(len);
-       flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET;
-       flags = (flags & ~CDC_DCMD_IF_MASK) |
-               (ifidx << CDC_DCMD_IF_SHIFT);
-       msg->flags = cpu_to_le32(flags);
-
-       if (buf)
-               memcpy(prot->buf, buf, len);
-
-       ret = brcmf_proto_cdc_msg(drvr);
-       if (ret < 0)
-               goto done;
-
-       ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len);
-       if (ret < 0)
-               goto done;
-
-       flags = le32_to_cpu(msg->flags);
-       id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT;
-
-       if (id != prot->reqid) {
-               brcmf_err("%s: unexpected request id %d (expected %d)\n",
-                         brcmf_ifname(drvr, ifidx), id, prot->reqid);
-               ret = -EINVAL;
-               goto done;
-       }
-
-       /* Check the ERROR flag */
-       if (flags & CDC_DCMD_ERROR)
-               ret = le32_to_cpu(msg->status);
-
-done:
-       return ret;
-}
-
-static bool pkt_sum_needed(struct sk_buff *skb)
-{
-       return skb->ip_summed == CHECKSUM_PARTIAL;
-}
-
-static void pkt_set_sum_good(struct sk_buff *skb, bool x)
-{
-       skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE);
-}
-
-void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset,
-                        struct sk_buff *pktbuf)
-{
-       struct brcmf_proto_bdc_header *h;
-
-       brcmf_dbg(CDC, "Enter\n");
-
-       /* Push BDC header used to convey priority for buses that don't */
-       skb_push(pktbuf, BDC_HEADER_LEN);
-
-       h = (struct brcmf_proto_bdc_header *)(pktbuf->data);
-
-       h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
-       if (pkt_sum_needed(pktbuf))
-               h->flags |= BDC_FLAG_SUM_NEEDED;
-
-       h->priority = (pktbuf->priority & BDC_PRIORITY_MASK);
-       h->flags2 = 0;
-       h->data_offset = offset;
-       BDC_SET_IF_IDX(h, ifidx);
-       trace_brcmf_bdchdr(pktbuf->data);
-}
-
-int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
-                       struct sk_buff *pktbuf)
-{
-       struct brcmf_proto_bdc_header *h;
-
-       brcmf_dbg(CDC, "Enter\n");
-
-       /* Pop BDC header used to convey priority for buses that don't */
-
-       if (pktbuf->len <= BDC_HEADER_LEN) {
-               brcmf_dbg(INFO, "rx data too short (%d <= %d)\n",
-                         pktbuf->len, BDC_HEADER_LEN);
-               return -EBADE;
-       }
-
-       trace_brcmf_bdchdr(pktbuf->data);
-       h = (struct brcmf_proto_bdc_header *)(pktbuf->data);
-
-       *ifidx = BDC_GET_IF_IDX(h);
-       if (*ifidx >= BRCMF_MAX_IFS) {
-               brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);
-               return -EBADE;
-       }
-       /* The ifidx is the idx to map to matching netdev/ifp. When receiving
-        * events this is easy because it contains the bssidx which maps
-        * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
-        * bssidx 1 is used for p2p0 and no data can be received or
-        * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
-        */
-       if (*ifidx)
-               (*ifidx)++;
-
-       if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) !=
-           BDC_PROTO_VER) {
-               brcmf_err("%s: non-BDC packet received, flags 0x%x\n",
-                         brcmf_ifname(drvr, *ifidx), h->flags);
-               return -EBADE;
-       }
-
-       if (h->flags & BDC_FLAG_SUM_GOOD) {
-               brcmf_dbg(CDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
-                         brcmf_ifname(drvr, *ifidx), h->flags);
-               pkt_set_sum_good(pktbuf, true);
-       }
-
-       pktbuf->priority = h->priority & BDC_PRIORITY_MASK;
-
-       skb_pull(pktbuf, BDC_HEADER_LEN);
-       if (do_fws)
-               brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf);
-       else
-               skb_pull(pktbuf, h->data_offset << 2);
-
-       if (pktbuf->len == 0)
-               return -ENODATA;
-       return 0;
-}
-
-int brcmf_proto_attach(struct brcmf_pub *drvr)
-{
-       struct brcmf_proto *cdc;
-
-       cdc = kzalloc(sizeof(struct brcmf_proto), GFP_ATOMIC);
-       if (!cdc)
-               goto fail;
-
-       /* ensure that the msg buf directly follows the cdc msg struct */
-       if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) {
-               brcmf_err("struct brcmf_proto is not correctly defined\n");
-               goto fail;
-       }
-
-       drvr->prot = cdc;
-       drvr->hdrlen += BDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
-       drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN +
-                       sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN;
-       return 0;
-
-fail:
-       kfree(cdc);
-       return -ENOMEM;
-}
-
-/* ~NOTE~ What if another thread is waiting on the semaphore?  Holding it? */
-void brcmf_proto_detach(struct brcmf_pub *drvr)
-{
-       kfree(drvr->prot);
-       drvr->prot = NULL;
-}
-
-void brcmf_proto_stop(struct brcmf_pub *drvr)
-{
-       /* Nothing to do for CDC */
-}
index 9431af2465f3135fc76d5df370853a3b85a77d67..548dbb5542c63eb2631aafa8b2344013bfd90752 100644 (file)
@@ -21,9 +21,9 @@
 #include <brcmu_utils.h>
 #include "dhd.h"
 #include "dhd_bus.h"
-#include "dhd_proto.h"
 #include "dhd_dbg.h"
 #include "fwil.h"
+#include "fwil_types.h"
 #include "tracepoint.h"
 
 #define PKTFILTER_BUF_SIZE             128
@@ -257,8 +257,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
        u8 buf[BRCMF_DCMD_SMLEN];
        char *ptr;
        s32 err;
-       struct brcmf_bus_dcmd *cmdlst;
-       struct list_head *cur, *q;
 
        /* retreive mac address */
        err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
@@ -281,9 +279,14 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
        }
        ptr = (char *)buf;
        strsep(&ptr, "\n");
+
        /* Print fw version info */
        brcmf_err("Firmware version = %s\n", buf);
 
+       /* locate firmware version number for ethtool */
+       ptr = strrchr(buf, ' ') + 1;
+       strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));
+
        /*
         * Setup timeout if Beacons are lost and roam is off to report
         * link down
@@ -342,17 +345,8 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
        brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,
                                         0, true);
 
-       /* set bus specific command if there is any */
-       list_for_each_safe(cur, q, &ifp->drvr->bus_if->dcmd_list) {
-               cmdlst = list_entry(cur, struct brcmf_bus_dcmd, list);
-               if (cmdlst->name && cmdlst->param && cmdlst->param_len) {
-                       brcmf_fil_iovar_data_set(ifp, cmdlst->name,
-                                                cmdlst->param,
-                                                cmdlst->param_len);
-               }
-               list_del(cur);
-               kfree(cmdlst);
-       }
+       /* do bus specific preinit here */
+       err = brcmf_bus_preinit(ifp->drvr->bus_if);
 done:
        return err;
 }
index 0f9e9057e7dd2dea3868383990bf67b16cc23a65..03fe8aca4d3261c81f704f89853364f0f0bb7507 100644 (file)
@@ -22,7 +22,6 @@
 #include "dhd.h"
 #include "dhd_bus.h"
 #include "dhd_dbg.h"
-#include "tracepoint.h"
 
 static struct dentry *root_folder;
 
@@ -42,6 +41,40 @@ void brcmf_debugfs_exit(void)
        root_folder = NULL;
 }
 
+static
+ssize_t brcmf_debugfs_chipinfo_read(struct file *f, char __user *data,
+                                  size_t count, loff_t *ppos)
+{
+       struct brcmf_pub *drvr = f->private_data;
+       struct brcmf_bus *bus = drvr->bus_if;
+       char buf[40];
+       int res;
+
+       /* only allow read from start */
+       if (*ppos > 0)
+               return 0;
+
+       res = scnprintf(buf, sizeof(buf), "chip: %x(%u) rev %u\n",
+                       bus->chip, bus->chip, bus->chiprev);
+       return simple_read_from_buffer(data, count, ppos, buf, res);
+}
+
+static const struct file_operations brcmf_debugfs_chipinfo_ops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .read = brcmf_debugfs_chipinfo_read
+};
+
+static int brcmf_debugfs_create_chipinfo(struct brcmf_pub *drvr)
+{
+       struct dentry *dentry =  drvr->dbgfs_dir;
+
+       if (!IS_ERR_OR_NULL(dentry))
+               debugfs_create_file("chipinfo", S_IRUGO, dentry, drvr,
+                                   &brcmf_debugfs_chipinfo_ops);
+       return 0;
+}
+
 int brcmf_debugfs_attach(struct brcmf_pub *drvr)
 {
        struct device *dev = drvr->bus_if->dev;
@@ -50,6 +83,7 @@ int brcmf_debugfs_attach(struct brcmf_pub *drvr)
                return -ENODEV;
 
        drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
+       brcmf_debugfs_create_chipinfo(drvr);
        return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
 }
 
index 0af1f5dc583a8fd7dd9a550b6e3e5f585ab64925..ef52ed7abc69349640081292f5f862277900607c 100644 (file)
@@ -33,7 +33,7 @@
 #define BRCMF_USB_VAL  0x00002000
 #define BRCMF_SCAN_VAL 0x00004000
 #define BRCMF_CONN_VAL 0x00008000
-#define BRCMF_CDC_VAL  0x00010000
+#define BRCMF_BCDC_VAL 0x00010000
 #define BRCMF_SDIO_VAL 0x00020000
 
 /* set default print format */
index 64e9cff241b9156745bab110010520bfba730394..bce0b8e511fd22eb085077169050426f42714838 100644 (file)
 
 #include "dhd.h"
 #include "dhd_bus.h"
-#include "dhd_proto.h"
 #include "dhd_dbg.h"
 #include "fwil_types.h"
 #include "p2p.h"
 #include "wl_cfg80211.h"
 #include "fwil.h"
 #include "fwsignal.h"
+#include "proto.h"
 
 MODULE_AUTHOR("Broadcom Corporation");
 MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
@@ -592,28 +592,6 @@ static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
        return &ifp->stats;
 }
 
-/*
- * Set current toe component enables in toe_ol iovar,
- * and set toe global enable iovar
- */
-static int brcmf_toe_set(struct brcmf_if *ifp, u32 toe_ol)
-{
-       s32 err;
-
-       err = brcmf_fil_iovar_int_set(ifp, "toe_ol", toe_ol);
-       if (err < 0) {
-               brcmf_err("Setting toe_ol failed, %d\n", err);
-               return err;
-       }
-
-       err = brcmf_fil_iovar_int_set(ifp, "toe", (toe_ol != 0));
-       if (err < 0)
-               brcmf_err("Setting toe failed, %d\n", err);
-
-       return err;
-
-}
-
 static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
                                    struct ethtool_drvinfo *info)
 {
@@ -621,8 +599,8 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
        struct brcmf_pub *drvr = ifp->drvr;
 
        strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
-       snprintf(info->version, sizeof(info->version), "%lu",
-                drvr->drv_version);
+       snprintf(info->version, sizeof(info->version), "n/a");
+       strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version));
        strlcpy(info->bus_info, dev_name(drvr->bus_if->dev),
                sizeof(info->bus_info));
 }
@@ -631,124 +609,6 @@ static const struct ethtool_ops brcmf_ethtool_ops = {
        .get_drvinfo = brcmf_ethtool_get_drvinfo,
 };
 
-static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
-{
-       struct brcmf_pub *drvr = ifp->drvr;
-       struct ethtool_drvinfo info;
-       char drvname[sizeof(info.driver)];
-       u32 cmd;
-       struct ethtool_value edata;
-       u32 toe_cmpnt, csum_dir;
-       int ret;
-
-       brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
-
-       /* all ethtool calls start with a cmd word */
-       if (copy_from_user(&cmd, uaddr, sizeof(u32)))
-               return -EFAULT;
-
-       switch (cmd) {
-       case ETHTOOL_GDRVINFO:
-               /* Copy out any request driver name */
-               if (copy_from_user(&info, uaddr, sizeof(info)))
-                       return -EFAULT;
-               strncpy(drvname, info.driver, sizeof(info.driver));
-               drvname[sizeof(info.driver) - 1] = '\0';
-
-               /* clear struct for return */
-               memset(&info, 0, sizeof(info));
-               info.cmd = cmd;
-
-               /* if requested, identify ourselves */
-               if (strcmp(drvname, "?dhd") == 0) {
-                       sprintf(info.driver, "dhd");
-                       strcpy(info.version, BRCMF_VERSION_STR);
-               }
-               /* report dongle driver type */
-               else
-                       sprintf(info.driver, "wl");
-
-               sprintf(info.version, "%lu", drvr->drv_version);
-               if (copy_to_user(uaddr, &info, sizeof(info)))
-                       return -EFAULT;
-               brcmf_dbg(TRACE, "given %*s, returning %s\n",
-                         (int)sizeof(drvname), drvname, info.driver);
-               break;
-
-               /* Get toe offload components from dongle */
-       case ETHTOOL_GRXCSUM:
-       case ETHTOOL_GTXCSUM:
-               ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
-               if (ret < 0)
-                       return ret;
-
-               csum_dir =
-                   (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
-
-               edata.cmd = cmd;
-               edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
-
-               if (copy_to_user(uaddr, &edata, sizeof(edata)))
-                       return -EFAULT;
-               break;
-
-               /* Set toe offload components in dongle */
-       case ETHTOOL_SRXCSUM:
-       case ETHTOOL_STXCSUM:
-               if (copy_from_user(&edata, uaddr, sizeof(edata)))
-                       return -EFAULT;
-
-               /* Read the current settings, update and write back */
-               ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
-               if (ret < 0)
-                       return ret;
-
-               csum_dir =
-                   (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
-
-               if (edata.data != 0)
-                       toe_cmpnt |= csum_dir;
-               else
-                       toe_cmpnt &= ~csum_dir;
-
-               ret = brcmf_toe_set(ifp, toe_cmpnt);
-               if (ret < 0)
-                       return ret;
-
-               /* If setting TX checksum mode, tell Linux the new mode */
-               if (cmd == ETHTOOL_STXCSUM) {
-                       if (edata.data)
-                               ifp->ndev->features |= NETIF_F_IP_CSUM;
-                       else
-                               ifp->ndev->features &= ~NETIF_F_IP_CSUM;
-               }
-
-               break;
-
-       default:
-               return -EOPNOTSUPP;
-       }
-
-       return 0;
-}
-
-static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
-                                   int cmd)
-{
-       struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_pub *drvr = ifp->drvr;
-
-       brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd);
-
-       if (!drvr->iflist[ifp->bssidx])
-               return -1;
-
-       if (cmd == SIOCETHTOOL)
-               return brcmf_ethtool(ifp, ifr->ifr_data);
-
-       return -EOPNOTSUPP;
-}
-
 static int brcmf_netdev_stop(struct net_device *ndev)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
@@ -769,7 +629,6 @@ static int brcmf_netdev_open(struct net_device *ndev)
        struct brcmf_pub *drvr = ifp->drvr;
        struct brcmf_bus *bus_if = drvr->bus_if;
        u32 toe_ol;
-       s32 ret = 0;
 
        brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
 
@@ -788,21 +647,20 @@ static int brcmf_netdev_open(struct net_device *ndev)
        else
                ndev->features &= ~NETIF_F_IP_CSUM;
 
-       /* Allow transmit calls */
-       netif_start_queue(ndev);
        if (brcmf_cfg80211_up(ndev)) {
                brcmf_err("failed to bring up cfg80211\n");
-               return -1;
+               return -EIO;
        }
 
-       return ret;
+       /* Allow transmit calls */
+       netif_start_queue(ndev);
+       return 0;
 }
 
 static const struct net_device_ops brcmf_netdev_ops_pri = {
        .ndo_open = brcmf_netdev_open,
        .ndo_stop = brcmf_netdev_stop,
        .ndo_get_stats = brcmf_netdev_get_stats,
-       .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
        .ndo_start_xmit = brcmf_netdev_start_xmit,
        .ndo_set_mac_address = brcmf_netdev_set_mac_address,
        .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
@@ -868,13 +726,6 @@ static int brcmf_net_p2p_stop(struct net_device *ndev)
        return brcmf_cfg80211_down(ndev);
 }
 
-static int brcmf_net_p2p_do_ioctl(struct net_device *ndev,
-                                 struct ifreq *ifr, int cmd)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-       return 0;
-}
-
 static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,
                                            struct net_device *ndev)
 {
@@ -887,7 +738,6 @@ static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,
 static const struct net_device_ops brcmf_netdev_ops_p2p = {
        .ndo_open = brcmf_net_p2p_open,
        .ndo_stop = brcmf_net_p2p_stop,
-       .ndo_do_ioctl = brcmf_net_p2p_do_ioctl,
        .ndo_start_xmit = brcmf_net_p2p_start_xmit
 };
 
@@ -1016,7 +866,7 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
        }
 }
 
-int brcmf_attach(uint bus_hdrlen, struct device *dev)
+int brcmf_attach(struct device *dev)
 {
        struct brcmf_pub *drvr = NULL;
        int ret = 0;
@@ -1031,7 +881,7 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
        mutex_init(&drvr->proto_block);
 
        /* Link to bus module */
-       drvr->hdrlen = bus_hdrlen;
+       drvr->hdrlen = 0;
        drvr->bus_if = dev_get_drvdata(dev);
        drvr->bus_if->drvr = drvr;
 
@@ -1048,8 +898,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
        /* attach firmware event handler */
        brcmf_fweh_attach(drvr);
 
-       INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);
-
        return ret;
 
 fail:
@@ -1138,14 +986,21 @@ fail:
        return 0;
 }
 
+void brcmf_bus_add_txhdrlen(struct device *dev, uint len)
+{
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_pub *drvr = bus_if->drvr;
+
+       if (drvr) {
+               drvr->hdrlen += len;
+       }
+}
+
 static void brcmf_bus_detach(struct brcmf_pub *drvr)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
        if (drvr) {
-               /* Stop the protocol module */
-               brcmf_proto_stop(drvr);
-
                /* Stop the bus module */
                brcmf_bus_stop(drvr->bus_if);
        }
@@ -1186,8 +1041,7 @@ void brcmf_detach(struct device *dev)
 
        brcmf_bus_detach(drvr);
 
-       if (drvr->prot)
-               brcmf_proto_detach(drvr);
+       brcmf_proto_detach(drvr);
 
        brcmf_fws_deinit(drvr);
 
@@ -1196,6 +1050,14 @@ void brcmf_detach(struct device *dev)
        kfree(drvr);
 }
 
+s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len)
+{
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_if *ifp = bus_if->drvr->iflist[0];
+
+       return brcmf_fil_iovar_data_set(ifp, name, data, len);
+}
+
 static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)
 {
        return atomic_read(&ifp->pend_8021x_cnt);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h
deleted file mode 100644 (file)
index 53c6e71..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * 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 _BRCMF_PROTO_H_
-#define _BRCMF_PROTO_H_
-
-/*
- * Exported from the brcmf protocol module (brcmf_cdc)
- */
-
-/* Linkage, sets prot link and updates hdrlen in pub */
-int brcmf_proto_attach(struct brcmf_pub *drvr);
-
-/* Unlink, frees allocated protocol memory (including brcmf_proto) */
-void brcmf_proto_detach(struct brcmf_pub *drvr);
-
-/* Stop protocol: sync w/dongle state. */
-void brcmf_proto_stop(struct brcmf_pub *drvr);
-
-/* Add any protocol-specific data header.
- * Caller must reserve prot_hdrlen prepend space.
- */
-void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, u8 offset,
-                        struct sk_buff *txp);
-
-/* Sets dongle media info (drv_version, mac address). */
-int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
-
-#endif                         /* _BRCMF_PROTO_H_ */
index b02953c4ade721235fbe0e4ed662aaa422ab21f7..0f95f3e79c10f6e04f8a5735a102e3059739e4f8 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/debugfs.h>
 #include <linux/vmalloc.h>
 #include <linux/platform_data/brcmfmac-sdio.h>
+#include <linux/moduleparam.h>
 #include <asm/unaligned.h>
 #include <defs.h>
 #include <brcmu_wifi.h>
@@ -110,6 +111,8 @@ struct rte_console {
 #define BRCMF_TXBOUND  20      /* Default for max tx frames in
                                 one scheduling */
 
+#define BRCMF_DEFAULT_TXGLOM_SIZE      32  /* max tx frames in glom chain */
+
 #define BRCMF_TXMINMAX 1       /* Max tx frames if rx still pending */
 
 #define MEMBLOCK       2048    /* Block size used for downloading
@@ -360,6 +363,8 @@ struct brcmf_sdio_hdrinfo {
        u16 len_left;
        u16 len_nxtfrm;
        u8 dat_offset;
+       bool lastfrm;
+       u16 tail_pad;
 };
 
 /* misc chip info needed by some of the routines */
@@ -384,7 +389,7 @@ struct brcmf_sdio {
        u8 tx_seq;              /* Transmit sequence number (next) */
        u8 tx_max;              /* Maximum transmit sequence allowed */
 
-       u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN];
+       u8 *hdrbuf;             /* buffer for handling rx frame */
        u8 *rxhdr;              /* Header of current rx frame (in hdrbuf) */
        u8 rx_seq;              /* Receive sequence number (expected) */
        struct brcmf_sdio_hdrinfo cur_read;
@@ -455,6 +460,10 @@ struct brcmf_sdio {
        bool sleeping; /* SDIO bus sleeping */
 
        u8 tx_hdrlen;           /* sdio bus header length for tx packet */
+       bool txglom;            /* host tx glomming enable flag */
+       struct sk_buff *txglom_sgpad;   /* scatter-gather padding buffer */
+       u16 head_align;         /* buffer pointer alignment */
+       u16 sgentry_align;      /* scatter-gather buffer alignment */
 };
 
 /* clkstate */
@@ -479,6 +488,10 @@ static const uint max_roundup = 512;
 
 #define ALIGNMENT  4
 
+static int brcmf_sdio_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
+module_param_named(txglomsz, brcmf_sdio_txglomsz, int, 0);
+MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]");
+
 enum brcmf_sdio_frmtype {
        BRCMF_SDIO_FT_NORMAL,
        BRCMF_SDIO_FT_SUPER,
@@ -499,6 +512,8 @@ enum brcmf_sdio_frmtype {
 #define BCM4334_NVRAM_NAME             "brcm/brcmfmac4334-sdio.txt"
 #define BCM4335_FIRMWARE_NAME          "brcm/brcmfmac4335-sdio.bin"
 #define BCM4335_NVRAM_NAME             "brcm/brcmfmac4335-sdio.txt"
+#define BCM4339_FIRMWARE_NAME          "brcm/brcmfmac4339-sdio.bin"
+#define BCM4339_NVRAM_NAME             "brcm/brcmfmac4339-sdio.txt"
 
 MODULE_FIRMWARE(BCM43143_FIRMWARE_NAME);
 MODULE_FIRMWARE(BCM43143_NVRAM_NAME);
@@ -514,6 +529,8 @@ MODULE_FIRMWARE(BCM4334_FIRMWARE_NAME);
 MODULE_FIRMWARE(BCM4334_NVRAM_NAME);
 MODULE_FIRMWARE(BCM4335_FIRMWARE_NAME);
 MODULE_FIRMWARE(BCM4335_NVRAM_NAME);
+MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM4339_NVRAM_NAME);
 
 struct brcmf_firmware_names {
        u32 chipid;
@@ -537,7 +554,8 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = {
        { BCM4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) },
        { BCM4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) },
        { BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
-       { BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }
+       { BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) },
+       { BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }
 };
 
 
@@ -1097,10 +1115,18 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
  * host and WiFi dongle which contains information needed for SDIO core and
  * firmware
  *
- * It consists of 2 parts: hw header and software header
+ * It consists of 3 parts: hardware header, hardware extension header and
+ * software header
  * hardware header (frame tag) - 4 bytes
  * Byte 0~1: Frame length
  * Byte 2~3: Checksum, bit-wise inverse of frame length
+ * hardware extension header - 8 bytes
+ * Tx glom mode only, N/A for Rx or normal Tx
+ * Byte 0~1: Packet length excluding hw frame tag
+ * Byte 2: Reserved
+ * Byte 3: Frame flags, bit 0: last frame indication
+ * Byte 4~5: Reserved
+ * Byte 6~7: Tail padding length
  * software header - 8 bytes
  * Byte 0: Rx/Tx sequence number
  * Byte 1: 4 MSB Channel number, 4 LSB arbitrary flag
@@ -1111,6 +1137,7 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
  * Byte 6~7: Reserved
  */
 #define SDPCM_HWHDR_LEN                        4
+#define SDPCM_HWEXT_LEN                        8
 #define SDPCM_SWHDR_LEN                        8
 #define SDPCM_HDRLEN                   (SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN)
 /* software header */
@@ -1147,7 +1174,7 @@ static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
        u8 rx_seq, fc, tx_seq_max;
        u32 swheader;
 
-       trace_brcmf_sdpcm_hdr(false, header);
+       trace_brcmf_sdpcm_hdr(SDPCM_RX, header);
 
        /* hw header */
        len = get_unaligned_le16(header);
@@ -1260,25 +1287,34 @@ static inline void brcmf_sdio_update_hwhdr(u8 *header, u16 frm_length)
 static void brcmf_sdio_hdpack(struct brcmf_sdio *bus, u8 *header,
                              struct brcmf_sdio_hdrinfo *hd_info)
 {
-       u32 sw_header;
+       u32 hdrval;
+       u8 hdr_offset;
 
        brcmf_sdio_update_hwhdr(header, hd_info->len);
-
-       sw_header = bus->tx_seq;
-       sw_header |= (hd_info->channel << SDPCM_CHANNEL_SHIFT) &
-                    SDPCM_CHANNEL_MASK;
-       sw_header |= (hd_info->dat_offset << SDPCM_DOFFSET_SHIFT) &
-                    SDPCM_DOFFSET_MASK;
-       *(((__le32 *)header) + 1) = cpu_to_le32(sw_header);
-       *(((__le32 *)header) + 2) = 0;
-       trace_brcmf_sdpcm_hdr(true, header);
+       hdr_offset = SDPCM_HWHDR_LEN;
+
+       if (bus->txglom) {
+               hdrval = (hd_info->len - hdr_offset) | (hd_info->lastfrm << 24);
+               *((__le32 *)(header + hdr_offset)) = cpu_to_le32(hdrval);
+               hdrval = (u16)hd_info->tail_pad << 16;
+               *(((__le32 *)(header + hdr_offset)) + 1) = cpu_to_le32(hdrval);
+               hdr_offset += SDPCM_HWEXT_LEN;
+       }
+
+       hdrval = hd_info->seq_num;
+       hdrval |= (hd_info->channel << SDPCM_CHANNEL_SHIFT) &
+                 SDPCM_CHANNEL_MASK;
+       hdrval |= (hd_info->dat_offset << SDPCM_DOFFSET_SHIFT) &
+                 SDPCM_DOFFSET_MASK;
+       *((__le32 *)(header + hdr_offset)) = cpu_to_le32(hdrval);
+       *(((__le32 *)(header + hdr_offset)) + 1) = 0;
+       trace_brcmf_sdpcm_hdr(SDPCM_TX + !!(bus->txglom), header);
 }
 
 static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 {
        u16 dlen, totlen;
        u8 *dptr, num = 0;
-       u32 align = 0;
        u16 sublen;
        struct sk_buff *pfirst, *pnext;
 
@@ -1293,11 +1329,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
        brcmf_dbg(SDIO, "start: glomd %p glom %p\n",
                  bus->glomd, skb_peek(&bus->glom));
 
-       if (bus->sdiodev->pdata)
-               align = bus->sdiodev->pdata->sd_sgentry_align;
-       if (align < 4)
-               align = 4;
-
        /* If there's a descriptor, generate the packet chain */
        if (bus->glomd) {
                pfirst = pnext = NULL;
@@ -1321,9 +1352,9 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                                pnext = NULL;
                                break;
                        }
-                       if (sublen % align) {
+                       if (sublen % bus->sgentry_align) {
                                brcmf_err("sublen %d not multiple of %d\n",
-                                         sublen, align);
+                                         sublen, bus->sgentry_align);
                        }
                        totlen += sublen;
 
@@ -1336,7 +1367,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                        }
 
                        /* Allocate/chain packet for next subframe */
-                       pnext = brcmu_pkt_buf_get_skb(sublen + align);
+                       pnext = brcmu_pkt_buf_get_skb(sublen + bus->sgentry_align);
                        if (pnext == NULL) {
                                brcmf_err("bcm_pkt_buf_get_skb failed, num %d len %d\n",
                                          num, sublen);
@@ -1345,7 +1376,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                        skb_queue_tail(&bus->glom, pnext);
 
                        /* Adhere to start alignment requirements */
-                       pkt_align(pnext, sublen, align);
+                       pkt_align(pnext, sublen, bus->sgentry_align);
                }
 
                /* If all allocations succeeded, save packet chain
@@ -1549,9 +1580,9 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
                goto done;
 
        rbuf = bus->rxbuf;
-       pad = ((unsigned long)rbuf % BRCMF_SDALIGN);
+       pad = ((unsigned long)rbuf % bus->head_align);
        if (pad)
-               rbuf += (BRCMF_SDALIGN - pad);
+               rbuf += (bus->head_align - pad);
 
        /* Copy the already-read portion over */
        memcpy(buf, hdr, BRCMF_FIRSTREAD);
@@ -1565,14 +1596,10 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
                if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
                    ((len + pad) < bus->sdiodev->bus_if->maxctl))
                        rdlen += pad;
-       } else if (rdlen % BRCMF_SDALIGN) {
-               rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
+       } else if (rdlen % bus->head_align) {
+               rdlen += bus->head_align - (rdlen % bus->head_align);
        }
 
-       /* Satisfy length-alignment requirements */
-       if (rdlen & (ALIGNMENT - 1))
-               rdlen = roundup(rdlen, ALIGNMENT);
-
        /* Drop if the read is too big or it exceeds our maximum */
        if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {
                brcmf_err("%d-byte control read exceeds %d-byte buffer\n",
@@ -1637,8 +1664,8 @@ static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
                if (*pad <= bus->roundup && *pad < bus->blocksize &&
                    *rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ)
                        *rdlen += *pad;
-       } else if (*rdlen % BRCMF_SDALIGN) {
-               *rdlen += BRCMF_SDALIGN - (*rdlen % BRCMF_SDALIGN);
+       } else if (*rdlen % bus->head_align) {
+               *rdlen += bus->head_align - (*rdlen % bus->head_align);
        }
 }
 
@@ -1726,7 +1753,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                brcmf_pad(bus, &pad, &rd->len_left);
 
                pkt = brcmu_pkt_buf_get_skb(rd->len_left + head_read +
-                                           BRCMF_SDALIGN);
+                                           bus->head_align);
                if (!pkt) {
                        /* Give up on data, request rtx of events */
                        brcmf_err("brcmu_pkt_buf_get_skb failed\n");
@@ -1736,7 +1763,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                        continue;
                }
                skb_pull(pkt, head_read);
-               pkt_align(pkt, rd->len_left, BRCMF_SDALIGN);
+               pkt_align(pkt, rd->len_left, bus->head_align);
 
                ret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
                                              SDIO_FUNC_2, F2SYNC, pkt);
@@ -1871,6 +1898,29 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
        return;
 }
 
+static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt)
+{
+       u16 head_pad;
+       u8 *dat_buf;
+
+       dat_buf = (u8 *)(pkt->data);
+
+       /* Check head padding */
+       head_pad = ((unsigned long)dat_buf % bus->head_align);
+       if (head_pad) {
+               if (skb_headroom(pkt) < head_pad) {
+                       bus->sdiodev->bus_if->tx_realloc++;
+                       head_pad = 0;
+                       if (skb_cow(pkt, head_pad))
+                               return -ENOMEM;
+               }
+               skb_push(pkt, head_pad);
+               dat_buf = (u8 *)(pkt->data);
+               memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
+       }
+       return head_pad;
+}
+
 /**
  * struct brcmf_skbuff_cb reserves first two bytes in sk_buff::cb for
  * bus layer usage.
@@ -1880,32 +1930,40 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
 /* bit mask of data length chopped from the previous packet */
 #define ALIGN_SKB_CHOP_LEN_MASK        0x7fff
 
-static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio_dev *sdiodev,
+static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
                                    struct sk_buff_head *pktq,
-                                   struct sk_buff *pkt, uint chan)
+                                   struct sk_buff *pkt, u16 total_len)
 {
+       struct brcmf_sdio_dev *sdiodev;
        struct sk_buff *pkt_pad;
-       u16 tail_pad, tail_chop, sg_align;
+       u16 tail_pad, tail_chop, chain_pad;
        unsigned int blksize;
-       u8 *dat_buf;
-       int ntail;
+       bool lastfrm;
+       int ntail, ret;
 
+       sdiodev = bus->sdiodev;
        blksize = sdiodev->func[SDIO_FUNC_2]->cur_blksize;
-       sg_align = 4;
-       if (sdiodev->pdata && sdiodev->pdata->sd_sgentry_align > 4)
-               sg_align = sdiodev->pdata->sd_sgentry_align;
        /* sg entry alignment should be a divisor of block size */
-       WARN_ON(blksize % sg_align);
+       WARN_ON(blksize % bus->sgentry_align);
 
        /* Check tail padding */
-       pkt_pad = NULL;
-       tail_chop = pkt->len % sg_align;
-       tail_pad = sg_align - tail_chop;
-       tail_pad += blksize - (pkt->len + tail_pad) % blksize;
+       lastfrm = skb_queue_is_last(pktq, pkt);
+       tail_pad = 0;
+       tail_chop = pkt->len % bus->sgentry_align;
+       if (tail_chop)
+               tail_pad = bus->sgentry_align - tail_chop;
+       chain_pad = (total_len + tail_pad) % blksize;
+       if (lastfrm && chain_pad)
+               tail_pad += blksize - chain_pad;
        if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) {
-               pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop);
+               pkt_pad = bus->txglom_sgpad;
+               if (pkt_pad == NULL)
+                         brcmu_pkt_buf_get_skb(tail_pad + tail_chop);
                if (pkt_pad == NULL)
                        return -ENOMEM;
+               ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad);
+               if (unlikely(ret < 0))
+                       return ret;
                memcpy(pkt_pad->data,
                       pkt->data + pkt->len - tail_chop,
                       tail_chop);
@@ -1920,14 +1978,10 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio_dev *sdiodev,
                                return -ENOMEM;
                if (skb_linearize(pkt))
                        return -ENOMEM;
-               dat_buf = (u8 *)(pkt->data);
                __skb_put(pkt, tail_pad);
        }
 
-       if (pkt_pad)
-               return pkt->len + tail_chop;
-       else
-               return pkt->len - tail_pad;
+       return tail_pad;
 }
 
 /**
@@ -1946,58 +2000,66 @@ static int
 brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
                      uint chan)
 {
-       u16 head_pad, head_align;
+       u16 head_pad, total_len;
        struct sk_buff *pkt_next;
-       u8 *dat_buf;
-       int err;
+       u8 txseq;
+       int ret;
        struct brcmf_sdio_hdrinfo hd_info = {0};
 
-       /* SDIO ADMA requires at least 32 bit alignment */
-       head_align = 4;
-       if (bus->sdiodev->pdata && bus->sdiodev->pdata->sd_head_align > 4)
-               head_align = bus->sdiodev->pdata->sd_head_align;
+       txseq = bus->tx_seq;
+       total_len = 0;
+       skb_queue_walk(pktq, pkt_next) {
+               /* alignment packet inserted in previous
+                * loop cycle can be skipped as it is
+                * already properly aligned and does not
+                * need an sdpcm header.
+                */
+               if (*(u32 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
+                       continue;
 
-       pkt_next = pktq->next;
-       dat_buf = (u8 *)(pkt_next->data);
+               /* align packet data pointer */
+               ret = brcmf_sdio_txpkt_hdalign(bus, pkt_next);
+               if (ret < 0)
+                       return ret;
+               head_pad = (u16)ret;
+               if (head_pad)
+                       memset(pkt_next->data, 0, head_pad + bus->tx_hdrlen);
 
-       /* Check head padding */
-       head_pad = ((unsigned long)dat_buf % head_align);
-       if (head_pad) {
-               if (skb_headroom(pkt_next) < head_pad) {
-                       bus->sdiodev->bus_if->tx_realloc++;
-                       head_pad = 0;
-                       if (skb_cow(pkt_next, head_pad))
-                               return -ENOMEM;
-               }
-               skb_push(pkt_next, head_pad);
-               dat_buf = (u8 *)(pkt_next->data);
-               memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
-       }
+               total_len += pkt_next->len;
 
-       if (bus->sdiodev->sg_support && pktq->qlen > 1) {
-               err = brcmf_sdio_txpkt_prep_sg(bus->sdiodev, pktq,
-                                              pkt_next, chan);
-               if (err < 0)
-                       return err;
-               hd_info.len = (u16)err;
-       } else {
                hd_info.len = pkt_next->len;
-       }
-
-       hd_info.channel = chan;
-       hd_info.dat_offset = head_pad + bus->tx_hdrlen;
-
-       /* Now fill the header */
-       brcmf_sdio_hdpack(bus, dat_buf, &hd_info);
-
-       if (BRCMF_BYTES_ON() &&
-           ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
-            (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
-               brcmf_dbg_hex_dump(true, pkt_next, hd_info.len, "Tx Frame:\n");
-       else if (BRCMF_HDRS_ON())
-               brcmf_dbg_hex_dump(true, pkt_next, head_pad + bus->tx_hdrlen,
-                                  "Tx Header:\n");
+               hd_info.lastfrm = skb_queue_is_last(pktq, pkt_next);
+               if (bus->txglom && pktq->qlen > 1) {
+                       ret = brcmf_sdio_txpkt_prep_sg(bus, pktq,
+                                                      pkt_next, total_len);
+                       if (ret < 0)
+                               return ret;
+                       hd_info.tail_pad = (u16)ret;
+                       total_len += (u16)ret;
+               }
 
+               hd_info.channel = chan;
+               hd_info.dat_offset = head_pad + bus->tx_hdrlen;
+               hd_info.seq_num = txseq++;
+
+               /* Now fill the header */
+               brcmf_sdio_hdpack(bus, pkt_next->data, &hd_info);
+
+               if (BRCMF_BYTES_ON() &&
+                   ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
+                    (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
+                       brcmf_dbg_hex_dump(true, pkt_next, hd_info.len,
+                                          "Tx Frame:\n");
+               else if (BRCMF_HDRS_ON())
+                       brcmf_dbg_hex_dump(true, pkt_next,
+                                          head_pad + bus->tx_hdrlen,
+                                          "Tx Header:\n");
+       }
+       /* Hardware length tag of the first packet should be total
+        * length of the chain (including padding)
+        */
+       if (bus->txglom)
+               brcmf_sdio_update_hwhdr(pktq->next->data, total_len);
        return 0;
 }
 
@@ -2015,6 +2077,7 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
 {
        u8 *hdr;
        u32 dat_offset;
+       u16 tail_pad;
        u32 dummy_flags, chop_len;
        struct sk_buff *pkt_next, *tmp, *pkt_prev;
 
@@ -2024,42 +2087,42 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
                        chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK;
                        if (chop_len) {
                                pkt_prev = pkt_next->prev;
-                               memcpy(pkt_prev->data + pkt_prev->len,
-                                      pkt_next->data, chop_len);
                                skb_put(pkt_prev, chop_len);
                        }
                        __skb_unlink(pkt_next, pktq);
                        brcmu_pkt_buf_free_skb(pkt_next);
                } else {
-                       hdr = pkt_next->data + SDPCM_HWHDR_LEN;
+                       hdr = pkt_next->data + bus->tx_hdrlen - SDPCM_SWHDR_LEN;
                        dat_offset = le32_to_cpu(*(__le32 *)hdr);
                        dat_offset = (dat_offset & SDPCM_DOFFSET_MASK) >>
                                     SDPCM_DOFFSET_SHIFT;
                        skb_pull(pkt_next, dat_offset);
+                       if (bus->txglom) {
+                               tail_pad = le16_to_cpu(*(__le16 *)(hdr - 2));
+                               skb_trim(pkt_next, pkt_next->len - tail_pad);
+                       }
                }
        }
 }
 
 /* Writes a HW/SW header into the packet and sends it. */
 /* Assumes: (a) header space already there, (b) caller holds lock */
-static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
+static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
                              uint chan)
 {
        int ret;
        int i;
-       struct sk_buff_head localq;
+       struct sk_buff *pkt_next, *tmp;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       __skb_queue_head_init(&localq);
-       __skb_queue_tail(&localq, pkt);
-       ret = brcmf_sdio_txpkt_prep(bus, &localq, chan);
+       ret = brcmf_sdio_txpkt_prep(bus, pktq, chan);
        if (ret)
                goto done;
 
        sdio_claim_host(bus->sdiodev->func[1]);
        ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
-                                   SDIO_FUNC_2, F2SYNC, &localq);
+                                   SDIO_FUNC_2, F2SYNC, pktq);
        bus->sdcnt.f2txdata++;
 
        if (ret < 0) {
@@ -2083,42 +2146,56 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
                        if ((hi == 0) && (lo == 0))
                                break;
                }
-
        }
        sdio_release_host(bus->sdiodev->func[1]);
-       if (ret == 0)
-               bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
 
 done:
-       brcmf_sdio_txpkt_postp(bus, &localq);
-       __skb_dequeue_tail(&localq);
-       brcmf_txcomplete(bus->sdiodev->dev, pkt, ret == 0);
+       brcmf_sdio_txpkt_postp(bus, pktq);
+       if (ret == 0)
+               bus->tx_seq = (bus->tx_seq + pktq->qlen) % SDPCM_SEQ_WRAP;
+       skb_queue_walk_safe(pktq, pkt_next, tmp) {
+               __skb_unlink(pkt_next, pktq);
+               brcmf_txcomplete(bus->sdiodev->dev, pkt_next, ret == 0);
+       }
        return ret;
 }
 
 static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
 {
        struct sk_buff *pkt;
+       struct sk_buff_head pktq;
        u32 intstatus = 0;
-       int ret = 0, prec_out;
+       int ret = 0, prec_out, i;
        uint cnt = 0;
-       u8 tx_prec_map;
+       u8 tx_prec_map, pkt_num;
 
        brcmf_dbg(TRACE, "Enter\n");
 
        tx_prec_map = ~bus->flowcontrol;
 
        /* Send frames until the limit or some other event */
-       for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) {
+       for (cnt = 0; (cnt < maxframes) && data_ok(bus);) {
+               pkt_num = 1;
+               __skb_queue_head_init(&pktq);
+               if (bus->txglom)
+                       pkt_num = min_t(u8, bus->tx_max - bus->tx_seq,
+                                       brcmf_sdio_txglomsz);
+               pkt_num = min_t(u32, pkt_num,
+                               brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol));
                spin_lock_bh(&bus->txqlock);
-               pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
-               if (pkt == NULL) {
-                       spin_unlock_bh(&bus->txqlock);
-                       break;
+               for (i = 0; i < pkt_num; i++) {
+                       pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map,
+                                             &prec_out);
+                       if (pkt == NULL)
+                               break;
+                       __skb_queue_tail(&pktq, pkt);
                }
                spin_unlock_bh(&bus->txqlock);
+               if (i == 0)
+                       break;
 
-               ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL);
+               ret = brcmf_sdbrcm_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL);
+               cnt += i;
 
                /* In poll mode, need to check for other events */
                if (!bus->intr && cnt) {
@@ -2665,7 +2742,7 @@ static int
 brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 {
        u8 *frame;
-       u16 len;
+       u16 len, pad;
        uint retries = 0;
        u8 doff = 0;
        int ret = -1;
@@ -2681,28 +2758,26 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
        len = (msglen += bus->tx_hdrlen);
 
        /* Add alignment padding (optional for ctl frames) */
-       doff = ((unsigned long)frame % BRCMF_SDALIGN);
+       doff = ((unsigned long)frame % bus->head_align);
        if (doff) {
                frame -= doff;
                len += doff;
                msglen += doff;
                memset(frame, 0, doff + bus->tx_hdrlen);
        }
-       /* precondition: doff < BRCMF_SDALIGN */
+       /* precondition: doff < bus->head_align */
        doff += bus->tx_hdrlen;
 
        /* Round send length to next SDIO block */
+       pad = 0;
        if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
-               u16 pad = bus->blocksize - (len % bus->blocksize);
-               if ((pad <= bus->roundup) && (pad < bus->blocksize))
-                       len += pad;
-       } else if (len % BRCMF_SDALIGN) {
-               len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
+               pad = bus->blocksize - (len % bus->blocksize);
+               if ((pad > bus->roundup) || (pad >= bus->blocksize))
+                       pad = 0;
+       } else if (len % bus->head_align) {
+               pad = bus->head_align - (len % bus->head_align);
        }
-
-       /* Satisfy length-alignment requirements */
-       if (len & (ALIGNMENT - 1))
-               len = roundup(len, ALIGNMENT);
+       len += pad;
 
        /* precondition: IS_ALIGNED((unsigned long)frame, 2) */
 
@@ -2714,8 +2789,14 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
        hd_info.len = (u16)msglen;
        hd_info.channel = SDPCM_CONTROL_CHANNEL;
        hd_info.dat_offset = doff;
+       hd_info.seq_num = bus->tx_seq;
+       hd_info.lastfrm = true;
+       hd_info.tail_pad = pad;
        brcmf_sdio_hdpack(bus, frame, &hd_info);
 
+       if (bus->txglom)
+               brcmf_sdio_update_hwhdr(frame, len);
+
        if (!data_ok(bus)) {
                brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
                          bus->tx_max, bus->tx_seq);
@@ -3425,6 +3506,65 @@ brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
        return ret;
 }
 
+static int brcmf_sdbrcm_bus_preinit(struct device *dev)
+{
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+       struct brcmf_sdio *bus = sdiodev->bus;
+       uint pad_size;
+       u32 value;
+       u8 idx;
+       int err;
+
+       /* the commands below use the terms tx and rx from
+        * a device perspective, ie. bus:txglom affects the
+        * bus transfers from device to host.
+        */
+       idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
+       if (bus->ci->c_inf[idx].rev < 12) {
+               /* for sdio core rev < 12, disable txgloming */
+               value = 0;
+               err = brcmf_iovar_data_set(dev, "bus:txglom", &value,
+                                          sizeof(u32));
+       } else {
+               /* otherwise, set txglomalign */
+               value = 4;
+               if (sdiodev->pdata)
+                       value = sdiodev->pdata->sd_sgentry_align;
+               /* SDIO ADMA requires at least 32 bit alignment */
+               value = max_t(u32, value, 4);
+               err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value,
+                                          sizeof(u32));
+       }
+
+       if (err < 0)
+               goto done;
+
+       bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
+       if (sdiodev->sg_support) {
+               bus->txglom = false;
+               value = 1;
+               pad_size = bus->sdiodev->func[2]->cur_blksize << 1;
+               bus->txglom_sgpad = brcmu_pkt_buf_get_skb(pad_size);
+               if (!bus->txglom_sgpad)
+                       brcmf_err("allocating txglom padding skb failed, reduced performance\n");
+
+               err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom",
+                                          &value, sizeof(u32));
+               if (err < 0) {
+                       /* bus:rxglom is allowed to fail */
+                       err = 0;
+               } else {
+                       bus->txglom = true;
+                       bus->tx_hdrlen += SDPCM_HWEXT_LEN;
+               }
+       }
+       brcmf_bus_add_txhdrlen(bus->sdiodev->dev, bus->tx_hdrlen);
+
+done:
+       return err;
+}
+
 static int brcmf_sdbrcm_bus_init(struct device *dev)
 {
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
@@ -3673,7 +3813,7 @@ static bool brcmf_sdbrcm_probe_malloc(struct brcmf_sdio *bus)
        if (bus->sdiodev->bus_if->maxctl) {
                bus->rxblen =
                    roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN),
-                           ALIGNMENT) + BRCMF_SDALIGN;
+                           ALIGNMENT) + bus->head_align;
                bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
                if (!(bus->rxbuf))
                        return false;
@@ -3774,9 +3914,13 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
 
        brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
 
+       /* allocate header buffer */
+       bus->hdrbuf = kzalloc(MAX_HDR_READ + bus->head_align, GFP_KERNEL);
+       if (!bus->hdrbuf)
+               return false;
        /* Locate an appropriately-aligned portion of hdrbuf */
        bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0],
-                                   BRCMF_SDALIGN);
+                                   bus->head_align);
 
        /* Set the poll and/or interrupt flags */
        bus->intr = true;
@@ -3895,8 +4039,9 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
                        brcmf_sdbrcm_release_dongle(bus);
                }
 
+               brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
                brcmf_sdbrcm_release_malloc(bus);
-
+               kfree(bus->hdrbuf);
                kfree(bus);
        }
 
@@ -3905,6 +4050,7 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
 
 static struct brcmf_bus_ops brcmf_sdio_bus_ops = {
        .stop = brcmf_sdbrcm_bus_stop,
+       .preinit = brcmf_sdbrcm_bus_preinit,
        .init = brcmf_sdbrcm_bus_init,
        .txdata = brcmf_sdbrcm_bus_txdata,
        .txctl = brcmf_sdbrcm_bus_txctl,
@@ -3916,10 +4062,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
 {
        int ret;
        struct brcmf_sdio *bus;
-       struct brcmf_bus_dcmd *dlst;
-       u32 dngl_txglom;
-       u32 txglomalign = 0;
-       u8 idx;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3939,6 +4081,18 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
        bus->txminmax = BRCMF_TXMINMAX;
        bus->tx_seq = SDPCM_SEQ_WRAP - 1;
 
+       /* platform specific configuration:
+        *   alignments must be at least 4 bytes for ADMA
+         */
+       bus->head_align = ALIGNMENT;
+       bus->sgentry_align = ALIGNMENT;
+       if (sdiodev->pdata) {
+               if (sdiodev->pdata->sd_head_align > ALIGNMENT)
+                       bus->head_align = sdiodev->pdata->sd_head_align;
+               if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT)
+                       bus->sgentry_align = sdiodev->pdata->sd_sgentry_align;
+       }
+
        INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
        bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");
        if (bus->brcmf_wq == NULL) {
@@ -3983,7 +4137,7 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
        bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
 
        /* Attach to the common layer, reserve hdr space */
-       ret = brcmf_attach(bus->tx_hdrlen, bus->sdiodev->dev);
+       ret = brcmf_attach(bus->sdiodev->dev);
        if (ret != 0) {
                brcmf_err("brcmf_attach failed\n");
                goto fail;
@@ -4003,30 +4157,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
        brcmf_sdio_debugfs_create(bus);
        brcmf_dbg(INFO, "completed!!\n");
 
-       /* sdio bus core specific dcmd */
-       idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
-       dlst = kzalloc(sizeof(struct brcmf_bus_dcmd), GFP_KERNEL);
-       if (dlst) {
-               if (bus->ci->c_inf[idx].rev < 12) {
-                       /* for sdio core rev < 12, disable txgloming */
-                       dngl_txglom = 0;
-                       dlst->name = "bus:txglom";
-                       dlst->param = (char *)&dngl_txglom;
-                       dlst->param_len = sizeof(u32);
-               } else {
-                       /* otherwise, set txglomalign */
-                       if (sdiodev->pdata)
-                               txglomalign = sdiodev->pdata->sd_sgentry_align;
-                       /* SDIO ADMA requires at least 32 bit alignment */
-                       if (txglomalign < 4)
-                               txglomalign = 4;
-                       dlst->name = "bus:txglomalign";
-                       dlst->param = (char *)&txglomalign;
-                       dlst->param_len = sizeof(u32);
-               }
-               list_add(&dlst->list, &bus->sdiodev->bus_if->dcmd_list);
-       }
-
        /* if firmware path present try to download and bring up bus */
        ret = brcmf_bus_start(bus->sdiodev->dev);
        if (ret != 0) {
index 14bc24dc5baeb1f8272b4da0660d893c4bfc9b48..51b53a73d07464c0bb9b8b5a6f551e20314c37ce 100644 (file)
@@ -122,6 +122,52 @@ enum brcmf_fweh_event_code {
 #define BRCMF_EVENT_MSG_FLUSHTXQ       0x02
 #define BRCMF_EVENT_MSG_GROUP          0x04
 
+/* status field values in struct brcmf_event_msg */
+#define BRCMF_E_STATUS_SUCCESS                 0
+#define BRCMF_E_STATUS_FAIL                    1
+#define BRCMF_E_STATUS_TIMEOUT                 2
+#define BRCMF_E_STATUS_NO_NETWORKS             3
+#define BRCMF_E_STATUS_ABORT                   4
+#define BRCMF_E_STATUS_NO_ACK                  5
+#define BRCMF_E_STATUS_UNSOLICITED             6
+#define BRCMF_E_STATUS_ATTEMPT                 7
+#define BRCMF_E_STATUS_PARTIAL                 8
+#define BRCMF_E_STATUS_NEWSCAN                 9
+#define BRCMF_E_STATUS_NEWASSOC                        10
+#define BRCMF_E_STATUS_11HQUIET                        11
+#define BRCMF_E_STATUS_SUPPRESS                        12
+#define BRCMF_E_STATUS_NOCHANS                 13
+#define BRCMF_E_STATUS_CS_ABORT                        15
+#define BRCMF_E_STATUS_ERROR                   16
+
+/* reason field values in struct brcmf_event_msg */
+#define BRCMF_E_REASON_INITIAL_ASSOC           0
+#define BRCMF_E_REASON_LOW_RSSI                        1
+#define BRCMF_E_REASON_DEAUTH                  2
+#define BRCMF_E_REASON_DISASSOC                        3
+#define BRCMF_E_REASON_BCNS_LOST               4
+#define BRCMF_E_REASON_MINTXRATE               9
+#define BRCMF_E_REASON_TXFAIL                  10
+
+#define BRCMF_E_REASON_LINK_BSSCFG_DIS         4
+#define BRCMF_E_REASON_FAST_ROAM_FAILED                5
+#define BRCMF_E_REASON_DIRECTED_ROAM           6
+#define BRCMF_E_REASON_TSPEC_REJECTED          7
+#define BRCMF_E_REASON_BETTER_AP               8
+
+/* action field values for brcmf_ifevent */
+#define BRCMF_E_IF_ADD                         1
+#define BRCMF_E_IF_DEL                         2
+#define BRCMF_E_IF_CHANGE                      3
+
+/* flag field values for brcmf_ifevent */
+#define BRCMF_E_IF_FLAG_NOIF                   1
+
+/* role field values for brcmf_ifevent */
+#define BRCMF_E_IF_ROLE_STA                    0
+#define BRCMF_E_IF_ROLE_AP                     1
+#define BRCMF_E_IF_ROLE_WDS                    2
+
 /**
  * definitions for event packet validation.
  */
@@ -160,6 +206,14 @@ struct brcmf_event_msg {
        u8 bsscfgidx;
 };
 
+struct brcmf_if_event {
+       u8 ifidx;
+       u8 action;
+       u8 flags;
+       u8 bssidx;
+       u8 role;
+};
+
 typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp,
                                    const struct brcmf_event_msg *evtmsg,
                                    void *data);
index 04f395930d86742372585ff42b3ce3837f0d606d..b72d3395499a3c1e713af54a4379f86e93ca407a 100644 (file)
@@ -27,6 +27,7 @@
 #include "dhd_dbg.h"
 #include "tracepoint.h"
 #include "fwil.h"
+#include "proto.h"
 
 
 #define MAX_HEX_DUMP_LEN       64
@@ -46,11 +47,9 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
        if (data != NULL)
                len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
        if (set)
-               err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data,
-                                              len);
+               err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd, data, len);
        else
-               err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data,
-                                                len);
+               err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len);
 
        if (err >= 0)
                err = 0;
index 16eb8202fb1e4678be1c5b180e2ba964ac43e6f5..77eae86e55c23318e439fa23118f3d10e4b33788 100644 (file)
 #ifndef _fwil_h_
 #define _fwil_h_
 
+/*******************************************************************************
+ * Dongle command codes that are interpreted by firmware
+ ******************************************************************************/
+#define BRCMF_C_GET_VERSION                    1
+#define BRCMF_C_UP                             2
+#define BRCMF_C_DOWN                           3
+#define BRCMF_C_SET_PROMISC                    10
+#define BRCMF_C_GET_RATE                       12
+#define BRCMF_C_GET_INFRA                      19
+#define BRCMF_C_SET_INFRA                      20
+#define BRCMF_C_GET_AUTH                       21
+#define BRCMF_C_SET_AUTH                       22
+#define BRCMF_C_GET_BSSID                      23
+#define BRCMF_C_GET_SSID                       25
+#define BRCMF_C_SET_SSID                       26
+#define BRCMF_C_TERMINATED                     28
+#define BRCMF_C_GET_CHANNEL                    29
+#define BRCMF_C_SET_CHANNEL                    30
+#define BRCMF_C_GET_SRL                                31
+#define BRCMF_C_SET_SRL                                32
+#define BRCMF_C_GET_LRL                                33
+#define BRCMF_C_SET_LRL                                34
+#define BRCMF_C_GET_RADIO                      37
+#define BRCMF_C_SET_RADIO                      38
+#define BRCMF_C_GET_PHYTYPE                    39
+#define BRCMF_C_SET_KEY                                45
+#define BRCMF_C_SET_PASSIVE_SCAN               49
+#define BRCMF_C_SCAN                           50
+#define BRCMF_C_SCAN_RESULTS                   51
+#define BRCMF_C_DISASSOC                       52
+#define BRCMF_C_REASSOC                                53
+#define BRCMF_C_SET_ROAM_TRIGGER               55
+#define BRCMF_C_SET_ROAM_DELTA                 57
+#define BRCMF_C_GET_BCNPRD                     75
+#define BRCMF_C_SET_BCNPRD                     76
+#define BRCMF_C_GET_DTIMPRD                    77
+#define BRCMF_C_SET_DTIMPRD                    78
+#define BRCMF_C_SET_COUNTRY                    84
+#define BRCMF_C_GET_PM                         85
+#define BRCMF_C_SET_PM                         86
+#define BRCMF_C_GET_CURR_RATESET               114
+#define BRCMF_C_GET_AP                         117
+#define BRCMF_C_SET_AP                         118
+#define BRCMF_C_GET_RSSI                       127
+#define BRCMF_C_GET_WSEC                       133
+#define BRCMF_C_SET_WSEC                       134
+#define BRCMF_C_GET_PHY_NOISE                  135
+#define BRCMF_C_GET_BSS_INFO                   136
+#define BRCMF_C_GET_BANDLIST                   140
+#define BRCMF_C_SET_SCB_TIMEOUT                        158
+#define BRCMF_C_GET_PHYLIST                    180
+#define BRCMF_C_SET_SCAN_CHANNEL_TIME          185
+#define BRCMF_C_SET_SCAN_UNASSOC_TIME          187
+#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON  201
+#define BRCMF_C_GET_VALID_CHANNELS             217
+#define BRCMF_C_GET_KEY_PRIMARY                        235
+#define BRCMF_C_SET_KEY_PRIMARY                        236
+#define BRCMF_C_SET_SCAN_PASSIVE_TIME          258
+#define BRCMF_C_GET_VAR                                262
+#define BRCMF_C_SET_VAR                                263
+
 s32 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);
 s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);
 s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data);
index ecabb04f33c3059c603513511cfd2679d23d6bb0..af17a5bc8b83bdab2ee9d5a5ff2ec17490cb7603 100644 (file)
 #define BRCMF_ARP_OL_HOST_AUTO_REPLY   0x00000004
 #define BRCMF_ARP_OL_PEER_AUTO_REPLY   0x00000008
 
+#define        BRCMF_BSS_INFO_VERSION  109 /* curr ver of brcmf_bss_info_le struct */
+#define BRCMF_BSS_RSSI_ON_CHANNEL      0x0002
+
+#define BRCMF_STA_ASSOC                        0x10            /* Associated */
+
+/* size of brcmf_scan_params not including variable length array */
+#define BRCMF_SCAN_PARAMS_FIXED_SIZE   64
+
+/* masks for channel and ssid count */
+#define BRCMF_SCAN_PARAMS_COUNT_MASK   0x0000ffff
+#define BRCMF_SCAN_PARAMS_NSSID_SHIFT  16
+
+/* primary (ie tx) key */
+#define BRCMF_PRIMARY_KEY              (1 << 1)
+#define DOT11_BSSTYPE_ANY              2
+#define BRCMF_ESCAN_REQ_VERSION                1
+
+#define BRCMF_MAXRATES_IN_SET          16      /* max # of rates in rateset */
 
 enum brcmf_fil_p2p_if_types {
        BRCMF_FIL_P2P_IF_CLIENT,
@@ -90,4 +108,290 @@ enum brcmf_tdls_manual_ep_ops {
        BRCMF_TDLS_MANUAL_EP_DISCOVERY = 6
 };
 
+/* Pattern matching filter. Specifies an offset within received packets to
+ * start matching, the pattern to match, the size of the pattern, and a bitmask
+ * that indicates which bits within the pattern should be matched.
+ */
+struct brcmf_pkt_filter_pattern_le {
+       /*
+        * Offset within received packet to start pattern matching.
+        * Offset '0' is the first byte of the ethernet header.
+        */
+       __le32 offset;
+       /* Size of the pattern.  Bitmask must be the same size.*/
+       __le32 size_bytes;
+       /*
+        * Variable length mask and pattern data. mask starts at offset 0.
+        * Pattern immediately follows mask.
+        */
+       u8 mask_and_pattern[1];
+};
+
+/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */
+struct brcmf_pkt_filter_le {
+       __le32 id;              /* Unique filter id, specified by app. */
+       __le32 type;            /* Filter type (WL_PKT_FILTER_TYPE_xxx). */
+       __le32 negate_match;    /* Negate the result of filter matches */
+       union {                 /* Filter definitions */
+               struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */
+       } u;
+};
+
+/* IOVAR "pkt_filter_enable" parameter. */
+struct brcmf_pkt_filter_enable_le {
+       __le32 id;              /* Unique filter id */
+       __le32 enable;          /* Enable/disable bool */
+};
+
+/* BSS info structure
+ * Applications MUST CHECK ie_offset field and length field to access IEs and
+ * next bss_info structure in a vector (in struct brcmf_scan_results)
+ */
+struct brcmf_bss_info_le {
+       __le32 version;         /* version field */
+       __le32 length;          /* byte length of data in this record,
+                                * starting at version and including IEs
+                                */
+       u8 BSSID[ETH_ALEN];
+       __le16 beacon_period;   /* units are Kusec */
+       __le16 capability;      /* Capability information */
+       u8 SSID_len;
+       u8 SSID[32];
+       struct {
+               __le32 count;   /* # rates in this set */
+               u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */
+       } rateset;              /* supported rates */
+       __le16 chanspec;        /* chanspec for bss */
+       __le16 atim_window;     /* units are Kusec */
+       u8 dtim_period; /* DTIM period */
+       __le16 RSSI;            /* receive signal strength (in dBm) */
+       s8 phy_noise;           /* noise (in dBm) */
+
+       u8 n_cap;               /* BSS is 802.11N Capable */
+       /* 802.11N BSS Capabilities (based on HT_CAP_*): */
+       __le32 nbss_cap;
+       u8 ctl_ch;              /* 802.11N BSS control channel number */
+       __le32 reserved32[1];   /* Reserved for expansion of BSS properties */
+       u8 flags;               /* flags */
+       u8 reserved[3]; /* Reserved for expansion of BSS properties */
+       u8 basic_mcs[MCSSET_LEN];       /* 802.11N BSS required MCS set */
+
+       __le16 ie_offset;       /* offset at which IEs start, from beginning */
+       __le32 ie_length;       /* byte length of Information Elements */
+       __le16 SNR;             /* average SNR of during frame reception */
+       /* Add new fields here */
+       /* variable length Information Elements */
+};
+
+struct brcm_rateset_le {
+       /* # rates in this set */
+       __le32 count;
+       /* rates in 500kbps units w/hi bit set if basic */
+       u8 rates[BRCMF_MAXRATES_IN_SET];
+};
+
+struct brcmf_ssid {
+       u32 SSID_len;
+       unsigned char SSID[32];
+};
+
+struct brcmf_ssid_le {
+       __le32 SSID_len;
+       unsigned char SSID[32];
+};
+
+struct brcmf_scan_params_le {
+       struct brcmf_ssid_le ssid_le;   /* default: {0, ""} */
+       u8 bssid[ETH_ALEN];     /* default: bcast */
+       s8 bss_type;            /* default: any,
+                                * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT
+                                */
+       u8 scan_type;   /* flags, 0 use default */
+       __le32 nprobes;   /* -1 use default, number of probes per channel */
+       __le32 active_time;     /* -1 use default, dwell time per channel for
+                                * active scanning
+                                */
+       __le32 passive_time;    /* -1 use default, dwell time per channel
+                                * for passive scanning
+                                */
+       __le32 home_time;       /* -1 use default, dwell time for the
+                                * home channel between channel scans
+                                */
+       __le32 channel_num;     /* count of channels and ssids that follow
+                                *
+                                * low half is count of channels in
+                                * channel_list, 0 means default (use all
+                                * available channels)
+                                *
+                                * high half is entries in struct brcmf_ssid
+                                * array that follows channel_list, aligned for
+                                * s32 (4 bytes) meaning an odd channel count
+                                * implies a 2-byte pad between end of
+                                * channel_list and first ssid
+                                *
+                                * if ssid count is zero, single ssid in the
+                                * fixed parameter portion is assumed, otherwise
+                                * ssid in the fixed portion is ignored
+                                */
+       __le16 channel_list[1]; /* list of chanspecs */
+};
+
+struct brcmf_scan_results {
+       u32 buflen;
+       u32 version;
+       u32 count;
+       struct brcmf_bss_info_le bss_info_le[];
+};
+
+struct brcmf_escan_params_le {
+       __le32 version;
+       __le16 action;
+       __le16 sync_id;
+       struct brcmf_scan_params_le params_le;
+};
+
+struct brcmf_escan_result_le {
+       __le32 buflen;
+       __le32 version;
+       __le16 sync_id;
+       __le16 bss_count;
+       struct brcmf_bss_info_le bss_info_le;
+};
+
+#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(struct brcmf_escan_result_le) - \
+       sizeof(struct brcmf_bss_info_le))
+
+/* used for association with a specific BSSID and chanspec list */
+struct brcmf_assoc_params_le {
+       /* 00:00:00:00:00:00: broadcast scan */
+       u8 bssid[ETH_ALEN];
+       /* 0: all available channels, otherwise count of chanspecs in
+        * chanspec_list */
+       __le32 chanspec_num;
+       /* list of chanspecs */
+       __le16 chanspec_list[1];
+};
+
+/* used for join with or without a specific bssid and channel list */
+struct brcmf_join_params {
+       struct brcmf_ssid_le ssid_le;
+       struct brcmf_assoc_params_le params_le;
+};
+
+/* scan params for extended join */
+struct brcmf_join_scan_params_le {
+       u8 scan_type;           /* 0 use default, active or passive scan */
+       __le32 nprobes;         /* -1 use default, nr of probes per channel */
+       __le32 active_time;     /* -1 use default, dwell time per channel for
+                                * active scanning
+                                */
+       __le32 passive_time;    /* -1 use default, dwell time per channel
+                                * for passive scanning
+                                */
+       __le32 home_time;       /* -1 use default, dwell time for the home
+                                * channel between channel scans
+                                */
+};
+
+/* extended join params */
+struct brcmf_ext_join_params_le {
+       struct brcmf_ssid_le ssid_le;   /* {0, ""}: wildcard scan */
+       struct brcmf_join_scan_params_le scan_le;
+       struct brcmf_assoc_params_le assoc_le;
+};
+
+struct brcmf_wsec_key {
+       u32 index;              /* key index */
+       u32 len;                /* key length */
+       u8 data[WLAN_MAX_KEY_LEN];      /* key data */
+       u32 pad_1[18];
+       u32 algo;       /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
+       u32 flags;      /* misc flags */
+       u32 pad_2[3];
+       u32 iv_initialized;     /* has IV been initialized already? */
+       u32 pad_3;
+       /* Rx IV */
+       struct {
+               u32 hi; /* upper 32 bits of IV */
+               u16 lo; /* lower 16 bits of IV */
+       } rxiv;
+       u32 pad_4[2];
+       u8 ea[ETH_ALEN];        /* per station */
+};
+
+/*
+ * dongle requires same struct as above but with fields in little endian order
+ */
+struct brcmf_wsec_key_le {
+       __le32 index;           /* key index */
+       __le32 len;             /* key length */
+       u8 data[WLAN_MAX_KEY_LEN];      /* key data */
+       __le32 pad_1[18];
+       __le32 algo;    /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
+       __le32 flags;   /* misc flags */
+       __le32 pad_2[3];
+       __le32 iv_initialized;  /* has IV been initialized already? */
+       __le32 pad_3;
+       /* Rx IV */
+       struct {
+               __le32 hi;      /* upper 32 bits of IV */
+               __le16 lo;      /* lower 16 bits of IV */
+       } rxiv;
+       __le32 pad_4[2];
+       u8 ea[ETH_ALEN];        /* per station */
+};
+
+/* Used to get specific STA parameters */
+struct brcmf_scb_val_le {
+       __le32 val;
+       u8 ea[ETH_ALEN];
+};
+
+/* channel encoding */
+struct brcmf_channel_info_le {
+       __le32 hw_channel;
+       __le32 target_channel;
+       __le32 scan_channel;
+};
+
+struct brcmf_sta_info_le {
+       __le16  ver;            /* version of this struct */
+       __le16  len;            /* length in bytes of this structure */
+       __le16  cap;            /* sta's advertised capabilities */
+       __le32  flags;          /* flags defined below */
+       __le32  idle;           /* time since data pkt rx'd from sta */
+       u8      ea[ETH_ALEN];           /* Station address */
+       __le32  count;                  /* # rates in this set */
+       u8      rates[BRCMF_MAXRATES_IN_SET];   /* rates in 500kbps units */
+                                               /* w/hi bit set if basic */
+       __le32  in;             /* seconds elapsed since associated */
+       __le32  listen_interval_inms; /* Min Listen interval in ms for STA */
+       __le32  tx_pkts;        /* # of packets transmitted */
+       __le32  tx_failures;    /* # of packets failed */
+       __le32  rx_ucast_pkts;  /* # of unicast packets received */
+       __le32  rx_mcast_pkts;  /* # of multicast packets received */
+       __le32  tx_rate;        /* Rate of last successful tx frame */
+       __le32  rx_rate;        /* Rate of last successful rx frame */
+       __le32  rx_decrypt_succeeds;    /* # of packet decrypted successfully */
+       __le32  rx_decrypt_failures;    /* # of packet decrypted failed */
+};
+
+struct brcmf_chanspec_list {
+       __le32  count;          /* # of entries */
+       __le32  element[1];     /* variable length uint32 list */
+};
+
+/*
+ * WLC_E_PROBRESP_MSG
+ * WLC_E_P2P_PROBREQ_MSG
+ * WLC_E_ACTION_FRAME_RX
+ */
+struct brcmf_rx_mgmt_data {
+       __be16  version;
+       __be16  chanspec;
+       __be32  rssi;
+       __be32  mactime;
+       __be32  rate;
+};
+
 #endif /* FWIL_TYPES_H_ */
index d0cd0bf95c5af4393719a981d008049cde67756d..e9bdfdb95d8f06915fc734dd27053a3e092c046e 100644 (file)
@@ -27,7 +27,6 @@
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
 #include "dhd.h"
-#include "dhd_proto.h"
 #include "dhd_dbg.h"
 #include "dhd_bus.h"
 #include "fwil.h"
@@ -36,6 +35,7 @@
 #include "fwsignal.h"
 #include "p2p.h"
 #include "wl_cfg80211.h"
+#include "proto.h"
 
 /**
  * DOC: Firmware Signalling
@@ -105,6 +105,7 @@ static struct {
 };
 #undef BRCMF_FWS_TLV_DEF
 
+
 static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
 {
        int i;
@@ -122,6 +123,12 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
 }
 #endif /* DEBUG */
 
+/*
+ * The PKTTAG tlv has additional bytes when firmware-signalling
+ * mode has REUSESEQ flag set.
+ */
+#define BRCMF_FWS_TYPE_SEQ_LEN                         2
+
 /*
  * flags used to enable tlv signalling from firmware.
  */
@@ -147,8 +154,15 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
 #define BRCMF_FWS_HTOD_FLAG_PKTFROMHOST                        0x01
 #define BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED              0x02
 
-#define BRCMF_FWS_RET_OK_NOSCHEDULE    0
-#define BRCMF_FWS_RET_OK_SCHEDULE      1
+#define BRCMF_FWS_RET_OK_NOSCHEDULE                    0
+#define BRCMF_FWS_RET_OK_SCHEDULE                      1
+
+#define BRCMF_FWS_MODE_REUSESEQ_SHIFT                  3       /* seq reuse */
+#define BRCMF_FWS_MODE_SET_REUSESEQ(x, val)    ((x) = \
+               ((x) & ~(1 << BRCMF_FWS_MODE_REUSESEQ_SHIFT)) | \
+               (((val) & 1) << BRCMF_FWS_MODE_REUSESEQ_SHIFT))
+#define BRCMF_FWS_MODE_GET_REUSESEQ(x) \
+               (((x) >> BRCMF_FWS_MODE_REUSESEQ_SHIFT) & 1)
 
 /**
  * enum brcmf_fws_skb_state - indicates processing state of skb.
@@ -171,6 +185,7 @@ enum brcmf_fws_skb_state {
  * @bus_flags: 2 bytes reserved for bus specific parameters
  * @if_flags: holds interface index and packet related flags.
  * @htod: host to device packet identifier (used in PKTTAG tlv).
+ * @htod_seq: this 16-bit is original seq number for every suppress packet.
  * @state: transmit state of the packet.
  * @mac: descriptor related to destination for this packet.
  *
@@ -181,6 +196,7 @@ struct brcmf_skbuff_cb {
        u16 bus_flags;
        u16 if_flags;
        u32 htod;
+       u16 htod_seq;
        enum brcmf_fws_skb_state state;
        struct brcmf_fws_mac_descriptor *mac;
 };
@@ -257,6 +273,22 @@ struct brcmf_skbuff_cb {
                        BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \
                        BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT)
 
+#define BRCMF_SKB_HTOD_SEQ_FROMFW_MASK                 0x2000
+#define BRCMF_SKB_HTOD_SEQ_FROMFW_SHIFT                        13
+#define BRCMF_SKB_HTOD_SEQ_FROMDRV_MASK                        0x1000
+#define BRCMF_SKB_HTOD_SEQ_FROMDRV_SHIFT               12
+#define BRCMF_SKB_HTOD_SEQ_NR_MASK                     0x0fff
+#define BRCMF_SKB_HTOD_SEQ_NR_SHIFT                    0
+
+#define brcmf_skb_htod_seq_set_field(skb, field, value) \
+       brcmu_maskset16(&(brcmf_skbcb(skb)->htod_seq), \
+                       BRCMF_SKB_HTOD_SEQ_ ## field ## _MASK, \
+                       BRCMF_SKB_HTOD_SEQ_ ## field ## _SHIFT, (value))
+#define brcmf_skb_htod_seq_get_field(skb, field) \
+       brcmu_maskget16(brcmf_skbcb(skb)->htod_seq, \
+                       BRCMF_SKB_HTOD_SEQ_ ## field ## _MASK, \
+                       BRCMF_SKB_HTOD_SEQ_ ## field ## _SHIFT)
+
 #define BRCMF_FWS_TXSTAT_GENERATION_MASK       0x80000000
 #define BRCMF_FWS_TXSTAT_GENERATION_SHIFT      31
 #define BRCMF_FWS_TXSTAT_FLAGS_MASK            0x78000000
@@ -265,8 +297,8 @@ struct brcmf_skbuff_cb {
 #define BRCMF_FWS_TXSTAT_FIFO_SHIFT            24
 #define BRCMF_FWS_TXSTAT_HSLOT_MASK            0x00FFFF00
 #define BRCMF_FWS_TXSTAT_HSLOT_SHIFT           8
-#define BRCMF_FWS_TXSTAT_PKTID_MASK            0x00FFFFFF
-#define BRCMF_FWS_TXSTAT_PKTID_SHIFT           0
+#define BRCMF_FWS_TXSTAT_FREERUN_MASK          0x000000FF
+#define BRCMF_FWS_TXSTAT_FREERUN_SHIFT         0
 
 #define brcmf_txstatus_get_field(txs, field) \
        brcmu_maskget32(txs, BRCMF_FWS_TXSTAT_ ## field ## _MASK, \
@@ -443,6 +475,7 @@ struct brcmf_fws_info {
        unsigned long borrow_defer_timestamp;
        bool bus_flow_blocked;
        bool creditmap_received;
+       u8 mode;
 };
 
 /*
@@ -812,13 +845,16 @@ static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
        u16 data_offset = 0;
        u8 fillers;
        __le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod);
+       __le16 pktseq = cpu_to_le16(brcmf_skbcb(skb)->htod_seq);
 
-       brcmf_dbg(TRACE, "enter: %s, idx=%d pkttag=0x%08X, hslot=%d\n",
+       brcmf_dbg(TRACE, "enter: %s, idx=%d hslot=%d htod %X seq %X\n",
                  entry->name, brcmf_skb_if_flags_get_field(skb, INDEX),
-                 le32_to_cpu(pkttag), (le32_to_cpu(pkttag) >> 8) & 0xffff);
+                 (le32_to_cpu(pkttag) >> 8) & 0xffff,
+                 brcmf_skbcb(skb)->htod, brcmf_skbcb(skb)->htod_seq);
        if (entry->send_tim_signal)
                data_offset += 2 + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
-
+       if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode))
+               data_offset += BRCMF_FWS_TYPE_SEQ_LEN;
        /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */
        data_offset += 2 + BRCMF_FWS_TYPE_PKTTAG_LEN;
        fillers = round_up(data_offset, 4) - data_offset;
@@ -830,7 +866,12 @@ static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
        wlh[0] = BRCMF_FWS_TYPE_PKTTAG;
        wlh[1] = BRCMF_FWS_TYPE_PKTTAG_LEN;
        memcpy(&wlh[2], &pkttag, sizeof(pkttag));
-       wlh += BRCMF_FWS_TYPE_PKTTAG_LEN + 2;
+       if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) {
+               wlh[1] += BRCMF_FWS_TYPE_SEQ_LEN;
+               memcpy(&wlh[2 + BRCMF_FWS_TYPE_PKTTAG_LEN], &pktseq,
+                      sizeof(pktseq));
+       }
+       wlh += wlh[1] + 2;
 
        if (entry->send_tim_signal) {
                entry->send_tim_signal = 0;
@@ -875,6 +916,7 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
                /* create a dummy packet and sent that. The traffic          */
                /* bitmap info will automatically be attached to that packet */
                len = BRCMF_FWS_TYPE_PKTTAG_LEN + 2 +
+                     BRCMF_FWS_TYPE_SEQ_LEN +
                      BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2 +
                      4 + fws->drvr->hdrlen;
                skb = brcmu_pkt_buf_get_skb(len);
@@ -884,6 +926,8 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
                skcb = brcmf_skbcb(skb);
                skcb->mac = entry;
                skcb->state = BRCMF_FWS_SKBSTATE_TIM;
+               skcb->htod = 0;
+               skcb->htod_seq = 0;
                bus = fws->drvr->bus_if;
                err = brcmf_fws_hdrpush(fws, skb);
                if (err == 0) {
@@ -1172,8 +1216,13 @@ static int brcmf_fws_enq(struct brcmf_fws_info *fws,
 {
        int prec = 2 * fifo;
        u32 *qfull_stat = &fws->stats.delayq_full_error;
-
        struct brcmf_fws_mac_descriptor *entry;
+       struct pktq *pq;
+       struct sk_buff_head *queue;
+       struct sk_buff *p_head;
+       struct sk_buff *p_tail;
+       u32 fr_new;
+       u32 fr_compare;
 
        entry = brcmf_skbcb(p)->mac;
        if (entry == NULL) {
@@ -1185,9 +1234,55 @@ static int brcmf_fws_enq(struct brcmf_fws_info *fws,
        if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
                prec += 1;
                qfull_stat = &fws->stats.supprq_full_error;
-       }
 
-       if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) {
+               /* Fix out of order delivery of frames. Dont assume frame    */
+               /* can be inserted at the end, but look for correct position */
+               pq = &entry->psq;
+               if (pktq_full(pq) || pktq_pfull(pq, prec)) {
+                       *qfull_stat += 1;
+                       return -ENFILE;
+               }
+               queue = &pq->q[prec].skblist;
+
+               p_head = skb_peek(queue);
+               p_tail = skb_peek_tail(queue);
+               fr_new = brcmf_skb_htod_tag_get_field(p, FREERUN);
+
+               while (p_head != p_tail) {
+                       fr_compare = brcmf_skb_htod_tag_get_field(p_tail,
+                                                                 FREERUN);
+                       /* be sure to handle wrap of 256 */
+                       if (((fr_new > fr_compare) &&
+                            ((fr_new - fr_compare) < 128)) ||
+                           ((fr_new < fr_compare) &&
+                            ((fr_compare - fr_new) > 128)))
+                               break;
+                       p_tail = skb_queue_prev(queue, p_tail);
+               }
+               /* Position found. Determine what to do */
+               if (p_tail == NULL) {
+                       /* empty list */
+                       __skb_queue_tail(queue, p);
+               } else {
+                       fr_compare = brcmf_skb_htod_tag_get_field(p_tail,
+                                                                 FREERUN);
+                       if (((fr_new > fr_compare) &&
+                            ((fr_new - fr_compare) < 128)) ||
+                           ((fr_new < fr_compare) &&
+                            ((fr_compare - fr_new) > 128))) {
+                               /* After tail */
+                               __skb_queue_after(queue, p_tail, p);
+                       } else {
+                               /* Before tail */
+                               __skb_insert(p, p_tail->prev, p_tail, queue);
+                       }
+               }
+
+               /* Complete the counters and statistics */
+               pq->len++;
+               if (pq->hi_prec < prec)
+                       pq->hi_prec = (u8) prec;
+       } else if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) {
                *qfull_stat += 1;
                return -ENFILE;
        }
@@ -1277,7 +1372,8 @@ done:
 }
 
 static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
-                                        struct sk_buff *skb, u32 genbit)
+                                        struct sk_buff *skb, u32 genbit,
+                                        u16 seq)
 {
        struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
        u32 hslot;
@@ -1298,6 +1394,14 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
 
        ret = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
        if (ret == 0)
+               brcmf_skb_htod_tag_set_field(skb, GENERATION, genbit);
+               brcmf_skbcb(skb)->htod_seq = seq;
+               if (brcmf_skb_htod_seq_get_field(skb, FROMFW)) {
+                       brcmf_skb_htod_seq_set_field(skb, FROMDRV, 1);
+                       brcmf_skb_htod_seq_set_field(skb, FROMFW, 0);
+               } else {
+                       brcmf_skb_htod_seq_set_field(skb, FROMDRV, 0);
+               }
                ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo,
                                    skb);
        if (ret != 0) {
@@ -1317,7 +1421,7 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
 
 static int
 brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
-                          u32 genbit)
+                     u32 genbit, u16 seq)
 {
        u32 fifo;
        int ret;
@@ -1360,8 +1464,8 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
        if (entry->suppressed && entry->suppr_transit_count)
                entry->suppr_transit_count--;
 
-       brcmf_dbg(DATA, "%s flags %X htod %X\n", entry->name, skcb->if_flags,
-                 skcb->htod);
+       brcmf_dbg(DATA, "%s flags %d htod %X seq %X\n", entry->name, flags,
+                 skcb->htod, seq);
 
        /* pick up the implicit credit from this packet */
        fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
@@ -1374,7 +1478,8 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
        brcmf_fws_macdesc_return_req_credit(skb);
 
        if (!remove_from_hanger)
-               ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit);
+               ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit,
+                                                   seq);
 
        if (remove_from_hanger || ret)
                brcmf_txfinalize(fws->drvr, skb, true);
@@ -1406,10 +1511,12 @@ static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
 static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
 {
        __le32 status_le;
+       __le16 seq_le;
        u32 status;
        u32 hslot;
        u32 genbit;
        u8 flags;
+       u16 seq;
 
        fws->stats.txs_indicate++;
        memcpy(&status_le, data, sizeof(status_le));
@@ -1417,9 +1524,16 @@ static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
        flags = brcmf_txstatus_get_field(status, FLAGS);
        hslot = brcmf_txstatus_get_field(status, HSLOT);
        genbit = brcmf_txstatus_get_field(status, GENERATION);
+       if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) {
+               memcpy(&seq_le, &data[BRCMF_FWS_TYPE_PKTTAG_LEN],
+                      sizeof(seq_le));
+               seq = le16_to_cpu(seq_le);
+       } else {
+               seq = 0;
+       }
 
        brcmf_fws_lock(fws);
-       brcmf_fws_txs_process(fws, flags, hslot, genbit);
+       brcmf_fws_txs_process(fws, flags, hslot, genbit, seq);
        brcmf_fws_unlock(fws);
        return BRCMF_FWS_RET_OK_NOSCHEDULE;
 }
@@ -1610,8 +1724,8 @@ static void brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
        struct brcmf_fws_mac_descriptor *entry = skcb->mac;
        u8 flags;
 
-       brcmf_skb_if_flags_set_field(p, TRANSMIT, 1);
-       brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation);
+       if (skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED)
+               brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation);
        flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;
        if (brcmf_skb_if_flags_get_field(p, REQUESTED)) {
                /*
@@ -1652,7 +1766,7 @@ static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
                fws->stats.rollback_failed++;
                hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
                brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED,
-                                     hslot, 0);
+                                     hslot, 0, 0);
        } else {
                fws->stats.rollback_success++;
                brcmf_fws_return_credits(fws, fifo, 1);
@@ -1732,6 +1846,8 @@ static int brcmf_fws_assign_htod(struct brcmf_fws_info *fws, struct sk_buff *p,
        struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
        int rc, hslot;
 
+       skcb->htod = 0;
+       skcb->htod_seq = 0;
        hslot = brcmf_fws_hanger_get_free_slot(&fws->hanger);
        brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);
        brcmf_skb_htod_tag_set_field(p, FREERUN, skcb->mac->seq[fifo]);
@@ -1908,6 +2024,7 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
        struct brcmf_fws_info *fws;
        u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
        int rc;
+       u32 mode;
 
        drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL);
        if (!drvr->fws) {
@@ -1966,6 +2083,18 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
        if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1))
                brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n");
 
+       /* Enable seq number reuse, if supported */
+       if (brcmf_fil_iovar_int_get(drvr->iflist[0], "wlfc_mode", &mode) == 0) {
+               if (BRCMF_FWS_MODE_GET_REUSESEQ(mode)) {
+                       mode = 0;
+                       BRCMF_FWS_MODE_SET_REUSESEQ(mode, 1);
+                       if (brcmf_fil_iovar_int_set(drvr->iflist[0],
+                                                   "wlfc_mode", mode) == 0) {
+                               BRCMF_FWS_MODE_SET_REUSESEQ(fws->mode, 1);
+                       }
+               }
+       }
+
        brcmf_fws_hanger_init(&fws->hanger);
        brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0);
        brcmf_fws_macdesc_set_name(fws, &fws->desc.other);
@@ -2022,7 +2151,7 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
        }
        brcmf_fws_lock(fws);
        hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
-       brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0);
+       brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0, 0);
        brcmf_fws_unlock(fws);
 }
 
index 4a2293041821ff708c6cefef86ed21406f18266c..d3180360725925c40f6e59bf09bdfb28e18a4300 100644 (file)
@@ -812,7 +812,7 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,
                        struct ieee80211_channel *chan = request->channels[i];
 
                        if (chan->flags & (IEEE80211_CHAN_RADAR |
-                                          IEEE80211_CHAN_PASSIVE_SCAN))
+                                          IEEE80211_CHAN_NO_IR))
                                continue;
 
                        chanspecs[i] = channel_to_chanspec(&p2p->cfg->d11inf,
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/proto.c b/drivers/net/wireless/brcm80211/brcmfmac/proto.c
new file mode 100644 (file)
index 0000000..87eb2bd
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+ #include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+
+#include <brcmu_wifi.h>
+#include "dhd.h"
+#include "dhd_dbg.h"
+#include "proto.h"
+#include "bcdc.h"
+
+
+int brcmf_proto_attach(struct brcmf_pub *drvr)
+{
+       struct brcmf_proto *proto;
+
+       proto = kzalloc(sizeof(*proto), GFP_ATOMIC);
+       if (!proto)
+               goto fail;
+
+       drvr->proto = proto;
+       /* BCDC protocol is only protocol supported for the moment */
+       if (brcmf_proto_bcdc_attach(drvr))
+               goto fail;
+
+       if ((proto->hdrpush == NULL) || (proto->hdrpull == NULL) ||
+           (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL)) {
+               brcmf_err("Not all proto handlers have been installed\n");
+               goto fail;
+       }
+       return 0;
+
+fail:
+       kfree(proto);
+       drvr->proto = NULL;
+       return -ENOMEM;
+}
+
+void brcmf_proto_detach(struct brcmf_pub *drvr)
+{
+       if (drvr->proto) {
+               brcmf_proto_bcdc_detach(drvr);
+               kfree(drvr->proto);
+               drvr->proto = NULL;
+       }
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/proto.h b/drivers/net/wireless/brcm80211/brcmfmac/proto.h
new file mode 100644 (file)
index 0000000..8de1b3b
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013 Broadcom Corporation
+ *
+ * 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 BRCMFMAC_PROTO_H
+#define BRCMFMAC_PROTO_H
+
+struct brcmf_proto {
+       void (*hdrpush)(struct brcmf_pub *drvr, int ifidx, u8 offset,
+                       struct sk_buff *skb);
+       int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
+                      struct sk_buff *skb);
+       int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd,
+                         void *buf, uint len);
+       int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
+                       uint len);
+       void *pd;
+};
+
+
+int brcmf_proto_attach(struct brcmf_pub *drvr);
+void brcmf_proto_detach(struct brcmf_pub *drvr);
+
+static inline void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
+                                      u8 offset, struct sk_buff *skb)
+{
+       drvr->proto->hdrpush(drvr, ifidx, offset, skb);
+}
+static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws,
+                                     u8 *ifidx, struct sk_buff *skb)
+{
+       return drvr->proto->hdrpull(drvr, do_fws, ifidx, skb);
+}
+static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx,
+                                        uint cmd, void *buf, uint len)
+{
+       return drvr->proto->query_dcmd(drvr, ifidx, cmd, buf, len);
+}
+static inline int brcmf_proto_set_dcmd(struct brcmf_pub *drvr, int ifidx,
+                                      uint cmd, void *buf, uint len)
+{
+       return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len);
+}
+
+
+#endif /* BRCMFMAC_PROTO_H */
index 3c67529b90743123691d08aa7ed4d3fdb4a45c6d..4d7d51f9571637de5f9a0a7423f68336af6d2a41 100644 (file)
@@ -89,7 +89,7 @@ TRACE_EVENT(brcmf_hexdump,
        TP_printk("hexdump [addr=%lx, length=%lu]", __entry->addr, __entry->len)
 );
 
-TRACE_EVENT(brcmf_bdchdr,
+TRACE_EVENT(brcmf_bcdchdr,
        TP_PROTO(void *data),
        TP_ARGS(data),
        TP_STRUCT__entry(
@@ -107,24 +107,35 @@ TRACE_EVENT(brcmf_bdchdr,
                memcpy(__get_dynamic_array(signal),
                       (u8 *)data + 4, __entry->siglen);
        ),
-       TP_printk("bdc: prio=%d siglen=%d", __entry->prio, __entry->siglen)
+       TP_printk("bcdc: prio=%d siglen=%d", __entry->prio, __entry->siglen)
 );
 
+#ifndef SDPCM_RX
+#define SDPCM_RX       0
+#endif
+#ifndef SDPCM_TX
+#define SDPCM_TX       1
+#endif
+#ifndef SDPCM_GLOM
+#define SDPCM_GLOM     2
+#endif
+
 TRACE_EVENT(brcmf_sdpcm_hdr,
-       TP_PROTO(bool tx, void *data),
-       TP_ARGS(tx, data),
+       TP_PROTO(u8 dir, void *data),
+       TP_ARGS(dir, data),
        TP_STRUCT__entry(
-               __field(u8, tx)
+               __field(u8, dir)
                __field(u16, len)
-               __array(u8, hdr, 12)
+               __dynamic_array(u8, hdr, dir == SDPCM_GLOM ? 20 : 12)
        ),
        TP_fast_assign(
-               memcpy(__entry->hdr, data, 12);
-               __entry->len = __entry->hdr[0] | (__entry->hdr[1] << 8);
-               __entry->tx = tx ? 1 : 0;
+               memcpy(__get_dynamic_array(hdr), data, dir == SDPCM_GLOM ? 20 : 12);
+               __entry->len = *(u8 *)data | (*((u8 *)data + 1) << 8);
+               __entry->dir = dir;
        ),
-       TP_printk("sdpcm: %s len %u, seq %d", __entry->tx ? "TX" : "RX",
-                 __entry->len, __entry->hdr[4])
+       TP_printk("sdpcm: %s len %u, seq %d",
+                 __entry->dir == SDPCM_RX ? "RX" : "TX",
+                 __entry->len, ((u8 *)__get_dynamic_array(hdr))[4])
 );
 
 #ifdef CONFIG_BRCM_TRACING
index 422f44c631756b2332dc10d4c1fb24c8172343ff..51c4de054b15e9c89c154acb93e3fff79e0c4ffa 100644 (file)
@@ -1255,7 +1255,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
        bus->chiprev = bus_pub->chiprev;
 
        /* Attach to the common driver interface */
-       ret = brcmf_attach(0, dev);
+       ret = brcmf_attach(dev);
        if (ret) {
                brcmf_err("brcmf_attach failed\n");
                goto fail;
@@ -1454,7 +1454,7 @@ static int brcmf_usb_resume(struct usb_interface *intf)
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
 
        brcmf_dbg(USB, "Enter\n");
-       if (!brcmf_attach(0, devinfo->dev))
+       if (!brcmf_attach(devinfo->dev))
                return brcmf_bus_start(&usb->dev);
 
        return 0;
index 571f013cebbb0d0a80f32e2351975b659d7d53d1..3966fe0fcfd971418fb3ca22bfc9fcaddf7afaf7 100644 (file)
@@ -202,9 +202,9 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = {
 
 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
  * By default world regulatory domain defined in reg.c puts the flags
- * NL80211_RRF_PASSIVE_SCAN and NL80211_RRF_NO_IBSS for 5GHz channels (for
- * 36..48 and 149..165). With respect to these flags, wpa_supplicant doesn't
- * start p2p operations on 5GHz channels. All the changes in world regulatory
+ * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
+ * With respect to these flags, wpa_supplicant doesn't * start p2p
+ * operations on 5GHz channels. All the changes in world regulatory
  * domain are to be done here.
  */
 static const struct ieee80211_regdomain brcmf_regdom = {
@@ -2556,8 +2556,8 @@ brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
                ch_bss.band == ch_bss_info_le.band &&
                bss_info_le->SSID_len == bss->SSID_len &&
                !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
-               if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
-                       (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
+               if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
+                       (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
                        s16 bss_rssi = le16_to_cpu(bss->RSSI);
                        s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);
 
@@ -2566,13 +2566,13 @@ brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
                        */
                        if (bss_info_rssi > bss_rssi)
                                bss->RSSI = bss_info_le->RSSI;
-               } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
-                       (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
+               } else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
+                       (bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
                        /* preserve the on-channel rssi measurement
                        * if the new measurement is off channel
                        */
                        bss->RSSI = bss_info_le->RSSI;
-                       bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
+                       bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
                }
                return 1;
        }
@@ -3973,11 +3973,12 @@ brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
 
 static int
 brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
-                      struct ieee80211_channel *chan, bool offchan,
-                      unsigned int wait, const u8 *buf, size_t len,
-                      bool no_cck, bool dont_wait_for_ack, u64 *cookie)
+                      struct cfg80211_mgmt_tx_params *params, u64 *cookie)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct ieee80211_channel *chan = params->chan;
+       const u8 *buf = params->buf;
+       size_t len = params->len;
        const struct ieee80211_mgmt *mgmt;
        struct brcmf_cfg80211_vif *vif;
        s32 err = 0;
@@ -4341,7 +4342,7 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
        wiphy->max_remain_on_channel_duration = 5000;
        brcmf_wiphy_pno_params(wiphy);
        brcmf_dbg(INFO, "Registering custom regulatory\n");
-       wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+       wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
        wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
        err = wiphy_register(wiphy);
        if (err < 0) {
@@ -5197,10 +5198,10 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
                                        if (channel & WL_CHAN_RADAR)
                                                band_chan_arr[index].flags |=
                                                        (IEEE80211_CHAN_RADAR |
-                                                       IEEE80211_CHAN_NO_IBSS);
+                                                       IEEE80211_CHAN_NO_IR);
                                        if (channel & WL_CHAN_PASSIVE)
                                                band_chan_arr[index].flags |=
-                                                   IEEE80211_CHAN_PASSIVE_SCAN;
+                                                   IEEE80211_CHAN_NO_IR;
                                }
                        }
                        if (!update)
index cc87926f505562335a02c605541c739725cf1a03..635ae034c7e5d8d149cec933b55d7405678fa6ba 100644 (file)
 
 #define BRCM_2GHZ_2412_2462    REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
 #define BRCM_2GHZ_2467_2472    REG_RULE(2467-10, 2472+10, 20, 0, 19, \
-                                        NL80211_RRF_PASSIVE_SCAN | \
-                                        NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 
 #define BRCM_5GHZ_5180_5240    REG_RULE(5180-10, 5240+10, 40, 0, 21, \
-                                        NL80211_RRF_PASSIVE_SCAN | \
-                                        NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 #define BRCM_5GHZ_5260_5320    REG_RULE(5260-10, 5320+10, 40, 0, 21, \
-                                        NL80211_RRF_PASSIVE_SCAN | \
                                         NL80211_RRF_DFS | \
-                                        NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 #define BRCM_5GHZ_5500_5700    REG_RULE(5500-10, 5700+10, 40, 0, 21, \
-                                        NL80211_RRF_PASSIVE_SCAN | \
                                         NL80211_RRF_DFS | \
-                                        NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 #define BRCM_5GHZ_5745_5825    REG_RULE(5745-10, 5825+10, 40, 0, 21, \
-                                        NL80211_RRF_PASSIVE_SCAN | \
-                                        NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 
 static const struct ieee80211_regdomain brcms_regdom_x2 = {
        .n_reg_rules = 6,
@@ -395,7 +390,7 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
                brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
 
        brcms_b_set_chanspec(wlc->hw, chanspec,
-                             !!(ch->flags & IEEE80211_CHAN_PASSIVE_SCAN),
+                             !!(ch->flags & IEEE80211_CHAN_NO_IR),
                              &txpwr);
 }
 
@@ -657,8 +652,8 @@ static void brcms_reg_apply_radar_flags(struct wiphy *wiphy)
                 */
                if (!(ch->flags & IEEE80211_CHAN_DISABLED))
                        ch->flags |= IEEE80211_CHAN_RADAR |
-                                    IEEE80211_CHAN_NO_IBSS |
-                                    IEEE80211_CHAN_PASSIVE_SCAN;
+                                    IEEE80211_CHAN_NO_IR |
+                                    IEEE80211_CHAN_NO_IR;
        }
 }
 
@@ -684,18 +679,15 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
                                continue;
 
                        if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-                               rule = freq_reg_info(wiphy, ch->center_freq);
+                               rule = freq_reg_info(wiphy,
+                                                    MHZ_TO_KHZ(ch->center_freq));
                                if (IS_ERR(rule))
                                        continue;
 
-                               if (!(rule->flags & NL80211_RRF_NO_IBSS))
-                                       ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
-                               if (!(rule->flags & NL80211_RRF_PASSIVE_SCAN))
-                                       ch->flags &=
-                                               ~IEEE80211_CHAN_PASSIVE_SCAN;
+                               if (!(rule->flags & NL80211_RRF_NO_IR))
+                                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                        } else if (ch->beacon_found) {
-                               ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
-                                              IEEE80211_CHAN_PASSIVE_SCAN);
+                               ch->flags &= ~IEEE80211_CHAN_NO_IR;
                        }
                }
        }
@@ -775,8 +767,8 @@ void brcms_c_regd_init(struct brcms_c_info *wlc)
        }
 
        wlc->wiphy->reg_notifier = brcms_reg_notifier;
-       wlc->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
-                            WIPHY_FLAG_STRICT_REGULATORY;
+       wlc->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+                                       REGULATORY_STRICT_REG;
        wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain);
        brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER);
 }
index edc5d105ff980e40e1ad2221a4c7686f87b0cea1..e71ce8c842a22f3a337cf1bbf4a08dc0e3e52b70 100644 (file)
@@ -125,13 +125,13 @@ static struct ieee80211_channel brcms_2ghz_chantable[] = {
        CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS),
        CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS),
        CHAN2GHZ(12, 2467,
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_NO_IR |
                 IEEE80211_CHAN_NO_HT40PLUS),
        CHAN2GHZ(13, 2472,
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_NO_IR |
                 IEEE80211_CHAN_NO_HT40PLUS),
        CHAN2GHZ(14, 2484,
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_NO_IR |
                 IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS |
                 IEEE80211_CHAN_NO_OFDM)
 };
@@ -144,51 +144,51 @@ static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = {
        CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS),
        /* UNII-2 */
        CHAN5GHZ(52,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(56,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        CHAN5GHZ(60,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(64,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        /* MID */
        CHAN5GHZ(100,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(104,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        CHAN5GHZ(108,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(112,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        CHAN5GHZ(116,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(120,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        CHAN5GHZ(124,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(128,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        CHAN5GHZ(132,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(136,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        CHAN5GHZ(140,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS |
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS |
                 IEEE80211_CHAN_NO_HT40MINUS),
        /* UNII-3 */
        CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS),
index ebdcdf44f1557de4230125be8862e6f333fccbc2..d3acc85932a569024a51d4b9d68b6dbc79dcfec8 100644 (file)
@@ -108,9 +108,9 @@ static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id)
        struct hwbus_priv *self = dev_id;
 
        if (self->core) {
-               sdio_claim_host(self->func);
+               cw1200_sdio_lock(self);
                cw1200_irq_handler(self->core);
-               sdio_release_host(self->func);
+               cw1200_sdio_unlock(self);
                return IRQ_HANDLED;
        } else {
                return IRQ_NONE;
index ee3c19037aac5e039fe023a0fa3fa3b7d08f503d..9afcd4ce3368d37908a055df935f29cf4032f259 100644 (file)
@@ -173,8 +173,9 @@ void cw1200_scan_work(struct work_struct *work)
                        cw1200_set_pm(priv, &priv->powersave_mode);
 
                if (priv->scan.status < 0)
-                       wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan failed (%d).\n",
-                                 priv->scan.status);
+                       wiphy_warn(priv->hw->wiphy,
+                                  "[SCAN] Scan failed (%d).\n",
+                                  priv->scan.status);
                else if (priv->scan.req)
                        wiphy_dbg(priv->hw->wiphy,
                                  "[SCAN] Scan completed.\n");
@@ -197,9 +198,9 @@ void cw1200_scan_work(struct work_struct *work)
                        if ((*it)->band != first->band)
                                break;
                        if (((*it)->flags ^ first->flags) &
-                                       IEEE80211_CHAN_PASSIVE_SCAN)
+                                       IEEE80211_CHAN_NO_IR)
                                break;
-                       if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
+                       if (!(first->flags & IEEE80211_CHAN_NO_IR) &&
                            (*it)->max_power != first->max_power)
                                break;
                }
@@ -210,7 +211,7 @@ void cw1200_scan_work(struct work_struct *work)
                else
                        scan.max_tx_rate = WSM_TRANSMIT_RATE_1;
                scan.num_probes =
-                       (first->flags & IEEE80211_CHAN_PASSIVE_SCAN) ? 0 : 2;
+                       (first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2;
                scan.num_ssids = priv->scan.n_ssids;
                scan.ssids = &priv->scan.ssids[0];
                scan.num_channels = it - priv->scan.curr;
@@ -233,7 +234,7 @@ void cw1200_scan_work(struct work_struct *work)
                }
                for (i = 0; i < scan.num_channels; ++i) {
                        scan.ch[i].number = priv->scan.curr[i]->hw_value;
-                       if (priv->scan.curr[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) {
+                       if (priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR) {
                                scan.ch[i].min_chan_time = 50;
                                scan.ch[i].max_chan_time = 100;
                        } else {
@@ -241,7 +242,7 @@ void cw1200_scan_work(struct work_struct *work)
                                scan.ch[i].max_chan_time = 25;
                        }
                }
-               if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
+               if (!(first->flags & IEEE80211_CHAN_NO_IR) &&
                    priv->scan.output_power != first->max_power) {
                        priv->scan.output_power = first->max_power;
                        wsm_set_output_power(priv,
index f8ab193009cd9f3044a3d8846d4da4e7cbaec3e5..3aba49259ef1886d09157559977cb7f72ac1d944 100644 (file)
@@ -1930,10 +1930,10 @@ static int ipw2100_wdev_init(struct net_device *dev)
                        bg_band->channels[i].max_power = geo->bg[i].max_power;
                        if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
                                bg_band->channels[i].flags |=
-                                       IEEE80211_CHAN_PASSIVE_SCAN;
+                                       IEEE80211_CHAN_NO_IR;
                        if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
                                bg_band->channels[i].flags |=
-                                       IEEE80211_CHAN_NO_IBSS;
+                                       IEEE80211_CHAN_NO_IR;
                        if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
                                bg_band->channels[i].flags |=
                                        IEEE80211_CHAN_RADAR;
@@ -6362,7 +6362,6 @@ out:
                                   &ipw2100_attribute_group);
 
                free_libipw(dev, 0);
-               pci_set_drvdata(pci_dev, NULL);
        }
 
        pci_iounmap(pci_dev, ioaddr);
index 81903e33d5b1bd4779681da798dc0183c0638f48..9244b3661d343d8908bb72ec3a4516391d1d9900 100644 (file)
@@ -11472,10 +11472,10 @@ static int ipw_wdev_init(struct net_device *dev)
                        bg_band->channels[i].max_power = geo->bg[i].max_power;
                        if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
                                bg_band->channels[i].flags |=
-                                       IEEE80211_CHAN_PASSIVE_SCAN;
+                                       IEEE80211_CHAN_NO_IR;
                        if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
                                bg_band->channels[i].flags |=
-                                       IEEE80211_CHAN_NO_IBSS;
+                                       IEEE80211_CHAN_NO_IR;
                        if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
                                bg_band->channels[i].flags |=
                                        IEEE80211_CHAN_RADAR;
@@ -11511,10 +11511,10 @@ static int ipw_wdev_init(struct net_device *dev)
                        a_band->channels[i].max_power = geo->a[i].max_power;
                        if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY)
                                a_band->channels[i].flags |=
-                                       IEEE80211_CHAN_PASSIVE_SCAN;
+                                       IEEE80211_CHAN_NO_IR;
                        if (geo->a[i].flags & LIBIPW_CH_NO_IBSS)
                                a_band->channels[i].flags |=
-                                       IEEE80211_CHAN_NO_IBSS;
+                                       IEEE80211_CHAN_NO_IR;
                        if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT)
                                a_band->channels[i].flags |=
                                        IEEE80211_CHAN_RADAR;
index dea3b50d68b9c5bcfc1c95794262992bc59d917d..0487461ae4da22053607bb49178e296787e18dc3 100644 (file)
@@ -1595,7 +1595,7 @@ il3945_get_channels_for_scan(struct il_priv *il, enum ieee80211_band band,
                 *  and use long active_dwell time.
                 */
                if (!is_active || il_is_channel_passive(ch_info) ||
-                   (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
+                   (chan->flags & IEEE80211_CHAN_NO_IR)) {
                        scan_ch->type = 0;      /* passive */
                        if (IL_UCODE_API(il->ucode_ver) == 1)
                                scan_ch->active_dwell =
@@ -2396,8 +2396,7 @@ __il3945_up(struct il_priv *il)
                clear_bit(S_RFKILL, &il->status);
        else {
                set_bit(S_RFKILL, &il->status);
-               IL_WARN("Radio disabled by HW RF Kill switch\n");
-               return -ENODEV;
+               return -ERFKILL;
        }
 
        _il_wr(il, CSR_INT, 0xFFFFFFFF);
@@ -3575,9 +3574,9 @@ il3945_setup_mac(struct il_priv *il)
        hw->wiphy->interface_modes =
            BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
 
-       hw->wiphy->flags |=
-           WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
-           WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+                                      REGULATORY_DISABLE_BEACON_HINTS;
 
        hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
index 3982ab76f3755fdbda4f0cab89aa6cca537a8f43..43f488a8cda21790a646dcd4efa4ffd04d445c96 100644 (file)
@@ -805,7 +805,7 @@ il4965_get_channels_for_scan(struct il_priv *il, struct ieee80211_vif *vif,
                }
 
                if (!is_active || il_is_channel_passive(ch_info) ||
-                   (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
+                   (chan->flags & IEEE80211_CHAN_NO_IR))
                        scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
                else
                        scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
@@ -5778,9 +5778,9 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
        hw->wiphy->interface_modes =
            BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
 
-       hw->wiphy->flags |=
-           WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
-           WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+                                      REGULATORY_DISABLE_BEACON_HINTS;
 
        /*
         * For now, disable PS by default because it affects
index b03e22ef5462d929ea20ffad72a4a01ff067c4a4..a27b14cfeaec05753bb64fe8708ec7c25065995c 100644 (file)
@@ -3445,10 +3445,10 @@ il_init_geos(struct il_priv *il)
 
                if (il_is_channel_valid(ch)) {
                        if (!(ch->flags & EEPROM_CHANNEL_IBSS))
-                               geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
+                               geo_ch->flags |= IEEE80211_CHAN_NO_IR;
 
                        if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
-                               geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+                               geo_ch->flags |= IEEE80211_CHAN_NO_IR;
 
                        if (ch->flags & EEPROM_CHANNEL_RADAR)
                                geo_ch->flags |= IEEE80211_CHAN_RADAR;
index eff26501d60a63407fba5b8cff66778d612df54e..3a487a3bb5de8fd62c896409df62562712e41239 100644 (file)
@@ -567,12 +567,12 @@ il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count,
                                      flags & IEEE80211_CHAN_RADAR ?
                                      " (IEEE 802.11h required)" : "",
                                      ((channels[i].
-                                       flags & IEEE80211_CHAN_NO_IBSS) ||
+                                       flags & IEEE80211_CHAN_NO_IR) ||
                                       (channels[i].
                                        flags & IEEE80211_CHAN_RADAR)) ? "" :
                                      ", IBSS",
                                      channels[i].
-                                     flags & IEEE80211_CHAN_PASSIVE_SCAN ?
+                                     flags & IEEE80211_CHAN_NO_IR ?
                                      "passive only" : "active/passive");
        }
        supp_band = il_get_hw_mode(il, IEEE80211_BAND_5GHZ);
@@ -594,12 +594,12 @@ il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count,
                                      flags & IEEE80211_CHAN_RADAR ?
                                      " (IEEE 802.11h required)" : "",
                                      ((channels[i].
-                                       flags & IEEE80211_CHAN_NO_IBSS) ||
+                                       flags & IEEE80211_CHAN_NO_IR) ||
                                       (channels[i].
                                        flags & IEEE80211_CHAN_RADAR)) ? "" :
                                      ", IBSS",
                                      channels[i].
-                                     flags & IEEE80211_CHAN_PASSIVE_SCAN ?
+                                     flags & IEEE80211_CHAN_NO_IR ?
                                      "passive only" : "active/passive");
        }
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
index d94f8ab15004cb93f2e757f92a91fd3e669759cb..f69301e505ee0e8968d5a9b90f9dcb3404c1f843 100644 (file)
@@ -352,12 +352,12 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
                                        channels[i].max_power,
                                        channels[i].flags & IEEE80211_CHAN_RADAR ?
                                        " (IEEE 802.11h required)" : "",
-                                       ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
+                                       ((channels[i].flags & IEEE80211_CHAN_NO_IR)
                                        || (channels[i].flags &
                                        IEEE80211_CHAN_RADAR)) ? "" :
                                        ", IBSS",
                                        channels[i].flags &
-                                       IEEE80211_CHAN_PASSIVE_SCAN ?
+                                       IEEE80211_CHAN_NO_IR ?
                                        "passive only" : "active/passive");
        }
        supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
@@ -375,12 +375,12 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
                                        channels[i].max_power,
                                        channels[i].flags & IEEE80211_CHAN_RADAR ?
                                        " (IEEE 802.11h required)" : "",
-                                       ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
+                                       ((channels[i].flags & IEEE80211_CHAN_NO_IR)
                                        || (channels[i].flags &
                                        IEEE80211_CHAN_RADAR)) ? "" :
                                        ", IBSS",
                                        channels[i].flags &
-                                       IEEE80211_CHAN_PASSIVE_SCAN ?
+                                       IEEE80211_CHAN_NO_IR ?
                                        "passive only" : "active/passive");
        }
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
index cae4d3182e334f9451e38d0afada8a8468785195..217f1ca321a0fecb7aaa876a5a22b5ec214b5818 100644 (file)
@@ -155,9 +155,9 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
                        ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
        }
 
-       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
-                           WIPHY_FLAG_DISABLE_BEACON_HINTS |
-                           WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+                                      REGULATORY_DISABLE_BEACON_HINTS;
 
 #ifdef CONFIG_PM_SLEEP
        if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
index 35e0ee8b4e5b64162ecdb2287ae53ab3acd5ee4b..928f8640a0a7965aebfb5c429265ac71a4970f88 100644 (file)
@@ -544,7 +544,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
                channel = chan->hw_value;
                scan_ch->channel = cpu_to_le16(channel);
 
-               if (!is_active || (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
+               if (!is_active || (chan->flags & IEEE80211_CHAN_NO_IR))
                        scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
                else
                        scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
index 4c887f3659089ea3451bc9cc4f2a8dc44c764601..f4a6d317a023aad241ac4f15351a1cc2deae7a2c 100644 (file)
@@ -614,10 +614,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                        channel->flags = IEEE80211_CHAN_NO_HT40;
 
                        if (!(eeprom_ch->flags & EEPROM_CHANNEL_IBSS))
-                               channel->flags |= IEEE80211_CHAN_NO_IBSS;
+                               channel->flags |= IEEE80211_CHAN_NO_IR;
 
                        if (!(eeprom_ch->flags & EEPROM_CHANNEL_ACTIVE))
-                               channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+                               channel->flags |= IEEE80211_CHAN_NO_IR;
 
                        if (eeprom_ch->flags & EEPROM_CHANNEL_RADAR)
                                channel->flags |= IEEE80211_CHAN_RADAR;
index b76a9a8fc0b3dbe831f74ce7d20a811e6cf17ada..2fab203d30275c658a5e4e6a8c296d9595a4ce73 100644 (file)
@@ -223,10 +223,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                        channel->flags |= IEEE80211_CHAN_NO_160MHZ;
 
                if (!(ch_flags & NVM_CHANNEL_IBSS))
-                       channel->flags |= IEEE80211_CHAN_NO_IBSS;
+                       channel->flags |= IEEE80211_CHAN_NO_IR;
 
                if (!(ch_flags & NVM_CHANNEL_ACTIVE))
-                       channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+                       channel->flags |= IEEE80211_CHAN_NO_IR;
 
                if (ch_flags & NVM_CHANNEL_RADAR)
                        channel->flags |= IEEE80211_CHAN_RADAR;
index 74bc2c8af06d62fb360de4357621dca50201a8c2..b56c989ad784d97b00e293209f02bc69d34f31c5 100644 (file)
@@ -199,9 +199,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8)
                hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
 
-       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
-                           WIPHY_FLAG_DISABLE_BEACON_HINTS |
-                           WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+                                      REGULATORY_DISABLE_BEACON_HINTS;
 
        hw->wiphy->iface_combinations = iwl_mvm_iface_combinations;
        hw->wiphy->n_iface_combinations =
index dff7592e1ff84e5c3f6a05d673e2a39514cbb870..e0cd100b40cd6d5f69155d04fb2bcccd0d2c62a6 100644 (file)
@@ -192,7 +192,7 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
        for (i = 0; i < cmd->channel_count; i++) {
                chan->channel = cpu_to_le16(req->channels[i]->hw_value);
                chan->type = cpu_to_le32(type);
-               if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+               if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR)
                        chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
                chan->active_dwell = cpu_to_le16(active_dwell);
                chan->passive_dwell = cpu_to_le16(passive_dwell);
@@ -642,7 +642,7 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
                channels->iter_count[index] = cpu_to_le16(1);
                channels->iter_interval[index] = 0;
 
-               if (!(s_band->channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
+               if (!(s_band->channels[i].flags & IEEE80211_CHAN_NO_IR))
                        channels->type[index] |=
                                cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE);
 
index 991238afd1b60c04ae437fafeb7a108713ea3134..58c6ee5de98f9256b2e3db4735adbfe1fed299bd 100644 (file)
@@ -849,7 +849,7 @@ static void if_sdio_finish_power_on(struct if_sdio_card *card)
                        card->started = true;
                        /* Tell PM core that we don't need the card to be
                         * powered now */
-                       pm_runtime_put_noidle(&func->dev);
+                       pm_runtime_put(&func->dev);
                }
        }
 
@@ -907,8 +907,8 @@ static int if_sdio_power_on(struct if_sdio_card *card)
        sdio_release_host(func);
        ret = if_sdio_prog_firmware(card);
        if (ret) {
-               sdio_disable_func(func);
-               return ret;
+               sdio_claim_host(func);
+               goto disable;
        }
 
        return 0;
index 83669151bb8242e31931735700eb27fe4cd01821..f11728a866ff3129b44e33ae6aa8597171c7005b 100644 (file)
@@ -93,7 +93,6 @@ static void free_if_spi_card(struct if_spi_card *card)
                list_del(&packet->list);
                kfree(packet);
        }
-       spi_set_drvdata(card->spi, NULL);
        kfree(card);
 }
 
index c72438bb2fafd24b8e59f416d4e4311752dce941..9c0cc8ded0216de43d09300dbed19cfa9fe2e3b3 100644 (file)
@@ -159,7 +159,7 @@ static const struct ieee80211_regdomain hwsim_world_regdom_custom_02 = {
        .reg_rules = {
                REG_RULE(2412-10, 2462+10, 40, 0, 20, 0),
                REG_RULE(5725-10, 5850+10, 40, 0, 30,
-                       NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
+                        NL80211_RRF_NO_IR),
        }
 };
 
@@ -353,7 +353,6 @@ struct mac80211_hwsim_data {
        } ps;
        bool ps_poll_pending;
        struct dentry *debugfs;
-       struct dentry *debugfs_ps;
 
        struct sk_buff_head pending;    /* packets pending */
        /*
@@ -362,7 +361,6 @@ struct mac80211_hwsim_data {
         * radio can be in more then one group.
         */
        u64 group;
-       struct dentry *debugfs_group;
 
        int power_level;
 
@@ -1493,7 +1491,7 @@ static void hw_scan_work(struct work_struct *work)
                    req->channels[hwsim->scan_chan_idx]->center_freq);
 
        hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx];
-       if (hwsim->tmp_chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
+       if (hwsim->tmp_chan->flags & IEEE80211_CHAN_NO_IR ||
            !req->n_ssids) {
                dwell = 120;
        } else {
@@ -1742,9 +1740,7 @@ static void mac80211_hwsim_free(void)
        spin_unlock_bh(&hwsim_radio_lock);
 
        list_for_each_entry_safe(data, tmpdata, &tmplist, list) {
-               debugfs_remove(data->debugfs_group);
-               debugfs_remove(data->debugfs_ps);
-               debugfs_remove(data->debugfs);
+               debugfs_remove_recursive(data->debugfs);
                ieee80211_unregister_hw(data->hw);
                device_release_driver(data->dev);
                device_unregister(data->dev);
@@ -1901,6 +1897,17 @@ static int hwsim_fops_ps_write(void *dat, u64 val)
 DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write,
                        "%llu\n");
 
+static int hwsim_write_simulate_radar(void *dat, u64 val)
+{
+       struct mac80211_hwsim_data *data = dat;
+
+       ieee80211_radar_detected(data->hw);
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(hwsim_simulate_radar, NULL,
+                       hwsim_write_simulate_radar, "%llu\n");
 
 static int hwsim_fops_group_read(void *dat, u64 *val)
 {
@@ -2201,11 +2208,28 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
        { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
 };
 
-static struct ieee80211_iface_combination hwsim_if_comb = {
-       .limits = hwsim_if_limits,
-       .n_limits = ARRAY_SIZE(hwsim_if_limits),
-       .max_interfaces = 2048,
-       .num_different_channels = 1,
+static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = {
+       { .max = 8, .types = BIT(NL80211_IFTYPE_AP) },
+};
+
+static struct ieee80211_iface_combination hwsim_if_comb[] = {
+       {
+               .limits = hwsim_if_limits,
+               .n_limits = ARRAY_SIZE(hwsim_if_limits),
+               .max_interfaces = 2048,
+               .num_different_channels = 1,
+       },
+       {
+               .limits = hwsim_if_dfs_limits,
+               .n_limits = ARRAY_SIZE(hwsim_if_dfs_limits),
+               .max_interfaces = 8,
+               .num_different_channels = 1,
+               .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+                                      BIT(NL80211_CHAN_WIDTH_20) |
+                                      BIT(NL80211_CHAN_WIDTH_40) |
+                                      BIT(NL80211_CHAN_WIDTH_80) |
+                                      BIT(NL80211_CHAN_WIDTH_160),
+       }
 };
 
 static int __init init_mac80211_hwsim(void)
@@ -2223,7 +2247,7 @@ static int __init init_mac80211_hwsim(void)
                return -EINVAL;
 
        if (channels > 1) {
-               hwsim_if_comb.num_different_channels = channels;
+               hwsim_if_comb[0].num_different_channels = channels;
                mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan;
                mac80211_hwsim_ops.cancel_hw_scan =
                        mac80211_hwsim_cancel_hw_scan;
@@ -2303,13 +2327,15 @@ static int __init init_mac80211_hwsim(void)
                hw->wiphy->n_addresses = 2;
                hw->wiphy->addresses = data->addresses;
 
-               hw->wiphy->iface_combinations = &hwsim_if_comb;
-               hw->wiphy->n_iface_combinations = 1;
+               hw->wiphy->iface_combinations = hwsim_if_comb;
+               hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb);
 
                if (channels > 1) {
                        hw->wiphy->max_scan_ssids = 255;
                        hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
                        hw->wiphy->max_remain_on_channel_duration = 1000;
+                       /* For channels > 1 DFS is not allowed */
+                       hw->wiphy->n_iface_combinations = 1;
                }
 
                INIT_DELAYED_WORK(&data->roc_done, hw_roc_done);
@@ -2333,7 +2359,8 @@ static int __init init_mac80211_hwsim(void)
                            IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
                            IEEE80211_HW_AMPDU_AGGREGATION |
                            IEEE80211_HW_WANT_MONITOR_VIF |
-                           IEEE80211_HW_QUEUE_CONTROL;
+                           IEEE80211_HW_QUEUE_CONTROL |
+                           IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
                if (rctbl)
                        hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
 
@@ -2393,6 +2420,7 @@ static int __init init_mac80211_hwsim(void)
                        sband->vht_cap.cap =
                                IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
                                IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
+                               IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
                                IEEE80211_VHT_CAP_RXLDPC |
                                IEEE80211_VHT_CAP_SHORT_GI_80 |
                                IEEE80211_VHT_CAP_SHORT_GI_160 |
@@ -2435,46 +2463,53 @@ static int __init init_mac80211_hwsim(void)
                        break;
                case HWSIM_REGTEST_WORLD_ROAM:
                        if (i == 0) {
-                               hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+                               hw->wiphy->regulatory_flags |=
+                                       REGULATORY_CUSTOM_REG;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_01);
                        }
                        break;
                case HWSIM_REGTEST_CUSTOM_WORLD:
-                       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+                       hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
                        wiphy_apply_custom_regulatory(hw->wiphy,
                                &hwsim_world_regdom_custom_01);
                        break;
                case HWSIM_REGTEST_CUSTOM_WORLD_2:
                        if (i == 0) {
-                               hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+                               hw->wiphy->regulatory_flags |=
+                                       REGULATORY_CUSTOM_REG;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_01);
                        } else if (i == 1) {
-                               hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+                               hw->wiphy->regulatory_flags |=
+                                       REGULATORY_CUSTOM_REG;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_02);
                        }
                        break;
                case HWSIM_REGTEST_STRICT_ALL:
-                       hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
+                       hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
                        break;
                case HWSIM_REGTEST_STRICT_FOLLOW:
                case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
                        if (i == 0)
-                               hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
+                               hw->wiphy->regulatory_flags |=
+                                       REGULATORY_STRICT_REG;
                        break;
                case HWSIM_REGTEST_ALL:
                        if (i == 0) {
-                               hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+                               hw->wiphy->regulatory_flags |=
+                                       REGULATORY_CUSTOM_REG;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_01);
                        } else if (i == 1) {
-                               hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+                               hw->wiphy->regulatory_flags |=
+                                       REGULATORY_CUSTOM_REG;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_02);
                        } else if (i == 4)
-                               hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
+                               hw->wiphy->regulatory_flags |=
+                                       REGULATORY_STRICT_REG;
                        break;
                default:
                        break;
@@ -2541,16 +2576,18 @@ static int __init init_mac80211_hwsim(void)
 
                data->debugfs = debugfs_create_dir("hwsim",
                                                   hw->wiphy->debugfsdir);
-               data->debugfs_ps = debugfs_create_file("ps", 0666,
-                                                      data->debugfs, data,
-                                                      &hwsim_fops_ps);
-               data->debugfs_group = debugfs_create_file("group", 0666,
-                                                       data->debugfs, data,
-                                                       &hwsim_fops_group);
+               debugfs_create_file("ps", 0666, data->debugfs, data,
+                                   &hwsim_fops_ps);
+               debugfs_create_file("group", 0666, data->debugfs, data,
+                                   &hwsim_fops_group);
+               if (channels == 1)
+                       debugfs_create_file("dfs_simulate_radar", 0222,
+                                           data->debugfs,
+                                           data, &hwsim_simulate_radar);
 
                tasklet_hrtimer_init(&data->beacon_timer,
                                     mac80211_hwsim_beacon,
-                                    CLOCK_REALTIME, HRTIMER_MODE_ABS);
+                                    CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS);
 
                list_add_tail(&data->list, &hwsim_radios);
        }
index aeaea0e3b4c414ae925b79a3eb4962f7bb36ad4b..d9b7330c902f1824a57cdc265df82590b16d3180 100644 (file)
@@ -50,24 +50,24 @@ static const struct ieee80211_regdomain mwifiex_world_regdom_custom = {
                REG_RULE(2412-10, 2462+10, 40, 3, 20, 0),
                /* Channel 12 - 13 */
                REG_RULE(2467-10, 2472+10, 20, 3, 20,
-                        NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
+                        NL80211_RRF_NO_IR),
                /* Channel 14 */
                REG_RULE(2484-10, 2484+10, 20, 3, 20,
-                        NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS |
+                        NL80211_RRF_NO_IR |
                         NL80211_RRF_NO_OFDM),
                /* Channel 36 - 48 */
                REG_RULE(5180-10, 5240+10, 40, 3, 20,
-                        NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
+                        NL80211_RRF_NO_IR),
                /* Channel 149 - 165 */
                REG_RULE(5745-10, 5825+10, 40, 3, 20,
-                        NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
+                        NL80211_RRF_NO_IR),
                /* Channel 52 - 64 */
                REG_RULE(5260-10, 5320+10, 40, 3, 30,
-                        NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS |
+                        NL80211_RRF_NO_IR |
                         NL80211_RRF_DFS),
                /* Channel 100 - 140 */
                REG_RULE(5500-10, 5700+10, 40, 3, 30,
-                        NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS |
+                        NL80211_RRF_NO_IR |
                         NL80211_RRF_DFS),
        }
 };
@@ -184,10 +184,10 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len)
  */
 static int
 mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
-                        struct ieee80211_channel *chan, bool offchan,
-                        unsigned int wait, const u8 *buf, size_t len,
-                        bool no_cck, bool dont_wait_for_ack, u64 *cookie)
+                        struct cfg80211_mgmt_tx_params *params, u64 *cookie)
 {
+       const u8 *buf = params->buf;
+       size_t len = params->len;
        struct sk_buff *skb;
        u16 pkt_len;
        const struct ieee80211_mgmt *mgmt;
@@ -1968,7 +1968,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_PASSIVE_SCAN)
+               if (chan->flags & IEEE80211_CHAN_NO_IR)
                        user_scan_cfg->chan_list[i].scan_type =
                                                MWIFIEX_SCAN_TYPE_PASSIVE;
                else
@@ -2702,9 +2702,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
        wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
                        WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
                        WIPHY_FLAG_AP_UAPSD |
-                       WIPHY_FLAG_CUSTOM_REGULATORY |
-                       WIPHY_FLAG_STRICT_REGULATORY |
                        WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+       wiphy->regulatory_flags |=
+                       REGULATORY_CUSTOM_REG |
+                       REGULATORY_STRICT_REG;
 
        wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom);
 
index 8cf7d50a7603121682c7f9a9684a64a978de85c9..0ed06646f19a1e9de631f8874b1cb236dce06340 100644 (file)
@@ -515,14 +515,14 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
                                scan_chan_list[chan_idx].max_scan_time =
                                        cpu_to_le16((u16) user_scan_in->
                                        chan_list[0].scan_time);
-                       else if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+                       else if (ch->flags & IEEE80211_CHAN_NO_IR)
                                scan_chan_list[chan_idx].max_scan_time =
                                        cpu_to_le16(adapter->passive_scan_time);
                        else
                                scan_chan_list[chan_idx].max_scan_time =
                                        cpu_to_le16(adapter->active_scan_time);
 
-                       if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+                       if (ch->flags & IEEE80211_CHAN_NO_IR)
                                scan_chan_list[chan_idx].chan_scan_mode_bitmap
                                        |= MWIFIEX_PASSIVE_SCAN;
                        else
index 2675ca7f8d146ca579a7a4bb4c1397f641a95ee0..551194605aa7ae1862c2df113b33a8701c8d5243 100644 (file)
@@ -338,8 +338,7 @@ static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf)
        if (!data_buf)
                return -1;
 
-       pg_tlv_hdr = (struct mwifiex_types_power_group *)
-               ((u8 *) data_buf + sizeof(struct host_cmd_ds_txpwr_cfg));
+       pg_tlv_hdr = (struct mwifiex_types_power_group *)((u8 *)data_buf);
        pg = (struct mwifiex_power_group *)
                ((u8 *) pg_tlv_hdr + sizeof(struct mwifiex_types_power_group));
        length = le16_to_cpu(pg_tlv_hdr->length);
@@ -383,19 +382,25 @@ static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
        struct mwifiex_types_power_group *pg_tlv_hdr;
        struct mwifiex_power_group *pg;
        u16 action = le16_to_cpu(txp_cfg->action);
+       u16 tlv_buf_left;
 
-       switch (action) {
-       case HostCmd_ACT_GEN_GET:
-               pg_tlv_hdr = (struct mwifiex_types_power_group *)
-                       ((u8 *) txp_cfg +
-                        sizeof(struct host_cmd_ds_txpwr_cfg));
+       pg_tlv_hdr = (struct mwifiex_types_power_group *)
+               ((u8 *)txp_cfg +
+                sizeof(struct host_cmd_ds_txpwr_cfg));
 
-               pg = (struct mwifiex_power_group *)
-                       ((u8 *) pg_tlv_hdr +
-                        sizeof(struct mwifiex_types_power_group));
+       pg = (struct mwifiex_power_group *)
+               ((u8 *)pg_tlv_hdr +
+                sizeof(struct mwifiex_types_power_group));
 
+       tlv_buf_left = le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*txp_cfg);
+       if (tlv_buf_left <
+                       le16_to_cpu(pg_tlv_hdr->length) + sizeof(*pg_tlv_hdr))
+               return 0;
+
+       switch (action) {
+       case HostCmd_ACT_GEN_GET:
                if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
-                       mwifiex_get_power_level(priv, txp_cfg);
+                       mwifiex_get_power_level(priv, pg_tlv_hdr);
 
                priv->tx_power_level = (u16) pg->power_min;
                break;
@@ -404,14 +409,6 @@ static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
                if (!le32_to_cpu(txp_cfg->mode))
                        break;
 
-               pg_tlv_hdr = (struct mwifiex_types_power_group *)
-                       ((u8 *) txp_cfg +
-                        sizeof(struct host_cmd_ds_txpwr_cfg));
-
-               pg = (struct mwifiex_power_group *)
-                       ((u8 *) pg_tlv_hdr +
-                        sizeof(struct mwifiex_types_power_group));
-
                if (pg->power_max == pg->power_min)
                        priv->tx_power_level = (u16) pg->power_min;
                break;
index e05d9b4c8317c44df17b9ca0c2dea0577741b1a6..7fa2898d06192615e4a9524a669fc987d141d24f 100644 (file)
@@ -914,7 +914,6 @@ islpci_setup(struct pci_dev *pdev)
       do_islpci_free_memory:
        islpci_free_memory(priv);
       do_free_netdev:
-       pci_set_drvdata(pdev, NULL);
        free_netdev(ndev);
        priv = NULL;
        return NULL;
index 9e68e0cb718ee0dfff1e00066aef36f1c04e0e15..d7b9e6376424d8153d87ec9862eea1d671185004 100644 (file)
@@ -199,7 +199,6 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
       do_unregister_netdev:
        unregister_netdev(ndev);
        islpci_free_memory(priv);
-       pci_set_drvdata(pdev, NULL);
        free_netdev(ndev);
        priv = NULL;
       do_pci_clear_mwi:
@@ -247,7 +246,6 @@ prism54_remove(struct pci_dev *pdev)
        /* free the PCI memory and unmap the remapped page */
        islpci_free_memory(priv);
 
-       pci_set_drvdata(pdev, NULL);
        free_netdev(ndev);
        priv = NULL;
 
index 776aff3678ff23bddda925dfbb48bde925cb7b82..5ee5b296ad28fceb720cbd7a3016b57beaa7ed2f 100644 (file)
@@ -5462,15 +5462,14 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
 
        rt2800_bbp_write(rt2x00dev, 68, 0x0b);
 
-       rt2800_bbp_write(rt2x00dev, 69, 0x12);
+       rt2800_bbp_write(rt2x00dev, 69, 0x0d);
+       rt2800_bbp_write(rt2x00dev, 70, 0x06);
        rt2800_bbp_write(rt2x00dev, 73, 0x13);
        rt2800_bbp_write(rt2x00dev, 75, 0x46);
        rt2800_bbp_write(rt2x00dev, 76, 0x28);
 
        rt2800_bbp_write(rt2x00dev, 77, 0x59);
 
-       rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-
        rt2800_bbp_write(rt2x00dev, 79, 0x13);
        rt2800_bbp_write(rt2x00dev, 80, 0x05);
        rt2800_bbp_write(rt2x00dev, 81, 0x33);
@@ -5513,6 +5512,7 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
        if (rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_bbp_write(rt2x00dev, 134, 0xd0);
                rt2800_bbp_write(rt2x00dev, 135, 0xf6);
+               rt2800_bbp_write(rt2x00dev, 148, 0x84);
        }
 
        rt2800_disable_unused_dac_adc(rt2x00dev);
@@ -6453,7 +6453,7 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
        rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
        rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
        rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
-       rt2800_rfcsr_write(rt2x00dev, 12, 0xc6);
+       rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
        rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
        rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
        rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
@@ -6466,7 +6466,8 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
        rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
        rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
        rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
-       if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+       if (rt2x00_is_usb(rt2x00dev) &&
+           rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
                rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
        else
                rt2800_rfcsr_write(rt2x00dev, 25, 0xc0);
@@ -6486,10 +6487,7 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
        rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
        rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
 
-       if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-               rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
-       else
-               rt2800_rfcsr_write(rt2x00dev, 40, 0x4b);
+       rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
        rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
        rt2800_rfcsr_write(rt2x00dev, 42, 0xd2);
        rt2800_rfcsr_write(rt2x00dev, 43, 0x9a);
@@ -6510,16 +6508,26 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
                rt2800_rfcsr_write(rt2x00dev, 53, 0x84);
        rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
        rt2800_rfcsr_write(rt2x00dev, 55, 0x44);
-       rt2800_rfcsr_write(rt2x00dev, 56, 0x22);
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+               rt2800_rfcsr_write(rt2x00dev, 56, 0x42);
+       else
+               rt2800_rfcsr_write(rt2x00dev, 56, 0x22);
        rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
        rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
        rt2800_rfcsr_write(rt2x00dev, 59, 0x8f);
 
        rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
-       if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-               rt2800_rfcsr_write(rt2x00dev, 61, 0xd1);
-       else
-               rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
+               if (rt2x00_is_usb(rt2x00dev))
+                       rt2800_rfcsr_write(rt2x00dev, 61, 0xd1);
+               else
+                       rt2800_rfcsr_write(rt2x00dev, 61, 0xd5);
+       } else {
+               if (rt2x00_is_usb(rt2x00dev))
+                       rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
+               else
+                       rt2800_rfcsr_write(rt2x00dev, 61, 0xb5);
+       }
        rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
        rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
 
@@ -6602,7 +6610,6 @@ static void rt2800_init_rfcsr_5592(struct rt2x00_dev *rt2x00dev)
 
        rt2800_rfcsr_write(rt2x00dev, 1, 0x3F);
        rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
-       rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
        rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
        rt2800_rfcsr_write(rt2x00dev, 6, 0xE4);
        rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
index 25da20e7e1f34ab2c0b1fd3e38a82d1faece0f9e..af721831dcbc902af12cf872857b8a4134d6b086 100644 (file)
@@ -156,8 +156,6 @@ exit_release_regions:
 exit_disable_device:
        pci_disable_device(pci_dev);
 
-       pci_set_drvdata(pci_dev, NULL);
-
        return retval;
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_probe);
@@ -177,7 +175,6 @@ void rt2x00pci_remove(struct pci_dev *pci_dev)
        /*
         * Free the PCI device data.
         */
-       pci_set_drvdata(pci_dev, NULL);
        pci_disable_device(pci_dev);
        pci_release_regions(pci_dev);
 }
index 9a6edb0c014ec3526c5b4c260b8784cc8fd855d0..ec9aa5b6738171f547dc50a45b977795de133486 100644 (file)
@@ -416,7 +416,7 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev)
        struct rtl8187_rx_info *info;
        int ret = 0;
 
-       while (skb_queue_len(&priv->rx_queue) < 16) {
+       while (skb_queue_len(&priv->rx_queue) < 32) {
                skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL);
                if (!skb) {
                        ret = -ENOMEM;
index ff784072fb4233a29a46a55bf21d75e094bb8d5c..fcf9b621918c07ba2ab42e38622af9b56ac66682 100644 (file)
@@ -1437,7 +1437,8 @@ void rtl_watchdog_wq_callback(void *data)
                        /* if we can't recv beacon for 6s, we should
                         * reconnect this AP
                         */
-                       if (rtlpriv->link_info.roam_times >= 3) {
+                       if ((rtlpriv->link_info.roam_times >= 3) &&
+                           !is_zero_ether_addr(rtlpriv->mac80211.bssid)) {
                                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
                                         "AP off, try to reconnect now\n");
                                rtlpriv->link_info.roam_times = 0;
index 210ce7cd94d8d14201a68ce285e9c880993d30db..2d337a0c3df027c86742af4367c0c00fe64d2f49 100644 (file)
@@ -46,10 +46,20 @@ void rtl_fw_cb(const struct firmware *firmware, void *context)
                         "Firmware callback routine entered!\n");
        complete(&rtlpriv->firmware_loading_complete);
        if (!firmware) {
+               if (rtlpriv->cfg->alt_fw_name) {
+                       err = request_firmware(&firmware,
+                                              rtlpriv->cfg->alt_fw_name,
+                                              rtlpriv->io.dev);
+                       pr_info("Loading alternative firmware %s\n",
+                               rtlpriv->cfg->alt_fw_name);
+                       if (!err)
+                               goto found_alt;
+               }
                pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name);
                rtlpriv->max_fw_size = 0;
                return;
        }
+found_alt:
        if (firmware->size > rtlpriv->max_fw_size) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
                         "Firmware is too big!\n");
@@ -184,6 +194,7 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
                                        rtlpriv->cfg->maps
                                        [RTL_IBSS_INT_MASKS]);
                }
+               mac->link_state = MAC80211_LINKED;
                break;
        case NL80211_IFTYPE_ADHOC:
                RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
index 0f494444bcd1d90b457b927d704bf77abe0592ca..8707d1a94995c740d11a5b6cd3dd5d4849616f53 100644 (file)
@@ -688,8 +688,6 @@ static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb,
                rtlpriv->stats.rxbytesunicast += skb->len;
        }
 
-       rtl_is_special_data(hw, skb, false);
-
        if (ieee80211_is_data(fc)) {
                rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX);
 
index d7d0d4948b01f2e804e6bcddfca93b10c7cdb312..a4eb9b271438657e863dc07af8d9ca20ac431301 100644 (file)
@@ -59,30 +59,26 @@ static struct country_code_to_enum_rd allCountries[] = {
  */
 #define RTL819x_2GHZ_CH12_13   \
        REG_RULE(2467-10, 2472+10, 40, 0, 20,\
-       NL80211_RRF_PASSIVE_SCAN)
+                NL80211_RRF_NO_IR)
 
 #define RTL819x_2GHZ_CH14      \
        REG_RULE(2484-10, 2484+10, 40, 0, 20, \
-       NL80211_RRF_PASSIVE_SCAN | \
-       NL80211_RRF_NO_OFDM)
+                NL80211_RRF_NO_IR | NL80211_RRF_NO_OFDM)
 
 /* 5G chan 36 - chan 64*/
 #define RTL819x_5GHZ_5150_5350 \
        REG_RULE(5150-10, 5350+10, 40, 0, 30, \
-       NL80211_RRF_PASSIVE_SCAN | \
-       NL80211_RRF_NO_IBSS)
+                NL80211_RRF_NO_IR)
 
 /* 5G chan 100 - chan 165*/
 #define RTL819x_5GHZ_5470_5850 \
        REG_RULE(5470-10, 5850+10, 40, 0, 30, \
-       NL80211_RRF_PASSIVE_SCAN | \
-       NL80211_RRF_NO_IBSS)
+                NL80211_RRF_NO_IR)
 
 /* 5G chan 149 - chan 165*/
 #define RTL819x_5GHZ_5725_5850 \
        REG_RULE(5725-10, 5850+10, 40, 0, 30, \
-       NL80211_RRF_PASSIVE_SCAN | \
-       NL80211_RRF_NO_IBSS)
+                NL80211_RRF_NO_IR)
 
 #define RTL819x_5GHZ_ALL       \
        (RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850)
@@ -172,7 +168,8 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
                            (ch->flags & IEEE80211_CHAN_RADAR))
                                continue;
                        if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-                               reg_rule = freq_reg_info(wiphy, ch->center_freq);
+                               reg_rule = freq_reg_info(wiphy,
+                                                        MHZ_TO_KHZ(ch->center_freq));
                                if (IS_ERR(reg_rule))
                                        continue;
 
@@ -185,16 +182,11 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
                                 *regulatory_hint().
                                 */
 
-                               if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
-                                       ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
-                               if (!(reg_rule->
-                                    flags & NL80211_RRF_PASSIVE_SCAN))
-                                       ch->flags &=
-                                           ~IEEE80211_CHAN_PASSIVE_SCAN;
+                               if (!(reg_rule->flags & NL80211_RRF_NO_IR))
+                                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                        } else {
                                if (ch->beacon_found)
-                                       ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
-                                                 IEEE80211_CHAN_PASSIVE_SCAN);
+                                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                        }
                }
        }
@@ -219,11 +211,11 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
         */
        if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
                ch = &sband->channels[11];      /* CH 12 */
-               if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                       ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               if (ch->flags & IEEE80211_CHAN_NO_IR)
+                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                ch = &sband->channels[12];      /* CH 13 */
-               if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                       ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               if (ch->flags & IEEE80211_CHAN_NO_IR)
+                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                return;
        }
 
@@ -235,19 +227,19 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
         */
 
        ch = &sband->channels[11];      /* CH 12 */
-       reg_rule = freq_reg_info(wiphy, ch->center_freq);
+       reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq));
        if (!IS_ERR(reg_rule)) {
-               if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
-                       if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                               ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               if (!(reg_rule->flags & NL80211_RRF_NO_IR))
+                       if (ch->flags & IEEE80211_CHAN_NO_IR)
+                               ch->flags &= ~IEEE80211_CHAN_NO_IR;
        }
 
        ch = &sband->channels[12];      /* CH 13 */
-       reg_rule = freq_reg_info(wiphy, ch->center_freq);
+       reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq));
        if (!IS_ERR(reg_rule)) {
-               if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
-                       if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                               ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               if (!(reg_rule->flags & NL80211_RRF_NO_IR))
+                       if (ch->flags & IEEE80211_CHAN_NO_IR)
+                               ch->flags &= ~IEEE80211_CHAN_NO_IR;
        }
 }
 
@@ -284,8 +276,7 @@ static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy)
                 */
                if (!(ch->flags & IEEE80211_CHAN_DISABLED))
                        ch->flags |= IEEE80211_CHAN_RADAR |
-                           IEEE80211_CHAN_NO_IBSS |
-                           IEEE80211_CHAN_PASSIVE_SCAN;
+                                    IEEE80211_CHAN_NO_IR;
        }
 }
 
@@ -354,9 +345,9 @@ static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
 
        wiphy->reg_notifier = reg_notifier;
 
-       wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
-       wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY;
-       wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS;
+       wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
+       wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG;
+       wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS;
 
        regd = _rtl_regdomain_select(reg);
        wiphy_apply_custom_regulatory(wiphy, regd);
index 21a5cf060677494106afced5c7e8907dfcf86f3d..a6184b6e1d57ff50bca6a4f4aa16ac2871dc295f 100644 (file)
@@ -1078,7 +1078,7 @@ static void rtl88e_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
                                rtldm->swing_flag_ofdm = true;
                        }
 
-                       if (rtldm->swing_idx_cck != rtldm->swing_idx_cck) {
+                       if (rtldm->swing_idx_cck_cur != rtldm->swing_idx_cck) {
                                rtldm->swing_idx_cck_cur = rtldm->swing_idx_cck;
                                rtldm->swing_flag_cck = true;
                        }
index e9caa5d4cff0f910488cd4b22899ad9b5c84665a..fd7e4a7c94dea1d4ad1e59d79c0633340964b8a7 100644 (file)
@@ -158,6 +158,42 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = {
        {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}
 };
 
+static u32 power_index_reg[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a};
+
+void dm_restorepowerindex(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8      index;
+
+       for (index = 0; index < 6; index++)
+               rtl_write_byte(rtlpriv, power_index_reg[index],
+                              rtlpriv->dm.powerindex_backup[index]);
+}
+EXPORT_SYMBOL_GPL(dm_restorepowerindex);
+
+void dm_writepowerindex(struct ieee80211_hw *hw, u8 value)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 index;
+
+       for (index = 0; index < 6; index++)
+               rtl_write_byte(rtlpriv, power_index_reg[index], value);
+}
+EXPORT_SYMBOL_GPL(dm_writepowerindex);
+
+void dm_savepowerindex(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 index;
+       u8 tmp;
+
+       for (index = 0; index < 6; index++) {
+               tmp = rtl_read_byte(rtlpriv, power_index_reg[index]);
+               rtlpriv->dm.powerindex_backup[index] = tmp;
+       }
+}
+EXPORT_SYMBOL_GPL(dm_savepowerindex);
+
 static void rtl92c_dm_diginit(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -180,7 +216,12 @@ static void rtl92c_dm_diginit(struct ieee80211_hw *hw)
        dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
        dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
        dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX;
-       dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX;
+       dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_LowRssi;
+
+       dm_digtable->forbidden_igi = DM_DIG_MIN;
+       dm_digtable->large_fa_hit = 0;
+       dm_digtable->recover_cnt = 0;
+       dm_digtable->dig_dynamic_min  = 0x25;
 }
 
 static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw)
@@ -206,7 +247,9 @@ static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw)
                rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb;
        }
 
-       return (u8) rssi_val_min;
+       if (rssi_val_min > 100)
+               rssi_val_min = 100;
+       return (u8)rssi_val_min;
 }
 
 static void rtl92c_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
@@ -224,9 +267,17 @@ static void rtl92c_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
 
        ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD);
        falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
+
+        ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, MASKDWORD);
+       falsealm_cnt->cnt_fast_fsync_fail = (ret_value & 0xffff);
+       falsealm_cnt->cnt_sb_search_fail = ((ret_value & 0xffff0000) >> 16);
+
        falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
-           falsealm_cnt->cnt_rate_illegal +
-           falsealm_cnt->cnt_crc8_fail + falsealm_cnt->cnt_mcs_fail;
+                                     falsealm_cnt->cnt_rate_illegal +
+                                     falsealm_cnt->cnt_crc8_fail +
+                                     falsealm_cnt->cnt_mcs_fail +
+                                     falsealm_cnt->cnt_fast_fsync_fail +
+                                     falsealm_cnt->cnt_sb_search_fail;
 
        rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(14), 1);
        ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0);
@@ -271,12 +322,14 @@ static void rtl92c_dm_ctrl_initgain_by_fa(struct ieee80211_hw *hw)
                value_igi++;
        else if (rtlpriv->falsealm_cnt.cnt_all >= DM_DIG_FA_TH2)
                value_igi += 2;
+
        if (value_igi > DM_DIG_FA_UPPER)
                value_igi = DM_DIG_FA_UPPER;
        else if (value_igi < DM_DIG_FA_LOWER)
                value_igi = DM_DIG_FA_LOWER;
+
        if (rtlpriv->falsealm_cnt.cnt_all > 10000)
-               value_igi = 0x32;
+               value_igi = DM_DIG_FA_UPPER;
 
        dm_digtable->cur_igvalue = value_igi;
        rtl92c_dm_write_dig(hw);
@@ -286,32 +339,80 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct dig_t *digtable = &rtlpriv->dm_digtable;
+       u32 isbt;
+
+       /* modify DIG lower bound, deal with abnorally large false alarm */
+       if (rtlpriv->falsealm_cnt.cnt_all > 10000) {
+               digtable->large_fa_hit++;
+               if (digtable->forbidden_igi < digtable->cur_igvalue) {
+                       digtable->forbidden_igi = digtable->cur_igvalue;
+                       digtable->large_fa_hit = 1;
+               }
 
-       if (rtlpriv->falsealm_cnt.cnt_all > digtable->fa_highthresh) {
-               if ((digtable->back_val - 2) < digtable->back_range_min)
-                       digtable->back_val = digtable->back_range_min;
-               else
-                       digtable->back_val -= 2;
-       } else if (rtlpriv->falsealm_cnt.cnt_all < digtable->fa_lowthresh) {
-               if ((digtable->back_val + 2) > digtable->back_range_max)
-                       digtable->back_val = digtable->back_range_max;
-               else
-                       digtable->back_val += 2;
+               if (digtable->large_fa_hit >= 3) {
+                       if ((digtable->forbidden_igi + 1) >
+                           digtable->rx_gain_max)
+                               digtable->rx_gain_min = digtable->rx_gain_max;
+                       else
+                               digtable->rx_gain_min = (digtable->forbidden_igi + 1);
+                       digtable->recover_cnt = 3600; /* 3600=2hr */
+               }
+       } else {
+               /* Recovery mechanism for IGI lower bound */
+               if (digtable->recover_cnt != 0) {
+                       digtable->recover_cnt--;
+               } else {
+                       if (digtable->large_fa_hit == 0) {
+                               if ((digtable->forbidden_igi-1) < DM_DIG_MIN) {
+                                       digtable->forbidden_igi = DM_DIG_MIN;
+                                       digtable->rx_gain_min = DM_DIG_MIN;
+                               } else {
+                                       digtable->forbidden_igi--;
+                                       digtable->rx_gain_min = digtable->forbidden_igi + 1;
+                               }
+                       } else if (digtable->large_fa_hit == 3) {
+                               digtable->large_fa_hit = 0;
+                       }
+               }
+       }
+       if (rtlpriv->falsealm_cnt.cnt_all < 250) {
+               isbt = rtl_read_byte(rtlpriv, 0x4fd) & 0x01;
+
+               if (!isbt) {
+                       if (rtlpriv->falsealm_cnt.cnt_all >
+                           digtable->fa_lowthresh) {
+                               if ((digtable->back_val - 2) <
+                                  digtable->back_range_min)
+                                       digtable->back_val = digtable->back_range_min;
+                               else
+                                       digtable->back_val -= 2;
+                       } else if (rtlpriv->falsealm_cnt.cnt_all <
+                                  digtable->fa_lowthresh) {
+                               if ((digtable->back_val + 2) >
+                                   digtable->back_range_max)
+                                       digtable->back_val = digtable->back_range_max;
+                               else
+                                       digtable->back_val += 2;
+                       }
+               } else {
+                       digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
+               }
+       } else {
+               /* Adjust initial gain by false alarm */
+               if (rtlpriv->falsealm_cnt.cnt_all > 1000)
+                       digtable->cur_igvalue = digtable->pre_igvalue + 2;
+               else if (rtlpriv->falsealm_cnt.cnt_all > 750)
+                       digtable->cur_igvalue = digtable->pre_igvalue + 1;
+               else if (rtlpriv->falsealm_cnt.cnt_all < 500)
+                       digtable->cur_igvalue = digtable->pre_igvalue - 1;
        }
 
-       if ((digtable->rssi_val_min + 10 - digtable->back_val) >
-           digtable->rx_gain_max)
+       /* Check initial gain by upper/lower bound */
+       if (digtable->cur_igvalue > digtable->rx_gain_max)
                digtable->cur_igvalue = digtable->rx_gain_max;
-       else if ((digtable->rssi_val_min + 10 -
-                 digtable->back_val) < digtable->rx_gain_min)
-               digtable->cur_igvalue = digtable->rx_gain_min;
-       else
-               digtable->cur_igvalue = digtable->rssi_val_min + 10 -
-                   digtable->back_val;
 
-       RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
-                "rssi_val_min = %x back_val %x\n",
-                digtable->rssi_val_min, digtable->back_val);
+       if (digtable->cur_igvalue < digtable->rx_gain_min)
+               digtable->cur_igvalue = digtable->rx_gain_min;
 
        rtl92c_dm_write_dig(hw);
 }
@@ -329,7 +430,7 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
                multi_sta = true;
 
        if (!multi_sta ||
-           dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) {
+           dm_digtable->cursta_cstate == DIG_STA_DISCONNECT) {
                initialized = false;
                dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
                return;
@@ -375,7 +476,6 @@ static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw)
        RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
                 "presta_cstate = %x, cursta_cstate = %x\n",
                 dm_digtable->presta_cstate, dm_digtable->cursta_cstate);
-
        if (dm_digtable->presta_cstate == dm_digtable->cursta_cstate ||
            dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT ||
            dm_digtable->cursta_cstate == DIG_STA_CONNECT) {
@@ -383,6 +483,8 @@ static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw)
                if (dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) {
                        dm_digtable->rssi_val_min =
                            rtl92c_dm_initial_gain_min_pwdb(hw);
+                       if (dm_digtable->rssi_val_min > 100)
+                               dm_digtable->rssi_val_min = 100;
                        rtl92c_dm_ctrl_initgain_by_rssi(hw);
                }
        } else {
@@ -398,11 +500,12 @@ static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw)
 static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
        struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
        if (dm_digtable->cursta_cstate == DIG_STA_CONNECT) {
                dm_digtable->rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw);
+               if (dm_digtable->rssi_val_min > 100)
+                       dm_digtable->rssi_val_min = 100;
 
                if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) {
                        if (dm_digtable->rssi_val_min <= 25)
@@ -424,48 +527,14 @@ static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
        }
 
        if (dm_digtable->pre_cck_pd_state != dm_digtable->cur_cck_pd_state) {
-               if (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) {
-                       if (rtlpriv->falsealm_cnt.cnt_cck_fail > 800)
-                               dm_digtable->cur_cck_fa_state =
-                                   CCK_FA_STAGE_High;
-                       else
-                               dm_digtable->cur_cck_fa_state = CCK_FA_STAGE_Low;
-
-                       if (dm_digtable->pre_cck_fa_state !=
-                           dm_digtable->cur_cck_fa_state) {
-                               if (dm_digtable->cur_cck_fa_state ==
-                                   CCK_FA_STAGE_Low)
-                                       rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2,
-                                                     0x83);
-                               else
-                                       rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2,
-                                                     0xcd);
-
-                               dm_digtable->pre_cck_fa_state =
-                                   dm_digtable->cur_cck_fa_state;
-                       }
-
-                       rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x40);
-
-                       if (IS_92C_SERIAL(rtlhal->version))
-                               rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT,
-                                             MASKBYTE2, 0xd7);
-               } else {
+               if ((dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) ||
+                   (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_MAX))
+                       rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x83);
+               else
                        rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd);
-                       rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x47);
 
-                       if (IS_92C_SERIAL(rtlhal->version))
-                               rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT,
-                                             MASKBYTE2, 0xd3);
-               }
                dm_digtable->pre_cck_pd_state = dm_digtable->cur_cck_pd_state;
        }
-
-       RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "CCKPDStage=%x\n",
-                dm_digtable->cur_cck_pd_state);
-
-       RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "is92C=%x\n",
-                IS_92C_SERIAL(rtlhal->version));
 }
 
 static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
@@ -482,6 +551,8 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
        else
                dm_digtable->cursta_cstate = DIG_STA_DISCONNECT;
 
+       dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT;
+
        rtl92c_dm_initial_gain_sta(hw);
        rtl92c_dm_initial_gain_multi_sta(hw);
        rtl92c_dm_cck_packet_detection_thresh(hw);
@@ -493,23 +564,26 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
 static void rtl92c_dm_dig(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
        if (rtlpriv->dm.dm_initialgain_enable == false)
                return;
-       if (dm_digtable->dig_enable_flag == false)
+       if (!rtlpriv->dm.dm_flag & DYNAMIC_FUNC_DIG)
                return;
 
        rtl92c_dm_ctrl_initgain_by_twoport(hw);
-
 }
 
 static void rtl92c_dm_init_dynamic_txpower(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-       rtlpriv->dm.dynamic_txpower_enable = false;
-
+       if (rtlpriv->rtlhal.interface == INTF_USB &&
+           rtlpriv->rtlhal.board_type & 0x1) {
+               dm_savepowerindex(hw);
+               rtlpriv->dm.dynamic_txpower_enable = true;
+       } else {
+               rtlpriv->dm.dynamic_txpower_enable = false;
+       }
        rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
        rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
 }
@@ -524,9 +598,14 @@ void rtl92c_dm_write_dig(struct ieee80211_hw *hw)
                 dm_digtable->cur_igvalue, dm_digtable->pre_igvalue,
                 dm_digtable->back_val);
 
-       dm_digtable->cur_igvalue += 2;
-       if (dm_digtable->cur_igvalue > 0x3f)
-               dm_digtable->cur_igvalue = 0x3f;
+       if (rtlpriv->rtlhal.interface == INTF_USB &&
+           !dm_digtable->dig_enable_flag) {
+               dm_digtable->pre_igvalue = 0x17;
+               return;
+       }
+       dm_digtable->cur_igvalue -= 1;
+       if (dm_digtable->cur_igvalue < DM_DIG_MIN)
+               dm_digtable->cur_igvalue = DM_DIG_MIN;
 
        if (dm_digtable->pre_igvalue != dm_digtable->cur_igvalue) {
                rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f,
@@ -536,11 +615,47 @@ void rtl92c_dm_write_dig(struct ieee80211_hw *hw)
 
                dm_digtable->pre_igvalue = dm_digtable->cur_igvalue;
        }
+       RT_TRACE(rtlpriv, COMP_DIG, DBG_WARNING,
+                "dig values 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+                dm_digtable->cur_igvalue, dm_digtable->pre_igvalue,
+                dm_digtable->rssi_val_min, dm_digtable->back_val,
+                dm_digtable->rx_gain_max, dm_digtable->rx_gain_min,
+                dm_digtable->large_fa_hit, dm_digtable->forbidden_igi);
 }
 EXPORT_SYMBOL(rtl92c_dm_write_dig);
 
 static void rtl92c_dm_pwdb_monitor(struct ieee80211_hw *hw)
 {
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       long tmpentry_max_pwdb = 0, tmpentry_min_pwdb = 0xff;
+
+       if (mac->link_state != MAC80211_LINKED)
+               return;
+
+       if (mac->opmode == NL80211_IFTYPE_ADHOC ||
+           mac->opmode == NL80211_IFTYPE_AP) {
+               /* TODO: Handle ADHOC and AP Mode */
+       }
+
+       if (tmpentry_max_pwdb != 0)
+               rtlpriv->dm.entry_max_undec_sm_pwdb = tmpentry_max_pwdb;
+       else
+               rtlpriv->dm.entry_max_undec_sm_pwdb = 0;
+
+       if (tmpentry_min_pwdb != 0xff)
+               rtlpriv->dm.entry_min_undec_sm_pwdb = tmpentry_min_pwdb;
+       else
+               rtlpriv->dm.entry_min_undec_sm_pwdb = 0;
+
+/* TODO:
+ *     if (mac->opmode == NL80211_IFTYPE_STATION) {
+ *             if (rtlpriv->rtlhal.fw_ready) {
+ *                     u32 param = (u32)(rtlpriv->dm.undec_sm_pwdb << 16);
+ *                     rtl8192c_set_rssi_cmd(hw, param);
+ *             }
+ *     }
+ */
 }
 
 void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw)
@@ -750,6 +865,7 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
                                rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i];
                        rtlpriv->dm.cck_index = cck_index_old;
                }
+               /* Handle USB High PA boards */
 
                delta = (thermalvalue > rtlpriv->dm.thermalvalue) ?
                    (thermalvalue - rtlpriv->dm.thermalvalue) :
@@ -1140,22 +1256,22 @@ void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct ps_t *dm_pstable = &rtlpriv->dm_pstable;
-       static u8 initialize;
-       static u32 reg_874, reg_c70, reg_85c, reg_a74;
 
-       if (initialize == 0) {
-               reg_874 = (rtl_get_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
-                                        MASKDWORD) & 0x1CC000) >> 14;
+       if (!rtlpriv->reg_init) {
+               rtlpriv->reg_874 = (rtl_get_bbreg(hw,
+                                                 RFPGA0_XCD_RFINTERFACESW,
+                                                 MASKDWORD) & 0x1CC000) >> 14;
 
-               reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1,
-                                        MASKDWORD) & BIT(3)) >> 3;
+               rtlpriv->reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1,
+                                   MASKDWORD) & BIT(3)) >> 3;
 
-               reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL,
-                                        MASKDWORD) & 0xFF000000) >> 24;
+               rtlpriv->reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL,
+                                   MASKDWORD) & 0xFF000000) >> 24;
 
-               reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) & 0xF000) >> 12;
+               rtlpriv->reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) &
+                                   0xF000) >> 12;
 
-               initialize = 1;
+               rtlpriv->reg_init = true;
        }
 
        if (!bforce_in_normal) {
@@ -1192,12 +1308,12 @@ void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal)
                        rtl_set_bbreg(hw, 0x818, BIT(28), 0x1);
                } else {
                        rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
-                                     0x1CC000, reg_874);
+                                     0x1CC000, rtlpriv->reg_874);
                        rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3),
-                                     reg_c70);
+                                     rtlpriv->reg_c70);
                        rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, 0xFF000000,
-                                     reg_85c);
-                       rtl_set_bbreg(hw, 0xa74, 0xF000, reg_a74);
+                                     rtlpriv->reg_85c);
+                       rtl_set_bbreg(hw, 0xa74, 0xF000, rtlpriv->reg_a74);
                        rtl_set_bbreg(hw, 0x818, BIT(28), 0x0);
                }
 
@@ -1213,6 +1329,7 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw)
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
+       /* Determine the minimum RSSI */
        if (((mac->link_state == MAC80211_NOLINK)) &&
            (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
                dm_pstable->rssi_val_min = 0;
@@ -1241,6 +1358,7 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw)
                         dm_pstable->rssi_val_min);
        }
 
+       /* Power Saving for 92C */
        if (IS_92C_SERIAL(rtlhal->version))
                ;/* rtl92c_dm_1r_cca(hw); */
        else
@@ -1252,12 +1370,23 @@ void rtl92c_dm_init(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
        rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
+       rtlpriv->dm.dm_flag = DYNAMIC_FUNC_DISABLE | DYNAMIC_FUNC_DIG;
+       rtlpriv->dm.undec_sm_pwdb = -1;
+       rtlpriv->dm.undec_sm_cck = -1;
+       rtlpriv->dm.dm_initialgain_enable = true;
        rtl92c_dm_diginit(hw);
+
+       rtlpriv->dm.dm_flag |= HAL_DM_HIPWR_DISABLE;
        rtl92c_dm_init_dynamic_txpower(hw);
+
        rtl92c_dm_init_edca_turbo(hw);
        rtl92c_dm_init_rate_adaptive_mask(hw);
+       rtlpriv->dm.dm_flag |= DYNAMIC_FUNC_SS;
        rtl92c_dm_initialize_txpower_tracking(hw);
        rtl92c_dm_init_dynamic_bb_powersaving(hw);
+
+       rtlpriv->dm.ofdm_pkt_cnt = 0;
+       rtlpriv->dm.dm_rssi_sel = RSSI_DEFAULT;
 }
 EXPORT_SYMBOL(rtl92c_dm_init);
 
@@ -1308,7 +1437,7 @@ void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
        }
 
        if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
-               rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+               rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL2;
                RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
                         "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n");
        } else if ((undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
@@ -1328,8 +1457,16 @@ void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
                         "PHY_SetTxPowerLevel8192S() Channel = %d\n",
                         rtlphy->current_channel);
                rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel);
+               if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+                   TXHIGHPWRLEVEL_NORMAL)
+                       dm_restorepowerindex(hw);
+               else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+                        TXHIGHPWRLEVEL_LEVEL1)
+                       dm_writepowerindex(hw, 0x14);
+               else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+                        TXHIGHPWRLEVEL_LEVEL2)
+                       dm_writepowerindex(hw, 0x10);
        }
-
        rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
 }
 
@@ -1400,12 +1537,6 @@ u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw)
        else
                curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW);
 
-       /* Set Tx Power according to BT status. */
-       if (undec_sm_pwdb >= 30)
-               curr_bt_rssi_state |=  BT_RSSI_STATE_TXPOWER_LOW;
-       else if (undec_sm_pwdb < 25)
-               curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW);
-
        /* Check BT state related to BT_Idle in B/G mode. */
        if (undec_sm_pwdb < 15)
                curr_bt_rssi_state |=  BT_RSSI_STATE_BG_EDCA_LOW;
index 518e208c018064049406a0b653cdd5763d601440..4f232a063636ee01aa137efffca38b0dcc034b21 100644 (file)
 #define TX_POWER_NEAR_FIELD_THRESH_LVL2                74
 #define TX_POWER_NEAR_FIELD_THRESH_LVL1                67
 
+#define DYNAMIC_FUNC_DISABLE                   0x0
+#define DYNAMIC_FUNC_DIG                       BIT(0)
+#define DYNAMIC_FUNC_HP                                BIT(1)
+#define DYNAMIC_FUNC_SS                                BIT(2) /*Tx Power Tracking*/
+#define DYNAMIC_FUNC_BT                                BIT(3)
+#define DYNAMIC_FUNC_ANT_DIV                   BIT(4)
+
+#define        RSSI_CCK                                0
+#define        RSSI_OFDM                               1
+#define        RSSI_DEFAULT                            2
+
 struct swat_t {
        u8 failure_cnt;
        u8 try_flag;
@@ -167,5 +178,8 @@ void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw);
 void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery);
 void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw);
 void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw);
+void dm_savepowerindex(struct ieee80211_hw *hw);
+void dm_writepowerindex(struct ieee80211_hw *hw, u8 value);
+void dm_restorepowerindex(struct ieee80211_hw *hw);
 
 #endif
index 0c0e78263a665190aacf3d33d21fa87b99d4dd86..9e32ac8a4425f5dd9b9d3c8f4c57db66d684c1dd 100644 (file)
@@ -1147,6 +1147,12 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
                0x522, 0x550, 0x551, 0x040
        };
 
+       u32 iqk_bb_reg_92C[9] = {
+               0xc04, 0xc08, 0x874, 0xb68,
+               0xb6c, 0x870, 0x860, 0x864,
+               0x800
+       };
+
        const u32 retrycount = 2;
 
        if (t == 0) {
@@ -1157,6 +1163,8 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
                                                rtlphy->adda_backup, 16);
                _rtl92c_phy_save_mac_registers(hw, iqk_mac_reg,
                                               rtlphy->iqk_mac_backup);
+               _rtl92c_phy_save_adda_registers(hw, iqk_bb_reg_92C,
+                                               rtlphy->iqk_bb_backup, 9);
        }
        _rtl92c_phy_path_adda_on(hw, adda_reg, true, is2t);
        if (t == 0) {
@@ -1167,14 +1175,18 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
 
        if (!rtlphy->rfpi_enable)
                _rtl92c_phy_pi_mode_switch(hw, true);
-       if (t == 0) {
-               rtlphy->reg_c04 = rtl_get_bbreg(hw, 0xc04, MASKDWORD);
-               rtlphy->reg_c08 = rtl_get_bbreg(hw, 0xc08, MASKDWORD);
-               rtlphy->reg_874 = rtl_get_bbreg(hw, 0x874, MASKDWORD);
-       }
+
+       rtl_set_bbreg(hw, 0x800, BIT(24), 0x0);
+
        rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600);
        rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4);
        rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000);
+
+       rtl_set_bbreg(hw, 0x870, BIT(10), 0x1);
+       rtl_set_bbreg(hw, 0x870, BIT(26), 0x1);
+       rtl_set_bbreg(hw, 0x860, BIT(10), 0x0);
+       rtl_set_bbreg(hw, 0x864, BIT(10), 0x0);
+
        if (is2t) {
                rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
                rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000);
@@ -1239,13 +1251,9 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
                                        0x3FF0000) >> 16;
                }
        }
-       rtl_set_bbreg(hw, 0xc04, MASKDWORD, rtlphy->reg_c04);
-       rtl_set_bbreg(hw, 0x874, MASKDWORD, rtlphy->reg_874);
-       rtl_set_bbreg(hw, 0xc08, MASKDWORD, rtlphy->reg_c08);
+
        rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
-       rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3);
-       if (is2t)
-               rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3);
+
        if (t != 0) {
                if (!rtlphy->rfpi_enable)
                        _rtl92c_phy_pi_mode_switch(hw, false);
@@ -1253,6 +1261,15 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
                                                  rtlphy->adda_backup, 16);
                _rtl92c_phy_reload_mac_registers(hw, iqk_mac_reg,
                                                 rtlphy->iqk_mac_backup);
+               _rtl92c_phy_reload_adda_registers(hw, iqk_bb_reg_92C,
+                                                 rtlphy->iqk_bb_backup, 9);
+
+               rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3);
+               if (is2t)
+                       rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3);
+
+               rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x01008c00);
+               rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x01008c00);
        }
 }
 
index 16a0b9e59acf726745d3ad90c5480f2c4151096d..c16209a336eac66c6b7ad78afa6ac3d24b197796 100644 (file)
@@ -101,6 +101,15 @@ void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw)
                         "PHY_SetTxPowerLevel8192S() Channel = %d\n",
                         rtlphy->current_channel);
                rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel);
+               if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+                   TXHIGHPWRLEVEL_NORMAL)
+                       dm_restorepowerindex(hw);
+               else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+                        TXHIGHPWRLEVEL_LEVEL1)
+                       dm_writepowerindex(hw, 0x14);
+               else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+                        TXHIGHPWRLEVEL_LEVEL2)
+                       dm_writepowerindex(hw, 0x10);
        }
 
        rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
index d947e7d350bbc146d7b56b1c463c9dce829b5dce..fafa6bac2a3f5062b98911dc5802dd9e82fc2b95 100644 (file)
@@ -30,3 +30,6 @@
 #include "../rtl8192ce/dm.h"
 
 void rtl92cu_dm_dynamic_txpower(struct ieee80211_hw *hw);
+void dm_savepowerindex(struct ieee80211_hw *hw);
+void dm_writepowerindex(struct ieee80211_hw *hw, u8 value);
+void dm_restorepowerindex(struct ieee80211_hw *hw);
index 189ba124a8c6f4cfca817e77d4b0c7027c976459..468bf73cc883f41bf26222cc7aa52e17c5ed96a3 100644 (file)
@@ -1022,7 +1022,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
        if (ppsc->rfpwr_state == ERFON) {
                rtl92c_phy_set_rfpath_switch(hw, 1);
                if (iqk_initialized) {
-                       rtl92c_phy_iq_calibrate(hw, false);
+                       rtl92c_phy_iq_calibrate(hw, true);
                } else {
                        rtl92c_phy_iq_calibrate(hw, false);
                        iqk_initialized = true;
index 34e56308301e8942c9ed3f216ad307a9b6b07763..0c09240eadccdee5fe6fd6ab266c561d7019684b 100644 (file)
@@ -120,6 +120,7 @@ bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
        u16 regval;
+       u32 regval32;
        u8 b_reg_hwparafile = 1;
 
        _rtl92c_phy_init_bb_rf_register_definition(hw);
@@ -135,8 +136,11 @@ bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw)
        } else if (IS_HARDWARE_TYPE_8192CU(rtlhal)) {
                rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD |
                               FEN_BB_GLB_RSTn | FEN_BBRSTB);
-               rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f);
        }
+       regval32 = rtl_read_dword(rtlpriv, 0x87c);
+       rtl_write_dword(rtlpriv, 0x87c, regval32 & (~BIT(31)));
+       if (IS_HARDWARE_TYPE_8192CU(rtlhal))
+               rtl_write_byte(rtlpriv, REG_LDOHCI12_CTRL, 0x0f);
        rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80);
        if (b_reg_hwparafile == 1)
                rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw);
index 2119313a737bab21e9c304627b2acb56d2a3ab43..b878d56d2f4df6020449e223dfed618c4d36edbc 100644 (file)
@@ -85,17 +85,15 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
        if (mac->act_scanning) {
                tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
                tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
-               if (turbo_scanoff) {
-                       for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
-                               tx_agc[idx1] = ppowerlevel[idx1] |
-                                   (ppowerlevel[idx1] << 8) |
-                                   (ppowerlevel[idx1] << 16) |
-                                   (ppowerlevel[idx1] << 24);
-                               if (rtlhal->interface == INTF_USB) {
-                                       if (tx_agc[idx1] > 0x20 &&
-                                           rtlefuse->external_pa)
-                                               tx_agc[idx1] = 0x20;
-                               }
+               for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+                       tx_agc[idx1] = ppowerlevel[idx1] |
+                           (ppowerlevel[idx1] << 8) |
+                           (ppowerlevel[idx1] << 16) |
+                           (ppowerlevel[idx1] << 24);
+                       if (rtlhal->interface == INTF_USB) {
+                               if (tx_agc[idx1] > 0x20 &&
+                                   rtlefuse->external_pa)
+                                       tx_agc[idx1] = 0x20;
                        }
                }
        } else {
@@ -107,7 +105,7 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
                           TXHIGHPWRLEVEL_LEVEL2) {
                        tx_agc[RF90_PATH_A] = 0x00000000;
                        tx_agc[RF90_PATH_B] = 0x00000000;
-               } else{
+               } else {
                        for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
                                tx_agc[idx1] = ppowerlevel[idx1] |
                                    (ppowerlevel[idx1] << 8) |
@@ -373,7 +371,12 @@ static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw,
                            regoffset == RTXAGC_B_MCS07_MCS04)
                                regoffset = 0xc98;
                        for (i = 0; i < 3; i++) {
-                               writeVal = (writeVal > 6) ? (writeVal - 6) : 0;
+                               if (i != 2)
+                                       writeVal = (writeVal > 8) ?
+                                                  (writeVal - 8) : 0;
+                               else
+                                       writeVal = (writeVal > 6) ?
+                                                  (writeVal - 6) : 0;
                                rtl_write_byte(rtlpriv, (u32)(regoffset + i),
                                              (u8)writeVal);
                        }
index 9936de716ad58929e50dc0e6f02fca77f5efee68..8501954cfb444d8d8f74dfb4d66cf097b45e83fd 100644 (file)
@@ -50,6 +50,9 @@ MODULE_AUTHOR("Larry Finger   <Larry.Finger@lwfinger.net>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n USB wireless");
 MODULE_FIRMWARE("rtlwifi/rtl8192cufw.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin");
 
 static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
 {
@@ -69,14 +72,21 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
                         "Can't alloc buffer for fw\n");
                return 1;
        }
-
+       if (IS_VENDOR_UMC_A_CUT(rtlpriv->rtlhal.version) &&
+           !IS_92C_SERIAL(rtlpriv->rtlhal.version)) {
+               rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_A.bin";
+       } else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlpriv->rtlhal.version)) {
+               rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_B.bin";
+       } else {
+               rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_TMSC.bin";
+       }
+       /* provide name of alternative file */
+       rtlpriv->cfg->alt_fw_name = "rtlwifi/rtl8192cufw.bin";
        pr_info("Loading firmware %s\n", rtlpriv->cfg->fw_name);
        rtlpriv->max_fw_size = 0x4000;
        err = request_firmware_nowait(THIS_MODULE, 1,
                                      rtlpriv->cfg->fw_name, rtlpriv->io.dev,
                                      GFP_KERNEL, hw, rtl_fw_cb);
-
-
        return err;
 }
 
index 966be519edb89b8780778ad0145e4ece80c6621a..7903c154de00d2cd193e54ed0d33a27d68ca9c1c 100644 (file)
@@ -36,7 +36,7 @@ u32 RTL8192CUPHY_REG_2TARRAY[RTL8192CUPHY_REG_2TARRAY_LENGTH] = {
        0x804, 0x00000003,
        0x808, 0x0000fc00,
        0x80c, 0x0000000a,
-       0x810, 0x10005388,
+       0x810, 0x10000330,
        0x814, 0x020c3d10,
        0x818, 0x02200385,
        0x81c, 0x00000000,
@@ -110,22 +110,22 @@ u32 RTL8192CUPHY_REG_2TARRAY[RTL8192CUPHY_REG_2TARRAY_LENGTH] = {
        0xc44, 0x000100b7,
        0xc48, 0xec020107,
        0xc4c, 0x007f037f,
-       0xc50, 0x6954341e,
+       0xc50, 0x69543420,
        0xc54, 0x43bc0094,
-       0xc58, 0x6954341e,
+       0xc58, 0x69543420,
        0xc5c, 0x433c0094,
        0xc60, 0x00000000,
        0xc64, 0x5116848b,
        0xc68, 0x47c00bff,
        0xc6c, 0x00000036,
        0xc70, 0x2c7f000d,
-       0xc74, 0x0186115b,
+       0xc74, 0x2186115b,
        0xc78, 0x0000001f,
        0xc7c, 0x00b99612,
        0xc80, 0x40000100,
        0xc84, 0x20f60000,
        0xc88, 0x40000100,
-       0xc8c, 0x20200000,
+       0xc8c, 0xa0e40000,
        0xc90, 0x00121820,
        0xc94, 0x00000000,
        0xc98, 0x00121820,
@@ -226,7 +226,7 @@ u32 RTL8192CUPHY_REG_1TARRAY[RTL8192CUPHY_REG_1TARRAY_LENGTH] = {
        0x804, 0x00000001,
        0x808, 0x0000fc00,
        0x80c, 0x0000000a,
-       0x810, 0x10005388,
+       0x810, 0x10000330,
        0x814, 0x020c3d10,
        0x818, 0x02200385,
        0x81c, 0x00000000,
@@ -300,9 +300,9 @@ u32 RTL8192CUPHY_REG_1TARRAY[RTL8192CUPHY_REG_1TARRAY_LENGTH] = {
        0xc44, 0x000100b7,
        0xc48, 0xec020107,
        0xc4c, 0x007f037f,
-       0xc50, 0x6954341e,
+       0xc50, 0x69543420,
        0xc54, 0x43bc0094,
-       0xc58, 0x6954341e,
+       0xc58, 0x69543420,
        0xc5c, 0x433c0094,
        0xc60, 0x00000000,
        0xc64, 0x5116848b,
@@ -340,7 +340,7 @@ u32 RTL8192CUPHY_REG_1TARRAY[RTL8192CUPHY_REG_1TARRAY_LENGTH] = {
        0xce4, 0x00000000,
        0xce8, 0x37644302,
        0xcec, 0x2f97d40c,
-       0xd00, 0x00080740,
+       0xd00, 0x00000740,
        0xd04, 0x00020401,
        0xd08, 0x0000907f,
        0xd0c, 0x20010201,
@@ -633,17 +633,17 @@ u32 RTL8192CURADIOA_2TARRAY[RTL8192CURADIOA_2TARRAYLENGTH] = {
        0x012, 0x00071000,
        0x012, 0x000b0000,
        0x012, 0x000fc000,
-       0x013, 0x000287af,
+       0x013, 0x000287b3,
        0x013, 0x000244b7,
        0x013, 0x000204ab,
        0x013, 0x0001c49f,
        0x013, 0x00018493,
-       0x013, 0x00014297,
-       0x013, 0x00010295,
-       0x013, 0x0000c298,
-       0x013, 0x0000819c,
-       0x013, 0x000040a8,
-       0x013, 0x0000001c,
+       0x013, 0x0001429b,
+       0x013, 0x00010299,
+       0x013, 0x0000c29c,
+       0x013, 0x000081a0,
+       0x013, 0x000040ac,
+       0x013, 0x00000020,
        0x014, 0x0001944c,
        0x014, 0x00059444,
        0x014, 0x0009944c,
@@ -932,10 +932,10 @@ u32 RTL8192CUMAC_2T_ARRAY[RTL8192CUMAC_2T_ARRAYLENGTH] = {
        0x608, 0x0000000e,
        0x609, 0x0000002a,
        0x652, 0x00000020,
-       0x63c, 0x0000000a,
-       0x63d, 0x0000000e,
-       0x63e, 0x0000000a,
-       0x63f, 0x0000000e,
+       0x63c, 0x00000008,
+       0x63d, 0x00000008,
+       0x63e, 0x0000000c,
+       0x63f, 0x0000000c,
        0x66e, 0x00000005,
        0x700, 0x00000021,
        0x701, 0x00000043,
index 8ed31744a0548467ad0536108b76e9fcfe0592da..4f083fc1d3607c41eb5a471f30ff04c3d234e557 100644 (file)
@@ -176,6 +176,7 @@ static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus)
        struct rtl_sta_info *drv_priv = NULL;
        struct ieee80211_sta *sta = NULL;
        long undec_sm_pwdb;
+       long undec_sm_cck;
 
        rcu_read_lock();
        if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION)
@@ -185,12 +186,16 @@ static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus)
        if (sta) {
                drv_priv = (struct rtl_sta_info *) sta->drv_priv;
                undec_sm_pwdb = drv_priv->rssi_stat.undec_sm_pwdb;
+               undec_sm_cck = drv_priv->rssi_stat.undec_sm_cck;
        } else {
                undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
+               undec_sm_cck = rtlpriv->dm.undec_sm_cck;
        }
 
        if (undec_sm_pwdb < 0)
                undec_sm_pwdb = pstatus->rx_pwdb_all;
+       if (undec_sm_cck < 0)
+               undec_sm_cck = pstatus->rx_pwdb_all;
        if (pstatus->rx_pwdb_all > (u32) undec_sm_pwdb) {
                undec_sm_pwdb = (((undec_sm_pwdb) *
                      (RX_SMOOTH_FACTOR - 1)) +
@@ -200,6 +205,15 @@ static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus)
                undec_sm_pwdb = (((undec_sm_pwdb) * (RX_SMOOTH_FACTOR - 1)) +
                     (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
        }
+       if (pstatus->rx_pwdb_all > (u32) undec_sm_cck) {
+               undec_sm_cck = (((undec_sm_pwdb) *
+                     (RX_SMOOTH_FACTOR - 1)) +
+                    (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
+               undec_sm_cck = undec_sm_cck + 1;
+       } else {
+               undec_sm_pwdb = (((undec_sm_cck) * (RX_SMOOTH_FACTOR - 1)) +
+                    (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
+       }
 
        if (sta) {
                drv_priv->rssi_stat.undec_sm_pwdb = undec_sm_pwdb;
index 6e2b5c5c83c8d21234ee013c802d7af317f6db8c..4933f02ce1d510cf94ef127b59ea025238ad9476 100644 (file)
@@ -475,14 +475,14 @@ static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw,
                        rtlpriv->stats.rxbytesunicast +=  skb->len;
                }
 
-               rtl_is_special_data(hw, skb, false);
-
                if (ieee80211_is_data(fc)) {
                        rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX);
 
                        if (unicast)
                                rtlpriv->link_info.num_rx_inperiod++;
                }
+               /* static bcn for roaming */
+               rtl_beacon_statistic(hw, skb);
        }
 }
 
@@ -517,8 +517,6 @@ static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw,
                        rtlpriv->stats.rxbytesunicast +=  skb->len;
                }
 
-               rtl_is_special_data(hw, skb, false);
-
                if (ieee80211_is_data(fc)) {
                        rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX);
 
@@ -553,7 +551,7 @@ static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb)
        }
 }
 
-#define __RX_SKB_MAX_QUEUED    32
+#define __RX_SKB_MAX_QUEUED    64
 
 static void _rtl_rx_work(unsigned long param)
 {
index 0c65386fa30d5cecda61d9d4ca290b6577df2f59..8c647391bedf0f4bc5ef4fca39b7ca39a05e1483 100644 (file)
@@ -1033,6 +1033,7 @@ struct rtl_ht_agg {
 
 struct rssi_sta {
        long undec_sm_pwdb;
+       long undec_sm_cck;
 };
 
 struct rtl_tid_data {
@@ -1323,8 +1324,10 @@ struct fast_ant_training {
 struct rtl_dm {
        /*PHY status for Dynamic Management */
        long entry_min_undec_sm_pwdb;
+       long undec_sm_cck;
        long undec_sm_pwdb;     /*out dm */
        long entry_max_undec_sm_pwdb;
+       s32 ofdm_pkt_cnt;
        bool dm_initialgain_enable;
        bool dynamic_txpower_enable;
        bool current_turbo_edca;
@@ -1339,6 +1342,7 @@ struct rtl_dm {
        bool inform_fw_driverctrldm;
        bool current_mrc_switch;
        u8 txpowercount;
+       u8 powerindex_backup[6];
 
        u8 thermalvalue_rxgain;
        u8 thermalvalue_iqk;
@@ -1350,7 +1354,9 @@ struct rtl_dm {
        bool done_txpower;
        u8 dynamic_txhighpower_lvl;     /*Tx high power level */
        u8 dm_flag;             /*Indicate each dynamic mechanism's status. */
+       u8 dm_flag_tmp;
        u8 dm_type;
+       u8 dm_rssi_sel;
        u8 txpower_track_control;
        bool interrupt_migration;
        bool disable_tx_int;
@@ -1804,6 +1810,7 @@ struct rtl_hal_cfg {
        bool write_readback;
        char *name;
        char *fw_name;
+       char *alt_fw_name;
        struct rtl_hal_ops *ops;
        struct rtl_mod_params *mod_params;
        struct rtl_hal_usbint_cfg *usb_interface_cfg;
@@ -1948,6 +1955,7 @@ struct dig_t {
        u8 pre_ccastate;
        u8 cur_ccasate;
        u8 large_fa_hit;
+       u8 dig_dynamic_min;
        u8 forbidden_igi;
        u8 dig_state;
        u8 dig_highpwrstate;
@@ -2028,22 +2036,15 @@ struct rtl_priv {
        struct dig_t dm_digtable;
        struct ps_t dm_pstable;
 
-       /* section shared by individual drivers */
-       union {
-               struct {        /* data buffer pointer for USB reads */
-                       __le32 *usb_data;
-                       int usb_data_index;
-                       bool initialized;
-               };
-               struct {        /* section for 8723ae */
-                       bool reg_init;  /* true if regs saved */
-                       u32 reg_874;
-                       u32 reg_c70;
-                       u32 reg_85c;
-                       u32 reg_a74;
-                       bool bt_operation_on;
-               };
-       };
+       u32 reg_874;
+       u32 reg_c70;
+       u32 reg_85c;
+       u32 reg_a74;
+       bool reg_init;  /* true if regs saved */
+       bool bt_operation_on;
+       __le32 *usb_data;
+       int usb_data_index;
+       bool initialized;
        bool enter_ps;  /* true when entering PS */
        u8 rate_mask[5];
 
index db6430c1a08414650a894d3e8a6d41c57cba1711..374268d5ac6a70e97355269489538ad31d802cbb 100644 (file)
@@ -18,10 +18,8 @@ int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod,
        wl1251_debug(DEBUG_ACX, "acx frame rates");
 
        rates = kzalloc(sizeof(*rates), GFP_KERNEL);
-       if (!rates) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!rates)
+               return -ENOMEM;
 
        rates->tx_ctrl_frame_rate = ctrl_rate;
        rates->tx_ctrl_frame_mod = ctrl_mod;
@@ -49,10 +47,8 @@ int wl1251_acx_station_id(struct wl1251 *wl)
        wl1251_debug(DEBUG_ACX, "acx dot11_station_id");
 
        mac = kzalloc(sizeof(*mac), GFP_KERNEL);
-       if (!mac) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!mac)
+               return -ENOMEM;
 
        for (i = 0; i < ETH_ALEN; i++)
                mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i];
@@ -74,10 +70,8 @@ int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id)
        wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id);
 
        default_key = kzalloc(sizeof(*default_key), GFP_KERNEL);
-       if (!default_key) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!default_key)
+               return -ENOMEM;
 
        default_key->id = key_id;
 
@@ -104,10 +98,8 @@ int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
        wl1251_debug(DEBUG_ACX, "acx wake up conditions");
 
        wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
-       if (!wake_up) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!wake_up)
+               return -ENOMEM;
 
        wake_up->wake_up_event = wake_up_event;
        wake_up->listen_interval = listen_interval;
@@ -132,16 +124,13 @@ int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth)
        wl1251_debug(DEBUG_ACX, "acx sleep auth");
 
        auth = kzalloc(sizeof(*auth), GFP_KERNEL);
-       if (!auth) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!auth)
+               return -ENOMEM;
 
        auth->sleep_auth = sleep_auth;
 
        ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
 
-out:
        kfree(auth);
        return ret;
 }
@@ -154,10 +143,8 @@ int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len)
        wl1251_debug(DEBUG_ACX, "acx fw rev");
 
        rev = kzalloc(sizeof(*rev), GFP_KERNEL);
-       if (!rev) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!rev)
+               return -ENOMEM;
 
        ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev));
        if (ret < 0) {
@@ -191,10 +178,8 @@ int wl1251_acx_tx_power(struct wl1251 *wl, int power)
                return -EINVAL;
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
-       if (!acx) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!acx)
+               return -ENOMEM;
 
        acx->current_tx_power = power * 10;
 
@@ -217,10 +202,8 @@ int wl1251_acx_feature_cfg(struct wl1251 *wl)
        wl1251_debug(DEBUG_ACX, "acx feature cfg");
 
        feature = kzalloc(sizeof(*feature), GFP_KERNEL);
-       if (!feature) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!feature)
+               return -ENOMEM;
 
        /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
        feature->data_flow_options = 0;
@@ -261,10 +244,8 @@ int wl1251_acx_data_path_params(struct wl1251 *wl,
        wl1251_debug(DEBUG_ACX, "acx data path params");
 
        params = kzalloc(sizeof(*params), GFP_KERNEL);
-       if (!params) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!params)
+               return -ENOMEM;
 
        params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE;
        params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE;
@@ -309,10 +290,8 @@ int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time)
        wl1251_debug(DEBUG_ACX, "acx rx msdu life time");
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
-       if (!acx) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!acx)
+               return -ENOMEM;
 
        acx->lifetime = life_time;
        ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME,
@@ -335,10 +314,8 @@ int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter)
        wl1251_debug(DEBUG_ACX, "acx rx config");
 
        rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL);
-       if (!rx_config) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!rx_config)
+               return -ENOMEM;
 
        rx_config->config_options = config;
        rx_config->filter_options = filter;
@@ -363,10 +340,8 @@ int wl1251_acx_pd_threshold(struct wl1251 *wl)
        wl1251_debug(DEBUG_ACX, "acx data pd threshold");
 
        pd = kzalloc(sizeof(*pd), GFP_KERNEL);
-       if (!pd) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!pd)
+               return -ENOMEM;
 
        /* FIXME: threshold value not set */
 
@@ -389,10 +364,8 @@ int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time)
        wl1251_debug(DEBUG_ACX, "acx slot");
 
        slot = kzalloc(sizeof(*slot), GFP_KERNEL);
-       if (!slot) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!slot)
+               return -ENOMEM;
 
        slot->wone_index = STATION_WONE_INDEX;
        slot->slot_time = slot_time;
@@ -416,10 +389,8 @@ int wl1251_acx_group_address_tbl(struct wl1251 *wl)
        wl1251_debug(DEBUG_ACX, "acx group address tbl");
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
-       if (!acx) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!acx)
+               return -ENOMEM;
 
        /* MAC filtering */
        acx->enabled = 0;
@@ -444,10 +415,8 @@ int wl1251_acx_service_period_timeout(struct wl1251 *wl)
        int ret;
 
        rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL);
-       if (!rx_timeout) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!rx_timeout)
+               return -ENOMEM;
 
        wl1251_debug(DEBUG_ACX, "acx service period timeout");
 
@@ -475,10 +444,8 @@ int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold)
        wl1251_debug(DEBUG_ACX, "acx rts threshold");
 
        rts = kzalloc(sizeof(*rts), GFP_KERNEL);
-       if (!rts) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!rts)
+               return -ENOMEM;
 
        rts->threshold = rts_threshold;
 
@@ -501,10 +468,8 @@ int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter)
        wl1251_debug(DEBUG_ACX, "acx beacon filter opt");
 
        beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL);
-       if (!beacon_filter) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!beacon_filter)
+               return -ENOMEM;
 
        beacon_filter->enable = enable_filter;
        beacon_filter->max_num_beacons = 0;
@@ -530,10 +495,8 @@ int wl1251_acx_beacon_filter_table(struct wl1251 *wl)
        wl1251_debug(DEBUG_ACX, "acx beacon filter table");
 
        ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL);
-       if (!ie_table) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!ie_table)
+               return -ENOMEM;
 
        /* configure default beacon pass-through rules */
        ie_table->num_ie = 1;
@@ -560,10 +523,8 @@ int wl1251_acx_conn_monit_params(struct wl1251 *wl)
        wl1251_debug(DEBUG_ACX, "acx connection monitor parameters");
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
-       if (!acx) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!acx)
+               return -ENOMEM;
 
        acx->synch_fail_thold = SYNCH_FAIL_DEFAULT_THRESHOLD;
        acx->bss_lose_timeout = NO_BEACON_DEFAULT_TIMEOUT;
@@ -589,10 +550,8 @@ int wl1251_acx_sg_enable(struct wl1251 *wl)
        wl1251_debug(DEBUG_ACX, "acx sg enable");
 
        pta = kzalloc(sizeof(*pta), GFP_KERNEL);
-       if (!pta) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!pta)
+               return -ENOMEM;
 
        pta->enable = SG_ENABLE;
 
@@ -615,10 +574,8 @@ int wl1251_acx_sg_cfg(struct wl1251 *wl)
        wl1251_debug(DEBUG_ACX, "acx sg cfg");
 
        param = kzalloc(sizeof(*param), GFP_KERNEL);
-       if (!param) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!param)
+               return -ENOMEM;
 
        /* BT-WLAN coext parameters */
        param->min_rate = RATE_INDEX_24MBPS;
@@ -669,10 +626,8 @@ int wl1251_acx_cca_threshold(struct wl1251 *wl)
        wl1251_debug(DEBUG_ACX, "acx cca threshold");
 
        detection = kzalloc(sizeof(*detection), GFP_KERNEL);
-       if (!detection) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!detection)
+               return -ENOMEM;
 
        detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
        detection->tx_energy_detection = 0;
@@ -682,7 +637,6 @@ int wl1251_acx_cca_threshold(struct wl1251 *wl)
        if (ret < 0)
                wl1251_warning("failed to set cca threshold: %d", ret);
 
-out:
        kfree(detection);
        return ret;
 }
@@ -695,10 +649,8 @@ int wl1251_acx_bcn_dtim_options(struct wl1251 *wl)
        wl1251_debug(DEBUG_ACX, "acx bcn dtim options");
 
        bb = kzalloc(sizeof(*bb), GFP_KERNEL);
-       if (!bb) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!bb)
+               return -ENOMEM;
 
        bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE;
        bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE;
@@ -724,10 +676,8 @@ int wl1251_acx_aid(struct wl1251 *wl, u16 aid)
        wl1251_debug(DEBUG_ACX, "acx aid");
 
        acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL);
-       if (!acx_aid) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!acx_aid)
+               return -ENOMEM;
 
        acx_aid->aid = aid;
 
@@ -750,10 +700,8 @@ int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask)
        wl1251_debug(DEBUG_ACX, "acx event mbox mask");
 
        mask = kzalloc(sizeof(*mask), GFP_KERNEL);
-       if (!mask) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!mask)
+               return -ENOMEM;
 
        /* high event mask is unused */
        mask->high_event_mask = 0xffffffff;
@@ -805,10 +753,8 @@ int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble)
        wl1251_debug(DEBUG_ACX, "acx_set_preamble");
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
-       if (!acx) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!acx)
+               return -ENOMEM;
 
        acx->preamble = preamble;
 
@@ -832,10 +778,8 @@ int wl1251_acx_cts_protect(struct wl1251 *wl,
        wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect");
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
-       if (!acx) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!acx)
+               return -ENOMEM;
 
        acx->ctsprotect = ctsprotect;
 
@@ -856,10 +800,8 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime)
        int ret;
 
        tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
-       if (!tsf_info) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!tsf_info)
+               return -ENOMEM;
 
        ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO,
                                     tsf_info, sizeof(*tsf_info));
@@ -900,11 +842,8 @@ int wl1251_acx_rate_policies(struct wl1251 *wl)
        wl1251_debug(DEBUG_ACX, "acx rate policies");
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
-
-       if (!acx) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!acx)
+               return -ENOMEM;
 
        /* configure one default (one-size-fits-all) rate class */
        acx->rate_class_cnt = 1;
@@ -932,10 +871,8 @@ int wl1251_acx_mem_cfg(struct wl1251 *wl)
        wl1251_debug(DEBUG_ACX, "acx mem cfg");
 
        mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
-       if (!mem_conf) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!mem_conf)
+               return -ENOMEM;
 
        /* memory config */
        mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
@@ -979,10 +916,8 @@ int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim)
        wl1251_debug(DEBUG_ACX, "acx tbtt and dtim");
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
-       if (!acx) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!acx)
+               return -ENOMEM;
 
        acx->tbtt = tbtt;
        acx->dtim = dtim;
@@ -1008,10 +943,8 @@ int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode,
        wl1251_debug(DEBUG_ACX, "acx bet enable");
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
-       if (!acx) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!acx)
+               return -ENOMEM;
 
        acx->enable = mode;
        acx->max_consecutive = max_consecutive;
@@ -1037,11 +970,8 @@ int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
                     "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop);
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
-
-       if (!acx) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!acx)
+               return -ENOMEM;
 
        acx->ac = ac;
        acx->cw_min = cw_min;
@@ -1073,11 +1003,8 @@ int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue,
                     ps_scheme, ack_policy);
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
-
-       if (!acx) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!acx)
+               return -ENOMEM;
 
        acx->queue = queue;
        acx->type = type;
index 4a0bbb13806bd6fd61266c729f4a433d110ac838..7541bd1a4a4b40de9b6be249dea94ca8f95e96ae 100644 (file)
@@ -47,7 +47,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
                     * In active scans, we only scan channels not
                     * marked as passive.
                     */
-                   (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) {
+                   (passive || !(flags & IEEE80211_CHAN_NO_IR))) {
                        wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
                                     req->channels[i]->band,
                                     req->channels[i]->center_freq);
index 34d9dfff2ad39ead03d3da275cd3e4443385a220..9b2ecf52449faa911f25bea176ed12683fe1836e 100644 (file)
@@ -1688,7 +1688,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl)
 
                        if (channel->flags & (IEEE80211_CHAN_DISABLED |
                                              IEEE80211_CHAN_RADAR |
-                                             IEEE80211_CHAN_PASSIVE_SCAN))
+                                             IEEE80211_CHAN_NO_IR))
                                continue;
 
                        ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch);
index 0368b9cbfb896d6460da3635b199ef6266805644..e9da47cead587704c7060ebd8ab754c1aa7da16b 100644 (file)
@@ -91,8 +91,7 @@ static void wl1271_reg_notify(struct wiphy *wiphy,
                        continue;
 
                if (ch->flags & IEEE80211_CHAN_RADAR)
-                       ch->flags |= IEEE80211_CHAN_NO_IBSS |
-                                    IEEE80211_CHAN_PASSIVE_SCAN;
+                       ch->flags |= IEEE80211_CHAN_NO_IR;
 
        }
 
index 7ed86203304b700c87e4b1ca48de127f7466420f..1e3d51cd673ab6d2be132c6fda17f698547b3ff7 100644 (file)
@@ -188,16 +188,14 @@ wlcore_scan_get_channels(struct wl1271 *wl,
                flags = req_channels[i]->flags;
 
                if (force_passive)
-                       flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+                       flags |= IEEE80211_CHAN_NO_IR;
 
                if ((req_channels[i]->band == band) &&
                    !(flags & IEEE80211_CHAN_DISABLED) &&
                    (!!(flags & IEEE80211_CHAN_RADAR) == radar) &&
                    /* if radar is set, we ignore the passive flag */
                    (radar ||
-                    !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) {
-
-
+                    !!(flags & IEEE80211_CHAN_NO_IR) == passive)) {
                        if (flags & IEEE80211_CHAN_RADAR) {
                                channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
 
@@ -220,7 +218,7 @@ wlcore_scan_get_channels(struct wl1271 *wl,
                            (band == IEEE80211_BAND_2GHZ) &&
                            (channels[j].channel >= 12) &&
                            (channels[j].channel <= 14) &&
-                           (flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
+                           (flags & IEEE80211_CHAN_NO_IR) &&
                            !force_passive) {
                                /* pactive channels treated as DFS */
                                channels[j].flags = SCAN_CHANNEL_FLAGS_DFS;
@@ -243,8 +241,8 @@ wlcore_scan_get_channels(struct wl1271 *wl,
                                     max_dwell_time_active,
                                     flags & IEEE80211_CHAN_RADAR ?
                                        ", DFS" : "",
-                                    flags & IEEE80211_CHAN_PASSIVE_SCAN ?
-                                       ", PASSIVE" : "");
+                                    flags & IEEE80211_CHAN_NO_IR ?
+                                       ", NO-IR" : "");
                        j++;
                }
        }
index 8c3b26a215745b755a5018764e4c0ca1f1bd52b7..776cbb80d098d37e90c0bf0e8c37736ab961f338 100644 (file)
@@ -1411,8 +1411,12 @@ struct ieee80211_vht_operation {
 #define IEEE80211_VHT_CAP_RXSTBC_MASK                          0x00000700
 #define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE                        0x00000800
 #define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE                        0x00001000
-#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX                   0x0000e000
-#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX              0x00070000
+#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT                  13
+#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK                  \
+               (7 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT)
+#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT            16
+#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK             \
+               (7 << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT)
 #define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE                        0x00080000
 #define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE                        0x00100000
 #define IEEE80211_VHT_CAP_VHT_TXOP_PS                          0x00200000
index 3eae46cb1acfecadbff979ee17e17aeab40971e7..e9abc7b536cdebb5434caae1cbd487378ad0dfe1 100644 (file)
@@ -91,9 +91,8 @@ enum ieee80211_band {
  * Channel flags set by the regulatory control code.
  *
  * @IEEE80211_CHAN_DISABLED: This channel is disabled.
- * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted
- *     on this channel.
- * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
+ * @IEEE80211_CHAN_NO_IR: do not initiate radiation, this includes
+ *     sending probe requests or beaconing.
  * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
  * @IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel
  *     is not permitted.
@@ -113,8 +112,8 @@ enum ieee80211_band {
  */
 enum ieee80211_channel_flags {
        IEEE80211_CHAN_DISABLED         = 1<<0,
-       IEEE80211_CHAN_PASSIVE_SCAN     = 1<<1,
-       IEEE80211_CHAN_NO_IBSS          = 1<<2,
+       IEEE80211_CHAN_NO_IR            = 1<<1,
+       /* hole at 1<<2 */
        IEEE80211_CHAN_RADAR            = 1<<3,
        IEEE80211_CHAN_NO_HT40PLUS      = 1<<4,
        IEEE80211_CHAN_NO_HT40MINUS     = 1<<5,
@@ -1944,6 +1943,29 @@ struct cfg80211_update_ft_ies_params {
        size_t ie_len;
 };
 
+/**
+ * struct cfg80211_mgmt_tx_params - mgmt tx parameters
+ *
+ * This structure provides information needed to transmit a mgmt frame
+ *
+ * @chan: channel to use
+ * @offchan: indicates wether off channel operation is required
+ * @wait: duration for ROC
+ * @buf: buffer to transmit
+ * @len: buffer length
+ * @no_cck: don't use cck rates for this frame
+ * @dont_wait_for_ack: tells the low level not to wait for an ack
+ */
+struct cfg80211_mgmt_tx_params {
+       struct ieee80211_channel *chan;
+       bool offchan;
+       unsigned int wait;
+       const u8 *buf;
+       size_t len;
+       bool no_cck;
+       bool dont_wait_for_ack;
+};
+
 /**
  * struct cfg80211_ops - backend description for wireless configuration
  *
@@ -2342,9 +2364,8 @@ struct cfg80211_ops {
                                            u64 cookie);
 
        int     (*mgmt_tx)(struct wiphy *wiphy, struct wireless_dev *wdev,
-                         struct ieee80211_channel *chan, bool offchan,
-                         unsigned int wait, const u8 *buf, size_t len,
-                         bool no_cck, bool dont_wait_for_ack, u64 *cookie);
+                          struct cfg80211_mgmt_tx_params *params,
+                          u64 *cookie);
        int     (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
                                       struct wireless_dev *wdev,
                                       u64 cookie);
@@ -2438,27 +2459,6 @@ struct cfg80211_ops {
 /**
  * enum wiphy_flags - wiphy capability flags
  *
- * @WIPHY_FLAG_CUSTOM_REGULATORY:  tells us the driver for this device
- *     has its own custom regulatory domain and cannot identify the
- *     ISO / IEC 3166 alpha2 it belongs to. When this is enabled
- *     we will disregard the first regulatory hint (when the
- *     initiator is %REGDOM_SET_BY_CORE).
- * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will
- *     ignore regulatory domain settings until it gets its own regulatory
- *     domain via its regulatory_hint() unless the regulatory hint is
- *     from a country IE. After its gets its own regulatory domain it will
- *     only allow further regulatory domain settings to further enhance
- *     compliance. For example if channel 13 and 14 are disabled by this
- *     regulatory domain no user regulatory domain can enable these channels
- *     at a later time. This can be used for devices which do not have
- *     calibration information guaranteed for frequencies or settings
- *     outside of its regulatory domain. If used in combination with
- *     WIPHY_FLAG_CUSTOM_REGULATORY the inspected country IE power settings
- *     will be followed.
- * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure
- *     that passive scan flags and beaconing flags may not be lifted by
- *     cfg80211 due to regulatory beacon hints. For more information on beacon
- *     hints read the documenation for regulatory_hint_found_beacon()
  * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this
  *     wiphy at all
  * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled
@@ -2497,9 +2497,9 @@ struct cfg80211_ops {
  *     beaconing mode (AP, IBSS, Mesh, ...).
  */
 enum wiphy_flags {
-       WIPHY_FLAG_CUSTOM_REGULATORY            = BIT(0),
-       WIPHY_FLAG_STRICT_REGULATORY            = BIT(1),
-       WIPHY_FLAG_DISABLE_BEACON_HINTS         = BIT(2),
+       /* use hole at 0 */
+       /* use hole at 1 */
+       /* use hole at 2 */
        WIPHY_FLAG_NETNS_OK                     = BIT(3),
        WIPHY_FLAG_PS_ON_BY_DEFAULT             = BIT(4),
        WIPHY_FLAG_4ADDR_AP                     = BIT(5),
@@ -2721,6 +2721,8 @@ struct wiphy_coalesce_support {
  * @software_iftypes: bitmask of software interface types, these are not
  *     subject to any restrictions since they are purely managed in SW.
  * @flags: wiphy flags, see &enum wiphy_flags
+ * @regulatory_flags: wiphy regulatory flags, see
+ *     &enum ieee80211_regulatory_flags
  * @features: features advertised to nl80211, see &enum nl80211_feature_flags.
  * @bss_priv_size: each BSS struct has private data allocated with it,
  *     this variable determines its size
@@ -2809,7 +2811,7 @@ struct wiphy {
 
        u16 max_acl_mac_addrs;
 
-       u32 flags, features;
+       u32 flags, regulatory_flags, features;
 
        u32 ap_sme_capa;
 
@@ -3472,6 +3474,9 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
  * custom regulatory domain will be trusted completely and as such previous
  * default channel settings will be disregarded. If no rule is found for a
  * channel on the regulatory domain the channel will be disabled.
+ * Drivers using this for a wiphy should also set the wiphy flag
+ * WIPHY_FLAG_CUSTOM_REGULATORY or cfg80211 will set it for the wiphy
+ * that called this helper.
  */
 void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
                                   const struct ieee80211_regdomain *regd);
@@ -4146,6 +4151,7 @@ void cfg80211_radar_event(struct wiphy *wiphy,
 /**
  * cfg80211_cac_event - Channel availability check (CAC) event
  * @netdev: network device
+ * @chandef: chandef for the current channel
  * @event: type of event
  * @gfp: context flags
  *
@@ -4154,6 +4160,7 @@ void cfg80211_radar_event(struct wiphy *wiphy,
  * also by full-MAC drivers.
  */
 void cfg80211_cac_event(struct net_device *netdev,
+                       const struct cfg80211_chan_def *chandef,
                        enum nl80211_radar_event event, gfp_t gfp);
 
 
@@ -4279,7 +4286,8 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
  * @dev: the device which switched channels
  * @chandef: the new channel definition
  *
- * Acquires wdev_lock, so must only be called from sleepable driver context!
+ * Caller must acquire wdev_lock, therefore must only be called from sleepable
+ * driver context!
  */
 void cfg80211_ch_switch_notify(struct net_device *dev,
                               struct cfg80211_chan_def *chandef);
index 7ceed99a05bc79218a841352a454a980df48741b..3cd408b326de7400b00e6284be2524955beefe27 100644 (file)
@@ -154,12 +154,14 @@ struct ieee80211_low_level_stats {
  * @IEEE80211_CHANCTX_CHANGE_RADAR: radar detection flag changed
  * @IEEE80211_CHANCTX_CHANGE_CHANNEL: switched to another operating channel,
  *     this is used only with channel switching with CSA
+ * @IEEE80211_CHANCTX_CHANGE_MIN_WIDTH: The min required channel width changed
  */
 enum ieee80211_chanctx_change {
        IEEE80211_CHANCTX_CHANGE_WIDTH          = BIT(0),
        IEEE80211_CHANCTX_CHANGE_RX_CHAINS      = BIT(1),
        IEEE80211_CHANCTX_CHANGE_RADAR          = BIT(2),
        IEEE80211_CHANCTX_CHANGE_CHANNEL        = BIT(3),
+       IEEE80211_CHANCTX_CHANGE_MIN_WIDTH      = BIT(4),
 };
 
 /**
@@ -169,6 +171,7 @@ enum ieee80211_chanctx_change {
  * that contains it is visible in mac80211 only.
  *
  * @def: the channel definition
+ * @min_def: the minimum channel definition currently required.
  * @rx_chains_static: The number of RX chains that must always be
  *     active on the channel to receive MIMO transmissions
  * @rx_chains_dynamic: The number of RX chains that must be enabled
@@ -180,6 +183,7 @@ enum ieee80211_chanctx_change {
  */
 struct ieee80211_chanctx_conf {
        struct cfg80211_chan_def def;
+       struct cfg80211_chan_def min_def;
 
        u8 rx_chains_static, rx_chains_dynamic;
 
@@ -1228,6 +1232,36 @@ struct ieee80211_key_conf {
        u8 key[0];
 };
 
+/**
+ * struct ieee80211_cipher_scheme - cipher scheme
+ *
+ * This structure contains a cipher scheme information defining
+ * the secure packet crypto handling.
+ *
+ * @cipher: a cipher suite selector
+ * @iftype: a cipher iftype bit mask indicating an allowed cipher usage
+ * @hdr_len: a length of a security header used the cipher
+ * @pn_len: a length of a packet number in the security header
+ * @pn_off: an offset of pn from the beginning of the security header
+ * @key_idx_off: an offset of key index byte in the security header
+ * @key_idx_mask: a bit mask of key_idx bits
+ * @key_idx_shift: a bit shift needed to get key_idx
+ *     key_idx value calculation:
+ *      (sec_header_base[key_idx_off] & key_idx_mask) >> key_idx_shift
+ * @mic_len: a mic length in bytes
+ */
+struct ieee80211_cipher_scheme {
+       u32 cipher;
+       u16 iftype;
+       u8 hdr_len;
+       u8 pn_len;
+       u8 pn_off;
+       u8 key_idx_off;
+       u8 key_idx_mask;
+       u8 key_idx_shift;
+       u8 mic_len;
+};
+
 /**
  * enum set_key_cmd - key command
  *
@@ -1636,6 +1670,10 @@ enum ieee80211_hw_flags {
  * @uapsd_max_sp_len: maximum number of total buffered frames the WMM AP may
  *     deliver to a WMM STA during any Service Period triggered by the WMM STA.
  *     Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct values.
+ *
+ * @n_cipher_schemes: a size of an array of cipher schemes definitions.
+ * @cipher_schemes: a pointer to an array of cipher scheme definitions
+ *     supported by HW.
  */
 struct ieee80211_hw {
        struct ieee80211_conf conf;
@@ -1663,6 +1701,8 @@ struct ieee80211_hw {
        netdev_features_t netdev_features;
        u8 uapsd_queues;
        u8 uapsd_max_sp_len;
+       u8 n_cipher_schemes;
+       const struct ieee80211_cipher_scheme *cipher_schemes;
 };
 
 /**
index f17ed590d64a35b314c8c9c42dc7dc153e0f1619..c96a0b86f342cc1093dee253f070f9ff225b0ba6 100644 (file)
@@ -38,17 +38,17 @@ enum environment_cap {
  *
  * @rcu_head: RCU head struct used to free the request
  * @wiphy_idx: this is set if this request's initiator is
- *     %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
- *     can be used by the wireless core to deal with conflicts
- *     and potentially inform users of which devices specifically
- *     cased the conflicts.
+ *     %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
+ *     can be used by the wireless core to deal with conflicts
+ *     and potentially inform users of which devices specifically
+ *     cased the conflicts.
  * @initiator: indicates who sent this request, could be any of
- *     of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*)
+ *     of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*)
  * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested
- *     regulatory domain. We have a few special codes:
- *     00 - World regulatory domain
- *     99 - built by driver but a specific alpha2 cannot be determined
- *     98 - result of an intersection between two regulatory domains
+ *     regulatory domain. We have a few special codes:
+ *     00 - World regulatory domain
+ *     99 - built by driver but a specific alpha2 cannot be determined
+ *     98 - result of an intersection between two regulatory domains
  *     97 - regulatory domain has not yet been configured
  * @dfs_region: If CRDA responded with a regulatory domain that requires
  *     DFS master operation on a known DFS region (NL80211_DFS_*),
@@ -59,8 +59,8 @@ enum environment_cap {
  *     of hint passed. This could be any of the %NL80211_USER_REG_HINT_*
  *     types.
  * @intersect: indicates whether the wireless core should intersect
- *     the requested regulatory domain with the presently set regulatory
- *     domain.
+ *     the requested regulatory domain with the presently set regulatory
+ *     domain.
  * @processed: indicates whether or not this requests has already been
  *     processed. When the last request is processed it means that the
  *     currently regulatory domain set on cfg80211 is updated from
@@ -68,9 +68,9 @@ enum environment_cap {
  *     the last request is not yet processed we must yield until it
  *     is processed before processing any new requests.
  * @country_ie_checksum: checksum of the last processed and accepted
- *     country IE
+ *     country IE
  * @country_ie_env: lets us know if the AP is telling us we are outdoor,
- *     indoor, or if it doesn't matter
+ *     indoor, or if it doesn't matter
  * @list: used to insert into the reg_requests_list linked list
  */
 struct regulatory_request {
@@ -79,13 +79,63 @@ struct regulatory_request {
        enum nl80211_reg_initiator initiator;
        enum nl80211_user_reg_hint_type user_reg_hint_type;
        char alpha2[2];
-       u8 dfs_region;
+       enum nl80211_dfs_regions dfs_region;
        bool intersect;
        bool processed;
        enum environment_cap country_ie_env;
        struct list_head list;
 };
 
+/**
+ * enum ieee80211_regulatory_flags - device regulatory flags
+ *
+ * @REGULATORY_CUSTOM_REG: tells us the driver for this device
+ *     has its own custom regulatory domain and cannot identify the
+ *     ISO / IEC 3166 alpha2 it belongs to. When this is enabled
+ *     we will disregard the first regulatory hint (when the
+ *     initiator is %REGDOM_SET_BY_CORE). Drivers that use
+ *     wiphy_apply_custom_regulatory() should have this flag set
+ *     or the regulatory core will set it for the wiphy.
+ * @REGULATORY_STRICT_REG: tells us that the wiphy for this device
+ *     has regulatory domain that it wishes to be considered as the
+ *     superset for regulatory rules. After this device gets its regulatory
+ *     domain programmed further regulatory hints shall only be considered
+ *     for this device to enhance regulatory compliance, forcing the
+ *     device to only possibly use subsets of the original regulatory
+ *     rules. For example if channel 13 and 14 are disabled by this
+ *     device's regulatory domain no user specified regulatory hint which
+ *     has these channels enabled would enable them for this wiphy,
+ *     the device's original regulatory domain will be trusted as the
+ *     base. You can program the superset of regulatory rules for this
+ *     wiphy with regulatory_hint() for cards programmed with an
+ *     ISO3166-alpha2 country code. wiphys that use regulatory_hint()
+ *     will have their wiphy->regd programmed once the regulatory
+ *     domain is set, and all other regulatory hints will be ignored
+ *     until their own regulatory domain gets programmed.
+ * @REGULATORY_DISABLE_BEACON_HINTS: enable this if your driver needs to
+ *     ensure that passive scan flags and beaconing flags may not be lifted by
+ *     cfg80211 due to regulatory beacon hints. For more information on beacon
+ *     hints read the documenation for regulatory_hint_found_beacon()
+ * @REGULATORY_COUNTRY_IE_FOLLOW_POWER:  for devices that have a preference
+ *     that even though they may have programmed their own custom power
+ *     setting prior to wiphy registration, they want to ensure their channel
+ *     power settings are updated for this connection with the power settings
+ *     derived from the regulatory domain. The regulatory domain used will be
+ *     based on the ISO3166-alpha2 from country IE provided through
+ *     regulatory_hint_country_ie()
+ * @REGULATORY_COUNTRY_IE_IGNORE: for devices that have a preference to ignore
+ *     all country IE information processed by the regulatory core. This will
+ *     override %REGULATORY_COUNTRY_IE_FOLLOW_POWER as all country IEs will
+ *     be ignored.
+ */
+enum ieee80211_regulatory_flags {
+       REGULATORY_CUSTOM_REG                   = BIT(0),
+       REGULATORY_STRICT_REG                   = BIT(1),
+       REGULATORY_DISABLE_BEACON_HINTS         = BIT(2),
+       REGULATORY_COUNTRY_IE_FOLLOW_POWER      = BIT(3),
+       REGULATORY_COUNTRY_IE_IGNORE            = BIT(4),
+};
+
 struct ieee80211_freq_range {
        u32 start_freq_khz;
        u32 end_freq_khz;
@@ -107,7 +157,7 @@ struct ieee80211_regdomain {
        struct rcu_head rcu_head;
        u32 n_reg_rules;
        char alpha2[2];
-       u8 dfs_region;
+       enum nl80211_dfs_regions dfs_region;
        struct ieee80211_reg_rule reg_rules[];
 };
 
index f752e9821e717ee68066f4d8467775a8bee2fd78..129b7b08714848279f3638019892a4dc0e9e6d65 100644 (file)
  *     operation, %NL80211_ATTR_MAC contains the peer MAC address, and
  *     %NL80211_ATTR_REASON_CODE the reason code to be used (only with
  *     %NL80211_TDLS_TEARDOWN).
- * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
+ * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. The
+ *     %NL80211_ATTR_TDLS_ACTION attribute determines the type of frame to be
+ *     sent. Public Action codes (802.11-2012 8.1.5.1) will be sent as
+ *     802.11 management frames, while TDLS action codes (802.11-2012
+ *     8.5.13.1) will be encapsulated and sent as data frames. The currently
+ *     supported Public Action code is %WLAN_PUB_ACTION_TDLS_DISCOVER_RES
+ *     and the currently supported TDLS actions codes are given in
+ *     &enum ieee80211_tdls_actioncode.
  *
  * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
  *     (or GO) interface (i.e. hostapd) to ask for unexpected frames to
@@ -1508,6 +1515,11 @@ enum nl80211_commands {
  *     to react to radar events, e.g. initiate a channel switch or leave the
  *     IBSS network.
  *
+ * @NL80211_ATTR_SUPPORT_5_MHZ: A flag indicating that the device supports
+ *     5 MHz channel bandwidth.
+ * @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports
+ *     10 MHz channel bandwidth.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1824,6 +1836,9 @@ enum nl80211_attrs {
 
        NL80211_ATTR_HANDLE_DFS,
 
+       NL80211_ATTR_SUPPORT_5_MHZ,
+       NL80211_ATTR_SUPPORT_10_MHZ,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2224,10 +2239,9 @@ enum nl80211_band_attr {
  * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
  * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
  *     regulatory domain.
- * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
- *     permitted on this channel in current regulatory domain.
- * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
- *     on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_IR: no mechanisms that initiate radiation
+ *     are permitted on this channel, this includes sending probe
+ *     requests, or modes of operation that require beaconing.
  * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
  *     on this channel in current regulatory domain.
  * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
@@ -2254,8 +2268,8 @@ enum nl80211_frequency_attr {
        __NL80211_FREQUENCY_ATTR_INVALID,
        NL80211_FREQUENCY_ATTR_FREQ,
        NL80211_FREQUENCY_ATTR_DISABLED,
-       NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
-       NL80211_FREQUENCY_ATTR_NO_IBSS,
+       NL80211_FREQUENCY_ATTR_NO_IR,
+       __NL80211_FREQUENCY_ATTR_NO_IBSS,
        NL80211_FREQUENCY_ATTR_RADAR,
        NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
        NL80211_FREQUENCY_ATTR_DFS_STATE,
@@ -2271,6 +2285,9 @@ enum nl80211_frequency_attr {
 };
 
 #define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
+#define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN    NL80211_FREQUENCY_ATTR_NO_IR
+#define NL80211_FREQUENCY_ATTR_NO_IBSS         NL80211_FREQUENCY_ATTR_NO_IR
+#define NL80211_FREQUENCY_ATTR_NO_IR           NL80211_FREQUENCY_ATTR_NO_IR
 
 /**
  * enum nl80211_bitrate_attr - bitrate attributes
@@ -2413,8 +2430,9 @@ enum nl80211_sched_scan_match_attr {
  * @NL80211_RRF_DFS: DFS support is required to be used
  * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
  * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
- * @NL80211_RRF_PASSIVE_SCAN: passive scan is required
- * @NL80211_RRF_NO_IBSS: no IBSS is allowed
+ * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed,
+ *     this includes probe requests or modes of operation that require
+ *     beaconing.
  */
 enum nl80211_reg_rule_flags {
        NL80211_RRF_NO_OFDM             = 1<<0,
@@ -2424,10 +2442,17 @@ enum nl80211_reg_rule_flags {
        NL80211_RRF_DFS                 = 1<<4,
        NL80211_RRF_PTP_ONLY            = 1<<5,
        NL80211_RRF_PTMP_ONLY           = 1<<6,
-       NL80211_RRF_PASSIVE_SCAN        = 1<<7,
-       NL80211_RRF_NO_IBSS             = 1<<8,
+       NL80211_RRF_NO_IR               = 1<<7,
+       __NL80211_RRF_NO_IBSS           = 1<<8,
 };
 
+#define NL80211_RRF_PASSIVE_SCAN       NL80211_RRF_NO_IR
+#define NL80211_RRF_NO_IBSS            NL80211_RRF_NO_IR
+#define NL80211_RRF_NO_IR              NL80211_RRF_NO_IR
+
+/* For backport compatibility with older userspace */
+#define NL80211_RRF_NO_IR_ALL          (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)
+
 /**
  * enum nl80211_dfs_regions - regulatory DFS regions
  *
index 364ce0c5962fd48c85ea23b71b2d1dd463082575..f80e8c4c6bcd303762781ed8a2aa613ff763f5fa 100644 (file)
@@ -133,7 +133,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                             struct key_params *params)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
        struct sta_info *sta = NULL;
+       const struct ieee80211_cipher_scheme *cs = NULL;
        struct ieee80211_key *key;
        int err;
 
@@ -145,22 +147,28 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        case WLAN_CIPHER_SUITE_WEP40:
        case WLAN_CIPHER_SUITE_TKIP:
        case WLAN_CIPHER_SUITE_WEP104:
-               if (IS_ERR(sdata->local->wep_tx_tfm))
+               if (IS_ERR(local->wep_tx_tfm))
                        return -EINVAL;
                break;
+       case WLAN_CIPHER_SUITE_CCMP:
+       case WLAN_CIPHER_SUITE_AES_CMAC:
+       case WLAN_CIPHER_SUITE_GCMP:
+               break;
        default:
+               cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type);
                break;
        }
 
        key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len,
-                                 params->key, params->seq_len, params->seq);
+                                 params->key, params->seq_len, params->seq,
+                                 cs);
        if (IS_ERR(key))
                return PTR_ERR(key);
 
        if (pairwise)
                key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
 
-       mutex_lock(&sdata->local->sta_mtx);
+       mutex_lock(&local->sta_mtx);
 
        if (mac_addr) {
                if (ieee80211_vif_is_mesh(&sdata->vif))
@@ -216,10 +224,13 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                break;
        }
 
+       if (sta)
+               sta->cipher_scheme = cs;
+
        err = ieee80211_key_link(key, sdata, sta);
 
  out_unlock:
-       mutex_unlock(&sdata->local->sta_mtx);
+       mutex_unlock(&local->sta_mtx);
 
        return err;
 }
@@ -244,7 +255,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
                        goto out_unlock;
 
                if (pairwise)
-                       key = key_mtx_dereference(local, sta->ptk);
+                       key = key_mtx_dereference(local, sta->ptk[key_idx]);
                else
                        key = key_mtx_dereference(local, sta->gtk[key_idx]);
        } else
@@ -291,7 +302,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                        goto out;
 
                if (pairwise)
-                       key = rcu_dereference(sta->ptk);
+                       key = rcu_dereference(sta->ptk[key_idx]);
                else if (key_idx < NUM_DEFAULT_KEYS)
                        key = rcu_dereference(sta->gtk[key_idx]);
        } else
@@ -521,8 +532,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                                 STATION_INFO_PEER_PM |
                                 STATION_INFO_NONPEER_PM;
 
-               sinfo->llid = le16_to_cpu(sta->llid);
-               sinfo->plid = le16_to_cpu(sta->plid);
+               sinfo->llid = sta->llid;
+               sinfo->plid = sta->plid;
                sinfo->plink_state = sta->plink_state;
                if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
                        sinfo->filled |= STATION_INFO_T_OFFSET;
@@ -846,7 +857,7 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
        if (!resp || !resp_len)
                return 1;
 
-       old = rtnl_dereference(sdata->u.ap.probe_resp);
+       old = sdata_dereference(sdata->u.ap.probe_resp, sdata);
 
        new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL);
        if (!new)
@@ -870,7 +881,8 @@ int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
        int size, err;
        u32 changed = BSS_CHANGED_BEACON;
 
-       old = rtnl_dereference(sdata->u.ap.beacon);
+       old = sdata_dereference(sdata->u.ap.beacon, sdata);
+
 
        /* Need to have a beacon head if we don't have one yet */
        if (!params->head && !old)
@@ -947,7 +959,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
                      BSS_CHANGED_P2P_PS;
        int err;
 
-       old = rtnl_dereference(sdata->u.ap.beacon);
+       old = sdata_dereference(sdata->u.ap.beacon, sdata);
        if (old)
                return -EALREADY;
 
@@ -968,11 +980,19 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
         */
        sdata->control_port_protocol = params->crypto.control_port_ethertype;
        sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
+       sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local,
+                                                       &params->crypto,
+                                                       sdata->vif.type);
+
        list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
                vlan->control_port_protocol =
                        params->crypto.control_port_ethertype;
                vlan->control_port_no_encrypt =
                        params->crypto.control_port_no_encrypt;
+               vlan->encrypt_headroom =
+                       ieee80211_cs_headroom(sdata->local,
+                                             &params->crypto,
+                                             vlan->vif.type);
        }
 
        sdata->vif.bss_conf.beacon_int = params->beacon_interval;
@@ -1001,7 +1021,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
 
        err = drv_start_ap(sdata->local, sdata);
        if (err) {
-               old = rtnl_dereference(sdata->u.ap.beacon);
+               old = sdata_dereference(sdata->u.ap.beacon, sdata);
+
                if (old)
                        kfree_rcu(old, rcu_head);
                RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
@@ -1032,7 +1053,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
        if (sdata->vif.csa_active)
                return -EBUSY;
 
-       old = rtnl_dereference(sdata->u.ap.beacon);
+       old = sdata_dereference(sdata->u.ap.beacon, sdata);
        if (!old)
                return -ENOENT;
 
@@ -1050,15 +1071,18 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        struct ieee80211_local *local = sdata->local;
        struct beacon_data *old_beacon;
        struct probe_resp *old_probe_resp;
+       struct cfg80211_chan_def chandef;
 
-       old_beacon = rtnl_dereference(sdata->u.ap.beacon);
+       old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata);
        if (!old_beacon)
                return -ENOENT;
-       old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp);
+       old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata);
 
        /* abort any running channel switch */
        sdata->vif.csa_active = false;
-       cancel_work_sync(&sdata->csa_finalize_work);
+       kfree(sdata->u.ap.next_beacon);
+       sdata->u.ap.next_beacon = NULL;
+
        cancel_work_sync(&sdata->u.ap.request_smps_work);
 
        /* turn off carrier for this interface and dependent VLANs */
@@ -1091,8 +1115,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
 
        if (sdata->wdev.cac_started) {
+               chandef = sdata->vif.bss_conf.chandef;
                cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
-               cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED,
+               cfg80211_cac_event(sdata->dev, &chandef,
+                                  NL80211_RADAR_CAC_ABORTED,
                                   GFP_KERNEL);
        }
 
@@ -1953,7 +1979,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
        enum ieee80211_band band;
        u32 changed = 0;
 
-       if (!rtnl_dereference(sdata->u.ap.beacon))
+       if (!sdata_dereference(sdata->u.ap.beacon, sdata))
                return -ENOENT;
 
        band = ieee80211_get_sdata_band(sdata);
@@ -2963,27 +2989,33 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
        struct ieee80211_local *local = sdata->local;
        int err, changed = 0;
 
+       sdata_lock(sdata);
+       /* AP might have been stopped while waiting for the lock. */
+       if (!sdata->vif.csa_active)
+               goto unlock;
+
        if (!ieee80211_sdata_running(sdata))
-               return;
+               goto unlock;
 
        sdata->radar_required = sdata->csa_radar_required;
-       err = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
-                                          &changed);
+       err = ieee80211_vif_change_channel(sdata, &changed);
        if (WARN_ON(err < 0))
-               return;
+               goto unlock;
 
        if (!local->use_chanctx) {
-               local->_oper_chandef = local->csa_chandef;
+               local->_oper_chandef = sdata->csa_chandef;
                ieee80211_hw_config(local, 0);
        }
 
        ieee80211_bss_info_change_notify(sdata, changed);
 
+       sdata->vif.csa_active = false;
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP:
                err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
                if (err < 0)
-                       return;
+                       goto unlock;
+
                changed |= err;
                kfree(sdata->u.ap.next_beacon);
                sdata->u.ap.next_beacon = NULL;
@@ -2997,20 +3029,22 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
        case NL80211_IFTYPE_MESH_POINT:
                err = ieee80211_mesh_finish_csa(sdata);
                if (err < 0)
-                       return;
+                       goto unlock;
                break;
 #endif
        default:
                WARN_ON(1);
-               return;
+               goto unlock;
        }
-       sdata->vif.csa_active = false;
 
        ieee80211_wake_queues_by_reason(&sdata->local->hw,
                                        IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
 
-       cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);
+       cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
+
+unlock:
+       sdata_unlock(sdata);
 }
 
 static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
@@ -3023,6 +3057,8 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_if_mesh __maybe_unused *ifmsh;
        int err, num_chanctx;
 
+       lockdep_assert_held(&sdata->wdev.mtx);
+
        if (!list_empty(&local->roc_list) || local->scanning)
                return -EBUSY;
 
@@ -3143,7 +3179,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                                IEEE80211_MAX_QUEUE_MAP,
                                IEEE80211_QUEUE_STOP_REASON_CSA);
 
-       local->csa_chandef = params->chandef;
+       sdata->csa_chandef = params->chandef;
        sdata->vif.csa_active = true;
 
        ieee80211_bss_info_change_notify(sdata, err);
@@ -3153,26 +3189,25 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
-                            struct ieee80211_channel *chan, bool offchan,
-                            unsigned int wait, const u8 *buf, size_t len,
-                            bool no_cck, bool dont_wait_for_ack, u64 *cookie)
+                            struct cfg80211_mgmt_tx_params *params,
+                            u64 *cookie)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct sta_info *sta;
-       const struct ieee80211_mgmt *mgmt = (void *)buf;
+       const struct ieee80211_mgmt *mgmt = (void *)params->buf;
        bool need_offchan = false;
        u32 flags;
        int ret;
 
-       if (dont_wait_for_ack)
+       if (params->dont_wait_for_ack)
                flags = IEEE80211_TX_CTL_NO_ACK;
        else
                flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
                        IEEE80211_TX_CTL_REQ_TX_STATUS;
 
-       if (no_cck)
+       if (params->no_cck)
                flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
 
        switch (sdata->vif.type) {
@@ -3220,7 +3255,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
        /* configurations requiring offchan cannot work if no channel has been
         * specified
         */
-       if (need_offchan && !chan)
+       if (need_offchan && !params->chan)
                return -EINVAL;
 
        mutex_lock(&local->mtx);
@@ -3233,8 +3268,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 
                if (chanctx_conf) {
-                       need_offchan = chan && (chan != chanctx_conf->def.chan);
-               } else if (!chan) {
+                       need_offchan = params->chan &&
+                                      (params->chan !=
+                                       chanctx_conf->def.chan);
+               } else if (!params->chan) {
                        ret = -EINVAL;
                        rcu_read_unlock();
                        goto out_unlock;
@@ -3244,19 +3281,19 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                rcu_read_unlock();
        }
 
-       if (need_offchan && !offchan) {
+       if (need_offchan && !params->offchan) {
                ret = -EBUSY;
                goto out_unlock;
        }
 
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + params->len);
        if (!skb) {
                ret = -ENOMEM;
                goto out_unlock;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
 
-       memcpy(skb_put(skb, len), buf, len);
+       memcpy(skb_put(skb, params->len), params->buf, params->len);
 
        IEEE80211_SKB_CB(skb)->flags = flags;
 
@@ -3276,8 +3313,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                        local->hw.offchannel_tx_hw_queue;
 
        /* This will handle all kinds of coalescing and immediate TX */
-       ret = ieee80211_start_roc_work(local, sdata, chan,
-                                      wait, cookie, skb,
+       ret = ieee80211_start_roc_work(local, sdata, params->chan,
+                                      params->wait, cookie, skb,
                                       IEEE80211_ROC_TYPE_MGMT_TX);
        if (ret)
                kfree_skb(skb);
index 03ba6b5c5373b373d47956518fafeaf1338b2ad0..a57d5d9466bcbca1c8aa05276502ede6987783e7 100644 (file)
@@ -9,6 +9,140 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
+static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
+{
+       switch (sta->bandwidth) {
+       case IEEE80211_STA_RX_BW_20:
+               if (sta->ht_cap.ht_supported)
+                       return NL80211_CHAN_WIDTH_20;
+               else
+                       return NL80211_CHAN_WIDTH_20_NOHT;
+       case IEEE80211_STA_RX_BW_40:
+               return NL80211_CHAN_WIDTH_40;
+       case IEEE80211_STA_RX_BW_80:
+               return NL80211_CHAN_WIDTH_80;
+       case IEEE80211_STA_RX_BW_160:
+               /*
+                * This applied for both 160 and 80+80. since we use
+                * the returned value to consider degradation of
+                * ctx->conf.min_def, we have to make sure to take
+                * the bigger one (NL80211_CHAN_WIDTH_160).
+                * Otherwise we might try degrading even when not
+                * needed, as the max required sta_bw returned (80+80)
+                * might be smaller than the configured bw (160).
+                */
+               return NL80211_CHAN_WIDTH_160;
+       default:
+               WARN_ON(1);
+               return NL80211_CHAN_WIDTH_20;
+       }
+}
+
+static enum nl80211_chan_width
+ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata)
+{
+       enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
+       struct sta_info *sta;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
+               if (sdata != sta->sdata &&
+                   !(sta->sdata->bss && sta->sdata->bss == sdata->bss))
+                       continue;
+
+               if (!sta->uploaded)
+                       continue;
+
+               max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta));
+       }
+       rcu_read_unlock();
+
+       return max_bw;
+}
+
+static enum nl80211_chan_width
+ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
+                                     struct ieee80211_chanctx_conf *conf)
+{
+       struct ieee80211_sub_if_data *sdata;
+       enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               struct ieee80211_vif *vif = &sdata->vif;
+               enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
+
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+
+               if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
+                       continue;
+
+               switch (vif->type) {
+               case NL80211_IFTYPE_AP:
+               case NL80211_IFTYPE_AP_VLAN:
+                       width = ieee80211_get_max_required_bw(sdata);
+                       break;
+               case NL80211_IFTYPE_P2P_DEVICE:
+                       continue;
+               case NL80211_IFTYPE_STATION:
+               case NL80211_IFTYPE_ADHOC:
+               case NL80211_IFTYPE_WDS:
+               case NL80211_IFTYPE_MESH_POINT:
+                       width = vif->bss_conf.chandef.width;
+                       break;
+               case NL80211_IFTYPE_UNSPECIFIED:
+               case NUM_NL80211_IFTYPES:
+               case NL80211_IFTYPE_MONITOR:
+               case NL80211_IFTYPE_P2P_CLIENT:
+               case NL80211_IFTYPE_P2P_GO:
+                       WARN_ON_ONCE(1);
+               }
+               max_bw = max(max_bw, width);
+       }
+       rcu_read_unlock();
+
+       return max_bw;
+}
+
+/*
+ * recalc the min required chan width of the channel context, which is
+ * the max of min required widths of all the interfaces bound to this
+ * channel context.
+ */
+void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
+                                     struct ieee80211_chanctx *ctx)
+{
+       enum nl80211_chan_width max_bw;
+       struct cfg80211_chan_def min_def;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       /* don't optimize 5MHz, 10MHz, and radar_enabled confs */
+       if (ctx->conf.def.width == NL80211_CHAN_WIDTH_5 ||
+           ctx->conf.def.width == NL80211_CHAN_WIDTH_10 ||
+           ctx->conf.radar_enabled) {
+               ctx->conf.min_def = ctx->conf.def;
+               return;
+       }
+
+       max_bw = ieee80211_get_chanctx_max_required_bw(local, &ctx->conf);
+
+       /* downgrade chandef up to max_bw */
+       min_def = ctx->conf.def;
+       while (min_def.width > max_bw)
+               ieee80211_chandef_downgrade(&min_def);
+
+       if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def))
+               return;
+
+       ctx->conf.min_def = min_def;
+       if (!ctx->driver_present)
+               return;
+
+       drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH);
+}
+
 static void ieee80211_change_chanctx(struct ieee80211_local *local,
                                     struct ieee80211_chanctx *ctx,
                                     const struct cfg80211_chan_def *chandef)
@@ -20,6 +154,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
 
        ctx->conf.def = *chandef;
        drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);
+       ieee80211_recalc_chanctx_min_def(local, ctx);
 
        if (!local->use_chanctx) {
                local->_oper_chandef = *chandef;
@@ -93,6 +228,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
        ctx->conf.rx_chains_dynamic = 1;
        ctx->mode = mode;
        ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
+       ieee80211_recalc_chanctx_min_def(local, ctx);
        if (!local->use_chanctx)
                local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
 
@@ -179,6 +315,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
        ctx->refcount++;
 
        ieee80211_recalc_txpower(sdata);
+       ieee80211_recalc_chanctx_min_def(local, ctx);
        sdata->vif.bss_conf.idle = false;
 
        if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
@@ -243,6 +380,7 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
                ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
                ieee80211_recalc_smps_chanctx(local, ctx);
                ieee80211_recalc_radar_chanctx(local, ctx);
+               ieee80211_recalc_chanctx_min_def(local, ctx);
        }
 }
 
@@ -411,12 +549,12 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 }
 
 int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-                                const struct cfg80211_chan_def *chandef,
                                 u32 *changed)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_chanctx_conf *conf;
        struct ieee80211_chanctx *ctx;
+       const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
        int ret;
        u32 chanctx_changed = 0;
 
@@ -456,6 +594,7 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
        ieee80211_recalc_chanctx_chantype(local, ctx);
        ieee80211_recalc_smps_chanctx(local, ctx);
        ieee80211_recalc_radar_chanctx(local, ctx);
+       ieee80211_recalc_chanctx_min_def(local, ctx);
 
        ret = 0;
  out:
index 5c090e41d9bbf1ea379307c8ecd6a648cb33f0ac..fa16e54980a1d3e76ce2f85fcb3253eb2599e838 100644 (file)
 
 #define DEBUGFS_FORMAT_BUFFER_SIZE 100
 
+#define TX_LATENCY_BIN_DELIMTER_C ','
+#define TX_LATENCY_BIN_DELIMTER_S ","
+#define TX_LATENCY_BINS_DISABLED "enable(bins disabled)\n"
+#define TX_LATENCY_DISABLED "disable\n"
+
+
+/*
+ * Display if Tx latency statistics & bins are enabled/disabled
+ */
+static ssize_t sta_tx_latency_stat_read(struct file *file,
+                                       char __user *userbuf,
+                                       size_t count, loff_t *ppos)
+{
+       struct ieee80211_local *local = file->private_data;
+       struct ieee80211_tx_latency_bin_ranges  *tx_latency;
+       char *buf;
+       int bufsz, i, ret;
+       int pos = 0;
+
+       rcu_read_lock();
+
+       tx_latency = rcu_dereference(local->tx_latency);
+
+       if (tx_latency && tx_latency->n_ranges) {
+               bufsz = tx_latency->n_ranges * 15;
+               buf = kzalloc(bufsz, GFP_ATOMIC);
+               if (!buf)
+                       goto err;
+
+               for (i = 0; i < tx_latency->n_ranges; i++)
+                       pos += scnprintf(buf + pos, bufsz - pos, "%d,",
+                                        tx_latency->ranges[i]);
+               pos += scnprintf(buf + pos, bufsz - pos, "\n");
+       } else if (tx_latency) {
+               bufsz = sizeof(TX_LATENCY_BINS_DISABLED) + 1;
+               buf = kzalloc(bufsz, GFP_ATOMIC);
+               if (!buf)
+                       goto err;
+
+               pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
+                                TX_LATENCY_BINS_DISABLED);
+       } else {
+               bufsz = sizeof(TX_LATENCY_DISABLED) + 1;
+               buf = kzalloc(bufsz, GFP_ATOMIC);
+               if (!buf)
+                       goto err;
+
+               pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
+                                TX_LATENCY_DISABLED);
+       }
+
+       rcu_read_unlock();
+
+       ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       kfree(buf);
+
+       return ret;
+err:
+       rcu_read_unlock();
+       return -ENOMEM;
+}
+
+/*
+ * Receive input from user regarding Tx latency statistics
+ * The input should indicate if Tx latency statistics and bins are
+ * enabled/disabled.
+ * If bins are enabled input should indicate the amount of different bins and
+ * their ranges. Each bin will count how many Tx frames transmitted within the
+ * appropriate latency.
+ * Legal input is:
+ * a) "enable(bins disabled)" - to enable only general statistics
+ * b) "a,b,c,d,...z" - to enable general statistics and bins, where all are
+ * numbers and a < b < c < d.. < z
+ * c) "disable" - disable all statistics
+ * NOTE: must configure Tx latency statistics bins before stations connected.
+ */
+
+static ssize_t sta_tx_latency_stat_write(struct file *file,
+                                        const char __user *userbuf,
+                                        size_t count, loff_t *ppos)
+{
+       struct ieee80211_local *local = file->private_data;
+       char buf[128] = {};
+       char *bins = buf;
+       char *token;
+       int buf_size, i, alloc_size;
+       int prev_bin = 0;
+       int n_ranges = 0;
+       int ret = count;
+       struct ieee80211_tx_latency_bin_ranges  *tx_latency;
+
+       if (sizeof(buf) <= count)
+               return -EINVAL;
+       buf_size = count;
+       if (copy_from_user(buf, userbuf, buf_size))
+               return -EFAULT;
+
+       mutex_lock(&local->sta_mtx);
+
+       /* cannot change config once we have stations */
+       if (local->num_sta)
+               goto unlock;
+
+       tx_latency =
+               rcu_dereference_protected(local->tx_latency,
+                                         lockdep_is_held(&local->sta_mtx));
+
+       /* disable Tx statistics */
+       if (!strcmp(buf, TX_LATENCY_DISABLED)) {
+               if (!tx_latency)
+                       goto unlock;
+               rcu_assign_pointer(local->tx_latency, NULL);
+               synchronize_rcu();
+               kfree(tx_latency);
+               goto unlock;
+       }
+
+       /* Tx latency already enabled */
+       if (tx_latency)
+               goto unlock;
+
+       if (strcmp(TX_LATENCY_BINS_DISABLED, buf)) {
+               /* check how many bins and between what ranges user requested */
+               token = buf;
+               while (*token != '\0') {
+                       if (*token == TX_LATENCY_BIN_DELIMTER_C)
+                               n_ranges++;
+                       token++;
+               }
+               n_ranges++;
+       }
+
+       alloc_size = sizeof(struct ieee80211_tx_latency_bin_ranges) +
+                    n_ranges * sizeof(u32);
+       tx_latency = kzalloc(alloc_size, GFP_ATOMIC);
+       if (!tx_latency) {
+               ret = -ENOMEM;
+               goto unlock;
+       }
+       tx_latency->n_ranges = n_ranges;
+       for (i = 0; i < n_ranges; i++) { /* setting bin ranges */
+               token = strsep(&bins, TX_LATENCY_BIN_DELIMTER_S);
+               sscanf(token, "%d", &tx_latency->ranges[i]);
+               /* bins values should be in ascending order */
+               if (prev_bin >= tx_latency->ranges[i]) {
+                       ret = -EINVAL;
+                       kfree(tx_latency);
+                       goto unlock;
+               }
+               prev_bin = tx_latency->ranges[i];
+       }
+       rcu_assign_pointer(local->tx_latency, tx_latency);
+
+unlock:
+       mutex_unlock(&local->sta_mtx);
+
+       return ret;
+}
+
+static const struct file_operations stats_tx_latency_ops = {
+       .write = sta_tx_latency_stat_write,
+       .read = sta_tx_latency_stat_read,
+       .open = simple_open,
+       .llseek = generic_file_llseek,
+};
+
 int mac80211_format_buffer(char __user *userbuf, size_t count,
                                  loff_t *ppos, char *fmt, ...)
 {
@@ -315,4 +481,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
        DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
        DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);
        DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);
+
+       DEBUGFS_DEVSTATS_ADD(tx_latency);
 }
index 19c54a44ed4793823713b717a86111d4dda0d57d..80194b557a0cff8f3d2aba52f06cfc348212abf8 100644 (file)
@@ -38,6 +38,13 @@ static const struct file_operations sta_ ##name## _ops = {           \
        .llseek = generic_file_llseek,                                  \
 }
 
+#define STA_OPS_W(name)                                                        \
+static const struct file_operations sta_ ##name## _ops = {             \
+       .write = sta_##name##_write,                                    \
+       .open = simple_open,                                            \
+       .llseek = generic_file_llseek,                                  \
+}
+
 #define STA_OPS_RW(name)                                               \
 static const struct file_operations sta_ ##name## _ops = {             \
        .read = sta_##name##_read,                                      \
@@ -388,6 +395,131 @@ static ssize_t sta_last_rx_rate_read(struct file *file, char __user *userbuf,
 }
 STA_OPS(last_rx_rate);
 
+static int
+sta_tx_latency_stat_header(struct ieee80211_tx_latency_bin_ranges *tx_latency,
+                          char *buf, int pos, int bufsz)
+{
+       int i;
+       int range_count = tx_latency->n_ranges;
+       u32 *bin_ranges = tx_latency->ranges;
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                         "Station\t\t\tTID\tMax\tAvg");
+       if (range_count) {
+               pos += scnprintf(buf + pos, bufsz - pos,
+                                 "\t<=%d", bin_ranges[0]);
+               for (i = 0; i < range_count - 1; i++)
+                       pos += scnprintf(buf + pos, bufsz - pos, "\t%d-%d",
+                                         bin_ranges[i], bin_ranges[i+1]);
+               pos += scnprintf(buf + pos, bufsz - pos,
+                                 "\t%d<", bin_ranges[range_count - 1]);
+       }
+
+       pos += scnprintf(buf + pos, bufsz - pos, "\n");
+
+       return pos;
+}
+
+static int
+sta_tx_latency_stat_table(struct ieee80211_tx_latency_bin_ranges *tx_lat_range,
+                         struct ieee80211_tx_latency_stat *tx_lat,
+                         char *buf, int pos, int bufsz, int tid)
+{
+       u32 avg = 0;
+       int j;
+       int bin_count = tx_lat->bin_count;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "\t\t\t%d", tid);
+       /* make sure you don't divide in 0 */
+       if (tx_lat->counter)
+               avg = tx_lat->sum / tx_lat->counter;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "\t%d\t%d",
+                         tx_lat->max, avg);
+
+       if (tx_lat_range->n_ranges && tx_lat->bins)
+               for (j = 0; j < bin_count; j++)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                         "\t%d", tx_lat->bins[j]);
+       pos += scnprintf(buf + pos, bufsz - pos, "\n");
+
+       return pos;
+}
+
+/*
+ * Output Tx latency statistics station && restart all statistics information
+ */
+static ssize_t sta_tx_latency_stat_read(struct file *file,
+                                       char __user *userbuf,
+                                       size_t count, loff_t *ppos)
+{
+       struct sta_info *sta = file->private_data;
+       struct ieee80211_local *local = sta->local;
+       struct ieee80211_tx_latency_bin_ranges *tx_latency;
+       char *buf;
+       int bufsz, ret, i;
+       int pos = 0;
+
+       bufsz = 20 * IEEE80211_NUM_TIDS *
+               sizeof(struct ieee80211_tx_latency_stat);
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       rcu_read_lock();
+
+       tx_latency = rcu_dereference(local->tx_latency);
+
+       if (!sta->tx_lat) {
+               pos += scnprintf(buf + pos, bufsz - pos,
+                                "Tx latency statistics are not enabled\n");
+               goto unlock;
+       }
+
+       pos = sta_tx_latency_stat_header(tx_latency, buf, pos, bufsz);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", sta->sta.addr);
+       for (i = 0; i < IEEE80211_NUM_TIDS; i++)
+               pos = sta_tx_latency_stat_table(tx_latency, &sta->tx_lat[i],
+                                               buf, pos, bufsz, i);
+unlock:
+       rcu_read_unlock();
+
+       ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       kfree(buf);
+
+       return ret;
+}
+STA_OPS(tx_latency_stat);
+
+static ssize_t sta_tx_latency_stat_reset_write(struct file *file,
+                                              const char __user *userbuf,
+                                              size_t count, loff_t *ppos)
+{
+       u32 *bins;
+       int bin_count;
+       struct sta_info *sta = file->private_data;
+       int i;
+
+       if (!sta->tx_lat)
+               return -EINVAL;
+
+       for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+               bins = sta->tx_lat[i].bins;
+               bin_count = sta->tx_lat[i].bin_count;
+
+               sta->tx_lat[i].max = 0;
+               sta->tx_lat[i].sum = 0;
+               sta->tx_lat[i].counter = 0;
+
+               if (bin_count)
+                       memset(bins, 0, bin_count * sizeof(u32));
+       }
+
+       return count;
+}
+STA_OPS_W(tx_latency_stat_reset);
+
 #define DEBUGFS_ADD(name) \
        debugfs_create_file(#name, 0400, \
                sta->debugfs.dir, sta, &sta_ ##name## _ops);
@@ -441,6 +573,8 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
        DEBUGFS_ADD(last_ack_signal);
        DEBUGFS_ADD(current_tx_rate);
        DEBUGFS_ADD(last_rx_rate);
+       DEBUGFS_ADD(tx_latency_stat);
+       DEBUGFS_ADD(tx_latency_stat_reset);
 
        DEBUGFS_ADD_COUNTER(rx_packets, rx_packets);
        DEBUGFS_ADD_COUNTER(tx_packets, tx_packets);
index 27a39de89679b7d3710fea18a65b6d5df6d003d0..2eda7b13124abb7469a8b7b86503de07c0155623 100644 (file)
@@ -550,12 +550,12 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
                                        capability);
                /* XXX: should not really modify cfg80211 data */
                if (cbss) {
-                       cbss->channel = sdata->local->csa_chandef.chan;
+                       cbss->channel = sdata->csa_chandef.chan;
                        cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
                }
        }
 
-       ifibss->chandef = sdata->local->csa_chandef;
+       ifibss->chandef = sdata->csa_chandef;
 
        /* generate the beacon */
        err = ieee80211_ibss_csa_beacon(sdata, NULL);
@@ -926,7 +926,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                                IEEE80211_MAX_QUEUE_MAP,
                                IEEE80211_QUEUE_STOP_REASON_CSA);
 
-       sdata->local->csa_chandef = params.chandef;
+       sdata->csa_chandef = params.chandef;
        sdata->vif.csa_active = true;
 
        ieee80211_bss_info_change_notify(sdata, err);
index 4aea4e7911135133818e66a1439b111d14e6147e..ed5bf8b4b5c2bfb8d4253a0dbaa15b76aac309dd 100644 (file)
@@ -728,6 +728,7 @@ struct ieee80211_sub_if_data {
        u16 sequence_number;
        __be16 control_port_protocol;
        bool control_port_no_encrypt;
+       int encrypt_headroom;
 
        struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
 
@@ -735,6 +736,7 @@ struct ieee80211_sub_if_data {
        int csa_counter_offset_beacon;
        int csa_counter_offset_presp;
        bool csa_radar_required;
+       struct cfg80211_chan_def csa_chandef;
 
        /* used to reconfigure hardware SM PS */
        struct work_struct recalc_smps;
@@ -811,6 +813,9 @@ static inline void sdata_unlock(struct ieee80211_sub_if_data *sdata)
        __release(&sdata->wdev.mtx);
 }
 
+#define sdata_dereference(p, sdata) \
+       rcu_dereference_protected(p, lockdep_is_held(&sdata->wdev.mtx))
+
 static inline void
 sdata_assert_lock(struct ieee80211_sub_if_data *sdata)
 {
@@ -896,6 +901,24 @@ struct tpt_led_trigger {
 };
 #endif
 
+/*
+ * struct ieee80211_tx_latency_bin_ranges - Tx latency statistics bins ranges
+ *
+ * Measuring Tx latency statistics. Counts how many Tx frames transmitted in a
+ * certain latency range (in Milliseconds). Each station that uses these
+ * ranges will have bins to count the amount of frames received in that range.
+ * The user can configure the ranges via debugfs.
+ * If ranges is NULL then Tx latency statistics bins are disabled for all
+ * stations.
+ *
+ * @n_ranges: number of ranges that are taken in account
+ * @ranges: the ranges that the user requested or NULL if disabled.
+ */
+struct ieee80211_tx_latency_bin_ranges {
+       int n_ranges;
+       u32 ranges[];
+};
+
 /**
  * mac80211 scan flags - currently active scan mode
  *
@@ -1048,6 +1071,12 @@ struct ieee80211_local {
        struct timer_list sta_cleanup;
        int sta_generation;
 
+       /*
+        * Tx latency statistics parameters for all stations.
+        * Can enable via debugfs (NULL when disabled).
+        */
+       struct ieee80211_tx_latency_bin_ranges __rcu *tx_latency;
+
        struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
        struct tasklet_struct tx_pending_tasklet;
 
@@ -1093,7 +1122,6 @@ struct ieee80211_local {
        enum mac80211_scan_state next_scan_state;
        struct delayed_work scan_work;
        struct ieee80211_sub_if_data __rcu *scan_sdata;
-       struct cfg80211_chan_def csa_chandef;
        /* For backward compatibility only -- do not use */
        struct cfg80211_chan_def _oper_chandef;
 
@@ -1693,6 +1721,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
 int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
                                enum ieee80211_smps_mode smps_mode);
 void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
+void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata);
 
 size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
                          const u8 *ids, int n_ids, size_t offset);
@@ -1731,7 +1760,6 @@ ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
 /* NOTE: only use ieee80211_vif_change_channel() for channel switch */
 int __must_check
 ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-                            const struct cfg80211_chan_def *chandef,
                             u32 *changed);
 void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
@@ -1742,6 +1770,8 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
                                   struct ieee80211_chanctx *chanctx);
 void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
                                    struct ieee80211_chanctx *chanctx);
+void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
+                                     struct ieee80211_chanctx *ctx);
 
 void ieee80211_dfs_cac_timer(unsigned long data);
 void ieee80211_dfs_cac_timer_work(struct work_struct *work);
@@ -1750,6 +1780,15 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work);
 int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
                              struct cfg80211_csa_settings *csa_settings);
 
+bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs);
+bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n);
+const struct ieee80211_cipher_scheme *
+ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
+                enum nl80211_iftype iftype);
+int ieee80211_cs_headroom(struct ieee80211_local *local,
+                         struct cfg80211_crypto_settings *crypto,
+                         enum nl80211_iftype iftype);
+
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
 #else
index 36c3a4cbcabf66b2a0864414b3c23ea2896b7c4e..7aa9f9dea9df0af487c25c36d52004179d76b72c 100644 (file)
@@ -401,6 +401,8 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
        snprintf(sdata->name, IFNAMSIZ, "%s-monitor",
                 wiphy_name(local->hw.wiphy));
 
+       sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
+
        ieee80211_set_default_queues(sdata);
 
        ret = drv_add_interface(local, sdata);
@@ -749,6 +751,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        u32 hw_reconf_flags = 0;
        int i, flushed;
        struct ps_data *ps;
+       struct cfg80211_chan_def chandef;
 
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
 
@@ -823,11 +826,13 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
 
        if (sdata->wdev.cac_started) {
+               chandef = sdata->vif.bss_conf.chandef;
                WARN_ON(local->suspended);
                mutex_lock(&local->iflist_mtx);
                ieee80211_vif_release_channel(sdata);
                mutex_unlock(&local->iflist_mtx);
-               cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED,
+               cfg80211_cac_event(sdata->dev, &chandef,
+                                  NL80211_RADAR_CAC_ABORTED,
                                   GFP_KERNEL);
        }
 
@@ -1036,7 +1041,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
  */
 static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
 {
-       int flushed;
        int i;
 
        /* free extra data */
@@ -1050,9 +1054,6 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
 
        if (ieee80211_vif_is_mesh(&sdata->vif))
                mesh_rmc_free(sdata);
-
-       flushed = sta_info_flush(sdata);
-       WARN_ON(flushed);
 }
 
 static void ieee80211_uninit(struct net_device *dev)
@@ -1270,6 +1271,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 
        sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);
        sdata->control_port_no_encrypt = false;
+       sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
 
        sdata->noack_map = 0;
 
@@ -1685,6 +1687,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
        sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
        sdata->user_power_level = local->user_power_level;
 
+       sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
+
        /* setup type-dependent data */
        ieee80211_setup_sdata(sdata, type);
 
index 3e51dd7d98b34aad114e6b927beae8e4ecdde9fb..e568d98167d0244e499e53c0b2a3aad1263b1ea0 100644 (file)
@@ -260,25 +260,29 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
        int idx;
        bool defunikey, defmultikey, defmgmtkey;
 
+       /* caller must provide at least one old/new */
+       if (WARN_ON(!new && !old))
+               return;
+
        if (new)
                list_add_tail(&new->list, &sdata->key_list);
 
-       if (sta && pairwise) {
-               rcu_assign_pointer(sta->ptk, new);
-       } else if (sta) {
-               if (old)
-                       idx = old->conf.keyidx;
-               else
-                       idx = new->conf.keyidx;
-               rcu_assign_pointer(sta->gtk[idx], new);
-       } else {
-               WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
+       WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
 
-               if (old)
-                       idx = old->conf.keyidx;
-               else
-                       idx = new->conf.keyidx;
+       if (old)
+               idx = old->conf.keyidx;
+       else
+               idx = new->conf.keyidx;
 
+       if (sta) {
+               if (pairwise) {
+                       rcu_assign_pointer(sta->ptk[idx], new);
+                       sta->ptk_idx = idx;
+               } else {
+                       rcu_assign_pointer(sta->gtk[idx], new);
+                       sta->gtk_idx = idx;
+               }
+       } else {
                defunikey = old &&
                        old == key_mtx_dereference(sdata->local,
                                                sdata->default_unicast_key);
@@ -312,9 +316,11 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
                list_del(&old->list);
 }
 
-struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
-                                         const u8 *key_data,
-                                         size_t seq_len, const u8 *seq)
+struct ieee80211_key *
+ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
+                   const u8 *key_data,
+                   size_t seq_len, const u8 *seq,
+                   const struct ieee80211_cipher_scheme *cs)
 {
        struct ieee80211_key *key;
        int i, j, err;
@@ -393,6 +399,18 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                        return ERR_PTR(err);
                }
                break;
+       default:
+               if (cs) {
+                       size_t len = (seq_len > MAX_PN_LEN) ?
+                                               MAX_PN_LEN : seq_len;
+
+                       key->conf.iv_len = cs->hdr_len;
+                       key->conf.icv_len = cs->mic_len;
+                       for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
+                               for (j = 0; j < len; j++)
+                                       key->u.gen.rx_pn[i][j] =
+                                                       seq[len - j - 1];
+               }
        }
        memcpy(key->conf.key, key_data, key_len);
        INIT_LIST_HEAD(&key->list);
@@ -475,7 +493,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
        mutex_lock(&sdata->local->key_mtx);
 
        if (sta && pairwise)
-               old_key = key_mtx_dereference(sdata->local, sta->ptk);
+               old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]);
        else if (sta)
                old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);
        else
@@ -625,8 +643,10 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local,
                list_add(&key->list, &keys);
        }
 
-       key = key_mtx_dereference(local, sta->ptk);
-       if (key) {
+       for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+               key = key_mtx_dereference(local, sta->ptk[i]);
+               if (!key)
+                       continue;
                ieee80211_key_replace(key->sdata, key->sta,
                                key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
                                key, NULL);
@@ -877,7 +897,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
 
        key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx,
                                  keyconf->keylen, keyconf->key,
-                                 0, NULL);
+                                 0, NULL, NULL);
        if (IS_ERR(key))
                return ERR_CAST(key);
 
index aaae0ed3700402433ae56244eb97baa2804aba5b..0aebb889cabae566d6f33e00e59a2f299c9baa69 100644 (file)
@@ -18,6 +18,7 @@
 
 #define NUM_DEFAULT_KEYS 4
 #define NUM_DEFAULT_MGMT_KEYS 2
+#define MAX_PN_LEN 16
 
 struct ieee80211_local;
 struct ieee80211_sub_if_data;
@@ -93,6 +94,10 @@ struct ieee80211_key {
                        u32 replays; /* dot11RSNAStatsCMACReplays */
                        u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
                } aes_cmac;
+               struct {
+                       /* generic cipher scheme */
+                       u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN];
+               } gen;
        } u;
 
        /* number of times this key has been used */
@@ -113,9 +118,11 @@ struct ieee80211_key {
        struct ieee80211_key_conf conf;
 };
 
-struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
-                                         const u8 *key_data,
-                                         size_t seq_len, const u8 *seq);
+struct ieee80211_key *
+ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
+                   const u8 *key_data,
+                   size_t seq_len, const u8 *seq,
+                   const struct ieee80211_cipher_scheme *cs);
 /*
  * Insert a key into data structures (sdata, sta if necessary)
  * to make it used, free old key. On failure, also free the new key.
index 7d1c3ac48ed941866170afdf387def183690d612..fa34cd2344b98b9615a940a00e78363b494bc06c 100644 (file)
@@ -651,15 +651,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 }
 EXPORT_SYMBOL(ieee80211_alloc_hw);
 
-int ieee80211_register_hw(struct ieee80211_hw *hw)
+static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
 {
-       struct ieee80211_local *local = hw_to_local(hw);
-       int result, i;
-       enum ieee80211_band band;
-       int channels, max_bitrates;
-       bool supp_ht, supp_vht;
-       netdev_features_t feature_whitelist;
-       struct cfg80211_chan_def dflt_chandef = {};
+       bool have_wep = !(IS_ERR(local->wep_tx_tfm) ||
+                         IS_ERR(local->wep_rx_tfm));
+       bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE;
+       const struct ieee80211_cipher_scheme *cs = local->hw.cipher_schemes;
+       int n_suites = 0, r = 0, w = 0;
+       u32 *suites;
        static const u32 cipher_suites[] = {
                /* keep WEP first, it may be removed below */
                WLAN_CIPHER_SUITE_WEP40,
@@ -671,6 +670,93 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                WLAN_CIPHER_SUITE_AES_CMAC
        };
 
+       /* Driver specifies the ciphers, we have nothing to do... */
+       if (local->hw.wiphy->cipher_suites && have_wep)
+               return 0;
+
+       /* Set up cipher suites if driver relies on mac80211 cipher defs */
+       if (!local->hw.wiphy->cipher_suites && !cs) {
+               local->hw.wiphy->cipher_suites = cipher_suites;
+               local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
+               if (!have_mfp)
+                       local->hw.wiphy->n_cipher_suites--;
+
+               if (!have_wep) {
+                       local->hw.wiphy->cipher_suites += 2;
+                       local->hw.wiphy->n_cipher_suites -= 2;
+               }
+
+               return 0;
+       }
+
+       if (!local->hw.wiphy->cipher_suites) {
+               /*
+                * Driver specifies cipher schemes only
+                * We start counting ciphers defined by schemes, TKIP and CCMP
+                */
+               n_suites = local->hw.n_cipher_schemes + 2;
+
+               /* check if we have WEP40 and WEP104 */
+               if (have_wep)
+                       n_suites += 2;
+
+               /* check if we have AES_CMAC */
+               if (have_mfp)
+                       n_suites++;
+
+               suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL);
+               if (!suites)
+                       return -ENOMEM;
+
+               suites[w++] = WLAN_CIPHER_SUITE_CCMP;
+               suites[w++] = WLAN_CIPHER_SUITE_TKIP;
+
+               if (have_wep) {
+                       suites[w++] = WLAN_CIPHER_SUITE_WEP40;
+                       suites[w++] = WLAN_CIPHER_SUITE_WEP104;
+               }
+
+               if (have_mfp)
+                       suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC;
+
+               for (r = 0; r < local->hw.n_cipher_schemes; r++)
+                       suites[w++] = cs[r].cipher;
+       } else {
+               /* Driver provides cipher suites, but we need to exclude WEP */
+               suites = kmemdup(local->hw.wiphy->cipher_suites,
+                                sizeof(u32) * local->hw.wiphy->n_cipher_suites,
+                                GFP_KERNEL);
+               if (!suites)
+                       return -ENOMEM;
+
+               for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
+                       u32 suite = local->hw.wiphy->cipher_suites[r];
+
+                       if (suite == WLAN_CIPHER_SUITE_WEP40 ||
+                           suite == WLAN_CIPHER_SUITE_WEP104)
+                               continue;
+                       suites[w++] = suite;
+               }
+       }
+
+       local->hw.wiphy->cipher_suites = suites;
+       local->hw.wiphy->n_cipher_suites = w;
+       local->wiphy_ciphers_allocated = true;
+
+       return 0;
+}
+
+int ieee80211_register_hw(struct ieee80211_hw *hw)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       int result, i;
+       enum ieee80211_band band;
+       int channels, max_bitrates;
+       bool supp_ht, supp_vht;
+       netdev_features_t feature_whitelist;
+       struct cfg80211_chan_def dflt_chandef = {};
+
        if (hw->flags & IEEE80211_HW_QUEUE_CONTROL &&
            (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE ||
             local->hw.offchannel_tx_hw_queue >= local->hw.queues))
@@ -851,43 +937,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (local->hw.wiphy->max_scan_ie_len)
                local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
 
-       /* Set up cipher suites unless driver already did */
-       if (!local->hw.wiphy->cipher_suites) {
-               local->hw.wiphy->cipher_suites = cipher_suites;
-               local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
-               if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
-                       local->hw.wiphy->n_cipher_suites--;
-       }
-       if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) {
-               if (local->hw.wiphy->cipher_suites == cipher_suites) {
-                       local->hw.wiphy->cipher_suites += 2;
-                       local->hw.wiphy->n_cipher_suites -= 2;
-               } else {
-                       u32 *suites;
-                       int r, w = 0;
-
-                       /* Filter out WEP */
-
-                       suites = kmemdup(
-                               local->hw.wiphy->cipher_suites,
-                               sizeof(u32) * local->hw.wiphy->n_cipher_suites,
-                               GFP_KERNEL);
-                       if (!suites) {
-                               result = -ENOMEM;
-                               goto fail_wiphy_register;
-                       }
-                       for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
-                               u32 suite = local->hw.wiphy->cipher_suites[r];
-                               if (suite == WLAN_CIPHER_SUITE_WEP40 ||
-                                   suite == WLAN_CIPHER_SUITE_WEP104)
-                                       continue;
-                               suites[w++] = suite;
-                       }
-                       local->hw.wiphy->cipher_suites = suites;
-                       local->hw.wiphy->n_cipher_suites = w;
-                       local->wiphy_ciphers_allocated = true;
-               }
-       }
+       WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes,
+                                        local->hw.n_cipher_schemes));
+
+       result = ieee80211_init_cipher_suites(local);
+       if (result < 0)
+               goto fail_wiphy_register;
 
        if (!local->ops->remain_on_channel)
                local->hw.wiphy->max_remain_on_channel_duration = 5000;
@@ -1090,6 +1145,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
                     ieee80211_free_ack_frame, NULL);
        idr_destroy(&local->ack_status_frames);
 
+       kfree(rcu_access_pointer(local->tx_latency));
+
        wiphy_free(local->hw.wiphy);
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
index ba105257d03f1cffc4398f42c52e67b1e8d3eaaa..89df62b2b6896f05a2d3170bce62a40fff23cf8c 100644 (file)
@@ -674,8 +674,6 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
        rcu_read_lock();
        csa = rcu_dereference(ifmsh->csa);
        if (csa) {
-               __le16 pre_value;
-
                pos = skb_put(skb, 13);
                memset(pos, 0, 13);
                *pos++ = WLAN_EID_CHANNEL_SWITCH;
@@ -697,8 +695,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
                          WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
                put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos);
                pos += 2;
-               pre_value = cpu_to_le16(ifmsh->pre_value);
-               memcpy(pos, &pre_value, 2);
+               put_unaligned_le16(ifmsh->pre_value, pos);
                pos += 2;
        }
        rcu_read_unlock();
@@ -964,7 +961,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
                                IEEE80211_MAX_QUEUE_MAP,
                                IEEE80211_QUEUE_STOP_REASON_CSA);
 
-       sdata->local->csa_chandef = params.chandef;
+       sdata->csa_chandef = params.chandef;
        sdata->vif.csa_active = true;
 
        ieee80211_bss_info_change_notify(sdata, err);
index 2bc7fd2f787dd9546ac616e8c55340e1957eafb1..f39a19f9090fe0d91181b8cb4487dd928232d24b 100644 (file)
@@ -215,8 +215,6 @@ int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
 bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
                        struct ieee802_11_elems *ie);
 void mesh_ids_set_default(struct ieee80211_if_mesh *mesh);
-void mesh_mgmt_ies_add(struct ieee80211_sub_if_data *sdata,
-                      struct sk_buff *skb);
 int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
                         struct sk_buff *skb);
 int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata,
@@ -303,8 +301,8 @@ void mesh_mpath_table_grow(void);
 void mesh_mpp_table_grow(void);
 /* Mesh paths */
 int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
-                      u8 ttl, const u8 *target, __le32 target_sn,
-                      __le16 target_rcode, const u8 *ra);
+                      u8 ttl, const u8 *target, u32 target_sn,
+                      u16 target_rcode, const u8 *ra);
 void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
 void mesh_path_flush_pending(struct mesh_path *mpath);
 void mesh_path_tx_pending(struct mesh_path *mpath);
index 486819cd02cd7d03924e30d4e93f7ac201248b4c..f9514685d45a54802cb0f21dce0953ccbe9b78f4 100644 (file)
@@ -102,12 +102,11 @@ enum mpath_frame_type {
 static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
 static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
-                                 const u8 *orig_addr, __le32 orig_sn,
+                                 const u8 *orig_addr, u32 orig_sn,
                                  u8 target_flags, const u8 *target,
-                                 __le32 target_sn, const u8 *da,
+                                 u32 target_sn, const u8 *da,
                                  u8 hop_count, u8 ttl,
-                                 __le32 lifetime, __le32 metric,
-                                 __le32 preq_id,
+                                 u32 lifetime, u32 metric, u32 preq_id,
                                  struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
@@ -167,33 +166,33 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
        if (action == MPATH_PREP) {
                memcpy(pos, target, ETH_ALEN);
                pos += ETH_ALEN;
-               memcpy(pos, &target_sn, 4);
+               put_unaligned_le32(target_sn, pos);
                pos += 4;
        } else {
                if (action == MPATH_PREQ) {
-                       memcpy(pos, &preq_id, 4);
+                       put_unaligned_le32(preq_id, pos);
                        pos += 4;
                }
                memcpy(pos, orig_addr, ETH_ALEN);
                pos += ETH_ALEN;
-               memcpy(pos, &orig_sn, 4);
+               put_unaligned_le32(orig_sn, pos);
                pos += 4;
        }
-       memcpy(pos, &lifetime, 4);      /* interval for RANN */
+       put_unaligned_le32(lifetime, pos); /* interval for RANN */
        pos += 4;
-       memcpy(pos, &metric, 4);
+       put_unaligned_le32(metric, pos);
        pos += 4;
        if (action == MPATH_PREQ) {
                *pos++ = 1; /* destination count */
                *pos++ = target_flags;
                memcpy(pos, target, ETH_ALEN);
                pos += ETH_ALEN;
-               memcpy(pos, &target_sn, 4);
+               put_unaligned_le32(target_sn, pos);
                pos += 4;
        } else if (action == MPATH_PREP) {
                memcpy(pos, orig_addr, ETH_ALEN);
                pos += ETH_ALEN;
-               memcpy(pos, &orig_sn, 4);
+               put_unaligned_le32(orig_sn, pos);
                pos += 4;
        }
 
@@ -239,8 +238,8 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
  * frame directly but add it to the pending queue instead.
  */
 int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
-                      u8 ttl, const u8 *target, __le32 target_sn,
-                      __le16 target_rcode, const u8 *ra)
+                      u8 ttl, const u8 *target, u32 target_sn,
+                      u16 target_rcode, const u8 *ra)
 {
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
@@ -254,13 +253,13 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
                return -EAGAIN;
 
        skb = dev_alloc_skb(local->tx_headroom +
-                           IEEE80211_ENCRYPT_HEADROOM +
+                           sdata->encrypt_headroom +
                            IEEE80211_ENCRYPT_TAILROOM +
                            hdr_len +
                            2 + 15 /* PERR IE */);
        if (!skb)
                return -1;
-       skb_reserve(skb, local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM);
+       skb_reserve(skb, local->tx_headroom + sdata->encrypt_headroom);
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
        memset(mgmt, 0, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
@@ -293,9 +292,9 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
        pos++;
        memcpy(pos, target, ETH_ALEN);
        pos += ETH_ALEN;
-       memcpy(pos, &target_sn, 4);
+       put_unaligned_le32(target_sn, pos);
        pos += 4;
-       memcpy(pos, &target_rcode, 2);
+       put_unaligned_le16(target_rcode, pos);
 
        /* see note in function header */
        prepare_frame_for_deferred_tx(sdata, skb);
@@ -592,10 +591,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                if (ttl != 0) {
                        mhwmp_dbg(sdata, "replying to the PREQ\n");
                        mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr,
-                               cpu_to_le32(orig_sn), 0, target_addr,
-                               cpu_to_le32(target_sn), mgmt->sa, 0, ttl,
-                               cpu_to_le32(lifetime), cpu_to_le32(metric),
-                               0, sdata);
+                                              orig_sn, 0, target_addr,
+                                              target_sn, mgmt->sa, 0, ttl,
+                                              lifetime, metric, 0, sdata);
                } else {
                        ifmsh->mshstats.dropped_frames_ttl++;
                }
@@ -625,11 +623,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                }
 
                mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
-                               cpu_to_le32(orig_sn), target_flags, target_addr,
-                               cpu_to_le32(target_sn), da,
-                               hopcount, ttl, cpu_to_le32(lifetime),
-                               cpu_to_le32(metric), cpu_to_le32(preq_id),
-                               sdata);
+                                      orig_sn, target_flags, target_addr,
+                                      target_sn, da, hopcount, ttl, lifetime,
+                                      metric, preq_id, sdata);
                if (!is_multicast_ether_addr(da))
                        ifmsh->mshstats.fwded_unicast++;
                else
@@ -695,11 +691,9 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
        target_sn = PREP_IE_TARGET_SN(prep_elem);
        orig_sn = PREP_IE_ORIG_SN(prep_elem);
 
-       mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr,
-               cpu_to_le32(orig_sn), 0, target_addr,
-               cpu_to_le32(target_sn), next_hop, hopcount,
-               ttl, cpu_to_le32(lifetime), cpu_to_le32(metric),
-               0, sdata);
+       mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, orig_sn, 0,
+                              target_addr, target_sn, next_hop, hopcount,
+                              ttl, lifetime, metric, 0, sdata);
        rcu_read_unlock();
 
        sdata->u.mesh.mshstats.fwded_unicast++;
@@ -750,8 +744,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
                        if (!ifmsh->mshcfg.dot11MeshForwarding)
                                goto endperr;
                        mesh_path_error_tx(sdata, ttl, target_addr,
-                                          cpu_to_le32(target_sn),
-                                          cpu_to_le16(target_rcode),
+                                          target_sn, target_rcode,
                                           broadcast_addr);
                } else
                        spin_unlock_bh(&mpath->state_lock);
@@ -847,11 +840,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
 
        if (ifmsh->mshcfg.dot11MeshForwarding) {
                mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
-                                      cpu_to_le32(orig_sn),
-                                      0, NULL, 0, broadcast_addr,
-                                      hopcount, ttl, cpu_to_le32(interval),
-                                      cpu_to_le32(metric + metric_txsta),
-                                      0, sdata);
+                                      orig_sn, 0, NULL, 0, broadcast_addr,
+                                      hopcount, ttl, interval,
+                                      metric + metric_txsta, 0, sdata);
        }
 
        rcu_read_unlock();
@@ -1049,11 +1040,9 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
 
        spin_unlock_bh(&mpath->state_lock);
        da = (mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr;
-       mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr,
-                       cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
-                       cpu_to_le32(mpath->sn), da, 0,
-                       ttl, cpu_to_le32(lifetime), 0,
-                       cpu_to_le32(ifmsh->preq_id++), sdata);
+       mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, ifmsh->sn,
+                              target_flags, mpath->dst, mpath->sn, da, 0,
+                              ttl, lifetime, 0, ifmsh->preq_id++, sdata);
        mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
 
 enddiscovery:
@@ -1212,10 +1201,9 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
        switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) {
        case IEEE80211_PROACTIVE_RANN:
                mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
-                              cpu_to_le32(++ifmsh->sn),
-                              0, NULL, 0, broadcast_addr,
-                              0, ifmsh->mshcfg.element_ttl,
-                              cpu_to_le32(interval), 0, 0, sdata);
+                                      ++ifmsh->sn, 0, NULL, 0, broadcast_addr,
+                                      0, ifmsh->mshcfg.element_ttl,
+                                      interval, 0, 0, sdata);
                break;
        case IEEE80211_PROACTIVE_PREQ_WITH_PREP:
                flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG;
@@ -1224,11 +1212,10 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
                target_flags |= IEEE80211_PREQ_TO_FLAG |
                                IEEE80211_PREQ_USN_FLAG;
                mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr,
-                               cpu_to_le32(++ifmsh->sn), target_flags,
-                               (u8 *) broadcast_addr, 0, broadcast_addr,
-                               0, ifmsh->mshcfg.element_ttl,
-                               cpu_to_le32(interval),
-                               0, cpu_to_le32(ifmsh->preq_id++), sdata);
+                                      ++ifmsh->sn, target_flags,
+                                      (u8 *) broadcast_addr, 0, broadcast_addr,
+                                      0, ifmsh->mshcfg.element_ttl, interval,
+                                      0, ifmsh->preq_id++, sdata);
                break;
        default:
                mhwmp_dbg(sdata, "Proactive mechanism not supported\n");
index 89aacfd2756d627287ce4d381e7038d0b0ebdd5e..7d050ed6fe5a4ec879bc9711c088db8360154448 100644 (file)
@@ -722,7 +722,6 @@ void mesh_plink_broken(struct sta_info *sta)
        struct mpath_node *node;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        int i;
-       __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE);
 
        rcu_read_lock();
        tbl = rcu_dereference(mesh_paths);
@@ -736,9 +735,9 @@ void mesh_plink_broken(struct sta_info *sta)
                        ++mpath->sn;
                        spin_unlock_bh(&mpath->state_lock);
                        mesh_path_error_tx(sdata,
-                                          sdata->u.mesh.mshcfg.element_ttl,
-                                          mpath->dst, cpu_to_le32(mpath->sn),
-                                          reason, bcast);
+                               sdata->u.mesh.mshcfg.element_ttl,
+                               mpath->dst, mpath->sn,
+                               WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast);
                }
        }
        rcu_read_unlock();
index 4301aa5aa227c3d539cd0bf89bdf5b004679976a..cf83217103f9c91479cd4f3f1b97a2752af0c897 100644 (file)
 #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
                                jiffies + HZ * t / 1000))
 
-/* We only need a valid sta if user configured a minimum rssi_threshold. */
-#define rssi_threshold_check(sta, sdata) \
-               (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\
-               (sta && (s8) -ewma_read(&sta->avg_signal) > \
-               sdata->u.mesh.mshcfg.rssi_threshold))
-
 enum plink_event {
        PLINK_UNDEFINED,
        OPN_ACPT,
@@ -61,7 +55,17 @@ static const char * const mplevents[] = {
 
 static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                               enum ieee80211_self_protected_actioncode action,
-                              u8 *da, __le16 llid, __le16 plid, __le16 reason);
+                              u8 *da, u16 llid, u16 plid, u16 reason);
+
+
+/* We only need a valid sta if user configured a minimum rssi_threshold. */
+static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata,
+                                struct sta_info *sta)
+{
+       s32 rssi_threshold = sdata->u.mesh.mshcfg.rssi_threshold;
+       return rssi_threshold == 0 ||
+              (sta && (s8) -ewma_read(&sta->avg_signal) > rssi_threshold);
+}
 
 /**
  * mesh_plink_fsm_restart - restart a mesh peer link finite state machine
@@ -242,7 +246,7 @@ u32 mesh_plink_deactivate(struct sta_info *sta)
 
        spin_lock_bh(&sta->lock);
        changed = __mesh_plink_deactivate(sta);
-       sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED);
+       sta->reason = WLAN_REASON_MESH_PEER_CANCELED;
        mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
                            sta->sta.addr, sta->llid, sta->plid,
                            sta->reason);
@@ -253,7 +257,7 @@ u32 mesh_plink_deactivate(struct sta_info *sta)
 
 static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                               enum ieee80211_self_protected_actioncode action,
-                              u8 *da, __le16 llid, __le16 plid, __le16 reason)
+                              u8 *da, u16 llid, u16 plid, u16 reason)
 {
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
@@ -279,7 +283,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                            2 + 8 + /* peering IE */
                            sdata->u.mesh.ie_len);
        if (!skb)
-               return -1;
+               return err;
        info = IEEE80211_SKB_CB(skb);
        skb_reserve(skb, local->tx_headroom);
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
@@ -301,7 +305,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
                        /* AID */
                        pos = skb_put(skb, 2);
-                       memcpy(pos + 2, &plid, 2);
+                       put_unaligned_le16(plid, pos + 2);
                }
                if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
                    ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
@@ -343,14 +347,14 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
        *pos++ = ie_len;
        memcpy(pos, &peering_proto, 2);
        pos += 2;
-       memcpy(pos, &llid, 2);
+       put_unaligned_le16(llid, pos);
        pos += 2;
        if (include_plid) {
-               memcpy(pos, &plid, 2);
+               put_unaligned_le16(plid, pos);
                pos += 2;
        }
        if (action == WLAN_SP_MESH_PEERING_CLOSE) {
-               memcpy(pos, &reason, 2);
+               put_unaligned_le16(reason, pos);
                pos += 2;
        }
 
@@ -518,7 +522,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
            sta->plink_state == NL80211_PLINK_LISTEN &&
            sdata->u.mesh.accepting_plinks &&
            sdata->u.mesh.mshcfg.auto_open_plinks &&
-           rssi_threshold_check(sta, sdata))
+           rssi_threshold_check(sdata, sta))
                changed = mesh_plink_open(sta);
 
        ieee80211_mps_frame_release(sta, elems);
@@ -530,9 +534,10 @@ out:
 static void mesh_plink_timer(unsigned long data)
 {
        struct sta_info *sta;
-       __le16 llid, plid, reason;
+       u16 reason = 0;
        struct ieee80211_sub_if_data *sdata;
        struct mesh_config *mshcfg;
+       enum ieee80211_self_protected_actioncode action = 0;
 
        /*
         * This STA is valid because sta_info_destroy() will
@@ -553,9 +558,6 @@ static void mesh_plink_timer(unsigned long data)
        mpl_dbg(sta->sdata,
                "Mesh plink timer for %pM fired on state %s\n",
                sta->sta.addr, mplstates[sta->plink_state]);
-       reason = 0;
-       llid = sta->llid;
-       plid = sta->plid;
        sdata = sta->sdata;
        mshcfg = &sdata->u.mesh.mshcfg;
 
@@ -574,33 +576,31 @@ static void mesh_plink_timer(unsigned long data)
                                             rand % sta->plink_timeout;
                        ++sta->plink_retries;
                        mod_plink_timer(sta, sta->plink_timeout);
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
-                                           sta->sta.addr, llid, 0, 0);
+                       action = WLAN_SP_MESH_PEERING_OPEN;
                        break;
                }
-               reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES);
+               reason = WLAN_REASON_MESH_MAX_RETRIES;
                /* fall through on else */
        case NL80211_PLINK_CNF_RCVD:
                /* confirm timer */
                if (!reason)
-                       reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT);
+                       reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT;
                sta->plink_state = NL80211_PLINK_HOLDING;
                mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
-               spin_unlock_bh(&sta->lock);
-               mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
-                                   sta->sta.addr, llid, plid, reason);
+               action = WLAN_SP_MESH_PEERING_CLOSE;
                break;
        case NL80211_PLINK_HOLDING:
                /* holding timer */
                del_timer(&sta->plink_timer);
                mesh_plink_fsm_restart(sta);
-               spin_unlock_bh(&sta->lock);
                break;
        default:
-               spin_unlock_bh(&sta->lock);
                break;
        }
+       spin_unlock_bh(&sta->lock);
+       if (action)
+               mesh_plink_frame_tx(sdata, action, sta->sta.addr,
+                                   sta->llid, sta->plid, reason);
 }
 
 static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
@@ -612,9 +612,40 @@ static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
        add_timer(&sta->plink_timer);
 }
 
+static bool llid_in_use(struct ieee80211_sub_if_data *sdata,
+                       u16 llid)
+{
+       struct ieee80211_local *local = sdata->local;
+       bool in_use = false;
+       struct sta_info *sta;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sta, &local->sta_list, list) {
+               if (!memcmp(&sta->llid, &llid, sizeof(llid))) {
+                       in_use = true;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+
+       return in_use;
+}
+
+static u16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata)
+{
+       u16 llid;
+
+       do {
+               get_random_bytes(&llid, sizeof(llid));
+               /* for mesh PS we still only have the AID range for TIM bits */
+               llid = (llid % IEEE80211_MAX_AID) + 1;
+       } while (llid_in_use(sdata, llid));
+
+       return llid;
+}
+
 u32 mesh_plink_open(struct sta_info *sta)
 {
-       __le16 llid;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        u32 changed;
 
@@ -622,8 +653,7 @@ u32 mesh_plink_open(struct sta_info *sta)
                return 0;
 
        spin_lock_bh(&sta->lock);
-       get_random_bytes(&llid, 2);
-       sta->llid = llid;
+       sta->llid = mesh_get_new_llid(sdata);
        if (sta->plink_state != NL80211_PLINK_LISTEN &&
            sta->plink_state != NL80211_PLINK_BLOCKED) {
                spin_unlock_bh(&sta->lock);
@@ -640,7 +670,7 @@ u32 mesh_plink_open(struct sta_info *sta)
        changed = ieee80211_mps_local_status_update(sdata);
 
        mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
-                           sta->sta.addr, llid, 0, 0);
+                           sta->sta.addr, sta->llid, 0, 0);
        return changed;
 }
 
@@ -656,390 +686,147 @@ u32 mesh_plink_block(struct sta_info *sta)
        return changed;
 }
 
-
-void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
-                        struct ieee80211_mgmt *mgmt, size_t len,
-                        struct ieee80211_rx_status *rx_status)
+static void mesh_plink_close(struct ieee80211_sub_if_data *sdata,
+                            struct sta_info *sta,
+                            enum plink_event event)
 {
        struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
-       struct ieee802_11_elems elems;
-       struct sta_info *sta;
-       enum plink_event event;
-       enum ieee80211_self_protected_actioncode ftype;
-       size_t baselen;
-       bool matches_local = true;
-       u8 ie_len;
-       u8 *baseaddr;
-       u32 changed = 0;
-       __le16 plid, llid, reason;
-
-       /* need action_code, aux */
-       if (len < IEEE80211_MIN_ACTION_SIZE + 3)
-               return;
-
-       if (sdata->u.mesh.user_mpm)
-               /* userspace must register for these */
-               return;
-
-       if (is_multicast_ether_addr(mgmt->da)) {
-               mpl_dbg(sdata,
-                       "Mesh plink: ignore frame from multicast address\n");
-               return;
-       }
-
-       baseaddr = mgmt->u.action.u.self_prot.variable;
-       baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
-       if (mgmt->u.action.u.self_prot.action_code ==
-                                               WLAN_SP_MESH_PEERING_CONFIRM) {
-               baseaddr += 4;
-               baselen += 4;
-       }
-       ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);
-
-       if (!elems.peering) {
-               mpl_dbg(sdata,
-                       "Mesh plink: missing necessary peer link ie\n");
-               return;
-       }
 
-       if (elems.rsn_len &&
-           sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
-               mpl_dbg(sdata,
-                       "Mesh plink: can't establish link with secure peer\n");
-               return;
-       }
+       u16 reason = (event == CLS_ACPT) ?
+                    WLAN_REASON_MESH_CLOSE : WLAN_REASON_MESH_CONFIG;
 
-       ftype = mgmt->u.action.u.self_prot.action_code;
-       ie_len = elems.peering_len;
-       if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
-           (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
-           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
-                                                       && ie_len != 8)) {
-               mpl_dbg(sdata,
-                       "Mesh plink: incorrect plink ie length %d %d\n",
-                       ftype, ie_len);
-               return;
-       }
-
-       if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
-           (!elems.mesh_id || !elems.mesh_config)) {
-               mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");
-               return;
-       }
-       /* Note the lines below are correct, the llid in the frame is the plid
-        * from the point of view of this host.
-        */
-       memcpy(&plid, PLINK_GET_LLID(elems.peering), 2);
-       if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
-           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
-               memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
-
-       /* WARNING: Only for sta pointer, is dropped & re-acquired */
-       rcu_read_lock();
-
-       sta = sta_info_get(sdata, mgmt->sa);
-       if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) {
-               mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
-               rcu_read_unlock();
-               return;
-       }
-
-       if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
-           !rssi_threshold_check(sta, sdata)) {
-               mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",
-                       mgmt->sa);
-               rcu_read_unlock();
-               return;
-       }
-
-       if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) {
-               mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
-               rcu_read_unlock();
-               return;
-       }
+       sta->reason = reason;
+       sta->plink_state = NL80211_PLINK_HOLDING;
+       mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
+}
 
-       if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) {
-               rcu_read_unlock();
-               return;
-       }
+static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata,
+                               struct sta_info *sta)
+{
+       struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
+       u32 changed = 0;
 
-       /* Now we will figure out the appropriate event... */
-       event = PLINK_UNDEFINED;
-       if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
-           !mesh_matches_local(sdata, &elems)) {
-               matches_local = false;
-               switch (ftype) {
-               case WLAN_SP_MESH_PEERING_OPEN:
-                       event = OPN_RJCT;
-                       break;
-               case WLAN_SP_MESH_PEERING_CONFIRM:
-                       event = CNF_RJCT;
-                       break;
-               default:
-                       break;
-               }
-       }
+       del_timer(&sta->plink_timer);
+       sta->plink_state = NL80211_PLINK_ESTAB;
+       changed |= mesh_plink_inc_estab_count(sdata);
+       changed |= mesh_set_ht_prot_mode(sdata);
+       changed |= mesh_set_short_slot_time(sdata);
+       mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr);
+       ieee80211_mps_sta_status_update(sta);
+       changed |= ieee80211_mps_set_sta_local_pm(sta, mshcfg->power_mode);
+       return changed;
+}
 
-       if (!sta && !matches_local) {
-               rcu_read_unlock();
-               reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
-               llid = 0;
-               mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
-                                   mgmt->sa, llid, plid, reason);
-               return;
-       } else if (!sta) {
-               /* ftype == WLAN_SP_MESH_PEERING_OPEN */
-               if (!mesh_plink_free_count(sdata)) {
-                       mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
-                       rcu_read_unlock();
-                       return;
-               }
-               event = OPN_ACPT;
-       } else if (matches_local) {
-               switch (ftype) {
-               case WLAN_SP_MESH_PEERING_OPEN:
-                       if (!mesh_plink_free_count(sdata) ||
-                           (sta->plid && sta->plid != plid))
-                               event = OPN_IGNR;
-                       else
-                               event = OPN_ACPT;
-                       break;
-               case WLAN_SP_MESH_PEERING_CONFIRM:
-                       if (!mesh_plink_free_count(sdata) ||
-                           (sta->llid != llid || sta->plid != plid))
-                               event = CNF_IGNR;
-                       else
-                               event = CNF_ACPT;
-                       break;
-               case WLAN_SP_MESH_PEERING_CLOSE:
-                       if (sta->plink_state == NL80211_PLINK_ESTAB)
-                               /* Do not check for llid or plid. This does not
-                                * follow the standard but since multiple plinks
-                                * per sta are not supported, it is necessary in
-                                * order to avoid a livelock when MP A sees an
-                                * establish peer link to MP B but MP B does not
-                                * see it. This can be caused by a timeout in
-                                * B's peer link establishment or B beign
-                                * restarted.
-                                */
-                               event = CLS_ACPT;
-                       else if (sta->plid != plid)
-                               event = CLS_IGNR;
-                       else if (ie_len == 7 && sta->llid != llid)
-                               event = CLS_IGNR;
-                       else
-                               event = CLS_ACPT;
-                       break;
-               default:
-                       mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");
-                       rcu_read_unlock();
-                       return;
-               }
-       }
+/**
+ * mesh_plink_fsm - step @sta MPM based on @event
+ *
+ * @sdata: interface
+ * @sta: mesh neighbor
+ * @event: peering event
+ *
+ * Return: changed MBSS flags
+ */
+static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
+                         struct sta_info *sta, enum plink_event event)
+{
+       struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
+       enum ieee80211_self_protected_actioncode action = 0;
+       u32 changed = 0;
 
-       if (event == OPN_ACPT) {
-               rcu_read_unlock();
-               /* allocate sta entry if necessary and update info */
-               sta = mesh_sta_info_get(sdata, mgmt->sa, &elems);
-               if (!sta) {
-                       mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");
-                       rcu_read_unlock();
-                       return;
-               }
-       }
+       mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr,
+               mplstates[sta->plink_state], mplevents[event]);
 
-       mpl_dbg(sdata, "peer %pM in state %s got event %s\n", mgmt->sa,
-                      mplstates[sta->plink_state], mplevents[event]);
-       reason = 0;
        spin_lock_bh(&sta->lock);
        switch (sta->plink_state) {
-               /* spin_unlock as soon as state is updated at each case */
        case NL80211_PLINK_LISTEN:
                switch (event) {
                case CLS_ACPT:
                        mesh_plink_fsm_restart(sta);
-                       spin_unlock_bh(&sta->lock);
                        break;
                case OPN_ACPT:
                        sta->plink_state = NL80211_PLINK_OPN_RCVD;
-                       sta->plid = plid;
-                       get_random_bytes(&llid, 2);
-                       sta->llid = llid;
+                       sta->llid = mesh_get_new_llid(sdata);
                        mesh_plink_timer_set(sta,
                                             mshcfg->dot11MeshRetryTimeout);
 
                        /* set the non-peer mode to active during peering */
                        changed |= ieee80211_mps_local_status_update(sdata);
-
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_OPEN,
-                                           sta->sta.addr, llid, 0, 0);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CONFIRM,
-                                           sta->sta.addr, llid, plid, 0);
+                       action = WLAN_SP_MESH_PEERING_OPEN;
                        break;
                default:
-                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
-
        case NL80211_PLINK_OPN_SNT:
                switch (event) {
                case OPN_RJCT:
                case CNF_RJCT:
-                       reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
                case CLS_ACPT:
-                       if (!reason)
-                               reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
-                       sta->reason = reason;
-                       sta->plink_state = NL80211_PLINK_HOLDING;
-                       if (!mod_plink_timer(sta,
-                                            mshcfg->dot11MeshHoldingTimeout))
-                               sta->ignore_plink_timer = true;
-
-                       llid = sta->llid;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CLOSE,
-                                           sta->sta.addr, llid, plid, reason);
+                       mesh_plink_close(sdata, sta, event);
+                       action = WLAN_SP_MESH_PEERING_CLOSE;
                        break;
                case OPN_ACPT:
                        /* retry timer is left untouched */
                        sta->plink_state = NL80211_PLINK_OPN_RCVD;
-                       sta->plid = plid;
-                       llid = sta->llid;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CONFIRM,
-                                           sta->sta.addr, llid, plid, 0);
+                       action = WLAN_SP_MESH_PEERING_CONFIRM;
                        break;
                case CNF_ACPT:
                        sta->plink_state = NL80211_PLINK_CNF_RCVD;
                        if (!mod_plink_timer(sta,
                                             mshcfg->dot11MeshConfirmTimeout))
                                sta->ignore_plink_timer = true;
-
-                       spin_unlock_bh(&sta->lock);
                        break;
                default:
-                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
-
        case NL80211_PLINK_OPN_RCVD:
                switch (event) {
                case OPN_RJCT:
                case CNF_RJCT:
-                       reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
                case CLS_ACPT:
-                       if (!reason)
-                               reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
-                       sta->reason = reason;
-                       sta->plink_state = NL80211_PLINK_HOLDING;
-                       if (!mod_plink_timer(sta,
-                                            mshcfg->dot11MeshHoldingTimeout))
-                               sta->ignore_plink_timer = true;
-
-                       llid = sta->llid;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
-                                           sta->sta.addr, llid, plid, reason);
+                       mesh_plink_close(sdata, sta, event);
+                       action = WLAN_SP_MESH_PEERING_CLOSE;
                        break;
                case OPN_ACPT:
-                       llid = sta->llid;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CONFIRM,
-                                           sta->sta.addr, llid, plid, 0);
+                       action = WLAN_SP_MESH_PEERING_CONFIRM;
                        break;
                case CNF_ACPT:
-                       del_timer(&sta->plink_timer);
-                       sta->plink_state = NL80211_PLINK_ESTAB;
-                       spin_unlock_bh(&sta->lock);
-                       changed |= mesh_plink_inc_estab_count(sdata);
-                       changed |= mesh_set_ht_prot_mode(sdata);
-                       changed |= mesh_set_short_slot_time(sdata);
-                       mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
-                               sta->sta.addr);
-                       ieee80211_mps_sta_status_update(sta);
-                       changed |= ieee80211_mps_set_sta_local_pm(sta,
-                                                      mshcfg->power_mode);
+                       changed |= mesh_plink_establish(sdata, sta);
                        break;
                default:
-                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
-
        case NL80211_PLINK_CNF_RCVD:
                switch (event) {
                case OPN_RJCT:
                case CNF_RJCT:
-                       reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
                case CLS_ACPT:
-                       if (!reason)
-                               reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
-                       sta->reason = reason;
-                       sta->plink_state = NL80211_PLINK_HOLDING;
-                       if (!mod_plink_timer(sta,
-                                            mshcfg->dot11MeshHoldingTimeout))
-                               sta->ignore_plink_timer = true;
-
-                       llid = sta->llid;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CLOSE,
-                                           sta->sta.addr, llid, plid, reason);
+                       mesh_plink_close(sdata, sta, event);
+                       action = WLAN_SP_MESH_PEERING_CLOSE;
                        break;
                case OPN_ACPT:
-                       del_timer(&sta->plink_timer);
-                       sta->plink_state = NL80211_PLINK_ESTAB;
-                       spin_unlock_bh(&sta->lock);
-                       changed |= mesh_plink_inc_estab_count(sdata);
-                       changed |= mesh_set_ht_prot_mode(sdata);
-                       changed |= mesh_set_short_slot_time(sdata);
-                       mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
-                               sta->sta.addr);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CONFIRM,
-                                           sta->sta.addr, llid, plid, 0);
-                       ieee80211_mps_sta_status_update(sta);
-                       changed |= ieee80211_mps_set_sta_local_pm(sta,
-                                                       mshcfg->power_mode);
+                       changed |= mesh_plink_establish(sdata, sta);
+                       action = WLAN_SP_MESH_PEERING_CONFIRM;
                        break;
                default:
-                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
-
        case NL80211_PLINK_ESTAB:
                switch (event) {
                case CLS_ACPT:
-                       reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
-                       sta->reason = reason;
                        changed |= __mesh_plink_deactivate(sta);
-                       sta->plink_state = NL80211_PLINK_HOLDING;
-                       llid = sta->llid;
-                       mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
-                       spin_unlock_bh(&sta->lock);
                        changed |= mesh_set_ht_prot_mode(sdata);
                        changed |= mesh_set_short_slot_time(sdata);
-                       mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
-                                           sta->sta.addr, llid, plid, reason);
+                       mesh_plink_close(sdata, sta, event);
+                       action = WLAN_SP_MESH_PEERING_CLOSE;
                        break;
                case OPN_ACPT:
-                       llid = sta->llid;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CONFIRM,
-                                           sta->sta.addr, llid, plid, 0);
+                       action = WLAN_SP_MESH_PEERING_CONFIRM;
                        break;
                default:
-                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
@@ -1049,32 +836,271 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
                        if (del_timer(&sta->plink_timer))
                                sta->ignore_plink_timer = 1;
                        mesh_plink_fsm_restart(sta);
-                       spin_unlock_bh(&sta->lock);
                        break;
                case OPN_ACPT:
                case CNF_ACPT:
                case OPN_RJCT:
                case CNF_RJCT:
-                       llid = sta->llid;
-                       reason = sta->reason;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
-                                           sta->sta.addr, llid, plid, reason);
+                       action = WLAN_SP_MESH_PEERING_CLOSE;
                        break;
                default:
-                       spin_unlock_bh(&sta->lock);
+                       break;
                }
                break;
        default:
                /* should not get here, PLINK_BLOCKED is dealt with at the
                 * beginning of the function
                 */
-               spin_unlock_bh(&sta->lock);
                break;
        }
+       spin_unlock_bh(&sta->lock);
+       if (action) {
+               mesh_plink_frame_tx(sdata, action, sta->sta.addr,
+                                   sta->llid, sta->plid, sta->reason);
+
+               /* also send confirm in open case */
+               if (action == WLAN_SP_MESH_PEERING_OPEN) {
+                       mesh_plink_frame_tx(sdata,
+                                           WLAN_SP_MESH_PEERING_CONFIRM,
+                                           sta->sta.addr, sta->llid,
+                                           sta->plid, 0);
+               }
+       }
+
+       return changed;
+}
+
+/*
+ * mesh_plink_get_event - get correct MPM event
+ *
+ * @sdata: interface
+ * @sta: peer, leave NULL if processing a frame from a new suitable peer
+ * @elems: peering management IEs
+ * @ftype: frame type
+ * @llid: peer's peer link ID
+ * @plid: peer's local link ID
+ *
+ * Return: new peering event for @sta, but PLINK_UNDEFINED should be treated as
+ * an error.
+ */
+static enum plink_event
+mesh_plink_get_event(struct ieee80211_sub_if_data *sdata,
+                    struct sta_info *sta,
+                    struct ieee802_11_elems *elems,
+                    enum ieee80211_self_protected_actioncode ftype,
+                    u16 llid, u16 plid)
+{
+       enum plink_event event = PLINK_UNDEFINED;
+       u8 ie_len = elems->peering_len;
+       bool matches_local;
+
+       matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE ||
+                        mesh_matches_local(sdata, elems));
+
+       /* deny open request from non-matching peer */
+       if (!matches_local && !sta) {
+               event = OPN_RJCT;
+               goto out;
+       }
+
+       if (!sta) {
+               if (ftype != WLAN_SP_MESH_PEERING_OPEN) {
+                       mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
+                       goto out;
+               }
+               /* ftype == WLAN_SP_MESH_PEERING_OPEN */
+               if (!mesh_plink_free_count(sdata)) {
+                       mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
+                       goto out;
+               }
+       } else {
+               if (!test_sta_flag(sta, WLAN_STA_AUTH)) {
+                       mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
+                       goto out;
+               }
+               if (sta->plink_state == NL80211_PLINK_BLOCKED)
+                       goto out;
+       }
+
+       /* new matching peer */
+       if (!sta) {
+               event = OPN_ACPT;
+               goto out;
+       }
+
+       switch (ftype) {
+       case WLAN_SP_MESH_PEERING_OPEN:
+               if (!matches_local)
+                       event = OPN_RJCT;
+               if (!mesh_plink_free_count(sdata) ||
+                   (sta->plid && sta->plid != plid))
+                       event = OPN_IGNR;
+               else
+                       event = OPN_ACPT;
+               break;
+       case WLAN_SP_MESH_PEERING_CONFIRM:
+               if (!matches_local)
+                       event = CNF_RJCT;
+               if (!mesh_plink_free_count(sdata) ||
+                   (sta->llid != llid || sta->plid != plid))
+                       event = CNF_IGNR;
+               else
+                       event = CNF_ACPT;
+               break;
+       case WLAN_SP_MESH_PEERING_CLOSE:
+               if (sta->plink_state == NL80211_PLINK_ESTAB)
+                       /* Do not check for llid or plid. This does not
+                        * follow the standard but since multiple plinks
+                        * per sta are not supported, it is necessary in
+                        * order to avoid a livelock when MP A sees an
+                        * establish peer link to MP B but MP B does not
+                        * see it. This can be caused by a timeout in
+                        * B's peer link establishment or B beign
+                        * restarted.
+                        */
+                       event = CLS_ACPT;
+               else if (sta->plid != plid)
+                       event = CLS_IGNR;
+               else if (ie_len == 8 && sta->llid != llid)
+                       event = CLS_IGNR;
+               else
+                       event = CLS_ACPT;
+               break;
+       default:
+               mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");
+               break;
+       }
+
+out:
+       return event;
+}
 
+static void
+mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
+                        struct ieee80211_mgmt *mgmt,
+                        struct ieee802_11_elems *elems)
+{
+
+       struct sta_info *sta;
+       enum plink_event event;
+       enum ieee80211_self_protected_actioncode ftype;
+       u32 changed = 0;
+       u8 ie_len = elems->peering_len;
+       __le16 _plid, _llid;
+       u16 plid, llid = 0;
+
+       if (!elems->peering) {
+               mpl_dbg(sdata,
+                       "Mesh plink: missing necessary peer link ie\n");
+               return;
+       }
+
+       if (elems->rsn_len &&
+           sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
+               mpl_dbg(sdata,
+                       "Mesh plink: can't establish link with secure peer\n");
+               return;
+       }
+
+       ftype = mgmt->u.action.u.self_prot.action_code;
+       if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
+           (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
+           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
+                                                       && ie_len != 8)) {
+               mpl_dbg(sdata,
+                       "Mesh plink: incorrect plink ie length %d %d\n",
+                       ftype, ie_len);
+               return;
+       }
+
+       if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
+           (!elems->mesh_id || !elems->mesh_config)) {
+               mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");
+               return;
+       }
+       /* Note the lines below are correct, the llid in the frame is the plid
+        * from the point of view of this host.
+        */
+       memcpy(&_plid, PLINK_GET_LLID(elems->peering), sizeof(__le16));
+       plid = le16_to_cpu(_plid);
+       if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
+           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) {
+               memcpy(&_llid, PLINK_GET_PLID(elems->peering), sizeof(__le16));
+               llid = le16_to_cpu(_llid);
+       }
+
+       /* WARNING: Only for sta pointer, is dropped & re-acquired */
+       rcu_read_lock();
+
+       sta = sta_info_get(sdata, mgmt->sa);
+
+       if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
+           !rssi_threshold_check(sdata, sta)) {
+               mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",
+                       mgmt->sa);
+               goto unlock_rcu;
+       }
+
+       /* Now we will figure out the appropriate event... */
+       event = mesh_plink_get_event(sdata, sta, elems, ftype, llid, plid);
+
+       if (event == OPN_ACPT) {
+               rcu_read_unlock();
+               /* allocate sta entry if necessary and update info */
+               sta = mesh_sta_info_get(sdata, mgmt->sa, elems);
+               if (!sta) {
+                       mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");
+                       goto unlock_rcu;
+               }
+               sta->plid = plid;
+       } else if (!sta && event == OPN_RJCT) {
+               mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+                                   mgmt->sa, 0, plid,
+                                   WLAN_REASON_MESH_CONFIG);
+               goto unlock_rcu;
+       } else if (!sta || event == PLINK_UNDEFINED) {
+               /* something went wrong */
+               goto unlock_rcu;
+       }
+
+       changed |= mesh_plink_fsm(sdata, sta, event);
+
+unlock_rcu:
        rcu_read_unlock();
 
        if (changed)
                ieee80211_mbss_info_change_notify(sdata, changed);
 }
+
+void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
+                        struct ieee80211_mgmt *mgmt, size_t len,
+                        struct ieee80211_rx_status *rx_status)
+{
+       struct ieee802_11_elems elems;
+       size_t baselen;
+       u8 *baseaddr;
+
+       /* need action_code, aux */
+       if (len < IEEE80211_MIN_ACTION_SIZE + 3)
+               return;
+
+       if (sdata->u.mesh.user_mpm)
+               /* userspace must register for these */
+               return;
+
+       if (is_multicast_ether_addr(mgmt->da)) {
+               mpl_dbg(sdata,
+                       "Mesh plink: ignore frame from multicast address\n");
+               return;
+       }
+
+       baseaddr = mgmt->u.action.u.self_prot.variable;
+       baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
+       if (mgmt->u.action.u.self_prot.action_code ==
+                                               WLAN_SP_MESH_PEERING_CONFIRM) {
+               baseaddr += 4;
+               baselen += 4;
+       }
+       ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);
+       mesh_process_plink_frame(sdata, mgmt, &elems);
+}
index 0f79b78b5e86b45a6d7059de497b68b44944da09..2802f9d9279de1527927a88bc731489cc22613c7 100644 (file)
@@ -576,10 +576,9 @@ void ieee80211_mps_frame_release(struct sta_info *sta,
        int ac, buffer_local = 0;
        bool has_buffered = false;
 
-       /* TIM map only for LLID <= IEEE80211_MAX_AID */
        if (sta->plink_state == NL80211_PLINK_ESTAB)
                has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len,
-                               le16_to_cpu(sta->llid) % IEEE80211_MAX_AID);
+                                                  sta->llid);
 
        if (has_buffered)
                mps_dbg(sta->sdata, "%pM indicates buffered frames\n",
index 05a256b38e245b64b26a4adb11023898bcd115e1..d1cf2d5534998957c13cfbd5ca23c630d7c9f6a7 100644 (file)
@@ -92,12 +92,20 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
        if (stype != IEEE80211_STYPE_BEACON)
                return;
 
-       /* The current tsf is a first approximation for the timestamp
-        * for the received beacon.  Further down we try to get a
-        * better value from the rx_status->mactime field if
-        * available. Also we have to call drv_get_tsf() before
-        * entering the rcu-read section.*/
-       t_r = drv_get_tsf(local, sdata);
+       /*
+        * Get time when timestamp field was received.  If we don't
+        * have rx timestamps, then use current tsf as an approximation.
+        * drv_get_tsf() must be called before entering the rcu-read
+        * section.
+        */
+       if (ieee80211_have_rx_timestamp(rx_status))
+               t_r = ieee80211_calculate_rx_timestamp(local, rx_status,
+                                                      24 + 12 +
+                                                      elems->total_len +
+                                                      FCS_LEN,
+                                                      24);
+       else
+               t_r = drv_get_tsf(local, sdata);
 
        rcu_read_lock();
        sta = sta_info_get(sdata, mgmt->sa);
@@ -117,14 +125,6 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
                goto no_sync;
        }
 
-       if (ieee80211_have_rx_timestamp(rx_status))
-               /* time when timestamp field was received */
-               t_r = ieee80211_calculate_rx_timestamp(local, rx_status,
-                                                      24 + 12 +
-                                                      elems->total_len +
-                                                      FCS_LEN,
-                                                      24);
-
        /* Timing offset calculation (see 13.13.2.2.2) */
        t_t = le64_to_cpu(mgmt->u.beacon.timestamp);
        sta->t_offset = t_t - t_r;
index b3a3ce316656ce8406859a3cdc325fa262e024a5..900ead344f5bd526fa5f9a54b438a8cae52012e6 100644 (file)
@@ -330,6 +330,16 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
        if (WARN_ON_ONCE(!sta))
                return -EINVAL;
 
+       /*
+        * if bss configuration changed store the new one -
+        * this may be applicable even if channel is identical
+        */
+       ht_opmode = le16_to_cpu(ht_oper->operation_mode);
+       if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
+               *changed |= BSS_CHANGED_HT;
+               sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
+       }
+
        chan = sdata->vif.bss_conf.chandef.chan;
        sband = local->hw.wiphy->bands[chan->band];
 
@@ -416,14 +426,6 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
                                         IEEE80211_RC_BW_CHANGED);
        }
 
-       ht_opmode = le16_to_cpu(ht_oper->operation_mode);
-
-       /* if bss configuration changed store the new one */
-       if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
-               *changed |= BSS_CHANGED_HT;
-               sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
-       }
-
        return 0;
 }
 
@@ -714,7 +716,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        }
 
        /* if present, add any custom IEs that go before HT */
-       if (assoc_data->ie_len && assoc_data->ie) {
+       if (assoc_data->ie_len) {
                static const u8 before_ht[] = {
                        WLAN_EID_SSID,
                        WLAN_EID_SUPP_RATES,
@@ -748,7 +750,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                                     &assoc_data->ap_vht_cap);
 
        /* if present, add any custom non-vendor IEs that go after HT */
-       if (assoc_data->ie_len && assoc_data->ie) {
+       if (assoc_data->ie_len) {
                noffset = ieee80211_ie_split_vendor(assoc_data->ie,
                                                    assoc_data->ie_len,
                                                    offset);
@@ -779,7 +781,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        }
 
        /* add any remaining custom (i.e. vendor specific here) IEs */
-       if (assoc_data->ie_len && assoc_data->ie) {
+       if (assoc_data->ie_len) {
                noffset = assoc_data->ie_len;
                pos = skb_put(skb, noffset - offset);
                memcpy(pos, assoc_data->ie + offset, noffset - offset);
@@ -886,8 +888,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        if (!ifmgd->associated)
                goto out;
 
-       ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
-                                          &changed);
+       ret = ieee80211_vif_change_channel(sdata, &changed);
        if (ret) {
                sdata_info(sdata,
                           "vif channel switch failed, disconnecting\n");
@@ -897,7 +898,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        }
 
        if (!local->use_chanctx) {
-               local->_oper_chandef = local->csa_chandef;
+               local->_oper_chandef = sdata->csa_chandef;
                /* Call "hw_config" only if doing sw channel switch.
                 * Otherwise update the channel directly
                 */
@@ -908,7 +909,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        }
 
        /* XXX: shouldn't really modify cfg80211-owned data! */
-       ifmgd->associated->channel = local->csa_chandef.chan;
+       ifmgd->associated->channel = sdata->csa_chandef.chan;
 
        /* XXX: wait for a beacon first? */
        ieee80211_wake_queues_by_reason(&local->hw,
@@ -1035,7 +1036,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        }
        mutex_unlock(&local->chanctx_mtx);
 
-       local->csa_chandef = csa_ie.chandef;
+       sdata->csa_chandef = csa_ie.chandef;
 
        if (csa_ie.mode)
                ieee80211_stop_queues_by_reason(&local->hw,
@@ -1398,10 +1399,12 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work)
        struct ieee80211_sub_if_data *sdata =
                container_of(delayed_work, struct ieee80211_sub_if_data,
                             dfs_cac_timer_work);
+       struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef;
 
        ieee80211_vif_release_channel(sdata);
-
-       cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
+       cfg80211_cac_event(sdata->dev, &chandef,
+                          NL80211_RADAR_CAC_FINISHED,
+                          GFP_KERNEL);
 }
 
 /* MLME */
@@ -1745,6 +1748,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        ifmgd->flags = 0;
        ieee80211_vif_release_channel(sdata);
+
+       sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
 }
 
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@@ -4191,6 +4196,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 
        sdata->control_port_protocol = req->crypto.control_port_ethertype;
        sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
+       sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto,
+                                                       sdata->vif.type);
 
        /* kick off associate process */
 
index 505bc0dea074809f1532f322528e222a5052c061..b95e16c070813da22169679e8c5c1aa7e3ee0f1d 100644 (file)
@@ -54,6 +54,8 @@ static inline void rate_control_rate_init(struct sta_info *sta)
        struct ieee80211_supported_band *sband;
        struct ieee80211_chanctx_conf *chanctx_conf;
 
+       ieee80211_sta_set_rx_nss(sta);
+
        if (!ref)
                return;
 
@@ -67,8 +69,6 @@ static inline void rate_control_rate_init(struct sta_info *sta)
 
        sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
 
-       ieee80211_sta_set_rx_nss(sta);
-
        ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista,
                            priv_sta);
        rcu_read_unlock();
index 7fa1b36e620247ed5c14e97d54b2d72d7a0b43cb..d2f19f7e7091b6e6b9111702f19b02f612fdb52c 100644 (file)
@@ -422,10 +422,9 @@ init_sample_table(struct minstrel_sta_info *mi)
        memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates);
 
        for (col = 0; col < SAMPLE_COLUMNS; col++) {
+               prandom_bytes(rnd, sizeof(rnd));
                for (i = 0; i < mi->n_rates; i++) {
-                       get_random_bytes(rnd, sizeof(rnd));
                        new_idx = (i + rnd[i & 7]) % mi->n_rates;
-
                        while (SAMPLE_TBL(mi, new_idx, col) != 0xff)
                                new_idx = (new_idx + 1) % mi->n_rates;
 
index 4096ff6cc24fe8a5c3505411c5b232e0d800e050..d2ed18d82fe1dd1f55a2f5c13f319920bbb9b887 100644 (file)
@@ -135,7 +135,7 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi);
 static int
 minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
 {
-       return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1,
+       return GROUP_IDX((rate->idx / 8) + 1,
                         !!(rate->flags & IEEE80211_TX_RC_SHORT_GI),
                         !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
 }
@@ -148,7 +148,7 @@ minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
 
        if (rate->flags & IEEE80211_TX_RC_MCS) {
                group = minstrel_ht_get_group_idx(rate);
-               idx = rate->idx % MCS_GROUP_RATES;
+               idx = rate->idx % 8;
        } else {
                group = MINSTREL_CCK_GROUP;
 
@@ -637,8 +637,7 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
                idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)];
                flags = 0;
        } else {
-               idx = index % MCS_GROUP_RATES +
-                     (group->streams - 1) * MCS_GROUP_RATES;
+               idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8;
                flags = IEEE80211_TX_RC_MCS | group->flags;
        }
 
@@ -702,12 +701,16 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
        if (!mi->sample_tries)
                return -1;
 
-       mg = &mi->groups[mi->sample_group];
+       sample_group = mi->sample_group;
+       mg = &mi->groups[sample_group];
        sample_idx = sample_table[mg->column][mg->index];
+       minstrel_next_sample_idx(mi);
+
+       if (!(mg->supported & BIT(sample_idx)))
+               return -1;
+
        mr = &mg->rates[sample_idx];
-       sample_group = mi->sample_group;
        sample_idx += sample_group * MCS_GROUP_RATES;
-       minstrel_next_sample_idx(mi);
 
        /*
         * Sampling might add some overhead (RTS, no aggregation)
@@ -818,7 +821,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        }
 
        rate->idx = sample_idx % MCS_GROUP_RATES +
-                   (sample_group->streams - 1) * MCS_GROUP_RATES;
+                   (sample_group->streams - 1) * 8;
        rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags;
 }
 
@@ -1053,10 +1056,9 @@ init_sample_table(void)
 
        memset(sample_table, 0xff, sizeof(sample_table));
        for (col = 0; col < SAMPLE_COLUMNS; col++) {
+               prandom_bytes(rnd, sizeof(rnd));
                for (i = 0; i < MCS_GROUP_RATES; i++) {
-                       get_random_bytes(rnd, sizeof(rnd));
                        new_idx = (i + rnd[i]) % MCS_GROUP_RATES;
-
                        while (sample_table[col][new_idx] != 0xff)
                                new_idx = (new_idx + 1) % MCS_GROUP_RATES;
 
index df44a5ad827049f251dd255f47e5c06262f1eb77..3e7d793de0c3407180965bb785485fd361700560 100644 (file)
@@ -54,8 +54,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
                        int r = bitrates[j % 4];
                        p += sprintf(p, " %2u.%1uM", r / 10, r % 10);
                } else {
-                       p += sprintf(p, " MCS%-2u", (mg->streams - 1) *
-                                        MCS_GROUP_RATES + j);
+                       p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j);
                }
 
                tp = mr->cur_tp / 10;
index 2b0debb0422b91d89a0a7982b94726f3b9ceae11..2dfa755227339533d2c105313ba8ab4ea3ba67b5 100644 (file)
@@ -638,6 +638,27 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
        return le16_to_cpu(mmie->key_id);
 }
 
+static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs,
+                                struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       __le16 fc;
+       int hdrlen;
+       u8 keyid;
+
+       fc = hdr->frame_control;
+       hdrlen = ieee80211_hdrlen(fc);
+
+       if (skb->len < hdrlen + cs->hdr_len)
+               return -EINVAL;
+
+       skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1);
+       keyid &= cs->key_idx_mask;
+       keyid >>= cs->key_idx_shift;
+
+       return keyid;
+}
+
 static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
@@ -729,9 +750,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata
        lockdep_assert_held(&tid_agg_rx->reorder_lock);
 
        while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) {
-               index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
-                                        tid_agg_rx->ssn) %
-                                                       tid_agg_rx->buf_size;
+               index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
                ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
                                                frames);
        }
@@ -757,8 +776,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
        lockdep_assert_held(&tid_agg_rx->reorder_lock);
 
        /* release the buffer until next missing frame */
-       index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
-                                tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+       index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
        if (!tid_agg_rx->reorder_buf[index] &&
            tid_agg_rx->stored_mpdu_num) {
                /*
@@ -793,15 +811,11 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
        } else while (tid_agg_rx->reorder_buf[index]) {
                ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
                                                frames);
-               index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
-                                        tid_agg_rx->ssn) %
-                                                       tid_agg_rx->buf_size;
+               index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
        }
 
        if (tid_agg_rx->stored_mpdu_num) {
-               j = index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
-                                            tid_agg_rx->ssn) %
-                                                       tid_agg_rx->buf_size;
+               j = index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
 
                for (; j != (index - 1) % tid_agg_rx->buf_size;
                     j = (j + 1) % tid_agg_rx->buf_size) {
@@ -861,8 +875,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
 
        /* Now the new frame is always in the range of the reordering buffer */
 
-       index = ieee80211_sn_sub(mpdu_seq_num,
-                                tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+       index = mpdu_seq_num % tid_agg_rx->buf_size;
 
        /* check if we already stored this frame */
        if (tid_agg_rx->reorder_buf[index]) {
@@ -1369,6 +1382,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        struct ieee80211_key *sta_ptk = NULL;
        int mmie_keyidx = -1;
        __le16 fc;
+       const struct ieee80211_cipher_scheme *cs = NULL;
 
        /*
         * Key selection 101
@@ -1406,11 +1420,19 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 
        /* start without a key */
        rx->key = NULL;
+       fc = hdr->frame_control;
 
-       if (rx->sta)
-               sta_ptk = rcu_dereference(rx->sta->ptk);
+       if (rx->sta) {
+               int keyid = rx->sta->ptk_idx;
 
-       fc = hdr->frame_control;
+               if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) {
+                       cs = rx->sta->cipher_scheme;
+                       keyid = iwl80211_get_cs_keyid(cs, rx->skb);
+                       if (unlikely(keyid < 0))
+                               return RX_DROP_UNUSABLE;
+               }
+               sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
+       }
 
        if (!ieee80211_has_protected(fc))
                mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
@@ -1472,6 +1494,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                return RX_CONTINUE;
        } else {
                u8 keyid;
+
                /*
                 * The device doesn't give us the IV so we won't be
                 * able to look up the key. That's ok though, we
@@ -1487,15 +1510,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 
                hdrlen = ieee80211_hdrlen(fc);
 
-               if (rx->skb->len < 8 + hdrlen)
-                       return RX_DROP_UNUSABLE; /* TODO: count this? */
+               if (cs) {
+                       keyidx = iwl80211_get_cs_keyid(cs, rx->skb);
 
-               /*
-                * no need to call ieee80211_wep_get_keyidx,
-                * it verifies a bunch of things we've done already
-                */
-               skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
-               keyidx = keyid >> 6;
+                       if (unlikely(keyidx < 0))
+                               return RX_DROP_UNUSABLE;
+               } else {
+                       if (rx->skb->len < 8 + hdrlen)
+                               return RX_DROP_UNUSABLE; /* TODO: count this? */
+                       /*
+                        * no need to call ieee80211_wep_get_keyidx,
+                        * it verifies a bunch of things we've done already
+                        */
+                       skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
+                       keyidx = keyid >> 6;
+               }
 
                /* check per-station GTK first, if multicast packet */
                if (is_multicast_ether_addr(hdr->addr1) && rx->sta)
@@ -1543,11 +1572,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                result = ieee80211_crypto_aes_cmac_decrypt(rx);
                break;
        default:
-               /*
-                * We can reach here only with HW-only algorithms
-                * but why didn't it decrypt the frame?!
-                */
-               return RX_DROP_UNUSABLE;
+               result = ieee80211_crypto_hw_decrypt(rx);
        }
 
        /* the hdr variable is invalid after the decrypt handlers */
@@ -2057,7 +2082,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-       __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
        u16 q, hdrlen;
 
        hdr = (struct ieee80211_hdr *) skb->data;
@@ -2165,7 +2189,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        } else {
                /* unable to resolve next hop */
                mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
-                                  fwd_hdr->addr3, 0, reason, fwd_hdr->addr2);
+                                  fwd_hdr->addr3, 0,
+                                  WLAN_REASON_MESH_PATH_NOFORWARD,
+                                  fwd_hdr->addr2);
                IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
                kfree_skb(fwd_skb);
                return RX_DROP_MONITOR;
index bcc4833d7542b91e1b754ed490d1dedcaee559c1..4d73c46df86262a385ad5fb9a5912c6a8168831e 100644 (file)
@@ -526,7 +526,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
                ieee80211_hw_config(local, 0);
 
                if ((req->channels[0]->flags &
-                    IEEE80211_CHAN_PASSIVE_SCAN) ||
+                    IEEE80211_CHAN_NO_IR) ||
                    !local->scan_req->n_ssids) {
                        next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
                } else {
@@ -572,7 +572,7 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
         * TODO: channel switching also consumes quite some time,
         * add that delay as well to get a better estimation
         */
-       if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+       if (chan->flags & IEEE80211_CHAN_NO_IR)
                return IEEE80211_PASSIVE_CHANNEL_TIME;
        return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
 }
@@ -696,7 +696,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
         *
         * In any case, it is not necessary for a passive scan.
         */
-       if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
+       if (chan->flags & IEEE80211_CHAN_NO_IR ||
            !local->scan_req->n_ssids) {
                *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
                local->next_scan_state = SCAN_DECISION;
@@ -881,7 +881,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
                                struct ieee80211_channel *tmp_ch =
                                    &local->hw.wiphy->bands[band]->channels[i];
 
-                               if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS |
+                               if (tmp_ch->flags & (IEEE80211_CHAN_NO_IR |
                                                     IEEE80211_CHAN_DISABLED))
                                        continue;
 
@@ -895,7 +895,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
 
                local->int_scan_req->n_channels = n_ch;
        } else {
-               if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS |
+               if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IR |
                                                IEEE80211_CHAN_DISABLED)))
                        goto unlock;
 
index 1eb66e26e49d0a02869ec5e5ff4789583e9760d1..8ed97f76c3cfade5f0986fa2d17c8275753b3c35 100644 (file)
@@ -266,9 +266,17 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
  */
 void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
 {
+       int i;
+
        if (sta->rate_ctrl)
                rate_control_free_sta(sta);
 
+       if (sta->tx_lat) {
+               for (i = 0; i < IEEE80211_NUM_TIDS; i++)
+                       kfree(sta->tx_lat[i].bins);
+               kfree(sta->tx_lat);
+       }
+
        sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
 
        kfree(sta);
@@ -333,6 +341,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
        struct timespec uptime;
+       struct ieee80211_tx_latency_bin_ranges *tx_latency;
        int i;
 
        sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
@@ -410,6 +419,31 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                }
        }
 
+       rcu_read_lock();
+
+       tx_latency = rcu_dereference(local->tx_latency);
+       /* init stations Tx latency statistics && TID bins */
+       if (tx_latency)
+               sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS *
+                                     sizeof(struct ieee80211_tx_latency_stat),
+                                     GFP_ATOMIC);
+
+       /*
+        * if Tx latency and bins are enabled and the previous allocation
+        * succeeded
+        */
+       if (tx_latency && tx_latency->n_ranges && sta->tx_lat)
+               for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+                       /* size of bins is size of the ranges +1 */
+                       sta->tx_lat[i].bin_count =
+                               tx_latency->n_ranges + 1;
+                       sta->tx_lat[i].bins  = kcalloc(sta->tx_lat[i].bin_count,
+                                                      sizeof(u32),
+                                                      GFP_ATOMIC);
+               }
+
+       rcu_read_unlock();
+
        sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
 
        return sta;
@@ -507,6 +541,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
 
        set_sta_flag(sta, WLAN_STA_INSERTED);
 
+       ieee80211_recalc_min_chandef(sdata);
        ieee80211_sta_debugfs_add(sta);
        rate_control_add_sta_debugfs(sta);
 
@@ -630,8 +665,8 @@ void sta_info_recalc_tim(struct sta_info *sta)
 #ifdef CONFIG_MAC80211_MESH
        } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) {
                ps = &sta->sdata->u.mesh.ps;
-               /* TIM map only for PLID <= IEEE80211_MAX_AID */
-               id = le16_to_cpu(sta->plid) % IEEE80211_MAX_AID;
+               /* TIM map only for 1 <= PLID <= IEEE80211_MAX_AID */
+               id = sta->plid % (IEEE80211_MAX_AID + 1);
 #endif
        } else {
                return;
@@ -869,6 +904,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
 
        rate_control_remove_sta_debugfs(sta);
        ieee80211_sta_debugfs_remove(sta);
+       ieee80211_recalc_min_chandef(sdata);
 
        call_rcu(&sta->rcu_head, free_sta_rcu);
 
index 3ef06a26b9cb9feaddfd3d752dd9bd8ac971a11c..0218caf5c14a793ef14045da6c0db6a13781b259 100644 (file)
@@ -220,6 +220,25 @@ struct sta_ampdu_mlme {
        u8 dialog_token_allocator;
 };
 
+/*
+ * struct ieee80211_tx_latency_stat - Tx latency statistics
+ *
+ * Measures TX latency and jitter for a station per TID.
+ *
+ * @max: worst case latency
+ * @sum: sum of all latencies
+ * @counter: amount of Tx frames sent from interface
+ * @bins: each bin counts how many frames transmitted within a certain
+ * latency range. when disabled it is NULL.
+ * @bin_count: amount of bins.
+ */
+struct ieee80211_tx_latency_stat {
+       u32 max;
+       u32 sum;
+       u32 counter;
+       u32 *bins;
+       u32 bin_count;
+};
 
 /**
  * struct sta_info - STA information
@@ -231,8 +250,10 @@ struct sta_ampdu_mlme {
  * @hnext: hash table linked list pointer
  * @local: pointer to the global information
  * @sdata: virtual interface this station belongs to
- * @ptk: peer key negotiated with this station, if any
+ * @ptk: peer keys negotiated with this station, if any
+ * @ptk_idx: last installed peer key index
  * @gtk: group keys negotiated with this station, if any
+ * @gtk_idx: last installed group key index
  * @rate_ctrl: rate control algorithm reference
  * @rate_ctrl_priv: rate control private per-STA pointer
  * @last_tx_rate: rate used for last transmit, to report to userspace as
@@ -274,6 +295,7 @@ struct sta_ampdu_mlme {
  * @tid_seq: per-TID sequence numbers for sending to this STA
  * @ampdu_mlme: A-MPDU state machine state
  * @timer_to_tid: identity mapping to ID timers
+ * @tx_lat: Tx latency statistics
  * @llid: Local link ID
  * @plid: Peer link ID
  * @reason: Cancel reason on PLINK_HOLDING state
@@ -303,6 +325,7 @@ struct sta_ampdu_mlme {
  * @chain_signal_avg: signal average (per chain)
  * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for
  *     AP only.
+ * @cipher_scheme: optional cipher scheme for this station
  */
 struct sta_info {
        /* General information, mostly static */
@@ -312,7 +335,9 @@ struct sta_info {
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
-       struct ieee80211_key __rcu *ptk;
+       struct ieee80211_key __rcu *ptk[NUM_DEFAULT_KEYS];
+       u8 gtk_idx;
+       u8 ptk_idx;
        struct rate_control_ref *rate_ctrl;
        void *rate_ctrl_priv;
        spinlock_t lock;
@@ -380,14 +405,16 @@ struct sta_info {
        struct sta_ampdu_mlme ampdu_mlme;
        u8 timer_to_tid[IEEE80211_NUM_TIDS];
 
+       struct ieee80211_tx_latency_stat *tx_lat;
+
 #ifdef CONFIG_MAC80211_MESH
        /*
         * Mesh peer link attributes
         * TODO: move to a sub-structure that is referenced with pointer?
         */
-       __le16 llid;
-       __le16 plid;
-       __le16 reason;
+       u16 llid;
+       u16 plid;
+       u16 reason;
        u8 plink_retries;
        bool ignore_plink_timer;
        enum nl80211_plink_state plink_state;
@@ -414,6 +441,7 @@ struct sta_info {
        unsigned int beacon_loss_count;
 
        enum ieee80211_smps_mode known_smps_mode;
+       const struct ieee80211_cipher_scheme *cipher_scheme;
 
        /* keep last! */
        struct ieee80211_sta sta;
index 52a152b01b063b226fb5a523b19a4e9863eeffaf..1ee85c402439bfc886029f9ae6dfe6ec306e013f 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/export.h>
 #include <linux/etherdevice.h>
+#include <linux/time.h>
 #include <net/mac80211.h>
 #include <asm/unaligned.h>
 #include "ieee80211_i.h"
@@ -462,6 +463,77 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
        }
 }
 
+/*
+ * Measure Tx frame completion and removal time for Tx latency statistics
+ * calculation. A single Tx frame latency should be measured from when it
+ * is entering the Kernel until we receive Tx complete confirmation indication
+ * and remove the skb.
+ */
+static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local,
+                                           struct sk_buff *skb,
+                                           struct sta_info *sta,
+                                           struct ieee80211_hdr *hdr)
+{
+       ktime_t skb_dprt;
+       struct timespec dprt_time;
+       u32 msrmnt;
+       u16 tid;
+       u8 *qc;
+       int i, bin_range_count, bin_count;
+       u32 *bin_ranges;
+       __le16 fc;
+       struct ieee80211_tx_latency_stat *tx_lat;
+       struct ieee80211_tx_latency_bin_ranges *tx_latency;
+       ktime_t skb_arv = skb->tstamp;
+
+       tx_latency = rcu_dereference(local->tx_latency);
+
+       /* assert Tx latency stats are enabled & frame arrived when enabled */
+       if (!tx_latency || !ktime_to_ns(skb_arv))
+               return;
+
+       fc = hdr->frame_control;
+
+       if (!ieee80211_is_data(fc)) /* make sure it is a data frame */
+               return;
+
+       /* get frame tid */
+       if (ieee80211_is_data_qos(hdr->frame_control)) {
+               qc = ieee80211_get_qos_ctl(hdr);
+               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+       } else {
+               tid = 0;
+       }
+
+       tx_lat = &sta->tx_lat[tid];
+
+       ktime_get_ts(&dprt_time); /* time stamp completion time */
+       skb_dprt = ktime_set(dprt_time.tv_sec, dprt_time.tv_nsec);
+       msrmnt = ktime_to_ms(ktime_sub(skb_dprt, skb_arv));
+
+       if (tx_lat->max < msrmnt) /* update stats */
+               tx_lat->max = msrmnt;
+       tx_lat->counter++;
+       tx_lat->sum += msrmnt;
+
+       if (!tx_lat->bins) /* bins not activated */
+               return;
+
+       /* count how many Tx frames transmitted with the appropriate latency */
+       bin_range_count = tx_latency->n_ranges;
+       bin_ranges = tx_latency->ranges;
+       bin_count = tx_lat->bin_count;
+
+       for (i = 0; i < bin_range_count; i++) {
+               if (msrmnt <= bin_ranges[i]) {
+                       tx_lat->bins[i]++;
+                       break;
+               }
+       }
+       if (i == bin_range_count) /* msrmnt is bigger than the biggest range */
+               tx_lat->bins[i]++;
+}
+
 /*
  * Use a static threshold for now, best value to be determined
  * by testing ...
@@ -620,6 +692,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
                if (acked)
                        sta->last_ack_signal = info->status.ack_signal;
+
+               /*
+                * Measure frame removal for tx latency
+                * statistics calculation
+                */
+               ieee80211_tx_latency_end_msrmnt(local, skb, sta, hdr);
        }
 
        rcu_read_unlock();
index d4cee98533fdc5a532a8ba74e48d6158faeb5003..e9ccf22f6dd972c8b0517c5d35a345085eb45ec6 100644 (file)
 #define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width,                     \
                        __entry->center_freq1, __entry->center_freq2
 
+#define MIN_CHANDEF_ENTRY                                                              \
+                       __field(u32, min_control_freq)                                  \
+                       __field(u32, min_chan_width)                                    \
+                       __field(u32, min_center_freq1)                                  \
+                       __field(u32, min_center_freq2)
+
+#define MIN_CHANDEF_ASSIGN(c)                                                          \
+                       __entry->min_control_freq = (c)->chan ? (c)->chan->center_freq : 0;     \
+                       __entry->min_chan_width = (c)->width;                           \
+                       __entry->min_center_freq1 = (c)->center_freq1;                  \
+                       __entry->min_center_freq2 = (c)->center_freq2;
+#define MIN_CHANDEF_PR_FMT     " min_control:%d MHz min_width:%d min_center: %d/%d MHz"
+#define MIN_CHANDEF_PR_ARG     __entry->min_control_freq, __entry->min_chan_width,     \
+                       __entry->min_center_freq1, __entry->min_center_freq2
+
 #define CHANCTX_ENTRY  CHANDEF_ENTRY                                                   \
+                       MIN_CHANDEF_ENTRY                                               \
                        __field(u8, rx_chains_static)                                   \
                        __field(u8, rx_chains_dynamic)
 #define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def)                                  \
+                       MIN_CHANDEF_ASSIGN(&ctx->conf.min_def)                          \
                        __entry->rx_chains_static = ctx->conf.rx_chains_static;         \
                        __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic
-#define CHANCTX_PR_FMT CHANDEF_PR_FMT " chains:%d/%d"
-#define CHANCTX_PR_ARG CHANDEF_PR_ARG,                                                 \
+#define CHANCTX_PR_FMT CHANDEF_PR_FMT MIN_CHANDEF_PR_FMT " chains:%d/%d"
+#define CHANCTX_PR_ARG CHANDEF_PR_ARG, MIN_CHANDEF_PR_ARG,                             \
                        __entry->rx_chains_static, __entry->rx_chains_dynamic
 
 
index c558b246ef0036c38e6c8a00b338b43c46913f78..6d59e21cdb9fe8b686fdcef53ddc83a83738d0cf 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/bitmap.h>
 #include <linux/rcupdate.h>
 #include <linux/export.h>
+#include <linux/time.h>
 #include <net/net_namespace.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
@@ -557,7 +558,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
 
        if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
                tx->key = NULL;
-       else if (tx->sta && (key = rcu_dereference(tx->sta->ptk)))
+       else if (tx->sta &&
+                (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx])))
                tx->key = key;
        else if (ieee80211_is_mgmt(hdr->frame_control) &&
                 is_multicast_ether_addr(hdr->addr1) &&
@@ -840,15 +842,16 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx,
                rem -= fraglen;
                tmp = dev_alloc_skb(local->tx_headroom +
                                    frag_threshold +
-                                   IEEE80211_ENCRYPT_HEADROOM +
+                                   tx->sdata->encrypt_headroom +
                                    IEEE80211_ENCRYPT_TAILROOM);
                if (!tmp)
                        return -ENOMEM;
 
                __skb_queue_tail(&tx->skbs, tmp);
 
-               skb_reserve(tmp, local->tx_headroom +
-                                IEEE80211_ENCRYPT_HEADROOM);
+               skb_reserve(tmp,
+                           local->tx_headroom + tx->sdata->encrypt_headroom);
+
                /* copy control information */
                memcpy(tmp->cb, skb->cb, sizeof(tmp->cb));
 
@@ -1485,7 +1488,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
 
        headroom = local->tx_headroom;
        if (may_encrypt)
-               headroom += IEEE80211_ENCRYPT_HEADROOM;
+               headroom += sdata->encrypt_headroom;
        headroom -= skb_headroom(skb);
        headroom = max_t(int, 0, headroom);
 
@@ -1724,8 +1727,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
         * radar detection by itself. We can do that later by adding a
         * monitor flag interfaces used for AP support.
         */
-       if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
-                           IEEE80211_CHAN_PASSIVE_SCAN)))
+       if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)))
                goto fail_rcu;
 
        ieee80211_xmit(sdata, skb, chan->band);
@@ -1740,6 +1742,26 @@ fail:
        return NETDEV_TX_OK; /* meaning, we dealt with the skb */
 }
 
+/*
+ * Measure Tx frame arrival time for Tx latency statistics calculation
+ * A single Tx frame latency should be measured from when it is entering the
+ * Kernel until we receive Tx complete confirmation indication and the skb is
+ * freed.
+ */
+static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local,
+                                             struct sk_buff *skb)
+{
+       struct timespec skb_arv;
+       struct ieee80211_tx_latency_bin_ranges *tx_latency;
+
+       tx_latency = rcu_dereference(local->tx_latency);
+       if (!tx_latency)
+               return;
+
+       ktime_get_ts(&skb_arv);
+       skb->tstamp = ktime_set(skb_arv.tv_sec, skb_arv.tv_nsec);
+}
+
 /**
  * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type
  * subinterfaces (wlan#, WDS, and VLAN interfaces)
@@ -1790,6 +1812,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
 
        rcu_read_lock();
 
+       /* Measure frame arrival for Tx latency statistics calculation */
+       ieee80211_tx_latency_start_msrmnt(local, skb);
+
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP_VLAN:
                sta = rcu_dereference(sdata->u.vlan.sta);
@@ -2109,7 +2134,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
         */
 
        if (head_need > 0 || skb_cloned(skb)) {
-               head_need += IEEE80211_ENCRYPT_HEADROOM;
+               head_need += sdata->encrypt_headroom;
                head_need += local->tx_headroom;
                head_need = max_t(int, 0, head_need);
                if (ieee80211_skb_resize(sdata, skb, head_need, true)) {
index 9f9b9bd3fd44798e7030fb3a44c46da962cfd7ba..875e172c001c697a72f85941fd0db8ef1b28b86a 100644 (file)
@@ -1804,6 +1804,26 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
        mutex_unlock(&local->chanctx_mtx);
 }
 
+void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_chanctx *chanctx;
+
+       mutex_lock(&local->chanctx_mtx);
+
+       chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+                                       lockdep_is_held(&local->chanctx_mtx));
+
+       if (WARN_ON_ONCE(!chanctx_conf))
+               goto unlock;
+
+       chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+       ieee80211_recalc_chanctx_min_def(local, chanctx);
+ unlock:
+       mutex_unlock(&local->chanctx_mtx);
+}
+
 static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
 {
        int i;
@@ -2259,14 +2279,17 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
 void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
+       struct cfg80211_chan_def chandef;
 
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry(sdata, &local->interfaces, list) {
                cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
 
                if (sdata->wdev.cac_started) {
+                       chandef = sdata->vif.bss_conf.chandef;
                        ieee80211_vif_release_channel(sdata);
                        cfg80211_cac_event(sdata->dev,
+                                          &chandef,
                                           NL80211_RADAR_CAC_ABORTED,
                                           GFP_KERNEL);
                }
@@ -2445,7 +2468,6 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
 
        if (ieee80211_vif_is_mesh(&sdata->vif)) {
                struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-               __le16 pre_value;
 
                skb_put(skb, 8);
                *pos++ = WLAN_EID_CHAN_SWITCH_PARAM;            /* EID */
@@ -2457,11 +2479,78 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
                          WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
                put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */
                pos += 2;
-               pre_value = cpu_to_le16(ifmsh->pre_value);
-               memcpy(pos, &pre_value, 2);             /* Precedence Value */
+               put_unaligned_le16(ifmsh->pre_value, pos);/* Precedence Value */
                pos += 2;
        }
 
        ieee80211_tx_skb(sdata, skb);
        return 0;
 }
+
+bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs)
+{
+       return !(cs == NULL || cs->cipher == 0 ||
+                cs->hdr_len < cs->pn_len + cs->pn_off ||
+                cs->hdr_len <= cs->key_idx_off ||
+                cs->key_idx_shift > 7 ||
+                cs->key_idx_mask == 0);
+}
+
+bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n)
+{
+       int i;
+
+       /* Ensure we have enough iftype bitmap space for all iftype values */
+       WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype));
+
+       for (i = 0; i < n; i++)
+               if (!ieee80211_cs_valid(&cs[i]))
+                       return false;
+
+       return true;
+}
+
+const struct ieee80211_cipher_scheme *
+ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
+                enum nl80211_iftype iftype)
+{
+       const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes;
+       int n = local->hw.n_cipher_schemes;
+       int i;
+       const struct ieee80211_cipher_scheme *cs = NULL;
+
+       for (i = 0; i < n; i++) {
+               if (l[i].cipher == cipher) {
+                       cs = &l[i];
+                       break;
+               }
+       }
+
+       if (!cs || !(cs->iftype & BIT(iftype)))
+               return NULL;
+
+       return cs;
+}
+
+int ieee80211_cs_headroom(struct ieee80211_local *local,
+                         struct cfg80211_crypto_settings *crypto,
+                         enum nl80211_iftype iftype)
+{
+       const struct ieee80211_cipher_scheme *cs;
+       int headroom = IEEE80211_ENCRYPT_HEADROOM;
+       int i;
+
+       for (i = 0; i < crypto->n_ciphers_pairwise; i++) {
+               cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i],
+                                     iftype);
+
+               if (cs && headroom < cs->hdr_len)
+                       headroom = cs->hdr_len;
+       }
+
+       cs = ieee80211_cs_get(local, crypto->cipher_group, iftype);
+       if (cs && headroom < cs->hdr_len)
+               headroom = cs->hdr_len;
+
+       return headroom;
+}
index de0112785aae19a8b23b2f8f84b364c80d27e8b3..d75f35c6e1a0884eb9452030cb27bcafb33deeab 100644 (file)
@@ -182,16 +182,15 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                         IEEE80211_VHT_CAP_SHORT_GI_160);
 
        /* remaining ones */
-       if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) {
+       if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)
                vht_cap->cap |= cap_info &
                                (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
-                                IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX);
-       }
+                                IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK);
 
        if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)
                vht_cap->cap |= cap_info &
                                (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
-                                IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX);
+                                IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK);
 
        if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)
                vht_cap->cap |= cap_info &
index d6572822076367cdf203207892a2880c7e4487c2..7313d379c0d32aea2c6a152c9756263ff7bf523f 100644 (file)
@@ -545,6 +545,106 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
        return RX_CONTINUE;
 }
 
+static ieee80211_tx_result
+ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx,
+                           struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_key *key = tx->key;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       const struct ieee80211_cipher_scheme *cs = key->sta->cipher_scheme;
+       int hdrlen;
+       u8 *pos;
+
+       if (info->control.hw_key &&
+           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
+               /* hwaccel has no need for preallocated head room */
+               return TX_CONTINUE;
+       }
+
+       if (unlikely(skb_headroom(skb) < cs->hdr_len &&
+                    pskb_expand_head(skb, cs->hdr_len, 0, GFP_ATOMIC)))
+               return TX_DROP;
+
+       hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+       pos = skb_push(skb, cs->hdr_len);
+       memmove(pos, pos + cs->hdr_len, hdrlen);
+       skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len);
+
+       return TX_CONTINUE;
+}
+
+static inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len)
+{
+       int i;
+
+       /* pn is little endian */
+       for (i = len - 1; i >= 0; i--) {
+               if (pn1[i] < pn2[i])
+                       return -1;
+               else if (pn1[i] > pn2[i])
+                       return 1;
+       }
+
+       return 0;
+}
+
+static ieee80211_rx_result
+ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx)
+{
+       struct ieee80211_key *key = rx->key;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+       const struct ieee80211_cipher_scheme *cs = NULL;
+       int hdrlen = ieee80211_hdrlen(hdr->frame_control);
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+       int data_len;
+       u8 *rx_pn;
+       u8 *skb_pn;
+       u8 qos_tid;
+
+       if (!rx->sta || !rx->sta->cipher_scheme ||
+           !(status->flag & RX_FLAG_DECRYPTED))
+               return RX_DROP_UNUSABLE;
+
+       if (!ieee80211_is_data(hdr->frame_control))
+               return RX_CONTINUE;
+
+       cs = rx->sta->cipher_scheme;
+
+       data_len = rx->skb->len - hdrlen - cs->hdr_len;
+
+       if (data_len < 0)
+               return RX_DROP_UNUSABLE;
+
+       if (ieee80211_is_data_qos(hdr->frame_control))
+               qos_tid = *ieee80211_get_qos_ctl(hdr) &
+                               IEEE80211_QOS_CTL_TID_MASK;
+       else
+               qos_tid = 0;
+
+       if (skb_linearize(rx->skb))
+               return RX_DROP_UNUSABLE;
+
+       hdr = (struct ieee80211_hdr *)rx->skb->data;
+
+       rx_pn = key->u.gen.rx_pn[qos_tid];
+       skb_pn = rx->skb->data + hdrlen + cs->pn_off;
+
+       if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0)
+               return RX_DROP_UNUSABLE;
+
+       memcpy(rx_pn, skb_pn, cs->pn_len);
+
+       /* remove security header and MIC */
+       if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len))
+               return RX_DROP_UNUSABLE;
+
+       memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen);
+       skb_pull(rx->skb, cs->hdr_len);
+
+       return RX_CONTINUE;
+}
 
 static void bip_aad(struct sk_buff *skb, u8 *aad)
 {
@@ -685,6 +785,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
 {
        struct sk_buff *skb;
        struct ieee80211_tx_info *info = NULL;
+       ieee80211_tx_result res;
 
        skb_queue_walk(&tx->skbs, skb) {
                info  = IEEE80211_SKB_CB(skb);
@@ -692,9 +793,24 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
                /* handle hw-only algorithm */
                if (!info->control.hw_key)
                        return TX_DROP;
+
+               if (tx->key->sta->cipher_scheme) {
+                       res = ieee80211_crypto_cs_encrypt(tx, skb);
+                       if (res != TX_CONTINUE)
+                               return res;
+               }
        }
 
        ieee80211_tx_set_protected(tx);
 
        return TX_CONTINUE;
 }
+
+ieee80211_rx_result
+ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx)
+{
+       if (rx->sta->cipher_scheme)
+               return ieee80211_crypto_cs_decrypt(rx);
+
+       return RX_DROP_UNUSABLE;
+}
index 07e33f899c71fc52f9ff1771cd283226a8a64084..62e5a12dfe0a24010b32eec210d7a38a1c4c3eb8 100644 (file)
@@ -34,5 +34,7 @@ ieee80211_rx_result
 ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx);
 ieee80211_tx_result
 ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx);
+ieee80211_rx_result
+ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx);
 
 #endif /* WPA_H */
index 9b8cc877eb191a2a62370c9f2617bed513200d24..78559b5bbd1fe1d98c533f18dd1cc4fce4087baa 100644 (file)
@@ -277,6 +277,32 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy,
                                     width, dfs_state);
 }
 
+static u32 cfg80211_get_start_freq(u32 center_freq,
+                                  u32 bandwidth)
+{
+       u32 start_freq;
+
+       if (bandwidth <= 20)
+               start_freq = center_freq;
+       else
+               start_freq = center_freq - bandwidth/2 + 10;
+
+       return start_freq;
+}
+
+static u32 cfg80211_get_end_freq(u32 center_freq,
+                                u32 bandwidth)
+{
+       u32 end_freq;
+
+       if (bandwidth <= 20)
+               end_freq = center_freq;
+       else
+               end_freq = center_freq + bandwidth/2 - 10;
+
+       return end_freq;
+}
+
 static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
                                            u32 center_freq,
                                            u32 bandwidth)
@@ -284,13 +310,8 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
        struct ieee80211_channel *c;
        u32 freq, start_freq, end_freq;
 
-       if (bandwidth <= 20) {
-               start_freq = center_freq;
-               end_freq = center_freq;
-       } else {
-               start_freq = center_freq - bandwidth/2 + 10;
-               end_freq = center_freq + bandwidth/2 - 10;
-       }
+       start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
+       end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
 
        for (freq = start_freq; freq <= end_freq; freq += 20) {
                c = ieee80211_get_channel(wiphy, freq);
@@ -330,33 +351,159 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
 
-static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
-                                       u32 center_freq, u32 bandwidth,
-                                       u32 prohibited_flags)
+static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
+                                        u32 center_freq,
+                                        u32 bandwidth)
 {
        struct ieee80211_channel *c;
        u32 freq, start_freq, end_freq;
+       int count = 0;
 
-       if (bandwidth <= 20) {
-               start_freq = center_freq;
-               end_freq = center_freq;
-       } else {
-               start_freq = center_freq - bandwidth/2 + 10;
-               end_freq = center_freq + bandwidth/2 - 10;
+       start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
+       end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
+
+       /*
+        * Check entire range of channels for the bandwidth.
+        * Check all channels are DFS channels (DFS_USABLE or
+        * DFS_AVAILABLE). Return number of usable channels
+        * (require CAC). Allow DFS and non-DFS channel mix.
+        */
+       for (freq = start_freq; freq <= end_freq; freq += 20) {
+               c = ieee80211_get_channel(wiphy, freq);
+               if (!c)
+                       return -EINVAL;
+
+               if (c->flags & IEEE80211_CHAN_DISABLED)
+                       return -EINVAL;
+
+               if (c->flags & IEEE80211_CHAN_RADAR) {
+                       if (c->dfs_state == NL80211_DFS_UNAVAILABLE)
+                               return -EINVAL;
+
+                       if (c->dfs_state == NL80211_DFS_USABLE)
+                               count++;
+               }
        }
 
+       return count;
+}
+
+bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
+                                const struct cfg80211_chan_def *chandef)
+{
+       int width;
+       int r1, r2 = 0;
+
+       if (WARN_ON(!cfg80211_chandef_valid(chandef)))
+               return false;
+
+       width = cfg80211_chandef_get_width(chandef);
+       if (width < 0)
+               return false;
+
+       r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1,
+                                         width);
+
+       if (r1 < 0)
+               return false;
+
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_80P80:
+               WARN_ON(!chandef->center_freq2);
+               r2 = cfg80211_get_chans_dfs_usable(wiphy,
+                                                  chandef->center_freq2,
+                                                  width);
+               if (r2 < 0)
+                       return false;
+               break;
+       default:
+               WARN_ON(chandef->center_freq2);
+               break;
+       }
+
+       return (r1 + r2 > 0);
+}
+
+
+static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
+                                            u32 center_freq,
+                                            u32 bandwidth)
+{
+       struct ieee80211_channel *c;
+       u32 freq, start_freq, end_freq;
+
+       start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
+       end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
+
+       /*
+        * Check entire range of channels for the bandwidth.
+        * If any channel in between is disabled or has not
+        * had gone through CAC return false
+        */
        for (freq = start_freq; freq <= end_freq; freq += 20) {
                c = ieee80211_get_channel(wiphy, freq);
                if (!c)
                        return false;
 
-               /* check for radar flags */
-               if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) &&
+               if (c->flags & IEEE80211_CHAN_DISABLED)
+                       return false;
+
+               if ((c->flags & IEEE80211_CHAN_RADAR)  &&
                    (c->dfs_state != NL80211_DFS_AVAILABLE))
                        return false;
+       }
+
+       return true;
+}
+
+static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
+                               const struct cfg80211_chan_def *chandef)
+{
+       int width;
+       int r;
+
+       if (WARN_ON(!cfg80211_chandef_valid(chandef)))
+               return false;
+
+       width = cfg80211_chandef_get_width(chandef);
+       if (width < 0)
+               return false;
+
+       r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1,
+                                            width);
+
+       /* If any of channels unavailable for cf1 just return */
+       if (!r)
+               return r;
+
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_80P80:
+               WARN_ON(!chandef->center_freq2);
+               r = cfg80211_get_chans_dfs_available(wiphy,
+                                                    chandef->center_freq2,
+                                                    width);
+       default:
+               WARN_ON(chandef->center_freq2);
+               break;
+       }
+
+       return r;
+}
 
-               /* check for the other flags */
-               if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR)
+
+static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
+                                       u32 center_freq, u32 bandwidth,
+                                       u32 prohibited_flags)
+{
+       struct ieee80211_channel *c;
+       u32 freq, start_freq, end_freq;
+
+       start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
+       end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
+
+       for (freq = start_freq; freq <= end_freq; freq += 20) {
+               c = ieee80211_get_channel(wiphy, freq);
+               if (!c || c->flags & prohibited_flags)
                        return false;
        }
 
@@ -462,14 +609,19 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
                             struct cfg80211_chan_def *chandef)
 {
        bool res;
+       u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
+                              IEEE80211_CHAN_NO_IR |
+                              IEEE80211_CHAN_RADAR;
 
        trace_cfg80211_reg_can_beacon(wiphy, chandef);
 
-       res = cfg80211_chandef_usable(wiphy, chandef,
-                                     IEEE80211_CHAN_DISABLED |
-                                     IEEE80211_CHAN_PASSIVE_SCAN |
-                                     IEEE80211_CHAN_NO_IBSS |
-                                     IEEE80211_CHAN_RADAR);
+       if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 &&
+           cfg80211_chandef_dfs_available(wiphy, chandef)) {
+               /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
+               prohibited_flags = IEEE80211_CHAN_DISABLED;
+       }
+
+       res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags);
 
        trace_cfg80211_return_bool(res);
        return res;
@@ -510,6 +662,7 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
                                  : CHAN_MODE_EXCLUSIVE;
                        return;
                }
+               break;
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_CLIENT:
                if (wdev->current_bss) {
index 52b865fb7351ac3c221c120bc0cc236687a12513..06db6eb5258aefc332fb4fb09ed165562ea8cd7d 100644 (file)
@@ -357,8 +357,6 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
        rdev->wiphy.rts_threshold = (u32) -1;
        rdev->wiphy.coverage_class = 0;
 
-       rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH;
-
        return &rdev->wiphy;
 }
 EXPORT_SYMBOL(wiphy_new);
@@ -575,6 +573,8 @@ int wiphy_register(struct wiphy *wiphy)
        /* check and set up bitrates */
        ieee80211_set_bitrate_flags(wiphy);
 
+       rdev->wiphy.features |= NL80211_FEATURE_SCAN_FLUSH;
+
        rtnl_lock();
        res = device_add(&rdev->wiphy.dev);
        if (res) {
@@ -595,7 +595,7 @@ int wiphy_register(struct wiphy *wiphy)
        if (IS_ERR(rdev->wiphy.debugfsdir))
                rdev->wiphy.debugfsdir = NULL;
 
-       if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) {
+       if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
                struct regulatory_request request;
 
                request.wiphy_idx = get_wiphy_idx(wiphy);
index af10e59af2d86f418bd7cc4e69914c9bb31831c7..0a277c33bb027a879d854492ddde295be2c663a0 100644 (file)
@@ -317,9 +317,8 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
 void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
 int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          struct wireless_dev *wdev,
-                         struct ieee80211_channel *chan, bool offchan,
-                         unsigned int wait, const u8 *buf, size_t len,
-                         bool no_cck, bool dont_wait_for_ack, u64 *cookie);
+                         struct cfg80211_mgmt_tx_params *params,
+                         u64 *cookie);
 void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
                               const struct ieee80211_ht_cap *ht_capa_mask);
 void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
@@ -382,6 +381,19 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                                 enum cfg80211_chan_mode chanmode,
                                 u8 radar_detect);
 
+/**
+ * cfg80211_chandef_dfs_usable - checks if chandef is DFS usable
+ * @wiphy: the wiphy to validate against
+ * @chandef: the channel definition to check
+ *
+ * Checks if chandef is usable and we can/need start CAC on such channel.
+ *
+ * Return: Return true if all channels available and at least
+ *        one channel require CAC (NL80211_DFS_USABLE)
+ */
+bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
+                                const struct cfg80211_chan_def *chandef);
+
 void cfg80211_set_dfs_state(struct wiphy *wiphy,
                            const struct cfg80211_chan_def *chandef,
                            enum nl80211_dfs_state dfs_state);
index 42ed274e81f4ca7debc59c4ae17137c35a0993d8..9a8217d2a90882f872451833cabe30159a64953f 100644 (file)
@@ -33,15 +33,7 @@ BEGIN {
        regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n"
 }
 
-/^[ \t]*#/ {
-       # Ignore
-}
-
-!active && /^[ \t]*$/ {
-       # Ignore
-}
-
-!active && /country/ {
+function parse_country_head() {
        country=$2
        sub(/:/, "", country)
        printf "static const struct ieee80211_regdomain regdom_%s = {\n", country
@@ -57,7 +49,8 @@ BEGIN {
        regdb = regdb "\t&regdom_" country ",\n"
 }
 
-active && /^[ \t]*\(/ {
+function parse_reg_rule()
+{
        start = $1
        sub(/\(/, "", start)
        end = $3
@@ -107,17 +100,21 @@ active && /^[ \t]*\(/ {
                } else if (flagarray[arg] == "PTMP-ONLY") {
                        flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | "
                } else if (flagarray[arg] == "PASSIVE-SCAN") {
-                       flags = flags "\n\t\t\tNL80211_RRF_PASSIVE_SCAN | "
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
                } else if (flagarray[arg] == "NO-IBSS") {
-                       flags = flags "\n\t\t\tNL80211_RRF_NO_IBSS | "
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
+               } else if (flagarray[arg] == "NO-IR") {
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
                }
+
        }
        flags = flags "0"
        printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags
        rules++
 }
 
-active && /^[ \t]*$/ {
+function print_tail_country()
+{
        active = 0
        printf "\t},\n"
        printf "\t.n_reg_rules = %d\n", rules
@@ -125,7 +122,29 @@ active && /^[ \t]*$/ {
        rules = 0;
 }
 
+/^[ \t]*#/ {
+       # Ignore
+}
+
+!active && /^[ \t]*$/ {
+       # Ignore
+}
+
+!active && /country/ {
+       parse_country_head()
+}
+
+active && /^[ \t]*\(/ {
+       parse_reg_rule()
+}
+
+active && /^[ \t]*$/ {
+       print_tail_country()
+}
+
 END {
+       if (active)
+               print_tail_country()
        print regdb "};"
        print ""
        print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);"
index 89737ee2669a8de9bc8f02aa1c392052369d210b..730147ed8e652c625cb035309df687ca08fd5b49 100644 (file)
@@ -274,7 +274,7 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
 
                        for (i = 0; i < sband->n_channels; i++) {
                                chan = &sband->channels[i];
-                               if (chan->flags & IEEE80211_CHAN_NO_IBSS)
+                               if (chan->flags & IEEE80211_CHAN_NO_IR)
                                        continue;
                                if (chan->flags & IEEE80211_CHAN_DISABLED)
                                        continue;
@@ -346,7 +346,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
                chan = ieee80211_get_channel(wdev->wiphy, freq);
                if (!chan)
                        return -EINVAL;
-               if (chan->flags & IEEE80211_CHAN_NO_IBSS ||
+               if (chan->flags & IEEE80211_CHAN_NO_IR ||
                    chan->flags & IEEE80211_CHAN_DISABLED)
                        return -EINVAL;
        }
index 0553fd4d85aeb4b9338d2661ba020448105a68e9..b0e1869de7de0b0775561c445389f4f2013beb58 100644 (file)
@@ -141,8 +141,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 
                        for (i = 0; i < sband->n_channels; i++) {
                                chan = &sband->channels[i];
-                               if (chan->flags & (IEEE80211_CHAN_NO_IBSS |
-                                                  IEEE80211_CHAN_PASSIVE_SCAN |
+                               if (chan->flags & (IEEE80211_CHAN_NO_IR |
                                                   IEEE80211_CHAN_DISABLED |
                                                   IEEE80211_CHAN_RADAR))
                                        continue;
index 6a6b1c8e907df93e73b44a8912a3ae1fda5f80a5..52cca05044a898b977927f2c9e540b00d6811634 100644 (file)
@@ -520,9 +520,7 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
 
 int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          struct wireless_dev *wdev,
-                         struct ieee80211_channel *chan, bool offchan,
-                         unsigned int wait, const u8 *buf, size_t len,
-                         bool no_cck, bool dont_wait_for_ack, u64 *cookie)
+                         struct cfg80211_mgmt_tx_params *params, u64 *cookie)
 {
        const struct ieee80211_mgmt *mgmt;
        u16 stype;
@@ -533,10 +531,10 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
        if (!rdev->ops->mgmt_tx)
                return -EOPNOTSUPP;
 
-       if (len < 24 + 1)
+       if (params->len < 24 + 1)
                return -EINVAL;
 
-       mgmt = (const struct ieee80211_mgmt *) buf;
+       mgmt = (const struct ieee80211_mgmt *)params->buf;
 
        if (!ieee80211_is_mgmt(mgmt->frame_control))
                return -EINVAL;
@@ -615,9 +613,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                return -EINVAL;
 
        /* Transmit the Action frame as requested by user space */
-       return rdev_mgmt_tx(rdev, wdev, chan, offchan,
-                           wait, buf, len, no_cck, dont_wait_for_ack,
-                           cookie);
+       return rdev_mgmt_tx(rdev, wdev, params, cookie);
 }
 
 bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
@@ -763,12 +759,12 @@ void cfg80211_radar_event(struct wiphy *wiphy,
 EXPORT_SYMBOL(cfg80211_radar_event);
 
 void cfg80211_cac_event(struct net_device *netdev,
+                       const struct cfg80211_chan_def *chandef,
                        enum nl80211_radar_event event, gfp_t gfp)
 {
        struct wireless_dev *wdev = netdev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-       struct cfg80211_chan_def chandef;
        unsigned long timeout;
 
        trace_cfg80211_cac_event(netdev, event);
@@ -779,14 +775,12 @@ void cfg80211_cac_event(struct net_device *netdev,
        if (WARN_ON(!wdev->channel))
                return;
 
-       cfg80211_chandef_create(&chandef, wdev->channel, NL80211_CHAN_NO_HT);
-
        switch (event) {
        case NL80211_RADAR_CAC_FINISHED:
                timeout = wdev->cac_start_time +
                          msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
                WARN_ON(!time_after_eq(jiffies, timeout));
-               cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_AVAILABLE);
+               cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
                break;
        case NL80211_RADAR_CAC_ABORTED:
                break;
@@ -796,6 +790,6 @@ void cfg80211_cac_event(struct net_device *netdev,
        }
        wdev->cac_started = false;
 
-       nl80211_radar_notify(rdev, &chandef, event, netdev, gfp);
+       nl80211_radar_notify(rdev, chandef, event, netdev, gfp);
 }
 EXPORT_SYMBOL(cfg80211_cac_event);
index 138dc3bb8b67d8c345531a95ce0c8342271ce79e..a693f86e59704016e9c8419eb82a8c43185d9642 100644 (file)
@@ -564,12 +564,12 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
        if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
            nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
                goto nla_put_failure;
-       if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
-           nla_put_flag(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN))
-               goto nla_put_failure;
-       if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
-           nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS))
-               goto nla_put_failure;
+       if (chan->flags & IEEE80211_CHAN_NO_IR) {
+               if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
+                       goto nla_put_failure;
+               if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
+                       goto nla_put_failure;
+       }
        if (chan->flags & IEEE80211_CHAN_RADAR) {
                if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
                        goto nla_put_failure;
@@ -1247,10 +1247,6 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
                    nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
                        goto nla_put_failure;
-               if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
-                   nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ))
-                       goto nla_put_failure;
-
                state->split_start++;
                if (state->split)
                        break;
@@ -1579,6 +1575,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                if (nl80211_send_coalesce(msg, dev))
                        goto nla_put_failure;
 
+               if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
+                   (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
+                    nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
+                       goto nla_put_failure;
+
                /* done */
                state->split_start = 0;
                break;
@@ -2187,7 +2188,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
 }
 
 static int nl80211_send_chandef(struct sk_buff *msg,
-                                struct cfg80211_chan_def *chandef)
+                               const struct cfg80211_chan_def *chandef)
 {
        WARN_ON(!cfg80211_chandef_valid(chandef));
 
@@ -3236,6 +3237,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
                        return PTR_ERR(params.acl);
        }
 
+       wdev_lock(wdev);
        err = rdev_start_ap(rdev, dev, &params);
        if (!err) {
                wdev->preset_chandef = params.chandef;
@@ -3244,6 +3246,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
                wdev->ssid_len = params.ssid_len;
                memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
        }
+       wdev_unlock(wdev);
 
        kfree(params.acl);
 
@@ -3272,7 +3275,11 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
        if (err)
                return err;
 
-       return rdev_change_beacon(rdev, dev, &params);
+       wdev_lock(wdev);
+       err = rdev_change_beacon(rdev, dev, &params);
+       wdev_unlock(wdev);
+
+       return err;
 }
 
 static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
@@ -4478,7 +4485,9 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct bss_parameters params;
+       int err;
 
        memset(&params, 0, sizeof(params));
        /* default to not changing parameters */
@@ -4544,7 +4553,11 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
                return -EOPNOTSUPP;
 
-       return rdev_change_bss(rdev, dev, &params);
+       wdev_lock(wdev);
+       err = rdev_change_bss(rdev, dev, &params);
+       wdev_unlock(wdev);
+
+       return err;
 }
 
 static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
@@ -5098,7 +5111,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
        char *alpha2 = NULL;
        int rem_reg_rules = 0, r = 0;
        u32 num_rules = 0, rule_idx = 0, size_of_regd;
-       u8 dfs_region = 0;
+       enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
        struct ieee80211_regdomain *rd = NULL;
 
        if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
@@ -5119,6 +5132,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
                        return -EINVAL;
        }
 
+       if (!reg_is_valid_request(alpha2))
+               return -EINVAL;
+
        size_of_regd = sizeof(struct ieee80211_regdomain) +
                       num_rules * sizeof(struct ieee80211_reg_rule);
 
@@ -5365,10 +5381,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
                request->flags = nla_get_u32(
                        info->attrs[NL80211_ATTR_SCAN_FLAGS]);
-               if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
-                    !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
-                   ((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
-                    !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
+               if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
+                   !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
                        err = -EOPNOTSUPP;
                        goto out_free;
                }
@@ -5608,10 +5622,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
        if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
                request->flags = nla_get_u32(
                        info->attrs[NL80211_ATTR_SCAN_FLAGS]);
-               if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
-                    !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
-                   ((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
-                    !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
+               if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
+                   !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
                        err = -EOPNOTSUPP;
                        goto out_free;
                }
@@ -5674,7 +5686,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
        if (err == 0)
                return -EINVAL;
 
-       if (chandef.chan->dfs_state != NL80211_DFS_USABLE)
+       if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef))
                return -EINVAL;
 
        if (!rdev->ops->start_radar_detection)
@@ -5814,7 +5826,11 @@ skip_beacons:
        if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
                params.block_tx = true;
 
-       return rdev_channel_switch(rdev, dev, &params);
+       wdev_lock(wdev);
+       err = rdev_channel_switch(rdev, dev, &params);
+       wdev_unlock(wdev);
+
+       return err;
 }
 
 static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
@@ -7447,10 +7463,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        void *hdr = NULL;
        u64 cookie;
        struct sk_buff *msg = NULL;
-       unsigned int wait = 0;
-       bool offchan, no_cck, dont_wait_for_ack;
-
-       dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
+       struct cfg80211_mgmt_tx_params params = {
+               .dont_wait_for_ack =
+                       info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
+       };
 
        if (!info->attrs[NL80211_ATTR_FRAME])
                return -EINVAL;
@@ -7477,24 +7493,24 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_DURATION]) {
                if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
                        return -EINVAL;
-               wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
+               params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
 
                /*
                 * We should wait on the channel for at least a minimum amount
                 * of time (10ms) but no longer than the driver supports.
                 */
-               if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
-                   wait > rdev->wiphy.max_remain_on_channel_duration)
+               if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
+                   params.wait > rdev->wiphy.max_remain_on_channel_duration)
                        return -EINVAL;
 
        }
 
-       offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
+       params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
 
-       if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
+       if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
                return -EINVAL;
 
-       no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
+       params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
 
        /* get the channel if any has been specified, otherwise pass NULL to
         * the driver. The latter will use the current one
@@ -7506,10 +7522,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                        return err;
        }
 
-       if (!chandef.chan && offchan)
+       if (!chandef.chan && params.offchan)
                return -EINVAL;
 
-       if (!dont_wait_for_ack) {
+       if (!params.dont_wait_for_ack) {
                msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
                if (!msg)
                        return -ENOMEM;
@@ -7522,10 +7538,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
-       err = cfg80211_mlme_mgmt_tx(rdev, wdev, chandef.chan, offchan, wait,
-                                   nla_data(info->attrs[NL80211_ATTR_FRAME]),
-                                   nla_len(info->attrs[NL80211_ATTR_FRAME]),
-                                   no_cck, dont_wait_for_ack, &cookie);
+       params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
+       params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
+       params.chan = chandef.chan;
+       err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
        if (err)
                goto free_msg;
 
@@ -10810,21 +10826,18 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
-       trace_cfg80211_ch_switch_notify(dev, chandef);
+       ASSERT_WDEV_LOCK(wdev);
 
-       wdev_lock(wdev);
+       trace_cfg80211_ch_switch_notify(dev, chandef);
 
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
                    wdev->iftype != NL80211_IFTYPE_P2P_GO &&
                    wdev->iftype != NL80211_IFTYPE_ADHOC &&
                    wdev->iftype != NL80211_IFTYPE_MESH_POINT))
-               goto out;
+               return;
 
        wdev->channel = chandef->chan;
        nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
-out:
-       wdev_unlock(wdev);
-       return;
 }
 EXPORT_SYMBOL(cfg80211_ch_switch_notify);
 
@@ -10883,7 +10896,7 @@ EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
 
 void
 nl80211_radar_notify(struct cfg80211_registered_device *rdev,
-                    struct cfg80211_chan_def *chandef,
+                    const struct cfg80211_chan_def *chandef,
                     enum nl80211_radar_event event,
                     struct net_device *netdev, gfp_t gfp)
 {
index 2c0f2b3c07cba7e4c2f50b17895d498c79d08dfb..b1b231324e102a44218bcf2354e52662fac78f5a 100644 (file)
@@ -70,7 +70,7 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
 
 void
 nl80211_radar_notify(struct cfg80211_registered_device *rdev,
-                    struct cfg80211_chan_def *chandef,
+                    const struct cfg80211_chan_def *chandef,
                     enum nl80211_radar_event event,
                     struct net_device *netdev, gfp_t gfp);
 
index 37ce9fdfe934345fe6603b399b8c4d3fd4f44ec1..a6c03ab14a0d47ea9a7f676dec76301804ab809b 100644 (file)
@@ -624,16 +624,12 @@ rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev,
 
 static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev,
                               struct wireless_dev *wdev,
-                              struct ieee80211_channel *chan, bool offchan,
-                              unsigned int wait, const u8 *buf, size_t len,
-                              bool no_cck, bool dont_wait_for_ack, u64 *cookie)
+                              struct cfg80211_mgmt_tx_params *params,
+                              u64 *cookie)
 {
        int ret;
-       trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
-                          wait, no_cck, dont_wait_for_ack);
-       ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
-                                 wait, buf, len, no_cck,
-                                 dont_wait_for_ack, cookie);
+       trace_rdev_mgmt_tx(&rdev->wiphy, wdev, params);
+       ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, params, cookie);
        trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
        return ret;
 }
index 7da67fd0b4188a7cf3e3ded0ae2a64d565274947..ec54e1aac8e29c01e89ab4d0c6e9078bf112b5f9 100644 (file)
@@ -120,6 +120,21 @@ static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy)
        return rtnl_dereference(wiphy->regd);
 }
 
+static const char *reg_dfs_region_str(enum nl80211_dfs_regions dfs_region)
+{
+       switch (dfs_region) {
+       case NL80211_DFS_UNSET:
+               return "unset";
+       case NL80211_DFS_FCC:
+               return "FCC";
+       case NL80211_DFS_ETSI:
+               return "ETSI";
+       case NL80211_DFS_JP:
+               return "JP";
+       }
+       return "Unknown";
+}
+
 static void rcu_free_regdom(const struct ieee80211_regdomain *r)
 {
        if (!r)
@@ -163,35 +178,29 @@ static const struct ieee80211_regdomain world_regdom = {
                REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
                /* IEEE 802.11b/g, channels 12..13. */
                REG_RULE(2467-10, 2472+10, 40, 6, 20,
-                       NL80211_RRF_PASSIVE_SCAN |
-                       NL80211_RRF_NO_IBSS),
+                       NL80211_RRF_NO_IR),
                /* IEEE 802.11 channel 14 - Only JP enables
                 * this and for 802.11b only */
                REG_RULE(2484-10, 2484+10, 20, 6, 20,
-                       NL80211_RRF_PASSIVE_SCAN |
-                       NL80211_RRF_NO_IBSS |
+                       NL80211_RRF_NO_IR |
                        NL80211_RRF_NO_OFDM),
                /* IEEE 802.11a, channel 36..48 */
                REG_RULE(5180-10, 5240+10, 160, 6, 20,
-                        NL80211_RRF_PASSIVE_SCAN |
-                        NL80211_RRF_NO_IBSS),
+                        NL80211_RRF_NO_IR),
 
                /* IEEE 802.11a, channel 52..64 - DFS required */
                REG_RULE(5260-10, 5320+10, 160, 6, 20,
-                       NL80211_RRF_PASSIVE_SCAN |
-                       NL80211_RRF_NO_IBSS |
+                       NL80211_RRF_NO_IR |
                        NL80211_RRF_DFS),
 
                /* IEEE 802.11a, channel 100..144 - DFS required */
                REG_RULE(5500-10, 5720+10, 160, 6, 20,
-                       NL80211_RRF_PASSIVE_SCAN |
-                       NL80211_RRF_NO_IBSS |
+                       NL80211_RRF_NO_IR |
                        NL80211_RRF_DFS),
 
                /* IEEE 802.11a, channel 149..165 */
                REG_RULE(5745-10, 5825+10, 80, 6, 20,
-                       NL80211_RRF_PASSIVE_SCAN |
-                       NL80211_RRF_NO_IBSS),
+                       NL80211_RRF_NO_IR),
 
                /* IEEE 802.11ad (60gHz), channels 1..3 */
                REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0),
@@ -208,11 +217,26 @@ static char user_alpha2[2];
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 
+static void reg_kfree_last_request(void)
+{
+       struct regulatory_request *lr;
+
+       lr = get_last_request();
+
+       if (lr != &core_request_world && lr)
+               kfree_rcu(lr, rcu_head);
+}
+
+static void reg_update_last_request(struct regulatory_request *request)
+{
+       reg_kfree_last_request();
+       rcu_assign_pointer(last_request, request);
+}
+
 static void reset_regdomains(bool full_reset,
                             const struct ieee80211_regdomain *new_regdom)
 {
        const struct ieee80211_regdomain *r;
-       struct regulatory_request *lr;
 
        ASSERT_RTNL();
 
@@ -235,10 +259,7 @@ static void reset_regdomains(bool full_reset,
        if (!full_reset)
                return;
 
-       lr = get_last_request();
-       if (lr != &core_request_world && lr)
-               kfree_rcu(lr, rcu_head);
-       rcu_assign_pointer(last_request, &core_request_world);
+       reg_update_last_request(&core_request_world);
 }
 
 /*
@@ -456,7 +477,15 @@ static int call_crda(const char *alpha2)
        return kobject_uevent(&reg_pdev->dev.kobj, KOBJ_CHANGE);
 }
 
-static bool reg_is_valid_request(const char *alpha2)
+static enum reg_request_treatment
+reg_call_crda(struct regulatory_request *request)
+{
+       if (call_crda(request->alpha2))
+               return REG_REQ_IGNORE;
+       return REG_REQ_OK;
+}
+
+bool reg_is_valid_request(const char *alpha2)
 {
        struct regulatory_request *lr = get_last_request();
 
@@ -556,6 +585,20 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
 #undef ONE_GHZ_IN_KHZ
 }
 
+/*
+ * Later on we can perhaps use the more restrictive DFS
+ * region but we don't have information for that yet so
+ * for now simply disallow conflicts.
+ */
+static enum nl80211_dfs_regions
+reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1,
+                        const enum nl80211_dfs_regions dfs_region2)
+{
+       if (dfs_region1 != dfs_region2)
+               return NL80211_DFS_UNSET;
+       return dfs_region1;
+}
+
 /*
  * Helper for regdom_intersect(), this does the real
  * mathematical intersection fun
@@ -687,6 +730,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
        rd->n_reg_rules = num_rules;
        rd->alpha2[0] = '9';
        rd->alpha2[1] = '8';
+       rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region,
+                                                 rd2->dfs_region);
 
        return rd;
 }
@@ -698,10 +743,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
 static u32 map_regdom_flags(u32 rd_flags)
 {
        u32 channel_flags = 0;
-       if (rd_flags & NL80211_RRF_PASSIVE_SCAN)
-               channel_flags |= IEEE80211_CHAN_PASSIVE_SCAN;
-       if (rd_flags & NL80211_RRF_NO_IBSS)
-               channel_flags |= IEEE80211_CHAN_NO_IBSS;
+       if (rd_flags & NL80211_RRF_NO_IR_ALL)
+               channel_flags |= IEEE80211_CHAN_NO_IR;
        if (rd_flags & NL80211_RRF_DFS)
                channel_flags |= IEEE80211_CHAN_RADAR;
        if (rd_flags & NL80211_RRF_NO_OFDM)
@@ -854,8 +897,18 @@ static void handle_channel(struct wiphy *wiphy,
                    PTR_ERR(reg_rule) == -ERANGE)
                        return;
 
-               REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq);
-               chan->flags |= IEEE80211_CHAN_DISABLED;
+               if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+                   request_wiphy && request_wiphy == wiphy &&
+                   request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
+                       REG_DBG_PRINT("Disabling freq %d MHz for good\n",
+                                     chan->center_freq);
+                       chan->orig_flags |= IEEE80211_CHAN_DISABLED;
+                       chan->flags = chan->orig_flags;
+               } else {
+                       REG_DBG_PRINT("Disabling freq %d MHz\n",
+                                     chan->center_freq);
+                       chan->flags |= IEEE80211_CHAN_DISABLED;
+               }
                return;
        }
 
@@ -873,7 +926,7 @@ static void handle_channel(struct wiphy *wiphy,
 
        if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
            request_wiphy && request_wiphy == wiphy &&
-           request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
+           request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
                /*
                 * This guarantees the driver's requested regulatory domain
                 * will always be used as a base for further regulatory
@@ -899,13 +952,11 @@ static void handle_channel(struct wiphy *wiphy,
        chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
        if (chan->orig_mpwr) {
                /*
-                * Devices that have their own custom regulatory domain
-                * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the
-                * passed country IE power settings.
+                * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER
+                * will always follow the passed country IE power settings.
                 */
                if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-                   wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY &&
-                   wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
+                   wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_FOLLOW_POWER)
                        chan->max_power = chan->max_reg_power;
                else
                        chan->max_power = min(chan->orig_mpwr,
@@ -975,8 +1026,8 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
 
 static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy)
 {
-       if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY &&
-           !(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY))
+       if (wiphy->regulatory_flags & REGULATORY_STRICT_REG &&
+           !(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG))
                return true;
        return false;
 }
@@ -994,7 +1045,7 @@ static bool ignore_reg_update(struct wiphy *wiphy,
        }
 
        if (initiator == NL80211_REGDOM_SET_BY_CORE &&
-           wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) {
+           wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
                REG_DBG_PRINT("Ignoring regulatory request set by %s "
                              "since the driver uses its own custom "
                              "regulatory domain\n",
@@ -1032,7 +1083,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy)
                return true;
 
        if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-           wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
+           wiphy->regulatory_flags & REGULATORY_CUSTOM_REG)
                return true;
 
        return false;
@@ -1060,19 +1111,14 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx,
        if (!reg_is_world_roaming(wiphy))
                return;
 
-       if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS)
+       if (wiphy->regulatory_flags & REGULATORY_DISABLE_BEACON_HINTS)
                return;
 
        chan_before.center_freq = chan->center_freq;
        chan_before.flags = chan->flags;
 
-       if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) {
-               chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
-               channel_changed = true;
-       }
-
-       if (chan->flags & IEEE80211_CHAN_NO_IBSS) {
-               chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
+       if (chan->flags & IEEE80211_CHAN_NO_IR) {
+               chan->flags &= ~IEEE80211_CHAN_NO_IR;
                channel_changed = true;
        }
 
@@ -1205,14 +1251,30 @@ static void reg_process_ht_flags(struct wiphy *wiphy)
                reg_process_ht_flags_band(wiphy, wiphy->bands[band]);
 }
 
+static void reg_call_notifier(struct wiphy *wiphy,
+                             struct regulatory_request *request)
+{
+       if (wiphy->reg_notifier)
+               wiphy->reg_notifier(wiphy, request);
+}
+
 static void wiphy_update_regulatory(struct wiphy *wiphy,
                                    enum nl80211_reg_initiator initiator)
 {
        enum ieee80211_band band;
        struct regulatory_request *lr = get_last_request();
 
-       if (ignore_reg_update(wiphy, initiator))
+       if (ignore_reg_update(wiphy, initiator)) {
+               /*
+                * Regulatory updates set by CORE are ignored for custom
+                * regulatory cards. Let us notify the changes to the driver,
+                * as some drivers used this to restore its orig_* reg domain.
+                */
+               if (initiator == NL80211_REGDOM_SET_BY_CORE &&
+                   wiphy->regulatory_flags & REGULATORY_CUSTOM_REG)
+                       reg_call_notifier(wiphy, lr);
                return;
+       }
 
        lr->dfs_region = get_cfg80211_regdom()->dfs_region;
 
@@ -1221,9 +1283,7 @@ static void wiphy_update_regulatory(struct wiphy *wiphy,
 
        reg_process_beacons(wiphy);
        reg_process_ht_flags(wiphy);
-
-       if (wiphy->reg_notifier)
-               wiphy->reg_notifier(wiphy, lr);
+       reg_call_notifier(wiphy, lr);
 }
 
 static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
@@ -1236,15 +1296,6 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
        list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
                wiphy = &rdev->wiphy;
                wiphy_update_regulatory(wiphy, initiator);
-               /*
-                * Regulatory updates set by CORE are ignored for custom
-                * regulatory cards. Let us notify the changes to the driver,
-                * as some drivers used this to restore its orig_* reg domain.
-                */
-               if (initiator == NL80211_REGDOM_SET_BY_CORE &&
-                   wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY &&
-                   wiphy->reg_notifier)
-                       wiphy->reg_notifier(wiphy, get_last_request());
        }
 }
 
@@ -1263,7 +1314,8 @@ static void handle_channel_custom(struct wiphy *wiphy,
        if (IS_ERR(reg_rule)) {
                REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n",
                              chan->center_freq);
-               chan->flags = IEEE80211_CHAN_DISABLED;
+               chan->orig_flags |= IEEE80211_CHAN_DISABLED;
+               chan->flags = chan->orig_flags;
                return;
        }
 
@@ -1305,6 +1357,10 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
        enum ieee80211_band band;
        unsigned int bands_set = 0;
 
+       WARN(!(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG),
+            "wiphy should have REGULATORY_CUSTOM_REG\n");
+       wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
+
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                if (!wiphy->bands[band])
                        continue;
@@ -1320,225 +1376,285 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
 
-/* This has the logic which determines when a new request
- * should be ignored. */
-static enum reg_request_treatment
-get_reg_request_treatment(struct wiphy *wiphy,
-                         struct regulatory_request *pending_request)
+static void reg_set_request_processed(void)
 {
-       struct wiphy *last_wiphy = NULL;
+       bool need_more_processing = false;
        struct regulatory_request *lr = get_last_request();
 
-       /* All initial requests are respected */
-       if (!lr)
-               return REG_REQ_OK;
+       lr->processed = true;
 
-       switch (pending_request->initiator) {
-       case NL80211_REGDOM_SET_BY_CORE:
-               return REG_REQ_OK;
-       case NL80211_REGDOM_SET_BY_COUNTRY_IE:
-               if (reg_request_cell_base(lr)) {
-                       /* Trust a Cell base station over the AP's country IE */
-                       if (regdom_changes(pending_request->alpha2))
-                               return REG_REQ_IGNORE;
-                       return REG_REQ_ALREADY_SET;
-               }
+       spin_lock(&reg_requests_lock);
+       if (!list_empty(&reg_requests_list))
+               need_more_processing = true;
+       spin_unlock(&reg_requests_lock);
 
-               last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
+       if (lr->initiator == NL80211_REGDOM_SET_BY_USER)
+               cancel_delayed_work(&reg_timeout);
 
-               if (unlikely(!is_an_alpha2(pending_request->alpha2)))
-                       return -EINVAL;
-               if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-                       if (last_wiphy != wiphy) {
-                               /*
-                                * Two cards with two APs claiming different
-                                * Country IE alpha2s. We could
-                                * intersect them, but that seems unlikely
-                                * to be correct. Reject second one for now.
-                                */
-                               if (regdom_changes(pending_request->alpha2))
-                                       return REG_REQ_IGNORE;
-                               return REG_REQ_ALREADY_SET;
-                       }
-                       /*
-                        * Two consecutive Country IE hints on the same wiphy.
-                        * This should be picked up early by the driver/stack
-                        */
-                       if (WARN_ON(regdom_changes(pending_request->alpha2)))
-                               return REG_REQ_OK;
-                       return REG_REQ_ALREADY_SET;
-               }
-               return REG_REQ_OK;
-       case NL80211_REGDOM_SET_BY_DRIVER:
-               if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) {
-                       if (regdom_changes(pending_request->alpha2))
-                               return REG_REQ_OK;
-                       return REG_REQ_ALREADY_SET;
-               }
+       if (need_more_processing)
+               schedule_work(&reg_work);
+}
 
-               /*
-                * This would happen if you unplug and plug your card
-                * back in or if you add a new device for which the previously
-                * loaded card also agrees on the regulatory domain.
-                */
-               if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
-                   !regdom_changes(pending_request->alpha2))
-                       return REG_REQ_ALREADY_SET;
+/**
+ * reg_process_hint_core - process core regulatory requests
+ * @pending_request: a pending core regulatory request
+ *
+ * The wireless subsystem can use this function to process
+ * a regulatory request issued by the regulatory core.
+ *
+ * Returns one of the different reg request treatment values.
+ */
+static enum reg_request_treatment
+reg_process_hint_core(struct regulatory_request *core_request)
+{
+
+       core_request->intersect = false;
+       core_request->processed = false;
+
+       reg_update_last_request(core_request);
 
+       return reg_call_crda(core_request);
+}
+
+static enum reg_request_treatment
+__reg_process_hint_user(struct regulatory_request *user_request)
+{
+       struct regulatory_request *lr = get_last_request();
+
+       if (reg_request_cell_base(user_request))
+               return reg_ignore_cell_hint(user_request);
+
+       if (reg_request_cell_base(lr))
+               return REG_REQ_IGNORE;
+
+       if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
                return REG_REQ_INTERSECT;
-       case NL80211_REGDOM_SET_BY_USER:
-               if (reg_request_cell_base(pending_request))
-                       return reg_ignore_cell_hint(pending_request);
+       /*
+        * If the user knows better the user should set the regdom
+        * to their country before the IE is picked up
+        */
+       if (lr->initiator == NL80211_REGDOM_SET_BY_USER &&
+           lr->intersect)
+               return REG_REQ_IGNORE;
+       /*
+        * Process user requests only after previous user/driver/core
+        * requests have been processed
+        */
+       if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE ||
+            lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+            lr->initiator == NL80211_REGDOM_SET_BY_USER) &&
+           regdom_changes(lr->alpha2))
+               return REG_REQ_IGNORE;
 
-               if (reg_request_cell_base(lr))
-                       return REG_REQ_IGNORE;
+       if (!regdom_changes(user_request->alpha2))
+               return REG_REQ_ALREADY_SET;
 
-               if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
-                       return REG_REQ_INTERSECT;
-               /*
-                * If the user knows better the user should set the regdom
-                * to their country before the IE is picked up
-                */
-               if (lr->initiator == NL80211_REGDOM_SET_BY_USER &&
-                   lr->intersect)
-                       return REG_REQ_IGNORE;
-               /*
-                * Process user requests only after previous user/driver/core
-                * requests have been processed
-                */
-               if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE ||
-                    lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
-                    lr->initiator == NL80211_REGDOM_SET_BY_USER) &&
-                   regdom_changes(lr->alpha2))
-                       return REG_REQ_IGNORE;
+       return REG_REQ_OK;
+}
 
-               if (!regdom_changes(pending_request->alpha2))
-                       return REG_REQ_ALREADY_SET;
+/**
+ * reg_process_hint_user - process user regulatory requests
+ * @user_request: a pending user regulatory request
+ *
+ * The wireless subsystem can use this function to process
+ * a regulatory request initiated by userspace.
+ *
+ * Returns one of the different reg request treatment values.
+ */
+static enum reg_request_treatment
+reg_process_hint_user(struct regulatory_request *user_request)
+{
+       enum reg_request_treatment treatment;
 
-               return REG_REQ_OK;
+       treatment = __reg_process_hint_user(user_request);
+       if (treatment == REG_REQ_IGNORE ||
+           treatment == REG_REQ_ALREADY_SET) {
+               kfree(user_request);
+               return treatment;
        }
 
-       return REG_REQ_IGNORE;
+       user_request->intersect = treatment == REG_REQ_INTERSECT;
+       user_request->processed = false;
+
+       reg_update_last_request(user_request);
+
+       user_alpha2[0] = user_request->alpha2[0];
+       user_alpha2[1] = user_request->alpha2[1];
+
+       return reg_call_crda(user_request);
 }
 
-static void reg_set_request_processed(void)
+static enum reg_request_treatment
+__reg_process_hint_driver(struct regulatory_request *driver_request)
 {
-       bool need_more_processing = false;
        struct regulatory_request *lr = get_last_request();
 
-       lr->processed = true;
-
-       spin_lock(&reg_requests_lock);
-       if (!list_empty(&reg_requests_list))
-               need_more_processing = true;
-       spin_unlock(&reg_requests_lock);
+       if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) {
+               if (regdom_changes(driver_request->alpha2))
+                       return REG_REQ_OK;
+               return REG_REQ_ALREADY_SET;
+       }
 
-       if (lr->initiator == NL80211_REGDOM_SET_BY_USER)
-               cancel_delayed_work(&reg_timeout);
+       /*
+        * This would happen if you unplug and plug your card
+        * back in or if you add a new device for which the previously
+        * loaded card also agrees on the regulatory domain.
+        */
+       if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+           !regdom_changes(driver_request->alpha2))
+               return REG_REQ_ALREADY_SET;
 
-       if (need_more_processing)
-               schedule_work(&reg_work);
+       return REG_REQ_INTERSECT;
 }
 
 /**
- * __regulatory_hint - hint to the wireless core a regulatory domain
- * @wiphy: if the hint comes from country information from an AP, this
- *     is required to be set to the wiphy that received the information
- * @pending_request: the regulatory request currently being processed
+ * reg_process_hint_driver - process driver regulatory requests
+ * @driver_request: a pending driver regulatory request
  *
- * The Wireless subsystem can use this function to hint to the wireless core
- * what it believes should be the current regulatory domain.
+ * The wireless subsystem can use this function to process
+ * a regulatory request issued by an 802.11 driver.
  *
  * Returns one of the different reg request treatment values.
  */
 static enum reg_request_treatment
-__regulatory_hint(struct wiphy *wiphy,
-                 struct regulatory_request *pending_request)
+reg_process_hint_driver(struct wiphy *wiphy,
+                       struct regulatory_request *driver_request)
 {
        const struct ieee80211_regdomain *regd;
-       bool intersect = false;
        enum reg_request_treatment treatment;
-       struct regulatory_request *lr;
 
-       treatment = get_reg_request_treatment(wiphy, pending_request);
+       treatment = __reg_process_hint_driver(driver_request);
 
        switch (treatment) {
-       case REG_REQ_INTERSECT:
-               if (pending_request->initiator ==
-                   NL80211_REGDOM_SET_BY_DRIVER) {
-                       regd = reg_copy_regd(get_cfg80211_regdom());
-                       if (IS_ERR(regd)) {
-                               kfree(pending_request);
-                               return PTR_ERR(regd);
-                       }
-                       rcu_assign_pointer(wiphy->regd, regd);
-               }
-               intersect = true;
-               break;
        case REG_REQ_OK:
                break;
-       default:
-               /*
-                * If the regulatory domain being requested by the
-                * driver has already been set just copy it to the
-                * wiphy
-                */
-               if (treatment == REG_REQ_ALREADY_SET &&
-                   pending_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) {
-                       regd = reg_copy_regd(get_cfg80211_regdom());
-                       if (IS_ERR(regd)) {
-                               kfree(pending_request);
-                               return REG_REQ_IGNORE;
-                       }
-                       treatment = REG_REQ_ALREADY_SET;
-                       rcu_assign_pointer(wiphy->regd, regd);
-                       goto new_request;
-               }
-               kfree(pending_request);
+       case REG_REQ_IGNORE:
+               kfree(driver_request);
                return treatment;
+       case REG_REQ_INTERSECT:
+               /* fall through */
+       case REG_REQ_ALREADY_SET:
+               regd = reg_copy_regd(get_cfg80211_regdom());
+               if (IS_ERR(regd)) {
+                       kfree(driver_request);
+                       return REG_REQ_IGNORE;
+               }
+               rcu_assign_pointer(wiphy->regd, regd);
        }
 
-new_request:
-       lr = get_last_request();
-       if (lr != &core_request_world && lr)
-               kfree_rcu(lr, rcu_head);
 
-       pending_request->intersect = intersect;
-       pending_request->processed = false;
-       rcu_assign_pointer(last_request, pending_request);
-       lr = pending_request;
+       driver_request->intersect = treatment == REG_REQ_INTERSECT;
+       driver_request->processed = false;
 
-       pending_request = NULL;
+       reg_update_last_request(driver_request);
 
-       if (lr->initiator == NL80211_REGDOM_SET_BY_USER) {
-               user_alpha2[0] = lr->alpha2[0];
-               user_alpha2[1] = lr->alpha2[1];
+       /*
+        * Since CRDA will not be called in this case as we already
+        * have applied the requested regulatory domain before we just
+        * inform userspace we have processed the request
+        */
+       if (treatment == REG_REQ_ALREADY_SET) {
+               nl80211_send_reg_change_event(driver_request);
+               reg_set_request_processed();
+               return treatment;
        }
 
-       /* When r == REG_REQ_INTERSECT we do need to call CRDA */
-       if (treatment != REG_REQ_OK && treatment != REG_REQ_INTERSECT) {
+       return reg_call_crda(driver_request);
+}
+
+static enum reg_request_treatment
+__reg_process_hint_country_ie(struct wiphy *wiphy,
+                             struct regulatory_request *country_ie_request)
+{
+       struct wiphy *last_wiphy = NULL;
+       struct regulatory_request *lr = get_last_request();
+
+       if (reg_request_cell_base(lr)) {
+               /* Trust a Cell base station over the AP's country IE */
+               if (regdom_changes(country_ie_request->alpha2))
+                       return REG_REQ_IGNORE;
+               return REG_REQ_ALREADY_SET;
+       } else {
+               if (wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_IGNORE)
+                       return REG_REQ_IGNORE;
+       }
+
+       if (unlikely(!is_an_alpha2(country_ie_request->alpha2)))
+               return -EINVAL;
+
+       if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)
+               return REG_REQ_OK;
+
+       last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
+
+       if (last_wiphy != wiphy) {
                /*
-                * Since CRDA will not be called in this case as we already
-                * have applied the requested regulatory domain before we just
-                * inform userspace we have processed the request
+                * Two cards with two APs claiming different
+                * Country IE alpha2s. We could
+                * intersect them, but that seems unlikely
+                * to be correct. Reject second one for now.
                 */
-               if (treatment == REG_REQ_ALREADY_SET) {
-                       nl80211_send_reg_change_event(lr);
-                       reg_set_request_processed();
-               }
-               return treatment;
+               if (regdom_changes(country_ie_request->alpha2))
+                       return REG_REQ_IGNORE;
+               return REG_REQ_ALREADY_SET;
        }
+       /*
+        * Two consecutive Country IE hints on the same wiphy.
+        * This should be picked up early by the driver/stack
+        */
+       if (WARN_ON(regdom_changes(country_ie_request->alpha2)))
+               return REG_REQ_OK;
+       return REG_REQ_ALREADY_SET;
+}
+
+/**
+ * reg_process_hint_country_ie - process regulatory requests from country IEs
+ * @country_ie_request: a regulatory request from a country IE
+ *
+ * The wireless subsystem can use this function to process
+ * a regulatory request issued by a country Information Element.
+ *
+ * Returns one of the different reg request treatment values.
+ */
+static enum reg_request_treatment
+reg_process_hint_country_ie(struct wiphy *wiphy,
+                           struct regulatory_request *country_ie_request)
+{
+       enum reg_request_treatment treatment;
+
+       treatment = __reg_process_hint_country_ie(wiphy, country_ie_request);
 
-       if (call_crda(lr->alpha2))
+       switch (treatment) {
+       case REG_REQ_OK:
+               break;
+       case REG_REQ_IGNORE:
+               /* fall through */
+       case REG_REQ_ALREADY_SET:
+               kfree(country_ie_request);
+               return treatment;
+       case REG_REQ_INTERSECT:
+               kfree(country_ie_request);
+               /*
+                * This doesn't happen yet, not sure we
+                * ever want to support it for this case.
+                */
+               WARN_ONCE(1, "Unexpected intersection for country IEs");
                return REG_REQ_IGNORE;
-       return REG_REQ_OK;
+       }
+
+       country_ie_request->intersect = false;
+       country_ie_request->processed = false;
+
+       reg_update_last_request(country_ie_request);
+
+       return reg_call_crda(country_ie_request);
 }
 
 /* This processes *all* regulatory hints */
-static void reg_process_hint(struct regulatory_request *reg_request,
-                            enum nl80211_reg_initiator reg_initiator)
+static void reg_process_hint(struct regulatory_request *reg_request)
 {
        struct wiphy *wiphy = NULL;
+       enum reg_request_treatment treatment;
 
        if (WARN_ON(!reg_request->alpha2))
                return;
@@ -1546,23 +1662,37 @@ static void reg_process_hint(struct regulatory_request *reg_request,
        if (reg_request->wiphy_idx != WIPHY_IDX_INVALID)
                wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
 
-       if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) {
+       if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) {
                kfree(reg_request);
                return;
        }
 
-       switch (__regulatory_hint(wiphy, reg_request)) {
-       case REG_REQ_ALREADY_SET:
-               /* This is required so that the orig_* parameters are saved */
-               if (wiphy && wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
-                       wiphy_update_regulatory(wiphy, reg_initiator);
+       switch (reg_request->initiator) {
+       case NL80211_REGDOM_SET_BY_CORE:
+               reg_process_hint_core(reg_request);
+               return;
+       case NL80211_REGDOM_SET_BY_USER:
+               treatment = reg_process_hint_user(reg_request);
+               if (treatment == REG_REQ_OK ||
+                   treatment == REG_REQ_ALREADY_SET)
+                       return;
+               schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
+               return;
+       case NL80211_REGDOM_SET_BY_DRIVER:
+               treatment = reg_process_hint_driver(wiphy, reg_request);
                break;
-       default:
-               if (reg_initiator == NL80211_REGDOM_SET_BY_USER)
-                       schedule_delayed_work(&reg_timeout,
-                                             msecs_to_jiffies(3142));
+       case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+               treatment = reg_process_hint_country_ie(wiphy, reg_request);
                break;
+       default:
+               WARN(1, "invalid initiator %d\n", reg_request->initiator);
+               return;
        }
+
+       /* This is required so that the orig_* parameters are saved */
+       if (treatment == REG_REQ_ALREADY_SET && wiphy &&
+           wiphy->regulatory_flags & REGULATORY_STRICT_REG)
+               wiphy_update_regulatory(wiphy, reg_request->initiator);
 }
 
 /*
@@ -1596,7 +1726,7 @@ static void reg_process_pending_hints(void)
 
        spin_unlock(&reg_requests_lock);
 
-       reg_process_hint(reg_request, reg_request->initiator);
+       reg_process_hint(reg_request);
 }
 
 /* Processes beacon hints -- this has nothing to do with country IEs */
@@ -1888,7 +2018,7 @@ static void restore_regulatory_settings(bool reset_user)
        world_alpha2[1] = cfg80211_world_regdom->alpha2[1];
 
        list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
-               if (rdev->wiphy.flags & WIPHY_FLAG_CUSTOM_REGULATORY)
+               if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG)
                        restore_custom_reg_settings(&rdev->wiphy);
        }
 
@@ -2016,7 +2146,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
        }
 }
 
-bool reg_supported_dfs_region(u8 dfs_region)
+bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region)
 {
        switch (dfs_region) {
        case NL80211_DFS_UNSET:
@@ -2031,27 +2161,6 @@ bool reg_supported_dfs_region(u8 dfs_region)
        }
 }
 
-static void print_dfs_region(u8 dfs_region)
-{
-       if (!dfs_region)
-               return;
-
-       switch (dfs_region) {
-       case NL80211_DFS_FCC:
-               pr_info(" DFS Master region FCC");
-               break;
-       case NL80211_DFS_ETSI:
-               pr_info(" DFS Master region ETSI");
-               break;
-       case NL80211_DFS_JP:
-               pr_info(" DFS Master region JP");
-               break;
-       default:
-               pr_info(" DFS Master region Unknown");
-               break;
-       }
-}
-
 static void print_regdomain(const struct ieee80211_regdomain *rd)
 {
        struct regulatory_request *lr = get_last_request();
@@ -2083,7 +2192,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
                }
        }
 
-       print_dfs_region(rd->dfs_region);
+       pr_info(" DFS Master region: %s", reg_dfs_region_str(rd->dfs_region));
        print_rd_rules(rd);
 }
 
@@ -2093,48 +2202,60 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd)
        print_rd_rules(rd);
 }
 
-/* Takes ownership of rd only if it doesn't fail */
-static int __set_regdom(const struct ieee80211_regdomain *rd)
+static int reg_set_rd_core(const struct ieee80211_regdomain *rd)
+{
+       if (!is_world_regdom(rd->alpha2))
+               return -EINVAL;
+       update_world_regdomain(rd);
+       return 0;
+}
+
+static int reg_set_rd_user(const struct ieee80211_regdomain *rd,
+                          struct regulatory_request *user_request)
 {
-       const struct ieee80211_regdomain *regd;
        const struct ieee80211_regdomain *intersected_rd = NULL;
-       struct wiphy *request_wiphy;
-       struct regulatory_request *lr = get_last_request();
 
-       /* Some basic sanity checks first */
+       if (is_world_regdom(rd->alpha2))
+               return -EINVAL;
+
+       if (!regdom_changes(rd->alpha2))
+               return -EALREADY;
 
-       if (!reg_is_valid_request(rd->alpha2))
+       if (!is_valid_rd(rd)) {
+               pr_err("Invalid regulatory domain detected:\n");
+               print_regdomain_info(rd);
                return -EINVAL;
+       }
 
-       if (is_world_regdom(rd->alpha2)) {
-               update_world_regdomain(rd);
+       if (!user_request->intersect) {
+               reset_regdomains(false, rd);
                return 0;
        }
 
-       if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&
-           !is_unknown_alpha2(rd->alpha2))
+       intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());
+       if (!intersected_rd)
                return -EINVAL;
 
-       /*
-        * Lets only bother proceeding on the same alpha2 if the current
-        * rd is non static (it means CRDA was present and was used last)
-        * and the pending request came in from a country IE
-        */
-       if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-               /*
-                * If someone else asked us to change the rd lets only bother
-                * checking if the alpha2 changes if CRDA was already called
-                */
-               if (!regdom_changes(rd->alpha2))
-                       return -EALREADY;
-       }
+       kfree(rd);
+       rd = NULL;
+       reset_regdomains(false, intersected_rd);
 
-       /*
-        * Now lets set the regulatory domain, update all driver channels
-        * and finally inform them of what we have done, in case they want
-        * to review or adjust their own settings based on their own
-        * internal EEPROM data
-        */
+       return 0;
+}
+
+static int reg_set_rd_driver(const struct ieee80211_regdomain *rd,
+                            struct regulatory_request *driver_request)
+{
+       const struct ieee80211_regdomain *regd;
+       const struct ieee80211_regdomain *intersected_rd = NULL;
+       const struct ieee80211_regdomain *tmp;
+       struct wiphy *request_wiphy;
+
+       if (is_world_regdom(rd->alpha2))
+               return -EINVAL;
+
+       if (!regdom_changes(rd->alpha2))
+               return -EALREADY;
 
        if (!is_valid_rd(rd)) {
                pr_err("Invalid regulatory domain detected:\n");
@@ -2142,29 +2263,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                return -EINVAL;
        }
 
-       request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
-       if (!request_wiphy &&
-           (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
-            lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
+       request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx);
+       if (!request_wiphy) {
                schedule_delayed_work(&reg_timeout, 0);
                return -ENODEV;
        }
 
-       if (!lr->intersect) {
-               if (lr->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
-                       reset_regdomains(false, rd);
-                       return 0;
-               }
-
-               /*
-                * For a driver hint, lets copy the regulatory domain the
-                * driver wanted to the wiphy to deal with conflicts
-                */
-
-               /*
-                * Userspace could have sent two replies with only
-                * one kernel request.
-                */
+       if (!driver_request->intersect) {
                if (request_wiphy->regd)
                        return -EALREADY;
 
@@ -2177,38 +2282,59 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                return 0;
        }
 
-       /* Intersection requires a bit more work */
+       intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());
+       if (!intersected_rd)
+               return -EINVAL;
 
-       if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-               intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());
-               if (!intersected_rd)
-                       return -EINVAL;
+       /*
+        * We can trash what CRDA provided now.
+        * However if a driver requested this specific regulatory
+        * domain we keep it for its private use
+        */
+       tmp = get_wiphy_regdom(request_wiphy);
+       rcu_assign_pointer(request_wiphy->regd, rd);
+       rcu_free_regdom(tmp);
 
-               /*
-                * We can trash what CRDA provided now.
-                * However if a driver requested this specific regulatory
-                * domain we keep it for its private use
-                */
-               if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER) {
-                       const struct ieee80211_regdomain *tmp;
+       rd = NULL;
 
-                       tmp = get_wiphy_regdom(request_wiphy);
-                       rcu_assign_pointer(request_wiphy->regd, rd);
-                       rcu_free_regdom(tmp);
-               } else {
-                       kfree(rd);
-               }
+       reset_regdomains(false, intersected_rd);
 
-               rd = NULL;
+       return 0;
+}
 
-               reset_regdomains(false, intersected_rd);
+static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
+                                struct regulatory_request *country_ie_request)
+{
+       struct wiphy *request_wiphy;
 
-               return 0;
+       if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&
+           !is_unknown_alpha2(rd->alpha2))
+               return -EINVAL;
+
+       /*
+        * Lets only bother proceeding on the same alpha2 if the current
+        * rd is non static (it means CRDA was present and was used last)
+        * and the pending request came in from a country IE
+        */
+
+       if (!is_valid_rd(rd)) {
+               pr_err("Invalid regulatory domain detected:\n");
+               print_regdomain_info(rd);
+               return -EINVAL;
        }
 
-       return -EINVAL;
-}
+       request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx);
+       if (!request_wiphy) {
+               schedule_delayed_work(&reg_timeout, 0);
+               return -ENODEV;
+       }
+
+       if (country_ie_request->intersect)
+               return -EINVAL;
 
+       reset_regdomains(false, rd);
+       return 0;
+}
 
 /*
  * Use this call to set the current regulatory domain. Conflicts with
@@ -2220,10 +2346,32 @@ int set_regdom(const struct ieee80211_regdomain *rd)
        struct regulatory_request *lr;
        int r;
 
+       if (!reg_is_valid_request(rd->alpha2)) {
+               kfree(rd);
+               return -EINVAL;
+       }
+
        lr = get_last_request();
 
        /* Note that this doesn't update the wiphys, this is done below */
-       r = __set_regdom(rd);
+       switch (lr->initiator) {
+       case NL80211_REGDOM_SET_BY_CORE:
+               r = reg_set_rd_core(rd);
+               break;
+       case NL80211_REGDOM_SET_BY_USER:
+               r = reg_set_rd_user(rd, lr);
+               break;
+       case NL80211_REGDOM_SET_BY_DRIVER:
+               r = reg_set_rd_driver(rd, lr);
+               break;
+       case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+               r = reg_set_rd_country_ie(rd, lr);
+               break;
+       default:
+               WARN(1, "invalid initiator %d\n", lr->initiator);
+               return -EINVAL;
+       }
+
        if (r) {
                if (r == -EALREADY)
                        reg_set_request_processed();
index 9677e3c13da98da5b00f34e112b0562512b6fc65..cc4c2c0a67236cd2801f954e0a8e15dc4b5adea5 100644 (file)
@@ -18,8 +18,9 @@
 
 extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
 
+bool reg_is_valid_request(const char *alpha2);
 bool is_world_regdom(const char *alpha2);
-bool reg_supported_dfs_region(u8 dfs_region);
+bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region);
 
 int regulatory_hint_user(const char *alpha2,
                         enum nl80211_user_reg_hint_type user_reg_hint_type);
index ba5f0d6614d5d4cee4d08c609bb192dd501f0b34..f7aa7a72d9bc928aa7d24153d709e13634773b06 100644 (file)
@@ -1653,9 +1653,8 @@ TRACE_EVENT(rdev_cancel_remain_on_channel,
 
 TRACE_EVENT(rdev_mgmt_tx,
        TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
-                struct ieee80211_channel *chan, bool offchan,
-                unsigned int wait, bool no_cck, bool dont_wait_for_ack),
-       TP_ARGS(wiphy, wdev, chan, offchan, wait, no_cck, dont_wait_for_ack),
+                struct cfg80211_mgmt_tx_params *params),
+       TP_ARGS(wiphy, wdev, params),
        TP_STRUCT__entry(
                WIPHY_ENTRY
                WDEV_ENTRY
@@ -1668,11 +1667,11 @@ TRACE_EVENT(rdev_mgmt_tx,
        TP_fast_assign(
                WIPHY_ASSIGN;
                WDEV_ASSIGN;
-               CHAN_ASSIGN(chan);
-               __entry->offchan = offchan;
-               __entry->wait = wait;
-               __entry->no_cck = no_cck;
-               __entry->dont_wait_for_ack = dont_wait_for_ack;
+               CHAN_ASSIGN(params->chan);
+               __entry->offchan = params->offchan;
+               __entry->wait = params->wait;
+               __entry->no_cck = params->no_cck;
+               __entry->dont_wait_for_ack = params->dont_wait_for_ack;
        ),
        TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", offchan: %s,"
                  " wait: %u, no cck: %s, dont wait for ack: %s",