diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 05:04:47 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 05:04:47 +0100 |
commit | 3b59bf081622b6446db77ad06c93fe23677bc533 (patch) | |
tree | 3f4bb5a27c90cc86994a1f6d3c53fbf9208003cb /drivers/net/wireless/ath | |
parent | Merge branch 'for-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq (diff) | |
parent | Fix pppol2tp getsockname() (diff) | |
download | linux-3b59bf081622b6446db77ad06c93fe23677bc533.tar.xz linux-3b59bf081622b6446db77ad06c93fe23677bc533.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking merge from David Miller:
"1) Move ixgbe driver over to purely page based buffering on receive.
From Alexander Duyck.
2) Add receive packet steering support to e1000e, from Bruce Allan.
3) Convert TCP MD5 support over to RCU, from Eric Dumazet.
4) Reduce cpu usage in handling out-of-order TCP packets on modern
systems, also from Eric Dumazet.
5) Support the IP{,V6}_UNICAST_IF socket options, making the wine
folks happy, from Erich Hoover.
6) Support VLAN trunking from guests in hyperv driver, from Haiyang
Zhang.
7) Support byte-queue-limtis in r8169, from Igor Maravic.
8) Outline code intended for IP_RECVTOS in IP_PKTOPTIONS existed but
was never properly implemented, Jiri Benc fixed that.
9) 64-bit statistics support in r8169 and 8139too, from Junchang Wang.
10) Support kernel side dump filtering by ctmark in netfilter
ctnetlink, from Pablo Neira Ayuso.
11) Support byte-queue-limits in gianfar driver, from Paul Gortmaker.
12) Add new peek socket options to assist with socket migration, from
Pavel Emelyanov.
13) Add sch_plug packet scheduler whose queue is controlled by
userland daemons using explicit freeze and release commands. From
Shriram Rajagopalan.
14) Fix FCOE checksum offload handling on transmit, from Yi Zou."
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1846 commits)
Fix pppol2tp getsockname()
Remove printk from rds_sendmsg
ipv6: fix incorrent ipv6 ipsec packet fragment
cpsw: Hook up default ndo_change_mtu.
net: qmi_wwan: fix build error due to cdc-wdm dependecy
netdev: driver: ethernet: Add TI CPSW driver
netdev: driver: ethernet: add cpsw address lookup engine support
phy: add am79c874 PHY support
mlx4_core: fix race on comm channel
bonding: send igmp report for its master
fs_enet: Add MPC5125 FEC support and PHY interface selection
net: bpf_jit: fix BPF_S_LDX_B_MSH compilation
net: update the usage of CHECKSUM_UNNECESSARY
fcoe: use CHECKSUM_UNNECESSARY instead of CHECKSUM_PARTIAL on tx
net: do not do gso for CHECKSUM_UNNECESSARY in netif_needs_gso
ixgbe: Fix issues with SR-IOV loopback when flow control is disabled
net/hyperv: Fix the code handling tx busy
ixgbe: fix namespace issues when FCoE/DCB is not enabled
rtlwifi: Remove unused ETH_ADDR_LEN defines
igbvf: Use ETH_ALEN
...
Fix up fairly trivial conflicts in drivers/isdn/gigaset/interface.c and
drivers/net/usb/{Kconfig,qmi_wwan.c} as per David.
Diffstat (limited to 'drivers/net/wireless/ath')
90 files changed, 5522 insertions, 6902 deletions
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index efc01110dc34..c54b7d37bff1 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -174,28 +174,24 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry); void ath_hw_cycle_counters_update(struct ath_common *common); int32_t ath_hw_get_listen_time(struct ath_common *common); -extern __printf(2, 3) void ath_printk(const char *level, const char *fmt, ...); - -#define _ath_printk(level, common, fmt, ...) \ -do { \ - __always_unused struct ath_common *unused = common; \ - ath_printk(level, fmt, ##__VA_ARGS__); \ -} while (0) +__printf(3, 4) +void ath_printk(const char *level, const struct ath_common *common, + const char *fmt, ...); #define ath_emerg(common, fmt, ...) \ - _ath_printk(KERN_EMERG, common, fmt, ##__VA_ARGS__) + ath_printk(KERN_EMERG, common, fmt, ##__VA_ARGS__) #define ath_alert(common, fmt, ...) \ - _ath_printk(KERN_ALERT, common, fmt, ##__VA_ARGS__) + ath_printk(KERN_ALERT, common, fmt, ##__VA_ARGS__) #define ath_crit(common, fmt, ...) \ - _ath_printk(KERN_CRIT, common, fmt, ##__VA_ARGS__) + ath_printk(KERN_CRIT, common, fmt, ##__VA_ARGS__) #define ath_err(common, fmt, ...) \ - _ath_printk(KERN_ERR, common, fmt, ##__VA_ARGS__) + ath_printk(KERN_ERR, common, fmt, ##__VA_ARGS__) #define ath_warn(common, fmt, ...) \ - _ath_printk(KERN_WARNING, common, fmt, ##__VA_ARGS__) + ath_printk(KERN_WARNING, common, fmt, ##__VA_ARGS__) #define ath_notice(common, fmt, ...) \ - _ath_printk(KERN_NOTICE, common, fmt, ##__VA_ARGS__) + ath_printk(KERN_NOTICE, common, fmt, ##__VA_ARGS__) #define ath_info(common, fmt, ...) \ - _ath_printk(KERN_INFO, common, fmt, ##__VA_ARGS__) + ath_printk(KERN_INFO, common, fmt, ##__VA_ARGS__) /** * enum ath_debug_level - atheros wireless debug level @@ -256,7 +252,7 @@ enum ATH_DEBUG { #define ath_dbg(common, dbg_mask, fmt, ...) \ do { \ if ((common)->debug_mask & ATH_DBG_##dbg_mask) \ - _ath_printk(KERN_DEBUG, common, fmt, ##__VA_ARGS__); \ + ath_printk(KERN_DEBUG, common, fmt, ##__VA_ARGS__); \ } while (0) #define ATH_DBG_WARN(foo, arg...) WARN(foo, arg) diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index ee7ea572b065..8faa129da5a0 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -140,23 +140,23 @@ static int ath_ahb_probe(struct platform_device *pdev) if (bcfg->devid >= AR5K_SREV_AR2315_R6) { /* Enable WMAC AHB arbitration */ - reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL); + reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL); reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN; - __raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL); + iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL); /* Enable global WMAC swapping */ - reg = __raw_readl((void __iomem *) AR5K_AR2315_BYTESWAP); + reg = ioread32((void __iomem *) AR5K_AR2315_BYTESWAP); reg |= AR5K_AR2315_BYTESWAP_WMAC; - __raw_writel(reg, (void __iomem *) AR5K_AR2315_BYTESWAP); + iowrite32(reg, (void __iomem *) AR5K_AR2315_BYTESWAP); } else { /* Enable WMAC DMA access (assuming 5312 or 231x*/ /* TODO: check other platforms */ - reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE); + reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE); if (to_platform_device(ah->dev)->id == 0) reg |= AR5K_AR5312_ENABLE_WLAN0; else reg |= AR5K_AR5312_ENABLE_WLAN1; - __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE); + iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE); /* * On a dual-band AR5312, the multiband radio is only @@ -203,17 +203,17 @@ static int ath_ahb_remove(struct platform_device *pdev) if (bcfg->devid >= AR5K_SREV_AR2315_R6) { /* Disable WMAC AHB arbitration */ - reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL); + reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL); reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN; - __raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL); + iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL); } else { /*Stop DMA access */ - reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE); + reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE); if (to_platform_device(ah->dev)->id == 0) reg &= ~AR5K_AR5312_ENABLE_WLAN0; else reg &= ~AR5K_AR5312_ENABLE_WLAN1; - __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE); + iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE); } ath5k_deinit_ah(ah); diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c index bf674161a217..35e93704c4ef 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -257,7 +257,7 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, "beacon RSSI high"); /* only OFDM: beacon RSSI is high, we can disable ODFM weak * signal detection */ - if (ofdm_trigger && as->ofdm_weak_sig == true) { + if (ofdm_trigger && as->ofdm_weak_sig) { ath5k_ani_set_ofdm_weak_signal_detection(ah, false); ath5k_ani_set_spur_immunity_level(ah, 0); return; @@ -272,7 +272,7 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, * but can raise firstep level */ ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "beacon RSSI mid"); - if (ofdm_trigger && as->ofdm_weak_sig == false) + if (ofdm_trigger && !as->ofdm_weak_sig) ath5k_ani_set_ofdm_weak_signal_detection(ah, true); if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL) ath5k_ani_set_firstep_level(ah, as->firstep_level + 1); @@ -282,7 +282,7 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, * detect and zero firstep level to maximize CCK sensitivity */ ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "beacon RSSI low, 2GHz"); - if (ofdm_trigger && as->ofdm_weak_sig == true) + if (ofdm_trigger && as->ofdm_weak_sig) ath5k_ani_set_ofdm_weak_signal_detection(ah, false); if (as->firstep_level > 0) ath5k_ani_set_firstep_level(ah, 0); @@ -326,7 +326,7 @@ ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) } else if (rssi > ATH5K_ANI_RSSI_THR_LOW) { /* beacon RSSI is mid-range: turn on ODFM weak signal * detection and next, lower firstep level */ - if (as->ofdm_weak_sig == false) { + if (!as->ofdm_weak_sig) { ath5k_ani_set_ofdm_weak_signal_detection(ah, true); return; diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index c2b2518c2ecd..8d434b8f5855 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1320,6 +1320,7 @@ struct ath5k_hw { struct ieee80211_vif *bslot[ATH_BCBUF]; u16 num_ap_vifs; u16 num_adhoc_vifs; + u16 num_mesh_vifs; unsigned int bhalq, /* SW q for outgoing beacons */ bmisscount, /* missed beacon transmits */ bintval, /* beacon interval in TU */ @@ -1656,12 +1657,12 @@ static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg) static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg) { - return __raw_readl(ath5k_ahb_reg(ah, reg)); + return ioread32(ath5k_ahb_reg(ah, reg)); } static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg) { - __raw_writel(val, ath5k_ahb_reg(ah, reg)); + iowrite32(val, ath5k_ahb_reg(ah, reg)); } #else diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index d366dadcf86e..0e643b016b32 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -80,7 +80,7 @@ static bool modparam_fastchanswitch; module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO); MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios."); -static int ath5k_modparam_no_hw_rfkill_switch; +static bool ath5k_modparam_no_hw_rfkill_switch; module_param_named(no_hw_rfkill_switch, ath5k_modparam_no_hw_rfkill_switch, bool, S_IRUGO); MODULE_PARM_DESC(no_hw_rfkill_switch, "Ignore the GPIO RFKill switch state"); @@ -1867,7 +1867,8 @@ ath5k_beacon_send(struct ath5k_hw *ah) ah->bmisscount = 0; } - if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs > 1) || + if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs + + ah->num_mesh_vifs > 1) || ah->opmode == NL80211_IFTYPE_MESH_POINT) { u64 tsf = ath5k_hw_get_tsf64(ah); u32 tsftu = TSF_TO_TU(tsf); @@ -1952,7 +1953,8 @@ ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf) u64 hw_tsf; intval = ah->bintval & AR5K_BEACON_PERIOD; - if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs > 1) { + if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs + + ah->num_mesh_vifs > 1) { intval /= ATH_BCBUF; /* staggered multi-bss beacons */ if (intval < 15) ATH5K_WARN(ah, "intval %u is too low, min 15\n", @@ -2330,15 +2332,6 @@ ath5k_calibrate_work(struct work_struct *work) "got new rfgain, resetting\n"); ieee80211_queue_work(ah->hw, &ah->reset_work); } - - /* TODO: On full calibration we should stop TX here, - * so that it doesn't interfere (mostly due to gain_f - * calibration that messes with tx packets -see phy.c). - * - * NOTE: Stopping the queues from above is not enough - * to stop TX but saves us from disconecting (at least - * we don't lose packets). */ - ieee80211_stop_queues(ah->hw); } else ah->ah_cal_mask |= AR5K_CALIBRATION_SHORT; @@ -2353,10 +2346,9 @@ ath5k_calibrate_work(struct work_struct *work) ah->curchan->center_freq)); /* Clear calibration flags */ - if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) { - ieee80211_wake_queues(ah->hw); + if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; - } else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT) + else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT) ah->ah_cal_mask &= ~AR5K_CALIBRATION_SHORT; } @@ -2442,6 +2434,9 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); + /* SW support for IBSS_RSN is provided by mac80211 */ + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + /* both antennas can be configured as RX or TX */ hw->wiphy->available_antennas_tx = 0x3; hw->wiphy->available_antennas_rx = 0x3; diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 6ed4c0717e3e..5c5329955414 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -134,6 +134,8 @@ ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) ah->num_ap_vifs++; else if (avf->opmode == NL80211_IFTYPE_ADHOC) ah->num_adhoc_vifs++; + else if (avf->opmode == NL80211_IFTYPE_MESH_POINT) + ah->num_mesh_vifs++; } /* Any MAC address is fine, all others are included through the @@ -175,6 +177,8 @@ ath5k_remove_interface(struct ieee80211_hw *hw, ah->num_ap_vifs--; else if (avf->opmode == NL80211_IFTYPE_ADHOC) ah->num_adhoc_vifs--; + else if (avf->opmode == NL80211_IFTYPE_MESH_POINT) + ah->num_mesh_vifs--; ath5k_update_bssid_mask_and_opmode(ah, NULL); mutex_unlock(&ah->lock); @@ -483,6 +487,14 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (ath5k_modparam_nohwcrypt) return -EOPNOTSUPP; + if (vif->type == NL80211_IFTYPE_ADHOC && + (key->cipher == WLAN_CIPHER_SUITE_TKIP || + key->cipher == WLAN_CIPHER_SUITE_CCMP) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + /* don't program group keys when using IBSS_RSN */ + return -EOPNOTSUPP; + } + switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index e1f8613426a9..3a2845489a1b 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1871,31 +1871,15 @@ ath5k_hw_phy_calibrate(struct ath5k_hw *ah, ret = 0; } - /* On full calibration do an AGC calibration and - * request a PAPD probe for gainf calibration if - * needed */ - if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) { - - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, - AR5K_PHY_AGCCTL_CAL); - - ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, - AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF, - 0, false); - if (ret) { - ATH5K_ERR(ah, - "gain calibration timeout (%uMHz)\n", - channel->center_freq); - } - - if ((ah->ah_radio == AR5K_RF5111 || - ah->ah_radio == AR5K_RF5112) - && (channel->hw_value != AR5K_MODE_11B)) - ath5k_hw_request_rfgain_probe(ah); - } - - /* Update noise floor - * XXX: Only do this after AGC calibration */ + /* On full calibration request a PAPD probe for + * gainf calibration if needed */ + if ((ah->ah_cal_mask & AR5K_CALIBRATION_FULL) && + (ah->ah_radio == AR5K_RF5111 || + ah->ah_radio == AR5K_RF5112) && + channel->hw_value != AR5K_MODE_11B) + ath5k_hw_request_rfgain_probe(ah); + + /* Update noise floor */ if (!(ah->ah_cal_mask & AR5K_CALIBRATION_NF)) ath5k_hw_update_noise_floor(ah); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 250db40b751d..200f165c0c6d 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -473,14 +473,14 @@ ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) } /* Put BB/MAC into reset */ - regval = __raw_readl(reg); - __raw_writel(regval | val, reg); - regval = __raw_readl(reg); + regval = ioread32(reg); + iowrite32(regval | val, reg); + regval = ioread32(reg); usleep_range(100, 150); /* Bring BB/MAC out of reset */ - __raw_writel(regval & ~val, reg); - regval = __raw_readl(reg); + iowrite32(regval & ~val, reg); + regval = ioread32(reg); /* * Reset configuration register (for hw byte-swap). Note that this diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig index 3d5f8be20eac..d755a5e7ed20 100644 --- a/drivers/net/wireless/ath/ath6kl/Kconfig +++ b/drivers/net/wireless/ath/ath6kl/Kconfig @@ -1,12 +1,29 @@ config ATH6KL - tristate "Atheros ath6kl support" + tristate "Atheros mobile chipsets support" + +config ATH6KL_SDIO + tristate "Atheros ath6kl SDIO support" + depends on ATH6KL depends on MMC depends on CFG80211 ---help--- This module adds support for wireless adapters based on - Atheros AR6003 chipset running over SDIO. If you choose to - build it as a module, it will be called ath6kl. Pls note - that AR6002 and AR6001 are not supported by this driver. + Atheros AR6003 and AR6004 chipsets running over SDIO. If you + choose to build it as a module, it will be called ath6kl_sdio. + Please note that AR6002 and AR6001 are not supported by this + driver. + +config ATH6KL_USB + tristate "Atheros ath6kl USB support" + depends on ATH6KL + depends on USB + depends on CFG80211 + depends on EXPERIMENTAL + ---help--- + This module adds support for wireless adapters based on + Atheros AR6004 chipset running over USB. This is still under + implementation and it isn't functional. If you choose to + build it as a module, it will be called ath6kl_usb. config ATH6KL_DEBUG bool "Atheros ath6kl debugging" diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile index 707069303550..85746c3eb027 100644 --- a/drivers/net/wireless/ath/ath6kl/Makefile +++ b/drivers/net/wireless/ath/ath6kl/Makefile @@ -1,5 +1,6 @@ #------------------------------------------------------------------------------ -# Copyright (c) 2004-2010 Atheros Communications Inc. +# Copyright (c) 2004-2011 Atheros Communications Inc. +# Copyright (c) 2011-2012 Qualcomm Atheros, Inc. # All rights reserved. # # @@ -21,17 +22,21 @@ # Author(s): ="Atheros" #------------------------------------------------------------------------------ -obj-$(CONFIG_ATH6KL) := ath6kl.o -ath6kl-y += debug.o -ath6kl-y += hif.o -ath6kl-y += htc.o -ath6kl-y += bmi.o -ath6kl-y += cfg80211.o -ath6kl-y += init.o -ath6kl-y += main.o -ath6kl-y += txrx.o -ath6kl-y += wmi.o -ath6kl-y += sdio.o -ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o +obj-$(CONFIG_ATH6KL) += ath6kl_core.o +ath6kl_core-y += debug.o +ath6kl_core-y += hif.o +ath6kl_core-y += htc.o +ath6kl_core-y += bmi.o +ath6kl_core-y += cfg80211.o +ath6kl_core-y += init.o +ath6kl_core-y += main.o +ath6kl_core-y += txrx.o +ath6kl_core-y += wmi.o +ath6kl_core-y += core.o +ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o -ccflags-y += -D__CHECK_ENDIAN__ +obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o +ath6kl_sdio-y += sdio.o + +obj-$(CONFIG_ATH6KL_USB) += ath6kl_usb.o +ath6kl_usb-y += usb.o diff --git a/drivers/net/wireless/ath/ath6kl/bmi.c b/drivers/net/wireless/ath/ath6kl/bmi.c index bce3575c310a..334dbd834b3a 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.c +++ b/drivers/net/wireless/ath/ath6kl/bmi.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-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 @@ -57,8 +58,14 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, return ret; } - ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version, - sizeof(targ_info->version)); + if (ar->hif_type == ATH6KL_HIF_TYPE_USB) { + ret = ath6kl_hif_bmi_read(ar, (u8 *)targ_info, + sizeof(*targ_info)); + } else { + ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version, + sizeof(targ_info->version)); + } + if (ret) { ath6kl_err("Unable to recv target info: %d\n", ret); return ret; @@ -99,7 +106,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, } ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n", - targ_info->version, targ_info->type); + targ_info->version, targ_info->type); return 0; } @@ -186,7 +193,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) memset(ar->bmi.cmd_buf, 0, ar->bmi.max_data_size + header); ath6kl_dbg(ATH6KL_DBG_BMI, - "bmi write memory: addr: 0x%x, len: %d\n", addr, len); + "bmi write memory: addr: 0x%x, len: %d\n", addr, len); len_remain = len; while (len_remain) { @@ -428,7 +435,7 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len) memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len)); offset += sizeof(tx_len); memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain], - tx_len); + tx_len); offset += tx_len; ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); diff --git a/drivers/net/wireless/ath/ath6kl/bmi.h b/drivers/net/wireless/ath/ath6kl/bmi.h index f1ca6812456d..18fdd69e1f71 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.h +++ b/drivers/net/wireless/ath/ath6kl/bmi.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011 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 @@ -222,6 +223,29 @@ struct ath6kl_bmi_target_info { __le32 type; /* target type */ } __packed; +#define ath6kl_bmi_write_hi32(ar, item, val) \ + ({ \ + u32 addr; \ + __le32 v; \ + \ + addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \ + v = cpu_to_le32(val); \ + ath6kl_bmi_write(ar, addr, (u8 *) &v, sizeof(v)); \ + }) + +#define ath6kl_bmi_read_hi32(ar, item, val) \ + ({ \ + u32 addr, *check_type = val; \ + __le32 tmp; \ + int ret; \ + \ + (void) (check_type == val); \ + addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \ + ret = ath6kl_bmi_read(ar, addr, (u8 *) &tmp, 4); \ + *val = le32_to_cpu(tmp); \ + ret; \ + }) + int ath6kl_bmi_init(struct ath6kl *ar); void ath6kl_bmi_cleanup(struct ath6kl *ar); void ath6kl_bmi_reset(struct ath6kl *ar); diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 6c59a217b1a1..00d38952b5fb 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-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 @@ -15,6 +16,8 @@ */ #include <linux/moduleparam.h> +#include <linux/inetdevice.h> +#include <linux/export.h> #include "core.h" #include "cfg80211.h" @@ -22,10 +25,6 @@ #include "hif-ops.h" #include "testmode.h" -static unsigned int ath6kl_p2p; - -module_param(ath6kl_p2p, uint, 0644); - #define RATETAB_ENT(_rate, _rateid, _flags) { \ .bitrate = (_rate), \ .flags = (_flags), \ @@ -70,6 +69,10 @@ static struct ieee80211_rate ath6kl_rates[] = { #define ath6kl_g_rates (ath6kl_rates + 0) #define ath6kl_g_rates_size 12 +#define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ + IEEE80211_HT_CAP_SGI_20 | \ + IEEE80211_HT_CAP_SGI_40) + static struct ieee80211_channel ath6kl_2ghz_channels[] = { CHAN2G(1, 2412, 0), CHAN2G(2, 2417, 0), @@ -114,6 +117,8 @@ static struct ieee80211_supported_band ath6kl_band_2ghz = { .channels = ath6kl_2ghz_channels, .n_bitrates = ath6kl_g_rates_size, .bitrates = ath6kl_g_rates, + .ht_cap.cap = ath6kl_g_htcap, + .ht_cap.ht_supported = true, }; static struct ieee80211_supported_band ath6kl_band_5ghz = { @@ -121,6 +126,8 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = { .channels = ath6kl_5ghz_a_channels, .n_bitrates = ath6kl_a_rates_size, .bitrates = ath6kl_a_rates, + .ht_cap.cap = ath6kl_g_htcap, + .ht_cap.ht_supported = true, }; #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */ @@ -196,7 +203,7 @@ static int ath6kl_set_auth_type(struct ath6kl_vif *vif, break; default: - ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type); + ath6kl_err("%s: 0x%x not supported\n", __func__, auth_type); return -ENOTSUPP; } @@ -383,7 +390,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type, return false; if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) && - ar->num_vif)) + ar->num_vif)) return false; if (type == NL80211_IFTYPE_STATION || @@ -409,6 +416,12 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type, return false; } +static bool ath6kl_is_tx_pending(struct ath6kl *ar) +{ + return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0; +} + + static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) { @@ -416,6 +429,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct ath6kl_vif *vif = netdev_priv(dev); int status; u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE; + u16 interval; ath6kl_cfg80211_sscan_disable(vif); @@ -452,8 +466,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, * sleep until the command queue drains */ wait_event_interruptible_timeout(ar->event_wq, - ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0, - WMI_TIMEOUT); + ath6kl_is_tx_pending(ar), + WMI_TIMEOUT); if (signal_pending(current)) { ath6kl_err("cmd queue drain timeout\n"); up(&ar->sem); @@ -461,13 +475,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, } } - if (sme->ie && (sme->ie_len > 0)) { - status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len); - if (status) { - up(&ar->sem); - return status; - } - } else + status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len); + if (status) { + up(&ar->sem); + return status; + } + + if (sme->ie == NULL || sme->ie_len == 0) ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG; if (test_bit(CONNECTED, &vif->flags) && @@ -523,8 +537,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, (vif->prwise_crypto == WEP_CRYPT)) { struct ath6kl_key *key = NULL; - if (sme->key_idx < WMI_MIN_KEY_INDEX || - sme->key_idx > WMI_MAX_KEY_INDEX) { + if (sme->key_idx > WMI_MAX_KEY_INDEX) { ath6kl_err("key index %d out of bounds\n", sme->key_idx); up(&ar->sem); @@ -549,7 +562,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, if (!ar->usr_bss_filter) { clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags); if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, - ALL_BSS_FILTER, 0) != 0) { + ALL_BSS_FILTER, 0) != 0) { ath6kl_err("couldn't set bss filtering\n"); up(&ar->sem); return -EIO; @@ -571,6 +584,20 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, vif->grp_crypto_len, vif->ch_hint); vif->reconnect_flag = 0; + + if (vif->nw_type == INFRA_NETWORK) { + interval = max_t(u16, vif->listen_intvl_t, + ATH6KL_MAX_WOW_LISTEN_INTL); + status = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, + interval, + 0); + if (status) { + ath6kl_err("couldn't set listen intervel\n"); + up(&ar->sem); + return status; + } + } + status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type, vif->dot11_auth_mode, vif->auth_mode, vif->prwise_crypto, @@ -593,8 +620,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, } if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) && - ((vif->auth_mode == WPA_PSK_AUTH) - || (vif->auth_mode == WPA2_PSK_AUTH))) { + ((vif->auth_mode == WPA_PSK_AUTH) || + (vif->auth_mode == WPA2_PSK_AUTH))) { mod_timer(&vif->disconnect_timer, jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL)); } @@ -605,11 +632,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return 0; } -static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, - enum network_type nw_type, - const u8 *bssid, - struct ieee80211_channel *chan, - const u8 *beacon_ie, size_t beacon_ie_len) +static struct cfg80211_bss * +ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, + enum network_type nw_type, + const u8 *bssid, + struct ieee80211_channel *chan, + const u8 *beacon_ie, + size_t beacon_ie_len) { struct ath6kl *ar = vif->ar; struct cfg80211_bss *bss; @@ -638,7 +667,7 @@ static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, */ ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL); if (ie == NULL) - return -ENOMEM; + return NULL; ie[0] = WLAN_EID_SSID; ie[1] = vif->ssid_len; memcpy(ie + 2, vif->ssid, vif->ssid_len); @@ -652,15 +681,9 @@ static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, "cfg80211\n", bssid); kfree(ie); } else - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss " - "entry\n"); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n"); - if (bss == NULL) - return -ENOMEM; - - cfg80211_put_bss(bss); - - return 0; + return bss; } void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, @@ -672,6 +695,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, { struct ieee80211_channel *chan; struct ath6kl *ar = vif->ar; + struct cfg80211_bss *bss; /* capinfo + listen interval */ u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16); @@ -712,8 +736,9 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, chan = ieee80211_get_channel(ar->wiphy, (int) channel); - if (ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan, assoc_info, - beacon_ie_len) < 0) { + bss = ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan, + assoc_info, beacon_ie_len); + if (!bss) { ath6kl_err("could not add cfg80211 bss entry\n"); return; } @@ -722,6 +747,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n", nw_type & ADHOC_CREATOR ? "creator" : "joiner"); cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); + cfg80211_put_bss(bss); return; } @@ -732,11 +758,11 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, assoc_req_ie, assoc_req_len, assoc_resp_ie, assoc_resp_len, WLAN_STATUS_SUCCESS, GFP_KERNEL); + cfg80211_put_bss(bss); } else if (vif->sme_state == SME_CONNECTED) { /* inform roam event to cfg80211 */ - cfg80211_roamed(vif->ndev, chan, bssid, - assoc_req_ie, assoc_req_len, - assoc_resp_ie, assoc_resp_len, GFP_KERNEL); + cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len, + assoc_resp_ie, assoc_resp_len, GFP_KERNEL); } } @@ -828,13 +854,13 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, if (vif->sme_state == SME_CONNECTING) { cfg80211_connect_result(vif->ndev, - bssid, NULL, 0, - NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); + bssid, NULL, 0, + NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); } else if (vif->sme_state == SME_CONNECTED) { cfg80211_disconnected(vif->ndev, reason, - NULL, 0, GFP_KERNEL); + NULL, 0, GFP_KERNEL); } vif->sme_state = SME_DISCONNECTED; @@ -880,19 +906,14 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, request->ssids[i].ssid); } - /* - * FIXME: we should clear the IE in fw if it's not set so just - * remove the check altogether - */ - if (request->ie) { - ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, - WMI_FRAME_PROBE_REQ, - request->ie, request->ie_len); - if (ret) { - ath6kl_err("failed to set Probe Request appie for " - "scan"); - return ret; - } + /* this also clears IE in fw if it's not set */ + ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, + WMI_FRAME_PROBE_REQ, + request->ie, request->ie_len); + if (ret) { + ath6kl_err("failed to set Probe Request appie for " + "scan"); + return ret; } /* @@ -921,7 +942,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, force_fg_scan = 1; if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, - ar->fw_capabilities)) { + ar->fw_capabilities)) { /* * If capable of doing P2P mgmt operations using * station interface, send additional information like @@ -930,14 +951,17 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, */ ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN, force_fg_scan, - false, 0, 0, n_channels, - channels, request->no_cck, + false, 0, + ATH6KL_FG_SCAN_INTERVAL, + n_channels, channels, + request->no_cck, request->rates); } else { ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN, force_fg_scan, - false, 0, 0, n_channels, - channels); + false, 0, + ATH6KL_FG_SCAN_INTERVAL, + n_channels, channels); } if (ret) ath6kl_err("wmi_startscan_cmd failed\n"); @@ -984,6 +1008,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, struct ath6kl *ar = ath6kl_priv(ndev); struct ath6kl_vif *vif = netdev_priv(ndev); struct ath6kl_key *key = NULL; + int seq_len; u8 key_usage; u8 key_type; @@ -997,7 +1022,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, params->key); } - if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { + if (key_index > WMI_MAX_KEY_INDEX) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: key index %d out of bounds\n", __func__, key_index); @@ -1012,23 +1037,21 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, else key_usage = GROUP_USAGE; - if (params) { - int seq_len = params->seq_len; - if (params->cipher == WLAN_CIPHER_SUITE_SMS4 && - seq_len > ATH6KL_KEY_SEQ_LEN) { - /* Only first half of the WPI PN is configured */ - seq_len = ATH6KL_KEY_SEQ_LEN; - } - if (params->key_len > WLAN_MAX_KEY_LEN || - seq_len > sizeof(key->seq)) - return -EINVAL; - - key->key_len = params->key_len; - memcpy(key->key, params->key, key->key_len); - key->seq_len = seq_len; - memcpy(key->seq, params->seq, key->seq_len); - key->cipher = params->cipher; + seq_len = params->seq_len; + if (params->cipher == WLAN_CIPHER_SUITE_SMS4 && + seq_len > ATH6KL_KEY_SEQ_LEN) { + /* Only first half of the WPI PN is configured */ + seq_len = ATH6KL_KEY_SEQ_LEN; } + if (params->key_len > WLAN_MAX_KEY_LEN || + seq_len > sizeof(key->seq)) + return -EINVAL; + + key->key_len = params->key_len; + memcpy(key->key, params->key, key->key_len); + key->seq_len = seq_len; + memcpy(key->seq, params->seq, key->seq_len); + key->cipher = params->cipher; switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: @@ -1051,9 +1074,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, return -ENOTSUPP; } - if (((vif->auth_mode == WPA_PSK_AUTH) - || (vif->auth_mode == WPA2_PSK_AUTH)) - && (key_usage & GROUP_USAGE)) + if (((vif->auth_mode == WPA_PSK_AUTH) || + (vif->auth_mode == WPA2_PSK_AUTH)) && + (key_usage & GROUP_USAGE)) del_timer(&vif->disconnect_timer); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, @@ -1063,7 +1086,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, if (vif->nw_type == AP_NETWORK && !pairwise && (key_type == TKIP_CRYPT || key_type == AES_CRYPT || - key_type == WAPI_CRYPT) && params) { + key_type == WAPI_CRYPT)) { ar->ap_mode_bkey.valid = true; ar->ap_mode_bkey.key_index = key_index; ar->ap_mode_bkey.key_type = key_type; @@ -1115,7 +1138,7 @@ static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, if (!ath6kl_cfg80211_ready(vif)) return -EIO; - if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { + if (key_index > WMI_MAX_KEY_INDEX) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: key index %d out of bounds\n", __func__, key_index); @@ -1148,7 +1171,7 @@ static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, if (!ath6kl_cfg80211_ready(vif)) return -EIO; - if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { + if (key_index > WMI_MAX_KEY_INDEX) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: key index %d out of bounds\n", __func__, key_index); @@ -1184,7 +1207,7 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy, if (!ath6kl_cfg80211_ready(vif)) return -EIO; - if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { + if (key_index > WMI_MAX_KEY_INDEX) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: key index %d out of bounds\n", __func__, key_index); @@ -1268,7 +1291,6 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, { struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); struct ath6kl_vif *vif; - u8 ath6kl_dbm; int dbm = MBM_TO_DBM(mbm); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__, @@ -1285,7 +1307,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, case NL80211_TX_POWER_AUTOMATIC: return 0; case NL80211_TX_POWER_LIMITED: - ar->tx_pwr = ath6kl_dbm = dbm; + ar->tx_pwr = dbm; break; default: ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n", @@ -1293,7 +1315,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, return -EOPNOTSUPP; } - ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm); + ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, dbm); return 0; } @@ -1354,7 +1376,7 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, } if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx, - mode.pwr_mode) != 0) { + mode.pwr_mode) != 0) { ath6kl_err("wmi_powermode_cmd failed\n"); return -EIO; } @@ -1403,7 +1425,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy, ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); - ath6kl_deinit_if_data(vif); + ath6kl_cfg80211_vif_cleanup(vif); return 0; } @@ -1728,29 +1750,14 @@ static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) return 0; } -static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) +static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif, + struct cfg80211_wowlan *wow, u32 *filter) { - struct ath6kl_vif *vif; - int ret, pos, left; - u32 filter = 0; - u16 i; + int ret, pos; u8 mask[WOW_MASK_SIZE]; + u16 i; - vif = ath6kl_vif_first(ar); - if (!vif) - return -EIO; - - if (!ath6kl_cfg80211_ready(vif)) - return -EIO; - - if (!test_bit(CONNECTED, &vif->flags)) - return -EINVAL; - - /* Clear existing WOW patterns */ - for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++) - ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx, - WOW_LIST_ID, i); - /* Configure new WOW patterns */ + /* Configure the patterns that we received from the user. */ for (i = 0; i < wow->n_patterns; i++) { /* @@ -1773,29 +1780,249 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) * matched from the first byte of received pkt in the firmware. */ ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, - vif->fw_vif_idx, WOW_LIST_ID, - wow->patterns[i].pattern_len, - 0 /* pattern offset */, - wow->patterns[i].pattern, mask); + vif->fw_vif_idx, WOW_LIST_ID, + wow->patterns[i].pattern_len, + 0 /* pattern offset */, + wow->patterns[i].pattern, mask); if (ret) return ret; } if (wow->disconnect) - filter |= WOW_FILTER_OPTION_NWK_DISASSOC; + *filter |= WOW_FILTER_OPTION_NWK_DISASSOC; if (wow->magic_pkt) - filter |= WOW_FILTER_OPTION_MAGIC_PACKET; + *filter |= WOW_FILTER_OPTION_MAGIC_PACKET; if (wow->gtk_rekey_failure) - filter |= WOW_FILTER_OPTION_GTK_ERROR; + *filter |= WOW_FILTER_OPTION_GTK_ERROR; if (wow->eap_identity_req) - filter |= WOW_FILTER_OPTION_EAP_REQ; + *filter |= WOW_FILTER_OPTION_EAP_REQ; if (wow->four_way_handshake) - filter |= WOW_FILTER_OPTION_8021X_4WAYHS; + *filter |= WOW_FILTER_OPTION_8021X_4WAYHS; + + return 0; +} + +static int ath6kl_wow_ap(struct ath6kl *ar, struct ath6kl_vif *vif) +{ + static const u8 unicst_pattern[] = { 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08 }; + static const u8 unicst_mask[] = { 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f }; + u8 unicst_offset = 0; + static const u8 arp_pattern[] = { 0x08, 0x06 }; + static const u8 arp_mask[] = { 0xff, 0xff }; + u8 arp_offset = 20; + static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 }; + static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 }; + u8 discvr_offset = 38; + static const u8 dhcp_pattern[] = { 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x43 /* port 67 */ }; + static const u8 dhcp_mask[] = { 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff /* port 67 */ }; + u8 dhcp_offset = 0; + int ret; + + /* Setup unicast IP, EAPOL-like and ARP pkt pattern */ + ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, + vif->fw_vif_idx, WOW_LIST_ID, + sizeof(unicst_pattern), unicst_offset, + unicst_pattern, unicst_mask); + if (ret) { + ath6kl_err("failed to add WOW unicast IP pattern\n"); + return ret; + } + + /* Setup all ARP pkt pattern */ + ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, + vif->fw_vif_idx, WOW_LIST_ID, + sizeof(arp_pattern), arp_offset, + arp_pattern, arp_mask); + if (ret) { + ath6kl_err("failed to add WOW ARP pattern\n"); + return ret; + } + + /* + * Setup multicast pattern for mDNS 224.0.0.251, + * SSDP 239.255.255.250 and LLMNR 224.0.0.252 + */ + ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, + vif->fw_vif_idx, WOW_LIST_ID, + sizeof(discvr_pattern), discvr_offset, + discvr_pattern, discvr_mask); + if (ret) { + ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n"); + return ret; + } + + /* Setup all DHCP broadcast pkt pattern */ + ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, + vif->fw_vif_idx, WOW_LIST_ID, + sizeof(dhcp_pattern), dhcp_offset, + dhcp_pattern, dhcp_mask); + if (ret) { + ath6kl_err("failed to add WOW DHCP broadcast pattern\n"); + return ret; + } + + return 0; +} + +static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif) +{ + struct net_device *ndev = vif->ndev; + static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 }; + static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 }; + u8 discvr_offset = 38; + u8 mac_mask[ETH_ALEN]; + int ret; + + /* Setup unicast pkt pattern */ + memset(mac_mask, 0xff, ETH_ALEN); + ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, + vif->fw_vif_idx, WOW_LIST_ID, + ETH_ALEN, 0, ndev->dev_addr, + mac_mask); + if (ret) { + ath6kl_err("failed to add WOW unicast pattern\n"); + return ret; + } + + /* + * Setup multicast pattern for mDNS 224.0.0.251, + * SSDP 239.255.255.250 and LLMNR 224.0.0.252 + */ + if ((ndev->flags & IFF_ALLMULTI) || + (ndev->flags & IFF_MULTICAST && netdev_mc_count(ndev) > 0)) { + ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi, + vif->fw_vif_idx, WOW_LIST_ID, + sizeof(discvr_pattern), discvr_offset, + discvr_pattern, discvr_mask); + if (ret) { + ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR " + "pattern\n"); + return ret; + } + } + return 0; +} + +static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) +{ + struct in_device *in_dev; + struct in_ifaddr *ifa; + struct ath6kl_vif *vif; + int ret, left; + u32 filter = 0; + u16 i, bmiss_time; + u8 index = 0; + __be32 ips[MAX_IP_ADDRS]; + + vif = ath6kl_vif_first(ar); + if (!vif) + return -EIO; + + if (!ath6kl_cfg80211_ready(vif)) + return -EIO; + + if (!test_bit(CONNECTED, &vif->flags)) + return -ENOTCONN; + + if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) + return -EINVAL; + + /* Clear existing WOW patterns */ + for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++) + ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx, + WOW_LIST_ID, i); + + /* + * Skip the default WOW pattern configuration + * if the driver receives any WOW patterns from + * the user. + */ + if (wow) + ret = ath6kl_wow_usr(ar, vif, wow, &filter); + else if (vif->nw_type == AP_NETWORK) + ret = ath6kl_wow_ap(ar, vif); + else + ret = ath6kl_wow_sta(ar, vif); + + if (ret) + return ret; + + netif_stop_queue(vif->ndev); + + if (vif->nw_type != AP_NETWORK) { + ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, + ATH6KL_MAX_WOW_LISTEN_INTL, + 0); + if (ret) + return ret; + + /* Set listen interval x 15 times as bmiss time */ + bmiss_time = ATH6KL_MAX_WOW_LISTEN_INTL * 15; + if (bmiss_time > ATH6KL_MAX_BMISS_TIME) + bmiss_time = ATH6KL_MAX_BMISS_TIME; + + ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx, + bmiss_time, 0); + if (ret) + return ret; + + ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, + 0xFFFF, 0, 0xFFFF, 0, 0, 0, + 0, 0, 0, 0); + if (ret) + return ret; + } + + ar->state = ATH6KL_STATE_SUSPENDING; + + /* Setup own IP addr for ARP agent. */ + in_dev = __in_dev_get_rtnl(vif->ndev); + if (!in_dev) + goto skip_arp; + + ifa = in_dev->ifa_list; + memset(&ips, 0, sizeof(ips)); + + /* Configure IP addr only if IP address count < MAX_IP_ADDRS */ + while (index < MAX_IP_ADDRS && ifa) { + ips[index] = ifa->ifa_local; + ifa = ifa->ifa_next; + index++; + } + + if (ifa) { + ath6kl_err("total IP addr count is exceeding fw limit\n"); + return -EINVAL; + } + + ret = ath6kl_wmi_set_ip_cmd(ar->wmi, vif->fw_vif_idx, ips[0], ips[1]); + if (ret) { + ath6kl_err("fail to setup ip for arp agent\n"); + return ret; + } + +skip_arp: ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_WOW_MODE_ENABLE, filter, @@ -1803,11 +2030,26 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (ret) return ret; + clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); + ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_HOST_MODE_ASLEEP); if (ret) return ret; + left = wait_event_interruptible_timeout(ar->event_wq, + test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags), + WMI_TIMEOUT); + if (left == 0) { + ath6kl_warn("timeout, didn't get host sleep cmd " + "processed event\n"); + ret = -ETIMEDOUT; + } else if (left < 0) { + ath6kl_warn("error while waiting for host sleep cmd " + "processed event %d\n", left); + ret = left; + } + if (ar->tx_pending[ar->ctrl_ep]) { left = wait_event_interruptible_timeout(ar->event_wq, ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT); @@ -1832,15 +2074,46 @@ static int ath6kl_wow_resume(struct ath6kl *ar) if (!vif) return -EIO; + ar->state = ATH6KL_STATE_RESUMING; + ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_HOST_MODE_AWAKE); - return ret; + if (ret) { + ath6kl_warn("Failed to configure host sleep mode for " + "wow resume: %d\n", ret); + ar->state = ATH6KL_STATE_WOW; + return ret; + } + + if (vif->nw_type != AP_NETWORK) { + ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, + 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); + if (ret) + return ret; + + ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, + vif->listen_intvl_t, 0); + if (ret) + return ret; + + ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx, + vif->bmiss_time_t, 0); + if (ret) + return ret; + } + + ar->state = ATH6KL_STATE_ON; + + netif_wake_queue(vif->ndev); + + return 0; } int ath6kl_cfg80211_suspend(struct ath6kl *ar, enum ath6kl_cfg_suspend_mode mode, struct cfg80211_wowlan *wow) { + enum ath6kl_state prev_state; int ret; switch (mode) { @@ -1851,11 +2124,14 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, /* Flush all non control pkts in TX path */ ath6kl_tx_data_cleanup(ar); + prev_state = ar->state; + ret = ath6kl_wow_suspend(ar, wow); if (ret) { - ath6kl_err("wow suspend failed: %d\n", ret); + ar->state = prev_state; return ret; } + ar->state = ATH6KL_STATE_WOW; break; @@ -1911,6 +2187,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, return 0; } +EXPORT_SYMBOL(ath6kl_cfg80211_suspend); int ath6kl_cfg80211_resume(struct ath6kl *ar) { @@ -1926,7 +2203,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) return ret; } - ar->state = ATH6KL_STATE_ON; break; case ATH6KL_STATE_DEEPSLEEP: @@ -1962,6 +2238,7 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) return 0; } +EXPORT_SYMBOL(ath6kl_cfg80211_resume); #ifdef CONFIG_PM @@ -1999,6 +2276,9 @@ static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) */ void ath6kl_check_wow_status(struct ath6kl *ar) { + if (ar->state == ATH6KL_STATE_SUSPENDING) + return; + if (ar->state == ATH6KL_STATE_WOW) ath6kl_cfg80211_resume(ar); } @@ -2014,7 +2294,18 @@ static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) { - struct ath6kl_vif *vif = netdev_priv(dev); + struct ath6kl_vif *vif; + + /* + * 'dev' could be NULL if a channel change is required for the hardware + * device itself, instead of a particular VIF. + * + * FIXME: To be handled properly when monitor mode is supported. + */ + if (!dev) + return -EBUSY; + + vif = netdev_priv(dev); if (!ath6kl_cfg80211_ready(vif)) return -EIO; @@ -2069,19 +2360,51 @@ static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif, return ret; } -static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info, bool add) +static int ath6kl_set_ies(struct ath6kl_vif *vif, + struct cfg80211_beacon_data *info) +{ + struct ath6kl *ar = vif->ar; + int res; + + /* this also clears IE in fw if it's not set */ + res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, + WMI_FRAME_BEACON, + info->beacon_ies, + info->beacon_ies_len); + if (res) + return res; + + /* this also clears IE in fw if it's not set */ + res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, + info->proberesp_ies_len); + if (res) + return res; + + /* this also clears IE in fw if it's not set */ + res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, + WMI_FRAME_ASSOC_RESP, + info->assocresp_ies, + info->assocresp_ies_len); + if (res) + return res; + + return 0; +} + +static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *info) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); struct ieee80211_mgmt *mgmt; + bool hidden = false; u8 *ies; int ies_len; struct wmi_connect_cmd p; int res; int i, ret; - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); if (!ath6kl_cfg80211_ready(vif)) return -EIO; @@ -2089,31 +2412,7 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, if (vif->next_mode != AP_NETWORK) return -EOPNOTSUPP; - if (info->beacon_ies) { - res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, - WMI_FRAME_BEACON, - info->beacon_ies, - info->beacon_ies_len); - if (res) - return res; - } - if (info->proberesp_ies) { - res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, - info->proberesp_ies_len); - if (res) - return res; - } - if (info->assocresp_ies) { - res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, - WMI_FRAME_ASSOC_RESP, - info->assocresp_ies, - info->assocresp_ies_len); - if (res) - return res; - } - - if (!add) - return 0; + res = ath6kl_set_ies(vif, &info->beacon); ar->ap_mode_bkey.valid = false; @@ -2122,20 +2421,24 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, * info->dtim_period */ - if (info->head == NULL) + if (info->beacon.head == NULL) return -EINVAL; - mgmt = (struct ieee80211_mgmt *) info->head; + mgmt = (struct ieee80211_mgmt *) info->beacon.head; ies = mgmt->u.beacon.variable; - if (ies > info->head + info->head_len) + if (ies > info->beacon.head + info->beacon.head_len) return -EINVAL; - ies_len = info->head + info->head_len - ies; + ies_len = info->beacon.head + info->beacon.head_len - ies; if (info->ssid == NULL) return -EINVAL; memcpy(vif->ssid, info->ssid, info->ssid_len); vif->ssid_len = info->ssid_len; if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) - return -EOPNOTSUPP; /* TODO */ + hidden = true; + + res = ath6kl_wmi_ap_hidden_ssid(ar->wmi, vif->fw_vif_idx, hidden); + if (res) + return res; ret = ath6kl_set_auth_type(vif, info->auth_type); if (ret) @@ -2214,6 +2517,11 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, p.dot11_auth_mode = vif->dot11_auth_mode; p.ch = cpu_to_le16(vif->next_chan); + /* Enable uAPSD support by default */ + res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true); + if (res < 0) + return res; + if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) { p.nw_subtype = SUBTYPE_P2PGO; } else { @@ -2231,19 +2539,21 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, return 0; } -static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info) +static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_beacon_data *beacon) { - return ath6kl_ap_beacon(wiphy, dev, info, true); -} + struct ath6kl_vif *vif = netdev_priv(dev); -static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info) -{ - return ath6kl_ap_beacon(wiphy, dev, info, false); + if (!ath6kl_cfg80211_ready(vif)) + return -EIO; + + if (vif->next_mode != AP_NETWORK) + return -EOPNOTSUPP; + + return ath6kl_set_ies(vif, beacon); } -static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev) +static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); @@ -2259,6 +2569,19 @@ static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev) return 0; } +static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct ath6kl_vif *vif = netdev_priv(dev); + const u8 *addr = mac ? mac : bcast_addr; + + return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH, + addr, WLAN_REASON_PREV_AUTH_NOT_VALID); +} + static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_parameters *params) { @@ -2354,6 +2677,76 @@ static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif, return ret; } +static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif, + u32 id, + u32 freq, + u32 wait, + const u8 *buf, + size_t len, + bool *more_data, + bool no_cck) +{ + struct ieee80211_mgmt *mgmt; + struct ath6kl_sta *conn; + bool is_psq_empty = false; + struct ath6kl_mgmt_buff *mgmt_buf; + size_t mgmt_buf_size; + struct ath6kl *ar = vif->ar; + + mgmt = (struct ieee80211_mgmt *) buf; + if (is_multicast_ether_addr(mgmt->da)) + return false; + + conn = ath6kl_find_sta(vif, mgmt->da); + if (!conn) + return false; + + if (conn->sta_flags & STA_PS_SLEEP) { + if (!(conn->sta_flags & STA_PS_POLLED)) { + /* Queue the frames if the STA is sleeping */ + mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff); + mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL); + if (!mgmt_buf) + return false; + + INIT_LIST_HEAD(&mgmt_buf->list); + mgmt_buf->id = id; + mgmt_buf->freq = freq; + mgmt_buf->wait = wait; + mgmt_buf->len = len; + mgmt_buf->no_cck = no_cck; + memcpy(mgmt_buf->buf, buf, len); + spin_lock_bh(&conn->psq_lock); + is_psq_empty = skb_queue_empty(&conn->psq) && + (conn->mgmt_psq_len == 0); + list_add_tail(&mgmt_buf->list, &conn->mgmt_psq); + conn->mgmt_psq_len++; + spin_unlock_bh(&conn->psq_lock); + + /* + * If this is the first pkt getting queued + * for this STA, update the PVB for this + * STA. + */ + if (is_psq_empty) + ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx, + conn->aid, 1); + return true; + } + + /* + * This tx is because of a PsPoll. + * Determine if MoreData bit has to be set. + */ + spin_lock_bh(&conn->psq_lock); + if (!skb_queue_empty(&conn->psq) || (conn->mgmt_psq_len != 0)) + *more_data = true; + spin_unlock_bh(&conn->psq_lock); + } + + return false; +} + static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, @@ -2365,6 +2758,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, struct ath6kl_vif *vif = netdev_priv(dev); u32 id; const struct ieee80211_mgmt *mgmt; + bool more_data, queued; mgmt = (const struct ieee80211_mgmt *) buf; if (buf + len >= mgmt->u.probe_resp.variable && @@ -2390,22 +2784,19 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, *cookie = id; - if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, - ar->fw_capabilities)) { - /* - * If capable of doing P2P mgmt operations using - * station interface, send additional information like - * supported rates to advertise and xmit rates for - * probe requests - */ - return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, - chan->center_freq, wait, - buf, len, no_cck); - } else { - return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id, - chan->center_freq, wait, - buf, len); + /* AP mode Power saving processing */ + if (vif->nw_type == AP_NETWORK) { + queued = ath6kl_mgmt_powersave_ap(vif, + id, chan->center_freq, + wait, buf, + len, &more_data, no_cck); + if (queued) + return 0; } + + return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, + chan->center_freq, wait, + buf, len, no_cck); } static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, @@ -2518,6 +2909,12 @@ ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = { .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) }, + [NL80211_IFTYPE_AP] = { + .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_RESP >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, [NL80211_IFTYPE_P2P_CLIENT] = { .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), @@ -2559,9 +2956,10 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { .resume = __ath6kl_cfg80211_resume, #endif .set_channel = ath6kl_set_channel, - .add_beacon = ath6kl_add_beacon, - .set_beacon = ath6kl_set_beacon, - .del_beacon = ath6kl_del_beacon, + .start_ap = ath6kl_start_ap, + .change_beacon = ath6kl_change_beacon, + .stop_ap = ath6kl_stop_ap, + .del_station = ath6kl_del_station, .change_station = ath6kl_change_station, .remain_on_channel = ath6kl_remain_on_channel, .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel, @@ -2629,122 +3027,9 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) ath6kl_cfg80211_stop(vif); } -struct ath6kl *ath6kl_core_alloc(struct device *dev) -{ - struct ath6kl *ar; - struct wiphy *wiphy; - u8 ctr; - - /* create a new wiphy for use with cfg80211 */ - wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl)); - - if (!wiphy) { - ath6kl_err("couldn't allocate wiphy device\n"); - return NULL; - } - - ar = wiphy_priv(wiphy); - ar->p2p = !!ath6kl_p2p; - ar->wiphy = wiphy; - ar->dev = dev; - - ar->vif_max = 1; - - ar->max_norm_iface = 1; - - spin_lock_init(&ar->lock); - spin_lock_init(&ar->mcastpsq_lock); - spin_lock_init(&ar->list_lock); - - init_waitqueue_head(&ar->event_wq); - sema_init(&ar->sem, 1); - - INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue); - INIT_LIST_HEAD(&ar->vif_list); - - clear_bit(WMI_ENABLED, &ar->flag); - clear_bit(SKIP_SCAN, &ar->flag); - clear_bit(DESTROY_IN_PROGRESS, &ar->flag); - - ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL; - ar->listen_intvl_b = 0; - ar->tx_pwr = 0; - - ar->intra_bss = 1; - ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD; - - ar->state = ATH6KL_STATE_OFF; - - memset((u8 *)ar->sta_list, 0, - AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); - - /* Init the PS queues */ - for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { - spin_lock_init(&ar->sta_list[ctr].psq_lock); - skb_queue_head_init(&ar->sta_list[ctr].psq); - } - - skb_queue_head_init(&ar->mcastpsq); - - memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3); - - return ar; -} - -int ath6kl_register_ieee80211_hw(struct ath6kl *ar) -{ - struct wiphy *wiphy = ar->wiphy; - int ret; - - wiphy->mgmt_stypes = ath6kl_mgmt_stypes; - - wiphy->max_remain_on_channel_duration = 5000; - - /* set device pointer for wiphy */ - set_wiphy_dev(wiphy, ar->dev); - - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP); - if (ar->p2p) { - wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_P2P_CLIENT); - } - - /* max num of ssids that can be probed during scanning */ - wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; - wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */ - wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; - wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; - wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - - wiphy->cipher_suites = cipher_suites; - wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); - - wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | - WIPHY_WOWLAN_DISCONNECT | - WIPHY_WOWLAN_GTK_REKEY_FAILURE | - WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | - WIPHY_WOWLAN_EAP_IDENTITY_REQ | - WIPHY_WOWLAN_4WAY_HANDSHAKE; - wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST; - wiphy->wowlan.pattern_min_len = 1; - wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE; - - wiphy->max_sched_scan_ssids = 10; - - ret = wiphy_register(wiphy); - if (ret < 0) { - ath6kl_err("couldn't register wiphy device\n"); - return ret; - } - - return 0; -} - -static int ath6kl_init_if_data(struct ath6kl_vif *vif) +static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) { - vif->aggr_cntxt = aggr_init(vif->ndev); + vif->aggr_cntxt = aggr_init(vif); if (!vif->aggr_cntxt) { ath6kl_err("failed to initialize aggr\n"); return -ENOMEM; @@ -2758,12 +3043,15 @@ static int ath6kl_init_if_data(struct ath6kl_vif *vif) set_bit(WMM_ENABLED, &vif->flags); spin_lock_init(&vif->if_lock); + INIT_LIST_HEAD(&vif->mc_filter); + return 0; } -void ath6kl_deinit_if_data(struct ath6kl_vif *vif) +void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif) { struct ath6kl *ar = vif->ar; + struct ath6kl_mc_filter *mc_filter, *tmp; aggr_module_destroy(vif->aggr_cntxt); @@ -2772,6 +3060,11 @@ void ath6kl_deinit_if_data(struct ath6kl_vif *vif) if (vif->nw_type == ADHOC_NETWORK) ar->ibss_if_active = false; + list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) { + list_del(&mc_filter->list); + kfree(mc_filter); + } + unregister_netdevice(vif->ndev); ar->num_vif--; @@ -2797,7 +3090,10 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, vif->wdev.netdev = ndev; vif->wdev.iftype = type; vif->fw_vif_idx = fw_vif_idx; - vif->nw_type = vif->next_mode = nw_type; + vif->nw_type = nw_type; + vif->next_mode = nw_type; + vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; + vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); if (fw_vif_idx != 0) @@ -2808,8 +3104,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, ath6kl_init_control_info(vif); - /* TODO: Pass interface specific pointer instead of ar */ - if (ath6kl_init_if_data(vif)) + if (ath6kl_cfg80211_vif_init(vif)) goto err; if (register_netdevice(ndev)) @@ -2836,8 +3131,107 @@ err: return NULL; } -void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar) +int ath6kl_cfg80211_init(struct ath6kl *ar) +{ + struct wiphy *wiphy = ar->wiphy; + int ret; + + wiphy->mgmt_stypes = ath6kl_mgmt_stypes; + + wiphy->max_remain_on_channel_duration = 5000; + + /* set device pointer for wiphy */ + set_wiphy_dev(wiphy, ar->dev); + + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP); + if (ar->p2p) { + wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT); + } + + /* max num of ssids that can be probed during scanning */ + wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; + wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */ + wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; + wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + wiphy->cipher_suites = cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + + wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_GTK_REKEY_FAILURE | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | + WIPHY_WOWLAN_EAP_IDENTITY_REQ | + WIPHY_WOWLAN_4WAY_HANDSHAKE; + wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST; + wiphy->wowlan.pattern_min_len = 1; + wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE; + + wiphy->max_sched_scan_ssids = 10; + + ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | + WIPHY_FLAG_HAVE_AP_SME | + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; + + if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) + ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + + ar->wiphy->probe_resp_offload = + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; + + ret = wiphy_register(wiphy); + if (ret < 0) { + ath6kl_err("couldn't register wiphy device\n"); + return ret; + } + + ar->wiphy_registered = true; + + return 0; +} + +void ath6kl_cfg80211_cleanup(struct ath6kl *ar) { wiphy_unregister(ar->wiphy); + + ar->wiphy_registered = false; +} + +struct ath6kl *ath6kl_cfg80211_create(void) +{ + struct ath6kl *ar; + struct wiphy *wiphy; + + /* create a new wiphy for use with cfg80211 */ + wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl)); + + if (!wiphy) { + ath6kl_err("couldn't allocate wiphy device\n"); + return NULL; + } + + ar = wiphy_priv(wiphy); + ar->wiphy = wiphy; + + return ar; +} + +/* Note: ar variable must not be accessed after calling this! */ +void ath6kl_cfg80211_destroy(struct ath6kl *ar) +{ + int i; + + for (i = 0; i < AP_MAX_NUM_STA; i++) + kfree(ar->sta_list[i].aggr_conn); + wiphy_free(ar->wiphy); } + diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index 81f20a572315..c5def436417f 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h @@ -1,5 +1,6 @@ /* * Copyright (c) 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 @@ -27,10 +28,6 @@ enum ath6kl_cfg_suspend_mode { struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, enum nl80211_iftype type, u8 fw_vif_idx, u8 nw_type); -int ath6kl_register_ieee80211_hw(struct ath6kl *ar); -struct ath6kl *ath6kl_core_alloc(struct device *dev); -void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar); - void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted); void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, @@ -53,7 +50,15 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, int ath6kl_cfg80211_resume(struct ath6kl *ar); +void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif); + void ath6kl_cfg80211_stop(struct ath6kl_vif *vif); void ath6kl_cfg80211_stop_all(struct ath6kl *ar); +int ath6kl_cfg80211_init(struct ath6kl *ar); +void ath6kl_cfg80211_cleanup(struct ath6kl *ar); + +struct ath6kl *ath6kl_cfg80211_create(void); +void ath6kl_cfg80211_destroy(struct ath6kl *ar); + #endif /* ATH6KL_CFG80211_H */ diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h index bfd6597763da..a60e78c0472f 100644 --- a/drivers/net/wireless/ath/ath6kl/common.h +++ b/drivers/net/wireless/ath/ath6kl/common.h @@ -1,5 +1,6 @@ /* * 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 @@ -79,8 +80,5 @@ struct ath6kl; enum htc_credit_dist_reason; struct ath6kl_htc_credit_info; -struct ath6kl *ath6kl_core_alloc(struct device *sdev); -int ath6kl_core_init(struct ath6kl *ar); -void ath6kl_core_cleanup(struct ath6kl *ar); struct sk_buff *ath6kl_buf_alloc(int size); #endif /* COMMON_H */ diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c new file mode 100644 index 000000000000..45e641f3a41b --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2004-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. + */ + +#include "core.h" + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/export.h> + +#include "debug.h" +#include "hif-ops.h" +#include "cfg80211.h" + +unsigned int debug_mask; +static unsigned int suspend_mode; +static unsigned int wow_mode; +static unsigned int uart_debug; +static unsigned int ath6kl_p2p; +static unsigned int testmode; + +module_param(debug_mask, uint, 0644); +module_param(suspend_mode, uint, 0644); +module_param(wow_mode, uint, 0644); +module_param(uart_debug, uint, 0644); +module_param(ath6kl_p2p, uint, 0644); +module_param(testmode, uint, 0644); + +int ath6kl_core_init(struct ath6kl *ar) +{ + struct ath6kl_bmi_target_info targ_info; + struct net_device *ndev; + int ret = 0, i; + + ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); + if (!ar->ath6kl_wq) + return -ENOMEM; + + ret = ath6kl_bmi_init(ar); + if (ret) + goto err_wq; + + /* + * Turn on power to get hardware (target) version and leave power + * on delibrately as we will boot the hardware anyway within few + * seconds. + */ + ret = ath6kl_hif_power_on(ar); + if (ret) + goto err_bmi_cleanup; + + ret = ath6kl_bmi_get_target_info(ar, &targ_info); + if (ret) + goto err_power_off; + + ar->version.target_ver = le32_to_cpu(targ_info.version); + ar->target_type = le32_to_cpu(targ_info.type); + ar->wiphy->hw_version = le32_to_cpu(targ_info.version); + + ret = ath6kl_init_hw_params(ar); + if (ret) + goto err_power_off; + + ar->htc_target = ath6kl_htc_create(ar); + + if (!ar->htc_target) { + ret = -ENOMEM; + goto err_power_off; + } + + ar->testmode = testmode; + + ret = ath6kl_init_fetch_firmwares(ar); + if (ret) + goto err_htc_cleanup; + + /* FIXME: we should free all firmwares in the error cases below */ + + /* Indicate that WMI is enabled (although not ready yet) */ + set_bit(WMI_ENABLED, &ar->flag); + ar->wmi = ath6kl_wmi_init(ar); + if (!ar->wmi) { + ath6kl_err("failed to initialize wmi\n"); + ret = -EIO; + goto err_htc_cleanup; + } + + ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); + + /* setup access class priority mappings */ + ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */ + ar->ac_stream_pri_map[WMM_AC_BE] = 1; + ar->ac_stream_pri_map[WMM_AC_VI] = 2; + ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ + + /* allocate some buffers that handle larger AMSDU frames */ + ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); + + ath6kl_cookie_init(ar); + + ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | + ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; + + if (suspend_mode && + suspend_mode >= WLAN_POWER_STATE_CUT_PWR && + suspend_mode <= WLAN_POWER_STATE_WOW) + ar->suspend_mode = suspend_mode; + else + ar->suspend_mode = 0; + + if (suspend_mode == WLAN_POWER_STATE_WOW && + (wow_mode == WLAN_POWER_STATE_CUT_PWR || + wow_mode == WLAN_POWER_STATE_DEEP_SLEEP)) + ar->wow_suspend_mode = wow_mode; + else + ar->wow_suspend_mode = 0; + + if (uart_debug) + ar->conf_flags |= ATH6KL_CONF_UART_DEBUG; + + set_bit(FIRST_BOOT, &ar->flag); + + ath6kl_debug_init(ar); + + ret = ath6kl_init_hw_start(ar); + if (ret) { + ath6kl_err("Failed to start hardware: %d\n", ret); + goto err_rxbuf_cleanup; + } + + /* give our connected endpoints some buffers */ + ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); + ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); + + ret = ath6kl_cfg80211_init(ar); + if (ret) + goto err_rxbuf_cleanup; + + ret = ath6kl_debug_init_fs(ar); + if (ret) { + wiphy_unregister(ar->wiphy); + goto err_rxbuf_cleanup; + } + + for (i = 0; i < ar->vif_max; i++) + ar->avail_idx_map |= BIT(i); + + rtnl_lock(); + + /* Add an initial station interface */ + ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, + INFRA_NETWORK); + + rtnl_unlock(); + + if (!ndev) { + ath6kl_err("Failed to instantiate a network device\n"); + ret = -ENOMEM; + wiphy_unregister(ar->wiphy); + goto err_rxbuf_cleanup; + } + + ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", + __func__, ndev->name, ndev, ar); + + return ret; + +err_rxbuf_cleanup: + ath6kl_debug_cleanup(ar); + ath6kl_htc_flush_rx_buf(ar->htc_target); + ath6kl_cleanup_amsdu_rxbufs(ar); + ath6kl_wmi_shutdown(ar->wmi); + clear_bit(WMI_ENABLED, &ar->flag); + ar->wmi = NULL; +err_htc_cleanup: + ath6kl_htc_cleanup(ar->htc_target); +err_power_off: + ath6kl_hif_power_off(ar); +err_bmi_cleanup: + ath6kl_bmi_cleanup(ar); +err_wq: + destroy_workqueue(ar->ath6kl_wq); + + return ret; +} +EXPORT_SYMBOL(ath6kl_core_init); + +struct ath6kl *ath6kl_core_create(struct device *dev) +{ + struct ath6kl *ar; + u8 ctr; + + ar = ath6kl_cfg80211_create(); + if (!ar) + return NULL; + + ar->p2p = !!ath6kl_p2p; + ar->dev = dev; + + ar->vif_max = 1; + + ar->max_norm_iface = 1; + + spin_lock_init(&ar->lock); + spin_lock_init(&ar->mcastpsq_lock); + spin_lock_init(&ar->list_lock); + + init_waitqueue_head(&ar->event_wq); + sema_init(&ar->sem, 1); + + INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue); + INIT_LIST_HEAD(&ar->vif_list); + + clear_bit(WMI_ENABLED, &ar->flag); + clear_bit(SKIP_SCAN, &ar->flag); + clear_bit(DESTROY_IN_PROGRESS, &ar->flag); + + ar->tx_pwr = 0; + ar->intra_bss = 1; + ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD; + + ar->state = ATH6KL_STATE_OFF; + + memset((u8 *)ar->sta_list, 0, + AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); + + /* Init the PS queues */ + for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { + spin_lock_init(&ar->sta_list[ctr].psq_lock); + skb_queue_head_init(&ar->sta_list[ctr].psq); + skb_queue_head_init(&ar->sta_list[ctr].apsdq); + ar->sta_list[ctr].mgmt_psq_len = 0; + INIT_LIST_HEAD(&ar->sta_list[ctr].mgmt_psq); + ar->sta_list[ctr].aggr_conn = + kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL); + if (!ar->sta_list[ctr].aggr_conn) { + ath6kl_err("Failed to allocate memory for sta aggregation information\n"); + ath6kl_core_destroy(ar); + return NULL; + } + } + + skb_queue_head_init(&ar->mcastpsq); + + memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3); + + return ar; +} +EXPORT_SYMBOL(ath6kl_core_create); + +void ath6kl_core_cleanup(struct ath6kl *ar) +{ + ath6kl_hif_power_off(ar); + + destroy_workqueue(ar->ath6kl_wq); + + if (ar->htc_target) + ath6kl_htc_cleanup(ar->htc_target); + + ath6kl_cookie_cleanup(ar); + + ath6kl_cleanup_amsdu_rxbufs(ar); + + ath6kl_bmi_cleanup(ar); + + ath6kl_debug_cleanup(ar); + + kfree(ar->fw_board); + kfree(ar->fw_otp); + kfree(ar->fw); + kfree(ar->fw_patch); + kfree(ar->fw_testscript); + + ath6kl_cfg80211_cleanup(ar); +} +EXPORT_SYMBOL(ath6kl_core_cleanup); + +void ath6kl_core_destroy(struct ath6kl *ar) +{ + ath6kl_cfg80211_destroy(ar); +} +EXPORT_SYMBOL(ath6kl_core_destroy); + +MODULE_AUTHOR("Qualcomm Atheros"); +MODULE_DESCRIPTION("Core module for AR600x SDIO and USB devices."); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index c863a28f2e0c..f1dd8906be45 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -1,5 +1,6 @@ /* * 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 @@ -44,6 +45,10 @@ #define ATH6KL_MAX_ENDPOINTS 4 #define MAX_NODE_NUM 15 +#define ATH6KL_APSD_ALL_FRAME 0xFFFF +#define ATH6KL_APSD_NUM_OF_AC 0x4 +#define ATH6KL_APSD_FRAME_MASK 0xF + /* Extra bytes for htc header alignment */ #define ATH6KL_HTC_ALIGN_BYTES 3 @@ -55,8 +60,9 @@ #define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC) #define DISCON_TIMER_INTVAL 10000 /* in msec */ -#define A_DEFAULT_LISTEN_INTERVAL 100 -#define A_MAX_WOW_LISTEN_INTERVAL 1000 + +/* Channel dwell time in fg scan */ +#define ATH6KL_FG_SCAN_INTERVAL 50 /* in ms */ /* includes also the null byte */ #define ATH6KL_FIRMWARE_MAGIC "QCA-ATH6KL" @@ -97,45 +103,49 @@ struct ath6kl_fw_ie { u8 data[0]; }; +#define ATH6KL_FW_API2_FILE "fw-2.bin" +#define ATH6KL_FW_API3_FILE "fw-3.bin" + /* AR6003 1.0 definitions */ #define AR6003_HW_1_0_VERSION 0x300002ba /* AR6003 2.0 definitions */ #define AR6003_HW_2_0_VERSION 0x30000384 #define AR6003_HW_2_0_PATCH_DOWNLOAD_ADDRESS 0x57e910 -#define AR6003_HW_2_0_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77" -#define AR6003_HW_2_0_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77" -#define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin" -#define AR6003_HW_2_0_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin" -#define AR6003_HW_2_0_FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2.bin" +#define AR6003_HW_2_0_FW_DIR "ath6k/AR6003/hw2.0" +#define AR6003_HW_2_0_OTP_FILE "otp.bin.z77" +#define AR6003_HW_2_0_FIRMWARE_FILE "athwlan.bin.z77" +#define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "athtcmd_ram.bin" +#define AR6003_HW_2_0_PATCH_FILE "data.patch.bin" #define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin" #define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \ "ath6k/AR6003/hw2.0/bdata.SD31.bin" /* AR6003 3.0 definitions */ #define AR6003_HW_2_1_1_VERSION 0x30000582 -#define AR6003_HW_2_1_1_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin" -#define AR6003_HW_2_1_1_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin" -#define AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE \ - "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin" -#define AR6003_HW_2_1_1_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin" -#define AR6003_HW_2_1_1_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin" +#define AR6003_HW_2_1_1_FW_DIR "ath6k/AR6003/hw2.1.1" +#define AR6003_HW_2_1_1_OTP_FILE "otp.bin" +#define AR6003_HW_2_1_1_FIRMWARE_FILE "athwlan.bin" +#define AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE "athtcmd_ram.bin" +#define AR6003_HW_2_1_1_UTF_FIRMWARE_FILE "utf.bin" +#define AR6003_HW_2_1_1_TESTSCRIPT_FILE "nullTestFlow.bin" +#define AR6003_HW_2_1_1_PATCH_FILE "data.patch.bin" #define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin" #define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE \ "ath6k/AR6003/hw2.1.1/bdata.SD31.bin" /* AR6004 1.0 definitions */ #define AR6004_HW_1_0_VERSION 0x30000623 -#define AR6004_HW_1_0_FIRMWARE_2_FILE "ath6k/AR6004/hw1.0/fw-2.bin" -#define AR6004_HW_1_0_FIRMWARE_FILE "ath6k/AR6004/hw1.0/fw.ram.bin" +#define AR6004_HW_1_0_FW_DIR "ath6k/AR6004/hw1.0" +#define AR6004_HW_1_0_FIRMWARE_FILE "fw.ram.bin" #define AR6004_HW_1_0_BOARD_DATA_FILE "ath6k/AR6004/hw1.0/bdata.bin" #define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \ "ath6k/AR6004/hw1.0/bdata.DB132.bin" /* AR6004 1.1 definitions */ #define AR6004_HW_1_1_VERSION 0x30000001 -#define AR6004_HW_1_1_FIRMWARE_2_FILE "ath6k/AR6004/hw1.1/fw-2.bin" -#define AR6004_HW_1_1_FIRMWARE_FILE "ath6k/AR6004/hw1.1/fw.ram.bin" +#define AR6004_HW_1_1_FW_DIR "ath6k/AR6004/hw1.1" +#define AR6004_HW_1_1_FIRMWARE_FILE "fw.ram.bin" #define AR6004_HW_1_1_BOARD_DATA_FILE "ath6k/AR6004/hw1.1/bdata.bin" #define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \ "ath6k/AR6004/hw1.1/bdata.DB132.bin" @@ -144,6 +154,8 @@ struct ath6kl_fw_ie { #define STA_PS_AWAKE BIT(0) #define STA_PS_SLEEP BIT(1) #define STA_PS_POLLED BIT(2) +#define STA_PS_APSD_TRIGGER BIT(3) +#define STA_PS_APSD_EOSP BIT(4) /* HTC TX packet tagging definitions */ #define ATH6KL_CONTROL_PKT_TAG HTC_TX_PACKET_TAG_USER_DEFINED @@ -173,6 +185,11 @@ struct ath6kl_fw_ie { #define MBOX_YIELD_LIMIT 99 +#define ATH6KL_DEFAULT_LISTEN_INTVAL 100 /* in TUs */ +#define ATH6KL_DEFAULT_BMISS_TIME 1500 +#define ATH6KL_MAX_WOW_LISTEN_INTL 300 /* in TUs */ +#define ATH6KL_MAX_BMISS_TIME 5000 + /* configuration lags */ /* * ATH6KL_CONF_IGNORE_ERP_BARKER: Ignore the barker premable in @@ -186,7 +203,7 @@ struct ath6kl_fw_ie { #define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN BIT(1) #define ATH6KL_CONF_ENABLE_11N BIT(2) #define ATH6KL_CONF_ENABLE_TX_BURST BIT(3) -#define ATH6KL_CONF_SUSPEND_CUTPOWER BIT(4) +#define ATH6KL_CONF_UART_DEBUG BIT(4) enum wlan_low_pwr_state { WLAN_POWER_STATE_ON, @@ -216,6 +233,12 @@ struct rxtid { u32 hold_q_sz; struct skb_hold_q *hold_q; struct sk_buff_head q; + + /* + * FIXME: No clue what this should protect. Apparently it should + * protect some of the fields above but they are also accessed + * without taking the lock. + */ spinlock_t lock; }; @@ -231,14 +254,19 @@ struct rxtid_stats { u32 num_bar; }; -struct aggr_info { +struct aggr_info_conn { u8 aggr_sz; u8 timer_scheduled; struct timer_list timer; struct net_device *dev; struct rxtid rx_tid[NUM_OF_TIDS]; - struct sk_buff_head free_q; struct rxtid_stats stat[NUM_OF_TIDS]; + struct aggr_info *aggr_info; +}; + +struct aggr_info { + struct aggr_info_conn *aggr_conn; + struct sk_buff_head rx_amsdu_freeq; }; struct ath6kl_wep_key { @@ -270,6 +298,16 @@ struct ath6kl_cookie { struct ath6kl_cookie *arc_list_next; }; +struct ath6kl_mgmt_buff { + struct list_head list; + u32 freq; + u32 wait; + u32 id; + bool no_cck; + size_t len; + u8 buf[0]; +}; + struct ath6kl_sta { u16 sta_flags; u8 mac[ETH_ALEN]; @@ -279,7 +317,15 @@ struct ath6kl_sta { u8 auth; u8 wpa_ie[ATH6KL_MAX_IE]; struct sk_buff_head psq; + + /* protects psq, mgmt_psq, apsdq, and mgmt_psq_len fields */ spinlock_t psq_lock; + + struct list_head mgmt_psq; + size_t mgmt_psq_len; + u8 apsd_info; + struct sk_buff_head apsdq; + struct aggr_info_conn *aggr_conn; }; struct ath6kl_version { @@ -408,6 +454,13 @@ enum ath6kl_hif_type { ATH6KL_HIF_TYPE_USB, }; +/* Max number of filters that hw supports */ +#define ATH6K_MAX_MC_FILTERS_PER_LIST 7 +struct ath6kl_mc_filter { + struct list_head list; + char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; +}; + /* * Driver's maximum limit, note that some firmwares support only one vif * and the runtime (current) limit must be checked from ar->vif_max. @@ -426,6 +479,7 @@ enum ath6kl_vif_state { DTIM_PERIOD_AVAIL, WLAN_ENABLED, STATS_UPDATE_PEND, + HOST_SLEEP_MODE_CMD_PROCESSED, }; struct ath6kl_vif { @@ -468,9 +522,13 @@ struct ath6kl_vif { bool probe_req_report; u16 next_chan; u16 assoc_bss_beacon_int; + u16 listen_intvl_t; + u16 bmiss_time_t; u8 assoc_bss_dtim_period; struct net_device_stats net_stats; struct target_stats target_stats; + + struct list_head mc_filter; }; #define WOW_LIST_ID 0 @@ -493,6 +551,8 @@ enum ath6kl_dev_state { enum ath6kl_state { ATH6KL_STATE_OFF, ATH6KL_STATE_ON, + ATH6KL_STATE_SUSPENDING, + ATH6KL_STATE_RESUMING, ATH6KL_STATE_DEEPSLEEP, ATH6KL_STATE_CUTPOWER, ATH6KL_STATE_WOW, @@ -504,6 +564,7 @@ struct ath6kl { struct wiphy *wiphy; enum ath6kl_state state; + unsigned int testmode; struct ath6kl_bmi bmi; const struct ath6kl_hif_ops *hif_ops; @@ -520,10 +581,14 @@ struct ath6kl { unsigned int vif_max; u8 max_norm_iface; u8 avail_idx_map; + + /* + * Protects at least amsdu_rx_buffer_queue, ath6kl_alloc_cookie() + * calls, tx_pending and total_tx_data_pend. + */ spinlock_t lock; + struct semaphore sem; - u16 listen_intvl_b; - u16 listen_intvl_t; u8 lrssi_roam_threshold; struct ath6kl_version version; u32 target_type; @@ -549,7 +614,13 @@ struct ath6kl { u8 sta_list_index; struct ath6kl_req_key ap_mode_bkey; struct sk_buff_head mcastpsq; + + /* + * FIXME: protects access to mcastpsq but is actually useless as + * all skbe_queue_*() functions provide serialisation themselves + */ spinlock_t mcastpsq_lock; + u8 intra_bss; struct wmi_ap_mode_stat ap_stats; u8 ap_country_code[3]; @@ -574,17 +645,25 @@ struct ath6kl { u32 board_addr; u32 refclk_hz; u32 uarttx_pin; + u32 testscript_addr; + + struct ath6kl_hw_fw { + const char *dir; + const char *otp; + const char *fw; + const char *tcmd; + const char *patch; + const char *utf; + const char *testscript; + } fw; - const char *fw_otp; - const char *fw; - const char *fw_tcmd; - const char *fw_patch; - const char *fw_api2; const char *fw_board; const char *fw_default_board; } hw; u16 conf_flags; + u16 suspend_mode; + u16 wow_suspend_mode; wait_queue_head_t event_wq; struct ath6kl_mbox_info mbox_info; @@ -603,6 +682,10 @@ struct ath6kl { u8 *fw_patch; size_t fw_patch_len; + u8 *fw_testscript; + size_t fw_testscript_len; + + unsigned int fw_api; unsigned long fw_capabilities[ATH6KL_CAPABILITY_LEN]; struct workqueue_struct *ath6kl_wq; @@ -611,12 +694,16 @@ struct ath6kl { bool p2p; + bool wiphy_registered; + #ifdef CONFIG_ATH6KL_DEBUG struct { - struct circ_buf fwlog_buf; - spinlock_t fwlog_lock; - void *fwlog_tmp; + struct sk_buff_head fwlog_queue; + struct completion fwlog_completion; + bool fwlog_open; + u32 fwlog_mask; + unsigned int dbgfs_diag_reg; u32 diag_reg_addr_wr; u32 diag_reg_val_wr; @@ -676,7 +763,9 @@ struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar); void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie); int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev); -struct aggr_info *aggr_init(struct net_device *dev); +struct aggr_info *aggr_init(struct ath6kl_vif *vif); +void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info, + struct aggr_info_conn *aggr_conn); void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint); void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count); @@ -684,12 +773,12 @@ struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target, enum htc_endpoint_id endpoint, int len); void aggr_module_destroy(struct aggr_info *aggr_info); -void aggr_reset_state(struct aggr_info *aggr_info); +void aggr_reset_state(struct aggr_info_conn *aggr_conn); -struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 * node_addr); +struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr); struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid); -void ath6kl_ready_event(void *devt, u8 * datap, u32 sw_ver, u32 abi_ver); +void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver); int ath6kl_control_tx(void *devt, struct sk_buff *skb, enum htc_endpoint_id eid); void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, @@ -700,7 +789,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel); void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, u8 keymgmt, u8 ucipher, u8 auth, - u8 assoc_req_len, u8 *assoc_info); + u8 assoc_req_len, u8 *assoc_info, u8 apsd_info); void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, u8 assoc_resp_len, u8 *assoc_info, u16 prot_reason_status); @@ -723,12 +812,18 @@ void ath6kl_wakeup_event(void *dev); void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, bool wait_fot_compltn, bool cold_reset); void ath6kl_init_control_info(struct ath6kl_vif *vif); -void ath6kl_deinit_if_data(struct ath6kl_vif *vif); -void ath6kl_core_free(struct ath6kl *ar); struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar); void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready); int ath6kl_init_hw_start(struct ath6kl *ar); int ath6kl_init_hw_stop(struct ath6kl *ar); +int ath6kl_init_fetch_firmwares(struct ath6kl *ar); +int ath6kl_init_hw_params(struct ath6kl *ar); + void ath6kl_check_wow_status(struct ath6kl *ar); +struct ath6kl *ath6kl_core_create(struct device *dev); +int ath6kl_core_init(struct ath6kl *ar); +void ath6kl_core_cleanup(struct ath6kl *ar); +void ath6kl_core_destroy(struct ath6kl *ar); + #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index eb808b46f94c..552adb3f80d0 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-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 @@ -16,7 +17,7 @@ #include "core.h" -#include <linux/circ_buf.h> +#include <linux/skbuff.h> #include <linux/fs.h> #include <linux/vmalloc.h> #include <linux/export.h> @@ -32,9 +33,8 @@ struct ath6kl_fwlog_slot { u8 payload[0]; }; -#define ATH6KL_FWLOG_SIZE 32768 -#define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \ - ATH6KL_FWLOG_PAYLOAD_SIZE) +#define ATH6KL_FWLOG_MAX_ENTRIES 20 + #define ATH6KL_FWLOG_VALID_MASK 0x1ffff int ath6kl_printk(const char *level, const char *fmt, ...) @@ -54,9 +54,42 @@ int ath6kl_printk(const char *level, const char *fmt, ...) return rtn; } +EXPORT_SYMBOL(ath6kl_printk); #ifdef CONFIG_ATH6KL_DEBUG +void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + if (!(debug_mask & mask)) + return; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + ath6kl_printk(KERN_DEBUG, "%pV", &vaf); + + va_end(args); +} +EXPORT_SYMBOL(ath6kl_dbg); + +void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, + const char *msg, const char *prefix, + const void *buf, size_t len) +{ + if (debug_mask & mask) { + if (msg) + ath6kl_dbg(mask, "%s\n", msg); + + print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); + } +} +EXPORT_SYMBOL(ath6kl_dbg_dump); + #define REG_OUTPUT_LEN_PER_LINE 25 #define REGTYPE_STR_LEN 100 @@ -82,63 +115,63 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, struct ath6kl_irq_enable_reg *irq_enable_reg) { - ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n")); + ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n")); if (irq_proc_reg != NULL) { - ath6kl_dbg(ATH6KL_DBG_ANY, - "Host Int status: 0x%x\n", - irq_proc_reg->host_int_status); - ath6kl_dbg(ATH6KL_DBG_ANY, + ath6kl_dbg(ATH6KL_DBG_IRQ, + "Host Int status: 0x%x\n", + irq_proc_reg->host_int_status); + ath6kl_dbg(ATH6KL_DBG_IRQ, "CPU Int status: 0x%x\n", - irq_proc_reg->cpu_int_status); - ath6kl_dbg(ATH6KL_DBG_ANY, + irq_proc_reg->cpu_int_status); + ath6kl_dbg(ATH6KL_DBG_IRQ, "Error Int status: 0x%x\n", - irq_proc_reg->error_int_status); - ath6kl_dbg(ATH6KL_DBG_ANY, + irq_proc_reg->error_int_status); + ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status: 0x%x\n", - irq_proc_reg->counter_int_status); - ath6kl_dbg(ATH6KL_DBG_ANY, + irq_proc_reg->counter_int_status); + ath6kl_dbg(ATH6KL_DBG_IRQ, "Mbox Frame: 0x%x\n", - irq_proc_reg->mbox_frame); - ath6kl_dbg(ATH6KL_DBG_ANY, + irq_proc_reg->mbox_frame); + ath6kl_dbg(ATH6KL_DBG_IRQ, "Rx Lookahead Valid: 0x%x\n", - irq_proc_reg->rx_lkahd_valid); - ath6kl_dbg(ATH6KL_DBG_ANY, + irq_proc_reg->rx_lkahd_valid); + ath6kl_dbg(ATH6KL_DBG_IRQ, "Rx Lookahead 0: 0x%x\n", - irq_proc_reg->rx_lkahd[0]); - ath6kl_dbg(ATH6KL_DBG_ANY, + irq_proc_reg->rx_lkahd[0]); + ath6kl_dbg(ATH6KL_DBG_IRQ, "Rx Lookahead 1: 0x%x\n", - irq_proc_reg->rx_lkahd[1]); + irq_proc_reg->rx_lkahd[1]); if (dev->ar->mbox_info.gmbox_addr != 0) { /* * If the target supports GMBOX hardware, dump some * additional state. */ - ath6kl_dbg(ATH6KL_DBG_ANY, - "GMBOX Host Int status 2: 0x%x\n", - irq_proc_reg->host_int_status2); - ath6kl_dbg(ATH6KL_DBG_ANY, - "GMBOX RX Avail: 0x%x\n", - irq_proc_reg->gmbox_rx_avail); - ath6kl_dbg(ATH6KL_DBG_ANY, - "GMBOX lookahead alias 0: 0x%x\n", - irq_proc_reg->rx_gmbox_lkahd_alias[0]); - ath6kl_dbg(ATH6KL_DBG_ANY, - "GMBOX lookahead alias 1: 0x%x\n", - irq_proc_reg->rx_gmbox_lkahd_alias[1]); + ath6kl_dbg(ATH6KL_DBG_IRQ, + "GMBOX Host Int status 2: 0x%x\n", + irq_proc_reg->host_int_status2); + ath6kl_dbg(ATH6KL_DBG_IRQ, + "GMBOX RX Avail: 0x%x\n", + irq_proc_reg->gmbox_rx_avail); + ath6kl_dbg(ATH6KL_DBG_IRQ, + "GMBOX lookahead alias 0: 0x%x\n", + irq_proc_reg->rx_gmbox_lkahd_alias[0]); + ath6kl_dbg(ATH6KL_DBG_IRQ, + "GMBOX lookahead alias 1: 0x%x\n", + irq_proc_reg->rx_gmbox_lkahd_alias[1]); } } if (irq_enable_reg != NULL) { - ath6kl_dbg(ATH6KL_DBG_ANY, - "Int status Enable: 0x%x\n", - irq_enable_reg->int_status_en); - ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n", - irq_enable_reg->cntr_int_status_en); + ath6kl_dbg(ATH6KL_DBG_IRQ, + "Int status Enable: 0x%x\n", + irq_enable_reg->int_status_en); + ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n", + irq_enable_reg->cntr_int_status_en); } - ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n"); + ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n"); } static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist) @@ -175,9 +208,6 @@ void dump_cred_dist_stats(struct htc_target *target) { struct htc_endpoint_credit_dist *ep_list; - if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_CREDIT)) - return; - list_for_each_entry(ep_list, &target->cred_dist_list, list) dump_cred_dist(ep_list); @@ -238,105 +268,103 @@ static const struct file_operations fops_war_stats = { .llseek = default_llseek, }; -static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf, - size_t buf_len) +void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) { - struct circ_buf *fwlog = &ar->debug.fwlog_buf; - size_t space; - int i; + struct ath6kl_fwlog_slot *slot; + struct sk_buff *skb; + size_t slot_len; - /* entries must all be equal size */ - if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE)) + if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) return; - space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE); - if (space < buf_len) - /* discard oldest slot */ - fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) & - (ATH6KL_FWLOG_SIZE - 1); + slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE; - for (i = 0; i < buf_len; i += space) { - space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail, - ATH6KL_FWLOG_SIZE); + skb = alloc_skb(slot_len, GFP_KERNEL); + if (!skb) + return; - if ((size_t) space > buf_len - i) - space = buf_len - i; + slot = (struct ath6kl_fwlog_slot *) skb_put(skb, slot_len); + slot->timestamp = cpu_to_le32(jiffies); + slot->length = cpu_to_le32(len); + memcpy(slot->payload, buf, len); - memcpy(&fwlog->buf[fwlog->head], buf, space); - fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1); - } + /* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */ + memset(slot->payload + len, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - len); -} + spin_lock(&ar->debug.fwlog_queue.lock); -void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) -{ - struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp; - size_t slot_len; + __skb_queue_tail(&ar->debug.fwlog_queue, skb); + complete(&ar->debug.fwlog_completion); - if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) - return; + /* drop oldest entries */ + while (skb_queue_len(&ar->debug.fwlog_queue) > + ATH6KL_FWLOG_MAX_ENTRIES) { + skb = __skb_dequeue(&ar->debug.fwlog_queue); + kfree_skb(skb); + } - spin_lock_bh(&ar->debug.fwlog_lock); + spin_unlock(&ar->debug.fwlog_queue.lock); - slot->timestamp = cpu_to_le32(jiffies); - slot->length = cpu_to_le32(len); - memcpy(slot->payload, buf, len); + return; +} - slot_len = sizeof(*slot) + len; +static int ath6kl_fwlog_open(struct inode *inode, struct file *file) +{ + struct ath6kl *ar = inode->i_private; - if (slot_len < ATH6KL_FWLOG_SLOT_SIZE) - memset(slot->payload + len, 0, - ATH6KL_FWLOG_SLOT_SIZE - slot_len); + if (ar->debug.fwlog_open) + return -EBUSY; - ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE); + ar->debug.fwlog_open = true; - spin_unlock_bh(&ar->debug.fwlog_lock); + file->private_data = inode->i_private; + return 0; } -static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar) +static int ath6kl_fwlog_release(struct inode *inode, struct file *file) { - return CIRC_CNT(ar->debug.fwlog_buf.head, - ar->debug.fwlog_buf.tail, - ATH6KL_FWLOG_SLOT_SIZE) == 0; + struct ath6kl *ar = inode->i_private; + + ar->debug.fwlog_open = false; + + return 0; } static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath6kl *ar = file->private_data; - struct circ_buf *fwlog = &ar->debug.fwlog_buf; - size_t len = 0, buf_len = count; + struct sk_buff *skb; ssize_t ret_cnt; + size_t len = 0; char *buf; - int ccnt; - buf = vmalloc(buf_len); + buf = vmalloc(count); if (!buf) return -ENOMEM; /* read undelivered logs from firmware */ ath6kl_read_fwlogs(ar); - spin_lock_bh(&ar->debug.fwlog_lock); + spin_lock(&ar->debug.fwlog_queue.lock); - while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) { - ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail, - ATH6KL_FWLOG_SIZE); + while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) { + if (skb->len > count - len) { + /* not enough space, put skb back and leave */ + __skb_queue_head(&ar->debug.fwlog_queue, skb); + break; + } - if ((size_t) ccnt > buf_len - len) - ccnt = buf_len - len; - memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt); - len += ccnt; + memcpy(buf + len, skb->data, skb->len); + len += skb->len; - fwlog->tail = (fwlog->tail + ccnt) & - (ATH6KL_FWLOG_SIZE - 1); + kfree_skb(skb); } - spin_unlock_bh(&ar->debug.fwlog_lock); + spin_unlock(&ar->debug.fwlog_queue.lock); - if (WARN_ON(len > buf_len)) - len = buf_len; + /* FIXME: what to do if len == 0? */ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); @@ -346,12 +374,87 @@ static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, } static const struct file_operations fops_fwlog = { - .open = ath6kl_debugfs_open, + .open = ath6kl_fwlog_open, + .release = ath6kl_fwlog_release, .read = ath6kl_fwlog_read, .owner = THIS_MODULE, .llseek = default_llseek, }; +static ssize_t ath6kl_fwlog_block_read(struct file *file, + char __user *user_buf, + size_t count, + loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + struct sk_buff *skb; + ssize_t ret_cnt; + size_t len = 0, not_copied; + char *buf; + int ret; + + buf = vmalloc(count); + if (!buf) + return -ENOMEM; + + spin_lock(&ar->debug.fwlog_queue.lock); + + if (skb_queue_len(&ar->debug.fwlog_queue) == 0) { + /* we must init under queue lock */ + init_completion(&ar->debug.fwlog_completion); + + spin_unlock(&ar->debug.fwlog_queue.lock); + + ret = wait_for_completion_interruptible( + &ar->debug.fwlog_completion); + if (ret == -ERESTARTSYS) + return ret; + + spin_lock(&ar->debug.fwlog_queue.lock); + } + + while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) { + if (skb->len > count - len) { + /* not enough space, put skb back and leave */ + __skb_queue_head(&ar->debug.fwlog_queue, skb); + break; + } + + + memcpy(buf + len, skb->data, skb->len); + len += skb->len; + + kfree_skb(skb); + } + + spin_unlock(&ar->debug.fwlog_queue.lock); + + /* FIXME: what to do if len == 0? */ + + not_copied = copy_to_user(user_buf, buf, len); + if (not_copied != 0) { + ret_cnt = -EFAULT; + goto out; + } + + *ppos = *ppos + len; + + ret_cnt = len; + +out: + vfree(buf); + + return ret_cnt; +} + +static const struct file_operations fops_fwlog_block = { + .open = ath6kl_fwlog_open, + .release = ath6kl_fwlog_release, + .read = ath6kl_fwlog_block_read, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -637,9 +740,13 @@ static ssize_t ath6kl_endpoint_stats_read(struct file *file, return -ENOMEM; #define EPSTAT(name) \ - len = print_endpoint_stat(target, buf, buf_len, len, \ - offsetof(struct htc_endpoint_stats, name), \ - #name) + do { \ + len = print_endpoint_stat(target, buf, buf_len, len, \ + offsetof(struct htc_endpoint_stats, \ + name), \ + #name); \ + } while (0) + EPSTAT(cred_low_indicate); EPSTAT(tx_issued); EPSTAT(tx_pkt_bundled); @@ -749,17 +856,9 @@ static ssize_t ath6kl_regread_write(struct file *file, size_t count, loff_t *ppos) { struct ath6kl *ar = file->private_data; - u8 buf[50]; - unsigned int len; unsigned long reg_addr; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - - if (strict_strtoul(buf, 0, ®_addr)) + if (kstrtoul_from_user(user_buf, count, 0, ®_addr)) return -EINVAL; if ((reg_addr % 4) != 0) @@ -873,15 +972,8 @@ static ssize_t ath6kl_lrssi_roam_write(struct file *file, { struct ath6kl *ar = file->private_data; unsigned long lrssi_roam_threshold; - char buf[32]; - ssize_t len; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (strict_strtoul(buf, 0, &lrssi_roam_threshold)) + if (kstrtoul_from_user(user_buf, count, 0, &lrssi_roam_threshold)) return -EINVAL; ar->lrssi_roam_threshold = lrssi_roam_threshold; @@ -1411,6 +1503,8 @@ static ssize_t ath6kl_create_qos_write(struct file *file, return -EINVAL; pstream.medium_time = cpu_to_le32(val32); + pstream.nominal_phy = le32_to_cpu(pstream.min_phy_rate) / 1000000; + ath6kl_wmi_create_pstream_cmd(ar->wmi, vif->fw_vif_idx, &pstream); return count; @@ -1505,57 +1599,51 @@ static const struct file_operations fops_bgscan_int = { }; static ssize_t ath6kl_listen_int_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) + const char __user *user_buf, + size_t count, loff_t *ppos) { struct ath6kl *ar = file->private_data; - u16 listen_int_t, listen_int_b; + struct ath6kl_vif *vif; + u16 listen_interval; char buf[32]; - char *sptr, *token; ssize_t len; + vif = ath6kl_vif_first(ar); + if (!vif) + return -EIO; + len = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, len)) return -EFAULT; buf[len] = '\0'; - sptr = buf; - - token = strsep(&sptr, " "); - if (!token) + if (kstrtou16(buf, 0, &listen_interval)) return -EINVAL; - if (kstrtou16(token, 0, &listen_int_t)) + if ((listen_interval < 15) || (listen_interval > 3000)) return -EINVAL; - if (kstrtou16(sptr, 0, &listen_int_b)) - return -EINVAL; - - if ((listen_int_t < 15) || (listen_int_t > 5000)) - return -EINVAL; - - if ((listen_int_b < 1) || (listen_int_b > 50)) - return -EINVAL; - - ar->listen_intvl_t = listen_int_t; - ar->listen_intvl_b = listen_int_b; - - ath6kl_wmi_listeninterval_cmd(ar->wmi, 0, ar->listen_intvl_t, - ar->listen_intvl_b); + vif->listen_intvl_t = listen_interval; + ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, + vif->listen_intvl_t, 0); return count; } static ssize_t ath6kl_listen_int_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) + char __user *user_buf, + size_t count, loff_t *ppos) { struct ath6kl *ar = file->private_data; + struct ath6kl_vif *vif; char buf[32]; int len; - len = scnprintf(buf, sizeof(buf), "%u %u\n", ar->listen_intvl_t, - ar->listen_intvl_b); + vif = ath6kl_vif_first(ar); + if (!vif) + return -EIO; + + len = scnprintf(buf, sizeof(buf), "%u\n", vif->listen_intvl_t); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -1628,33 +1716,29 @@ static const struct file_operations fops_power_params = { .llseek = default_llseek, }; -int ath6kl_debug_init(struct ath6kl *ar) +void ath6kl_debug_init(struct ath6kl *ar) { - ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE); - if (ar->debug.fwlog_buf.buf == NULL) - return -ENOMEM; - - ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL); - if (ar->debug.fwlog_tmp == NULL) { - vfree(ar->debug.fwlog_buf.buf); - return -ENOMEM; - } - - spin_lock_init(&ar->debug.fwlog_lock); + skb_queue_head_init(&ar->debug.fwlog_queue); + init_completion(&ar->debug.fwlog_completion); /* * Actually we are lying here but don't know how to read the mask * value from the firmware. */ ar->debug.fwlog_mask = 0; +} +/* + * Initialisation needs to happen in two stages as fwlog events can come + * before cfg80211 is initialised, and debugfs depends on cfg80211 + * initialisation. + */ +int ath6kl_debug_init_fs(struct ath6kl *ar) +{ ar->debugfs_phy = debugfs_create_dir("ath6kl", ar->wiphy->debugfsdir); - if (!ar->debugfs_phy) { - vfree(ar->debug.fwlog_buf.buf); - kfree(ar->debug.fwlog_tmp); + if (!ar->debugfs_phy) return -ENOMEM; - } debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, &fops_tgt_stats); @@ -1668,6 +1752,9 @@ int ath6kl_debug_init(struct ath6kl *ar) debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, &fops_fwlog); + debugfs_create_file("fwlog_block", S_IRUSR, ar->debugfs_phy, ar, + &fops_fwlog_block); + debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar, &fops_fwlog_mask); @@ -1702,24 +1789,26 @@ int ath6kl_debug_init(struct ath6kl *ar) ar->debugfs_phy, ar, &fops_disconnect_timeout); debugfs_create_file("create_qos", S_IWUSR, ar->debugfs_phy, ar, - &fops_create_qos); + &fops_create_qos); debugfs_create_file("delete_qos", S_IWUSR, ar->debugfs_phy, ar, - &fops_delete_qos); + &fops_delete_qos); debugfs_create_file("bgscan_interval", S_IWUSR, - ar->debugfs_phy, ar, &fops_bgscan_int); + ar->debugfs_phy, ar, &fops_bgscan_int); + + debugfs_create_file("listen_interval", S_IRUSR | S_IWUSR, + ar->debugfs_phy, ar, &fops_listen_int); debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar, - &fops_power_params); + &fops_power_params); return 0; } void ath6kl_debug_cleanup(struct ath6kl *ar) { - vfree(ar->debug.fwlog_buf.buf); - kfree(ar->debug.fwlog_tmp); + skb_queue_purge(&ar->debug.fwlog_queue); kfree(ar->debug.roam_tbl); } diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index 9853c9c125c1..1803a0baae82 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -1,5 +1,6 @@ /* * Copyright (c) 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 @@ -41,6 +42,7 @@ enum ATH6K_DEBUG_MASK { ATH6KL_DBG_BOOT = BIT(18), /* driver init and fw boot */ ATH6KL_DBG_WMI_DUMP = BIT(19), ATH6KL_DBG_SUSPEND = BIT(20), + ATH6KL_DBG_USB = BIT(21), ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ }; @@ -55,35 +57,16 @@ int ath6kl_printk(const char *level, const char *fmt, ...); #define ath6kl_warn(fmt, ...) \ ath6kl_printk(KERN_WARNING, fmt, ##__VA_ARGS__) -#define AR_DBG_LVL_CHECK(mask) (debug_mask & mask) - enum ath6kl_war { ATH6KL_WAR_INVALID_RATE, }; #ifdef CONFIG_ATH6KL_DEBUG -#define ath6kl_dbg(mask, fmt, ...) \ - ({ \ - int rtn; \ - if (debug_mask & mask) \ - rtn = ath6kl_printk(KERN_DEBUG, fmt, ##__VA_ARGS__); \ - else \ - rtn = 0; \ - \ - rtn; \ - }) - -static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, - const char *msg, const char *prefix, - const void *buf, size_t len) -{ - if (debug_mask & mask) { - if (msg) - ath6kl_dbg(mask, "%s\n", msg); - print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); - } -} +void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...); +void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, + const char *msg, const char *prefix, + const void *buf, size_t len); void ath6kl_dump_registers(struct ath6kl_device *dev, struct ath6kl_irq_proc_registers *irq_proc_reg, @@ -95,7 +78,8 @@ int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf, size_t len); void ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive); void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout); -int ath6kl_debug_init(struct ath6kl *ar); +void ath6kl_debug_init(struct ath6kl *ar); +int ath6kl_debug_init_fs(struct ath6kl *ar); void ath6kl_debug_cleanup(struct ath6kl *ar); #else @@ -145,7 +129,11 @@ static inline void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, { } -static inline int ath6kl_debug_init(struct ath6kl *ar) +static inline void ath6kl_debug_init(struct ath6kl *ar) +{ +} + +static inline int ath6kl_debug_init_fs(struct ath6kl *ar) { return 0; } diff --git a/drivers/net/wireless/ath/ath6kl/hif-ops.h b/drivers/net/wireless/ath/ath6kl/hif-ops.h index 2fe1dadfc77a..fd84086638e3 100644 --- a/drivers/net/wireless/ath/ath6kl/hif-ops.h +++ b/drivers/net/wireless/ath/ath6kl/hif-ops.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011 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 diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index e57da35e59fa..68ed6c2665b7 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2007-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 @@ -15,6 +16,8 @@ */ #include "hif.h" +#include <linux/export.h> + #include "core.h" #include "target.h" #include "hif-ops.h" @@ -59,6 +62,8 @@ int ath6kl_hif_rw_comp_handler(void *context, int status) return 0; } +EXPORT_SYMBOL(ath6kl_hif_rw_comp_handler); + #define REG_DUMP_COUNT_AR6003 60 #define REGISTER_DUMP_LEN_MAX 60 @@ -85,7 +90,7 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar) } ath6kl_dbg(ATH6KL_DBG_IRQ, "register dump data address 0x%x\n", - regdump_addr); + regdump_addr); regdump_addr = TARG_VTOP(ar->target_type, regdump_addr); /* fetch register dump data */ @@ -102,9 +107,9 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar) BUILD_BUG_ON(REG_DUMP_COUNT_AR6003 % 4); - for (i = 0; i < REG_DUMP_COUNT_AR6003 / 4; i++) { + for (i = 0; i < REG_DUMP_COUNT_AR6003; i += 4) { ath6kl_info("%d: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n", - 4 * i, + i, le32_to_cpu(regdump_val[i]), le32_to_cpu(regdump_val[i + 1]), le32_to_cpu(regdump_val[i + 2]), @@ -130,6 +135,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev) ath6kl_warn("Failed to clear debug interrupt: %d\n", ret); ath6kl_hif_dump_fw_crash(dev->ar); + ath6kl_read_fwlogs(dev->ar); return ret; } @@ -279,7 +285,7 @@ static int ath6kl_hif_proc_counter_intr(struct ath6kl_device *dev) dev->irq_en_reg.cntr_int_status_en; ath6kl_dbg(ATH6KL_DBG_IRQ, - "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n", + "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n", counter_int_status); /* @@ -354,7 +360,7 @@ static int ath6kl_hif_proc_cpu_intr(struct ath6kl_device *dev) } ath6kl_dbg(ATH6KL_DBG_IRQ, - "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n", + "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n", cpu_int_status); /* Clear the interrupt */ @@ -429,9 +435,8 @@ static int proc_pending_irqs(struct ath6kl_device *dev, bool *done) if (status) goto out; - if (AR_DBG_LVL_CHECK(ATH6KL_DBG_IRQ)) - ath6kl_dump_registers(dev, &dev->irq_proc_reg, - &dev->irq_en_reg); + ath6kl_dump_registers(dev, &dev->irq_proc_reg, + &dev->irq_en_reg); /* Update only those registers that are enabled */ host_int_status = dev->irq_proc_reg.host_int_status & @@ -561,6 +566,7 @@ int ath6kl_hif_intr_bh_handler(struct ath6kl *ar) return status; } +EXPORT_SYMBOL(ath6kl_hif_intr_bh_handler); static int ath6kl_hif_enable_intrs(struct ath6kl_device *dev) { @@ -689,6 +695,11 @@ int ath6kl_hif_setup(struct ath6kl_device *dev) ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n", dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr); + /* usb doesn't support enabling interrupts */ + /* FIXME: remove check once USB support is implemented */ + if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) + return 0; + status = ath6kl_hif_disable_intrs(dev); fail_setup: diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h index 699a036f3a44..20ed6b73517b 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.h +++ b/drivers/net/wireless/ath/ath6kl/hif.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011 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 @@ -197,6 +198,8 @@ struct hif_scatter_req { u8 *virt_dma_buf; struct hif_scatter_item scat_list[1]; + + u32 scat_q_depth; }; struct ath6kl_irq_proc_registers { @@ -220,6 +223,7 @@ struct ath6kl_irq_enable_reg { } __packed; struct ath6kl_device { + /* protects irq_proc_reg and irq_en_reg below */ spinlock_t lock; struct ath6kl_irq_proc_registers irq_proc_reg; struct ath6kl_irq_enable_reg irq_en_reg; diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c index f3b63ca25c7e..4849d99cce77 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.c +++ b/drivers/net/wireless/ath/ath6kl/htc.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2007-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 @@ -22,6 +23,9 @@ #define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) +/* threshold to re-enable Tx bundling for an AC*/ +#define TX_RESUME_BUNDLE_THRESHOLD 1500 + /* Functions for Tx credit handling */ static void ath6kl_credit_deposit(struct ath6kl_htc_credit_info *cred_info, struct htc_endpoint_credit_dist *ep_dist, @@ -168,31 +172,29 @@ static void ath6kl_credit_reduce(struct ath6kl_htc_credit_info *cred_info, static void ath6kl_credit_update(struct ath6kl_htc_credit_info *cred_info, struct list_head *epdist_list) { - struct htc_endpoint_credit_dist *cur_dist_list; + struct htc_endpoint_credit_dist *cur_list; - list_for_each_entry(cur_dist_list, epdist_list, list) { - if (cur_dist_list->endpoint == ENDPOINT_0) + list_for_each_entry(cur_list, epdist_list, list) { + if (cur_list->endpoint == ENDPOINT_0) continue; - if (cur_dist_list->cred_to_dist > 0) { - cur_dist_list->credits += - cur_dist_list->cred_to_dist; - cur_dist_list->cred_to_dist = 0; - if (cur_dist_list->credits > - cur_dist_list->cred_assngd) + if (cur_list->cred_to_dist > 0) { + cur_list->credits += cur_list->cred_to_dist; + cur_list->cred_to_dist = 0; + + if (cur_list->credits > cur_list->cred_assngd) ath6kl_credit_reduce(cred_info, - cur_dist_list, - cur_dist_list->cred_assngd); + cur_list, + cur_list->cred_assngd); - if (cur_dist_list->credits > - cur_dist_list->cred_norm) - ath6kl_credit_reduce(cred_info, cur_dist_list, - cur_dist_list->cred_norm); + if (cur_list->credits > cur_list->cred_norm) + ath6kl_credit_reduce(cred_info, cur_list, + cur_list->cred_norm); - if (!(cur_dist_list->dist_flags & HTC_EP_ACTIVE)) { - if (cur_dist_list->txq_depth == 0) + if (!(cur_list->dist_flags & HTC_EP_ACTIVE)) { + if (cur_list->txq_depth == 0) ath6kl_credit_reduce(cred_info, - cur_dist_list, 0); + cur_list, 0); } } } @@ -460,8 +462,8 @@ static void htc_async_tx_scat_complete(struct htc_target *target, INIT_LIST_HEAD(&tx_compq); ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx scat complete len %d entries %d\n", - scat_req->len, scat_req->scat_entries); + "htc tx scat complete len %d entries %d\n", + scat_req->len, scat_req->scat_entries); if (scat_req->status) ath6kl_err("send scatter req failed: %d\n", scat_req->status); @@ -599,8 +601,8 @@ static void ath6kl_htc_tx_pkts_get(struct htc_target *target, list); ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx got packet 0x%p queue depth %d\n", - packet, get_queue_depth(&endpoint->txq)); + "htc tx got packet 0x%p queue depth %d\n", + packet, get_queue_depth(&endpoint->txq)); len = CALC_TXRX_PADDED_LEN(target, packet->act_len + HTC_HDR_LENGTH); @@ -670,6 +672,7 @@ static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target, struct htc_packet *packet; int i, len, rem_scat, cred_pad; int status = 0; + u8 flags; rem_scat = target->max_tx_bndl_sz; @@ -696,9 +699,9 @@ static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target, scat_req->scat_list[i].packet = packet; /* prepare packet and flag message as part of a send bundle */ - ath6kl_htc_tx_prep_pkt(packet, - packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE, - cred_pad, packet->info.tx.seqno); + flags = packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE; + ath6kl_htc_tx_prep_pkt(packet, flags, + cred_pad, packet->info.tx.seqno); /* Make sure the buffer is 4-byte aligned */ ath6kl_htc_tx_buf_align(&packet->buf, packet->act_len + HTC_HDR_LENGTH); @@ -744,6 +747,12 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, struct hif_scatter_req *scat_req = NULL; int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0; int status; + u32 txb_mask; + u8 ac = WMM_NUM_AC; + + if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || + (WMI_CONTROL_SVC != endpoint->svc_id)) + ac = target->dev->ar->ep2ac_map[endpoint->eid]; while (true) { status = 0; @@ -759,10 +768,35 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, if (!scat_req) { /* no scatter resources */ ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx no more scatter resources\n"); + "htc tx no more scatter resources\n"); break; } + if ((ac < WMM_NUM_AC) && (ac != WMM_AC_BK)) { + if (WMM_AC_BE == ac) + /* + * BE, BK have priorities and bit + * positions reversed + */ + txb_mask = (1 << WMM_AC_BK); + else + /* + * any AC with priority lower than + * itself + */ + txb_mask = ((1 << ac) - 1); + /* + * when the scatter request resources drop below a + * certain threshold, disable Tx bundling for all + * AC's with priority lower than the current requesting + * AC. Otherwise re-enable Tx bundling for them + */ + if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS) + target->tx_bndl_mask &= ~txb_mask; + else + target->tx_bndl_mask |= txb_mask; + } + ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n", n_scat); @@ -806,6 +840,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, struct htc_packet *packet; int bundle_sent; int n_pkts_bundle; + u8 ac = WMM_NUM_AC; spin_lock_bh(&target->tx_lock); @@ -823,6 +858,10 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, */ INIT_LIST_HEAD(&txq); + if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || + (WMI_CONTROL_SVC != endpoint->svc_id)) + ac = target->dev->ar->ep2ac_map[endpoint->eid]; + while (true) { if (list_empty(&endpoint->txq)) @@ -840,15 +879,18 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, while (true) { /* try to send a bundle on each pass */ - if ((target->tx_bndl_enable) && + if ((target->tx_bndl_mask) && (get_queue_depth(&txq) >= HTC_MIN_HTC_MSGS_TO_BUNDLE)) { int temp1 = 0, temp2 = 0; - ath6kl_htc_tx_bundle(endpoint, &txq, - &temp1, &temp2); - bundle_sent += temp1; - n_pkts_bundle += temp2; + /* check if bundling is enabled for an AC */ + if (target->tx_bndl_mask & (1 << ac)) { + ath6kl_htc_tx_bundle(endpoint, &txq, + &temp1, &temp2); + bundle_sent += temp1; + n_pkts_bundle += temp2; + } } if (list_empty(&txq)) @@ -867,6 +909,26 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, endpoint->ep_st.tx_bundles += bundle_sent; endpoint->ep_st.tx_pkt_bundled += n_pkts_bundle; + + /* + * if an AC has bundling disabled and no tx bundling + * has occured continously for a certain number of TX, + * enable tx bundling for this AC + */ + if (!bundle_sent) { + if (!(target->tx_bndl_mask & (1 << ac)) && + (ac < WMM_NUM_AC)) { + if (++target->ac_tx_count[ac] >= + TX_RESUME_BUNDLE_THRESHOLD) { + target->ac_tx_count[ac] = 0; + target->tx_bndl_mask |= (1 << ac); + } + } + } else { + /* tx bundling will reset the counter */ + if (ac < WMM_NUM_AC) + target->ac_tx_count[ac] = 0; + } } endpoint->tx_proc_cnt = 0; @@ -979,8 +1041,8 @@ static int htc_setup_tx_complete(struct htc_target *target) memcpy(&setup_comp_ext->flags, &flags, sizeof(setup_comp_ext->flags)); set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp_ext, - sizeof(struct htc_setup_comp_ext_msg), - ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + sizeof(struct htc_setup_comp_ext_msg), + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); } else { struct htc_setup_comp_msg *setup_comp; @@ -988,8 +1050,8 @@ static int htc_setup_tx_complete(struct htc_target *target) memset(setup_comp, 0, sizeof(struct htc_setup_comp_msg)); setup_comp->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_ID); set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp, - sizeof(struct htc_setup_comp_msg), - ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + sizeof(struct htc_setup_comp_msg), + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); } /* we want synchronous operation */ @@ -1088,9 +1150,9 @@ void ath6kl_htc_flush_txep(struct htc_target *target, packet->status = -ECANCELED; list_del(&packet->list); ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx flushing pkt 0x%p len %d ep %d tag 0x%x\n", - packet, packet->act_len, - packet->endpoint, packet->info.tx.tag); + "htc tx flushing pkt 0x%p len %d ep %d tag 0x%x\n", + packet, packet->act_len, + packet->endpoint, packet->info.tx.tag); INIT_LIST_HEAD(&container); list_add_tail(&packet->list, &container); @@ -1490,7 +1552,7 @@ static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets) if (packets->act_len > 0) { ath6kl_err("htc_ctrl_rx, got message with len:%zu\n", - packets->act_len + HTC_HDR_LENGTH); + packets->act_len + HTC_HDR_LENGTH); ath6kl_dbg_dump(ATH6KL_DBG_HTC, "htc rx unexpected endpoint 0 message", "", @@ -1609,8 +1671,8 @@ static int htc_parse_trailer(struct htc_target *target, } lk_ahd = (struct htc_lookahead_report *) record_buf; - if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) - && next_lk_ahds) { + if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) && + next_lk_ahds) { ath6kl_dbg(ATH6KL_DBG_HTC, "htc rx lk_ahd found pre_valid 0x%x post_valid 0x%x\n", @@ -2038,13 +2100,13 @@ fail_rx: list_for_each_entry_safe(packet, tmp_pkt, rx_pktq, list) { list_del(&packet->list); htc_reclaim_rxbuf(target, packet, - &target->endpoint[packet->endpoint]); + &target->endpoint[packet->endpoint]); } list_for_each_entry_safe(packet, tmp_pkt, &tmp_rxq, list) { list_del(&packet->list); htc_reclaim_rxbuf(target, packet, - &target->endpoint[packet->endpoint]); + &target->endpoint[packet->endpoint]); } return status; @@ -2062,6 +2124,7 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, enum htc_endpoint_id id; int n_fetched = 0; + INIT_LIST_HEAD(&comp_pktq); *num_pkts = 0; /* @@ -2175,11 +2238,11 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target) u32 look_ahead; if (ath6kl_hif_poll_mboxmsg_rx(target->dev, &look_ahead, - HTC_TARGET_RESPONSE_TIMEOUT)) + HTC_TARGET_RESPONSE_TIMEOUT)) return NULL; ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx wait ctrl look_ahead 0x%X\n", look_ahead); + "htc rx wait ctrl look_ahead 0x%X\n", look_ahead); htc_hdr = (struct htc_frame_hdr *)&look_ahead; @@ -2244,7 +2307,7 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, depth = get_queue_depth(pkt_queue); ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx add multiple ep id %d cnt %d len %d\n", + "htc rx add multiple ep id %d cnt %d len %d\n", first_pkt->endpoint, depth, first_pkt->buf_len); endpoint = &target->endpoint[first_pkt->endpoint]; @@ -2270,8 +2333,8 @@ int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) { if (target->ep_waiting == first_pkt->endpoint) { ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx blocked on ep %d, unblocking\n", - target->ep_waiting); + "htc rx blocked on ep %d, unblocking\n", + target->ep_waiting); target->rx_st_flags &= ~HTC_RECV_WAIT_BUFFERS; target->ep_waiting = ENDPOINT_MAX; rx_unblock = true; @@ -2308,7 +2371,21 @@ void ath6kl_htc_flush_rx_buf(struct htc_target *target) "htc rx flush pkt 0x%p len %d ep %d\n", packet, packet->buf_len, packet->endpoint); - dev_kfree_skb(packet->pkt_cntxt); + /* + * packets in rx_bufq of endpoint 0 have originally + * been queued from target->free_ctrl_rxbuf where + * packet and packet->buf_start are allocated + * separately using kmalloc(). For other endpoint + * rx_bufq, it is allocated as skb where packet is + * skb->head. Take care of this difference while freeing + * the memory. + */ + if (packet->endpoint == ENDPOINT_0) { + kfree(packet->buf_start); + kfree(packet); + } else { + dev_kfree_skb(packet->pkt_cntxt); + } spin_lock_bh(&target->rx_lock); } spin_unlock_bh(&target->rx_lock); @@ -2327,6 +2404,7 @@ int ath6kl_htc_conn_service(struct htc_target *target, enum htc_endpoint_id assigned_ep = ENDPOINT_MAX; unsigned int max_msg_sz = 0; int status = 0; + u16 msg_id; ath6kl_dbg(ATH6KL_DBG_HTC, "htc connect service target 0x%p service id 0x%x\n", @@ -2370,9 +2448,10 @@ int ath6kl_htc_conn_service(struct htc_target *target, } resp_msg = (struct htc_conn_service_resp *)rx_pkt->buf; + msg_id = le16_to_cpu(resp_msg->msg_id); - if ((le16_to_cpu(resp_msg->msg_id) != HTC_MSG_CONN_SVC_RESP_ID) - || (rx_pkt->act_len < sizeof(*resp_msg))) { + if ((msg_id != HTC_MSG_CONN_SVC_RESP_ID) || + (rx_pkt->act_len < sizeof(*resp_msg))) { status = -ENOMEM; goto fail_tx; } @@ -2419,6 +2498,15 @@ int ath6kl_htc_conn_service(struct htc_target *target, endpoint->cred_dist.endpoint = assigned_ep; endpoint->cred_dist.cred_sz = target->tgt_cred_sz; + switch (endpoint->svc_id) { + case WMI_DATA_BK_SVC: + endpoint->tx_drop_packet_threshold = MAX_DEF_COOKIE_NUM / 3; + break; + default: + endpoint->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM; + break; + } + if (conn_req->max_rxmsg_sz) { /* * Override cred_per_msg calculation, this optimizes @@ -2516,7 +2604,8 @@ static void htc_setup_msg_bndl(struct htc_target *target) target->max_rx_bndl_sz, target->max_tx_bndl_sz); if (target->max_tx_bndl_sz) - target->tx_bndl_enable = true; + /* tx_bndl_mask is enabled per AC, each has 1 bit */ + target->tx_bndl_mask = (1 << WMM_NUM_AC) - 1; if (target->max_rx_bndl_sz) target->rx_bndl_enable = true; @@ -2531,7 +2620,7 @@ static void htc_setup_msg_bndl(struct htc_target *target) * padding will spill into the next credit buffer * which is fatal. */ - target->tx_bndl_enable = false; + target->tx_bndl_mask = 0; } } @@ -2543,6 +2632,12 @@ int ath6kl_htc_wait_target(struct htc_target *target) struct htc_service_connect_resp resp; int status; + /* FIXME: remove once USB support is implemented */ + if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) { + ath6kl_err("HTC doesn't support USB yet. Patience!\n"); + return -EOPNOTSUPP; + } + /* we should be getting 1 control message that the target is ready */ packet = htc_wait_for_ctrl_msg(target); @@ -2582,8 +2677,8 @@ int ath6kl_htc_wait_target(struct htc_target *target) } ath6kl_dbg(ATH6KL_DBG_BOOT, "htc using protocol %s (%d)\n", - (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1", - target->htc_tgt_ver); + (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1", + target->htc_tgt_ver); if (target->msg_per_bndl_max > 0) htc_setup_msg_bndl(target); @@ -2772,17 +2867,19 @@ void ath6kl_htc_cleanup(struct htc_target *target) { struct htc_packet *packet, *tmp_packet; - ath6kl_hif_cleanup_scatter(target->dev->ar); + /* FIXME: remove check once USB support is implemented */ + if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB) + ath6kl_hif_cleanup_scatter(target->dev->ar); list_for_each_entry_safe(packet, tmp_packet, - &target->free_ctrl_txbuf, list) { + &target->free_ctrl_txbuf, list) { list_del(&packet->list); kfree(packet->buf_start); kfree(packet); } list_for_each_entry_safe(packet, tmp_packet, - &target->free_ctrl_rxbuf, list) { + &target->free_ctrl_rxbuf, list) { list_del(&packet->list); kfree(packet->buf_start); kfree(packet); diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h index 57672e1ed1a6..5027ccc36b62 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.h +++ b/drivers/net/wireless/ath/ath6kl/htc.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011 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 @@ -87,6 +88,8 @@ #define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4) #define WMI_MAX_SERVICES 5 +#define WMM_NUM_AC 4 + /* reserved and used to flush ALL packets */ #define HTC_TX_PACKET_TAG_ALL 0 #define HTC_SERVICE_TX_PACKET_TAG 1 @@ -498,6 +501,7 @@ struct htc_endpoint { u8 seqno; u32 conn_flags; struct htc_endpoint_stats ep_st; + u16 tx_drop_packet_threshold; }; struct htc_control_buffer { @@ -519,9 +523,16 @@ struct htc_target { struct ath6kl_htc_credit_info *credit_info; int tgt_creds; unsigned int tgt_cred_sz; + + /* protects free_ctrl_txbuf and free_ctrl_rxbuf */ spinlock_t htc_lock; + + /* FIXME: does this protext rx_bufq and endpoint structures or what? */ spinlock_t rx_lock; + + /* protects endpoint->txq */ spinlock_t tx_lock; + struct ath6kl_device *dev; u32 htc_flags; u32 rx_st_flags; @@ -531,7 +542,7 @@ struct htc_target { /* max messages per bundle for HTC */ int msg_per_bndl_max; - bool tx_bndl_enable; + u32 tx_bndl_mask; int rx_bndl_enable; int max_rx_bndl_sz; int max_tx_bndl_sz; @@ -543,6 +554,9 @@ struct htc_target { int max_xfer_szper_scatreq; int chk_irq_status_cnt; + + /* counts the number of Tx without bundling continously per AC */ + u32 ac_tx_count[WMM_NUM_AC]; }; void *ath6kl_htc_create(struct ath6kl *ar); diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 7f55be3092d1..03cae142f178 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1,6 +1,7 @@ /* * Copyright (c) 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 @@ -17,22 +18,16 @@ #include <linux/moduleparam.h> #include <linux/errno.h> +#include <linux/export.h> #include <linux/of.h> #include <linux/mmc/sdio_func.h> + #include "core.h" #include "cfg80211.h" #include "target.h" #include "debug.h" #include "hif-ops.h" -unsigned int debug_mask; -static unsigned int testmode; -static bool suspend_cutpower; - -module_param(debug_mask, uint, 0644); -module_param(testmode, uint, 0644); -module_param(suspend_cutpower, bool, 0444); - static const struct ath6kl_hw hw_list[] = { { .id = AR6003_HW_2_0_VERSION, @@ -47,11 +42,14 @@ static const struct ath6kl_hw hw_list[] = { /* hw2.0 needs override address hardcoded */ .app_start_override_addr = 0x944C00, - .fw_otp = AR6003_HW_2_0_OTP_FILE, - .fw = AR6003_HW_2_0_FIRMWARE_FILE, - .fw_tcmd = AR6003_HW_2_0_TCMD_FIRMWARE_FILE, - .fw_patch = AR6003_HW_2_0_PATCH_FILE, - .fw_api2 = AR6003_HW_2_0_FIRMWARE_2_FILE, + .fw = { + .dir = AR6003_HW_2_0_FW_DIR, + .otp = AR6003_HW_2_0_OTP_FILE, + .fw = AR6003_HW_2_0_FIRMWARE_FILE, + .tcmd = AR6003_HW_2_0_TCMD_FIRMWARE_FILE, + .patch = AR6003_HW_2_0_PATCH_FILE, + }, + .fw_board = AR6003_HW_2_0_BOARD_DATA_FILE, .fw_default_board = AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE, }, @@ -64,14 +62,20 @@ static const struct ath6kl_hw hw_list[] = { .reserved_ram_size = 512, .refclk_hz = 26000000, .uarttx_pin = 8, + .testscript_addr = 0x57ef74, + + .fw = { + .dir = AR6003_HW_2_1_1_FW_DIR, + .otp = AR6003_HW_2_1_1_OTP_FILE, + .fw = AR6003_HW_2_1_1_FIRMWARE_FILE, + .tcmd = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE, + .patch = AR6003_HW_2_1_1_PATCH_FILE, + .utf = AR6003_HW_2_1_1_UTF_FIRMWARE_FILE, + .testscript = AR6003_HW_2_1_1_TESTSCRIPT_FILE, + }, - .fw_otp = AR6003_HW_2_1_1_OTP_FILE, - .fw = AR6003_HW_2_1_1_FIRMWARE_FILE, - .fw_tcmd = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE, - .fw_patch = AR6003_HW_2_1_1_PATCH_FILE, - .fw_api2 = AR6003_HW_2_1_1_FIRMWARE_2_FILE, .fw_board = AR6003_HW_2_1_1_BOARD_DATA_FILE, - .fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE, + .fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE, }, { .id = AR6004_HW_1_0_VERSION, @@ -84,8 +88,11 @@ static const struct ath6kl_hw hw_list[] = { .refclk_hz = 26000000, .uarttx_pin = 11, - .fw = AR6004_HW_1_0_FIRMWARE_FILE, - .fw_api2 = AR6004_HW_1_0_FIRMWARE_2_FILE, + .fw = { + .dir = AR6004_HW_1_0_FW_DIR, + .fw = AR6004_HW_1_0_FIRMWARE_FILE, + }, + .fw_board = AR6004_HW_1_0_BOARD_DATA_FILE, .fw_default_board = AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE, }, @@ -100,8 +107,11 @@ static const struct ath6kl_hw hw_list[] = { .refclk_hz = 40000000, .uarttx_pin = 11, - .fw = AR6004_HW_1_1_FIRMWARE_FILE, - .fw_api2 = AR6004_HW_1_1_FIRMWARE_2_FILE, + .fw = { + .dir = AR6004_HW_1_1_FW_DIR, + .fw = AR6004_HW_1_1_FIRMWARE_FILE, + }, + .fw_board = AR6004_HW_1_1_BOARD_DATA_FILE, .fw_default_board = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE, }, @@ -342,11 +352,7 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, blk_size |= ((u32)htc_ctrl_buf) << 16; /* set the host interest area for the block size */ - status = ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_mbox_io_block_sz)), - (u8 *)&blk_size, - 4); + status = ath6kl_bmi_write_hi32(ar, hi_mbox_io_block_sz, blk_size); if (status) { ath6kl_err("bmi_write_memory for IO block size failed\n"); goto out; @@ -358,11 +364,8 @@ static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, if (mbox_isr_yield_val) { /* set the host interest area for the mbox ISR yield limit */ - status = ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_mbox_isr_yield_limit)), - (u8 *)&mbox_isr_yield_val, - 4); + status = ath6kl_bmi_write_hi32(ar, hi_mbox_isr_yield_limit, + mbox_isr_yield_val); if (status) { ath6kl_err("bmi_write_memory for yield limit failed\n"); goto out; @@ -375,7 +378,6 @@ out: static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) { - int status = 0; int ret; /* @@ -383,43 +385,54 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) * default values. Required if checksum offload is needed. Set * RxMetaVersion to 2. */ - if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx, - ar->rx_meta_ver, 0, 0)) { - ath6kl_err("unable to set the rx frame format\n"); - status = -EIO; + ret = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, idx, + ar->rx_meta_ver, 0, 0); + if (ret) { + ath6kl_err("unable to set the rx frame format: %d\n", ret); + return ret; } - if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) - if ((ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1, - IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) { - ath6kl_err("unable to set power save fail event policy\n"); - status = -EIO; + if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) { + ret = ath6kl_wmi_pmparams_cmd(ar->wmi, idx, 0, 1, 0, 0, 1, + IGNORE_PS_FAIL_DURING_SCAN); + if (ret) { + ath6kl_err("unable to set power save fail event policy: %d\n", + ret); + return ret; } + } - if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) - if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0, - WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) { - ath6kl_err("unable to set barker preamble policy\n"); - status = -EIO; + if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) { + ret = ath6kl_wmi_set_lpreamble_cmd(ar->wmi, idx, 0, + WMI_FOLLOW_BARKER_IN_ERP); + if (ret) { + ath6kl_err("unable to set barker preamble policy: %d\n", + ret); + return ret; } + } - if (ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx, - WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) { - ath6kl_err("unable to set keep alive interval\n"); - status = -EIO; + ret = ath6kl_wmi_set_keepalive_cmd(ar->wmi, idx, + WLAN_CONFIG_KEEP_ALIVE_INTERVAL); + if (ret) { + ath6kl_err("unable to set keep alive interval: %d\n", ret); + return ret; } - if (ath6kl_wmi_disctimeout_cmd(ar->wmi, idx, - WLAN_CONFIG_DISCONNECT_TIMEOUT)) { - ath6kl_err("unable to set disconnect timeout\n"); - status = -EIO; + ret = ath6kl_wmi_disctimeout_cmd(ar->wmi, idx, + WLAN_CONFIG_DISCONNECT_TIMEOUT); + if (ret) { + ath6kl_err("unable to set disconnect timeout: %d\n", ret); + return ret; } - if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) - if (ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED)) { - ath6kl_err("unable to set txop bursting\n"); - status = -EIO; + if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) { + ret = ath6kl_wmi_set_wmm_txop(ar->wmi, idx, WMI_TXOP_DISABLED); + if (ret) { + ath6kl_err("unable to set txop bursting: %d\n", ret); + return ret; } + } if (ar->p2p && (ar->vif_max == 1 || idx)) { ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx, @@ -443,7 +456,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) } } - return status; + return ret; } int ath6kl_configure_target(struct ath6kl *ar) @@ -452,6 +465,12 @@ int ath6kl_configure_target(struct ath6kl *ar) u8 fw_iftype, fw_mode = 0, fw_submode = 0; int i, status; + param = !!(ar->conf_flags & ATH6KL_CONF_UART_DEBUG); + if (ath6kl_bmi_write_hi32(ar, hi_serial_enable, param)) { + ath6kl_err("bmi_write_memory for uart debug failed\n"); + return -EIO; + } + /* * Note: Even though the firmware interface type is * chosen as BSS_STA for all three interfaces, can @@ -483,11 +502,8 @@ int ath6kl_configure_target(struct ath6kl *ar) if (ar->p2p && ar->vif_max == 1) fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV; - param = HTC_PROTOCOL_VERSION; - if (ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_app_host_interest)), - (u8 *)¶m, 4) != 0) { + if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest, + HTC_PROTOCOL_VERSION) != 0) { ath6kl_err("bmi_write_memory for htc version failed\n"); return -EIO; } @@ -495,10 +511,7 @@ int ath6kl_configure_target(struct ath6kl *ar) /* set the firmware mode to STA/IBSS/AP */ param = 0; - if (ath6kl_bmi_read(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_option_flag)), - (u8 *)¶m, 4) != 0) { + if (ath6kl_bmi_read_hi32(ar, hi_option_flag, ¶m) != 0) { ath6kl_err("bmi_read_memory for setting fwmode failed\n"); return -EIO; } @@ -510,11 +523,7 @@ int ath6kl_configure_target(struct ath6kl *ar) param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); - if (ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_option_flag)), - (u8 *)¶m, - 4) != 0) { + if (ath6kl_bmi_write_hi32(ar, hi_option_flag, param) != 0) { ath6kl_err("bmi_write_memory for setting fwmode failed\n"); return -EIO; } @@ -533,16 +542,13 @@ int ath6kl_configure_target(struct ath6kl *ar) param = ar->hw.board_ext_data_addr; ram_reserved_size = ar->hw.reserved_ram_size; - if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_board_ext_data)), - (u8 *)¶m, 4) != 0) { + if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) { ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); return -EIO; } - if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_end_ram_reserve_sz)), - (u8 *)&ram_reserved_size, 4) != 0) { + if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, + ram_reserved_size) != 0) { ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); return -EIO; } @@ -553,56 +559,19 @@ int ath6kl_configure_target(struct ath6kl *ar) return -EIO; /* Configure GPIO AR600x UART */ - param = ar->hw.uarttx_pin; - status = ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_dbg_uart_txpin)), - (u8 *)¶m, 4); + status = ath6kl_bmi_write_hi32(ar, hi_dbg_uart_txpin, + ar->hw.uarttx_pin); if (status) return status; /* Configure target refclk_hz */ - param = ar->hw.refclk_hz; - status = ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_refclk_hz)), - (u8 *)¶m, 4); + status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz, ar->hw.refclk_hz); if (status) return status; return 0; } -void ath6kl_core_free(struct ath6kl *ar) -{ - wiphy_free(ar->wiphy); -} - -void ath6kl_core_cleanup(struct ath6kl *ar) -{ - ath6kl_hif_power_off(ar); - - destroy_workqueue(ar->ath6kl_wq); - - if (ar->htc_target) - ath6kl_htc_cleanup(ar->htc_target); - - ath6kl_cookie_cleanup(ar); - - ath6kl_cleanup_amsdu_rxbufs(ar); - - ath6kl_bmi_cleanup(ar); - - ath6kl_debug_cleanup(ar); - - kfree(ar->fw_board); - kfree(ar->fw_otp); - kfree(ar->fw); - kfree(ar->fw_patch); - - ath6kl_deinit_ieee80211_hw(ar); -} - /* firmware upload */ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, u8 **fw, size_t *fw_len) @@ -626,21 +595,6 @@ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, } #ifdef CONFIG_OF -static const char *get_target_ver_dir(const struct ath6kl *ar) -{ - switch (ar->version.target_ver) { - case AR6003_HW_1_0_VERSION: - return "ath6k/AR6003/hw1.0"; - case AR6003_HW_2_0_VERSION: - return "ath6k/AR6003/hw2.0"; - case AR6003_HW_2_1_1_VERSION: - return "ath6k/AR6003/hw2.1.1"; - } - ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__, - ar->version.target_ver); - return NULL; -} - /* * Check the device tree for a board-id and use it to construct * the pathname to the firmware file. Used (for now) to find a @@ -663,7 +617,7 @@ static bool check_device_tree(struct ath6kl *ar) continue; } snprintf(board_filename, sizeof(board_filename), - "%s/bdata.%s.bin", get_target_ver_dir(ar), board_id); + "%s/bdata.%s.bin", ar->hw.fw.dir, board_id); ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board, &ar->fw_board_len); @@ -730,19 +684,20 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar) static int ath6kl_fetch_otp_file(struct ath6kl *ar) { - const char *filename; + char filename[100]; int ret; if (ar->fw_otp != NULL) return 0; - if (ar->hw.fw_otp == NULL) { + if (ar->hw.fw.otp == NULL) { ath6kl_dbg(ATH6KL_DBG_BOOT, "no OTP file configured for this hw\n"); return 0; } - filename = ar->hw.fw_otp; + snprintf(filename, sizeof(filename), "%s/%s", + ar->hw.fw.dir, ar->hw.fw.otp); ret = ath6kl_get_fw(ar, filename, &ar->fw_otp, &ar->fw_otp_len); @@ -755,33 +710,61 @@ static int ath6kl_fetch_otp_file(struct ath6kl *ar) return 0; } -static int ath6kl_fetch_fw_file(struct ath6kl *ar) +static int ath6kl_fetch_testmode_file(struct ath6kl *ar) { - const char *filename; + char filename[100]; int ret; - if (ar->fw != NULL) + if (ar->testmode == 0) return 0; - if (testmode) { - if (ar->hw.fw_tcmd == NULL) { - ath6kl_warn("testmode not supported\n"); + ath6kl_dbg(ATH6KL_DBG_BOOT, "testmode %d\n", ar->testmode); + + if (ar->testmode == 2) { + if (ar->hw.fw.utf == NULL) { + ath6kl_warn("testmode 2 not supported\n"); return -EOPNOTSUPP; } - filename = ar->hw.fw_tcmd; + snprintf(filename, sizeof(filename), "%s/%s", + ar->hw.fw.dir, ar->hw.fw.utf); + } else { + if (ar->hw.fw.tcmd == NULL) { + ath6kl_warn("testmode 1 not supported\n"); + return -EOPNOTSUPP; + } - set_bit(TESTMODE, &ar->flag); + snprintf(filename, sizeof(filename), "%s/%s", + ar->hw.fw.dir, ar->hw.fw.tcmd); + } + + set_bit(TESTMODE, &ar->flag); - goto get_fw; + ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); + if (ret) { + ath6kl_err("Failed to get testmode %d firmware file %s: %d\n", + ar->testmode, filename, ret); + return ret; } - if (WARN_ON(ar->hw.fw == NULL)) + return 0; +} + +static int ath6kl_fetch_fw_file(struct ath6kl *ar) +{ + char filename[100]; + int ret; + + if (ar->fw != NULL) + return 0; + + /* FIXME: remove WARN_ON() as we won't support FW API 1 for long */ + if (WARN_ON(ar->hw.fw.fw == NULL)) return -EINVAL; - filename = ar->hw.fw; + snprintf(filename, sizeof(filename), "%s/%s", + ar->hw.fw.dir, ar->hw.fw.fw); -get_fw: ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); if (ret) { ath6kl_err("Failed to get firmware file %s: %d\n", @@ -794,16 +777,17 @@ get_fw: static int ath6kl_fetch_patch_file(struct ath6kl *ar) { - const char *filename; + char filename[100]; int ret; if (ar->fw_patch != NULL) return 0; - if (ar->hw.fw_patch == NULL) + if (ar->hw.fw.patch == NULL) return 0; - filename = ar->hw.fw_patch; + snprintf(filename, sizeof(filename), "%s/%s", + ar->hw.fw.dir, ar->hw.fw.patch); ret = ath6kl_get_fw(ar, filename, &ar->fw_patch, &ar->fw_patch_len); @@ -816,6 +800,34 @@ static int ath6kl_fetch_patch_file(struct ath6kl *ar) return 0; } +static int ath6kl_fetch_testscript_file(struct ath6kl *ar) +{ + char filename[100]; + int ret; + + if (ar->testmode != 2) + return 0; + + if (ar->fw_testscript != NULL) + return 0; + + if (ar->hw.fw.testscript == NULL) + return 0; + + snprintf(filename, sizeof(filename), "%s/%s", + ar->hw.fw.dir, ar->hw.fw.testscript); + + ret = ath6kl_get_fw(ar, filename, &ar->fw_testscript, + &ar->fw_testscript_len); + if (ret) { + ath6kl_err("Failed to get testscript file %s: %d\n", + filename, ret); + return ret; + } + + return 0; +} + static int ath6kl_fetch_fw_api1(struct ath6kl *ar) { int ret; @@ -832,23 +844,24 @@ static int ath6kl_fetch_fw_api1(struct ath6kl *ar) if (ret) return ret; + ret = ath6kl_fetch_testscript_file(ar); + if (ret) + return ret; + return 0; } -static int ath6kl_fetch_fw_api2(struct ath6kl *ar) +static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) { size_t magic_len, len, ie_len; const struct firmware *fw; struct ath6kl_fw_ie *hdr; - const char *filename; + char filename[100]; const u8 *data; int ret, ie_id, i, index, bit; __le32 *val; - if (ar->hw.fw_api2 == NULL) - return -EOPNOTSUPP; - - filename = ar->hw.fw_api2; + snprintf(filename, sizeof(filename), "%s/%s", ar->hw.fw.dir, name); ret = request_firmware(&fw, filename, ar->dev); if (ret) @@ -892,7 +905,7 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar) switch (ie_id) { case ATH6KL_FW_IE_OTP_IMAGE: ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n", - ie_len); + ie_len); ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL); @@ -905,7 +918,11 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar) break; case ATH6KL_FW_IE_FW_IMAGE: ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n", - ie_len); + ie_len); + + /* in testmode we already might have a fw file */ + if (ar->fw != NULL) + break; ar->fw = kmemdup(data, ie_len, GFP_KERNEL); @@ -918,7 +935,7 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar) break; case ATH6KL_FW_IE_PATCH_IMAGE: ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n", - ie_len); + ie_len); ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL); @@ -1010,7 +1027,7 @@ out: return ret; } -static int ath6kl_fetch_firmwares(struct ath6kl *ar) +int ath6kl_init_fetch_firmwares(struct ath6kl *ar) { int ret; @@ -1018,17 +1035,30 @@ static int ath6kl_fetch_firmwares(struct ath6kl *ar) if (ret) return ret; - ret = ath6kl_fetch_fw_api2(ar); + ret = ath6kl_fetch_testmode_file(ar); + if (ret) + return ret; + + ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE); if (ret == 0) { - ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 2\n"); - return 0; + ar->fw_api = 3; + goto out; + } + + ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API2_FILE); + if (ret == 0) { + ar->fw_api = 2; + goto out; } ret = ath6kl_fetch_fw_api1(ar); if (ret) return ret; - ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 1\n"); + ar->fw_api = 1; + +out: + ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api %d\n", ar->fw_api); return 0; } @@ -1049,22 +1079,14 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) */ if (ar->hw.board_addr != 0) { board_address = ar->hw.board_addr; - ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_board_data)), - (u8 *) &board_address, 4); + ath6kl_bmi_write_hi32(ar, hi_board_data, + board_address); } else { - ath6kl_bmi_read(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_board_data)), - (u8 *) &board_address, 4); + ath6kl_bmi_read_hi32(ar, hi_board_data, &board_address); } /* determine where in target ram to write extended board data */ - ath6kl_bmi_read(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_board_ext_data)), - (u8 *) &board_ext_address, 4); + ath6kl_bmi_read_hi32(ar, hi_board_ext_data, &board_ext_address); if (ar->target_type == TARGET_TYPE_AR6003 && board_ext_address == 0) { @@ -1076,6 +1098,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) case TARGET_TYPE_AR6003: board_data_size = AR6003_BOARD_DATA_SZ; board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ; + if (ar->fw_board_len > (board_data_size + board_ext_data_size)) + board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ_V2; break; case TARGET_TYPE_AR6004: board_data_size = AR6004_BOARD_DATA_SZ; @@ -1107,10 +1131,7 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) /* record that extended board data is initialized */ param = (board_ext_data_size << 16) | 1; - ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_board_ext_data_config)), - (unsigned char *) ¶m, 4); + ath6kl_bmi_write_hi32(ar, hi_board_ext_data_config, param); } if (ar->fw_board_len < board_data_size) { @@ -1131,11 +1152,7 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) } /* record the fact that Board Data IS initialized */ - param = 1; - ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_board_data_initialized)), - (u8 *)¶m, 4); + ath6kl_bmi_write_hi32(ar, hi_board_data_initialized, 1); return ret; } @@ -1162,10 +1179,7 @@ static int ath6kl_upload_otp(struct ath6kl *ar) } /* read firmware start address */ - ret = ath6kl_bmi_read(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_app_start)), - (u8 *) &address, sizeof(address)); + ret = ath6kl_bmi_read_hi32(ar, hi_app_start, &address); if (ret) { ath6kl_err("Failed to read hi_app_start: %d\n", ret); @@ -1223,7 +1237,7 @@ static int ath6kl_upload_firmware(struct ath6kl *ar) static int ath6kl_upload_patch(struct ath6kl *ar) { - u32 address, param; + u32 address; int ret; if (ar->fw_patch == NULL) @@ -1240,11 +1254,37 @@ static int ath6kl_upload_patch(struct ath6kl *ar) return ret; } - param = address; - ath6kl_bmi_write(ar, - ath6kl_get_hi_item_addr(ar, - HI_ITEM(hi_dset_list_head)), - (unsigned char *) ¶m, 4); + ath6kl_bmi_write_hi32(ar, hi_dset_list_head, address); + + return 0; +} + +static int ath6kl_upload_testscript(struct ath6kl *ar) +{ + u32 address; + int ret; + + if (ar->testmode != 2) + return 0; + + if (ar->fw_testscript == NULL) + return 0; + + address = ar->hw.testscript_addr; + + ath6kl_dbg(ATH6KL_DBG_BOOT, "writing testscript to 0x%x (%zd B)\n", + address, ar->fw_testscript_len); + + ret = ath6kl_bmi_write(ar, address, ar->fw_testscript, + ar->fw_testscript_len); + if (ret) { + ath6kl_err("Failed to write testscript file: %d\n", ret); + return ret; + } + + ath6kl_bmi_write_hi32(ar, hi_ota_testscript, address); + ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 4096); + ath6kl_bmi_write_hi32(ar, hi_test_apps_related, 1); return 0; } @@ -1255,7 +1295,7 @@ static int ath6kl_init_upload(struct ath6kl *ar) int status = 0; if (ar->target_type != TARGET_TYPE_AR6003 && - ar->target_type != TARGET_TYPE_AR6004) + ar->target_type != TARGET_TYPE_AR6004) return -EINVAL; /* temporarily disable system sleep */ @@ -1312,7 +1352,8 @@ static int ath6kl_init_upload(struct ath6kl *ar) return status; /* WAR to avoid SDIO CRC err */ - if (ar->version.target_ver == AR6003_HW_2_0_VERSION) { + if (ar->version.target_ver == AR6003_HW_2_0_VERSION || + ar->version.target_ver == AR6003_HW_2_1_1_VERSION) { ath6kl_err("temporary war to avoid sdio crc error\n"); param = 0x20; @@ -1357,6 +1398,11 @@ static int ath6kl_init_upload(struct ath6kl *ar) if (status) return status; + /* Download the test script */ + status = ath6kl_upload_testscript(ar); + if (status) + return status; + /* Restore system sleep */ address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS; status = ath6kl_bmi_reg_write(ar, address, sleep); @@ -1372,9 +1418,9 @@ static int ath6kl_init_upload(struct ath6kl *ar) return status; } -static int ath6kl_init_hw_params(struct ath6kl *ar) +int ath6kl_init_hw_params(struct ath6kl *ar) { - const struct ath6kl_hw *hw; + const struct ath6kl_hw *uninitialized_var(hw); int i; for (i = 0; i < ARRAY_SIZE(hw_list); i++) { @@ -1481,10 +1527,11 @@ int ath6kl_init_hw_start(struct ath6kl *ar) if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) { - ath6kl_info("%s %s fw %s%s\n", + ath6kl_info("%s %s fw %s api %d%s\n", ar->hw.name, ath6kl_init_get_hif_name(ar->hif_type), ar->wiphy->fw_version, + ar->fw_api, test_bit(TESTMODE, &ar->flag) ? " testmode" : ""); } @@ -1549,173 +1596,7 @@ int ath6kl_init_hw_stop(struct ath6kl *ar) return 0; } -int ath6kl_core_init(struct ath6kl *ar) -{ - struct ath6kl_bmi_target_info targ_info; - struct net_device *ndev; - int ret = 0, i; - - ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); - if (!ar->ath6kl_wq) - return -ENOMEM; - - ret = ath6kl_bmi_init(ar); - if (ret) - goto err_wq; - - /* - * Turn on power to get hardware (target) version and leave power - * on delibrately as we will boot the hardware anyway within few - * seconds. - */ - ret = ath6kl_hif_power_on(ar); - if (ret) - goto err_bmi_cleanup; - - ret = ath6kl_bmi_get_target_info(ar, &targ_info); - if (ret) - goto err_power_off; - - ar->version.target_ver = le32_to_cpu(targ_info.version); - ar->target_type = le32_to_cpu(targ_info.type); - ar->wiphy->hw_version = le32_to_cpu(targ_info.version); - - ret = ath6kl_init_hw_params(ar); - if (ret) - goto err_power_off; - - ar->htc_target = ath6kl_htc_create(ar); - - if (!ar->htc_target) { - ret = -ENOMEM; - goto err_power_off; - } - - ret = ath6kl_fetch_firmwares(ar); - if (ret) - goto err_htc_cleanup; - - /* FIXME: we should free all firmwares in the error cases below */ - - /* Indicate that WMI is enabled (although not ready yet) */ - set_bit(WMI_ENABLED, &ar->flag); - ar->wmi = ath6kl_wmi_init(ar); - if (!ar->wmi) { - ath6kl_err("failed to initialize wmi\n"); - ret = -EIO; - goto err_htc_cleanup; - } - - ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); - - ret = ath6kl_register_ieee80211_hw(ar); - if (ret) - goto err_node_cleanup; - - ret = ath6kl_debug_init(ar); - if (ret) { - wiphy_unregister(ar->wiphy); - goto err_node_cleanup; - } - - for (i = 0; i < ar->vif_max; i++) - ar->avail_idx_map |= BIT(i); - - rtnl_lock(); - - /* Add an initial station interface */ - ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, - INFRA_NETWORK); - - rtnl_unlock(); - - if (!ndev) { - ath6kl_err("Failed to instantiate a network device\n"); - ret = -ENOMEM; - wiphy_unregister(ar->wiphy); - goto err_debug_init; - } - - - ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", - __func__, ndev->name, ndev, ar); - - /* setup access class priority mappings */ - ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */ - ar->ac_stream_pri_map[WMM_AC_BE] = 1; - ar->ac_stream_pri_map[WMM_AC_VI] = 2; - ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ - - /* give our connected endpoints some buffers */ - ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); - ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); - - /* allocate some buffers that handle larger AMSDU frames */ - ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); - - ath6kl_cookie_init(ar); - - ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | - ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; - - if (suspend_cutpower) - ar->conf_flags |= ATH6KL_CONF_SUSPEND_CUTPOWER; - - ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | - WIPHY_FLAG_HAVE_AP_SME | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | - WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - - if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) - ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; - - ar->wiphy->probe_resp_offload = - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; - - set_bit(FIRST_BOOT, &ar->flag); - - ret = ath6kl_init_hw_start(ar); - if (ret) { - ath6kl_err("Failed to start hardware: %d\n", ret); - goto err_rxbuf_cleanup; - } - - /* - * Set mac address which is received in ready event - * FIXME: Move to ath6kl_interface_add() - */ - memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); - - return ret; - -err_rxbuf_cleanup: - ath6kl_htc_flush_rx_buf(ar->htc_target); - ath6kl_cleanup_amsdu_rxbufs(ar); - rtnl_lock(); - ath6kl_deinit_if_data(netdev_priv(ndev)); - rtnl_unlock(); - wiphy_unregister(ar->wiphy); -err_debug_init: - ath6kl_debug_cleanup(ar); -err_node_cleanup: - ath6kl_wmi_shutdown(ar->wmi); - clear_bit(WMI_ENABLED, &ar->flag); - ar->wmi = NULL; -err_htc_cleanup: - ath6kl_htc_cleanup(ar->htc_target); -err_power_off: - ath6kl_hif_power_off(ar); -err_bmi_cleanup: - ath6kl_bmi_cleanup(ar); -err_wq: - destroy_workqueue(ar->ath6kl_wq); - - return ret; -} - +/* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) { static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; @@ -1747,6 +1628,7 @@ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) void ath6kl_stop_txrx(struct ath6kl *ar) { struct ath6kl_vif *vif, *tmp_vif; + int i; set_bit(DESTROY_IN_PROGRESS, &ar->flag); @@ -1755,13 +1637,16 @@ void ath6kl_stop_txrx(struct ath6kl *ar) return; } + for (i = 0; i < AP_MAX_NUM_STA; i++) + aggr_reset_state(ar->sta_list[i].aggr_conn); + spin_lock_bh(&ar->list_lock); list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) { list_del(&vif->list); spin_unlock_bh(&ar->list_lock); ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); rtnl_lock(); - ath6kl_deinit_if_data(vif); + ath6kl_cfg80211_vif_cleanup(vif); rtnl_unlock(); spin_lock_bh(&ar->list_lock); } @@ -1791,8 +1676,11 @@ void ath6kl_stop_txrx(struct ath6kl *ar) * configure NOT to reset the target during a debug session. */ ath6kl_dbg(ATH6KL_DBG_TRC, - "attempting to reset target on instance destroy\n"); + "attempting to reset target on instance destroy\n"); ath6kl_reset_device(ar, ar->target_type, true, true); clear_bit(WLAN_ENABLED, &ar->flag); + + up(&ar->sem); } +EXPORT_SYMBOL(ath6kl_stop_txrx); diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index eea3c747653e..229e1922ebe4 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-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 @@ -52,9 +53,11 @@ struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid) return conn; } -static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie, - u8 ielen, u8 keymgmt, u8 ucipher, u8 auth) +static void ath6kl_add_new_sta(struct ath6kl_vif *vif, u8 *mac, u16 aid, + u8 *wpaie, size_t ielen, u8 keymgmt, + u8 ucipher, u8 auth, u8 apsd_info) { + struct ath6kl *ar = vif->ar; struct ath6kl_sta *sta; u8 free_slot; @@ -68,18 +71,31 @@ static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie, sta->keymgmt = keymgmt; sta->ucipher = ucipher; sta->auth = auth; + sta->apsd_info = apsd_info; ar->sta_list_index = ar->sta_list_index | (1 << free_slot); ar->ap_stats.sta[free_slot].aid = cpu_to_le32(aid); + aggr_conn_init(vif, vif->aggr_cntxt, sta->aggr_conn); } static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i) { struct ath6kl_sta *sta = &ar->sta_list[i]; + struct ath6kl_mgmt_buff *entry, *tmp; /* empty the queued pkts in the PS queue if any */ spin_lock_bh(&sta->psq_lock); skb_queue_purge(&sta->psq); + skb_queue_purge(&sta->apsdq); + + if (sta->mgmt_psq_len != 0) { + list_for_each_entry_safe(entry, tmp, &sta->mgmt_psq, list) { + kfree(entry); + } + INIT_LIST_HEAD(&sta->mgmt_psq); + sta->mgmt_psq_len = 0; + } + spin_unlock_bh(&sta->psq_lock); memset(&ar->ap_stats.sta[sta->aid - 1], 0, @@ -90,7 +106,7 @@ static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i) sta->sta_flags = 0; ar->sta_list_index = ar->sta_list_index & ~(1 << i); - + aggr_reset_state(sta->aggr_conn); } static u8 ath6kl_remove_sta(struct ath6kl *ar, u8 *mac, u16 reason) @@ -252,7 +268,7 @@ int ath6kl_read_fwlogs(struct ath6kl *ar) struct ath6kl_dbglog_hdr debug_hdr; struct ath6kl_dbglog_buf debug_buf; u32 address, length, dropped, firstbuf, debug_hdr_addr; - int ret = 0, loop; + int ret, loop; u8 *buf; buf = kmalloc(ATH6KL_FWLOG_PAYLOAD_SIZE, GFP_KERNEL); @@ -334,7 +350,7 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, __le32 data; if (target_type != TARGET_TYPE_AR6003 && - target_type != TARGET_TYPE_AR6004) + target_type != TARGET_TYPE_AR6004) return; data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) : @@ -347,9 +363,6 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, case TARGET_TYPE_AR6004: address = AR6004_RESET_CONTROL_ADDRESS; break; - default: - address = AR6003_RESET_CONTROL_ADDRESS; - break; } status = ath6kl_diag_write32(ar, address, data); @@ -363,7 +376,7 @@ static void ath6kl_install_static_wep_keys(struct ath6kl_vif *vif) u8 index; u8 keyusage; - for (index = WMI_MIN_KEY_INDEX; index <= WMI_MAX_KEY_INDEX; index++) { + for (index = 0; index <= WMI_MAX_KEY_INDEX; index++) { if (vif->wep_key_list[index].key_len) { keyusage = GROUP_USAGE; if (index == vif->def_txkey_index) @@ -428,9 +441,8 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, u8 keymgmt, u8 ucipher, u8 auth, - u8 assoc_req_len, u8 *assoc_info) + u8 assoc_req_len, u8 *assoc_info, u8 apsd_info) { - struct ath6kl *ar = vif->ar; u8 *ies = NULL, *wpa_ie = NULL, *pos; size_t ies_len = 0; struct station_info sinfo; @@ -484,9 +496,9 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, pos += 2 + pos[1]; } - ath6kl_add_new_sta(ar, mac_addr, aid, wpa_ie, + ath6kl_add_new_sta(vif, mac_addr, aid, wpa_ie, wpa_ie ? 2 + wpa_ie[1] : 0, - keymgmt, ucipher, auth); + keymgmt, ucipher, auth, apsd_info); /* send event to application */ memset(&sinfo, 0, sizeof(sinfo)); @@ -589,8 +601,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, if ((vif->nw_type == INFRA_NETWORK)) ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, - ar->listen_intvl_t, - ar->listen_intvl_b); + vif->listen_intvl_t, 0); netif_wake_queue(vif->ndev); @@ -601,7 +612,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, netif_carrier_on(vif->ndev); spin_unlock_bh(&vif->if_lock); - aggr_reset_state(vif->aggr_cntxt); + aggr_reset_state(vif->aggr_cntxt->aggr_conn); vif->reconnect_flag = 0; if ((vif->nw_type == ADHOC_NETWORK) && ar->ibss_ps_enable) { @@ -808,6 +819,7 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid) struct sk_buff *skb; bool psq_empty = false; struct ath6kl *ar = vif->ar; + struct ath6kl_mgmt_buff *mgmt_buf; conn = ath6kl_find_sta_by_aid(ar, aid); @@ -818,7 +830,7 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid) * becomes empty update the PVB for this station. */ spin_lock_bh(&conn->psq_lock); - psq_empty = skb_queue_empty(&conn->psq); + psq_empty = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0); spin_unlock_bh(&conn->psq_lock); if (psq_empty) @@ -826,15 +838,31 @@ void ath6kl_pspoll_event(struct ath6kl_vif *vif, u8 aid) return; spin_lock_bh(&conn->psq_lock); - skb = skb_dequeue(&conn->psq); - spin_unlock_bh(&conn->psq_lock); + if (conn->mgmt_psq_len > 0) { + mgmt_buf = list_first_entry(&conn->mgmt_psq, + struct ath6kl_mgmt_buff, list); + list_del(&mgmt_buf->list); + conn->mgmt_psq_len--; + spin_unlock_bh(&conn->psq_lock); + + conn->sta_flags |= STA_PS_POLLED; + ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, + mgmt_buf->id, mgmt_buf->freq, + mgmt_buf->wait, mgmt_buf->buf, + mgmt_buf->len, mgmt_buf->no_cck); + conn->sta_flags &= ~STA_PS_POLLED; + kfree(mgmt_buf); + } else { + skb = skb_dequeue(&conn->psq); + spin_unlock_bh(&conn->psq_lock); - conn->sta_flags |= STA_PS_POLLED; - ath6kl_data_tx(skb, vif->ndev); - conn->sta_flags &= ~STA_PS_POLLED; + conn->sta_flags |= STA_PS_POLLED; + ath6kl_data_tx(skb, vif->ndev); + conn->sta_flags &= ~STA_PS_POLLED; + } spin_lock_bh(&conn->psq_lock); - psq_empty = skb_queue_empty(&conn->psq); + psq_empty = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0); spin_unlock_bh(&conn->psq_lock); if (psq_empty) @@ -920,10 +948,10 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, } ath6kl_cfg80211_disconnect_event(vif, reason, bssid, - assoc_resp_len, assoc_info, - prot_reason_status); + assoc_resp_len, assoc_info, + prot_reason_status); - aggr_reset_state(vif->aggr_cntxt); + aggr_reset_state(vif->aggr_cntxt->aggr_conn); del_timer(&vif->disconnect_timer); @@ -941,9 +969,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, } else { set_bit(CONNECT_PEND, &vif->flags); if (((reason == ASSOC_FAILED) && - (prot_reason_status == 0x11)) || - ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0) - && (vif->reconnect_flag == 1))) { + (prot_reason_status == 0x11)) || + ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0) && + (vif->reconnect_flag == 1))) { set_bit(CONNECTED, &vif->flags); return; } @@ -1020,11 +1048,155 @@ static struct net_device_stats *ath6kl_get_stats(struct net_device *dev) return &vif->net_stats; } -static struct net_device_ops ath6kl_netdev_ops = { +static int ath6kl_set_features(struct net_device *dev, + netdev_features_t features) +{ + struct ath6kl_vif *vif = netdev_priv(dev); + struct ath6kl *ar = vif->ar; + int err = 0; + + if ((features & NETIF_F_RXCSUM) && + (ar->rx_meta_ver != WMI_META_VERSION_2)) { + ar->rx_meta_ver = WMI_META_VERSION_2; + err = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, + vif->fw_vif_idx, + ar->rx_meta_ver, 0, 0); + if (err) { + dev->features = features & ~NETIF_F_RXCSUM; + return err; + } + } else if (!(features & NETIF_F_RXCSUM) && + (ar->rx_meta_ver == WMI_META_VERSION_2)) { + ar->rx_meta_ver = 0; + err = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, + vif->fw_vif_idx, + ar->rx_meta_ver, 0, 0); + if (err) { + dev->features = features | NETIF_F_RXCSUM; + return err; + } + + } + + return err; +} + +static void ath6kl_set_multicast_list(struct net_device *ndev) +{ + struct ath6kl_vif *vif = netdev_priv(ndev); + bool mc_all_on = false, mc_all_off = false; + int mc_count = netdev_mc_count(ndev); + struct netdev_hw_addr *ha; + bool found; + struct ath6kl_mc_filter *mc_filter, *tmp; + struct list_head mc_filter_new; + int ret; + + if (!test_bit(WMI_READY, &vif->ar->flag) || + !test_bit(WLAN_ENABLED, &vif->flags)) + return; + + mc_all_on = !!(ndev->flags & IFF_PROMISC) || + !!(ndev->flags & IFF_ALLMULTI) || + !!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST); + + mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0; + + if (mc_all_on || mc_all_off) { + /* Enable/disable all multicast */ + ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n", + mc_all_on ? "enabling" : "disabling"); + ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, + mc_all_on); + if (ret) + ath6kl_warn("Failed to %s multicast receive\n", + mc_all_on ? "enable" : "disable"); + return; + } + + list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) { + found = false; + netdev_for_each_mc_addr(ha, ndev) { + if (memcmp(ha->addr, mc_filter->hw_addr, + ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { + found = true; + break; + } + } + + if (!found) { + /* + * Delete the filter which was previously set + * but not in the new request. + */ + ath6kl_dbg(ATH6KL_DBG_TRC, + "Removing %pM from multicast filter\n", + mc_filter->hw_addr); + ret = ath6kl_wmi_add_del_mcast_filter_cmd(vif->ar->wmi, + vif->fw_vif_idx, mc_filter->hw_addr, + false); + if (ret) { + ath6kl_warn("Failed to remove multicast filter:%pM\n", + mc_filter->hw_addr); + return; + } + + list_del(&mc_filter->list); + kfree(mc_filter); + } + } + + INIT_LIST_HEAD(&mc_filter_new); + + netdev_for_each_mc_addr(ha, ndev) { + found = false; + list_for_each_entry(mc_filter, &vif->mc_filter, list) { + if (memcmp(ha->addr, mc_filter->hw_addr, + ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) { + found = true; + break; + } + } + + if (!found) { + mc_filter = kzalloc(sizeof(struct ath6kl_mc_filter), + GFP_ATOMIC); + if (!mc_filter) { + WARN_ON(1); + goto out; + } + + memcpy(mc_filter->hw_addr, ha->addr, + ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE); + /* Set the multicast filter */ + ath6kl_dbg(ATH6KL_DBG_TRC, + "Adding %pM to multicast filter list\n", + mc_filter->hw_addr); + ret = ath6kl_wmi_add_del_mcast_filter_cmd(vif->ar->wmi, + vif->fw_vif_idx, mc_filter->hw_addr, + true); + if (ret) { + ath6kl_warn("Failed to add multicast filter :%pM\n", + mc_filter->hw_addr); + kfree(mc_filter); + goto out; + } + + list_add_tail(&mc_filter->list, &mc_filter_new); + } + } + +out: + list_splice_tail(&mc_filter_new, &vif->mc_filter); +} + +static const struct net_device_ops ath6kl_netdev_ops = { .ndo_open = ath6kl_open, .ndo_stop = ath6kl_close, .ndo_start_xmit = ath6kl_data_tx, .ndo_get_stats = ath6kl_get_stats, + .ndo_set_features = ath6kl_set_features, + .ndo_set_rx_mode = ath6kl_set_multicast_list, }; void init_netdev(struct net_device *dev) @@ -1038,5 +1210,7 @@ void init_netdev(struct net_device *dev) sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH + WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES; + dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; + return; } diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 9475e2d0d0b7..53528648b425 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-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 @@ -31,6 +32,7 @@ struct ath6kl_sdio { struct sdio_func *func; + /* protects access to bus_req_freeq */ spinlock_t lock; /* free list */ @@ -49,14 +51,20 @@ struct ath6kl_sdio { /* scatter request list head */ struct list_head scat_req; + atomic_t irq_handling; + wait_queue_head_t irq_wq; + + /* protects access to scat_req */ spinlock_t scat_lock; + bool scatter_enabled; bool is_disabled; - atomic_t irq_handling; const struct sdio_device_id *id; struct work_struct wr_async_work; struct list_head wr_asyncq; + + /* protects access to wr_asyncq */ spinlock_t wr_async_lock; }; @@ -402,7 +410,10 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, return -ENOMEM; mutex_lock(&ar_sdio->dma_buffer_mutex); tbuf = ar_sdio->dma_buffer; - memcpy(tbuf, buf, len); + + if (request & HIF_WRITE) + memcpy(tbuf, buf, len); + bounced = true; } else tbuf = buf; @@ -461,7 +472,6 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func) ar_sdio = sdio_get_drvdata(func); atomic_set(&ar_sdio->irq_handling, 1); - /* * Release the host during interrups so we can pick it back up when * we process commands. @@ -470,7 +480,10 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func) status = ath6kl_hif_intr_bh_handler(ar_sdio->ar); sdio_claim_host(ar_sdio->func); + atomic_set(&ar_sdio->irq_handling, 0); + wake_up(&ar_sdio->irq_wq); + WARN_ON(status && status != -ECANCELED); } @@ -571,6 +584,13 @@ static void ath6kl_sdio_irq_enable(struct ath6kl *ar) sdio_release_host(ar_sdio->func); } +static bool ath6kl_sdio_is_on_irq(struct ath6kl *ar) +{ + struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); + + return !atomic_read(&ar_sdio->irq_handling); +} + static void ath6kl_sdio_irq_disable(struct ath6kl *ar) { struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); @@ -578,10 +598,14 @@ static void ath6kl_sdio_irq_disable(struct ath6kl *ar) sdio_claim_host(ar_sdio->func); - /* Mask our function IRQ */ - while (atomic_read(&ar_sdio->irq_handling)) { + if (atomic_read(&ar_sdio->irq_handling)) { sdio_release_host(ar_sdio->func); - schedule_timeout(HZ / 10); + + ret = wait_event_interruptible(ar_sdio->irq_wq, + ath6kl_sdio_is_on_irq(ar)); + if (ret) + return; + sdio_claim_host(ar_sdio->func); } @@ -603,6 +627,8 @@ static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar) node = list_first_entry(&ar_sdio->scat_req, struct hif_scatter_req, list); list_del(&node->list); + + node->scat_q_depth = get_queue_depth(&ar_sdio->scat_req); } spin_unlock_bh(&ar_sdio->scat_lock); @@ -635,8 +661,8 @@ static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar, return -EINVAL; ath6kl_dbg(ATH6KL_DBG_SCATTER, - "hif-scatter: total len: %d scatter entries: %d\n", - scat_req->len, scat_req->scat_entries); + "hif-scatter: total len: %d scatter entries: %d\n", + scat_req->len, scat_req->scat_entries); if (request & HIF_SYNCHRONOUS) status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest); @@ -772,7 +798,6 @@ static int ath6kl_sdio_config(struct ath6kl *ar) if (ret) { ath6kl_err("Set sdio block size %d failed: %d)\n", HIF_MBOX_BLOCK_SIZE, ret); - sdio_release_host(func); goto out; } @@ -782,7 +807,7 @@ out: return ret; } -static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) +static int ath6kl_set_sdio_pm_caps(struct ath6kl *ar) { struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); struct sdio_func *func = ar_sdio->func; @@ -793,60 +818,104 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags); - if (!(flags & MMC_PM_KEEP_POWER) || - (ar->conf_flags & ATH6KL_CONF_SUSPEND_CUTPOWER)) { - /* as host doesn't support keep power we need to cut power */ - return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, - NULL); - } + if (!(flags & MMC_PM_WAKE_SDIO_IRQ) || + !(flags & MMC_PM_KEEP_POWER)) + return -EINVAL; ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); if (ret) { - printk(KERN_ERR "ath6kl: set sdio pm flags failed: %d\n", - ret); + ath6kl_err("set sdio keep pwr flag failed: %d\n", ret); return ret; } - if (!(flags & MMC_PM_WAKE_SDIO_IRQ)) - goto deepsleep; - /* sdio irq wakes up host */ + ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ); + if (ret) + ath6kl_err("set sdio wake irq flag failed: %d\n", ret); + + return ret; +} + +static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) +{ + struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + mmc_pm_flag_t flags; + bool try_deepsleep = false; + int ret; if (ar->state == ATH6KL_STATE_SCHED_SCAN) { + ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n"); + + ret = ath6kl_set_sdio_pm_caps(ar); + if (ret) + goto cut_pwr; + ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_SCHED_SCAN, NULL); - if (ret) { - ath6kl_warn("Schedule scan suspend failed: %d", ret); - return ret; - } + if (ret) + goto cut_pwr; + + return 0; + } + + if (ar->suspend_mode == WLAN_POWER_STATE_WOW || + (!ar->suspend_mode && wow)) { - ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ); + ret = ath6kl_set_sdio_pm_caps(ar); if (ret) - ath6kl_warn("set sdio wake irq flag failed: %d\n", ret); + goto cut_pwr; - return ret; + ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow); + if (ret && ret != -ENOTCONN) + ath6kl_err("wow suspend failed: %d\n", ret); + + if (ret && + (!ar->wow_suspend_mode || + ar->wow_suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP)) + try_deepsleep = true; + else if (ret && + ar->wow_suspend_mode == WLAN_POWER_STATE_CUT_PWR) + goto cut_pwr; + if (!ret) + return 0; } - if (wow) { + if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP || + !ar->suspend_mode || try_deepsleep) { + + flags = sdio_get_host_pm_caps(func); + if (!(flags & MMC_PM_KEEP_POWER)) + goto cut_pwr; + + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (ret) + goto cut_pwr; + /* - * The host sdio controller is capable of keep power and - * sdio irq wake up at this point. It's fine to continue - * wow suspend operation. + * Workaround to support Deep Sleep with MSM, set the host pm + * flag as MMC_PM_WAKE_SDIO_IRQ to allow SDCC deiver to disable + * the sdc2_clock and internally allows MSM to enter + * TCXO shutdown properly. */ - ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow); - if (ret) - return ret; + if ((flags & MMC_PM_WAKE_SDIO_IRQ)) { + ret = sdio_set_host_pm_flags(func, + MMC_PM_WAKE_SDIO_IRQ); + if (ret) + goto cut_pwr; + } - ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ); + ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, + NULL); if (ret) - ath6kl_err("set sdio wake irq flag failed: %d\n", ret); + goto cut_pwr; - return ret; + return 0; } -deepsleep: - return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL); +cut_pwr: + return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL); } static int ath6kl_sdio_resume(struct ath6kl *ar) @@ -869,8 +938,15 @@ static int ath6kl_sdio_resume(struct ath6kl *ar) case ATH6KL_STATE_WOW: break; + case ATH6KL_STATE_SCHED_SCAN: break; + + case ATH6KL_STATE_SUSPENDING: + break; + + case ATH6KL_STATE_RESUMING: + break; } ath6kl_cfg80211_resume(ar); @@ -949,7 +1025,7 @@ static int ath6kl_sdio_diag_read32(struct ath6kl *ar, u32 address, u32 *data) (u8 *)data, sizeof(u32), HIF_RD_SYNC_BYTE_INC); if (status) { ath6kl_err("%s: failed to read from window data addr\n", - __func__); + __func__); return status; } @@ -1260,10 +1336,12 @@ static int ath6kl_sdio_probe(struct sdio_func *func, INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work); + init_waitqueue_head(&ar_sdio->irq_wq); + for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]); - ar = ath6kl_core_alloc(&ar_sdio->func->dev); + ar = ath6kl_core_create(&ar_sdio->func->dev); if (!ar) { ath6kl_err("Failed to alloc ath6kl core\n"); ret = -ENOMEM; @@ -1293,7 +1371,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func, return ret; err_core_alloc: - ath6kl_core_free(ar_sdio->ar); + ath6kl_core_destroy(ar_sdio->ar); err_dma: kfree(ar_sdio->dma_buffer); err_hif: @@ -1316,6 +1394,7 @@ static void ath6kl_sdio_remove(struct sdio_func *func) cancel_work_sync(&ar_sdio->wr_async_work); ath6kl_core_cleanup(ar_sdio->ar); + ath6kl_core_destroy(ar_sdio->ar); kfree(ar_sdio->dma_buffer); kfree(ar_sdio); @@ -1332,7 +1411,7 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = { MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices); static struct sdio_driver ath6kl_sdio_driver = { - .name = "ath6kl", + .name = "ath6kl_sdio", .id_table = ath6kl_sdio_devices, .probe = ath6kl_sdio_probe, .remove = ath6kl_sdio_remove, @@ -1362,19 +1441,19 @@ MODULE_AUTHOR("Atheros Communications, Inc."); MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_FIRMWARE(AR6003_HW_2_0_OTP_FILE); -MODULE_FIRMWARE(AR6003_HW_2_0_FIRMWARE_FILE); -MODULE_FIRMWARE(AR6003_HW_2_0_PATCH_FILE); +MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_OTP_FILE); +MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_PATCH_FILE); MODULE_FIRMWARE(AR6003_HW_2_0_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE); -MODULE_FIRMWARE(AR6003_HW_2_1_1_OTP_FILE); -MODULE_FIRMWARE(AR6003_HW_2_1_1_FIRMWARE_FILE); -MODULE_FIRMWARE(AR6003_HW_2_1_1_PATCH_FILE); +MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_OTP_FILE); +MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_PATCH_FILE); MODULE_FIRMWARE(AR6003_HW_2_1_1_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE); -MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_0_FW_DIR "/" AR6004_HW_1_0_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE); -MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_1_FW_DIR "/" AR6004_HW_1_1_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h index 108a723a1085..78e0ef4567a5 100644 --- a/drivers/net/wireless/ath/ath6kl/target.h +++ b/drivers/net/wireless/ath/ath6kl/target.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2010 Atheros Communications Inc. + * Copyright (c) 2011 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 @@ -19,6 +20,7 @@ #define AR6003_BOARD_DATA_SZ 1024 #define AR6003_BOARD_EXT_DATA_SZ 768 +#define AR6003_BOARD_EXT_DATA_SZ_V2 1024 #define AR6004_BOARD_DATA_SZ 6144 #define AR6004_BOARD_EXT_DATA_SZ 0 diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c index 381eb66a605f..6675c92b542b 100644 --- a/drivers/net/wireless/ath/ath6kl/testmode.c +++ b/drivers/net/wireless/ath/ath6kl/testmode.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,6 +16,7 @@ */ #include "testmode.h" +#include "debug.h" #include <net/netlink.h> @@ -30,7 +32,7 @@ enum ath6kl_tm_attr { enum ath6kl_tm_cmd { ATH6KL_TM_CMD_TCMD = 0, - ATH6KL_TM_CMD_RX_REPORT = 1, + ATH6KL_TM_CMD_RX_REPORT = 1, /* not used anymore */ }; #define ATH6KL_TM_DATA_MAX_LEN 5000 @@ -41,84 +43,33 @@ static const struct nla_policy ath6kl_tm_policy[ATH6KL_TM_ATTR_MAX + 1] = { .len = ATH6KL_TM_DATA_MAX_LEN }, }; -void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len) +void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len) { - if (down_interruptible(&ar->sem)) - return; - - kfree(ar->tm.rx_report); - - ar->tm.rx_report = kmemdup(buf, buf_len, GFP_KERNEL); - ar->tm.rx_report_len = buf_len; - - up(&ar->sem); - - wake_up(&ar->event_wq); -} - -static int ath6kl_tm_rx_report(struct ath6kl *ar, void *buf, size_t buf_len, - struct sk_buff *skb) -{ - int ret = 0; - long left; - - if (down_interruptible(&ar->sem)) - return -ERESTARTSYS; - - if (!test_bit(WMI_READY, &ar->flag)) { - ret = -EIO; - goto out; - } - - if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) { - ret = -EBUSY; - goto out; - } - - if (ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len) < 0) { - up(&ar->sem); - return -EIO; - } - - left = wait_event_interruptible_timeout(ar->event_wq, - ar->tm.rx_report != NULL, - WMI_TIMEOUT); + struct sk_buff *skb; - if (left == 0) { - ret = -ETIMEDOUT; - goto out; - } else if (left < 0) { - ret = left; - goto out; - } + if (!buf || buf_len == 0) + return; - if (ar->tm.rx_report == NULL || ar->tm.rx_report_len == 0) { - ret = -EINVAL; - goto out; + skb = cfg80211_testmode_alloc_event_skb(ar->wiphy, buf_len, GFP_KERNEL); + if (!skb) { + ath6kl_warn("failed to allocate testmode rx skb!\n"); + return; } - - NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, ar->tm.rx_report_len, - ar->tm.rx_report); - - kfree(ar->tm.rx_report); - ar->tm.rx_report = NULL; - -out: - up(&ar->sem); - - return ret; + NLA_PUT_U32(skb, ATH6KL_TM_ATTR_CMD, ATH6KL_TM_CMD_TCMD); + NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, buf_len, buf); + cfg80211_testmode_event(skb, GFP_KERNEL); + return; nla_put_failure: - ret = -ENOBUFS; - goto out; + kfree_skb(skb); + ath6kl_warn("nla_put failed on testmode rx skb!\n"); } int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) { struct ath6kl *ar = wiphy_priv(wiphy); struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1]; - int err, buf_len, reply_len; - struct sk_buff *skb; + int err, buf_len; void *buf; err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len, @@ -143,24 +94,6 @@ int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) break; case ATH6KL_TM_CMD_RX_REPORT: - if (!tb[ATH6KL_TM_ATTR_DATA]) - return -EINVAL; - - buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); - buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); - - reply_len = nla_total_size(ATH6KL_TM_DATA_MAX_LEN); - skb = cfg80211_testmode_alloc_reply_skb(wiphy, reply_len); - if (!skb) - return -ENOMEM; - - err = ath6kl_tm_rx_report(ar, buf, buf_len, skb); - if (err < 0) { - kfree_skb(skb); - return err; - } - - return cfg80211_testmode_reply(skb); default: return -EOPNOTSUPP; } diff --git a/drivers/net/wireless/ath/ath6kl/testmode.h b/drivers/net/wireless/ath/ath6kl/testmode.h index 43dffcc11fb1..fe651d6707df 100644 --- a/drivers/net/wireless/ath/ath6kl/testmode.h +++ b/drivers/net/wireless/ath/ath6kl/testmode.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011 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 @@ -18,13 +19,13 @@ #ifdef CONFIG_NL80211_TESTMODE -void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len); +void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len); int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len); #else -static inline void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, - size_t buf_len) +static inline void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, + size_t buf_len) { } diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 506a3031a885..f85353fd1792 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-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 @@ -17,6 +18,23 @@ #include "core.h" #include "debug.h" +/* + * tid - tid_mux0..tid_mux3 + * aid - tid_mux4..tid_mux7 + */ +#define ATH6KL_TID_MASK 0xf +#define ATH6KL_AID_SHIFT 4 + +static inline u8 ath6kl_get_tid(u8 tid_mux) +{ + return tid_mux & ATH6KL_TID_MASK; +} + +static inline u8 ath6kl_get_aid(u8 tid_mux) +{ + return tid_mux >> ATH6KL_AID_SHIFT; +} + static u8 ath6kl_ibss_map_epid(struct sk_buff *skb, struct net_device *dev, u32 *map_no) { @@ -77,12 +95,118 @@ static u8 ath6kl_ibss_map_epid(struct sk_buff *skb, struct net_device *dev, return ar->node_map[ep_map].ep_id; } +static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn, + struct ath6kl_vif *vif, + struct sk_buff *skb, + u32 *flags) +{ + struct ath6kl *ar = vif->ar; + bool is_apsdq_empty = false; + struct ethhdr *datap = (struct ethhdr *) skb->data; + u8 up = 0, traffic_class, *ip_hdr; + u16 ether_type; + struct ath6kl_llc_snap_hdr *llc_hdr; + + if (conn->sta_flags & STA_PS_APSD_TRIGGER) { + /* + * This tx is because of a uAPSD trigger, determine + * more and EOSP bit. Set EOSP if queue is empty + * or sufficient frames are delivered for this trigger. + */ + spin_lock_bh(&conn->psq_lock); + if (!skb_queue_empty(&conn->apsdq)) + *flags |= WMI_DATA_HDR_FLAGS_MORE; + else if (conn->sta_flags & STA_PS_APSD_EOSP) + *flags |= WMI_DATA_HDR_FLAGS_EOSP; + *flags |= WMI_DATA_HDR_FLAGS_UAPSD; + spin_unlock_bh(&conn->psq_lock); + return false; + } else if (!conn->apsd_info) + return false; + + if (test_bit(WMM_ENABLED, &vif->flags)) { + ether_type = be16_to_cpu(datap->h_proto); + if (is_ethertype(ether_type)) { + /* packet is in DIX format */ + ip_hdr = (u8 *)(datap + 1); + } else { + /* packet is in 802.3 format */ + llc_hdr = (struct ath6kl_llc_snap_hdr *) + (datap + 1); + ether_type = be16_to_cpu(llc_hdr->eth_type); + ip_hdr = (u8 *)(llc_hdr + 1); + } + + if (ether_type == IP_ETHERTYPE) + up = ath6kl_wmi_determine_user_priority( + ip_hdr, 0); + } + + traffic_class = ath6kl_wmi_get_traffic_class(up); + + if ((conn->apsd_info & (1 << traffic_class)) == 0) + return false; + + /* Queue the frames if the STA is sleeping */ + spin_lock_bh(&conn->psq_lock); + is_apsdq_empty = skb_queue_empty(&conn->apsdq); + skb_queue_tail(&conn->apsdq, skb); + spin_unlock_bh(&conn->psq_lock); + + /* + * If this is the first pkt getting queued + * for this STA, update the PVB for this STA + */ + if (is_apsdq_empty) { + ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi, + vif->fw_vif_idx, + conn->aid, 1, 0); + } + *flags |= WMI_DATA_HDR_FLAGS_UAPSD; + + return true; +} + +static bool ath6kl_process_psq(struct ath6kl_sta *conn, + struct ath6kl_vif *vif, + struct sk_buff *skb, + u32 *flags) +{ + bool is_psq_empty = false; + struct ath6kl *ar = vif->ar; + + if (conn->sta_flags & STA_PS_POLLED) { + spin_lock_bh(&conn->psq_lock); + if (!skb_queue_empty(&conn->psq)) + *flags |= WMI_DATA_HDR_FLAGS_MORE; + spin_unlock_bh(&conn->psq_lock); + return false; + } + + /* Queue the frames if the STA is sleeping */ + spin_lock_bh(&conn->psq_lock); + is_psq_empty = skb_queue_empty(&conn->psq); + skb_queue_tail(&conn->psq, skb); + spin_unlock_bh(&conn->psq_lock); + + /* + * If this is the first pkt getting queued + * for this STA, update the PVB for this + * STA. + */ + if (is_psq_empty) + ath6kl_wmi_set_pvb_cmd(ar->wmi, + vif->fw_vif_idx, + conn->aid, 1); + return true; +} + static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb, - bool *more_data) + u32 *flags) { struct ethhdr *datap = (struct ethhdr *) skb->data; struct ath6kl_sta *conn = NULL; - bool ps_queued = false, is_psq_empty = false; + bool ps_queued = false; struct ath6kl *ar = vif->ar; if (is_multicast_ether_addr(datap->h_dest)) { @@ -128,7 +252,7 @@ static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb, */ spin_lock_bh(&ar->mcastpsq_lock); if (!skb_queue_empty(&ar->mcastpsq)) - *more_data = true; + *flags |= WMI_DATA_HDR_FLAGS_MORE; spin_unlock_bh(&ar->mcastpsq_lock); } } @@ -142,37 +266,13 @@ static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb, } if (conn->sta_flags & STA_PS_SLEEP) { - if (!(conn->sta_flags & STA_PS_POLLED)) { - /* Queue the frames if the STA is sleeping */ - spin_lock_bh(&conn->psq_lock); - is_psq_empty = skb_queue_empty(&conn->psq); - skb_queue_tail(&conn->psq, skb); - spin_unlock_bh(&conn->psq_lock); - - /* - * If this is the first pkt getting queued - * for this STA, update the PVB for this - * STA. - */ - if (is_psq_empty) - ath6kl_wmi_set_pvb_cmd(ar->wmi, - vif->fw_vif_idx, - conn->aid, 1); - - ps_queued = true; - } else { - /* - * This tx is because of a PsPoll. - * Determine if MoreData bit has to be set. - */ - spin_lock_bh(&conn->psq_lock); - if (!skb_queue_empty(&conn->psq)) - *more_data = true; - spin_unlock_bh(&conn->psq_lock); - } + ps_queued = ath6kl_process_uapsdq(conn, + vif, skb, flags); + if (!(*flags & WMI_DATA_HDR_FLAGS_UAPSD)) + ps_queued = ath6kl_process_psq(conn, + vif, skb, flags); } } - return ps_queued; } @@ -185,6 +285,9 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, int status = 0; struct ath6kl_cookie *cookie = NULL; + if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) + return -EACCES; + spin_lock_bh(&ar->lock); ath6kl_dbg(ATH6KL_DBG_WLAN_TX, @@ -242,8 +345,13 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) u32 map_no = 0; u16 htc_tag = ATH6KL_DATA_PKT_TAG; u8 ac = 99 ; /* initialize to unmapped ac */ - bool chk_adhoc_ps_mapping = false, more_data = false; + bool chk_adhoc_ps_mapping = false; int ret; + struct wmi_tx_meta_v2 meta_v2; + void *meta; + u8 csum_start = 0, csum_dest = 0, csum = skb->ip_summed; + u8 meta_ver = 0; + u32 flags = 0; ath6kl_dbg(ATH6KL_DBG_WLAN_TX, "%s: skb=0x%p, data=0x%p, len=0x%x\n", __func__, @@ -255,16 +363,29 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) return 0; } + if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON)) { + dev_kfree_skb(skb); + return 0; + } + if (!test_bit(WMI_READY, &ar->flag)) goto fail_tx; /* AP mode Power saving processing */ if (vif->nw_type == AP_NETWORK) { - if (ath6kl_powersave_ap(vif, skb, &more_data)) + if (ath6kl_powersave_ap(vif, skb, &flags)) return 0; } if (test_bit(WMI_ENABLED, &ar->flag)) { + if ((dev->features & NETIF_F_IP_CSUM) && + (csum == CHECKSUM_PARTIAL)) { + csum_start = skb->csum_start - + (skb_network_header(skb) - skb->head) + + sizeof(struct ath6kl_llc_snap_hdr); + csum_dest = skb->csum_offset + csum_start; + } + if (skb_headroom(skb) < dev->needed_headroom) { struct sk_buff *tmp_skb = skb; @@ -281,15 +402,33 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) goto fail_tx; } - if (ath6kl_wmi_data_hdr_add(ar->wmi, skb, DATA_MSGTYPE, - more_data, 0, 0, NULL, - vif->fw_vif_idx)) { - ath6kl_err("wmi_data_hdr_add failed\n"); + if ((dev->features & NETIF_F_IP_CSUM) && + (csum == CHECKSUM_PARTIAL)) { + meta_v2.csum_start = csum_start; + meta_v2.csum_dest = csum_dest; + + /* instruct target to calculate checksum */ + meta_v2.csum_flags = WMI_META_V2_FLAG_CSUM_OFFLOAD; + meta_ver = WMI_META_VERSION_2; + meta = &meta_v2; + } else { + meta_ver = 0; + meta = NULL; + } + + ret = ath6kl_wmi_data_hdr_add(ar->wmi, skb, + DATA_MSGTYPE, flags, 0, + meta_ver, + meta, vif->fw_vif_idx); + + if (ret) { + ath6kl_warn("failed to add wmi data header:%d\n" + , ret); goto fail_tx; } if ((vif->nw_type == ADHOC_NETWORK) && - ar->ibss_ps_enable && test_bit(CONNECTED, &vif->flags)) + ar->ibss_ps_enable && test_bit(CONNECTED, &vif->flags)) chk_adhoc_ps_mapping = true; else { /* get the stream mapping */ @@ -449,9 +588,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, * WMI queue with too many commands the only exception to * this is during testing using endpointping. */ - spin_lock_bh(&ar->lock); set_bit(WMI_CTRL_EP_FULL, &ar->flag); - spin_unlock_bh(&ar->lock); ath6kl_err("wmi ctrl ep is full\n"); return action; } @@ -465,7 +602,8 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, */ if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] < ar->hiac_stream_active_pri && - ar->cookie_count <= MAX_HI_COOKIE_NUM) + ar->cookie_count <= + target->endpoint[endpoint].tx_drop_packet_threshold) /* * Give preference to the highest priority stream by * dropping the packets which overflowed. @@ -479,9 +617,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, action != HTC_SEND_FULL_DROP) { spin_unlock_bh(&ar->list_lock); - spin_lock_bh(&vif->if_lock); set_bit(NETQ_STOPPED, &vif->flags); - spin_unlock_bh(&vif->if_lock); netif_stop_queue(vif->ndev); return action; @@ -710,10 +846,12 @@ static struct sk_buff *aggr_get_free_skb(struct aggr_info *p_aggr) { struct sk_buff *skb = NULL; - if (skb_queue_len(&p_aggr->free_q) < (AGGR_NUM_OF_FREE_NETBUFS >> 2)) - ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS); + if (skb_queue_len(&p_aggr->rx_amsdu_freeq) < + (AGGR_NUM_OF_FREE_NETBUFS >> 2)) + ath6kl_alloc_netbufs(&p_aggr->rx_amsdu_freeq, + AGGR_NUM_OF_FREE_NETBUFS); - skb = skb_dequeue(&p_aggr->free_q); + skb = skb_dequeue(&p_aggr->rx_amsdu_freeq); return skb; } @@ -748,7 +886,7 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint) if (!IS_ALIGNED((unsigned long) skb->data, 4)) skb->data = PTR_ALIGN(skb->data - 4, 4); set_htc_rxpkt_info(packet, skb, skb->data, - ATH6KL_BUFFER_SIZE, endpoint); + ATH6KL_BUFFER_SIZE, endpoint); list_add_tail(&packet->list, &queue); } @@ -881,7 +1019,7 @@ static void aggr_slice_amsdu(struct aggr_info *p_aggr, dev_kfree_skb(skb); } -static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, +static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid, u16 seq_no, u8 order) { struct sk_buff *skb; @@ -890,11 +1028,8 @@ static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, u16 idx, idx_end, seq_end; struct rxtid_stats *stats; - if (!p_aggr) - return; - - rxtid = &p_aggr->rx_tid[tid]; - stats = &p_aggr->stat[tid]; + rxtid = &agg_conn->rx_tid[tid]; + stats = &agg_conn->stat[tid]; idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz); @@ -923,7 +1058,8 @@ static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, if (node->skb) { if (node->is_amsdu) - aggr_slice_amsdu(p_aggr, rxtid, node->skb); + aggr_slice_amsdu(agg_conn->aggr_info, rxtid, + node->skb); else skb_queue_tail(&rxtid->q, node->skb); node->skb = NULL; @@ -939,10 +1075,10 @@ static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, stats->num_delivered += skb_queue_len(&rxtid->q); while ((skb = skb_dequeue(&rxtid->q))) - ath6kl_deliver_frames_to_nw_stack(p_aggr->dev, skb); + ath6kl_deliver_frames_to_nw_stack(agg_conn->dev, skb); } -static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, +static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid, u16 seq_no, bool is_amsdu, struct sk_buff *frame) { @@ -954,18 +1090,18 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, bool is_queued = false; u16 extended_end; - rxtid = &agg_info->rx_tid[tid]; - stats = &agg_info->stat[tid]; + rxtid = &agg_conn->rx_tid[tid]; + stats = &agg_conn->stat[tid]; stats->num_into_aggr++; if (!rxtid->aggr) { if (is_amsdu) { - aggr_slice_amsdu(agg_info, rxtid, frame); + aggr_slice_amsdu(agg_conn->aggr_info, rxtid, frame); is_queued = true; stats->num_amsdu++; while ((skb = skb_dequeue(&rxtid->q))) - ath6kl_deliver_frames_to_nw_stack(agg_info->dev, + ath6kl_deliver_frames_to_nw_stack(agg_conn->dev, skb); } return is_queued; @@ -985,7 +1121,7 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, (cur < end || cur > extended_end)) || ((end > extended_end) && (cur > extended_end) && (cur < end))) { - aggr_deque_frms(agg_info, tid, 0, 0); + aggr_deque_frms(agg_conn, tid, 0, 0); if (cur >= rxtid->hold_q_sz - 1) rxtid->seq_next = cur - (rxtid->hold_q_sz - 1); else @@ -1002,7 +1138,7 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, st = ATH6KL_MAX_SEQ_NO - (rxtid->hold_q_sz - 2 - cur); - aggr_deque_frms(agg_info, tid, st, 0); + aggr_deque_frms(agg_conn, tid, st, 0); } stats->num_oow++; @@ -1041,9 +1177,9 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, spin_unlock_bh(&rxtid->lock); - aggr_deque_frms(agg_info, tid, 0, 1); + aggr_deque_frms(agg_conn, tid, 0, 1); - if (agg_info->timer_scheduled) + if (agg_conn->timer_scheduled) rxtid->progress = true; else for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) { @@ -1054,8 +1190,8 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, * the frame doesn't remain stuck * forever. */ - agg_info->timer_scheduled = true; - mod_timer(&agg_info->timer, + agg_conn->timer_scheduled = true; + mod_timer(&agg_conn->timer, (jiffies + HZ * (AGGR_RX_TIMEOUT) / 1000)); rxtid->progress = false; @@ -1067,6 +1203,76 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, return is_queued; } +static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif, + struct ath6kl_sta *conn) +{ + struct ath6kl *ar = vif->ar; + bool is_apsdq_empty, is_apsdq_empty_at_start; + u32 num_frames_to_deliver, flags; + struct sk_buff *skb = NULL; + + /* + * If the APSD q for this STA is not empty, dequeue and + * send a pkt from the head of the q. Also update the + * More data bit in the WMI_DATA_HDR if there are + * more pkts for this STA in the APSD q. + * If there are no more pkts for this STA, + * update the APSD bitmap for this STA. + */ + + num_frames_to_deliver = (conn->apsd_info >> ATH6KL_APSD_NUM_OF_AC) & + ATH6KL_APSD_FRAME_MASK; + /* + * Number of frames to send in a service period is + * indicated by the station + * in the QOS_INFO of the association request + * If it is zero, send all frames + */ + if (!num_frames_to_deliver) + num_frames_to_deliver = ATH6KL_APSD_ALL_FRAME; + + spin_lock_bh(&conn->psq_lock); + is_apsdq_empty = skb_queue_empty(&conn->apsdq); + spin_unlock_bh(&conn->psq_lock); + is_apsdq_empty_at_start = is_apsdq_empty; + + while ((!is_apsdq_empty) && (num_frames_to_deliver)) { + + spin_lock_bh(&conn->psq_lock); + skb = skb_dequeue(&conn->apsdq); + is_apsdq_empty = skb_queue_empty(&conn->apsdq); + spin_unlock_bh(&conn->psq_lock); + + /* + * Set the STA flag to Trigger delivery, + * so that the frame will go out + */ + conn->sta_flags |= STA_PS_APSD_TRIGGER; + num_frames_to_deliver--; + + /* Last frame in the service period, set EOSP or queue empty */ + if ((is_apsdq_empty) || (!num_frames_to_deliver)) + conn->sta_flags |= STA_PS_APSD_EOSP; + + ath6kl_data_tx(skb, vif->ndev); + conn->sta_flags &= ~(STA_PS_APSD_TRIGGER); + conn->sta_flags &= ~(STA_PS_APSD_EOSP); + } + + if (is_apsdq_empty) { + if (is_apsdq_empty_at_start) + flags = WMI_AP_APSD_NO_DELIVERY_FRAMES; + else + flags = 0; + + ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi, + vif->fw_vif_idx, + conn->aid, 0, flags); + } + + return; +} + void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) { struct ath6kl *ar = target->dev->ar; @@ -1078,10 +1284,12 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) int status = packet->status; enum htc_endpoint_id ept = packet->endpoint; bool is_amsdu, prev_ps, ps_state = false; + bool trig_state = false; struct ath6kl_sta *conn = NULL; struct sk_buff *skb1 = NULL; struct ethhdr *datap = NULL; struct ath6kl_vif *vif; + struct aggr_info_conn *aggr_conn; u16 seq_no, offset; u8 tid, if_idx; @@ -1098,7 +1306,15 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) skb_put(skb, packet->act_len + HTC_HDR_LENGTH); skb_pull(skb, HTC_HDR_LENGTH); + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ", + skb->data, skb->len); + if (ept == ar->ctrl_ep) { + if (test_bit(WMI_ENABLED, &ar->flag)) { + ath6kl_check_wow_status(ar); + ath6kl_wmi_control_rx(ar->wmi, skb); + return; + } if_idx = wmi_cmd_hdr_get_if_idx((struct wmi_cmd_hdr *) skb->data); } else { @@ -1123,10 +1339,6 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) spin_unlock_bh(&vif->if_lock); - - ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ", - skb->data, skb->len); - skb->dev = vif->ndev; if (!test_bit(WMI_ENABLED, &ar->flag)) { @@ -1138,11 +1350,6 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) ath6kl_check_wow_status(ar); - if (ept == ar->ctrl_ep) { - ath6kl_wmi_control_rx(ar->wmi, skb); - return; - } - min_hdr_len = sizeof(struct ethhdr) + sizeof(struct wmi_data_hdr) + sizeof(struct ath6kl_llc_snap_hdr); @@ -1171,6 +1378,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) WMI_DATA_HDR_PS_MASK); offset = sizeof(struct wmi_data_hdr); + trig_state = !!(le16_to_cpu(dhdr->info3) & WMI_DATA_HDR_TRIG); switch (meta_type) { case 0: @@ -1209,18 +1417,61 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) else conn->sta_flags &= ~STA_PS_SLEEP; + /* Accept trigger only when the station is in sleep */ + if ((conn->sta_flags & STA_PS_SLEEP) && trig_state) + ath6kl_uapsd_trigger_frame_rx(vif, conn); + if (prev_ps ^ !!(conn->sta_flags & STA_PS_SLEEP)) { if (!(conn->sta_flags & STA_PS_SLEEP)) { struct sk_buff *skbuff = NULL; + bool is_apsdq_empty; + struct ath6kl_mgmt_buff *mgmt; + u8 idx; spin_lock_bh(&conn->psq_lock); - while ((skbuff = skb_dequeue(&conn->psq)) - != NULL) { + while (conn->mgmt_psq_len > 0) { + mgmt = list_first_entry( + &conn->mgmt_psq, + struct ath6kl_mgmt_buff, + list); + list_del(&mgmt->list); + conn->mgmt_psq_len--; + spin_unlock_bh(&conn->psq_lock); + idx = vif->fw_vif_idx; + + ath6kl_wmi_send_mgmt_cmd(ar->wmi, + idx, + mgmt->id, + mgmt->freq, + mgmt->wait, + mgmt->buf, + mgmt->len, + mgmt->no_cck); + + kfree(mgmt); + spin_lock_bh(&conn->psq_lock); + } + conn->mgmt_psq_len = 0; + while ((skbuff = skb_dequeue(&conn->psq))) { + spin_unlock_bh(&conn->psq_lock); + ath6kl_data_tx(skbuff, vif->ndev); + spin_lock_bh(&conn->psq_lock); + } + + is_apsdq_empty = skb_queue_empty(&conn->apsdq); + while ((skbuff = skb_dequeue(&conn->apsdq))) { spin_unlock_bh(&conn->psq_lock); ath6kl_data_tx(skbuff, vif->ndev); spin_lock_bh(&conn->psq_lock); } spin_unlock_bh(&conn->psq_lock); + + if (!is_apsdq_empty) + ath6kl_wmi_set_apsd_bfrd_traf( + ar->wmi, + vif->fw_vif_idx, + conn->aid, 0, 0); + /* Clear the PVB for this STA */ ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx, conn->aid, 0); @@ -1314,11 +1565,21 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) datap = (struct ethhdr *) skb->data; - if (is_unicast_ether_addr(datap->h_dest) && - aggr_process_recv_frm(vif->aggr_cntxt, tid, seq_no, - is_amsdu, skb)) - /* aggregation code will handle the skb */ - return; + if (is_unicast_ether_addr(datap->h_dest)) { + if (vif->nw_type == AP_NETWORK) { + conn = ath6kl_find_sta(vif, datap->h_source); + if (!conn) + return; + aggr_conn = conn->aggr_conn; + } else + aggr_conn = vif->aggr_cntxt->aggr_conn; + + if (aggr_process_recv_frm(aggr_conn, tid, seq_no, + is_amsdu, skb)) { + /* aggregation code will handle the skb */ + return; + } + } ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb); } @@ -1326,13 +1587,13 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) static void aggr_timeout(unsigned long arg) { u8 i, j; - struct aggr_info *p_aggr = (struct aggr_info *) arg; + struct aggr_info_conn *aggr_conn = (struct aggr_info_conn *) arg; struct rxtid *rxtid; struct rxtid_stats *stats; for (i = 0; i < NUM_OF_TIDS; i++) { - rxtid = &p_aggr->rx_tid[i]; - stats = &p_aggr->stat[i]; + rxtid = &aggr_conn->rx_tid[i]; + stats = &aggr_conn->stat[i]; if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress) continue; @@ -1343,18 +1604,18 @@ static void aggr_timeout(unsigned long arg) rxtid->seq_next, ((rxtid->seq_next + rxtid->hold_q_sz-1) & ATH6KL_MAX_SEQ_NO)); - aggr_deque_frms(p_aggr, i, 0, 0); + aggr_deque_frms(aggr_conn, i, 0, 0); } - p_aggr->timer_scheduled = false; + aggr_conn->timer_scheduled = false; for (i = 0; i < NUM_OF_TIDS; i++) { - rxtid = &p_aggr->rx_tid[i]; + rxtid = &aggr_conn->rx_tid[i]; if (rxtid->aggr && rxtid->hold_q) { for (j = 0; j < rxtid->hold_q_sz; j++) { if (rxtid->hold_q[j].skb) { - p_aggr->timer_scheduled = true; + aggr_conn->timer_scheduled = true; rxtid->timer_mon = true; rxtid->progress = false; break; @@ -1366,24 +1627,24 @@ static void aggr_timeout(unsigned long arg) } } - if (p_aggr->timer_scheduled) - mod_timer(&p_aggr->timer, + if (aggr_conn->timer_scheduled) + mod_timer(&aggr_conn->timer, jiffies + msecs_to_jiffies(AGGR_RX_TIMEOUT)); } -static void aggr_delete_tid_state(struct aggr_info *p_aggr, u8 tid) +static void aggr_delete_tid_state(struct aggr_info_conn *aggr_conn, u8 tid) { struct rxtid *rxtid; struct rxtid_stats *stats; - if (!p_aggr || tid >= NUM_OF_TIDS) + if (!aggr_conn || tid >= NUM_OF_TIDS) return; - rxtid = &p_aggr->rx_tid[tid]; - stats = &p_aggr->stat[tid]; + rxtid = &aggr_conn->rx_tid[tid]; + stats = &aggr_conn->stat[tid]; if (rxtid->aggr) - aggr_deque_frms(p_aggr, tid, 0, 0); + aggr_deque_frms(aggr_conn, tid, 0, 0); rxtid->aggr = false; rxtid->progress = false; @@ -1398,26 +1659,40 @@ static void aggr_delete_tid_state(struct aggr_info *p_aggr, u8 tid) memset(stats, 0, sizeof(struct rxtid_stats)); } -void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid, u16 seq_no, +void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid_mux, u16 seq_no, u8 win_sz) { - struct aggr_info *p_aggr = vif->aggr_cntxt; + struct ath6kl_sta *sta; + struct aggr_info_conn *aggr_conn = NULL; struct rxtid *rxtid; struct rxtid_stats *stats; u16 hold_q_size; + u8 tid, aid; - if (!p_aggr) + if (vif->nw_type == AP_NETWORK) { + aid = ath6kl_get_aid(tid_mux); + sta = ath6kl_find_sta_by_aid(vif->ar, aid); + if (sta) + aggr_conn = sta->aggr_conn; + } else + aggr_conn = vif->aggr_cntxt->aggr_conn; + + if (!aggr_conn) return; - rxtid = &p_aggr->rx_tid[tid]; - stats = &p_aggr->stat[tid]; + tid = ath6kl_get_tid(tid_mux); + if (tid >= NUM_OF_TIDS) + return; + + rxtid = &aggr_conn->rx_tid[tid]; + stats = &aggr_conn->stat[tid]; if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n", __func__, win_sz, tid); if (rxtid->aggr) - aggr_delete_tid_state(p_aggr, tid); + aggr_delete_tid_state(aggr_conn, tid); rxtid->seq_next = seq_no; hold_q_size = TID_WINDOW_SZ(win_sz) * sizeof(struct skb_hold_q); @@ -1433,31 +1708,23 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid, u16 seq_no, rxtid->aggr = true; } -struct aggr_info *aggr_init(struct net_device *dev) +void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info, + struct aggr_info_conn *aggr_conn) { - struct aggr_info *p_aggr = NULL; struct rxtid *rxtid; u8 i; - p_aggr = kzalloc(sizeof(struct aggr_info), GFP_KERNEL); - if (!p_aggr) { - ath6kl_err("failed to alloc memory for aggr_node\n"); - return NULL; - } - - p_aggr->aggr_sz = AGGR_SZ_DEFAULT; - p_aggr->dev = dev; - init_timer(&p_aggr->timer); - p_aggr->timer.function = aggr_timeout; - p_aggr->timer.data = (unsigned long) p_aggr; - - p_aggr->timer_scheduled = false; - skb_queue_head_init(&p_aggr->free_q); + aggr_conn->aggr_sz = AGGR_SZ_DEFAULT; + aggr_conn->dev = vif->ndev; + init_timer(&aggr_conn->timer); + aggr_conn->timer.function = aggr_timeout; + aggr_conn->timer.data = (unsigned long) aggr_conn; + aggr_conn->aggr_info = aggr_info; - ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS); + aggr_conn->timer_scheduled = false; for (i = 0; i < NUM_OF_TIDS; i++) { - rxtid = &p_aggr->rx_tid[i]; + rxtid = &aggr_conn->rx_tid[i]; rxtid->aggr = false; rxtid->progress = false; rxtid->timer_mon = false; @@ -1465,29 +1732,75 @@ struct aggr_info *aggr_init(struct net_device *dev) spin_lock_init(&rxtid->lock); } +} + +struct aggr_info *aggr_init(struct ath6kl_vif *vif) +{ + struct aggr_info *p_aggr = NULL; + + p_aggr = kzalloc(sizeof(struct aggr_info), GFP_KERNEL); + if (!p_aggr) { + ath6kl_err("failed to alloc memory for aggr_node\n"); + return NULL; + } + + p_aggr->aggr_conn = kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL); + if (!p_aggr->aggr_conn) { + ath6kl_err("failed to alloc memory for connection specific aggr info\n"); + kfree(p_aggr); + return NULL; + } + + aggr_conn_init(vif, p_aggr, p_aggr->aggr_conn); + + skb_queue_head_init(&p_aggr->rx_amsdu_freeq); + ath6kl_alloc_netbufs(&p_aggr->rx_amsdu_freeq, AGGR_NUM_OF_FREE_NETBUFS); + return p_aggr; } -void aggr_recv_delba_req_evt(struct ath6kl_vif *vif, u8 tid) +void aggr_recv_delba_req_evt(struct ath6kl_vif *vif, u8 tid_mux) { - struct aggr_info *p_aggr = vif->aggr_cntxt; + struct ath6kl_sta *sta; struct rxtid *rxtid; + struct aggr_info_conn *aggr_conn = NULL; + u8 tid, aid; + + if (vif->nw_type == AP_NETWORK) { + aid = ath6kl_get_aid(tid_mux); + sta = ath6kl_find_sta_by_aid(vif->ar, aid); + if (sta) + aggr_conn = sta->aggr_conn; + } else + aggr_conn = vif->aggr_cntxt->aggr_conn; - if (!p_aggr) + if (!aggr_conn) return; - rxtid = &p_aggr->rx_tid[tid]; + tid = ath6kl_get_tid(tid_mux); + if (tid >= NUM_OF_TIDS) + return; + + rxtid = &aggr_conn->rx_tid[tid]; if (rxtid->aggr) - aggr_delete_tid_state(p_aggr, tid); + aggr_delete_tid_state(aggr_conn, tid); } -void aggr_reset_state(struct aggr_info *aggr_info) +void aggr_reset_state(struct aggr_info_conn *aggr_conn) { u8 tid; + if (!aggr_conn) + return; + + if (aggr_conn->timer_scheduled) { + del_timer(&aggr_conn->timer); + aggr_conn->timer_scheduled = false; + } + for (tid = 0; tid < NUM_OF_TIDS; tid++) - aggr_delete_tid_state(aggr_info, tid); + aggr_delete_tid_state(aggr_conn, tid); } /* clean up our amsdu buffer list */ @@ -1514,28 +1827,11 @@ void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar) void aggr_module_destroy(struct aggr_info *aggr_info) { - struct rxtid *rxtid; - u8 i, k; - if (!aggr_info) return; - if (aggr_info->timer_scheduled) { - del_timer(&aggr_info->timer); - aggr_info->timer_scheduled = false; - } - - for (i = 0; i < NUM_OF_TIDS; i++) { - rxtid = &aggr_info->rx_tid[i]; - if (rxtid->hold_q) { - for (k = 0; k < rxtid->hold_q_sz; k++) - dev_kfree_skb(rxtid->hold_q[k].skb); - kfree(rxtid->hold_q); - } - - skb_queue_purge(&rxtid->q); - } - - skb_queue_purge(&aggr_info->free_q); + aggr_reset_state(aggr_info->aggr_conn); + skb_queue_purge(&aggr_info->rx_amsdu_freeq); + kfree(aggr_info->aggr_conn); kfree(aggr_info); } diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c new file mode 100644 index 000000000000..325b1224c2b1 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2007-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. + */ + +#include <linux/module.h> +#include <linux/usb.h> + +#include "debug.h" +#include "core.h" + +/* usb device object */ +struct ath6kl_usb { + struct usb_device *udev; + struct usb_interface *interface; + u8 *diag_cmd_buffer; + u8 *diag_resp_buffer; + struct ath6kl *ar; +}; + +/* diagnostic command defnitions */ +#define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD 1 +#define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP 2 +#define ATH6KL_USB_CONTROL_REQ_DIAG_CMD 3 +#define ATH6KL_USB_CONTROL_REQ_DIAG_RESP 4 + +#define ATH6KL_USB_CTRL_DIAG_CC_READ 0 +#define ATH6KL_USB_CTRL_DIAG_CC_WRITE 1 + +struct ath6kl_usb_ctrl_diag_cmd_write { + __le32 cmd; + __le32 address; + __le32 value; + __le32 _pad[1]; +} __packed; + +struct ath6kl_usb_ctrl_diag_cmd_read { + __le32 cmd; + __le32 address; +} __packed; + +struct ath6kl_usb_ctrl_diag_resp_read { + __le32 value; +} __packed; + +#define ATH6KL_USB_MAX_DIAG_CMD (sizeof(struct ath6kl_usb_ctrl_diag_cmd_write)) +#define ATH6KL_USB_MAX_DIAG_RESP (sizeof(struct ath6kl_usb_ctrl_diag_resp_read)) + +static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb) +{ + usb_set_intfdata(ar_usb->interface, NULL); + + kfree(ar_usb->diag_cmd_buffer); + kfree(ar_usb->diag_resp_buffer); + + kfree(ar_usb); +} + +static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface) +{ + struct ath6kl_usb *ar_usb = NULL; + struct usb_device *dev = interface_to_usbdev(interface); + int status = 0; + + ar_usb = kzalloc(sizeof(struct ath6kl_usb), GFP_KERNEL); + if (ar_usb == NULL) + goto fail_ath6kl_usb_create; + + memset(ar_usb, 0, sizeof(struct ath6kl_usb)); + usb_set_intfdata(interface, ar_usb); + ar_usb->udev = dev; + ar_usb->interface = interface; + + ar_usb->diag_cmd_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_CMD, GFP_KERNEL); + if (ar_usb->diag_cmd_buffer == NULL) { + status = -ENOMEM; + goto fail_ath6kl_usb_create; + } + + ar_usb->diag_resp_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_RESP, + GFP_KERNEL); + if (ar_usb->diag_resp_buffer == NULL) { + status = -ENOMEM; + goto fail_ath6kl_usb_create; + } + +fail_ath6kl_usb_create: + if (status != 0) { + ath6kl_usb_destroy(ar_usb); + ar_usb = NULL; + } + return ar_usb; +} + +static void ath6kl_usb_device_detached(struct usb_interface *interface) +{ + struct ath6kl_usb *ar_usb; + + ar_usb = usb_get_intfdata(interface); + if (ar_usb == NULL) + return; + + ath6kl_stop_txrx(ar_usb->ar); + + ath6kl_core_cleanup(ar_usb->ar); + + ath6kl_usb_destroy(ar_usb); +} + +static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb, + u8 req, u16 value, u16 index, void *data, + u32 size) +{ + u8 *buf = NULL; + int ret; + + if (size > 0) { + buf = kmalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + memcpy(buf, data, size); + } + + /* note: if successful returns number of bytes transfered */ + ret = usb_control_msg(ar_usb->udev, + usb_sndctrlpipe(ar_usb->udev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, value, index, buf, + size, 1000); + + if (ret < 0) { + ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n", + __func__, ret); + } + + kfree(buf); + + return 0; +} + +static int ath6kl_usb_submit_ctrl_in(struct ath6kl_usb *ar_usb, + u8 req, u16 value, u16 index, void *data, + u32 size) +{ + u8 *buf = NULL; + int ret; + + if (size > 0) { + buf = kmalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + } + + /* note: if successful returns number of bytes transfered */ + ret = usb_control_msg(ar_usb->udev, + usb_rcvctrlpipe(ar_usb->udev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, value, index, buf, + size, 2 * HZ); + + if (ret < 0) { + ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n", + __func__, ret); + } + + memcpy((u8 *) data, buf, size); + + kfree(buf); + + return 0; +} + +static int ath6kl_usb_ctrl_msg_exchange(struct ath6kl_usb *ar_usb, + u8 req_val, u8 *req_buf, u32 req_len, + u8 resp_val, u8 *resp_buf, u32 *resp_len) +{ + int ret; + + /* send command */ + ret = ath6kl_usb_submit_ctrl_out(ar_usb, req_val, 0, 0, + req_buf, req_len); + + if (ret != 0) + return ret; + + if (resp_buf == NULL) { + /* no expected response */ + return ret; + } + + /* get response */ + ret = ath6kl_usb_submit_ctrl_in(ar_usb, resp_val, 0, 0, + resp_buf, *resp_len); + + return ret; +} + +static int ath6kl_usb_diag_read32(struct ath6kl *ar, u32 address, u32 *data) +{ + struct ath6kl_usb *ar_usb = ar->hif_priv; + struct ath6kl_usb_ctrl_diag_resp_read *resp; + struct ath6kl_usb_ctrl_diag_cmd_read *cmd; + u32 resp_len; + int ret; + + cmd = (struct ath6kl_usb_ctrl_diag_cmd_read *) ar_usb->diag_cmd_buffer; + + memset(cmd, 0, sizeof(*cmd)); + cmd->cmd = ATH6KL_USB_CTRL_DIAG_CC_READ; + cmd->address = cpu_to_le32(address); + resp_len = sizeof(*resp); + + ret = ath6kl_usb_ctrl_msg_exchange(ar_usb, + ATH6KL_USB_CONTROL_REQ_DIAG_CMD, + (u8 *) cmd, + sizeof(struct ath6kl_usb_ctrl_diag_cmd_write), + ATH6KL_USB_CONTROL_REQ_DIAG_RESP, + ar_usb->diag_resp_buffer, &resp_len); + + if (ret) + return ret; + + resp = (struct ath6kl_usb_ctrl_diag_resp_read *) + ar_usb->diag_resp_buffer; + + *data = le32_to_cpu(resp->value); + + return ret; +} + +static int ath6kl_usb_diag_write32(struct ath6kl *ar, u32 address, __le32 data) +{ + struct ath6kl_usb *ar_usb = ar->hif_priv; + struct ath6kl_usb_ctrl_diag_cmd_write *cmd; + + cmd = (struct ath6kl_usb_ctrl_diag_cmd_write *) ar_usb->diag_cmd_buffer; + + memset(cmd, 0, sizeof(struct ath6kl_usb_ctrl_diag_cmd_write)); + cmd->cmd = cpu_to_le32(ATH6KL_USB_CTRL_DIAG_CC_WRITE); + cmd->address = cpu_to_le32(address); + cmd->value = data; + + return ath6kl_usb_ctrl_msg_exchange(ar_usb, + ATH6KL_USB_CONTROL_REQ_DIAG_CMD, + (u8 *) cmd, + sizeof(*cmd), + 0, NULL, NULL); + +} + +static int ath6kl_usb_bmi_read(struct ath6kl *ar, u8 *buf, u32 len) +{ + struct ath6kl_usb *ar_usb = ar->hif_priv; + int ret; + + /* get response */ + ret = ath6kl_usb_submit_ctrl_in(ar_usb, + ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP, + 0, 0, buf, len); + if (ret != 0) { + ath6kl_err("Unable to read the bmi data from the device: %d\n", + ret); + return ret; + } + + return 0; +} + +static int ath6kl_usb_bmi_write(struct ath6kl *ar, u8 *buf, u32 len) +{ + struct ath6kl_usb *ar_usb = ar->hif_priv; + int ret; + + /* send command */ + ret = ath6kl_usb_submit_ctrl_out(ar_usb, + ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD, + 0, 0, buf, len); + if (ret != 0) { + ath6kl_err("unable to send the bmi data to the device: %d\n", + ret); + return ret; + } + + return 0; +} + +static int ath6kl_usb_power_on(struct ath6kl *ar) +{ + return 0; +} + +static int ath6kl_usb_power_off(struct ath6kl *ar) +{ + return 0; +} + +static const struct ath6kl_hif_ops ath6kl_usb_ops = { + .diag_read32 = ath6kl_usb_diag_read32, + .diag_write32 = ath6kl_usb_diag_write32, + .bmi_read = ath6kl_usb_bmi_read, + .bmi_write = ath6kl_usb_bmi_write, + .power_on = ath6kl_usb_power_on, + .power_off = ath6kl_usb_power_off, +}; + +/* ath6kl usb driver registered functions */ +static int ath6kl_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(interface); + struct ath6kl *ar; + struct ath6kl_usb *ar_usb = NULL; + int vendor_id, product_id; + int ret = 0; + + usb_get_dev(dev); + + vendor_id = le16_to_cpu(dev->descriptor.idVendor); + product_id = le16_to_cpu(dev->descriptor.idProduct); + + ath6kl_dbg(ATH6KL_DBG_USB, "vendor_id = %04x\n", vendor_id); + ath6kl_dbg(ATH6KL_DBG_USB, "product_id = %04x\n", product_id); + + if (interface->cur_altsetting) + ath6kl_dbg(ATH6KL_DBG_USB, "USB Interface %d\n", + interface->cur_altsetting->desc.bInterfaceNumber); + + + if (dev->speed == USB_SPEED_HIGH) + ath6kl_dbg(ATH6KL_DBG_USB, "USB 2.0 Host\n"); + else + ath6kl_dbg(ATH6KL_DBG_USB, "USB 1.1 Host\n"); + + ar_usb = ath6kl_usb_create(interface); + + if (ar_usb == NULL) { + ret = -ENOMEM; + goto err_usb_put; + } + + ar = ath6kl_core_create(&ar_usb->udev->dev); + if (ar == NULL) { + ath6kl_err("Failed to alloc ath6kl core\n"); + ret = -ENOMEM; + goto err_usb_destroy; + } + + ar->hif_priv = ar_usb; + ar->hif_type = ATH6KL_HIF_TYPE_USB; + ar->hif_ops = &ath6kl_usb_ops; + ar->mbox_info.block_size = 16; + ar->bmi.max_data_size = 252; + + ar_usb->ar = ar; + + ret = ath6kl_core_init(ar); + if (ret) { + ath6kl_err("Failed to init ath6kl core: %d\n", ret); + goto err_core_free; + } + + return ret; + +err_core_free: + ath6kl_core_destroy(ar); +err_usb_destroy: + ath6kl_usb_destroy(ar_usb); +err_usb_put: + usb_put_dev(dev); + + return ret; +} + +static void ath6kl_usb_remove(struct usb_interface *interface) +{ + usb_put_dev(interface_to_usbdev(interface)); + ath6kl_usb_device_detached(interface); +} + +/* table of devices that work with this driver */ +static struct usb_device_id ath6kl_usb_ids[] = { + {USB_DEVICE(0x0cf3, 0x9374)}, + { /* Terminating entry */ }, +}; + +MODULE_DEVICE_TABLE(usb, ath6kl_usb_ids); + +static struct usb_driver ath6kl_usb_driver = { + .name = "ath6kl_usb", + .probe = ath6kl_usb_probe, + .disconnect = ath6kl_usb_remove, + .id_table = ath6kl_usb_ids, +}; + +static int ath6kl_usb_init(void) +{ + usb_register(&ath6kl_usb_driver); + return 0; +} + +static void ath6kl_usb_exit(void) +{ + usb_deregister(&ath6kl_usb_driver); +} + +module_init(ath6kl_usb_init); +module_exit(ath6kl_usb_exit); + +MODULE_AUTHOR("Atheros Communications, Inc."); +MODULE_DESCRIPTION("Driver support for Atheros AR600x USB devices"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index f6f2aa27fc20..2b442332cd0f 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-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 @@ -126,7 +127,7 @@ int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb) if (!is_ethertype(be16_to_cpu(type))) { ath6kl_dbg(ATH6KL_DBG_WMI, - "%s: pkt is already in 802.3 format\n", __func__); + "%s: pkt is already in 802.3 format\n", __func__); return 0; } @@ -180,7 +181,7 @@ static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb, } int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, - u8 msg_type, bool more_data, + u8 msg_type, u32 flags, enum wmi_data_hdr_data_type data_type, u8 meta_ver, void *tx_meta_info, u8 if_idx) { @@ -204,17 +205,19 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT; data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT; - if (more_data) - data_hdr->info |= - WMI_DATA_HDR_MORE_MASK << WMI_DATA_HDR_MORE_SHIFT; + if (flags & WMI_DATA_HDR_FLAGS_MORE) + data_hdr->info |= WMI_DATA_HDR_MORE; - data_hdr->info2 = cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT); - data_hdr->info3 = cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK); + if (flags & WMI_DATA_HDR_FLAGS_EOSP) + data_hdr->info3 |= cpu_to_le16(WMI_DATA_HDR_EOSP); + + data_hdr->info2 |= cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT); + data_hdr->info3 |= cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK); return 0; } -static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri) +u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri) { struct iphdr *ip_hdr = (struct iphdr *) pkt; u8 ip_pri; @@ -236,6 +239,11 @@ static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri) return ip_pri; } +u8 ath6kl_wmi_get_traffic_class(u8 user_priority) +{ + return up_to_ac[user_priority & 0x7]; +} + int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx, struct sk_buff *skb, u32 layer2_priority, bool wmm_enabled, @@ -419,9 +427,6 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len) ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n", evt->num_msg, evt->msg_len, evt->msg_type); - if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_WMI)) - return 0; - for (index = 0; index < evt->num_msg; index++) { size = sizeof(struct wmi_tx_complete_event) + (index * sizeof(struct tx_complete_msg_v1)); @@ -552,7 +557,8 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len, dlen, freq, vif->probe_req_report); if (vif->probe_req_report || vif->nw_type == AP_NETWORK) - cfg80211_rx_mgmt(vif->ndev, freq, ev->data, dlen, GFP_ATOMIC); + cfg80211_rx_mgmt(vif->ndev, freq, 0, + ev->data, dlen, GFP_ATOMIC); return 0; } @@ -591,7 +597,8 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len, return -EINVAL; } ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); - cfg80211_rx_mgmt(vif->ndev, freq, ev->data, dlen, GFP_ATOMIC); + cfg80211_rx_mgmt(vif->ndev, freq, 0, + ev->data, dlen, GFP_ATOMIC); return 0; } @@ -786,12 +793,14 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len, ev->u.ap_sta.keymgmt, le16_to_cpu(ev->u.ap_sta.cipher), ev->u.ap_sta.apsd_info); + ath6kl_connect_ap_mode_sta( vif, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr, ev->u.ap_sta.keymgmt, le16_to_cpu(ev->u.ap_sta.cipher), ev->u.ap_sta.auth, ev->assoc_req_len, - ev->assoc_info + ev->beacon_ie_len); + ev->assoc_info + ev->beacon_ie_len, + ev->u.ap_sta.apsd_info); } return 0; } @@ -819,8 +828,8 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len, if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 && pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) { /* WMM OUT (00:50:F2) */ - if (pie[1] > 5 - && pie[6] == WMM_PARAM_OUI_SUBTYPE) + if (pie[1] > 5 && + pie[6] == WMM_PARAM_OUI_SUBTYPE) wmi->is_wmm_enabled = true; } break; @@ -904,17 +913,17 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) regpair = ath6kl_get_regpair((u16) reg_code); country = ath6kl_regd_find_country_by_rd((u16) reg_code); ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", - regpair->regDmnEnum); + regpair->regDmnEnum); } - if (country) { + if (country && wmi->parent_dev->wiphy_registered) { alpha2[0] = country->isoName[0]; alpha2[1] = country->isoName[1]; regulatory_hint(wmi->parent_dev->wiphy, alpha2); ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n", - alpha2[0], alpha2[1]); + alpha2[0], alpha2[1]); } } @@ -1025,8 +1034,9 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, if (len < 8 + 2 + 2) return -EINVAL; - if (bih->frame_type == BEACON_FTYPE && test_bit(CONNECTED, &vif->flags) - && memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) { + if (bih->frame_type == BEACON_FTYPE && + test_bit(CONNECTED, &vif->flags) && + memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) { const u8 *tim; tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2, len - 8 - 2 - 2); @@ -1145,9 +1155,9 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len) return 0; } -static int ath6kl_wmi_tcmd_test_report_rx(struct wmi *wmi, u8 *datap, int len) +static int ath6kl_wmi_test_rx(struct wmi *wmi, u8 *datap, int len) { - ath6kl_tm_rx_report_event(wmi->parent_dev, datap, len); + ath6kl_tm_rx_event(wmi->parent_dev, datap, len); return 0; } @@ -1358,8 +1368,8 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap, /* Upper threshold breached */ if (rssi < sq_thresh->upper_threshold[0]) { ath6kl_dbg(ATH6KL_DBG_WMI, - "spurious upper rssi threshold event: %d\n", - rssi); + "spurious upper rssi threshold event: %d\n", + rssi); } else if ((rssi < sq_thresh->upper_threshold[1]) && (rssi >= sq_thresh->upper_threshold[0])) { new_threshold = WMI_RSSI_THRESHOLD1_ABOVE; @@ -1382,7 +1392,7 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap, /* Lower threshold breached */ if (rssi > sq_thresh->lower_threshold[0]) { ath6kl_dbg(ATH6KL_DBG_WMI, - "spurious lower rssi threshold event: %d %d\n", + "spurious lower rssi threshold event: %d %d\n", rssi, sq_thresh->lower_threshold[0]); } else if ((rssi > sq_thresh->lower_threshold[1]) && (rssi <= sq_thresh->lower_threshold[0])) { @@ -1543,8 +1553,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap, /* Upper threshold breached */ if (snr < sq_thresh->upper_threshold[0]) { ath6kl_dbg(ATH6KL_DBG_WMI, - "spurious upper snr threshold event: %d\n", - snr); + "spurious upper snr threshold event: %d\n", + snr); } else if ((snr < sq_thresh->upper_threshold[1]) && (snr >= sq_thresh->upper_threshold[0])) { new_threshold = WMI_SNR_THRESHOLD1_ABOVE; @@ -1561,8 +1571,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap, /* Lower threshold breached */ if (snr > sq_thresh->lower_threshold[0]) { ath6kl_dbg(ATH6KL_DBG_WMI, - "spurious lower snr threshold event: %d\n", - sq_thresh->lower_threshold[0]); + "spurious lower snr threshold event: %d\n", + sq_thresh->lower_threshold[0]); } else if ((snr > sq_thresh->lower_threshold[1]) && (snr <= sq_thresh->lower_threshold[0])) { new_threshold = WMI_SNR_THRESHOLD4_BELOW; @@ -2020,6 +2030,26 @@ int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx, return ret; } +int ath6kl_wmi_bmisstime_cmd(struct wmi *wmi, u8 if_idx, + u16 bmiss_time, u16 num_beacons) +{ + struct sk_buff *skb; + struct wmi_bmiss_time_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_bmiss_time_cmd *) skb->data; + cmd->bmiss_time = cpu_to_le16(bmiss_time); + cmd->num_beacons = cpu_to_le16(num_beacons); + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_BMISS_TIME_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode) { struct sk_buff *skb; @@ -2479,15 +2509,16 @@ int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 if_idx, u8 traffic_class, return ret; } -int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd) +int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx, + __be32 ips0, __be32 ips1) { struct sk_buff *skb; struct wmi_set_ip_cmd *cmd; int ret; /* Multicast address are not valid */ - if ((*((u8 *) &ip_cmd->ips[0]) >= 0xE0) || - (*((u8 *) &ip_cmd->ips[1]) >= 0xE0)) + if (ipv4_is_multicast(ips0) || + ipv4_is_multicast(ips1)) return -EINVAL; skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_ip_cmd)); @@ -2495,9 +2526,10 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd) return -ENOMEM; cmd = (struct wmi_set_ip_cmd *) skb->data; - memcpy(cmd, ip_cmd, sizeof(struct wmi_set_ip_cmd)); + cmd->ips[0] = ips0; + cmd->ips[1] = ips1; - ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_IP_CMDID, + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IP_CMDID, NO_SYNC_WMIFLAG); return ret; } @@ -2582,6 +2614,18 @@ int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx, return ret; } +/* This command has zero length payload */ +static int ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(struct wmi *wmi, + struct ath6kl_vif *vif) +{ + struct ath6kl *ar = wmi->parent_dev; + + set_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); + wake_up(&ar->event_wq); + + return 0; +} + int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, enum ath6kl_wow_mode wow_mode, u32 filter, u16 host_req_delay) @@ -2591,7 +2635,7 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, int ret; if ((wow_mode != ATH6KL_WOW_MODE_ENABLE) && - wow_mode != ATH6KL_WOW_MODE_DISABLE) { + wow_mode != ATH6KL_WOW_MODE_DISABLE) { ath6kl_err("invalid wow mode: %d\n", wow_mode); return -EINVAL; } @@ -2612,7 +2656,8 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, u8 list_id, u8 filter_size, - u8 filter_offset, u8 *filter, u8 *mask) + u8 filter_offset, const u8 *filter, + const u8 *mask) { struct sk_buff *skb; struct wmi_add_wow_pattern_cmd *cmd; @@ -2853,6 +2898,51 @@ int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len) return ret; } +int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on) +{ + struct sk_buff *skb; + struct wmi_mcast_filter_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_mcast_filter_cmd *) skb->data; + cmd->mcast_all_enable = mc_all_on; + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_MCAST_FILTER_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, + u8 *filter, bool add_filter) +{ + struct sk_buff *skb; + struct wmi_mcast_filter_add_del_cmd *cmd; + int ret; + + if ((filter[0] != 0x33 || filter[1] != 0x33) && + (filter[0] != 0x01 || filter[1] != 0x00 || + filter[2] != 0x5e || filter[3] > 0x7f)) { + ath6kl_warn("invalid multicast filter address\n"); + return -EINVAL; + } + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_mcast_filter_add_del_cmd *) skb->data; + memcpy(cmd->mcast_mac, filter, ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE); + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, + add_filter ? WMI_SET_MCAST_FILTER_CMDID : + WMI_DEL_MCAST_FILTER_CMDID, + NO_SYNC_WMIFLAG); + + return ret; +} s32 ath6kl_wmi_get_rate(s8 rate_index) { @@ -2946,6 +3036,59 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac, NO_SYNC_WMIFLAG); } +int ath6kl_wmi_ap_hidden_ssid(struct wmi *wmi, u8 if_idx, bool enable) +{ + struct sk_buff *skb; + struct wmi_ap_hidden_ssid_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_ap_hidden_ssid_cmd *) skb->data; + cmd->hidden_ssid = enable ? 1 : 0; + + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_HIDDEN_SSID_CMDID, + NO_SYNC_WMIFLAG); +} + +/* This command will be used to enable/disable AP uAPSD feature */ +int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable) +{ + struct wmi_ap_set_apsd_cmd *cmd; + struct sk_buff *skb; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_ap_set_apsd_cmd *)skb->data; + cmd->enable = enable; + + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_SET_APSD_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_set_apsd_bfrd_traf(struct wmi *wmi, u8 if_idx, + u16 aid, u16 bitmap, u32 flags) +{ + struct wmi_ap_apsd_buffered_traffic_cmd *cmd; + struct sk_buff *skb; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_ap_apsd_buffered_traffic_cmd *)skb->data; + cmd->aid = cpu_to_le16(aid); + cmd->bitmap = cpu_to_le16(bitmap); + cmd->flags = cpu_to_le32(flags); + + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID, + NO_SYNC_WMIFLAG); +} + static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len, struct ath6kl_vif *vif) { @@ -3078,8 +3221,9 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur) * ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P * mgmt operations using station interface. */ -int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, - u32 wait, const u8 *data, u16 data_len) +static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, + u32 freq, u32 wait, const u8 *data, + u16 data_len) { struct sk_buff *skb; struct wmi_send_action_cmd *p; @@ -3115,9 +3259,9 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, NO_SYNC_WMIFLAG); } -int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, - u32 wait, const u8 *data, u16 data_len, - u32 no_cck) +static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, + u32 freq, u32 wait, const u8 *data, + u16 data_len, u32 no_cck) { struct sk_buff *skb; struct wmi_send_mgmt_cmd *p; @@ -3154,6 +3298,32 @@ int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, NO_SYNC_WMIFLAG); } +int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, + u32 wait, const u8 *data, u16 data_len, + u32 no_cck) +{ + int status; + struct ath6kl *ar = wmi->parent_dev; + + if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, + ar->fw_capabilities)) { + /* + * If capable of doing P2P mgmt operations using + * station interface, send additional information like + * supported rates to advertise and xmit rates for + * probe requests + */ + status = __ath6kl_wmi_send_mgmt_cmd(ar->wmi, if_idx, id, freq, + wait, data, data_len, + no_cck); + } else { + status = ath6kl_wmi_send_action_cmd(ar->wmi, if_idx, id, freq, + wait, data, data_len); + } + + return status; +} + int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq, const u8 *dst, const u8 *data, u16 data_len) @@ -3265,32 +3435,101 @@ static int ath6kl_wmi_roam_tbl_event_rx(struct wmi *wmi, u8 *datap, int len) return ath6kl_debug_roam_tbl_event(wmi->parent_dev, datap, len); } -/* Control Path */ -int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) +/* Process interface specific wmi events, caller would free the datap */ +static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id, + u8 *datap, u32 len) { - struct wmi_cmd_hdr *cmd; struct ath6kl_vif *vif; - u32 len; - u16 id; - u8 if_idx; - u8 *datap; - int ret = 0; - if (WARN_ON(skb == NULL)) + vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx); + if (!vif) { + ath6kl_dbg(ATH6KL_DBG_WMI, + "Wmi event for unavailable vif, vif_index:%d\n", + if_idx); return -EINVAL; + } - if (skb->len < sizeof(struct wmi_cmd_hdr)) { - ath6kl_err("bad packet 1\n"); - dev_kfree_skb(skb); + switch (cmd_id) { + case WMI_CONNECT_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n"); + return ath6kl_wmi_connect_event_rx(wmi, datap, len, vif); + case WMI_DISCONNECT_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n"); + return ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif); + case WMI_TKIP_MICERR_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n"); + return ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif); + case WMI_BSSINFO_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n"); + return ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif); + case WMI_NEIGHBOR_REPORT_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n"); + return ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len, + vif); + case WMI_SCAN_COMPLETE_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n"); + return ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif); + case WMI_REPORT_STATISTICS_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n"); + return ath6kl_wmi_stats_event_rx(wmi, datap, len, vif); + case WMI_CAC_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n"); + return ath6kl_wmi_cac_event_rx(wmi, datap, len, vif); + case WMI_PSPOLL_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n"); + return ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif); + case WMI_DTIMEXPIRY_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n"); + return ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif); + case WMI_ADDBA_REQ_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n"); + return ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif); + case WMI_DELBA_REQ_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n"); + return ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif); + case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, + "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID"); + return ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif); + case WMI_REMAIN_ON_CHNL_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n"); + return ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif); + case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, + "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n"); + return ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap, + len, vif); + case WMI_TX_STATUS_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n"); + return ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif); + case WMI_RX_PROBE_REQ_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n"); + return ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif); + case WMI_RX_ACTION_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); + return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif); + default: + ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id); return -EINVAL; } + return 0; +} + +static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb) +{ + struct wmi_cmd_hdr *cmd; + int ret = 0; + u32 len; + u16 id; + u8 if_idx; + u8 *datap; + cmd = (struct wmi_cmd_hdr *) skb->data; id = le16_to_cpu(cmd->cmd_id); if_idx = le16_to_cpu(cmd->info1) & WMI_CMD_HDR_IF_ID_MASK; skb_pull(skb, sizeof(struct wmi_cmd_hdr)); - datap = skb->data; len = skb->len; @@ -3298,15 +3537,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ", datap, len); - vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx); - if (!vif) { - ath6kl_dbg(ATH6KL_DBG_WMI, - "Wmi event for unavailable vif, vif_index:%d\n", - if_idx); - dev_kfree_skb(skb); - return -EINVAL; - } - switch (id) { case WMI_GET_BITRATE_CMDID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n"); @@ -3324,26 +3554,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n"); ret = ath6kl_wmi_ready_event_rx(wmi, datap, len); break; - case WMI_CONNECT_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n"); - ret = ath6kl_wmi_connect_event_rx(wmi, datap, len, vif); - break; - case WMI_DISCONNECT_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n"); - ret = ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif); - break; case WMI_PEER_NODE_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n"); ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len); break; - case WMI_TKIP_MICERR_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n"); - ret = ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif); - break; - case WMI_BSSINFO_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n"); - ret = ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif); - break; case WMI_REGDOMAIN_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n"); ath6kl_wmi_regdomain_event(wmi, datap, len); @@ -3352,23 +3566,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n"); ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len); break; - case WMI_NEIGHBOR_REPORT_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n"); - ret = ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len, - vif); - break; - case WMI_SCAN_COMPLETE_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n"); - ret = ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif); - break; case WMI_CMDERROR_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n"); ret = ath6kl_wmi_error_event_rx(wmi, datap, len); break; - case WMI_REPORT_STATISTICS_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n"); - ret = ath6kl_wmi_stats_event_rx(wmi, datap, len, vif); - break; case WMI_RSSI_THRESHOLD_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n"); ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len); @@ -3388,10 +3589,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n"); ret = ath6kl_wmi_control_rx_xtnd(wmi, skb); break; - case WMI_CAC_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n"); - ret = ath6kl_wmi_cac_event_rx(wmi, datap, len, vif); - break; case WMI_CHANNEL_CHANGE_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n"); break; @@ -3400,7 +3597,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) break; case WMI_TEST_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TEST_EVENTID\n"); - ret = ath6kl_wmi_tcmd_test_report_rx(wmi, datap, len); + ret = ath6kl_wmi_test_rx(wmi, datap, len); break; case WMI_GET_FIXRATES_CMDID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n"); @@ -3431,28 +3628,12 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n"); ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len); break; - case WMI_PSPOLL_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n"); - ret = ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif); - break; - case WMI_DTIMEXPIRY_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n"); - ret = ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif); - break; case WMI_SET_PARAMS_REPLY_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n"); break; - case WMI_ADDBA_REQ_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n"); - ret = ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif); - break; case WMI_ADDBA_RESP_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n"); break; - case WMI_DELBA_REQ_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n"); - ret = ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif); - break; case WMI_REPORT_BTCOEX_CONFIG_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n"); @@ -3465,47 +3646,39 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n"); ret = ath6kl_wmi_tx_complete_event_rx(datap, len); break; - case WMI_REMAIN_ON_CHNL_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n"); - ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif); - break; - case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, - "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n"); - ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap, - len, vif); - break; - case WMI_TX_STATUS_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n"); - ret = ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif); - break; - case WMI_RX_PROBE_REQ_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n"); - ret = ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif); - break; case WMI_P2P_CAPABILITIES_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n"); ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len); break; - case WMI_RX_ACTION_EVENTID: - ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); - ret = ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif); - break; case WMI_P2P_INFO_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n"); ret = ath6kl_wmi_p2p_info_event_rx(datap, len); break; default: - ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id); - ret = -EINVAL; + /* may be the event is interface specific */ + ret = ath6kl_wmi_proc_events_vif(wmi, if_idx, id, datap, len); break; } dev_kfree_skb(skb); - return ret; } +/* Control Path */ +int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) +{ + if (WARN_ON(skb == NULL)) + return -EINVAL; + + if (skb->len < sizeof(struct wmi_cmd_hdr)) { + ath6kl_err("bad packet 1\n"); + dev_kfree_skb(skb); + return -EINVAL; + } + + return ath6kl_wmi_proc_events(wmi, skb); +} + void ath6kl_wmi_reset(struct wmi *wmi) { spin_lock_bh(&wmi->lock); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 42ac311eda4e..4092e3e80790 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1,5 +1,6 @@ /* * 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 @@ -110,6 +111,8 @@ struct wmi { u8 fat_pipe_exist; struct ath6kl *parent_dev; u8 pwr_mode; + + /* protects fat_pipe_exist and stream_exist_for_ac */ spinlock_t lock; enum htc_endpoint_id ep_id; struct sq_threshold_params @@ -149,8 +152,7 @@ enum wmi_msg_type { #define WMI_DATA_HDR_PS_MASK 0x1 #define WMI_DATA_HDR_PS_SHIFT 5 -#define WMI_DATA_HDR_MORE_MASK 0x1 -#define WMI_DATA_HDR_MORE_SHIFT 5 +#define WMI_DATA_HDR_MORE 0x20 enum wmi_data_hdr_data_type { WMI_DATA_HDR_DATA_TYPE_802_3 = 0, @@ -160,6 +162,13 @@ enum wmi_data_hdr_data_type { WMI_DATA_HDR_DATA_TYPE_ACL, }; +/* Bitmap of data header flags */ +enum wmi_data_hdr_flags { + WMI_DATA_HDR_FLAGS_MORE = 0x1, + WMI_DATA_HDR_FLAGS_EOSP = 0x2, + WMI_DATA_HDR_FLAGS_UAPSD = 0x4, +}; + #define WMI_DATA_HDR_DATA_TYPE_MASK 0x3 #define WMI_DATA_HDR_DATA_TYPE_SHIFT 6 @@ -173,8 +182,12 @@ enum wmi_data_hdr_data_type { #define WMI_DATA_HDR_META_MASK 0x7 #define WMI_DATA_HDR_META_SHIFT 13 +/* Macros for operating on WMI_DATA_HDR (info3) field */ #define WMI_DATA_HDR_IF_IDX_MASK 0xF +#define WMI_DATA_HDR_TRIG 0x10 +#define WMI_DATA_HDR_EOSP 0x10 + struct wmi_data_hdr { s8 rssi; @@ -203,7 +216,8 @@ struct wmi_data_hdr { /* * usage of info3, 16-bit: * b3:b0 - Interface index - * b15:b4 - Reserved + * b4 - uAPSD trigger in rx & EOSP in tx + * b15:b5 - Reserved */ __le16 info3; } __packed; @@ -257,6 +271,9 @@ static inline u8 wmi_data_hdr_get_if_idx(struct wmi_data_hdr *dhdr) #define WMI_META_VERSION_1 0x01 #define WMI_META_VERSION_2 0x02 +/* Flag to signal to FW to calculate TCP checksum */ +#define WMI_META_V2_FLAG_CSUM_OFFLOAD 0x01 + struct wmi_tx_meta_v1 { /* packet ID to identify the tx request */ u8 pkt_id; @@ -646,7 +663,6 @@ enum auth_mode { WPA2_AUTH_CCKM = 0x40, }; -#define WMI_MIN_KEY_INDEX 0 #define WMI_MAX_KEY_INDEX 3 #define WMI_MAX_KEY_LEN 32 @@ -984,6 +1000,12 @@ struct wmi_listen_int_cmd { __le16 num_beacons; } __packed; +/* WMI_SET_BMISS_TIME_CMDID */ +struct wmi_bmiss_time_cmd { + __le16 bmiss_time; + __le16 num_beacons; +}; + /* WMI_SET_POWER_MODE_CMDID */ enum wmi_power_mode { REC_POWER = 0x01, @@ -1001,7 +1023,7 @@ struct wmi_power_mode_cmd { */ enum power_save_fail_event_policy { SEND_POWER_SAVE_FAIL_EVENT_ALWAYS = 1, - IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN = 2, + IGNORE_PS_FAIL_DURING_SCAN = 2, }; struct wmi_power_params_cmd { @@ -1199,7 +1221,7 @@ struct wmi_snr_threshold_params_cmd { enum wmi_preamble_policy { WMI_IGNORE_BARKER_IN_ERP = 0, - WMI_DONOT_IGNORE_BARKER_IN_ERP + WMI_FOLLOW_BARKER_IN_ERP, }; struct wmi_set_lpreamble_cmd { @@ -1237,6 +1259,15 @@ enum target_event_report_config { NO_DISCONN_EVT_IN_RECONN }; +struct wmi_mcast_filter_cmd { + u8 mcast_all_enable; +} __packed; + +#define ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE 6 +struct wmi_mcast_filter_add_del_cmd { + u8 mcast_mac[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; +} __packed; + /* Command Replies */ /* WMI_GET_CHANNEL_LIST_CMDID reply */ @@ -1335,6 +1366,8 @@ enum wmi_event_id { WMI_P2P_START_SDPD_EVENTID, WMI_P2P_SDPD_RX_EVENTID, + WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID = 0x1047, + WMI_THIN_RESERVED_START_EVENTID = 0x8000, /* Events in this range are reserved for thinmode */ WMI_THIN_RESERVED_END_EVENTID = 0x8fff, @@ -1903,7 +1936,7 @@ struct wow_filter { struct wmi_set_ip_cmd { /* IP in network byte order */ - __le32 ips[MAX_IP_ADDRS]; + __be32 ips[MAX_IP_ADDRS]; } __packed; enum ath6kl_wow_filters { @@ -2104,7 +2137,24 @@ struct wmi_rx_frame_format_cmd { u8 reserved[1]; } __packed; +struct wmi_ap_hidden_ssid_cmd { + u8 hidden_ssid; +} __packed; + /* AP mode events */ +struct wmi_ap_set_apsd_cmd { + u8 enable; +} __packed; + +enum wmi_ap_apsd_buffered_traffic_flags { + WMI_AP_APSD_NO_DELIVERY_FRAMES = 0x1, +}; + +struct wmi_ap_apsd_buffered_traffic_cmd { + __le16 aid; + __le16 bitmap; + __le32 flags; +} __packed; /* WMI_PS_POLL_EVENT */ struct wmi_pspoll_event { @@ -2321,7 +2371,7 @@ enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi); void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id); int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb); int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, - u8 msg_type, bool more_data, + u8 msg_type, u32 flags, enum wmi_data_hdr_data_type data_type, u8 meta_ver, void *tx_meta_info, u8 if_idx); @@ -2376,6 +2426,8 @@ int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag, int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx, u16 listen_interval, u16 listen_beacons); +int ath6kl_wmi_bmisstime_cmd(struct wmi *wmi, u8 if_idx, + u16 bmiss_time, u16 num_beacons); int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode); int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u8 if_idx, u16 idle_period, u16 ps_poll_num, u16 dtim_policy, @@ -2417,7 +2469,8 @@ int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len); s32 ath6kl_wmi_get_rate(s8 rate_index); -int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd); +int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx, + __be32 ips0, __be32 ips1); int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx, enum ath6kl_host_mode host_mode); int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, @@ -2425,14 +2478,28 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, u32 filter, u16 host_req_delay); int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, u8 list_id, u8 filter_size, - u8 filter_offset, u8 *filter, u8 *mask); + u8 filter_offset, const u8 *filter, + const u8 *mask); int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, u16 list_id, u16 filter_id); int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode); +int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); +int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, + u8 *filter, bool add_filter); +/* AP mode uAPSD */ +int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable); +int ath6kl_wmi_set_apsd_bfrd_traf(struct wmi *wmi, + u8 if_idx, u16 aid, + u16 bitmap, u32 flags); + +u8 ath6kl_wmi_get_traffic_class(u8 user_priority); + +u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri); /* AP mode */ +int ath6kl_wmi_ap_hidden_ssid(struct wmi *wmi, u8 if_idx, bool enable); int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx, struct wmi_connect_cmd *p); @@ -2454,9 +2521,6 @@ int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur); -int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, - u32 wait, const u8 *data, u16 data_len); - int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, u32 wait, const u8 *data, u16 data_len, u32 no_cck); diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index dc6be4afe8eb..e507e78398f3 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -6,6 +6,14 @@ config ATH9K_DFS_DEBUGFS def_bool y depends on ATH9K_DEBUGFS && ATH9K_DFS_CERTIFIED +config ATH9K_BTCOEX_SUPPORT + bool "Atheros bluetooth coexistence support" + depends on (ATH9K || ATH9K_HTC) + default y + ---help--- + Say Y, if you want to use the ath9k/ath9k_htc radios together with + Bluetooth modules in the same system. + config ATH9K tristate "Atheros 802.11n wireless cards support" depends on MAC80211 @@ -73,6 +81,14 @@ config ATH9K_DFS_CERTIFIED developed. At this point enabling this option won't do anything except increase code size. +config ATH9K_MAC_DEBUG + bool "Atheros MAC statistics" + depends on ATH9K_DEBUGFS + default y + ---help--- + This option enables collection of statistics for Rx/Tx status + data and some other MAC related statistics + config ATH9K_RATE_CONTROL bool "Atheros ath9k rate control" depends on ATH9K @@ -81,14 +97,6 @@ config ATH9K_RATE_CONTROL Say Y, if you want to use the ath9k specific rate control module instead of minstrel_ht. -config ATH9K_BTCOEX_SUPPORT - bool "Atheros ath9k bluetooth coexistence support" - depends on ATH9K - default y - ---help--- - Say Y, if you want to use the ath9k radios together with - Bluetooth modules in the same system. - config ATH9K_HTC tristate "Atheros HTC based wireless cards support" depends on USB && MAC80211 diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index da02242499af..27d95fe5ade0 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -3,9 +3,9 @@ ath9k-y += beacon.o \ init.o \ main.o \ recv.o \ - xmit.o \ - mci.o \ + xmit.o +ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o ath9k-$(CONFIG_ATH9K_PCI) += pci.o ath9k-$(CONFIG_ATH9K_AHB) += ahb.o @@ -31,14 +31,14 @@ ath9k_hw-y:= \ eeprom_4k.o \ eeprom_9287.o \ ani.o \ - btcoex.o \ mac.o \ ar9002_mac.o \ ar9003_mac.o \ ar9003_eeprom.o \ - ar9003_paprd.o \ - ar9003_mci.o + ar9003_paprd.o +ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \ + ar9003_mci.o obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index bc56f57b393b..7e0ea4e98334 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -407,20 +407,20 @@ static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah) if (aniState->ofdmWeakSigDetectOff) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - true) == true) + true)) return; } if (aniState->firstepLevel > 0) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1) == true) + aniState->firstepLevel - 1)) return; } } else { if (aniState->firstepLevel > 0) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1) == true) + aniState->firstepLevel - 1)) return; } } diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 86a891f93fc9..d7d8e9199140 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -834,9 +834,10 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, AR_SREV_9287_11_OR_LATER(ah)) REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); - if (AR_SREV_9271_10(ah)) - REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only, - modesIndex, regWrites); + if (AR_SREV_9271_10(ah)) { + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENA); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_ADC_ON, 0xa); + } ENABLE_REGWRITE_BUFFER(ah); @@ -858,21 +859,11 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, REGWRITE_BUFFER_FLUSH(ah); - if (AR_SREV_9271(ah)) { - if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 1) - REG_WRITE_ARRAY(&ah->iniModes_high_power_tx_gain_9271, - modesIndex, regWrites); - else - REG_WRITE_ARRAY(&ah->iniModes_normal_power_tx_gain_9271, - modesIndex, regWrites); - } - REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites); - if (IS_CHAN_A_FAST_CLOCK(ah, chan)) { - REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, + if (IS_CHAN_A_FAST_CLOCK(ah, chan)) + REG_WRITE_ARRAY(&ah->iniModesFastClock, modesIndex, regWrites); - } ar5008_hw_override_ini(ah, chan); ar5008_hw_set_channel_regs(ah, chan); diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h index e8bdc75405f1..ea4a230997ac 100644 --- a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h @@ -459,97 +459,6 @@ static const u32 ar5416Common_9100[][2] = { {0x0000a3e0, 0x000001ce}, }; -static const u32 ar5416Bank0_9100[][2] = { - /* Addr allmodes */ - {0x000098b0, 0x1e5795e5}, - {0x000098e0, 0x02008020}, -}; - -static const u32 ar5416BB_RfGain_9100[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x00009a00, 0x00000000, 0x00000000}, - {0x00009a04, 0x00000040, 0x00000040}, - {0x00009a08, 0x00000080, 0x00000080}, - {0x00009a0c, 0x000001a1, 0x00000141}, - {0x00009a10, 0x000001e1, 0x00000181}, - {0x00009a14, 0x00000021, 0x000001c1}, - {0x00009a18, 0x00000061, 0x00000001}, - {0x00009a1c, 0x00000168, 0x00000041}, - {0x00009a20, 0x000001a8, 0x000001a8}, - {0x00009a24, 0x000001e8, 0x000001e8}, - {0x00009a28, 0x00000028, 0x00000028}, - {0x00009a2c, 0x00000068, 0x00000068}, - {0x00009a30, 0x00000189, 0x000000a8}, - {0x00009a34, 0x000001c9, 0x00000169}, - {0x00009a38, 0x00000009, 0x000001a9}, - {0x00009a3c, 0x00000049, 0x000001e9}, - {0x00009a40, 0x00000089, 0x00000029}, - {0x00009a44, 0x00000170, 0x00000069}, - {0x00009a48, 0x000001b0, 0x00000190}, - {0x00009a4c, 0x000001f0, 0x000001d0}, - {0x00009a50, 0x00000030, 0x00000010}, - {0x00009a54, 0x00000070, 0x00000050}, - {0x00009a58, 0x00000191, 0x00000090}, - {0x00009a5c, 0x000001d1, 0x00000151}, - {0x00009a60, 0x00000011, 0x00000191}, - {0x00009a64, 0x00000051, 0x000001d1}, - {0x00009a68, 0x00000091, 0x00000011}, - {0x00009a6c, 0x000001b8, 0x00000051}, - {0x00009a70, 0x000001f8, 0x00000198}, - {0x00009a74, 0x00000038, 0x000001d8}, - {0x00009a78, 0x00000078, 0x00000018}, - {0x00009a7c, 0x00000199, 0x00000058}, - {0x00009a80, 0x000001d9, 0x00000098}, - {0x00009a84, 0x00000019, 0x00000159}, - {0x00009a88, 0x00000059, 0x00000199}, - {0x00009a8c, 0x00000099, 0x000001d9}, - {0x00009a90, 0x000000d9, 0x00000019}, - {0x00009a94, 0x000000f9, 0x00000059}, - {0x00009a98, 0x000000f9, 0x00000099}, - {0x00009a9c, 0x000000f9, 0x000000d9}, - {0x00009aa0, 0x000000f9, 0x000000f9}, - {0x00009aa4, 0x000000f9, 0x000000f9}, - {0x00009aa8, 0x000000f9, 0x000000f9}, - {0x00009aac, 0x000000f9, 0x000000f9}, - {0x00009ab0, 0x000000f9, 0x000000f9}, - {0x00009ab4, 0x000000f9, 0x000000f9}, - {0x00009ab8, 0x000000f9, 0x000000f9}, - {0x00009abc, 0x000000f9, 0x000000f9}, - {0x00009ac0, 0x000000f9, 0x000000f9}, - {0x00009ac4, 0x000000f9, 0x000000f9}, - {0x00009ac8, 0x000000f9, 0x000000f9}, - {0x00009acc, 0x000000f9, 0x000000f9}, - {0x00009ad0, 0x000000f9, 0x000000f9}, - {0x00009ad4, 0x000000f9, 0x000000f9}, - {0x00009ad8, 0x000000f9, 0x000000f9}, - {0x00009adc, 0x000000f9, 0x000000f9}, - {0x00009ae0, 0x000000f9, 0x000000f9}, - {0x00009ae4, 0x000000f9, 0x000000f9}, - {0x00009ae8, 0x000000f9, 0x000000f9}, - {0x00009aec, 0x000000f9, 0x000000f9}, - {0x00009af0, 0x000000f9, 0x000000f9}, - {0x00009af4, 0x000000f9, 0x000000f9}, - {0x00009af8, 0x000000f9, 0x000000f9}, - {0x00009afc, 0x000000f9, 0x000000f9}, -}; - -static const u32 ar5416Bank1_9100[][2] = { - /* Addr allmodes */ - {0x000098b0, 0x02108421}, - {0x000098ec, 0x00000008}, -}; - -static const u32 ar5416Bank2_9100[][2] = { - /* Addr allmodes */ - {0x000098b0, 0x0e73ff17}, - {0x000098e0, 0x00000420}, -}; - -static const u32 ar5416Bank3_9100[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x000098f0, 0x01400018, 0x01c00018}, -}; - static const u32 ar5416Bank6_9100[][3] = { /* Addr 5G_HT20 5G_HT40 */ {0x0000989c, 0x00000000, 0x00000000}, @@ -624,13 +533,6 @@ static const u32 ar5416Bank6TPC_9100[][3] = { {0x000098d0, 0x0000000f, 0x0010000f}, }; -static const u32 ar5416Bank7_9100[][2] = { - /* Addr allmodes */ - {0x0000989c, 0x00000500}, - {0x0000989c, 0x00000800}, - {0x000098cc, 0x0000000e}, -}; - static const u32 ar5416Addac_9100[][2] = { /* Addr allmodes */ {0x0000989c, 0x00000000}, @@ -1113,178 +1015,6 @@ static const u32 ar5416Common_9160[][2] = { {0x0000a3e0, 0x000001ce}, }; -static const u32 ar5416Bank0_9160[][2] = { - /* Addr allmodes */ - {0x000098b0, 0x1e5795e5}, - {0x000098e0, 0x02008020}, -}; - -static const u32 ar5416BB_RfGain_9160[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x00009a00, 0x00000000, 0x00000000}, - {0x00009a04, 0x00000040, 0x00000040}, - {0x00009a08, 0x00000080, 0x00000080}, - {0x00009a0c, 0x000001a1, 0x00000141}, - {0x00009a10, 0x000001e1, 0x00000181}, - {0x00009a14, 0x00000021, 0x000001c1}, - {0x00009a18, 0x00000061, 0x00000001}, - {0x00009a1c, 0x00000168, 0x00000041}, - {0x00009a20, 0x000001a8, 0x000001a8}, - {0x00009a24, 0x000001e8, 0x000001e8}, - {0x00009a28, 0x00000028, 0x00000028}, - {0x00009a2c, 0x00000068, 0x00000068}, - {0x00009a30, 0x00000189, 0x000000a8}, - {0x00009a34, 0x000001c9, 0x00000169}, - {0x00009a38, 0x00000009, 0x000001a9}, - {0x00009a3c, 0x00000049, 0x000001e9}, - {0x00009a40, 0x00000089, 0x00000029}, - {0x00009a44, 0x00000170, 0x00000069}, - {0x00009a48, 0x000001b0, 0x00000190}, - {0x00009a4c, 0x000001f0, 0x000001d0}, - {0x00009a50, 0x00000030, 0x00000010}, - {0x00009a54, 0x00000070, 0x00000050}, - {0x00009a58, 0x00000191, 0x00000090}, - {0x00009a5c, 0x000001d1, 0x00000151}, - {0x00009a60, 0x00000011, 0x00000191}, - {0x00009a64, 0x00000051, 0x000001d1}, - {0x00009a68, 0x00000091, 0x00000011}, - {0x00009a6c, 0x000001b8, 0x00000051}, - {0x00009a70, 0x000001f8, 0x00000198}, - {0x00009a74, 0x00000038, 0x000001d8}, - {0x00009a78, 0x00000078, 0x00000018}, - {0x00009a7c, 0x00000199, 0x00000058}, - {0x00009a80, 0x000001d9, 0x00000098}, - {0x00009a84, 0x00000019, 0x00000159}, - {0x00009a88, 0x00000059, 0x00000199}, - {0x00009a8c, 0x00000099, 0x000001d9}, - {0x00009a90, 0x000000d9, 0x00000019}, - {0x00009a94, 0x000000f9, 0x00000059}, - {0x00009a98, 0x000000f9, 0x00000099}, - {0x00009a9c, 0x000000f9, 0x000000d9}, - {0x00009aa0, 0x000000f9, 0x000000f9}, - {0x00009aa4, 0x000000f9, 0x000000f9}, - {0x00009aa8, 0x000000f9, 0x000000f9}, - {0x00009aac, 0x000000f9, 0x000000f9}, - {0x00009ab0, 0x000000f9, 0x000000f9}, - {0x00009ab4, 0x000000f9, 0x000000f9}, - {0x00009ab8, 0x000000f9, 0x000000f9}, - {0x00009abc, 0x000000f9, 0x000000f9}, - {0x00009ac0, 0x000000f9, 0x000000f9}, - {0x00009ac4, 0x000000f9, 0x000000f9}, - {0x00009ac8, 0x000000f9, 0x000000f9}, - {0x00009acc, 0x000000f9, 0x000000f9}, - {0x00009ad0, 0x000000f9, 0x000000f9}, - {0x00009ad4, 0x000000f9, 0x000000f9}, - {0x00009ad8, 0x000000f9, 0x000000f9}, - {0x00009adc, 0x000000f9, 0x000000f9}, - {0x00009ae0, 0x000000f9, 0x000000f9}, - {0x00009ae4, 0x000000f9, 0x000000f9}, - {0x00009ae8, 0x000000f9, 0x000000f9}, - {0x00009aec, 0x000000f9, 0x000000f9}, - {0x00009af0, 0x000000f9, 0x000000f9}, - {0x00009af4, 0x000000f9, 0x000000f9}, - {0x00009af8, 0x000000f9, 0x000000f9}, - {0x00009afc, 0x000000f9, 0x000000f9}, -}; - -static const u32 ar5416Bank1_9160[][2] = { - /* Addr allmodes */ - {0x000098b0, 0x02108421}, - {0x000098ec, 0x00000008}, -}; - -static const u32 ar5416Bank2_9160[][2] = { - /* Addr allmodes */ - {0x000098b0, 0x0e73ff17}, - {0x000098e0, 0x00000420}, -}; - -static const u32 ar5416Bank3_9160[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x000098f0, 0x01400018, 0x01c00018}, -}; - -static const u32 ar5416Bank6_9160[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x0000989c, 0x00000000, 0x00000000}, - {0x0000989c, 0x00000000, 0x00000000}, - {0x0000989c, 0x00000000, 0x00000000}, - {0x0000989c, 0x00e00000, 0x00e00000}, - {0x0000989c, 0x005e0000, 0x005e0000}, - {0x0000989c, 0x00120000, 0x00120000}, - {0x0000989c, 0x00620000, 0x00620000}, - {0x0000989c, 0x00020000, 0x00020000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x40ff0000, 0x40ff0000}, - {0x0000989c, 0x005f0000, 0x005f0000}, - {0x0000989c, 0x00870000, 0x00870000}, - {0x0000989c, 0x00f90000, 0x00f90000}, - {0x0000989c, 0x007b0000, 0x007b0000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x00f50000, 0x00f50000}, - {0x0000989c, 0x00dc0000, 0x00dc0000}, - {0x0000989c, 0x00110000, 0x00110000}, - {0x0000989c, 0x006100a8, 0x006100a8}, - {0x0000989c, 0x004210a2, 0x004210a2}, - {0x0000989c, 0x0014008f, 0x0014008f}, - {0x0000989c, 0x00c40003, 0x00c40003}, - {0x0000989c, 0x003000f2, 0x003000f2}, - {0x0000989c, 0x00440016, 0x00440016}, - {0x0000989c, 0x00410040, 0x00410040}, - {0x0000989c, 0x0001805e, 0x0001805e}, - {0x0000989c, 0x0000c0ab, 0x0000c0ab}, - {0x0000989c, 0x000000f1, 0x000000f1}, - {0x0000989c, 0x00002081, 0x00002081}, - {0x0000989c, 0x000000d4, 0x000000d4}, - {0x000098d0, 0x0000000f, 0x0010000f}, -}; - -static const u32 ar5416Bank6TPC_9160[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x0000989c, 0x00000000, 0x00000000}, - {0x0000989c, 0x00000000, 0x00000000}, - {0x0000989c, 0x00000000, 0x00000000}, - {0x0000989c, 0x00e00000, 0x00e00000}, - {0x0000989c, 0x005e0000, 0x005e0000}, - {0x0000989c, 0x00120000, 0x00120000}, - {0x0000989c, 0x00620000, 0x00620000}, - {0x0000989c, 0x00020000, 0x00020000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x40ff0000, 0x40ff0000}, - {0x0000989c, 0x005f0000, 0x005f0000}, - {0x0000989c, 0x00870000, 0x00870000}, - {0x0000989c, 0x00f90000, 0x00f90000}, - {0x0000989c, 0x007b0000, 0x007b0000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x00f50000, 0x00f50000}, - {0x0000989c, 0x00dc0000, 0x00dc0000}, - {0x0000989c, 0x00110000, 0x00110000}, - {0x0000989c, 0x006100a8, 0x006100a8}, - {0x0000989c, 0x00423022, 0x00423022}, - {0x0000989c, 0x2014008f, 0x2014008f}, - {0x0000989c, 0x00c40002, 0x00c40002}, - {0x0000989c, 0x003000f2, 0x003000f2}, - {0x0000989c, 0x00440016, 0x00440016}, - {0x0000989c, 0x00410040, 0x00410040}, - {0x0000989c, 0x0001805e, 0x0001805e}, - {0x0000989c, 0x0000c0ab, 0x0000c0ab}, - {0x0000989c, 0x000000e1, 0x000000e1}, - {0x0000989c, 0x00007080, 0x00007080}, - {0x0000989c, 0x000000d4, 0x000000d4}, - {0x000098d0, 0x0000000f, 0x0010000f}, -}; - -static const u32 ar5416Bank7_9160[][2] = { - /* Addr allmodes */ - {0x0000989c, 0x00000500}, - {0x0000989c, 0x00000800}, - {0x000098cc, 0x0000000e}, -}; - static const u32 ar5416Addac_9160[][2] = { /* Addr allmodes */ {0x0000989c, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index d190411ac8f5..d9a69fc470cd 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -34,74 +34,37 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar9271Modes_9271), 5); INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271, ARRAY_SIZE(ar9271Common_9271), 2); - INIT_INI_ARRAY(&ah->iniCommon_normal_cck_fir_coeff_9271, - ar9271Common_normal_cck_fir_coeff_9271, - ARRAY_SIZE(ar9271Common_normal_cck_fir_coeff_9271), 2); - INIT_INI_ARRAY(&ah->iniCommon_japan_2484_cck_fir_coeff_9271, - ar9271Common_japan_2484_cck_fir_coeff_9271, - ARRAY_SIZE(ar9271Common_japan_2484_cck_fir_coeff_9271), 2); - INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only, - ar9271Modes_9271_1_0_only, - ARRAY_SIZE(ar9271Modes_9271_1_0_only), 5); INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg, ARRAY_SIZE(ar9271Modes_9271_ANI_reg), 5); - INIT_INI_ARRAY(&ah->iniModes_high_power_tx_gain_9271, - ar9271Modes_high_power_tx_gain_9271, - ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 5); - INIT_INI_ARRAY(&ah->iniModes_normal_power_tx_gain_9271, - ar9271Modes_normal_power_tx_gain_9271, - ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 5); return; } + if (ah->config.pcie_clock_req) + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9280PciePhy_clkreq_off_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280), 2); + else + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9280PciePhy_clkreq_always_on_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2); + if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1, ARRAY_SIZE(ar9287Modes_9287_1_1), 5); INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1, ARRAY_SIZE(ar9287Common_9287_1_1), 2); - if (ah->config.pcie_clock_req) - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9287PciePhy_clkreq_off_L1_9287_1_1, - ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2); - else - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9287PciePhy_clkreq_always_on_L1_9287_1_1, - ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1), - 2); } else if (AR_SREV_9285_12_OR_LATER(ah)) { - - INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, ARRAY_SIZE(ar9285Modes_9285_1_2), 5); INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2, ARRAY_SIZE(ar9285Common_9285_1_2), 2); - - if (ah->config.pcie_clock_req) { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9285PciePhy_clkreq_off_L1_9285_1_2, - ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2); - } else { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9285PciePhy_clkreq_always_on_L1_9285_1_2, - ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2), - 2); - } } else if (AR_SREV_9280_20_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2, ARRAY_SIZE(ar9280Modes_9280_2), 5); INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2, ARRAY_SIZE(ar9280Common_9280_2), 2); - if (ah->config.pcie_clock_req) { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9280PciePhy_clkreq_off_L1_9280, - ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280), 2); - } else { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9280PciePhy_clkreq_always_on_L1_9280, - ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2); - } - INIT_INI_ARRAY(&ah->iniModesAdditional, + INIT_INI_ARRAY(&ah->iniModesFastClock, ar9280Modes_fast_clock_9280_2, ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3); } else if (AR_SREV_9160_10_OR_LATER(ah)) { @@ -109,22 +72,6 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar5416Modes_9160), 5); INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160, ARRAY_SIZE(ar5416Common_9160), 2); - INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160, - ARRAY_SIZE(ar5416Bank0_9160), 2); - INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160, - ARRAY_SIZE(ar5416BB_RfGain_9160), 3); - INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160, - ARRAY_SIZE(ar5416Bank1_9160), 2); - INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160, - ARRAY_SIZE(ar5416Bank2_9160), 2); - INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160, - ARRAY_SIZE(ar5416Bank3_9160), 3); - INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160, - ARRAY_SIZE(ar5416Bank6_9160), 3); - INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160, - ARRAY_SIZE(ar5416Bank6TPC_9160), 3); - INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160, - ARRAY_SIZE(ar5416Bank7_9160), 2); if (AR_SREV_9160_11(ah)) { INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160_1_1, @@ -138,22 +85,8 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar5416Modes_9100), 5); INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100, ARRAY_SIZE(ar5416Common_9100), 2); - INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100, - ARRAY_SIZE(ar5416Bank0_9100), 2); - INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100, - ARRAY_SIZE(ar5416BB_RfGain_9100), 3); - INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100, - ARRAY_SIZE(ar5416Bank1_9100), 2); - INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100, - ARRAY_SIZE(ar5416Bank2_9100), 2); - INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100, - ARRAY_SIZE(ar5416Bank3_9100), 3); INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100, ARRAY_SIZE(ar5416Bank6_9100), 3); - INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100, - ARRAY_SIZE(ar5416Bank6TPC_9100), 3); - INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100, - ARRAY_SIZE(ar5416Bank7_9100), 2); INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100, ARRAY_SIZE(ar5416Addac_9100), 2); } else { @@ -161,24 +94,37 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar5416Modes), 5); INIT_INI_ARRAY(&ah->iniCommon, ar5416Common, ARRAY_SIZE(ar5416Common), 2); - INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0, - ARRAY_SIZE(ar5416Bank0), 2); + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC, + ARRAY_SIZE(ar5416Bank6TPC), 3); + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac, + ARRAY_SIZE(ar5416Addac), 2); + } + + if (!AR_SREV_9280_20_OR_LATER(ah)) { + /* Common for AR5416, AR913x, AR9160 */ INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain, ARRAY_SIZE(ar5416BB_RfGain), 3); + + INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0, + ARRAY_SIZE(ar5416Bank0), 2); INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1, ARRAY_SIZE(ar5416Bank1), 2); INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2, ARRAY_SIZE(ar5416Bank2), 2); INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3, ARRAY_SIZE(ar5416Bank3), 3); - INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6, - ARRAY_SIZE(ar5416Bank6), 3); - INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC, - ARRAY_SIZE(ar5416Bank6TPC), 3); INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7, ARRAY_SIZE(ar5416Bank7), 2); - INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac, - ARRAY_SIZE(ar5416Addac), 2); + + /* Common for AR5416, AR9160 */ + if (!AR_SREV_9100(ah)) + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6, + ARRAY_SIZE(ar5416Bank6), 3); + + /* Common for AR913x, AR9160 */ + if (!AR_SREV_5416(ah)) + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100, + ARRAY_SIZE(ar5416Bank6TPC_9100), 3); } /* iniAddac needs to be modified for these chips */ @@ -199,11 +145,6 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) INI_RA(addac, 31,1) = 0; } } -} - -/* Support for Japan ch.14 (2484) spread */ -void ar9002_hw_cck_chan14_spread(struct ath_hw *ah) -{ if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniCckfirNormal, ar9287Common_normal_cck_fir_coeff_9287_1_1, @@ -243,14 +184,10 @@ static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah) } } -static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah) +static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type) { - u32 txgain_type; - if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) { - txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); - if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9280Modes_high_power_tx_gain_9280_2, @@ -266,8 +203,22 @@ static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah) } } +static void ar9271_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type) +{ + if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9271Modes_high_power_tx_gain_9271, + ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 5); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9271Modes_normal_power_tx_gain_9271, + ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 5); +} + static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) { + u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); + if (AR_SREV_9287_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9287Modes_rx_gain_9287_1_1, @@ -275,15 +226,15 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) else if (AR_SREV_9280_20(ah)) ar9280_20_hw_init_rxgain_ini(ah); - if (AR_SREV_9287_11_OR_LATER(ah)) { + if (AR_SREV_9271(ah)) { + ar9271_hw_init_txgain_ini(ah, txgain_type); + } else if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModesTxGain, ar9287Modes_tx_gain_9287_1_1, ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 5); } else if (AR_SREV_9280_20(ah)) { - ar9280_20_hw_init_txgain_ini(ah); + ar9280_20_hw_init_txgain_ini(ah, txgain_type); } else if (AR_SREV_9285_12_OR_LATER(ah)) { - u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); - /* txgain table */ if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) { if (AR_SREV_9285E_20(ah)) { diff --git a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h index 863db321070d..4d18c66a6790 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h @@ -925,34 +925,6 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { {0x00004044, 0x00000000}, }; -static const u32 ar9285PciePhy_clkreq_always_on_L1_9285[][2] = { - /* Addr allmodes */ - {0x00004040, 0x9248fd00}, - {0x00004040, 0x24924924}, - {0x00004040, 0xa8000019}, - {0x00004040, 0x13160820}, - {0x00004040, 0xe5980560}, - {0x00004040, 0xc01dcffd}, - {0x00004040, 0x1aaabe41}, - {0x00004040, 0xbe105554}, - {0x00004040, 0x00043007}, - {0x00004044, 0x00000000}, -}; - -static const u32 ar9285PciePhy_clkreq_off_L1_9285[][2] = { - /* Addr allmodes */ - {0x00004040, 0x9248fd00}, - {0x00004040, 0x24924924}, - {0x00004040, 0xa8000019}, - {0x00004040, 0x13160820}, - {0x00004040, 0xe5980560}, - {0x00004040, 0xc01dcffc}, - {0x00004040, 0x1aaabe41}, - {0x00004040, 0xbe105554}, - {0x00004040, 0x00043007}, - {0x00004044, 0x00000000}, -}; - static const u32 ar9285Modes_9285_1_2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, @@ -1743,34 +1715,6 @@ static const u32 ar9285Modes_XE2_0_high_power[][5] = { {0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7}, }; -static const u32 ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = { - /* Addr allmodes */ - {0x00004040, 0x9248fd00}, - {0x00004040, 0x24924924}, - {0x00004040, 0xa8000019}, - {0x00004040, 0x13160820}, - {0x00004040, 0xe5980560}, - {0x00004040, 0xc01dcffd}, - {0x00004040, 0x1aaabe41}, - {0x00004040, 0xbe105554}, - {0x00004040, 0x00043007}, - {0x00004044, 0x00000000}, -}; - -static const u32 ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = { - /* Addr allmodes */ - {0x00004040, 0x9248fd00}, - {0x00004040, 0x24924924}, - {0x00004040, 0xa8000019}, - {0x00004040, 0x13160820}, - {0x00004040, 0xe5980560}, - {0x00004040, 0xc01dcffc}, - {0x00004040, 0x1aaabe41}, - {0x00004040, 0xbe105554}, - {0x00004040, 0x00043007}, - {0x00004044, 0x00000000}, -}; - static const u32 ar9287Modes_9287_1_1[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160}, @@ -2512,34 +2456,6 @@ static const u32 ar9287Modes_rx_gain_9287_1_1[][5] = { {0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067}, }; -static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = { - /* Addr allmodes */ - {0x00004040, 0x9248fd00}, - {0x00004040, 0x24924924}, - {0x00004040, 0xa8000019}, - {0x00004040, 0x13160820}, - {0x00004040, 0xe5980560}, - {0x00004040, 0xc01dcffd}, - {0x00004040, 0x1aaabe41}, - {0x00004040, 0xbe105554}, - {0x00004040, 0x00043007}, - {0x00004044, 0x00000000}, -}; - -static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = { - /* Addr allmodes */ - {0x00004040, 0x9248fd00}, - {0x00004040, 0x24924924}, - {0x00004040, 0xa8000019}, - {0x00004040, 0x13160820}, - {0x00004040, 0xe5980560}, - {0x00004040, 0xc01dcffc}, - {0x00004040, 0x1aaabe41}, - {0x00004040, 0xbe105554}, - {0x00004040, 0x00043007}, - {0x00004044, 0x00000000}, -}; - static const u32 ar9271Modes_9271[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, @@ -3176,26 +3092,6 @@ static const u32 ar9271Common_9271[][2] = { {0x0000d384, 0xf3307ff0}, }; -static const u32 ar9271Common_normal_cck_fir_coeff_9271[][2] = { - /* Addr allmodes */ - {0x0000a1f4, 0x00fffeff}, - {0x0000a1f8, 0x00f5f9ff}, - {0x0000a1fc, 0xb79f6427}, -}; - -static const u32 ar9271Common_japan_2484_cck_fir_coeff_9271[][2] = { - /* Addr allmodes */ - {0x0000a1f4, 0x00000000}, - {0x0000a1f8, 0xefff0301}, - {0x0000a1fc, 0xca9228ee}, -}; - -static const u32 ar9271Modes_9271_1_0_only[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311}, - {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, -}; - static const u32 ar9271Modes_9271_ANI_reg[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2}, diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 7b6417b5212e..aa2abaf31cba 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -347,15 +347,12 @@ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags) { struct ar5416_desc *ads = AR5416DESC(ds); - struct ath9k_hw_capabilities *pCap = &ah->caps; ads->ds_ctl1 = size & AR_BufLen; if (flags & ATH9K_RXDESC_INTREQ) ads->ds_ctl1 |= AR_RxIntrReq; - ads->ds_rxstatus8 &= ~AR_RxDone; - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) - memset(&(ads->u), 0, sizeof(ads->u)); + memset(&ads->u.rx, 0, sizeof(ads->u.rx)); } EXPORT_SYMBOL(ath9k_hw_setuprxdesc); diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h index 453af6dc514b..f9eb2c357169 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h @@ -60,6 +60,8 @@ #define AR_PHY_RF_CTL3 0x9828 #define AR_PHY_TX_END_TO_A2_RX_ON 0x00FF0000 #define AR_PHY_TX_END_TO_A2_RX_ON_S 16 +#define AR_PHY_TX_END_TO_ADC_ON 0xFF000000 +#define AR_PHY_TX_END_TO_ADC_ON_S 24 #define AR_PHY_ADC_CTL 0x982C #define AR_PHY_ADC_CTL_OFF_INBUFGAIN 0x00000003 diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 026f9de15d15..46c79a3d4737 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -295,266 +295,6 @@ static const u32 ar9300_2p2_radio_core[][2] = { {0x00016bd4, 0x00000000}, }; -static const u32 ar9300Common_rx_gain_table_merlin_2p2[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x02000101}, - {0x0000a004, 0x02000102}, - {0x0000a008, 0x02000103}, - {0x0000a00c, 0x02000104}, - {0x0000a010, 0x02000200}, - {0x0000a014, 0x02000201}, - {0x0000a018, 0x02000202}, - {0x0000a01c, 0x02000203}, - {0x0000a020, 0x02000204}, - {0x0000a024, 0x02000205}, - {0x0000a028, 0x02000208}, - {0x0000a02c, 0x02000302}, - {0x0000a030, 0x02000303}, - {0x0000a034, 0x02000304}, - {0x0000a038, 0x02000400}, - {0x0000a03c, 0x02010300}, - {0x0000a040, 0x02010301}, - {0x0000a044, 0x02010302}, - {0x0000a048, 0x02000500}, - {0x0000a04c, 0x02010400}, - {0x0000a050, 0x02020300}, - {0x0000a054, 0x02020301}, - {0x0000a058, 0x02020302}, - {0x0000a05c, 0x02020303}, - {0x0000a060, 0x02020400}, - {0x0000a064, 0x02030300}, - {0x0000a068, 0x02030301}, - {0x0000a06c, 0x02030302}, - {0x0000a070, 0x02030303}, - {0x0000a074, 0x02030400}, - {0x0000a078, 0x02040300}, - {0x0000a07c, 0x02040301}, - {0x0000a080, 0x02040302}, - {0x0000a084, 0x02040303}, - {0x0000a088, 0x02030500}, - {0x0000a08c, 0x02040400}, - {0x0000a090, 0x02050203}, - {0x0000a094, 0x02050204}, - {0x0000a098, 0x02050205}, - {0x0000a09c, 0x02040500}, - {0x0000a0a0, 0x02050301}, - {0x0000a0a4, 0x02050302}, - {0x0000a0a8, 0x02050303}, - {0x0000a0ac, 0x02050400}, - {0x0000a0b0, 0x02050401}, - {0x0000a0b4, 0x02050402}, - {0x0000a0b8, 0x02050403}, - {0x0000a0bc, 0x02050500}, - {0x0000a0c0, 0x02050501}, - {0x0000a0c4, 0x02050502}, - {0x0000a0c8, 0x02050503}, - {0x0000a0cc, 0x02050504}, - {0x0000a0d0, 0x02050600}, - {0x0000a0d4, 0x02050601}, - {0x0000a0d8, 0x02050602}, - {0x0000a0dc, 0x02050603}, - {0x0000a0e0, 0x02050604}, - {0x0000a0e4, 0x02050700}, - {0x0000a0e8, 0x02050701}, - {0x0000a0ec, 0x02050702}, - {0x0000a0f0, 0x02050703}, - {0x0000a0f4, 0x02050704}, - {0x0000a0f8, 0x02050705}, - {0x0000a0fc, 0x02050708}, - {0x0000a100, 0x02050709}, - {0x0000a104, 0x0205070a}, - {0x0000a108, 0x0205070b}, - {0x0000a10c, 0x0205070c}, - {0x0000a110, 0x0205070d}, - {0x0000a114, 0x02050710}, - {0x0000a118, 0x02050711}, - {0x0000a11c, 0x02050712}, - {0x0000a120, 0x02050713}, - {0x0000a124, 0x02050714}, - {0x0000a128, 0x02050715}, - {0x0000a12c, 0x02050730}, - {0x0000a130, 0x02050731}, - {0x0000a134, 0x02050732}, - {0x0000a138, 0x02050733}, - {0x0000a13c, 0x02050734}, - {0x0000a140, 0x02050735}, - {0x0000a144, 0x02050750}, - {0x0000a148, 0x02050751}, - {0x0000a14c, 0x02050752}, - {0x0000a150, 0x02050753}, - {0x0000a154, 0x02050754}, - {0x0000a158, 0x02050755}, - {0x0000a15c, 0x02050770}, - {0x0000a160, 0x02050771}, - {0x0000a164, 0x02050772}, - {0x0000a168, 0x02050773}, - {0x0000a16c, 0x02050774}, - {0x0000a170, 0x02050775}, - {0x0000a174, 0x00000776}, - {0x0000a178, 0x00000776}, - {0x0000a17c, 0x00000776}, - {0x0000a180, 0x00000776}, - {0x0000a184, 0x00000776}, - {0x0000a188, 0x00000776}, - {0x0000a18c, 0x00000776}, - {0x0000a190, 0x00000776}, - {0x0000a194, 0x00000776}, - {0x0000a198, 0x00000776}, - {0x0000a19c, 0x00000776}, - {0x0000a1a0, 0x00000776}, - {0x0000a1a4, 0x00000776}, - {0x0000a1a8, 0x00000776}, - {0x0000a1ac, 0x00000776}, - {0x0000a1b0, 0x00000776}, - {0x0000a1b4, 0x00000776}, - {0x0000a1b8, 0x00000776}, - {0x0000a1bc, 0x00000776}, - {0x0000a1c0, 0x00000776}, - {0x0000a1c4, 0x00000776}, - {0x0000a1c8, 0x00000776}, - {0x0000a1cc, 0x00000776}, - {0x0000a1d0, 0x00000776}, - {0x0000a1d4, 0x00000776}, - {0x0000a1d8, 0x00000776}, - {0x0000a1dc, 0x00000776}, - {0x0000a1e0, 0x00000776}, - {0x0000a1e4, 0x00000776}, - {0x0000a1e8, 0x00000776}, - {0x0000a1ec, 0x00000776}, - {0x0000a1f0, 0x00000776}, - {0x0000a1f4, 0x00000776}, - {0x0000a1f8, 0x00000776}, - {0x0000a1fc, 0x00000776}, - {0x0000b000, 0x02000101}, - {0x0000b004, 0x02000102}, - {0x0000b008, 0x02000103}, - {0x0000b00c, 0x02000104}, - {0x0000b010, 0x02000200}, - {0x0000b014, 0x02000201}, - {0x0000b018, 0x02000202}, - {0x0000b01c, 0x02000203}, - {0x0000b020, 0x02000204}, - {0x0000b024, 0x02000205}, - {0x0000b028, 0x02000208}, - {0x0000b02c, 0x02000302}, - {0x0000b030, 0x02000303}, - {0x0000b034, 0x02000304}, - {0x0000b038, 0x02000400}, - {0x0000b03c, 0x02010300}, - {0x0000b040, 0x02010301}, - {0x0000b044, 0x02010302}, - {0x0000b048, 0x02000500}, - {0x0000b04c, 0x02010400}, - {0x0000b050, 0x02020300}, - {0x0000b054, 0x02020301}, - {0x0000b058, 0x02020302}, - {0x0000b05c, 0x02020303}, - {0x0000b060, 0x02020400}, - {0x0000b064, 0x02030300}, - {0x0000b068, 0x02030301}, - {0x0000b06c, 0x02030302}, - {0x0000b070, 0x02030303}, - {0x0000b074, 0x02030400}, - {0x0000b078, 0x02040300}, - {0x0000b07c, 0x02040301}, - {0x0000b080, 0x02040302}, - {0x0000b084, 0x02040303}, - {0x0000b088, 0x02030500}, - {0x0000b08c, 0x02040400}, - {0x0000b090, 0x02050203}, - {0x0000b094, 0x02050204}, - {0x0000b098, 0x02050205}, - {0x0000b09c, 0x02040500}, - {0x0000b0a0, 0x02050301}, - {0x0000b0a4, 0x02050302}, - {0x0000b0a8, 0x02050303}, - {0x0000b0ac, 0x02050400}, - {0x0000b0b0, 0x02050401}, - {0x0000b0b4, 0x02050402}, - {0x0000b0b8, 0x02050403}, - {0x0000b0bc, 0x02050500}, - {0x0000b0c0, 0x02050501}, - {0x0000b0c4, 0x02050502}, - {0x0000b0c8, 0x02050503}, - {0x0000b0cc, 0x02050504}, - {0x0000b0d0, 0x02050600}, - {0x0000b0d4, 0x02050601}, - {0x0000b0d8, 0x02050602}, - {0x0000b0dc, 0x02050603}, - {0x0000b0e0, 0x02050604}, - {0x0000b0e4, 0x02050700}, - {0x0000b0e8, 0x02050701}, - {0x0000b0ec, 0x02050702}, - {0x0000b0f0, 0x02050703}, - {0x0000b0f4, 0x02050704}, - {0x0000b0f8, 0x02050705}, - {0x0000b0fc, 0x02050708}, - {0x0000b100, 0x02050709}, - {0x0000b104, 0x0205070a}, - {0x0000b108, 0x0205070b}, - {0x0000b10c, 0x0205070c}, - {0x0000b110, 0x0205070d}, - {0x0000b114, 0x02050710}, - {0x0000b118, 0x02050711}, - {0x0000b11c, 0x02050712}, - {0x0000b120, 0x02050713}, - {0x0000b124, 0x02050714}, - {0x0000b128, 0x02050715}, - {0x0000b12c, 0x02050730}, - {0x0000b130, 0x02050731}, - {0x0000b134, 0x02050732}, - {0x0000b138, 0x02050733}, - {0x0000b13c, 0x02050734}, - {0x0000b140, 0x02050735}, - {0x0000b144, 0x02050750}, - {0x0000b148, 0x02050751}, - {0x0000b14c, 0x02050752}, - {0x0000b150, 0x02050753}, - {0x0000b154, 0x02050754}, - {0x0000b158, 0x02050755}, - {0x0000b15c, 0x02050770}, - {0x0000b160, 0x02050771}, - {0x0000b164, 0x02050772}, - {0x0000b168, 0x02050773}, - {0x0000b16c, 0x02050774}, - {0x0000b170, 0x02050775}, - {0x0000b174, 0x00000776}, - {0x0000b178, 0x00000776}, - {0x0000b17c, 0x00000776}, - {0x0000b180, 0x00000776}, - {0x0000b184, 0x00000776}, - {0x0000b188, 0x00000776}, - {0x0000b18c, 0x00000776}, - {0x0000b190, 0x00000776}, - {0x0000b194, 0x00000776}, - {0x0000b198, 0x00000776}, - {0x0000b19c, 0x00000776}, - {0x0000b1a0, 0x00000776}, - {0x0000b1a4, 0x00000776}, - {0x0000b1a8, 0x00000776}, - {0x0000b1ac, 0x00000776}, - {0x0000b1b0, 0x00000776}, - {0x0000b1b4, 0x00000776}, - {0x0000b1b8, 0x00000776}, - {0x0000b1bc, 0x00000776}, - {0x0000b1c0, 0x00000776}, - {0x0000b1c4, 0x00000776}, - {0x0000b1c8, 0x00000776}, - {0x0000b1cc, 0x00000776}, - {0x0000b1d0, 0x00000776}, - {0x0000b1d4, 0x00000776}, - {0x0000b1d8, 0x00000776}, - {0x0000b1dc, 0x00000776}, - {0x0000b1e0, 0x00000776}, - {0x0000b1e4, 0x00000776}, - {0x0000b1e8, 0x00000776}, - {0x0000b1ec, 0x00000776}, - {0x0000b1f0, 0x00000776}, - {0x0000b1f4, 0x00000776}, - {0x0000b1f8, 0x00000776}, - {0x0000b1fc, 0x00000776}, -}; - static const u32 ar9300_2p2_mac_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, @@ -572,48 +312,6 @@ static const u32 ar9300_2p2_soc_postamble[][5] = { {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, }; -static const u32 ar9200_merlin_2p2_radio_core[][2] = { - /* Addr allmodes */ - {0x00007800, 0x00040000}, - {0x00007804, 0xdb005012}, - {0x00007808, 0x04924914}, - {0x0000780c, 0x21084210}, - {0x00007810, 0x6d801300}, - {0x00007814, 0x0019beff}, - {0x00007818, 0x07e41000}, - {0x0000781c, 0x00392000}, - {0x00007820, 0x92592480}, - {0x00007824, 0x00040000}, - {0x00007828, 0xdb005012}, - {0x0000782c, 0x04924914}, - {0x00007830, 0x21084210}, - {0x00007834, 0x6d801300}, - {0x00007838, 0x0019beff}, - {0x0000783c, 0x07e40000}, - {0x00007840, 0x00392000}, - {0x00007844, 0x92592480}, - {0x00007848, 0x00100000}, - {0x0000784c, 0x773f0567}, - {0x00007850, 0x54214514}, - {0x00007854, 0x12035828}, - {0x00007858, 0x92592692}, - {0x0000785c, 0x00000000}, - {0x00007860, 0x56400000}, - {0x00007864, 0x0a8e370e}, - {0x00007868, 0xc0102850}, - {0x0000786c, 0x812d4000}, - {0x00007870, 0x807ec400}, - {0x00007874, 0x001b6db0}, - {0x00007878, 0x00376b63}, - {0x0000787c, 0x06db6db6}, - {0x00007880, 0x006d8000}, - {0x00007884, 0xffeffffe}, - {0x00007888, 0xffeffffe}, - {0x0000788c, 0x00010000}, - {0x00007890, 0x02060aeb}, - {0x00007894, 0x5a108000}, -}; - static const u32 ar9300_2p2_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 8e70f0bc073e..63089cc1fafd 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -925,7 +925,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_cal_data *caldata = ah->caldata; - struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; bool txiqcal_done = false, txclcal_done = false; bool is_reusable = true, status = true; bool run_rtt_cal = false, run_agc_cal; @@ -998,30 +997,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, } else if (caldata && !caldata->done_txiqcal_once) run_agc_cal = true; - if (mci && IS_CHAN_2GHZ(chan) && - (mci_hw->bt_state == MCI_BT_AWAKE) && - run_agc_cal && - !(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) { - - u32 pld[4] = {0, 0, 0, 0}; - - /* send CAL_REQ only when BT is AWAKE. */ - ath_dbg(common, MCI, "MCI send WLAN_CAL_REQ 0x%x\n", - mci_hw->wlan_cal_seq); - MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ); - pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++; - ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); - - /* Wait BT_CAL_GRANT for 50ms */ - ath_dbg(common, MCI, "MCI wait for BT_CAL_GRANT\n"); - - if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) - ath_dbg(common, MCI, "MCI got BT_CAL_GRANT\n"); - else { - is_reusable = false; - ath_dbg(common, MCI, "\nMCI BT is not responding\n"); - } - } + if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal) + ar9003_mci_init_cal_req(ah, &is_reusable); txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); @@ -1041,19 +1018,8 @@ skip_tx_iqcal: 0, AH_WAIT_TIMEOUT); } - if (mci && IS_CHAN_2GHZ(chan) && - (mci_hw->bt_state == MCI_BT_AWAKE) && - run_agc_cal && - !(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) { - - u32 pld[4] = {0, 0, 0, 0}; - - ath_dbg(common, MCI, "MCI Send WLAN_CAL_DONE 0x%x\n", - mci_hw->wlan_cal_done); - MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE); - pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++; - ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); - } + if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal) + ar9003_mci_init_cal_done(ah); if (rtt && !run_rtt_cal) { agc_ctrl |= agc_supp_cals; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 9fbcbddea165..6bb4db052bb0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3603,10 +3603,6 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz); if (AR_SREV_9462(ah)) { - if (AR_SREV_9462_10(ah)) { - value &= ~AR_SWITCH_TABLE_COM_SPDT; - value |= 0x00100000; - } REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_AR9462_ALL, value); } else diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index fb937ba93e0c..0f56e322dd3b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -22,7 +22,6 @@ #include "ar9330_1p1_initvals.h" #include "ar9330_1p2_initvals.h" #include "ar9580_1p0_initvals.h" -#include "ar9462_1p0_initvals.h" #include "ar9462_2p0_initvals.h" /* General hardware code for the AR9003 hadware family */ @@ -88,11 +87,11 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) /* additional clock settings */ if (ah->is_clk_25mhz) - INIT_INI_ARRAY(&ah->iniModesAdditional, + INIT_INI_ARRAY(&ah->iniAdditional, ar9331_1p1_xtal_25M, ARRAY_SIZE(ar9331_1p1_xtal_25M), 2); else - INIT_INI_ARRAY(&ah->iniModesAdditional, + INIT_INI_ARRAY(&ah->iniAdditional, ar9331_1p1_xtal_40M, ARRAY_SIZE(ar9331_1p1_xtal_40M), 2); } else if (AR_SREV_9330_12(ah)) { @@ -141,11 +140,11 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) /* additional clock settings */ if (ah->is_clk_25mhz) - INIT_INI_ARRAY(&ah->iniModesAdditional, + INIT_INI_ARRAY(&ah->iniAdditional, ar9331_1p2_xtal_25M, ARRAY_SIZE(ar9331_1p2_xtal_25M), 2); else - INIT_INI_ARRAY(&ah->iniModesAdditional, + INIT_INI_ARRAY(&ah->iniAdditional, ar9331_1p2_xtal_40M, ARRAY_SIZE(ar9331_1p2_xtal_40M), 2); } else if (AR_SREV_9340(ah)) { @@ -195,15 +194,16 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar9340Modes_high_ob_db_tx_gain_table_1p0), 5); - INIT_INI_ARRAY(&ah->iniModesAdditional, + INIT_INI_ARRAY(&ah->iniModesFastClock, ar9340Modes_fast_clock_1p0, ARRAY_SIZE(ar9340Modes_fast_clock_1p0), 3); - INIT_INI_ARRAY(&ah->iniModesAdditional_40M, - ar9340_1p0_radio_core_40M, - ARRAY_SIZE(ar9340_1p0_radio_core_40M), - 2); + if (!ah->is_clk_25mhz) + INIT_INI_ARRAY(&ah->iniAdditional, + ar9340_1p0_radio_core_40M, + ARRAY_SIZE(ar9340_1p0_radio_core_40M), + 2); } else if (AR_SREV_9485_11(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); @@ -264,63 +264,6 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9485_1_1_pcie_phy_clkreq_disable_L1, ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), 2); - } else if (AR_SREV_9462_10(ah)) { - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_1p0_mac_core, - ARRAY_SIZE(ar9462_1p0_mac_core), 2); - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], - ar9462_1p0_mac_postamble, - ARRAY_SIZE(ar9462_1p0_mac_postamble), - 5); - - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - ar9462_1p0_baseband_core, - ARRAY_SIZE(ar9462_1p0_baseband_core), - 2); - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - ar9462_1p0_baseband_postamble, - ARRAY_SIZE(ar9462_1p0_baseband_postamble), 5); - - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], - ar9462_1p0_radio_core, - ARRAY_SIZE(ar9462_1p0_radio_core), 2); - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], - ar9462_1p0_radio_postamble, - ARRAY_SIZE(ar9462_1p0_radio_postamble), 5); - - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], - ar9462_1p0_soc_preamble, - ARRAY_SIZE(ar9462_1p0_soc_preamble), 2); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], - ar9462_1p0_soc_postamble, - ARRAY_SIZE(ar9462_1p0_soc_postamble), 5); - - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_rx_gain_table_1p0, - ARRAY_SIZE(ar9462_common_rx_gain_table_1p0), 2); - - /* Awake -> Sleep Setting */ - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9462_pcie_phy_clkreq_disable_L1_1p0, - ARRAY_SIZE(ar9462_pcie_phy_clkreq_disable_L1_1p0), - 2); - - /* Sleep -> Awake Setting */ - INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9462_pcie_phy_clkreq_disable_L1_1p0, - ARRAY_SIZE(ar9462_pcie_phy_clkreq_disable_L1_1p0), - 2); - - INIT_INI_ARRAY(&ah->iniModesAdditional, - ar9462_modes_fast_clock_1p0, - ARRAY_SIZE(ar9462_modes_fast_clock_1p0), 3); - INIT_INI_ARRAY(&ah->iniCckfirJapan2484, - AR9462_BB_CTX_COEFJ(1p0), - ARRAY_SIZE(AR9462_BB_CTX_COEFJ(1p0)), 2); - } else if (AR_SREV_9462_20(ah)) { INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); @@ -379,7 +322,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) 2); /* Fast clock modal settings */ - INIT_INI_ARRAY(&ah->iniModesAdditional, + INIT_INI_ARRAY(&ah->iniModesFastClock, ar9462_modes_fast_clock_2p0, ARRAY_SIZE(ar9462_modes_fast_clock_2p0), 3); @@ -436,7 +379,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar9580_1p0_low_ob_db_tx_gain_table), 5); - INIT_INI_ARRAY(&ah->iniModesAdditional, + INIT_INI_ARRAY(&ah->iniModesFastClock, ar9580_1p0_modes_fast_clock, ARRAY_SIZE(ar9580_1p0_modes_fast_clock), 3); @@ -503,7 +446,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) 2); /* Fast clock modal settings */ - INIT_INI_ARRAY(&ah->iniModesAdditional, + INIT_INI_ARRAY(&ah->iniModesFastClock, ar9300Modes_fast_clock_2p2, ARRAY_SIZE(ar9300Modes_fast_clock_2p2), 3); @@ -537,11 +480,6 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) ar9580_1p0_lowest_ob_db_tx_gain_table, ARRAY_SIZE(ar9580_1p0_lowest_ob_db_tx_gain_table), 5); - else if (AR_SREV_9462_10(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9462_modes_low_ob_db_tx_gain_table_1p0, - ARRAY_SIZE(ar9462_modes_low_ob_db_tx_gain_table_1p0), - 5); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9462_modes_low_ob_db_tx_gain_table_2p0, @@ -581,11 +519,6 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) ar9580_1p0_high_ob_db_tx_gain_table, ARRAY_SIZE(ar9580_1p0_high_ob_db_tx_gain_table), 5); - else if (AR_SREV_9462_10(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9462_modes_high_ob_db_tx_gain_table_1p0, - ARRAY_SIZE(ar9462_modes_high_ob_db_tx_gain_table_1p0), - 5); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9462_modes_high_ob_db_tx_gain_table_2p0, @@ -712,11 +645,6 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) ar9580_1p0_rx_gain_table, ARRAY_SIZE(ar9580_1p0_rx_gain_table), 2); - else if (AR_SREV_9462_10(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_rx_gain_table_1p0, - ARRAY_SIZE(ar9462_common_rx_gain_table_1p0), - 2); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9462_common_rx_gain_table_2p0, @@ -751,11 +679,6 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) ar9485Common_wo_xlna_rx_gain_1_1, ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); - else if (AR_SREV_9462_10(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_wo_xlna_rx_gain_table_1p0, - ARRAY_SIZE(ar9462_common_wo_xlna_rx_gain_table_1p0), - 2); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9462_common_wo_xlna_rx_gain_table_2p0, @@ -775,14 +698,10 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) static void ar9003_rx_gain_table_mode2(struct ath_hw *ah) { - if (AR_SREV_9462_10(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_mixed_rx_gain_table_1p0, - ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_1p0), 2); - else if (AR_SREV_9462_20(ah)) + if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_mixed_rx_gain_table_2p0, - ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_2p0), 2); + ar9462_common_mixed_rx_gain_table_2p0, + ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_2p0), 2); } static void ar9003_rx_gain_table_apply(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 09b8c9dbf78f..a66a13b76848 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -16,6 +16,7 @@ #include <linux/export.h> #include "hw.h" #include "ar9003_mac.h" +#include "ar9003_mci.h" static void ar9003_hw_rx_enable(struct ath_hw *hw) { @@ -28,11 +29,14 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) struct ar9003_txc *ads = ds; int checksum = 0; u32 val, ctl12, ctl17; + u8 desc_len; + + desc_len = (AR_SREV_9462(ah) ? 0x18 : 0x17); val = (ATHEROS_VENDOR_ID << AR_DescId_S) | (1 << AR_TxRxDesc_S) | (1 << AR_CtrlStat_S) | - (i->qcu << AR_TxQcuNum_S) | 0x17; + (i->qcu << AR_TxQcuNum_S) | desc_len; checksum += val; ACCESS_ONCE(ads->info) = val; @@ -81,6 +85,7 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) ads->ctl20 = 0; ads->ctl21 = 0; ads->ctl22 = 0; + ads->ctl23 = 0; ctl17 = SM(i->keytype, AR_EncrType); if (!i->is_first) { @@ -176,7 +181,6 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) u32 mask2 = 0; struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 sync_cause = 0, async_cause; async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE); @@ -298,32 +302,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) ar9003_hw_bb_watchdog_read(ah); } - if (async_cause & AR_INTR_ASYNC_MASK_MCI) { - u32 raw_intr, rx_msg_intr; - - rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); - raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW); - - if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef)) - ath_dbg(common, MCI, - "MCI gets 0xdeadbeef during MCI int processing new raw_intr=0x%08x, new rx_msg_raw=0x%08x, raw_intr=0x%08x, rx_msg_raw=0x%08x\n", - raw_intr, rx_msg_intr, mci->raw_intr, - mci->rx_msg_intr); - else { - mci->rx_msg_intr |= rx_msg_intr; - mci->raw_intr |= raw_intr; - *masked |= ATH9K_INT_MCI; - - if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) - mci->cont_status = - REG_READ(ah, AR_MCI_CONT_STATUS); - - REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr); - REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr); - ath_dbg(common, MCI, "AR_INTR_SYNC_MCI\n"); - - } - } + if (async_cause & AR_INTR_ASYNC_MASK_MCI) + ar9003_mci_get_isr(ah, masked); if (sync_cause) { if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { @@ -346,7 +326,6 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_status *ts) { - struct ar9003_txc *txc = (struct ar9003_txc *) ds; struct ar9003_txs *ads; u32 status; @@ -356,11 +335,7 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, if ((status & AR_TxDone) == 0) return -EINPROGRESS; - ts->qid = MS(ads->ds_info, AR_TxQcuNum); - if (!txc || (MS(txc->info, AR_TxQcuNum) == ts->qid)) - ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size; - else - return -ENOENT; + ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size; if ((MS(ads->ds_info, AR_DescId) != ATHEROS_VENDOR_ID) || (MS(ads->ds_info, AR_TxRxDesc) != 1)) { @@ -374,6 +349,7 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->ts_seqnum = MS(status, AR_SeqNum); ts->tid = MS(status, AR_TxTid); + ts->qid = MS(ads->ds_info, AR_TxQcuNum); ts->desc_id = MS(ads->status1, AR_TxDescId); ts->ts_tstamp = ads->status4; ts->ts_status = 0; @@ -460,20 +436,14 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, struct ar9003_rxs *rxsp = (struct ar9003_rxs *) buf_addr; unsigned int phyerr; - /* TODO: byte swap on big endian for ar9300_10 */ - - if (!rxs) { - if ((rxsp->status11 & AR_RxDone) == 0) - return -EINPROGRESS; - - if (MS(rxsp->ds_info, AR_DescId) != 0x168c) - return -EINVAL; + if ((rxsp->status11 & AR_RxDone) == 0) + return -EINPROGRESS; - if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0) - return -EINPROGRESS; + if (MS(rxsp->ds_info, AR_DescId) != 0x168c) + return -EINVAL; - return 0; - } + if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0) + return -EINPROGRESS; rxs->rs_status = 0; rxs->rs_flags = 0; @@ -530,7 +500,11 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, */ if (rxsp->status11 & AR_CRCErr) rxs->rs_status |= ATH9K_RXERR_CRC; - else if (rxsp->status11 & AR_PHYErr) { + else if (rxsp->status11 & AR_DecryptCRCErr) + rxs->rs_status |= ATH9K_RXERR_DECRYPT; + else if (rxsp->status11 & AR_MichaelErr) + rxs->rs_status |= ATH9K_RXERR_MIC; + if (rxsp->status11 & AR_PHYErr) { phyerr = MS(rxsp->status11, AR_PHYErrCode); /* * If we reach a point here where AR_PostDelimCRCErr is @@ -552,11 +526,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, rxs->rs_status |= ATH9K_RXERR_PHY; rxs->rs_phyerr = phyerr; } - - } else if (rxsp->status11 & AR_DecryptCRCErr) - rxs->rs_status |= ATH9K_RXERR_DECRYPT; - else if (rxsp->status11 & AR_MichaelErr) - rxs->rs_status |= ATH9K_RXERR_MIC; + }; } if (rxsp->status11 & AR_KeyMiss) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.h b/drivers/net/wireless/ath/ath9k/ar9003_mac.h index e203b51e968b..cbf60b090bd9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.h @@ -92,7 +92,8 @@ struct ar9003_txc { u32 ctl20; /* DMA control 20 */ u32 ctl21; /* DMA control 21 */ u32 ctl22; /* DMA control 22 */ - u32 pad[9]; /* pad to cache line (128 bytes/32 dwords) */ + u32 ctl23; /* DMA control 23 */ + u32 pad[8]; /* pad to cache line (128 bytes/32 dwords) */ } __packed __aligned(4); struct ar9003_txs { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 709520c6835b..3cac293a2849 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -16,14 +16,12 @@ #include <linux/export.h> #include "hw.h" +#include "hw-ops.h" #include "ar9003_phy.h" #include "ar9003_mci.h" static void ar9003_mci_reset_req_wakeup(struct ath_hw *ah) { - if (!AR_SREV_9462_20(ah)) - return; - REG_RMW_FIELD(ah, AR_MCI_COMMAND2, AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 1); udelay(1); @@ -37,13 +35,10 @@ static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address, struct ath_common *common = ath9k_hw_common(ah); while (time_out) { - if (REG_READ(ah, address) & bit_position) { - REG_WRITE(ah, address, bit_position); if (address == AR_MCI_INTERRUPT_RX_MSG_RAW) { - if (bit_position & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) ar9003_mci_reset_req_wakeup(ah); @@ -81,25 +76,19 @@ static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address, return time_out; } -void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done) +static void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done) { u32 payload[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00}; - if (!ATH9K_HW_CAP_MCI) - return; - ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, payload, 16, wait_done, false); udelay(5); } -void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done) +static void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done) { u32 payload = 0x00000000; - if (!ATH9K_HW_CAP_MCI) - return; - ar9003_mci_send_message(ah, MCI_LNA_TRANS, 0, &payload, 1, wait_done, false); } @@ -111,11 +100,8 @@ static void ar9003_mci_send_req_wake(struct ath_hw *ah, bool wait_done) udelay(5); } -void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done) +static void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done) { - if (!ATH9K_HW_CAP_MCI) - return; - ar9003_mci_send_message(ah, MCI_SYS_WAKING, MCI_FLAG_DISABLE_TIMESTAMP, NULL, 0, wait_done, false); } @@ -138,30 +124,27 @@ static void ar9003_mci_send_sys_sleeping(struct ath_hw *ah, bool wait_done) static void ar9003_mci_send_coex_version_query(struct ath_hw *ah, bool wait_done) { - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 payload[4] = {0, 0, 0, 0}; if (!mci->bt_version_known && - (mci->bt_state != MCI_BT_SLEEP)) { - ath_dbg(common, MCI, "MCI Send Coex version query\n"); + (mci->bt_state != MCI_BT_SLEEP)) { MCI_GPM_SET_TYPE_OPCODE(payload, - MCI_GPM_COEX_AGENT, MCI_GPM_COEX_VERSION_QUERY); + MCI_GPM_COEX_AGENT, + MCI_GPM_COEX_VERSION_QUERY); ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, - wait_done, true); + wait_done, true); } } static void ar9003_mci_send_coex_version_response(struct ath_hw *ah, - bool wait_done) + bool wait_done) { - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 payload[4] = {0, 0, 0, 0}; - ath_dbg(common, MCI, "MCI Send Coex version response\n"); MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, - MCI_GPM_COEX_VERSION_RESPONSE); + MCI_GPM_COEX_VERSION_RESPONSE); *(((u8 *)payload) + MCI_GPM_COEX_B_MAJOR_VERSION) = mci->wlan_ver_major; *(((u8 *)payload) + MCI_GPM_COEX_B_MINOR_VERSION) = @@ -170,15 +153,16 @@ static void ar9003_mci_send_coex_version_response(struct ath_hw *ah, } static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah, - bool wait_done) + bool wait_done) { struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 *payload = &mci->wlan_channels[0]; if ((mci->wlan_channels_update == true) && - (mci->bt_state != MCI_BT_SLEEP)) { + (mci->bt_state != MCI_BT_SLEEP)) { MCI_GPM_SET_TYPE_OPCODE(payload, - MCI_GPM_COEX_AGENT, MCI_GPM_COEX_WLAN_CHANNELS); + MCI_GPM_COEX_AGENT, + MCI_GPM_COEX_WLAN_CHANNELS); ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff); @@ -188,7 +172,6 @@ static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah, static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah, bool wait_done, u8 query_type) { - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 payload[4] = {0, 0, 0, 0}; bool query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO | @@ -196,25 +179,19 @@ static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah, if (mci->bt_state != MCI_BT_SLEEP) { - ath_dbg(common, MCI, "MCI Send Coex BT Status Query 0x%02X\n", - query_type); - - MCI_GPM_SET_TYPE_OPCODE(payload, - MCI_GPM_COEX_AGENT, MCI_GPM_COEX_STATUS_QUERY); + MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, + MCI_GPM_COEX_STATUS_QUERY); *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type; + /* * If bt_status_query message is not sent successfully, * then need_flush_btinfo should be set again. */ if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true)) { - if (query_btinfo) { + if (query_btinfo) mci->need_flush_btinfo = true; - - ath_dbg(common, MCI, - "MCI send bt_status_query fail, set flush flag again\n"); - } } if (query_btinfo) @@ -222,21 +199,14 @@ static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah, } } -void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt, - bool wait_done) +static void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt, + bool wait_done) { - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 payload[4] = {0, 0, 0, 0}; - if (!ATH9K_HW_CAP_MCI) - return; - - ath_dbg(common, MCI, "MCI Send Coex %s BT GPM\n", - (halt) ? "halt" : "unhalt"); - - MCI_GPM_SET_TYPE_OPCODE(payload, - MCI_GPM_COEX_AGENT, MCI_GPM_COEX_HALT_BT_GPM); + MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, + MCI_GPM_COEX_HALT_BT_GPM); if (halt) { mci->query_bt = true; @@ -252,7 +222,6 @@ void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt, ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); } - static void ar9003_mci_prep_interface(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -269,30 +238,14 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah) REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, REG_READ(ah, AR_MCI_INTERRUPT_RAW)); - /* Remote Reset */ - ath_dbg(common, MCI, "MCI Reset sequence start\n"); - ath_dbg(common, MCI, "MCI send REMOTE_RESET\n"); ar9003_mci_remote_reset(ah, true); - - /* - * This delay is required for the reset delay worst case value 255 in - * MCI_COMMAND2 register - */ - - if (AR_SREV_9462_10(ah)) - udelay(252); - - ath_dbg(common, MCI, "MCI Send REQ_WAKE to remoter(BT)\n"); ar9003_mci_send_req_wake(ah, true); if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, - AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) { + AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) { - ath_dbg(common, MCI, "MCI SYS_WAKING from remote(BT)\n"); mci->bt_state = MCI_BT_AWAKE; - if (AR_SREV_9462_10(ah)) - udelay(10); /* * we don't need to send more remote_reset at this moment. * If BT receive first remote_reset, then BT HW will @@ -309,11 +262,6 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah) * Similarly, if in any case, WLAN can receive BT's sys_waking, * that means WLAN's RX is also fine. */ - - /* Send SYS_WAKING to BT */ - - ath_dbg(common, MCI, "MCI send SW SYS_WAKING to remote BT\n"); - ar9003_mci_send_sys_waking(ah, true); udelay(10); @@ -321,7 +269,6 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah) * Set BT priority interrupt value to be 0xff to * avoid having too many BT PRIORITY interrupts. */ - REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF); REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF); REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF); @@ -339,77 +286,70 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah) REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_BT_PRI); - if (AR_SREV_9462_10(ah) || mci->is_2g) { - /* Send LNA_TRANS */ - ath_dbg(common, MCI, "MCI send LNA_TRANS to BT\n"); + if (mci->is_2g) { ar9003_mci_send_lna_transfer(ah, true); udelay(5); } - if (AR_SREV_9462_10(ah) || (mci->is_2g && - !mci->update_2g5g)) { + if ((mci->is_2g && !mci->update_2g5g)) { if (ar9003_mci_wait_for_interrupt(ah, - AR_MCI_INTERRUPT_RX_MSG_RAW, - AR_MCI_INTERRUPT_RX_MSG_LNA_INFO, - mci_timeout)) + AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_LNA_INFO, + mci_timeout)) ath_dbg(common, MCI, "MCI WLAN has control over the LNA & BT obeys it\n"); else ath_dbg(common, MCI, "MCI BT didn't respond to LNA_TRANS\n"); } - - if (AR_SREV_9462_10(ah)) { - /* Send another remote_reset to deassert BT clk_req. */ - ath_dbg(common, MCI, - "MCI another remote_reset to deassert clk_req\n"); - ar9003_mci_remote_reset(ah, true); - udelay(252); - } } /* Clear the extra redundant SYS_WAKING from BT */ if ((mci->bt_state == MCI_BT_AWAKE) && (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) && - (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, - AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) { - - REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, - AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING); - REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, - AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE); + (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) { + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING); + REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, + AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE); } REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en); } -void ar9003_mci_disable_interrupt(struct ath_hw *ah) +void ar9003_mci_set_full_sleep(struct ath_hw *ah) { - if (!ATH9K_HW_CAP_MCI) - return; + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) && + (mci->bt_state != MCI_BT_SLEEP) && + !mci->halted_bt_gpm) { + ar9003_mci_send_coex_halt_bt_gpm(ah, true, true); + } + + mci->ready = false; + REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); +} + +static void ar9003_mci_disable_interrupt(struct ath_hw *ah) +{ REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0); } -void ar9003_mci_enable_interrupt(struct ath_hw *ah) +static void ar9003_mci_enable_interrupt(struct ath_hw *ah) { - if (!ATH9K_HW_CAP_MCI) - return; - REG_WRITE(ah, AR_MCI_INTERRUPT_EN, AR_MCI_INTERRUPT_DEFAULT); REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, AR_MCI_INTERRUPT_RX_MSG_DEFAULT); } -bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints) +static bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints) { u32 intr; - if (!ATH9K_HW_CAP_MCI) - return false; - intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); return ((intr & ints) == ints); } @@ -419,9 +359,6 @@ void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, { struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - if (!ATH9K_HW_CAP_MCI) - return; - *raw_intr = mci->raw_intr; *rx_msg_intr = mci->rx_msg_intr; @@ -431,12 +368,34 @@ void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, } EXPORT_SYMBOL(ar9003_mci_get_interrupt); -void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g) +void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked) { + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 raw_intr, rx_msg_intr; - if (!ATH9K_HW_CAP_MCI) - return; + rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); + raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW); + + if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef)) { + ath_dbg(common, MCI, + "MCI gets 0xdeadbeef during int processing\n"); + } else { + mci->rx_msg_intr |= rx_msg_intr; + mci->raw_intr |= raw_intr; + *masked |= ATH9K_INT_MCI; + + if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) + mci->cont_status = REG_READ(ah, AR_MCI_CONT_STATUS); + + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr); + REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr); + } +} + +static void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g) +{ + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; if (!mci->update_2g5g && (mci->is_2g != is_2g)) @@ -447,7 +406,6 @@ void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g) static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index) { - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 *payload; u32 recv_type, offset; @@ -460,10 +418,8 @@ static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index) payload = (u32 *)(mci->gpm_buf + offset); recv_type = MCI_GPM_TYPE(payload); - if (recv_type == MCI_GPM_RSVD_PATTERN) { - ath_dbg(common, MCI, "MCI Skip RSVD GPM\n"); + if (recv_type == MCI_GPM_RSVD_PATTERN) return false; - } return true; } @@ -471,42 +427,31 @@ static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index) static void ar9003_mci_observation_set_up(struct ath_hw *ah) { struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) { - ath9k_hw_cfg_output(ah, 3, - AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA); + if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) { + ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA); ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK); ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); - } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) { - ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX); ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX); ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); ath9k_hw_cfg_output(ah, 5, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) { - ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); - } else return; REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); - if (AR_SREV_9462_20_OR_LATER(ah)) { - REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, - AR_GLB_DS_JTAG_DISABLE, 1); - REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, - AR_GLB_WLAN_UART_INTF_EN, 0); - REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL, - ATH_MCI_CONFIG_MCI_OBS_GPIO); - } + REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_DS_JTAG_DISABLE, 1); + REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_WLAN_UART_INTF_EN, 0); + REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL, ATH_MCI_CONFIG_MCI_OBS_GPIO); REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_GPIO_OBS_SEL, 0); REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL, 1); @@ -520,13 +465,12 @@ static void ar9003_mci_observation_set_up(struct ath_hw *ah) } static bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done, - u8 opcode, u32 bt_flags) + u8 opcode, u32 bt_flags) { - struct ath_common *common = ath9k_hw_common(ah); u32 pld[4] = {0, 0, 0, 0}; - MCI_GPM_SET_TYPE_OPCODE(pld, - MCI_GPM_COEX_AGENT, MCI_GPM_COEX_BT_UPDATE_FLAGS); + MCI_GPM_SET_TYPE_OPCODE(pld, MCI_GPM_COEX_AGENT, + MCI_GPM_COEX_BT_UPDATE_FLAGS); *(((u8 *)pld) + MCI_GPM_COEX_B_BT_FLAGS_OP) = opcode; *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 0) = bt_flags & 0xFF; @@ -534,32 +478,360 @@ static bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done, *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 2) = (bt_flags >> 16) & 0xFF; *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 3) = (bt_flags >> 24) & 0xFF; - ath_dbg(common, MCI, - "MCI BT_MCI_FLAGS: Send Coex BT Update Flags %s 0x%08x\n", - opcode == MCI_GPM_COEX_BT_FLAGS_READ ? "READ" : - opcode == MCI_GPM_COEX_BT_FLAGS_SET ? "SET" : "CLEAR", - bt_flags); - return ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, - wait_done, true); + wait_done, true); } -void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, - bool is_full_sleep) +static void ar9003_mci_sync_bt_state(struct ath_hw *ah) +{ + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 cur_bt_state; + + cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL); + + if (mci->bt_state != cur_bt_state) + mci->bt_state = cur_bt_state; + + if (mci->bt_state != MCI_BT_SLEEP) { + + ar9003_mci_send_coex_version_query(ah, true); + ar9003_mci_send_coex_wlan_channels(ah, true); + + if (mci->unhalt_bt_gpm == true) + ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); + } +} + +void ar9003_mci_check_bt(struct ath_hw *ah) +{ + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; + + if (!mci_hw->ready) + return; + + /* + * check BT state again to make + * sure it's not changed. + */ + ar9003_mci_sync_bt_state(ah); + ar9003_mci_2g5g_switch(ah, true); + + if ((mci_hw->bt_state == MCI_BT_AWAKE) && + (mci_hw->query_bt == true)) { + mci_hw->need_flush_btinfo = true; + } +} + +static void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type, + u8 gpm_opcode, u32 *p_gpm) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - u32 regval, thresh; + u8 *p_data = (u8 *) p_gpm; - if (!ATH9K_HW_CAP_MCI) + if (gpm_type != MCI_GPM_COEX_AGENT) return; - ath_dbg(common, MCI, "MCI full_sleep = %d, is_2g = %d\n", - is_full_sleep, is_2g); + switch (gpm_opcode) { + case MCI_GPM_COEX_VERSION_QUERY: + ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n"); + ar9003_mci_send_coex_version_response(ah, true); + break; + case MCI_GPM_COEX_VERSION_RESPONSE: + ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n"); + mci->bt_ver_major = + *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION); + mci->bt_ver_minor = + *(p_data + MCI_GPM_COEX_B_MINOR_VERSION); + mci->bt_version_known = true; + ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n", + mci->bt_ver_major, mci->bt_ver_minor); + break; + case MCI_GPM_COEX_STATUS_QUERY: + ath_dbg(common, MCI, + "MCI Recv GPM COEX Status Query = 0x%02X\n", + *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP)); + mci->wlan_channels_update = true; + ar9003_mci_send_coex_wlan_channels(ah, true); + break; + case MCI_GPM_COEX_BT_PROFILE_INFO: + mci->query_bt = true; + ath_dbg(common, MCI, "MCI Recv GPM COEX BT_Profile_Info\n"); + break; + case MCI_GPM_COEX_BT_STATUS_UPDATE: + mci->query_bt = true; + ath_dbg(common, MCI, + "MCI Recv GPM COEX BT_Status_Update SEQ=%d (drop&query)\n", + *(p_gpm + 3)); + break; + default: + break; + } +} + +static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, + u8 gpm_opcode, int time_out) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 *p_gpm = NULL, mismatch = 0, more_data; + u32 offset; + u8 recv_type = 0, recv_opcode = 0; + bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE); + + more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE; + + while (time_out > 0) { + if (p_gpm) { + MCI_GPM_RECYCLE(p_gpm); + p_gpm = NULL; + } + + if (more_data != MCI_GPM_MORE) + time_out = ar9003_mci_wait_for_interrupt(ah, + AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_GPM, + time_out); + + if (!time_out) + break; + + offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET, + &more_data); + + if (offset == MCI_GPM_INVALID) + continue; + + p_gpm = (u32 *) (mci->gpm_buf + offset); + recv_type = MCI_GPM_TYPE(p_gpm); + recv_opcode = MCI_GPM_OPCODE(p_gpm); + + if (MCI_GPM_IS_CAL_TYPE(recv_type)) { + if (recv_type == gpm_type) { + if ((gpm_type == MCI_GPM_BT_CAL_DONE) && + !b_is_bt_cal_done) { + gpm_type = MCI_GPM_BT_CAL_GRANT; + continue; + } + break; + } + } else if ((recv_type == gpm_type) && (recv_opcode == gpm_opcode)) { + break; + } + + /* + * check if it's cal_grant + * + * When we're waiting for cal_grant in reset routine, + * it's possible that BT sends out cal_request at the + * same time. Since BT's calibration doesn't happen + * that often, we'll let BT completes calibration then + * we continue to wait for cal_grant from BT. + * Orginal: Wait BT_CAL_GRANT. + * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait + * BT_CAL_DONE -> Wait BT_CAL_GRANT. + */ + + if ((gpm_type == MCI_GPM_BT_CAL_GRANT) && + (recv_type == MCI_GPM_BT_CAL_REQ)) { + + u32 payload[4] = {0, 0, 0, 0}; + + gpm_type = MCI_GPM_BT_CAL_DONE; + MCI_GPM_SET_CAL_TYPE(payload, + MCI_GPM_WLAN_CAL_GRANT); + ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, + false, false); + continue; + } else { + ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n", + *(p_gpm + 1)); + mismatch++; + ar9003_mci_process_gpm_extra(ah, recv_type, + recv_opcode, p_gpm); + } + } + + if (p_gpm) { + MCI_GPM_RECYCLE(p_gpm); + p_gpm = NULL; + } + + if (time_out <= 0) + time_out = 0; + + while (more_data == MCI_GPM_MORE) { + offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET, + &more_data); + if (offset == MCI_GPM_INVALID) + break; + + p_gpm = (u32 *) (mci->gpm_buf + offset); + recv_type = MCI_GPM_TYPE(p_gpm); + recv_opcode = MCI_GPM_OPCODE(p_gpm); + + if (!MCI_GPM_IS_CAL_TYPE(recv_type)) + ar9003_mci_process_gpm_extra(ah, recv_type, + recv_opcode, p_gpm); + + MCI_GPM_RECYCLE(p_gpm); + } + + return time_out; +} + +bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; + u32 payload[4] = {0, 0, 0, 0}; + + ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan)); + + if (mci_hw->bt_state != MCI_BT_CAL_START) + return false; + + mci_hw->bt_state = MCI_BT_CAL; + + /* + * MCI FIX: disable mci interrupt here. This is to avoid + * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and + * lead to mci_intr reentry. + */ + ar9003_mci_disable_interrupt(ah); + + MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); + ar9003_mci_send_message(ah, MCI_GPM, 0, payload, + 16, true, false); + + /* Wait BT calibration to be completed for 25ms */ + + if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, + 0, 25000)) + ath_dbg(common, MCI, "MCI BT_CAL_DONE received\n"); + else + ath_dbg(common, MCI, + "MCI BT_CAL_DONE not received\n"); + + mci_hw->bt_state = MCI_BT_AWAKE; + /* MCI FIX: enable mci interrupt here */ + ar9003_mci_enable_interrupt(ah); + + return true; +} + +int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, + struct ath9k_hw_cal_data *caldata) +{ + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; + + if (!mci_hw->ready) + return 0; + + if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP)) + goto exit; + + if (ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) || + ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) { + + /* + * BT is sleeping. Check if BT wakes up during + * WLAN calibration. If BT wakes up during + * WLAN calibration, need to go through all + * message exchanges again and recal. + */ + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | + AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE); + + ar9003_mci_remote_reset(ah, true); + ar9003_mci_send_sys_waking(ah, true); + udelay(1); + + if (IS_CHAN_2GHZ(chan)) + ar9003_mci_send_lna_transfer(ah, true); + + mci_hw->bt_state = MCI_BT_AWAKE; + + if (caldata) { + caldata->done_txiqcal_once = false; + caldata->done_txclcal_once = false; + caldata->rtt_hist.num_readings = 0; + } + + if (!ath9k_hw_init_cal(ah, chan)) + return -EIO; + + } +exit: + ar9003_mci_enable_interrupt(ah); + return 0; +} + +static void ar9003_mci_mute_bt(struct ath_hw *ah) +{ + /* disable all MCI messages */ + REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff); + REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); + + /* wait pending HW messages to flush out */ + udelay(10); /* - * GPM buffer and scheduling message buffer are not allocated + * Send LNA_TAKE and SYS_SLEEPING when + * 1. reset not after resuming from full sleep + * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment */ + ar9003_mci_send_lna_take(ah, true); + + udelay(5); + + ar9003_mci_send_sys_sleeping(ah, true); +} + +static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable) +{ + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 thresh; + + if (enable) { + REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, + AR_MCI_SCHD_TABLE_2_HW_BASED, 1); + REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, + AR_MCI_SCHD_TABLE_2_MEM_BASED, 1); + + if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) { + thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH); + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, + AR_BTCOEX_CTRL_AGGR_THRESH, thresh); + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, + AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1); + } else { + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, + AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0); + } + + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, + AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1); + } else { + REG_CLR_BIT(ah, AR_BTCOEX_CTRL, + AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + } +} + +void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, + bool is_full_sleep) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 regval; + + ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n", + is_full_sleep, is_2g); if (!mci->gpm_addr && !mci->sched_addr) { ath_dbg(common, MCI, @@ -568,7 +840,7 @@ void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, } if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) { - ath_dbg(common, MCI, "MCI it's deadbeef, quit mci_reset\n"); + ath_dbg(common, MCI, "BTCOEX control register is dead\n"); return; } @@ -592,49 +864,23 @@ void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); - if (is_2g && (AR_SREV_9462_20(ah)) && - !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) { - - regval |= SM(1, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); - ath_dbg(common, MCI, "MCI sched one step look ahead\n"); - - if (!(mci->config & - ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) { - - thresh = MS(mci->config, - ATH_MCI_CONFIG_AGGR_THRESH); - thresh &= 7; - regval |= SM(1, - AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN); - regval |= SM(thresh, AR_BTCOEX_CTRL_AGGR_THRESH); - - REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, - AR_MCI_SCHD_TABLE_2_HW_BASED, 1); - REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, - AR_MCI_SCHD_TABLE_2_MEM_BASED, 1); - - } else - ath_dbg(common, MCI, "MCI sched aggr thresh: off\n"); - } else - ath_dbg(common, MCI, "MCI SCHED one step look ahead off\n"); - - if (AR_SREV_9462_10(ah)) - regval |= SM(1, AR_BTCOEX_CTRL_SPDT_ENABLE_10); - REG_WRITE(ah, AR_BTCOEX_CTRL, regval); - if (AR_SREV_9462_20(ah)) { - REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, - AR_BTCOEX_CTRL_SPDT_ENABLE); - REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3, - AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20); - } + if (is_2g && !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) + ar9003_mci_osla_setup(ah, true); + else + ar9003_mci_osla_setup(ah, false); + + REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, + AR_BTCOEX_CTRL_SPDT_ENABLE); + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3, + AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20); REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1); REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); - thresh = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV); - REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, thresh); + regval = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV); + REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, regval); REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN); /* Resetting the Rx and Tx paths of MCI */ @@ -659,15 +905,15 @@ void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, REG_WRITE(ah, AR_MCI_COMMAND2, regval); ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL); + REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) | SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM))); REG_CLR_BIT(ah, AR_MCI_TX_CTRL, - AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); + AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); - if (AR_SREV_9462_20_OR_LATER(ah)) - ar9003_mci_observation_set_up(ah); + ar9003_mci_observation_set_up(ah); mci->ready = true; ar9003_mci_prep_interface(ah); @@ -676,79 +922,28 @@ void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, ar9003_mci_enable_interrupt(ah); } -void ar9003_mci_mute_bt(struct ath_hw *ah) -{ - struct ath_common *common = ath9k_hw_common(ah); - - if (!ATH9K_HW_CAP_MCI) - return; - - /* disable all MCI messages */ - REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000); - REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff); - REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff); - REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff); - REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff); - REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); - - /* wait pending HW messages to flush out */ - udelay(10); - - /* - * Send LNA_TAKE and SYS_SLEEPING when - * 1. reset not after resuming from full sleep - * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment - */ - - ath_dbg(common, MCI, "MCI Send LNA take\n"); - ar9003_mci_send_lna_take(ah, true); - - udelay(5); - - ath_dbg(common, MCI, "MCI Send sys sleeping\n"); - ar9003_mci_send_sys_sleeping(ah, true); -} - -void ar9003_mci_sync_bt_state(struct ath_hw *ah) +void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep) { - struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - u32 cur_bt_state; - - if (!ATH9K_HW_CAP_MCI) - return; + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; - cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL); + ar9003_mci_disable_interrupt(ah); - if (mci->bt_state != cur_bt_state) { - ath_dbg(common, MCI, - "MCI BT state mismatches. old: %d, new: %d\n", - mci->bt_state, cur_bt_state); - mci->bt_state = cur_bt_state; + if (mci_hw->ready && !save_fullsleep) { + ar9003_mci_mute_bt(ah); + udelay(20); + REG_WRITE(ah, AR_BTCOEX_CTRL, 0); } - if (mci->bt_state != MCI_BT_SLEEP) { - - ar9003_mci_send_coex_version_query(ah, true); - ar9003_mci_send_coex_wlan_channels(ah, true); - - if (mci->unhalt_bt_gpm == true) { - ath_dbg(common, MCI, "MCI unhalt BT GPM\n"); - ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); - } - } + mci_hw->bt_state = MCI_BT_SLEEP; + mci_hw->ready = false; } static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done) { - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 new_flags, to_set, to_clear; - if (AR_SREV_9462_20(ah) && - mci->update_2g5g && - (mci->bt_state != MCI_BT_SLEEP)) { - + if (mci->update_2g5g && (mci->bt_state != MCI_BT_SLEEP)) { if (mci->is_2g) { new_flags = MCI_2G_FLAGS; to_clear = MCI_2G_FLAGS_CLEAR_MASK; @@ -759,44 +954,23 @@ static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done) to_set = MCI_5G_FLAGS_SET_MASK; } - ath_dbg(common, MCI, - "MCI BT_MCI_FLAGS: %s 0x%08x clr=0x%08x, set=0x%08x\n", - mci->is_2g ? "2G" : "5G", new_flags, to_clear, to_set); - if (to_clear) ar9003_mci_send_coex_bt_flags(ah, wait_done, - MCI_GPM_COEX_BT_FLAGS_CLEAR, to_clear); - + MCI_GPM_COEX_BT_FLAGS_CLEAR, + to_clear); if (to_set) ar9003_mci_send_coex_bt_flags(ah, wait_done, - MCI_GPM_COEX_BT_FLAGS_SET, to_set); + MCI_GPM_COEX_BT_FLAGS_SET, + to_set); } - - if (AR_SREV_9462_10(ah) && (mci->bt_state != MCI_BT_SLEEP)) - mci->update_2g5g = false; } static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header, u32 *payload, bool queue) { - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u8 type, opcode; - if (queue) { - - if (payload) - ath_dbg(common, MCI, - "MCI ERROR: Send fail: %02x: %02x %02x %02x\n", - header, - *(((u8 *)payload) + 4), - *(((u8 *)payload) + 5), - *(((u8 *)payload) + 6)); - else - ath_dbg(common, MCI, "MCI ERROR: Send fail: %02x\n", - header); - } - /* check if the message is to be queued */ if (header != MCI_GPM) return; @@ -809,64 +983,29 @@ static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header, switch (opcode) { case MCI_GPM_COEX_BT_UPDATE_FLAGS: - - if (AR_SREV_9462_10(ah)) - break; - if (*(((u8 *)payload) + MCI_GPM_COEX_B_BT_FLAGS_OP) == - MCI_GPM_COEX_BT_FLAGS_READ) + MCI_GPM_COEX_BT_FLAGS_READ) break; mci->update_2g5g = queue; - if (queue) - ath_dbg(common, MCI, - "MCI BT_MCI_FLAGS: 2G5G status <queued> %s\n", - mci->is_2g ? "2G" : "5G"); - else - ath_dbg(common, MCI, - "MCI BT_MCI_FLAGS: 2G5G status <sent> %s\n", - mci->is_2g ? "2G" : "5G"); - break; - case MCI_GPM_COEX_WLAN_CHANNELS: - mci->wlan_channels_update = queue; - if (queue) - ath_dbg(common, MCI, "MCI WLAN channel map <queued>\n"); - else - ath_dbg(common, MCI, "MCI WLAN channel map <sent>\n"); break; - case MCI_GPM_COEX_HALT_BT_GPM: - if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) == - MCI_GPM_COEX_BT_GPM_UNHALT) { - + MCI_GPM_COEX_BT_GPM_UNHALT) { mci->unhalt_bt_gpm = queue; - if (queue) - ath_dbg(common, MCI, - "MCI UNHALT BT GPM <queued>\n"); - else { + if (!queue) mci->halted_bt_gpm = false; - ath_dbg(common, MCI, - "MCI UNHALT BT GPM <sent>\n"); - } } if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) == MCI_GPM_COEX_BT_GPM_HALT) { mci->halted_bt_gpm = !queue; - - if (queue) - ath_dbg(common, MCI, - "MCI HALT BT GPM <not sent>\n"); - else - ath_dbg(common, MCI, - "MCI UNHALT BT GPM <sent>\n"); } break; @@ -877,46 +1016,33 @@ static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header, void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done) { - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - if (!ATH9K_HW_CAP_MCI) - return; - if (mci->update_2g5g) { if (mci->is_2g) { - ar9003_mci_send_2g5g_status(ah, true); - ath_dbg(common, MCI, "MCI Send LNA trans\n"); ar9003_mci_send_lna_transfer(ah, true); udelay(5); REG_CLR_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); + REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL, + AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); - if (AR_SREV_9462_20(ah)) { - REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL, - AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); - if (!(mci->config & - ATH_MCI_CONFIG_DISABLE_OSLA)) { - REG_SET_BIT(ah, AR_BTCOEX_CTRL, - AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); - } + if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) { + REG_SET_BIT(ah, AR_BTCOEX_CTRL, + AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); } } else { - ath_dbg(common, MCI, "MCI Send LNA take\n"); ar9003_mci_send_lna_take(ah, true); udelay(5); REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); - - if (AR_SREV_9462_20(ah)) { - REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, - AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); - REG_CLR_BIT(ah, AR_BTCOEX_CTRL, - AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); - } + REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, + AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); + REG_CLR_BIT(ah, AR_BTCOEX_CTRL, + AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); ar9003_mci_send_2g5g_status(ah, true); } @@ -934,28 +1060,19 @@ bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag, u32 saved_mci_int_en; int i; - if (!ATH9K_HW_CAP_MCI) - return false; - saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN); regval = REG_READ(ah, AR_BTCOEX_CTRL); if ((regval == 0xdeadbeef) || !(regval & AR_BTCOEX_CTRL_MCI_MODE_EN)) { - ath_dbg(common, MCI, "MCI Not sending 0x%x. MCI is not enabled. full_sleep = %d\n", - header, - (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0); - + header, (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0); ar9003_mci_queue_unsent_gpm(ah, header, payload, true); return false; - } else if (check_bt && (mci->bt_state == MCI_BT_SLEEP)) { - ath_dbg(common, MCI, "MCI Don't send message 0x%x. BT is in sleep state\n", header); - ar9003_mci_queue_unsent_gpm(ah, header, payload, true); return false; } @@ -983,7 +1100,7 @@ bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag, if (wait_done && !(ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RAW, - AR_MCI_INTERRUPT_SW_MSG_DONE, 500))) + AR_MCI_INTERRUPT_SW_MSG_DONE, 500))) ar9003_mci_queue_unsent_gpm(ah, header, payload, true); else { ar9003_mci_queue_unsent_gpm(ah, header, payload, false); @@ -997,220 +1114,64 @@ bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag, } EXPORT_SYMBOL(ar9003_mci_send_message); -void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, - u16 len, u32 sched_addr) +void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable) { - struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - void *sched_buf = (void *)((char *) gpm_buf + (sched_addr - gpm_addr)); + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; + u32 pld[4] = {0, 0, 0, 0}; - if (!ATH9K_HW_CAP_MCI) + if ((mci_hw->bt_state != MCI_BT_AWAKE) || + (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) return; - mci->gpm_addr = gpm_addr; - mci->gpm_buf = gpm_buf; - mci->gpm_len = len; - mci->sched_addr = sched_addr; - mci->sched_buf = sched_buf; + MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ); + pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++; - ar9003_mci_reset(ah, true, true, true); + ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); + + if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) { + ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n"); + } else { + is_reusable = false; + ath_dbg(common, MCI, "MCI BT_CAL_GRANT not received\n"); + } } -EXPORT_SYMBOL(ar9003_mci_setup); -void ar9003_mci_cleanup(struct ath_hw *ah) +void ar9003_mci_init_cal_done(struct ath_hw *ah) { - struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; + u32 pld[4] = {0, 0, 0, 0}; - if (!ATH9K_HW_CAP_MCI) + if ((mci_hw->bt_state != MCI_BT_AWAKE) || + (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) return; - /* Turn off MCI and Jupiter mode. */ - REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00); - ath_dbg(common, MCI, "MCI ar9003_mci_cleanup\n"); - ar9003_mci_disable_interrupt(ah); + MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE); + pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++; + ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); } -EXPORT_SYMBOL(ar9003_mci_cleanup); -static void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type, - u8 gpm_opcode, u32 *p_gpm) +void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, + u16 len, u32 sched_addr) { - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - u8 *p_data = (u8 *) p_gpm; - if (gpm_type != MCI_GPM_COEX_AGENT) - return; + mci->gpm_addr = gpm_addr; + mci->gpm_buf = gpm_buf; + mci->gpm_len = len; + mci->sched_addr = sched_addr; - switch (gpm_opcode) { - case MCI_GPM_COEX_VERSION_QUERY: - ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n"); - ar9003_mci_send_coex_version_response(ah, true); - break; - case MCI_GPM_COEX_VERSION_RESPONSE: - ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n"); - mci->bt_ver_major = - *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION); - mci->bt_ver_minor = - *(p_data + MCI_GPM_COEX_B_MINOR_VERSION); - mci->bt_version_known = true; - ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n", - mci->bt_ver_major, mci->bt_ver_minor); - break; - case MCI_GPM_COEX_STATUS_QUERY: - ath_dbg(common, MCI, - "MCI Recv GPM COEX Status Query = 0x%02X\n", - *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP)); - mci->wlan_channels_update = true; - ar9003_mci_send_coex_wlan_channels(ah, true); - break; - case MCI_GPM_COEX_BT_PROFILE_INFO: - mci->query_bt = true; - ath_dbg(common, MCI, "MCI Recv GPM COEX BT_Profile_Info\n"); - break; - case MCI_GPM_COEX_BT_STATUS_UPDATE: - mci->query_bt = true; - ath_dbg(common, MCI, - "MCI Recv GPM COEX BT_Status_Update SEQ=%d (drop&query)\n", - *(p_gpm + 3)); - break; - default: - break; - } + ar9003_mci_reset(ah, true, true, true); } +EXPORT_SYMBOL(ar9003_mci_setup); -u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, - u8 gpm_opcode, int time_out) +void ar9003_mci_cleanup(struct ath_hw *ah) { - struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - u32 *p_gpm = NULL, mismatch = 0, more_data; - u32 offset; - u8 recv_type = 0, recv_opcode = 0; - bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE); - - if (!ATH9K_HW_CAP_MCI) - return 0; - - more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE; - - while (time_out > 0) { - if (p_gpm) { - MCI_GPM_RECYCLE(p_gpm); - p_gpm = NULL; - } - - if (more_data != MCI_GPM_MORE) - time_out = ar9003_mci_wait_for_interrupt(ah, - AR_MCI_INTERRUPT_RX_MSG_RAW, - AR_MCI_INTERRUPT_RX_MSG_GPM, - time_out); - - if (!time_out) - break; - - offset = ar9003_mci_state(ah, - MCI_STATE_NEXT_GPM_OFFSET, &more_data); - - if (offset == MCI_GPM_INVALID) - continue; - - p_gpm = (u32 *) (mci->gpm_buf + offset); - recv_type = MCI_GPM_TYPE(p_gpm); - recv_opcode = MCI_GPM_OPCODE(p_gpm); - - if (MCI_GPM_IS_CAL_TYPE(recv_type)) { - - if (recv_type == gpm_type) { - - if ((gpm_type == MCI_GPM_BT_CAL_DONE) && - !b_is_bt_cal_done) { - gpm_type = MCI_GPM_BT_CAL_GRANT; - ath_dbg(common, MCI, - "MCI Recv BT_CAL_DONE wait BT_CAL_GRANT\n"); - continue; - } - - break; - } - } else if ((recv_type == gpm_type) && - (recv_opcode == gpm_opcode)) - break; - - /* not expected message */ - - /* - * check if it's cal_grant - * - * When we're waiting for cal_grant in reset routine, - * it's possible that BT sends out cal_request at the - * same time. Since BT's calibration doesn't happen - * that often, we'll let BT completes calibration then - * we continue to wait for cal_grant from BT. - * Orginal: Wait BT_CAL_GRANT. - * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait - * BT_CAL_DONE -> Wait BT_CAL_GRANT. - */ - - if ((gpm_type == MCI_GPM_BT_CAL_GRANT) && - (recv_type == MCI_GPM_BT_CAL_REQ)) { - - u32 payload[4] = {0, 0, 0, 0}; - - gpm_type = MCI_GPM_BT_CAL_DONE; - ath_dbg(common, MCI, - "MCI Rcv BT_CAL_REQ, send WLAN_CAL_GRANT\n"); - - MCI_GPM_SET_CAL_TYPE(payload, - MCI_GPM_WLAN_CAL_GRANT); - - ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, - false, false); - - ath_dbg(common, MCI, "MCI now wait for BT_CAL_DONE\n"); - - continue; - } else { - ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n", - *(p_gpm + 1)); - mismatch++; - ar9003_mci_process_gpm_extra(ah, recv_type, - recv_opcode, p_gpm); - } - } - if (p_gpm) { - MCI_GPM_RECYCLE(p_gpm); - p_gpm = NULL; - } - - if (time_out <= 0) { - time_out = 0; - ath_dbg(common, MCI, - "MCI GPM received timeout, mismatch = %d\n", mismatch); - } else - ath_dbg(common, MCI, "MCI Receive GPM type=0x%x, code=0x%x\n", - gpm_type, gpm_opcode); - - while (more_data == MCI_GPM_MORE) { - - ath_dbg(common, MCI, "MCI discard remaining GPM\n"); - offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET, - &more_data); - - if (offset == MCI_GPM_INVALID) - break; - - p_gpm = (u32 *) (mci->gpm_buf + offset); - recv_type = MCI_GPM_TYPE(p_gpm); - recv_opcode = MCI_GPM_OPCODE(p_gpm); - - if (!MCI_GPM_IS_CAL_TYPE(recv_type)) - ar9003_mci_process_gpm_extra(ah, recv_type, - recv_opcode, p_gpm); - - MCI_GPM_RECYCLE(p_gpm); - } - - return time_out; + /* Turn off MCI and Jupiter mode. */ + REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00); + ar9003_mci_disable_interrupt(ah); } +EXPORT_SYMBOL(ar9003_mci_cleanup); u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) { @@ -1219,13 +1180,9 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) u32 value = 0, more_gpm = 0, gpm_ptr; u8 query_type; - if (!ATH9K_HW_CAP_MCI) - return 0; - switch (state_type) { case MCI_STATE_ENABLE: if (mci->ready) { - value = REG_READ(ah, AR_BTCOEX_CTRL); if ((value == 0xdeadbeef) || (value == 0xffffffff)) @@ -1235,7 +1192,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) break; case MCI_STATE_INIT_GPM_OFFSET: value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); - ath_dbg(common, MCI, "MCI GPM initial WRITE_PTR=%d\n", value); mci->gpm_idx = value; break; case MCI_STATE_NEXT_GPM_OFFSET: @@ -1258,32 +1214,21 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) if (value == 0) value = mci->gpm_len - 1; else if (value >= mci->gpm_len) { - if (value != 0xFFFF) { + if (value != 0xFFFF) value = 0; - ath_dbg(common, MCI, - "MCI GPM offset out of range\n"); - } - } else + } else { value--; + } if (value == 0xFFFF) { value = MCI_GPM_INVALID; more_gpm = MCI_GPM_NOMORE; - ath_dbg(common, MCI, - "MCI GPM ptr invalid @ptr=%d, offset=%d, more=GPM_NOMORE\n", - gpm_ptr, value); } else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) { - if (gpm_ptr == mci->gpm_idx) { value = MCI_GPM_INVALID; more_gpm = MCI_GPM_NOMORE; - - ath_dbg(common, MCI, - "MCI GPM message not available @ptr=%d, @offset=%d, more=GPM_NOMORE\n", - gpm_ptr, value); } else { for (;;) { - u32 temp_index; /* skip reserved GPM if any */ @@ -1300,13 +1245,8 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) mci->gpm_len) mci->gpm_idx = 0; - ath_dbg(common, MCI, - "MCI GPM message got ptr=%d, @offset=%d, more=%d\n", - gpm_ptr, temp_index, - (more_gpm == MCI_GPM_MORE)); - if (ar9003_mci_is_gpm_valid(ah, - temp_index)) { + temp_index)) { value = temp_index; break; } @@ -1331,79 +1271,59 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) /* Make it in bytes */ value <<= 4; break; - case MCI_STATE_REMOTE_SLEEP: value = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_REMOTE_SLEEP) ? MCI_BT_SLEEP : MCI_BT_AWAKE; break; - case MCI_STATE_CONT_RSSI_POWER: value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER); - break; - + break; case MCI_STATE_CONT_PRIORITY: value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY); break; - case MCI_STATE_CONT_TXRX: value = MS(mci->cont_status, AR_MCI_CONT_TXRX); break; - case MCI_STATE_BT: value = mci->bt_state; break; - case MCI_STATE_SET_BT_SLEEP: mci->bt_state = MCI_BT_SLEEP; break; - case MCI_STATE_SET_BT_AWAKE: mci->bt_state = MCI_BT_AWAKE; ar9003_mci_send_coex_version_query(ah, true); ar9003_mci_send_coex_wlan_channels(ah, true); - if (mci->unhalt_bt_gpm) { - - ath_dbg(common, MCI, "MCI unhalt BT GPM\n"); + if (mci->unhalt_bt_gpm) ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); - } ar9003_mci_2g5g_switch(ah, true); break; - case MCI_STATE_SET_BT_CAL_START: mci->bt_state = MCI_BT_CAL_START; break; - case MCI_STATE_SET_BT_CAL: mci->bt_state = MCI_BT_CAL; break; - case MCI_STATE_RESET_REQ_WAKE: ar9003_mci_reset_req_wakeup(ah); mci->update_2g5g = true; - if ((AR_SREV_9462_20_OR_LATER(ah)) && - (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK)) { + if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK) { /* Check if we still have control of the GPIOs */ if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) & - ATH_MCI_CONFIG_MCI_OBS_GPIO) != - ATH_MCI_CONFIG_MCI_OBS_GPIO) { - - ath_dbg(common, MCI, - "MCI reconfigure observation\n"); + ATH_MCI_CONFIG_MCI_OBS_GPIO) != + ATH_MCI_CONFIG_MCI_OBS_GPIO) { ar9003_mci_observation_set_up(ah); } } break; - case MCI_STATE_SEND_WLAN_COEX_VERSION: ar9003_mci_send_coex_version_response(ah, true); break; - case MCI_STATE_SET_BT_COEX_VERSION: - if (!p_data) ath_dbg(common, MCI, "MCI Set BT Coex version with NULL data!!\n"); @@ -1415,7 +1335,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) mci->bt_ver_major, mci->bt_ver_minor); } break; - case MCI_STATE_SEND_WLAN_CHANNELS: if (p_data) { if (((mci->wlan_channels[1] & 0xffff0000) == @@ -1432,19 +1351,13 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) mci->wlan_channels_update = true; ar9003_mci_send_coex_wlan_channels(ah, true); break; - case MCI_STATE_SEND_VERSION_QUERY: ar9003_mci_send_coex_version_query(ah, true); break; - case MCI_STATE_SEND_STATUS_QUERY: - query_type = (AR_SREV_9462_10(ah)) ? - MCI_GPM_COEX_QUERY_BT_ALL_INFO : - MCI_GPM_COEX_QUERY_BT_TOPOLOGY; - + query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY; ar9003_mci_send_coex_bt_status_query(ah, true, query_type); break; - case MCI_STATE_NEED_FLUSH_BT_INFO: /* * btcoex_hw.mci.unhalt_bt_gpm means whether it's @@ -1464,28 +1377,21 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) mci->need_flush_btinfo = (*p_data != 0) ? true : false; break; - case MCI_STATE_RECOVER_RX: - - ath_dbg(common, MCI, "MCI hw RECOVER_RX\n"); ar9003_mci_prep_interface(ah); mci->query_bt = true; mci->need_flush_btinfo = true; ar9003_mci_send_coex_wlan_channels(ah, true); ar9003_mci_2g5g_switch(ah, true); break; - case MCI_STATE_NEED_FTP_STOMP: value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); break; - case MCI_STATE_NEED_TUNING: value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING); break; - default: break; - } return value; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h index 798da116a44c..4842f6c06b8c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h @@ -99,4 +99,237 @@ enum mci_gpm_coex_bt_update_flags_op { ATH_MCI_CONFIG_MCI_OBS_BT) #define ATH_MCI_CONFIG_MCI_OBS_GPIO 0x0000002F +enum mci_message_header { /* length of payload */ + MCI_LNA_CTRL = 0x10, /* len = 0 */ + MCI_CONT_NACK = 0x20, /* len = 0 */ + MCI_CONT_INFO = 0x30, /* len = 4 */ + MCI_CONT_RST = 0x40, /* len = 0 */ + MCI_SCHD_INFO = 0x50, /* len = 16 */ + MCI_CPU_INT = 0x60, /* len = 4 */ + MCI_SYS_WAKING = 0x70, /* len = 0 */ + MCI_GPM = 0x80, /* len = 16 */ + MCI_LNA_INFO = 0x90, /* len = 1 */ + MCI_LNA_STATE = 0x94, + MCI_LNA_TAKE = 0x98, + MCI_LNA_TRANS = 0x9c, + MCI_SYS_SLEEPING = 0xa0, /* len = 0 */ + MCI_REQ_WAKE = 0xc0, /* len = 0 */ + MCI_DEBUG_16 = 0xfe, /* len = 2 */ + MCI_REMOTE_RESET = 0xff /* len = 16 */ +}; + +enum ath_mci_gpm_coex_profile_type { + MCI_GPM_COEX_PROFILE_UNKNOWN, + MCI_GPM_COEX_PROFILE_RFCOMM, + MCI_GPM_COEX_PROFILE_A2DP, + MCI_GPM_COEX_PROFILE_HID, + MCI_GPM_COEX_PROFILE_BNEP, + MCI_GPM_COEX_PROFILE_VOICE, + MCI_GPM_COEX_PROFILE_MAX +}; + +/* MCI GPM/Coex opcode/type definitions */ +enum { + MCI_GPM_COEX_W_GPM_PAYLOAD = 1, + MCI_GPM_COEX_B_GPM_TYPE = 4, + MCI_GPM_COEX_B_GPM_OPCODE = 5, + /* MCI_GPM_WLAN_CAL_REQ, MCI_GPM_WLAN_CAL_DONE */ + MCI_GPM_WLAN_CAL_W_SEQUENCE = 2, + + /* MCI_GPM_COEX_VERSION_QUERY */ + /* MCI_GPM_COEX_VERSION_RESPONSE */ + MCI_GPM_COEX_B_MAJOR_VERSION = 6, + MCI_GPM_COEX_B_MINOR_VERSION = 7, + /* MCI_GPM_COEX_STATUS_QUERY */ + MCI_GPM_COEX_B_BT_BITMAP = 6, + MCI_GPM_COEX_B_WLAN_BITMAP = 7, + /* MCI_GPM_COEX_HALT_BT_GPM */ + MCI_GPM_COEX_B_HALT_STATE = 6, + /* MCI_GPM_COEX_WLAN_CHANNELS */ + MCI_GPM_COEX_B_CHANNEL_MAP = 6, + /* MCI_GPM_COEX_BT_PROFILE_INFO */ + MCI_GPM_COEX_B_PROFILE_TYPE = 6, + MCI_GPM_COEX_B_PROFILE_LINKID = 7, + MCI_GPM_COEX_B_PROFILE_STATE = 8, + MCI_GPM_COEX_B_PROFILE_ROLE = 9, + MCI_GPM_COEX_B_PROFILE_RATE = 10, + MCI_GPM_COEX_B_PROFILE_VOTYPE = 11, + MCI_GPM_COEX_H_PROFILE_T = 12, + MCI_GPM_COEX_B_PROFILE_W = 14, + MCI_GPM_COEX_B_PROFILE_A = 15, + /* MCI_GPM_COEX_BT_STATUS_UPDATE */ + MCI_GPM_COEX_B_STATUS_TYPE = 6, + MCI_GPM_COEX_B_STATUS_LINKID = 7, + MCI_GPM_COEX_B_STATUS_STATE = 8, + /* MCI_GPM_COEX_BT_UPDATE_FLAGS */ + MCI_GPM_COEX_W_BT_FLAGS = 6, + MCI_GPM_COEX_B_BT_FLAGS_OP = 10 +}; + +enum mci_gpm_subtype { + MCI_GPM_BT_CAL_REQ = 0, + MCI_GPM_BT_CAL_GRANT = 1, + MCI_GPM_BT_CAL_DONE = 2, + MCI_GPM_WLAN_CAL_REQ = 3, + MCI_GPM_WLAN_CAL_GRANT = 4, + MCI_GPM_WLAN_CAL_DONE = 5, + MCI_GPM_COEX_AGENT = 0x0c, + MCI_GPM_RSVD_PATTERN = 0xfe, + MCI_GPM_RSVD_PATTERN32 = 0xfefefefe, + MCI_GPM_BT_DEBUG = 0xff +}; + +enum mci_bt_state { + MCI_BT_SLEEP, + MCI_BT_AWAKE, + MCI_BT_CAL_START, + MCI_BT_CAL +}; + +/* Type of state query */ +enum mci_state_type { + MCI_STATE_ENABLE, + MCI_STATE_INIT_GPM_OFFSET, + MCI_STATE_NEXT_GPM_OFFSET, + MCI_STATE_LAST_GPM_OFFSET, + MCI_STATE_BT, + MCI_STATE_SET_BT_SLEEP, + MCI_STATE_SET_BT_AWAKE, + MCI_STATE_SET_BT_CAL_START, + MCI_STATE_SET_BT_CAL, + MCI_STATE_LAST_SCHD_MSG_OFFSET, + MCI_STATE_REMOTE_SLEEP, + MCI_STATE_CONT_RSSI_POWER, + MCI_STATE_CONT_PRIORITY, + MCI_STATE_CONT_TXRX, + MCI_STATE_RESET_REQ_WAKE, + MCI_STATE_SEND_WLAN_COEX_VERSION, + MCI_STATE_SET_BT_COEX_VERSION, + MCI_STATE_SEND_WLAN_CHANNELS, + MCI_STATE_SEND_VERSION_QUERY, + MCI_STATE_SEND_STATUS_QUERY, + MCI_STATE_NEED_FLUSH_BT_INFO, + MCI_STATE_SET_CONCUR_TX_PRI, + MCI_STATE_RECOVER_RX, + MCI_STATE_NEED_FTP_STOMP, + MCI_STATE_NEED_TUNING, + MCI_STATE_DEBUG, + MCI_STATE_MAX +}; + +enum mci_gpm_coex_opcode { + MCI_GPM_COEX_VERSION_QUERY, + MCI_GPM_COEX_VERSION_RESPONSE, + MCI_GPM_COEX_STATUS_QUERY, + MCI_GPM_COEX_HALT_BT_GPM, + MCI_GPM_COEX_WLAN_CHANNELS, + MCI_GPM_COEX_BT_PROFILE_INFO, + MCI_GPM_COEX_BT_STATUS_UPDATE, + MCI_GPM_COEX_BT_UPDATE_FLAGS +}; + +#define MCI_GPM_NOMORE 0 +#define MCI_GPM_MORE 1 +#define MCI_GPM_INVALID 0xffffffff + +#define MCI_GPM_RECYCLE(_p_gpm) do { \ + *(((u32 *)_p_gpm) + MCI_GPM_COEX_W_GPM_PAYLOAD) = \ + MCI_GPM_RSVD_PATTERN32; \ +} while (0) + +#define MCI_GPM_TYPE(_p_gpm) \ + (*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) & 0xff) + +#define MCI_GPM_OPCODE(_p_gpm) \ + (*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) & 0xff) + +#define MCI_GPM_SET_CAL_TYPE(_p_gpm, _cal_type) do { \ + *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_cal_type) & 0xff;\ +} while (0) + +#define MCI_GPM_SET_TYPE_OPCODE(_p_gpm, _type, _opcode) do { \ + *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_type) & 0xff; \ + *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) = (_opcode) & 0xff;\ +} while (0) + +#define MCI_GPM_IS_CAL_TYPE(_type) ((_type) <= MCI_GPM_WLAN_CAL_DONE) + +/* + * Functions that are available to the MCI driver core. + */ +bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag, + u32 *payload, u8 len, bool wait_done, + bool check_bt); +u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data); +void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, + u16 len, u32 sched_addr); +void ar9003_mci_cleanup(struct ath_hw *ah); +void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, + u32 *rx_msg_intr); + +/* + * These functions are used by ath9k_hw. + */ + +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + +static inline bool ar9003_mci_is_ready(struct ath_hw *ah) +{ + return ah->btcoex_hw.mci.ready; +} +void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep); +void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable); +void ar9003_mci_init_cal_done(struct ath_hw *ah); +void ar9003_mci_set_full_sleep(struct ath_hw *ah); +void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done); +void ar9003_mci_check_bt(struct ath_hw *ah); +bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan); +int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, + struct ath9k_hw_cal_data *caldata); +void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, + bool is_full_sleep); +void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked); + +#else + +static inline bool ar9003_mci_is_ready(struct ath_hw *ah) +{ + return false; +} +static inline void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep) +{ +} +static inline void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable) +{ +} +static inline void ar9003_mci_init_cal_done(struct ath_hw *ah) +{ +} +static inline void ar9003_mci_set_full_sleep(struct ath_hw *ah) +{ +} +static inline void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done) +{ +} +static inline void ar9003_mci_check_bt(struct ath_hw *ah) +{ +} +static inline bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan) +{ + return false; +} +static inline int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, + struct ath9k_hw_cal_data *caldata) +{ + return 0; +} +static inline void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, + bool is_full_sleep) +{ +} +static inline void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked) +{ +} +#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ + #endif diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 2b0bfb8cca02..bc992b237ae5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -679,18 +679,17 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, * different modal values. */ if (IS_CHAN_A_FAST_CLOCK(ah, chan)) - REG_WRITE_ARRAY(&ah->iniModesAdditional, + REG_WRITE_ARRAY(&ah->iniModesFastClock, modesIndex, regWrites); - if (AR_SREV_9330(ah)) - REG_WRITE_ARRAY(&ah->iniModesAdditional, 1, regWrites); - - if (AR_SREV_9340(ah) && !ah->is_clk_25mhz) - REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites); + REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites); if (AR_SREV_9462(ah)) ar9003_hw_prog_ini(ah, &ah->ini_BTCOEX_MAX_TXPWR, 1); + if (chan->channel == 2484) + ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1); + ah->modes_index = modesIndex; ar9003_hw_override_ini(ah); ar9003_hw_set_channel_regs(ah, chan); @@ -1099,13 +1098,20 @@ static void ar9003_hw_set_nf_limits(struct ath_hw *ah) { ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ; ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ; - if (AR_SREV_9330(ah)) - ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9330_2GHZ; - else - ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9300_2GHZ; + ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9300_2GHZ; ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ; ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ; ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9300_5GHZ; + + if (AR_SREV_9330(ah)) + ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9330_2GHZ; + + if (AR_SREV_9462(ah)) { + ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9462_2GHZ; + ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9462_2GHZ; + ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9462_5GHZ; + ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9462_5GHZ; + } } /* @@ -1313,13 +1319,9 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah, * different modal values. */ if (IS_CHAN_A_FAST_CLOCK(ah, chan)) - REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites); - - if (AR_SREV_9330(ah)) - REG_WRITE_ARRAY(&ah->iniModesAdditional, 1, regWrites); + REG_WRITE_ARRAY(&ah->iniModesFastClock, modesIndex, regWrites); - if (AR_SREV_9340(ah) && !ah->is_clk_25mhz) - REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites); + REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites); ah->modes_index = modesIndex; *ini_reloaded = true; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index ed64114571fc..d834d97fe727 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -325,13 +325,18 @@ #define AR_PHY_RX_OCGAIN (AR_AGC_BASE + 0x200) -#define AR_PHY_CCA_NOM_VAL_9300_2GHZ (AR_SREV_9462(ah) ? -127 : -110) -#define AR_PHY_CCA_NOM_VAL_9300_5GHZ (AR_SREV_9462(ah) ? -127 : -115) -#define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ (AR_SREV_9462(ah) ? -127 : -125) -#define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ (AR_SREV_9462(ah) ? -127 : -125) +#define AR_PHY_CCA_NOM_VAL_9300_2GHZ -110 +#define AR_PHY_CCA_NOM_VAL_9300_5GHZ -115 +#define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ -125 +#define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ -125 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ -95 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ -100 +#define AR_PHY_CCA_NOM_VAL_9462_2GHZ -127 +#define AR_PHY_CCA_MIN_GOOD_VAL_9462_2GHZ -127 +#define AR_PHY_CCA_NOM_VAL_9462_5GHZ -127 +#define AR_PHY_CCA_MIN_GOOD_VAL_9462_5GHZ -127 + #define AR_PHY_CCA_NOM_VAL_9330_2GHZ -118 /* @@ -612,16 +617,14 @@ #define AR_PHY_AIC_CTRL_1_B0 (AR_SM_BASE + 0x4b4) #define AR_PHY_AIC_CTRL_2_B0 (AR_SM_BASE + 0x4b8) #define AR_PHY_AIC_CTRL_3_B0 (AR_SM_BASE + 0x4bc) -#define AR_PHY_AIC_STAT_0_B0 (AR_SM_BASE + (AR_SREV_9462_10(ah) ? \ - 0x4c0 : 0x4c4)) -#define AR_PHY_AIC_STAT_1_B0 (AR_SM_BASE + (AR_SREV_9462_10(ah) ? \ - 0x4c4 : 0x4c8)) +#define AR_PHY_AIC_STAT_0_B0 (AR_SM_BASE + 0x4c4)) +#define AR_PHY_AIC_STAT_1_B0 (AR_SM_BASE + 0x4c8)) #define AR_PHY_AIC_CTRL_4_B0 (AR_SM_BASE + 0x4c0) #define AR_PHY_AIC_STAT_2_B0 (AR_SM_BASE + 0x4cc) #define AR_PHY_65NM_CH0_SYNTH4 0x1608c -#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT 0x00000002 -#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S 1 +#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT (AR_SREV_9462(ah) ? 0x00000001 : 0x00000002) +#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S (AR_SREV_9462(ah) ? 0 : 1) #define AR_PHY_65NM_CH0_SYNTH7 0x16098 #define AR_PHY_65NM_CH0_BIAS1 0x160c0 #define AR_PHY_65NM_CH0_BIAS2 0x160c4 diff --git a/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h deleted file mode 100644 index 5c55ae389adb..000000000000 --- a/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h +++ /dev/null @@ -1,1833 +0,0 @@ -/* - * Copyright (c) 2010 Atheros Communications 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_9462_1P0_H -#define INITVALS_9462_1P0_H - -/* AR9462 1.0 */ - -static const u32 ar9462_1p0_mac_core[][2] = { - /* Addr allmodes */ - {0x00000008, 0x00000000}, - {0x00000030, 0x00060085}, - {0x00000034, 0x00000005}, - {0x00000040, 0x00000000}, - {0x00000044, 0x00000000}, - {0x00000048, 0x00000008}, - {0x0000004c, 0x00000010}, - {0x00000050, 0x00000000}, - {0x00001040, 0x002ffc0f}, - {0x00001044, 0x002ffc0f}, - {0x00001048, 0x002ffc0f}, - {0x0000104c, 0x002ffc0f}, - {0x00001050, 0x002ffc0f}, - {0x00001054, 0x002ffc0f}, - {0x00001058, 0x002ffc0f}, - {0x0000105c, 0x002ffc0f}, - {0x00001060, 0x002ffc0f}, - {0x00001064, 0x002ffc0f}, - {0x000010f0, 0x00000100}, - {0x00001270, 0x00000000}, - {0x000012b0, 0x00000000}, - {0x000012f0, 0x00000000}, - {0x0000143c, 0x00000000}, - {0x0000147c, 0x00000000}, - {0x00001810, 0x0f000003}, - {0x00008000, 0x00000000}, - {0x00008004, 0x00000000}, - {0x00008008, 0x00000000}, - {0x0000800c, 0x00000000}, - {0x00008018, 0x00000000}, - {0x00008020, 0x00000000}, - {0x00008038, 0x00000000}, - {0x0000803c, 0x00080000}, - {0x00008040, 0x00000000}, - {0x00008044, 0x00000000}, - {0x00008048, 0x00000000}, - {0x0000804c, 0xffffffff}, - {0x00008050, 0xffffffff}, - {0x00008054, 0x00000000}, - {0x00008058, 0x00000000}, - {0x0000805c, 0x000fc78f}, - {0x00008060, 0x0000000f}, - {0x00008064, 0x00000000}, - {0x00008070, 0x00000310}, - {0x00008074, 0x00000020}, - {0x00008078, 0x00000000}, - {0x0000809c, 0x0000000f}, - {0x000080a0, 0x00000000}, - {0x000080a4, 0x02ff0000}, - {0x000080a8, 0x0e070605}, - {0x000080ac, 0x0000000d}, - {0x000080b0, 0x00000000}, - {0x000080b4, 0x00000000}, - {0x000080b8, 0x00000000}, - {0x000080bc, 0x00000000}, - {0x000080c0, 0x2a800000}, - {0x000080c4, 0x06900168}, - {0x000080c8, 0x13881c20}, - {0x000080cc, 0x01f40000}, - {0x000080d0, 0x00252500}, - {0x000080d4, 0x00a00005}, - {0x000080d8, 0x00400002}, - {0x000080dc, 0x00000000}, - {0x000080e0, 0xffffffff}, - {0x000080e4, 0x0000ffff}, - {0x000080e8, 0x3f3f3f3f}, - {0x000080ec, 0x00000000}, - {0x000080f0, 0x00000000}, - {0x000080f4, 0x00000000}, - {0x000080fc, 0x00020000}, - {0x00008100, 0x00000000}, - {0x00008108, 0x00000052}, - {0x0000810c, 0x00000000}, - {0x00008110, 0x00000000}, - {0x00008114, 0x000007ff}, - {0x00008118, 0x000000aa}, - {0x0000811c, 0x00003210}, - {0x00008124, 0x00000000}, - {0x00008128, 0x00000000}, - {0x0000812c, 0x00000000}, - {0x00008130, 0x00000000}, - {0x00008134, 0x00000000}, - {0x00008138, 0x00000000}, - {0x0000813c, 0x0000ffff}, - {0x00008144, 0xffffffff}, - {0x00008168, 0x00000000}, - {0x0000816c, 0x00000000}, - {0x00008170, 0x18486e00}, - {0x00008174, 0x33332210}, - {0x00008178, 0x00000000}, - {0x0000817c, 0x00020000}, - {0x000081c4, 0x33332210}, - {0x000081c8, 0x00000000}, - {0x000081cc, 0x00000000}, - {0x000081d4, 0x00000000}, - {0x000081ec, 0x00000000}, - {0x000081f0, 0x00000000}, - {0x000081f4, 0x00000000}, - {0x000081f8, 0x00000000}, - {0x000081fc, 0x00000000}, - {0x00008240, 0x00100000}, - {0x00008244, 0x0010f400}, - {0x00008248, 0x00000800}, - {0x0000824c, 0x0001e800}, - {0x00008250, 0x00000000}, - {0x00008254, 0x00000000}, - {0x00008258, 0x00000000}, - {0x0000825c, 0x40000000}, - {0x00008260, 0x00080922}, - {0x00008264, 0x99c00010}, - {0x00008268, 0xffffffff}, - {0x0000826c, 0x0000ffff}, - {0x00008270, 0x00000000}, - {0x00008274, 0x40000000}, - {0x00008278, 0x003e4180}, - {0x0000827c, 0x00000004}, - {0x00008284, 0x0000002c}, - {0x00008288, 0x0000002c}, - {0x0000828c, 0x000000ff}, - {0x00008294, 0x00000000}, - {0x00008298, 0x00000000}, - {0x0000829c, 0x00000000}, - {0x00008300, 0x00000140}, - {0x00008314, 0x00000000}, - {0x0000831c, 0x0000010d}, - {0x00008328, 0x00000000}, - {0x0000832c, 0x0000001f}, - {0x00008330, 0x00000302}, - {0x00008334, 0x00000700}, - {0x00008338, 0xffff0000}, - {0x0000833c, 0x02400000}, - {0x00008340, 0x000107ff}, - {0x00008344, 0xaa48105b}, - {0x00008348, 0x008f0000}, - {0x0000835c, 0x00000000}, - {0x00008360, 0xffffffff}, - {0x00008364, 0xffffffff}, - {0x00008368, 0x00000000}, - {0x00008370, 0x00000000}, - {0x00008374, 0x000000ff}, - {0x00008378, 0x00000000}, - {0x0000837c, 0x00000000}, - {0x00008380, 0xffffffff}, - {0x00008384, 0xffffffff}, - {0x00008390, 0xffffffff}, - {0x00008394, 0xffffffff}, - {0x00008398, 0x00000000}, - {0x0000839c, 0x00000000}, - {0x000083a4, 0x0000fa14}, - {0x000083a8, 0x000f0c00}, - {0x000083ac, 0x33332210}, - {0x000083b0, 0x33332210}, - {0x000083b4, 0x33332210}, - {0x000083b8, 0x33332210}, - {0x000083bc, 0x00000000}, - {0x000083c0, 0x00000000}, - {0x000083c4, 0x00000000}, - {0x000083c8, 0x00000000}, - {0x000083cc, 0x00000200}, - {0x000083d0, 0x000301ff}, -}; - -static const u32 ar9462_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { - /* Addr allmodes */ - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x6f7f0301}, - {0x0000a3a0, 0xca9228ee}, -}; - -static const u32 ar9462_1p0_sys3ant[][2] = { - /* Addr allmodes */ - {0x00063280, 0x00040807}, - {0x00063284, 0x104ccccc}, -}; - -static const u32 ar9462_pcie_phy_clkreq_enable_L1_1p0[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10053e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9462_1p0_mac_core_emulation[][2] = { - /* Addr allmodes */ - {0x00000030, 0x00060085}, - {0x00000044, 0x00000008}, - {0x0000805c, 0xffffc7ff}, - {0x00008344, 0xaa4a105b}, -}; - -static const u32 ar9462_common_rx_gain_table_ar9280_2p0_1p0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x02000101}, - {0x0000a004, 0x02000102}, - {0x0000a008, 0x02000103}, - {0x0000a00c, 0x02000104}, - {0x0000a010, 0x02000200}, - {0x0000a014, 0x02000201}, - {0x0000a018, 0x02000202}, - {0x0000a01c, 0x02000203}, - {0x0000a020, 0x02000204}, - {0x0000a024, 0x02000205}, - {0x0000a028, 0x02000208}, - {0x0000a02c, 0x02000302}, - {0x0000a030, 0x02000303}, - {0x0000a034, 0x02000304}, - {0x0000a038, 0x02000400}, - {0x0000a03c, 0x02010300}, - {0x0000a040, 0x02010301}, - {0x0000a044, 0x02010302}, - {0x0000a048, 0x02000500}, - {0x0000a04c, 0x02010400}, - {0x0000a050, 0x02020300}, - {0x0000a054, 0x02020301}, - {0x0000a058, 0x02020302}, - {0x0000a05c, 0x02020303}, - {0x0000a060, 0x02020400}, - {0x0000a064, 0x02030300}, - {0x0000a068, 0x02030301}, - {0x0000a06c, 0x02030302}, - {0x0000a070, 0x02030303}, - {0x0000a074, 0x02030400}, - {0x0000a078, 0x02040300}, - {0x0000a07c, 0x02040301}, - {0x0000a080, 0x02040302}, - {0x0000a084, 0x02040303}, - {0x0000a088, 0x02030500}, - {0x0000a08c, 0x02040400}, - {0x0000a090, 0x02050203}, - {0x0000a094, 0x02050204}, - {0x0000a098, 0x02050205}, - {0x0000a09c, 0x02040500}, - {0x0000a0a0, 0x02050301}, - {0x0000a0a4, 0x02050302}, - {0x0000a0a8, 0x02050303}, - {0x0000a0ac, 0x02050400}, - {0x0000a0b0, 0x02050401}, - {0x0000a0b4, 0x02050402}, - {0x0000a0b8, 0x02050403}, - {0x0000a0bc, 0x02050500}, - {0x0000a0c0, 0x02050501}, - {0x0000a0c4, 0x02050502}, - {0x0000a0c8, 0x02050503}, - {0x0000a0cc, 0x02050504}, - {0x0000a0d0, 0x02050600}, - {0x0000a0d4, 0x02050601}, - {0x0000a0d8, 0x02050602}, - {0x0000a0dc, 0x02050603}, - {0x0000a0e0, 0x02050604}, - {0x0000a0e4, 0x02050700}, - {0x0000a0e8, 0x02050701}, - {0x0000a0ec, 0x02050702}, - {0x0000a0f0, 0x02050703}, - {0x0000a0f4, 0x02050704}, - {0x0000a0f8, 0x02050705}, - {0x0000a0fc, 0x02050708}, - {0x0000a100, 0x02050709}, - {0x0000a104, 0x0205070a}, - {0x0000a108, 0x0205070b}, - {0x0000a10c, 0x0205070c}, - {0x0000a110, 0x0205070d}, - {0x0000a114, 0x02050710}, - {0x0000a118, 0x02050711}, - {0x0000a11c, 0x02050712}, - {0x0000a120, 0x02050713}, - {0x0000a124, 0x02050714}, - {0x0000a128, 0x02050715}, - {0x0000a12c, 0x02050730}, - {0x0000a130, 0x02050731}, - {0x0000a134, 0x02050732}, - {0x0000a138, 0x02050733}, - {0x0000a13c, 0x02050734}, - {0x0000a140, 0x02050735}, - {0x0000a144, 0x02050750}, - {0x0000a148, 0x02050751}, - {0x0000a14c, 0x02050752}, - {0x0000a150, 0x02050753}, - {0x0000a154, 0x02050754}, - {0x0000a158, 0x02050755}, - {0x0000a15c, 0x02050770}, - {0x0000a160, 0x02050771}, - {0x0000a164, 0x02050772}, - {0x0000a168, 0x02050773}, - {0x0000a16c, 0x02050774}, - {0x0000a170, 0x02050775}, - {0x0000a174, 0x00000776}, - {0x0000a178, 0x00000776}, - {0x0000a17c, 0x00000776}, - {0x0000a180, 0x00000776}, - {0x0000a184, 0x00000776}, - {0x0000a188, 0x00000776}, - {0x0000a18c, 0x00000776}, - {0x0000a190, 0x00000776}, - {0x0000a194, 0x00000776}, - {0x0000a198, 0x00000776}, - {0x0000a19c, 0x00000776}, - {0x0000a1a0, 0x00000776}, - {0x0000a1a4, 0x00000776}, - {0x0000a1a8, 0x00000776}, - {0x0000a1ac, 0x00000776}, - {0x0000a1b0, 0x00000776}, - {0x0000a1b4, 0x00000776}, - {0x0000a1b8, 0x00000776}, - {0x0000a1bc, 0x00000776}, - {0x0000a1c0, 0x00000776}, - {0x0000a1c4, 0x00000776}, - {0x0000a1c8, 0x00000776}, - {0x0000a1cc, 0x00000776}, - {0x0000a1d0, 0x00000776}, - {0x0000a1d4, 0x00000776}, - {0x0000a1d8, 0x00000776}, - {0x0000a1dc, 0x00000776}, - {0x0000a1e0, 0x00000776}, - {0x0000a1e4, 0x00000776}, - {0x0000a1e8, 0x00000776}, - {0x0000a1ec, 0x00000776}, - {0x0000a1f0, 0x00000776}, - {0x0000a1f4, 0x00000776}, - {0x0000a1f8, 0x00000776}, - {0x0000a1fc, 0x00000776}, - {0x0000b000, 0x02000101}, - {0x0000b004, 0x02000102}, - {0x0000b008, 0x02000103}, - {0x0000b00c, 0x02000104}, - {0x0000b010, 0x02000200}, - {0x0000b014, 0x02000201}, - {0x0000b018, 0x02000202}, - {0x0000b01c, 0x02000203}, - {0x0000b020, 0x02000204}, - {0x0000b024, 0x02000205}, - {0x0000b028, 0x02000208}, - {0x0000b02c, 0x02000302}, - {0x0000b030, 0x02000303}, - {0x0000b034, 0x02000304}, - {0x0000b038, 0x02000400}, - {0x0000b03c, 0x02010300}, - {0x0000b040, 0x02010301}, - {0x0000b044, 0x02010302}, - {0x0000b048, 0x02000500}, - {0x0000b04c, 0x02010400}, - {0x0000b050, 0x02020300}, - {0x0000b054, 0x02020301}, - {0x0000b058, 0x02020302}, - {0x0000b05c, 0x02020303}, - {0x0000b060, 0x02020400}, - {0x0000b064, 0x02030300}, - {0x0000b068, 0x02030301}, - {0x0000b06c, 0x02030302}, - {0x0000b070, 0x02030303}, - {0x0000b074, 0x02030400}, - {0x0000b078, 0x02040300}, - {0x0000b07c, 0x02040301}, - {0x0000b080, 0x02040302}, - {0x0000b084, 0x02040303}, - {0x0000b088, 0x02030500}, - {0x0000b08c, 0x02040400}, - {0x0000b090, 0x02050203}, - {0x0000b094, 0x02050204}, - {0x0000b098, 0x02050205}, - {0x0000b09c, 0x02040500}, - {0x0000b0a0, 0x02050301}, - {0x0000b0a4, 0x02050302}, - {0x0000b0a8, 0x02050303}, - {0x0000b0ac, 0x02050400}, - {0x0000b0b0, 0x02050401}, - {0x0000b0b4, 0x02050402}, - {0x0000b0b8, 0x02050403}, - {0x0000b0bc, 0x02050500}, - {0x0000b0c0, 0x02050501}, - {0x0000b0c4, 0x02050502}, - {0x0000b0c8, 0x02050503}, - {0x0000b0cc, 0x02050504}, - {0x0000b0d0, 0x02050600}, - {0x0000b0d4, 0x02050601}, - {0x0000b0d8, 0x02050602}, - {0x0000b0dc, 0x02050603}, - {0x0000b0e0, 0x02050604}, - {0x0000b0e4, 0x02050700}, - {0x0000b0e8, 0x02050701}, - {0x0000b0ec, 0x02050702}, - {0x0000b0f0, 0x02050703}, - {0x0000b0f4, 0x02050704}, - {0x0000b0f8, 0x02050705}, - {0x0000b0fc, 0x02050708}, - {0x0000b100, 0x02050709}, - {0x0000b104, 0x0205070a}, - {0x0000b108, 0x0205070b}, - {0x0000b10c, 0x0205070c}, - {0x0000b110, 0x0205070d}, - {0x0000b114, 0x02050710}, - {0x0000b118, 0x02050711}, - {0x0000b11c, 0x02050712}, - {0x0000b120, 0x02050713}, - {0x0000b124, 0x02050714}, - {0x0000b128, 0x02050715}, - {0x0000b12c, 0x02050730}, - {0x0000b130, 0x02050731}, - {0x0000b134, 0x02050732}, - {0x0000b138, 0x02050733}, - {0x0000b13c, 0x02050734}, - {0x0000b140, 0x02050735}, - {0x0000b144, 0x02050750}, - {0x0000b148, 0x02050751}, - {0x0000b14c, 0x02050752}, - {0x0000b150, 0x02050753}, - {0x0000b154, 0x02050754}, - {0x0000b158, 0x02050755}, - {0x0000b15c, 0x02050770}, - {0x0000b160, 0x02050771}, - {0x0000b164, 0x02050772}, - {0x0000b168, 0x02050773}, - {0x0000b16c, 0x02050774}, - {0x0000b170, 0x02050775}, - {0x0000b174, 0x00000776}, - {0x0000b178, 0x00000776}, - {0x0000b17c, 0x00000776}, - {0x0000b180, 0x00000776}, - {0x0000b184, 0x00000776}, - {0x0000b188, 0x00000776}, - {0x0000b18c, 0x00000776}, - {0x0000b190, 0x00000776}, - {0x0000b194, 0x00000776}, - {0x0000b198, 0x00000776}, - {0x0000b19c, 0x00000776}, - {0x0000b1a0, 0x00000776}, - {0x0000b1a4, 0x00000776}, - {0x0000b1a8, 0x00000776}, - {0x0000b1ac, 0x00000776}, - {0x0000b1b0, 0x00000776}, - {0x0000b1b4, 0x00000776}, - {0x0000b1b8, 0x00000776}, - {0x0000b1bc, 0x00000776}, - {0x0000b1c0, 0x00000776}, - {0x0000b1c4, 0x00000776}, - {0x0000b1c8, 0x00000776}, - {0x0000b1cc, 0x00000776}, - {0x0000b1d0, 0x00000776}, - {0x0000b1d4, 0x00000776}, - {0x0000b1d8, 0x00000776}, - {0x0000b1dc, 0x00000776}, - {0x0000b1e0, 0x00000776}, - {0x0000b1e4, 0x00000776}, - {0x0000b1e8, 0x00000776}, - {0x0000b1ec, 0x00000776}, - {0x0000b1f0, 0x00000776}, - {0x0000b1f4, 0x00000776}, - {0x0000b1f8, 0x00000776}, - {0x0000b1fc, 0x00000776}, -}; - -static const u32 ar9200_ar9280_2p0_radio_core_1p0[][2] = { - /* Addr allmodes */ - {0x00007800, 0x00040000}, - {0x00007804, 0xdb005012}, - {0x00007808, 0x04924914}, - {0x0000780c, 0x21084210}, - {0x00007810, 0x6d801300}, - {0x00007814, 0x0019beff}, - {0x00007818, 0x07e41000}, - {0x0000781c, 0x00392000}, - {0x00007820, 0x92592480}, - {0x00007824, 0x00040000}, - {0x00007828, 0xdb005012}, - {0x0000782c, 0x04924914}, - {0x00007830, 0x21084210}, - {0x00007834, 0x6d801300}, - {0x00007838, 0x0019beff}, - {0x0000783c, 0x07e40000}, - {0x00007840, 0x00392000}, - {0x00007844, 0x92592480}, - {0x00007848, 0x00100000}, - {0x0000784c, 0x773f0567}, - {0x00007850, 0x54214514}, - {0x00007854, 0x12035828}, - {0x00007858, 0x92592692}, - {0x0000785c, 0x00000000}, - {0x00007860, 0x56400000}, - {0x00007864, 0x0a8e370e}, - {0x00007868, 0xc0102850}, - {0x0000786c, 0x812d4000}, - {0x00007870, 0x807ec400}, - {0x00007874, 0x001b6db0}, - {0x00007878, 0x00376b63}, - {0x0000787c, 0x06db6db6}, - {0x00007880, 0x006d8000}, - {0x00007884, 0xffeffffe}, - {0x00007888, 0xffeffffe}, - {0x0000788c, 0x00010000}, - {0x00007890, 0x02060aeb}, - {0x00007894, 0x5a108000}, -}; - -static const u32 ar9462_1p0_baseband_postamble_emulation[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009e3c, 0xcf946221, 0xcf946221, 0xcf946221, 0xcf946221}, - {0x00009e44, 0x005c0000, 0x005c0000, 0x005c0000, 0x005c0000}, - {0x0000a258, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, - {0x0000a25c, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x0000a28c, 0x00011111, 0x00011111, 0x00011111, 0x00011111}, - {0x0000a2c4, 0x00148d18, 0x00148d18, 0x00148d20, 0x00148d20}, - {0x0000a2d8, 0xf999a800, 0xf999a800, 0xf999a80c, 0xf999a80c}, - {0x0000a50c, 0x0000c00a, 0x0000c00a, 0x0000c00a, 0x0000c00a}, - {0x0000a538, 0x00038e8c, 0x00038e8c, 0x00038e8c, 0x00038e8c}, - {0x0000a53c, 0x0003cecc, 0x0003cecc, 0x0003cecc, 0x0003cecc}, - {0x0000a540, 0x00040ed4, 0x00040ed4, 0x00040ed4, 0x00040ed4}, - {0x0000a544, 0x00044edc, 0x00044edc, 0x00044edc, 0x00044edc}, - {0x0000a548, 0x00048ede, 0x00048ede, 0x00048ede, 0x00048ede}, - {0x0000a54c, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e}, - {0x0000a550, 0x00050f5e, 0x00050f5e, 0x00050f5e, 0x00050f5e}, - {0x0000a554, 0x00054f9e, 0x00054f9e, 0x00054f9e, 0x00054f9e}, - {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -}; - -static const u32 ar9462_pcie_phy_pll_on_clkreq_disable_L1_1p0[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10012e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9462_common_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, 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_modes_high_ob_db_tx_gain_table_1p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, - {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, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, - {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84}, - {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3}, - {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5}, - {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9}, - {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb}, - {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {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}, - {0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, - {0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000}, -}; - -static const u32 ar9462_common_wo_xlna_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, 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_1p0_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_1p0_mac_postamble_emulation[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00008014, 0x10f810f8, 0x10f810f8, 0x10f810f8, 0x10f810f8}, - {0x0000801c, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017}, -}; - -static const u32 ar9462_1p0_tx_gain_table_baseband_postamble_emulation[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000000d5, 0x000000d5, 0x000000d5, 0x000000d5}, - {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a504, 0x00004002, 0x00004002, 0x00004002, 0x00004002}, - {0x0000a508, 0x00008004, 0x00008004, 0x00008004, 0x00008004}, - {0x0000a510, 0x0001000c, 0x0001000c, 0x0001000c, 0x0001000c}, - {0x0000a514, 0x0001420b, 0x0001420b, 0x0001420b, 0x0001420b}, - {0x0000a518, 0x0001824a, 0x0001824a, 0x0001824a, 0x0001824a}, - {0x0000a51c, 0x0001c44a, 0x0001c44a, 0x0001c44a, 0x0001c44a}, - {0x0000a520, 0x0002064a, 0x0002064a, 0x0002064a, 0x0002064a}, - {0x0000a524, 0x0002484a, 0x0002484a, 0x0002484a, 0x0002484a}, - {0x0000a528, 0x00028a4a, 0x00028a4a, 0x00028a4a, 0x00028a4a}, - {0x0000a52c, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a}, - {0x0000a530, 0x00030e4a, 0x00030e4a, 0x00030e4a, 0x00030e4a}, - {0x0000a534, 0x00034e8a, 0x00034e8a, 0x00034e8a, 0x00034e8a}, -}; - -static const u32 ar9462_1p0_radio_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524}, - {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24646c08, 0x24646c08}, - {0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70}, - {0x0001610c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, - {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, - {0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, - {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, -}; - -static const u32 ar9462_1p0_soc_postamble_emulation[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00007010, 0x00001133, 0x00001133, 0x00001133, 0x00001133}, -}; - -static const u32 ar9462_1p0_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, 0x32840bbe}, - {0x000098d0, 0x004b6a8e}, - {0x000098d4, 0x00000820}, - {0x000098dc, 0x00000000}, - {0x000098e4, 0x01ffffff}, - {0x000098e8, 0x01ffffff}, - {0x000098ec, 0x01ffffff}, - {0x000098f0, 0x00000000}, - {0x000098f4, 0x00000000}, - {0x00009c04, 0xff55ff55}, - {0x00009c08, 0x0320ff55}, - {0x00009c0c, 0x00000000}, - {0x00009c10, 0x00000000}, - {0x00009c14, 0x00046384}, - {0x00009c18, 0x05b6b440}, - {0x00009c1c, 0x00b6b440}, - {0x00009d00, 0xc080a333}, - {0x00009d04, 0x40206c10}, - {0x00009d08, 0x009c4060}, - {0x00009d0c, 0x9883800a}, - {0x00009d10, 0x01834061}, - {0x00009d14, 0x00c0040b}, - {0x00009d18, 0x00000000}, - {0x00009e08, 0x0038230c}, - {0x00009e24, 0x990bb514}, - {0x00009e28, 0x0c6f0000}, - {0x00009e30, 0x06336f77}, - {0x00009e34, 0x6af6532f}, - {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, - {0x00009e4c, 0x00001004}, - {0x00009e50, 0x00ff03f1}, - {0x00009e54, 0x64c355c7}, - {0x00009e58, 0xfd897735}, - {0x00009e5c, 0xe9198724}, - {0x00009fc0, 0x803e4788}, - {0x00009fc4, 0x0001efb5}, - {0x00009fcc, 0x40000014}, - {0x00009fd0, 0x01193b93}, - {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}, - {0x0000a3a4, 0x00000000}, - {0x0000a3a8, 0xaaaaaaaa}, - {0x0000a3ac, 0x3c466478}, - {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}, - {0x0000a41c, 0x1ce739ce}, - {0x0000a420, 0x000001ce}, - {0x0000a424, 0x1ce739ce}, - {0x0000a428, 0x000001ce}, - {0x0000a42c, 0x1ce739ce}, - {0x0000a430, 0x1ce739ce}, - {0x0000a434, 0x00000000}, - {0x0000a438, 0x00001801}, - {0x0000a43c, 0x00100000}, - {0x0000a440, 0x00000000}, - {0x0000a444, 0x00000000}, - {0x0000a448, 0x05000080}, - {0x0000a44c, 0x00000001}, - {0x0000a450, 0x00010000}, - {0x0000a458, 0x00000000}, - {0x0000a644, 0xbfad9d74}, - {0x0000a648, 0x0048060a}, - {0x0000a64c, 0x00003c37}, - {0x0000a670, 0x03020100}, - {0x0000a674, 0x09080504}, - {0x0000a678, 0x0d0c0b0a}, - {0x0000a67c, 0x13121110}, - {0x0000a680, 0x31301514}, - {0x0000a684, 0x35343332}, - {0x0000a688, 0x00000036}, - {0x0000a690, 0x00000838}, - {0x0000a6b0, 0x0000000a}, - {0x0000a6b4, 0x28f12c01}, - {0x0000a7c0, 0x00000000}, - {0x0000a7c4, 0xfffffffc}, - {0x0000a7c8, 0x00000000}, - {0x0000a7cc, 0x00000000}, - {0x0000a7d0, 0x00000000}, - {0x0000a7d4, 0x00000004}, - {0x0000a7dc, 0x00000001}, - {0x0000a8d0, 0x004b6a8e}, - {0x0000a8d4, 0x00000820}, - {0x0000a8dc, 0x00000000}, - {0x0000a8f0, 0x00000000}, - {0x0000a8f4, 0x00000000}, - {0x0000b2d0, 0x00000080}, - {0x0000b2d4, 0x00000000}, - {0x0000b2ec, 0x00000000}, - {0x0000b2f0, 0x00000000}, - {0x0000b2f4, 0x00000000}, - {0x0000b2f8, 0x00000000}, - {0x0000b408, 0x0e79e5c0}, - {0x0000b40c, 0x00820820}, - {0x0000b420, 0x00000000}, - {0x0000b6b0, 0x0000000a}, - {0x0000b6b4, 0x00c00001}, -}; - -static const u32 ar9462_1p0_baseband_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, - {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, - {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, - {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, - {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, - {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, - {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, - {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, - {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, - {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, - {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, - {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, - {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c782}, - {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, - {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, - {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, - {0x0000a204, 0x0131b7c0, 0x0131b7c4, 0x0131b7c4, 0x0131b7c0}, - {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, - {0x0000a22c, 0x01026a2f, 0x01026a27, 0x01026a2f, 0x01026a2f}, - {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, - {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, - {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, - {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, - {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, - {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, - {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, - {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, - {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, - {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, - {0x0000a288, 0x00000110, 0x00000110, 0x00100110, 0x00100110}, - {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, - {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, - {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, - {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000}, - {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, - {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, - {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, -}; - -static const u32 ar9462_modes_fast_clock_1p0[][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_modes_low_ob_db_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, 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}, - {0x00016444, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, - {0x00016448, 0x64992000, 0x64992000, 0x64992000, 0x64992000}, -}; - -static const u32 ar9462_1p0_soc_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00007010, 0x00002233, 0x00002233, 0x00002233, 0x00002233}, -}; - -static const u32 ar9462_common_mixed_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, 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_pcie_phy_clkreq_disable_L1_1p0[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10013e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9462_1p0_baseband_core_emulation[][2] = { - /* Addr allmodes */ - {0x00009800, 0xafa68e30}, - {0x00009884, 0x00002842}, - {0x00009c04, 0xff55ff55}, - {0x00009c08, 0x0320ff55}, - {0x00009e50, 0x00000000}, - {0x00009fcc, 0x00000014}, - {0x0000a344, 0x00000010}, - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x71733d01}, - {0x0000a3a0, 0xd0ad5c12}, - {0x0000a3c0, 0x22222220}, - {0x0000a3c4, 0x22222222}, - {0x0000a404, 0x00418a11}, - {0x0000a418, 0x050001ce}, - {0x0000a438, 0x00001800}, - {0x0000a458, 0x01444452}, - {0x0000a644, 0x3fad9d74}, - {0x0000a690, 0x00000038}, -}; - -static const u32 ar9462_1p0_radio_core[][2] = { - /* Addr allmodes */ - {0x00016000, 0x36db6db6}, - {0x00016004, 0x6db6db40}, - {0x00016008, 0x73f00000}, - {0x0001600c, 0x00000000}, - {0x00016010, 0x6d820001}, - {0x00016040, 0x7f80fff8}, - {0x0001604c, 0x2699e04f}, - {0x00016050, 0x6db6db6c}, - {0x00016054, 0x6db60000}, - {0x00016058, 0x6c200000}, - {0x00016080, 0x00040000}, - {0x00016084, 0x9a68048c}, - {0x00016088, 0x54214514}, - {0x0001608c, 0x12030409}, - {0x00016090, 0x24926490}, - {0x00016098, 0xd2888888}, - {0x000160a0, 0x0a108ffe}, - {0x000160a4, 0x812fc490}, - {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, 0x3d841400}, - {0x00016288, 0x00000000}, - {0x0001628c, 0xe3000000}, - {0x00016290, 0xa1005080}, - {0x00016294, 0x00000020}, - {0x00016298, 0x50a02900}, - {0x00016340, 0x121e4276}, - {0x00016344, 0x00300000}, - {0x00016400, 0x36db6db6}, - {0x00016404, 0x6db6db40}, - {0x00016408, 0x73f00000}, - {0x0001640c, 0x00000000}, - {0x00016410, 0x6c800001}, - {0x00016440, 0x7f80fff8}, - {0x0001644c, 0x4699e04f}, - {0x00016450, 0x6db6db6c}, - {0x00016454, 0x6db60000}, - {0x00016500, 0x3fffbe04}, - {0x00016504, 0xfff80000}, - {0x00016508, 0x00200400}, - {0x00016510, 0x00000000}, - {0x00016544, 0x02084080}, - {0x00016548, 0x000080c0}, -}; - -static const u32 ar9462_1p0_soc_preamble[][2] = { - /* Addr allmodes */ - {0x00007020, 0x00000000}, - {0x00007034, 0x00000002}, - {0x00007038, 0x000004c2}, -}; - -static const u32 ar9462_1p0_sys2ant[][2] = { - /* Addr allmodes */ - {0x00063120, 0x00801980}, -}; - -#endif /* INITVALS_9462_1P0_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index dc2054f0378e..b6ba1e8149be 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -98,14 +98,6 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, }; -static const u32 ar9462_2p0_mac_core_emulation[][2] = { - /* Addr allmodes */ - {0x00000030, 0x000e0085}, - {0x00000044, 0x00000008}, - {0x0000805c, 0xffffc7ff}, - {0x00008344, 0xaa4a105b}, -}; - static const u32 ar9462_common_rx_gain_table_2p0[][2] = { /* Addr allmodes */ {0x0000a000, 0x00010000}, @@ -380,349 +372,6 @@ static const u32 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0[][2] = { {0x00018c08, 0x0003580c}, }; -static const u32 ar9462_2p0_sys3ant[][2] = { - /* Addr allmodes */ - {0x00063280, 0x00040807}, - {0x00063284, 0x104ccccc}, -}; - -static const u32 ar9462_common_rx_gain_table_ar9280_2p0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x02000101}, - {0x0000a004, 0x02000102}, - {0x0000a008, 0x02000103}, - {0x0000a00c, 0x02000104}, - {0x0000a010, 0x02000200}, - {0x0000a014, 0x02000201}, - {0x0000a018, 0x02000202}, - {0x0000a01c, 0x02000203}, - {0x0000a020, 0x02000204}, - {0x0000a024, 0x02000205}, - {0x0000a028, 0x02000208}, - {0x0000a02c, 0x02000302}, - {0x0000a030, 0x02000303}, - {0x0000a034, 0x02000304}, - {0x0000a038, 0x02000400}, - {0x0000a03c, 0x02010300}, - {0x0000a040, 0x02010301}, - {0x0000a044, 0x02010302}, - {0x0000a048, 0x02000500}, - {0x0000a04c, 0x02010400}, - {0x0000a050, 0x02020300}, - {0x0000a054, 0x02020301}, - {0x0000a058, 0x02020302}, - {0x0000a05c, 0x02020303}, - {0x0000a060, 0x02020400}, - {0x0000a064, 0x02030300}, - {0x0000a068, 0x02030301}, - {0x0000a06c, 0x02030302}, - {0x0000a070, 0x02030303}, - {0x0000a074, 0x02030400}, - {0x0000a078, 0x02040300}, - {0x0000a07c, 0x02040301}, - {0x0000a080, 0x02040302}, - {0x0000a084, 0x02040303}, - {0x0000a088, 0x02030500}, - {0x0000a08c, 0x02040400}, - {0x0000a090, 0x02050203}, - {0x0000a094, 0x02050204}, - {0x0000a098, 0x02050205}, - {0x0000a09c, 0x02040500}, - {0x0000a0a0, 0x02050301}, - {0x0000a0a4, 0x02050302}, - {0x0000a0a8, 0x02050303}, - {0x0000a0ac, 0x02050400}, - {0x0000a0b0, 0x02050401}, - {0x0000a0b4, 0x02050402}, - {0x0000a0b8, 0x02050403}, - {0x0000a0bc, 0x02050500}, - {0x0000a0c0, 0x02050501}, - {0x0000a0c4, 0x02050502}, - {0x0000a0c8, 0x02050503}, - {0x0000a0cc, 0x02050504}, - {0x0000a0d0, 0x02050600}, - {0x0000a0d4, 0x02050601}, - {0x0000a0d8, 0x02050602}, - {0x0000a0dc, 0x02050603}, - {0x0000a0e0, 0x02050604}, - {0x0000a0e4, 0x02050700}, - {0x0000a0e8, 0x02050701}, - {0x0000a0ec, 0x02050702}, - {0x0000a0f0, 0x02050703}, - {0x0000a0f4, 0x02050704}, - {0x0000a0f8, 0x02050705}, - {0x0000a0fc, 0x02050708}, - {0x0000a100, 0x02050709}, - {0x0000a104, 0x0205070a}, - {0x0000a108, 0x0205070b}, - {0x0000a10c, 0x0205070c}, - {0x0000a110, 0x0205070d}, - {0x0000a114, 0x02050710}, - {0x0000a118, 0x02050711}, - {0x0000a11c, 0x02050712}, - {0x0000a120, 0x02050713}, - {0x0000a124, 0x02050714}, - {0x0000a128, 0x02050715}, - {0x0000a12c, 0x02050730}, - {0x0000a130, 0x02050731}, - {0x0000a134, 0x02050732}, - {0x0000a138, 0x02050733}, - {0x0000a13c, 0x02050734}, - {0x0000a140, 0x02050735}, - {0x0000a144, 0x02050750}, - {0x0000a148, 0x02050751}, - {0x0000a14c, 0x02050752}, - {0x0000a150, 0x02050753}, - {0x0000a154, 0x02050754}, - {0x0000a158, 0x02050755}, - {0x0000a15c, 0x02050770}, - {0x0000a160, 0x02050771}, - {0x0000a164, 0x02050772}, - {0x0000a168, 0x02050773}, - {0x0000a16c, 0x02050774}, - {0x0000a170, 0x02050775}, - {0x0000a174, 0x00000776}, - {0x0000a178, 0x00000776}, - {0x0000a17c, 0x00000776}, - {0x0000a180, 0x00000776}, - {0x0000a184, 0x00000776}, - {0x0000a188, 0x00000776}, - {0x0000a18c, 0x00000776}, - {0x0000a190, 0x00000776}, - {0x0000a194, 0x00000776}, - {0x0000a198, 0x00000776}, - {0x0000a19c, 0x00000776}, - {0x0000a1a0, 0x00000776}, - {0x0000a1a4, 0x00000776}, - {0x0000a1a8, 0x00000776}, - {0x0000a1ac, 0x00000776}, - {0x0000a1b0, 0x00000776}, - {0x0000a1b4, 0x00000776}, - {0x0000a1b8, 0x00000776}, - {0x0000a1bc, 0x00000776}, - {0x0000a1c0, 0x00000776}, - {0x0000a1c4, 0x00000776}, - {0x0000a1c8, 0x00000776}, - {0x0000a1cc, 0x00000776}, - {0x0000a1d0, 0x00000776}, - {0x0000a1d4, 0x00000776}, - {0x0000a1d8, 0x00000776}, - {0x0000a1dc, 0x00000776}, - {0x0000a1e0, 0x00000776}, - {0x0000a1e4, 0x00000776}, - {0x0000a1e8, 0x00000776}, - {0x0000a1ec, 0x00000776}, - {0x0000a1f0, 0x00000776}, - {0x0000a1f4, 0x00000776}, - {0x0000a1f8, 0x00000776}, - {0x0000a1fc, 0x00000776}, - {0x0000b000, 0x02000101}, - {0x0000b004, 0x02000102}, - {0x0000b008, 0x02000103}, - {0x0000b00c, 0x02000104}, - {0x0000b010, 0x02000200}, - {0x0000b014, 0x02000201}, - {0x0000b018, 0x02000202}, - {0x0000b01c, 0x02000203}, - {0x0000b020, 0x02000204}, - {0x0000b024, 0x02000205}, - {0x0000b028, 0x02000208}, - {0x0000b02c, 0x02000302}, - {0x0000b030, 0x02000303}, - {0x0000b034, 0x02000304}, - {0x0000b038, 0x02000400}, - {0x0000b03c, 0x02010300}, - {0x0000b040, 0x02010301}, - {0x0000b044, 0x02010302}, - {0x0000b048, 0x02000500}, - {0x0000b04c, 0x02010400}, - {0x0000b050, 0x02020300}, - {0x0000b054, 0x02020301}, - {0x0000b058, 0x02020302}, - {0x0000b05c, 0x02020303}, - {0x0000b060, 0x02020400}, - {0x0000b064, 0x02030300}, - {0x0000b068, 0x02030301}, - {0x0000b06c, 0x02030302}, - {0x0000b070, 0x02030303}, - {0x0000b074, 0x02030400}, - {0x0000b078, 0x02040300}, - {0x0000b07c, 0x02040301}, - {0x0000b080, 0x02040302}, - {0x0000b084, 0x02040303}, - {0x0000b088, 0x02030500}, - {0x0000b08c, 0x02040400}, - {0x0000b090, 0x02050203}, - {0x0000b094, 0x02050204}, - {0x0000b098, 0x02050205}, - {0x0000b09c, 0x02040500}, - {0x0000b0a0, 0x02050301}, - {0x0000b0a4, 0x02050302}, - {0x0000b0a8, 0x02050303}, - {0x0000b0ac, 0x02050400}, - {0x0000b0b0, 0x02050401}, - {0x0000b0b4, 0x02050402}, - {0x0000b0b8, 0x02050403}, - {0x0000b0bc, 0x02050500}, - {0x0000b0c0, 0x02050501}, - {0x0000b0c4, 0x02050502}, - {0x0000b0c8, 0x02050503}, - {0x0000b0cc, 0x02050504}, - {0x0000b0d0, 0x02050600}, - {0x0000b0d4, 0x02050601}, - {0x0000b0d8, 0x02050602}, - {0x0000b0dc, 0x02050603}, - {0x0000b0e0, 0x02050604}, - {0x0000b0e4, 0x02050700}, - {0x0000b0e8, 0x02050701}, - {0x0000b0ec, 0x02050702}, - {0x0000b0f0, 0x02050703}, - {0x0000b0f4, 0x02050704}, - {0x0000b0f8, 0x02050705}, - {0x0000b0fc, 0x02050708}, - {0x0000b100, 0x02050709}, - {0x0000b104, 0x0205070a}, - {0x0000b108, 0x0205070b}, - {0x0000b10c, 0x0205070c}, - {0x0000b110, 0x0205070d}, - {0x0000b114, 0x02050710}, - {0x0000b118, 0x02050711}, - {0x0000b11c, 0x02050712}, - {0x0000b120, 0x02050713}, - {0x0000b124, 0x02050714}, - {0x0000b128, 0x02050715}, - {0x0000b12c, 0x02050730}, - {0x0000b130, 0x02050731}, - {0x0000b134, 0x02050732}, - {0x0000b138, 0x02050733}, - {0x0000b13c, 0x02050734}, - {0x0000b140, 0x02050735}, - {0x0000b144, 0x02050750}, - {0x0000b148, 0x02050751}, - {0x0000b14c, 0x02050752}, - {0x0000b150, 0x02050753}, - {0x0000b154, 0x02050754}, - {0x0000b158, 0x02050755}, - {0x0000b15c, 0x02050770}, - {0x0000b160, 0x02050771}, - {0x0000b164, 0x02050772}, - {0x0000b168, 0x02050773}, - {0x0000b16c, 0x02050774}, - {0x0000b170, 0x02050775}, - {0x0000b174, 0x00000776}, - {0x0000b178, 0x00000776}, - {0x0000b17c, 0x00000776}, - {0x0000b180, 0x00000776}, - {0x0000b184, 0x00000776}, - {0x0000b188, 0x00000776}, - {0x0000b18c, 0x00000776}, - {0x0000b190, 0x00000776}, - {0x0000b194, 0x00000776}, - {0x0000b198, 0x00000776}, - {0x0000b19c, 0x00000776}, - {0x0000b1a0, 0x00000776}, - {0x0000b1a4, 0x00000776}, - {0x0000b1a8, 0x00000776}, - {0x0000b1ac, 0x00000776}, - {0x0000b1b0, 0x00000776}, - {0x0000b1b4, 0x00000776}, - {0x0000b1b8, 0x00000776}, - {0x0000b1bc, 0x00000776}, - {0x0000b1c0, 0x00000776}, - {0x0000b1c4, 0x00000776}, - {0x0000b1c8, 0x00000776}, - {0x0000b1cc, 0x00000776}, - {0x0000b1d0, 0x00000776}, - {0x0000b1d4, 0x00000776}, - {0x0000b1d8, 0x00000776}, - {0x0000b1dc, 0x00000776}, - {0x0000b1e0, 0x00000776}, - {0x0000b1e4, 0x00000776}, - {0x0000b1e8, 0x00000776}, - {0x0000b1ec, 0x00000776}, - {0x0000b1f0, 0x00000776}, - {0x0000b1f4, 0x00000776}, - {0x0000b1f8, 0x00000776}, - {0x0000b1fc, 0x00000776}, -}; - -static const u32 ar9200_ar9280_2p0_radio_core[][2] = { - /* Addr allmodes */ - {0x00007800, 0x00040000}, - {0x00007804, 0xdb005012}, - {0x00007808, 0x04924914}, - {0x0000780c, 0x21084210}, - {0x00007810, 0x6d801300}, - {0x00007814, 0x0019beff}, - {0x00007818, 0x07e41000}, - {0x0000781c, 0x00392000}, - {0x00007820, 0x92592480}, - {0x00007824, 0x00040000}, - {0x00007828, 0xdb005012}, - {0x0000782c, 0x04924914}, - {0x00007830, 0x21084210}, - {0x00007834, 0x6d801300}, - {0x00007838, 0x0019beff}, - {0x0000783c, 0x07e40000}, - {0x00007840, 0x00392000}, - {0x00007844, 0x92592480}, - {0x00007848, 0x00100000}, - {0x0000784c, 0x773f0567}, - {0x00007850, 0x54214514}, - {0x00007854, 0x12035828}, - {0x00007858, 0x92592692}, - {0x0000785c, 0x00000000}, - {0x00007860, 0x56400000}, - {0x00007864, 0x0a8e370e}, - {0x00007868, 0xc0102850}, - {0x0000786c, 0x812d4000}, - {0x00007870, 0x807ec400}, - {0x00007874, 0x001b6db0}, - {0x00007878, 0x00376b63}, - {0x0000787c, 0x06db6db6}, - {0x00007880, 0x006d8000}, - {0x00007884, 0xffeffffe}, - {0x00007888, 0xffeffffe}, - {0x0000788c, 0x00010000}, - {0x00007890, 0x02060aeb}, - {0x00007894, 0x5a108000}, -}; - -static const u32 ar9462_2p0_mac_postamble_emulation[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00008014, 0x10f810f8, 0x10f810f8, 0x10f810f8, 0x10f810f8}, - {0x0000801c, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017}, -}; - -static const u32 ar9462_2p0_radio_postamble_sys3ant[][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_2p0_baseband_postamble_emulation[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009e3c, 0xcf946221, 0xcf946221, 0xcf946221, 0xcf946221}, - {0x00009e44, 0xfc5c0000, 0xfc5c0000, 0xfc5c0000, 0xfc5c0000}, - {0x0000a258, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, - {0x0000a25c, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x0000a28c, 0x00011111, 0x00011111, 0x00011111, 0x00011111}, - {0x0000a2c4, 0x00148d18, 0x00148d18, 0x00148d20, 0x00148d20}, - {0x0000a2d8, 0xf999a800, 0xf999a800, 0xf999a80c, 0xf999a80c}, - {0x0000a50c, 0x0000c00a, 0x0000c00a, 0x0000c00a, 0x0000c00a}, - {0x0000a538, 0x00038e8c, 0x00038e8c, 0x00038e8c, 0x00038e8c}, - {0x0000a53c, 0x0003cecc, 0x0003cecc, 0x0003cecc, 0x0003cecc}, - {0x0000a540, 0x00040ed4, 0x00040ed4, 0x00040ed4, 0x00040ed4}, - {0x0000a544, 0x00044edc, 0x00044edc, 0x00044edc, 0x00044edc}, - {0x0000a548, 0x00048ede, 0x00048ede, 0x00048ede, 0x00048ede}, - {0x0000a54c, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e}, - {0x0000a550, 0x00050f5e, 0x00050f5e, 0x00050f5e, 0x00050f5e}, - {0x0000a554, 0x00054f9e, 0x00054f9e, 0x00054f9e, 0x00054f9e}, - {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -}; - static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, @@ -1356,24 +1005,6 @@ static const u32 ar9462_2p0_radio_core[][2] = { {0x00016548, 0x000080c0}, }; -static const u32 ar9462_2p0_tx_gain_table_baseband_postamble_emulation[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000000d5, 0x000000d5, 0x000000d5, 0x000000d5}, - {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a504, 0x00004002, 0x00004002, 0x00004002, 0x00004002}, - {0x0000a508, 0x00008004, 0x00008004, 0x00008004, 0x00008004}, - {0x0000a510, 0x0001000c, 0x0001000c, 0x0001000c, 0x0001000c}, - {0x0000a514, 0x0001420b, 0x0001420b, 0x0001420b, 0x0001420b}, - {0x0000a518, 0x0001824a, 0x0001824a, 0x0001824a, 0x0001824a}, - {0x0000a51c, 0x0001c44a, 0x0001c44a, 0x0001c44a, 0x0001c44a}, - {0x0000a520, 0x0002064a, 0x0002064a, 0x0002064a, 0x0002064a}, - {0x0000a524, 0x0002484a, 0x0002484a, 0x0002484a, 0x0002484a}, - {0x0000a528, 0x00028a4a, 0x00028a4a, 0x00028a4a, 0x00028a4a}, - {0x0000a52c, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a}, - {0x0000a530, 0x00030e4a, 0x00030e4a, 0x00030e4a, 0x00030e4a}, - {0x0000a534, 0x00034e8a, 0x00034e8a, 0x00034e8a, 0x00034e8a}, -}; - static const u32 ar9462_2p0_soc_preamble[][2] = { /* Addr allmodes */ {0x00007020, 0x00000000}, @@ -1381,11 +1012,6 @@ static const u32 ar9462_2p0_soc_preamble[][2] = { {0x00007038, 0x000004c2}, }; -static const u32 ar9462_2p0_sys2ant[][2] = { - /* Addr allmodes */ - {0x00063120, 0x00801980}, -}; - static const u32 ar9462_2p0_mac_core[][2] = { /* Addr allmodes */ {0x00000008, 0x00000000}, @@ -1822,75 +1448,6 @@ static const u32 ar9462_common_mixed_rx_gain_table_2p0[][2] = { {0x0000b1fc, 0x00000196}, }; -static const u32 ar9462_modes_green_ob_db_tx_gain_table_2p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003}, - {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, - {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000}, - {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, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x59025eb6, 0x59025eb6, 0x42001a83, 0x42001a83}, - {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001c84, 0x44001c84}, - {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3}, - {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5}, - {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9}, - {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb}, - {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, - {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, 0x6db60180, 0x6db60180, 0x6db60180, 0x6db60180}, - {0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, - {0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000}, - {0x00016454, 0x6db60180, 0x6db60180, 0x6db60180, 0x6db60180}, -}; - static const u32 ar9462_2p0_BTCOEX_MAX_TXPWR_table[][2] = { /* Addr allmodes */ {0x000018c0, 0x10101010}, @@ -1903,26 +1460,4 @@ static const u32 ar9462_2p0_BTCOEX_MAX_TXPWR_table[][2] = { {0x000018dc, 0x10101010}, }; -static const u32 ar9462_2p0_baseband_core_emulation[][2] = { - /* Addr allmodes */ - {0x00009800, 0xafa68e30}, - {0x00009884, 0x00002842}, - {0x00009c04, 0xff55ff55}, - {0x00009c08, 0x0320ff55}, - {0x00009e50, 0x00000000}, - {0x00009fcc, 0x00000014}, - {0x0000a344, 0x00000010}, - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x71733d01}, - {0x0000a3a0, 0xd0ad5c12}, - {0x0000a3c0, 0x22222220}, - {0x0000a3c4, 0x22222222}, - {0x0000a404, 0x00418a11}, - {0x0000a418, 0x050001ce}, - {0x0000a438, 0x00001800}, - {0x0000a458, 0x01444452}, - {0x0000a644, 0x3fad9d74}, - {0x0000a690, 0x00000038}, -}; - #endif /* INITVALS_9462_2P0_H */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 171ccf7c972f..8c84049682ab 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -299,7 +299,6 @@ struct ath_tx { struct ath_rx_edma { struct sk_buff_head rx_fifo; - struct sk_buff_head rx_buffers; u32 rx_fifo_hwsize; }; @@ -454,9 +453,39 @@ struct ath_btcoex { struct ath_mci_profile mci; }; -int ath_init_btcoex_timer(struct ath_softc *sc); +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT +int ath9k_init_btcoex(struct ath_softc *sc); +void ath9k_deinit_btcoex(struct ath_softc *sc); +void ath9k_start_btcoex(struct ath_softc *sc); +void ath9k_stop_btcoex(struct ath_softc *sc); void ath9k_btcoex_timer_resume(struct ath_softc *sc); void ath9k_btcoex_timer_pause(struct ath_softc *sc); +void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status); +u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen); +#else +static inline int ath9k_init_btcoex(struct ath_softc *sc) +{ + return 0; +} +static inline void ath9k_deinit_btcoex(struct ath_softc *sc) +{ +} +static inline void ath9k_start_btcoex(struct ath_softc *sc) +{ +} +static inline void ath9k_stop_btcoex(struct ath_softc *sc) +{ +} +static inline void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, + u32 status) +{ +} +static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, + u32 max_4ms_framelen) +{ + return 0; +} +#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ /********************/ /* LED Control */ @@ -554,19 +583,13 @@ struct ath_ant_comb { #define SC_OP_INVALID BIT(0) #define SC_OP_BEACONS BIT(1) -#define SC_OP_RXAGGR BIT(2) -#define SC_OP_TXAGGR BIT(3) -#define SC_OP_OFFCHANNEL BIT(4) -#define SC_OP_PREAMBLE_SHORT BIT(5) -#define SC_OP_PROTECT_ENABLE BIT(6) -#define SC_OP_RXFLUSH BIT(7) -#define SC_OP_LED_ASSOCIATED BIT(8) -#define SC_OP_LED_ON BIT(9) -#define SC_OP_TSF_RESET BIT(11) -#define SC_OP_BT_PRIORITY_DETECTED BIT(12) -#define SC_OP_BT_SCAN BIT(13) -#define SC_OP_ANI_RUN BIT(14) -#define SC_OP_PRIM_STA_VIF BIT(15) +#define SC_OP_OFFCHANNEL BIT(2) +#define SC_OP_RXFLUSH BIT(3) +#define SC_OP_TSF_RESET BIT(4) +#define SC_OP_BT_PRIORITY_DETECTED BIT(5) +#define SC_OP_BT_SCAN BIT(6) +#define SC_OP_ANI_RUN BIT(7) +#define SC_OP_PRIM_STA_VIF BIT(8) /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) @@ -588,15 +611,12 @@ struct ath9k_vif_iter_data { int nstations; /* number of station vifs */ int nwds; /* number of WDS vifs */ int nadhocs; /* number of adhoc vifs */ - int nothers; /* number of vifs not specified above. */ }; struct ath_softc { struct ieee80211_hw *hw; struct device *dev; - int chan_idx; - int chan_is_ht; struct survey_info *cur_survey; struct survey_info survey[ATH9K_NUM_CHANNELS]; @@ -650,8 +670,11 @@ struct ath_softc { struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; struct delayed_work hw_pll_work; + +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT struct ath_btcoex btcoex; struct ath_mci_coex mci_coex; +#endif struct ath_descdma txsdma; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index b8967e482e6e..626418222c85 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -67,7 +67,7 @@ int ath_beaconq_config(struct ath_softc *sc) * up rate codes, and channel flags. Beacons are always sent out at the * lowest rate, and are not retried. */ -static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, +static void ath_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, struct ath_buf *bf, int rateidx) { struct sk_buff *skb = bf->bf_mpdu; @@ -82,7 +82,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, sband = &sc->sbands[common->hw->conf.channel->band]; rate = sband->bitrates[rateidx].hw_value; - if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) + if (vif->bss_conf.use_short_preamble) rate |= sband->bitrates[rateidx].hw_value_short; memset(&info, 0, sizeof(info)); @@ -91,7 +91,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, info.txpower = MAX_RATE_POWER; info.keyix = ATH9K_TXKEYIX_INVALID; info.keytype = ATH9K_KEY_TYPE_CLEAR; - info.flags = ATH9K_TXDESC_NOACK; + info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_INTREQ; info.buf_addr[0] = bf->bf_buf_addr; info.buf_len[0] = roundup(skb->len, 4); @@ -209,7 +209,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, } } - ath_beacon_setup(sc, avp, bf, info->control.rates[0].idx); + ath_beacon_setup(sc, vif, bf, info->control.rates[0].idx); while (skb) { ath_tx_cabq(hw, skb); @@ -355,7 +355,6 @@ void ath_beacon_tasklet(unsigned long data) struct ath_common *common = ath9k_hw_common(ah); struct ath_buf *bf = NULL; struct ieee80211_vif *vif; - struct ath_tx_status ts; bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); int slot; u32 bfaddr, bc = 0; @@ -462,11 +461,6 @@ void ath_beacon_tasklet(unsigned long data) ath9k_hw_txstart(ah, sc->beacon.beaconq); sc->beacon.ast_be_xmit += bc; /* XXX per-vif? */ - if (edma) { - spin_lock_bh(&sc->sc_pcu_lock); - ath9k_hw_txprocdesc(ah, bf->bf_desc, (void *)&ts); - spin_unlock_bh(&sc->sc_pcu_lock); - } } } diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index a6712a95d76a..ec3271993411 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -68,9 +68,6 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) u32 i, idx; bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity; - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) - return; - if (AR_SREV_9300_20_OR_LATER(ah)) rxclear_polarity = !ath_bt_config.bt_rxclear_polarity; @@ -98,12 +95,43 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) } EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw); -void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) +void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah) { + struct ath_common *common = ath9k_hw_common(ah); struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) + /* + * Check if BTCOEX is globally disabled. + */ + if (!common->btcoex_enabled) { + btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE; return; + } + + if (AR_SREV_9462(ah)) { + btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI; + } else if (AR_SREV_9300_20_OR_LATER(ah)) { + btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; + btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300; + btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300; + btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300; + } else if (AR_SREV_9280_20_OR_LATER(ah)) { + btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280; + btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280; + + if (AR_SREV_9285(ah)) { + btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; + btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9285; + } else { + btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; + } + } +} +EXPORT_SYMBOL(ath9k_hw_btcoex_init_scheme); + +void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) +{ + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; /* connect bt_active to baseband */ REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, @@ -127,9 +155,6 @@ void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) - return; - /* btcoex 3-wire */ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB | @@ -152,13 +177,34 @@ void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire); +void ath9k_hw_btcoex_init_mci(struct ath_hw *ah) +{ + ah->btcoex_hw.mci.ready = false; + ah->btcoex_hw.mci.bt_state = 0; + ah->btcoex_hw.mci.bt_ver_major = 3; + ah->btcoex_hw.mci.bt_ver_minor = 0; + ah->btcoex_hw.mci.bt_version_known = false; + ah->btcoex_hw.mci.update_2g5g = true; + ah->btcoex_hw.mci.is_2g = true; + ah->btcoex_hw.mci.wlan_channels_update = false; + ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000; + ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff; + ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff; + ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff; + ah->btcoex_hw.mci.query_bt = true; + ah->btcoex_hw.mci.unhalt_bt_gpm = true; + ah->btcoex_hw.mci.halted_bt_gpm = false; + ah->btcoex_hw.mci.need_flush_btinfo = false; + ah->btcoex_hw.mci.wlan_cal_seq = 0; + ah->btcoex_hw.mci.wlan_cal_done = 0; + ah->btcoex_hw.mci.config = 0x2201; +} +EXPORT_SYMBOL(ath9k_hw_btcoex_init_mci); + static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) - return; - /* Configure the desired GPIO port for TX_FRAME output */ ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); @@ -170,9 +216,6 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) - return; - btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | SM(wlan_weight, AR_BTCOEX_WL_WGHT); } @@ -261,9 +304,6 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; int i; - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) - return; - btcoex_hw->enabled = false; if (btcoex_hw->scheme == ATH_BTCOEX_CFG_MCI) { ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); @@ -312,9 +352,6 @@ static void ar9003_btcoex_bt_stomp(struct ath_hw *ah, void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, enum ath_stomp_type stomp_type) { - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) - return; - if (AR_SREV_9300_20_OR_LATER(ah)) { ar9003_btcoex_bt_stomp(ah, stomp_type); return; diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 278361c867ca..8f93aef4414f 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -67,7 +67,6 @@ struct ath9k_hw_mci { u32 wlan_cal_done; u32 config; u8 *gpm_buf; - u8 *sched_buf; bool ready; bool update_2g5g; bool is_2g; @@ -98,13 +97,14 @@ struct ath_btcoex_hw { u32 wlan_weight[AR9300_NUM_WLAN_WEIGHTS]; }; +void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah); void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah); void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah); +void ath9k_hw_btcoex_init_mci(struct ath_hw *ah); void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum); void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, u32 bt_weight, u32 wlan_weight); -void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, enum ath_stomp_type stomp_type); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 68d972bf232d..35d1c8e91d1c 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -451,109 +451,6 @@ static const struct file_operations fops_interrupt = { .llseek = default_llseek, }; -static const char *channel_type_str(enum nl80211_channel_type t) -{ - switch (t) { - case NL80211_CHAN_NO_HT: - return "no ht"; - case NL80211_CHAN_HT20: - return "ht20"; - case NL80211_CHAN_HT40MINUS: - return "ht40-"; - case NL80211_CHAN_HT40PLUS: - return "ht40+"; - default: - return "???"; - } -} - -static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ieee80211_channel *chan = sc->hw->conf.channel; - struct ieee80211_conf *conf = &(sc->hw->conf); - char buf[512]; - unsigned int len = 0; - u8 addr[ETH_ALEN]; - u32 tmp; - - len += snprintf(buf + len, sizeof(buf) - len, - "%s (chan=%d center-freq: %d MHz channel-type: %d (%s))\n", - wiphy_name(sc->hw->wiphy), - ieee80211_frequency_to_channel(chan->center_freq), - chan->center_freq, - conf->channel_type, - channel_type_str(conf->channel_type)); - - ath9k_ps_wakeup(sc); - put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr); - put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); - len += snprintf(buf + len, sizeof(buf) - len, - "addr: %pM\n", addr); - put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_BSSMSKL), addr); - put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4); - len += snprintf(buf + len, sizeof(buf) - len, - "addrmask: %pM\n", addr); - tmp = ath9k_hw_getrxfilter(sc->sc_ah); - ath9k_ps_restore(sc); - len += snprintf(buf + len, sizeof(buf) - len, - "rfilt: 0x%x", tmp); - if (tmp & ATH9K_RX_FILTER_UCAST) - len += snprintf(buf + len, sizeof(buf) - len, " UCAST"); - if (tmp & ATH9K_RX_FILTER_MCAST) - len += snprintf(buf + len, sizeof(buf) - len, " MCAST"); - if (tmp & ATH9K_RX_FILTER_BCAST) - len += snprintf(buf + len, sizeof(buf) - len, " BCAST"); - if (tmp & ATH9K_RX_FILTER_CONTROL) - len += snprintf(buf + len, sizeof(buf) - len, " CONTROL"); - if (tmp & ATH9K_RX_FILTER_BEACON) - len += snprintf(buf + len, sizeof(buf) - len, " BEACON"); - if (tmp & ATH9K_RX_FILTER_PROM) - len += snprintf(buf + len, sizeof(buf) - len, " PROM"); - if (tmp & ATH9K_RX_FILTER_PROBEREQ) - len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ"); - if (tmp & ATH9K_RX_FILTER_PHYERR) - len += snprintf(buf + len, sizeof(buf) - len, " PHYERR"); - if (tmp & ATH9K_RX_FILTER_MYBEACON) - len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON"); - if (tmp & ATH9K_RX_FILTER_COMP_BAR) - len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR"); - if (tmp & ATH9K_RX_FILTER_PSPOLL) - len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL"); - if (tmp & ATH9K_RX_FILTER_PHYRADAR) - len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR"); - if (tmp & ATH9K_RX_FILTER_MCAST_BCAST_ALL) - len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL"); - - len += snprintf(buf + len, sizeof(buf) - len, - "\n\nReset causes:\n" - " baseband hang: %d\n" - " baseband watchdog: %d\n" - " fatal hardware error interrupt: %d\n" - " tx hardware error: %d\n" - " tx path hang: %d\n" - " pll rx hang: %d\n", - sc->debug.stats.reset[RESET_TYPE_BB_HANG], - sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG], - sc->debug.stats.reset[RESET_TYPE_FATAL_INT], - sc->debug.stats.reset[RESET_TYPE_TX_ERROR], - sc->debug.stats.reset[RESET_TYPE_TX_HANG], - sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); - - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static const struct file_operations fops_wiphy = { - .read = read_file_wiphy, - .open = ath9k_debugfs_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - #define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum #define PR(str, elem) \ do { \ @@ -763,87 +660,128 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, { struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_hw *ah = sc->sc_ah; struct ieee80211_hw *hw = sc->hw; - char *buf; - unsigned int len = 0, size = 8000; + struct ath9k_vif_iter_data iter_data; + char buf[512]; + unsigned int len = 0; ssize_t retval = 0; unsigned int reg; - struct ath9k_vif_iter_data iter_data; + u32 rxfilter; - ath9k_calculate_iter_data(hw, NULL, &iter_data); - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; + len += snprintf(buf + len, sizeof(buf) - len, + "BSSID: %pM\n", common->curbssid); + len += snprintf(buf + len, sizeof(buf) - len, + "BSSID-MASK: %pM\n", common->bssidmask); + len += snprintf(buf + len, sizeof(buf) - len, + "OPMODE: %s\n", ath_opmode_to_string(sc->sc_ah->opmode)); ath9k_ps_wakeup(sc); - len += snprintf(buf + len, size - len, - "curbssid: %pM\n" - "OP-Mode: %s(%i)\n" - "Beacon-Timer-Register: 0x%x\n", - common->curbssid, - ath_opmode_to_string(sc->sc_ah->opmode), - (int)(sc->sc_ah->opmode), - REG_READ(ah, AR_BEACON_PERIOD)); - - reg = REG_READ(ah, AR_TIMER_MODE); + rxfilter = ath9k_hw_getrxfilter(sc->sc_ah); ath9k_ps_restore(sc); - len += snprintf(buf + len, size - len, "Timer-Mode-Register: 0x%x (", - reg); - if (reg & AR_TBTT_TIMER_EN) - len += snprintf(buf + len, size - len, "TBTT "); - if (reg & AR_DBA_TIMER_EN) - len += snprintf(buf + len, size - len, "DBA "); - if (reg & AR_SWBA_TIMER_EN) - len += snprintf(buf + len, size - len, "SWBA "); - if (reg & AR_HCF_TIMER_EN) - len += snprintf(buf + len, size - len, "HCF "); - if (reg & AR_TIM_TIMER_EN) - len += snprintf(buf + len, size - len, "TIM "); - if (reg & AR_DTIM_TIMER_EN) - len += snprintf(buf + len, size - len, "DTIM "); - len += snprintf(buf + len, size - len, ")\n"); + + len += snprintf(buf + len, sizeof(buf) - len, + "RXFILTER: 0x%x", rxfilter); + + if (rxfilter & ATH9K_RX_FILTER_UCAST) + len += snprintf(buf + len, sizeof(buf) - len, " UCAST"); + if (rxfilter & ATH9K_RX_FILTER_MCAST) + len += snprintf(buf + len, sizeof(buf) - len, " MCAST"); + if (rxfilter & ATH9K_RX_FILTER_BCAST) + len += snprintf(buf + len, sizeof(buf) - len, " BCAST"); + if (rxfilter & ATH9K_RX_FILTER_CONTROL) + len += snprintf(buf + len, sizeof(buf) - len, " CONTROL"); + if (rxfilter & ATH9K_RX_FILTER_BEACON) + len += snprintf(buf + len, sizeof(buf) - len, " BEACON"); + if (rxfilter & ATH9K_RX_FILTER_PROM) + len += snprintf(buf + len, sizeof(buf) - len, " PROM"); + if (rxfilter & ATH9K_RX_FILTER_PROBEREQ) + len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ"); + if (rxfilter & ATH9K_RX_FILTER_PHYERR) + len += snprintf(buf + len, sizeof(buf) - len, " PHYERR"); + if (rxfilter & ATH9K_RX_FILTER_MYBEACON) + len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON"); + if (rxfilter & ATH9K_RX_FILTER_COMP_BAR) + len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR"); + if (rxfilter & ATH9K_RX_FILTER_PSPOLL) + len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL"); + if (rxfilter & ATH9K_RX_FILTER_PHYRADAR) + len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR"); + if (rxfilter & ATH9K_RX_FILTER_MCAST_BCAST_ALL) + len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL"); + if (rxfilter & ATH9K_RX_FILTER_CONTROL_WRAPPER) + len += snprintf(buf + len, sizeof(buf) - len, " CONTROL_WRAPPER"); + + len += snprintf(buf + len, sizeof(buf) - len, "\n"); reg = sc->sc_ah->imask; - len += snprintf(buf + len, size - len, "imask: 0x%x (", reg); + + len += snprintf(buf + len, sizeof(buf) - len, "INTERRUPT-MASK: 0x%x", reg); + if (reg & ATH9K_INT_SWBA) - len += snprintf(buf + len, size - len, "SWBA "); + len += snprintf(buf + len, sizeof(buf) - len, " SWBA"); if (reg & ATH9K_INT_BMISS) - len += snprintf(buf + len, size - len, "BMISS "); + len += snprintf(buf + len, sizeof(buf) - len, " BMISS"); if (reg & ATH9K_INT_CST) - len += snprintf(buf + len, size - len, "CST "); + len += snprintf(buf + len, sizeof(buf) - len, " CST"); if (reg & ATH9K_INT_RX) - len += snprintf(buf + len, size - len, "RX "); + len += snprintf(buf + len, sizeof(buf) - len, " RX"); if (reg & ATH9K_INT_RXHP) - len += snprintf(buf + len, size - len, "RXHP "); + len += snprintf(buf + len, sizeof(buf) - len, " RXHP"); if (reg & ATH9K_INT_RXLP) - len += snprintf(buf + len, size - len, "RXLP "); + len += snprintf(buf + len, sizeof(buf) - len, " RXLP"); if (reg & ATH9K_INT_BB_WATCHDOG) - len += snprintf(buf + len, size - len, "BB_WATCHDOG "); - /* there are other IRQs if one wanted to add them. */ - len += snprintf(buf + len, size - len, ")\n"); + len += snprintf(buf + len, sizeof(buf) - len, " BB_WATCHDOG"); - len += snprintf(buf + len, size - len, - "VIF Counts: AP: %i STA: %i MESH: %i WDS: %i" - " ADHOC: %i OTHER: %i nvifs: %hi beacon-vifs: %hi\n", + len += snprintf(buf + len, sizeof(buf) - len, "\n"); + + ath9k_calculate_iter_data(hw, NULL, &iter_data); + + len += snprintf(buf + len, sizeof(buf) - len, + "VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i" + " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", iter_data.naps, iter_data.nstations, iter_data.nmeshes, - iter_data.nwds, iter_data.nadhocs, iter_data.nothers, + iter_data.nwds, iter_data.nadhocs, sc->nvifs, sc->nbcnvifs); - len += snprintf(buf + len, size - len, - "Calculated-BSSID-Mask: %pM\n", - iter_data.mask); - - if (len > size) - len = size; + if (len > sizeof(buf)) + len = sizeof(buf); retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return retval; } +static ssize_t read_file_reset(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[512]; + unsigned int len = 0; + + len += snprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "Baseband Hang", + sc->debug.stats.reset[RESET_TYPE_BB_HANG]); + len += snprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "Baseband Watchdog", + sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]); + len += snprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "Fatal HW Error", + sc->debug.stats.reset[RESET_TYPE_FATAL_INT]); + len += snprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "TX HW error", + sc->debug.stats.reset[RESET_TYPE_TX_ERROR]); + len += snprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "TX Path Hang", + sc->debug.stats.reset[RESET_TYPE_TX_HANG]); + len += snprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "PLL RX Hang", + sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, struct ath_txq *txq, unsigned int flags) @@ -880,6 +818,7 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN) TX_STAT_INC(qnum, delim_underrun); +#ifdef CONFIG_ATH9K_MAC_DEBUG spin_lock(&sc->debug.samp_lock); TX_SAMP_DBG(jiffies) = jiffies; TX_SAMP_DBG(rssi_ctl0) = ts->ts_rssi_ctl0; @@ -906,6 +845,7 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, sc->debug.tsidx = (sc->debug.tsidx + 1) % ATH_DBG_MAX_SAMPLES; spin_unlock(&sc->debug.samp_lock); +#endif #undef TX_SAMP_DBG } @@ -931,16 +871,23 @@ static const struct file_operations fops_misc = { .llseek = default_llseek, }; +static const struct file_operations fops_reset = { + .read = read_file_reset, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static ssize_t read_file_recv(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { #define PHY_ERR(s, p) \ - len += snprintf(buf + len, size - len, "%18s : %10u\n", s, \ + len += snprintf(buf + len, size - len, "%22s : %10u\n", s, \ sc->debug.stats.rxstats.phy_err_stats[p]); struct ath_softc *sc = file->private_data; char *buf; - unsigned int len = 0, size = 1400; + unsigned int len = 0, size = 1600; ssize_t retval = 0; buf = kzalloc(size, GFP_KERNEL); @@ -948,87 +895,59 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, return -ENOMEM; len += snprintf(buf + len, size - len, - "%18s : %10u\n", "CRC ERR", + "%22s : %10u\n", "CRC ERR", sc->debug.stats.rxstats.crc_err); len += snprintf(buf + len, size - len, - "%18s : %10u\n", "DECRYPT CRC ERR", + "%22s : %10u\n", "DECRYPT CRC ERR", sc->debug.stats.rxstats.decrypt_crc_err); len += snprintf(buf + len, size - len, - "%18s : %10u\n", "PHY ERR", + "%22s : %10u\n", "PHY ERR", sc->debug.stats.rxstats.phy_err); len += snprintf(buf + len, size - len, - "%18s : %10u\n", "MIC ERR", + "%22s : %10u\n", "MIC ERR", sc->debug.stats.rxstats.mic_err); len += snprintf(buf + len, size - len, - "%18s : %10u\n", "PRE-DELIM CRC ERR", + "%22s : %10u\n", "PRE-DELIM CRC ERR", sc->debug.stats.rxstats.pre_delim_crc_err); len += snprintf(buf + len, size - len, - "%18s : %10u\n", "POST-DELIM CRC ERR", + "%22s : %10u\n", "POST-DELIM CRC ERR", sc->debug.stats.rxstats.post_delim_crc_err); len += snprintf(buf + len, size - len, - "%18s : %10u\n", "DECRYPT BUSY ERR", + "%22s : %10u\n", "DECRYPT BUSY ERR", sc->debug.stats.rxstats.decrypt_busy_err); - len += snprintf(buf + len, size - len, - "%18s : %10d\n", "RSSI-CTL0", - sc->debug.stats.rxstats.rs_rssi_ctl0); - - len += snprintf(buf + len, size - len, - "%18s : %10d\n", "RSSI-CTL1", - sc->debug.stats.rxstats.rs_rssi_ctl1); - - len += snprintf(buf + len, size - len, - "%18s : %10d\n", "RSSI-CTL2", - sc->debug.stats.rxstats.rs_rssi_ctl2); - - len += snprintf(buf + len, size - len, - "%18s : %10d\n", "RSSI-EXT0", - sc->debug.stats.rxstats.rs_rssi_ext0); + PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); + PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING); + PHY_ERR("PARITY ERR", ATH9K_PHYERR_PARITY); + PHY_ERR("RATE ERR", ATH9K_PHYERR_RATE); + PHY_ERR("LENGTH ERR", ATH9K_PHYERR_LENGTH); + PHY_ERR("RADAR ERR", ATH9K_PHYERR_RADAR); + PHY_ERR("SERVICE ERR", ATH9K_PHYERR_SERVICE); + PHY_ERR("TOR ERR", ATH9K_PHYERR_TOR); + PHY_ERR("OFDM-TIMING ERR", ATH9K_PHYERR_OFDM_TIMING); + PHY_ERR("OFDM-SIGNAL-PARITY ERR", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); + PHY_ERR("OFDM-RATE ERR", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); + PHY_ERR("OFDM-LENGTH ERR", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); + PHY_ERR("OFDM-POWER-DROP ERR", ATH9K_PHYERR_OFDM_POWER_DROP); + PHY_ERR("OFDM-SERVICE ERR", ATH9K_PHYERR_OFDM_SERVICE); + PHY_ERR("OFDM-RESTART ERR", ATH9K_PHYERR_OFDM_RESTART); + PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT); + PHY_ERR("CCK-TIMING ERR", ATH9K_PHYERR_CCK_TIMING); + PHY_ERR("CCK-HEADER-CRC ERR", ATH9K_PHYERR_CCK_HEADER_CRC); + PHY_ERR("CCK-RATE ERR", ATH9K_PHYERR_CCK_RATE_ILLEGAL); + PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE); + PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART); + PHY_ERR("CCK-LENGTH ERR", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); + PHY_ERR("CCK-POWER-DROP ERR", ATH9K_PHYERR_CCK_POWER_DROP); + PHY_ERR("HT-CRC ERR", ATH9K_PHYERR_HT_CRC_ERROR); + PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); + PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL); len += snprintf(buf + len, size - len, - "%18s : %10d\n", "RSSI-EXT1", - sc->debug.stats.rxstats.rs_rssi_ext1); - - len += snprintf(buf + len, size - len, - "%18s : %10d\n", "RSSI-EXT2", - sc->debug.stats.rxstats.rs_rssi_ext2); - - len += snprintf(buf + len, size - len, - "%18s : %10d\n", "Rx Antenna", - sc->debug.stats.rxstats.rs_antenna); - - PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); - PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); - PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); - PHY_ERR("RATE", ATH9K_PHYERR_RATE); - PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH); - PHY_ERR("RADAR", ATH9K_PHYERR_RADAR); - PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE); - PHY_ERR("TOR", ATH9K_PHYERR_TOR); - PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING); - PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); - PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); - PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); - PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP); - PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE); - PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART); - PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT); - PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING); - PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC); - PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL); - PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE); - PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART); - PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); - PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP); - PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR); - PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); - PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL); - - len += snprintf(buf + len, size - len, - "%18s : %10u\n", "RX-Pkts-All", + "%22s : %10u\n", "RX-Pkts-All", sc->debug.stats.rxstats.rx_pkts_all); len += snprintf(buf + len, size - len, - "%18s : %10u\n", "RX-Bytes-All", + "%22s : %10u\n", "RX-Bytes-All", sc->debug.stats.rxstats.rx_bytes_all); if (len > size) @@ -1049,8 +968,6 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) #define RX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].rs\ [sc->debug.rsidx].c) - u32 phyerr; - RX_STAT_INC(rx_pkts_all); sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen; @@ -1069,20 +986,11 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) if (rs->rs_status & ATH9K_RXERR_PHY) { RX_STAT_INC(phy_err); - phyerr = rs->rs_phyerr & 0x24; - RX_PHY_ERR_INC(phyerr); + if (rs->rs_phyerr < ATH9K_PHYERR_MAX) + RX_PHY_ERR_INC(rs->rs_phyerr); } - sc->debug.stats.rxstats.rs_rssi_ctl0 = rs->rs_rssi_ctl0; - sc->debug.stats.rxstats.rs_rssi_ctl1 = rs->rs_rssi_ctl1; - sc->debug.stats.rxstats.rs_rssi_ctl2 = rs->rs_rssi_ctl2; - - sc->debug.stats.rxstats.rs_rssi_ext0 = rs->rs_rssi_ext0; - sc->debug.stats.rxstats.rs_rssi_ext1 = rs->rs_rssi_ext1; - sc->debug.stats.rxstats.rs_rssi_ext2 = rs->rs_rssi_ext2; - - sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna; - +#ifdef CONFIG_ATH9K_MAC_DEBUG spin_lock(&sc->debug.samp_lock); RX_SAMP_DBG(jiffies) = jiffies; RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl0; @@ -1099,6 +1007,8 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) sc->debug.rsidx = (sc->debug.rsidx + 1) % ATH_DBG_MAX_SAMPLES; spin_unlock(&sc->debug.samp_lock); +#endif + #undef RX_STAT_INC #undef RX_PHY_ERR_INC #undef RX_SAMP_DBG @@ -1342,6 +1252,8 @@ static const struct file_operations fops_modal_eeprom = { .llseek = default_llseek, }; +#ifdef CONFIG_ATH9K_MAC_DEBUG + void ath9k_debug_samp_bb_mac(struct ath_softc *sc) { #define ATH_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].c) @@ -1615,6 +1527,7 @@ static const struct file_operations fops_samps = { .llseek = default_llseek, }; +#endif int ath9k_init_debug(struct ath_hw *ah) { @@ -1637,14 +1550,14 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_dma); debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_interrupt); - debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, - sc, &fops_wiphy); debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_xmit); debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_stations); debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_misc); + debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_reset); debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_recv); debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, @@ -1668,8 +1581,10 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_base_eeprom); debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_modal_eeprom); +#ifdef CONFIG_ATH9K_MAC_DEBUG debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_samps); +#endif debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); @@ -1677,10 +1592,5 @@ int ath9k_init_debug(struct ath_hw *ah) debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); - sc->debug.regidx = 0; - memset(&sc->debug.bb_mac_samp, 0, sizeof(sc->debug.bb_mac_samp)); - sc->debug.sampidx = 0; - sc->debug.tsidx = 0; - sc->debug.rsidx = 0; return 0; } diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 776a24ada600..64fcfad467bf 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -165,13 +165,6 @@ struct ath_rx_stats { u32 post_delim_crc_err; u32 decrypt_busy_err; u32 phy_err_stats[ATH9K_PHYERR_MAX]; - int8_t rs_rssi_ctl0; - int8_t rs_rssi_ctl1; - int8_t rs_rssi_ctl2; - int8_t rs_rssi_ext0; - int8_t rs_rssi_ext1; - int8_t rs_rssi_ext2; - u8 rs_antenna; }; enum ath_reset_type { @@ -235,16 +228,17 @@ struct ath9k_debug { struct dentry *debugfs_phy; u32 regidx; struct ath_stats stats; +#ifdef CONFIG_ATH9K_MAC_DEBUG spinlock_t samp_lock; struct ath_dbg_bb_mac_samp bb_mac_samp[ATH_DBG_MAX_SAMPLES]; u8 sampidx; u8 tsidx; u8 rsidx; +#endif }; int ath9k_init_debug(struct ath_hw *ah); -void ath9k_debug_samp_bb_mac(struct ath_softc *sc); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, struct ath_txq *txq, @@ -258,10 +252,6 @@ static inline int ath9k_init_debug(struct ath_hw *ah) return 0; } -static inline void ath9k_debug_samp_bb_mac(struct ath_softc *sc) -{ -} - static inline void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) { @@ -282,4 +272,17 @@ static inline void ath_debug_stat_rx(struct ath_softc *sc, #endif /* CONFIG_ATH9K_DEBUGFS */ +#ifdef CONFIG_ATH9K_MAC_DEBUG + +void ath9k_debug_samp_bb_mac(struct ath_softc *sc); + +#else + +static inline void ath9k_debug_samp_bb_mac(struct ath_softc *sc) +{ +} + +#endif + + #endif /* DEBUG_H */ diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 597c84e31adb..fbe23de1297f 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -110,6 +110,8 @@ void ath_start_rfkill_poll(struct ath_softc *sc) wiphy_rfkill_start_polling(sc->hw->wiphy); } +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + /******************/ /* BTCOEX */ /******************/ @@ -245,13 +247,10 @@ static void ath_btcoex_no_stomp_timer(void *arg) ath9k_ps_restore(sc); } -int ath_init_btcoex_timer(struct ath_softc *sc) +static int ath_init_btcoex_timer(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; - if (ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_NONE) - return 0; - btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * btcoex->btcoex_period / 100; @@ -284,9 +283,6 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc) ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n"); - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) - return; - /* make sure duty cycle timer is also stopped when resuming */ if (btcoex->hw_timer_enabled) ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); @@ -307,9 +303,6 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc) struct ath_btcoex *btcoex = &sc->btcoex; struct ath_hw *ah = sc->sc_ah; - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) - return; - del_timer_sync(&btcoex->period_timer); if (btcoex->hw_timer_enabled) @@ -317,3 +310,114 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc) btcoex->hw_timer_enabled = false; } + +u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) +{ + struct ath_mci_profile *mci = &sc->btcoex.mci; + u16 aggr_limit = 0; + + if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit) + aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4; + else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED) + aggr_limit = min((max_4ms_framelen * 3) / 8, + (u32)ATH_AMPDU_LIMIT_MAX); + + return aggr_limit; +} + +void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status) +{ + struct ath_hw *ah = sc->sc_ah; + + if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) + if (status & ATH9K_INT_GENTIMER) + ath_gen_timer_isr(sc->sc_ah); + + if (status & ATH9K_INT_MCI) + ath_mci_intr(sc); +} + +void ath9k_start_btcoex(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) && + !ah->btcoex_hw.enabled) { + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); + ath9k_hw_btcoex_enable(ah); + + if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) + ath9k_btcoex_timer_resume(sc); + } +} + +void ath9k_stop_btcoex(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + if (ah->btcoex_hw.enabled && + ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { + ath9k_hw_btcoex_disable(ah); + if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) + ath9k_btcoex_timer_pause(sc); + if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_MCI) + ath_mci_flush_profile(&sc->btcoex.mci); + } +} + +void ath9k_deinit_btcoex(struct ath_softc *sc) +{ + if ((sc->btcoex.no_stomp_timer) && + ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE) + ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); + + if (ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_MCI) + ath_mci_cleanup(sc); +} + +int ath9k_init_btcoex(struct ath_softc *sc) +{ + struct ath_txq *txq; + struct ath_hw *ah = sc->sc_ah; + int r; + + ath9k_hw_btcoex_init_scheme(ah); + + switch (ath9k_hw_get_btcoex_scheme(sc->sc_ah)) { + case ATH_BTCOEX_CFG_NONE: + break; + case ATH_BTCOEX_CFG_2WIRE: + ath9k_hw_btcoex_init_2wire(sc->sc_ah); + break; + case ATH_BTCOEX_CFG_3WIRE: + ath9k_hw_btcoex_init_3wire(sc->sc_ah); + r = ath_init_btcoex_timer(sc); + if (r) + return -1; + txq = sc->tx.txq_map[WME_AC_BE]; + ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); + sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; + break; + case ATH_BTCOEX_CFG_MCI: + sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; + sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; + INIT_LIST_HEAD(&sc->btcoex.mci.info); + + r = ath_mci_setup(sc); + if (r) + return r; + + ath9k_hw_btcoex_init_mci(ah); + + break; + default: + WARN_ON(1); + break; + } + + return 0; +} + +#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 77c8ded8de57..424aabb2c730 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -968,8 +968,7 @@ static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev) ath9k_hif_usb_dealloc_rx_urbs(hif_dev); } -static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev, - u32 drv_info) +static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) { int transfer, err; const void *data = hif_dev->firmware->data; @@ -982,7 +981,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev, return -ENOMEM; while (len) { - transfer = min_t(int, len, 4096); + transfer = min_t(size_t, len, 4096); memcpy(buf, data, transfer); err = usb_control_msg(hif_dev->udev, @@ -1000,7 +999,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev, } kfree(buf); - if (IS_AR7010_DEVICE(drv_info)) + if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info)) firm_offset = AR7010_FIRMWARE_TEXT; else firm_offset = AR9271_FIRMWARE_TEXT; @@ -1021,28 +1020,18 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev, return 0; } -static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev, u32 drv_info) +static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) { - int ret, idx; struct usb_host_interface *alt = &hif_dev->interface->altsetting[0]; struct usb_endpoint_descriptor *endp; + int ret, idx; - /* Request firmware */ - ret = request_firmware(&hif_dev->firmware, hif_dev->fw_name, - &hif_dev->udev->dev); - if (ret) { - dev_err(&hif_dev->udev->dev, - "ath9k_htc: Firmware - %s not found\n", hif_dev->fw_name); - goto err_fw_req; - } - - /* Download firmware */ - ret = ath9k_hif_usb_download_fw(hif_dev, drv_info); + ret = ath9k_hif_usb_download_fw(hif_dev); if (ret) { dev_err(&hif_dev->udev->dev, "ath9k_htc: Firmware - %s download failed\n", hif_dev->fw_name); - goto err_fw_download; + return ret; } /* On downloading the firmware to the target, the USB descriptor of EP4 @@ -1064,23 +1053,84 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev, u32 drv_info) if (ret) { dev_err(&hif_dev->udev->dev, "ath9k_htc: Unable to allocate URBs\n"); - goto err_fw_download; + return ret; } return 0; - -err_fw_download: - release_firmware(hif_dev->firmware); -err_fw_req: - hif_dev->firmware = NULL; - return ret; } static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev) { ath9k_hif_usb_dealloc_urbs(hif_dev); - if (hif_dev->firmware) - release_firmware(hif_dev->firmware); +} + +/* + * If initialization fails or the FW cannot be retrieved, + * detach the device. + */ +static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev) +{ + struct device *parent = hif_dev->udev->dev.parent; + + complete(&hif_dev->fw_done); + + if (parent) + device_lock(parent); + + device_release_driver(&hif_dev->udev->dev); + + if (parent) + device_unlock(parent); +} + +static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context) +{ + struct hif_device_usb *hif_dev = context; + int ret; + + if (!fw) { + dev_err(&hif_dev->udev->dev, + "ath9k_htc: Failed to get firmware %s\n", + hif_dev->fw_name); + goto err_fw; + } + + hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev, &hif_usb, + &hif_dev->udev->dev); + if (hif_dev->htc_handle == NULL) { + goto err_fw; + } + + hif_dev->firmware = fw; + + /* Proceed with initialization */ + + ret = ath9k_hif_usb_dev_init(hif_dev); + if (ret) + goto err_dev_init; + + ret = ath9k_htc_hw_init(hif_dev->htc_handle, + &hif_dev->interface->dev, + hif_dev->usb_device_id->idProduct, + hif_dev->udev->product, + hif_dev->usb_device_id->driver_info); + if (ret) { + ret = -EINVAL; + goto err_htc_hw_init; + } + + complete(&hif_dev->fw_done); + + return; + +err_htc_hw_init: + ath9k_hif_usb_dev_deinit(hif_dev); +err_dev_init: + ath9k_htc_hw_free(hif_dev->htc_handle); + release_firmware(fw); + hif_dev->firmware = NULL; +err_fw: + ath9k_hif_usb_firmware_fail(hif_dev); } /* @@ -1155,20 +1205,16 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, } usb_get_dev(udev); + hif_dev->udev = udev; hif_dev->interface = interface; - hif_dev->device_id = id->idProduct; + hif_dev->usb_device_id = id; #ifdef CONFIG_PM udev->reset_resume = 1; #endif usb_set_intfdata(interface, hif_dev); - hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev, &hif_usb, - &hif_dev->udev->dev); - if (hif_dev->htc_handle == NULL) { - ret = -ENOMEM; - goto err_htc_hw_alloc; - } + init_completion(&hif_dev->fw_done); /* Find out which firmware to load */ @@ -1177,29 +1223,22 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, else hif_dev->fw_name = FIRMWARE_AR9271; - ret = ath9k_hif_usb_dev_init(hif_dev, id->driver_info); - if (ret) { - ret = -EINVAL; - goto err_hif_init_usb; - } - - ret = ath9k_htc_hw_init(hif_dev->htc_handle, - &interface->dev, hif_dev->device_id, - hif_dev->udev->product, id->driver_info); + ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name, + &hif_dev->udev->dev, GFP_KERNEL, + hif_dev, ath9k_hif_usb_firmware_cb); if (ret) { - ret = -EINVAL; - goto err_htc_hw_init; + dev_err(&hif_dev->udev->dev, + "ath9k_htc: Async request for firmware %s failed\n", + hif_dev->fw_name); + goto err_fw_req; } - dev_info(&hif_dev->udev->dev, "ath9k_htc: USB layer initialized\n"); + dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n", + hif_dev->fw_name); return 0; -err_htc_hw_init: - ath9k_hif_usb_dev_deinit(hif_dev); -err_hif_init_usb: - ath9k_htc_hw_free(hif_dev->htc_handle); -err_htc_hw_alloc: +err_fw_req: usb_set_intfdata(interface, NULL); kfree(hif_dev); usb_put_dev(udev); @@ -1234,9 +1273,15 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface) if (!hif_dev) return; - ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged); - ath9k_htc_hw_free(hif_dev->htc_handle); - ath9k_hif_usb_dev_deinit(hif_dev); + wait_for_completion(&hif_dev->fw_done); + + if (hif_dev->firmware) { + ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged); + ath9k_htc_hw_free(hif_dev->htc_handle); + ath9k_hif_usb_dev_deinit(hif_dev); + release_firmware(hif_dev->firmware); + } + usb_set_intfdata(interface, NULL); if (!unplugged && (hif_dev->flags & HIF_USB_START)) @@ -1276,8 +1321,7 @@ static int ath9k_hif_usb_resume(struct usb_interface *interface) return ret; if (hif_dev->firmware) { - ret = ath9k_hif_usb_download_fw(hif_dev, - htc_handle->drv_priv->ah->hw_version.usbdev); + ret = ath9k_hif_usb_download_fw(hif_dev); if (ret) goto fail_resume; } else { diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index 794f63094e5d..487ff658b4c1 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -87,10 +87,11 @@ struct cmd_buf { #define HIF_USB_START BIT(0) struct hif_device_usb { - u16 device_id; struct usb_device *udev; struct usb_interface *interface; + const struct usb_device_id *usb_device_id; const struct firmware *firmware; + struct completion fw_done; struct htc_target *htc_handle; struct hif_usb_tx tx; struct usb_anchor regout_submitted; diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index da5596766d82..135795257d95 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -400,9 +400,21 @@ struct ath_btcoex { u32 btscan_no_stomp; }; -void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv); -void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv); -void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv); +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT +void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product); +void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv); +void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv); +#else +static inline void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product) +{ +} +static inline void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv) +{ +} +static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv) +{ +} +#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ #define OP_INVALID BIT(0) #define OP_SCANNING BIT(1) @@ -483,7 +495,10 @@ struct ath9k_htc_priv { int cabq; int hwq_map[WME_NUM_AC]; +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT struct ath_btcoex btcoex; +#endif + struct delayed_work coex_period_work; struct delayed_work duty_cycle_work; #ifdef CONFIG_ATH9K_HTC_DEBUGFS diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 6506e1fd5036..1c10e2e5c237 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -20,6 +20,10 @@ /* BTCOEX */ /******************/ +#define ATH_HTC_BTCOEX_PRODUCT_ID "wb193" + +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + /* * Detects if there is any priority bt traffic */ @@ -111,13 +115,10 @@ static void ath_btcoex_duty_cycle_work(struct work_struct *work) ath9k_hw_btcoex_enable(priv->ah); } -void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv) +static void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv) { struct ath_btcoex *btcoex = &priv->btcoex; - if (ath9k_hw_get_btcoex_scheme(priv->ah) == ATH_BTCOEX_CFG_NONE) - return; - btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD; btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * btcoex->btcoex_period / 100; @@ -131,14 +132,11 @@ void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv) * (Re)start btcoex work */ -void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv) +static void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv) { struct ath_btcoex *btcoex = &priv->btcoex; struct ath_hw *ah = priv->ah; - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) - return; - ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex work\n"); btcoex->bt_priority_cnt = 0; @@ -151,15 +149,66 @@ void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv) /* * Cancel btcoex and bt duty cycle work. */ -void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv) +static void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv) { - if (ath9k_hw_get_btcoex_scheme(priv->ah) == ATH_BTCOEX_CFG_NONE) - return; - cancel_delayed_work_sync(&priv->coex_period_work); cancel_delayed_work_sync(&priv->duty_cycle_work); } +void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv) +{ + struct ath_hw *ah = priv->ah; + + if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) { + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); + ath9k_hw_btcoex_enable(ah); + ath_htc_resume_btcoex_work(priv); + } +} + +void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv) +{ + struct ath_hw *ah = priv->ah; + + if (ah->btcoex_hw.enabled && + ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { + ath9k_hw_btcoex_disable(ah); + if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) + ath_htc_cancel_btcoex_work(priv); + } +} + +void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product) +{ + struct ath_hw *ah = priv->ah; + int qnum; + + if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) { + ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE; + } + + switch (ath9k_hw_get_btcoex_scheme(priv->ah)) { + case ATH_BTCOEX_CFG_NONE: + break; + case ATH_BTCOEX_CFG_3WIRE: + priv->ah->btcoex_hw.btactive_gpio = 7; + priv->ah->btcoex_hw.btpriority_gpio = 6; + priv->ah->btcoex_hw.wlanactive_gpio = 8; + priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; + ath9k_hw_btcoex_init_3wire(priv->ah); + ath_htc_init_btcoex_work(priv); + qnum = priv->hwq_map[WME_AC_BE]; + ath9k_hw_init_btcoex_hw(priv->ah, qnum); + break; + default: + WARN_ON(1); + break; + } +} + +#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ + /*******/ /* LED */ /*******/ diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 9be10a2da1c2..de5ee15ee639 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -41,8 +41,6 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); .max_power = 20, \ } -#define ATH_HTC_BTCOEX_PRODUCT_ID "wb193" - static struct ieee80211_channel ath9k_2ghz_channels[] = { CHAN2G(2412, 0), /* Channel 1 */ CHAN2G(2417, 1), /* Channel 2 */ @@ -603,29 +601,6 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv) priv->ah->opmode = NL80211_IFTYPE_STATION; } -static void ath9k_init_btcoex(struct ath9k_htc_priv *priv) -{ - int qnum; - - switch (ath9k_hw_get_btcoex_scheme(priv->ah)) { - case ATH_BTCOEX_CFG_NONE: - break; - case ATH_BTCOEX_CFG_3WIRE: - priv->ah->btcoex_hw.btactive_gpio = 7; - priv->ah->btcoex_hw.btpriority_gpio = 6; - priv->ah->btcoex_hw.wlanactive_gpio = 8; - priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - ath9k_hw_btcoex_init_3wire(priv->ah); - ath_htc_init_btcoex_work(priv); - qnum = priv->hwq_map[WME_AC_BE]; - ath9k_hw_init_btcoex_hw(priv->ah, qnum); - break; - default: - WARN_ON(1); - break; - } -} - static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid, char *product, u32 drv_info) @@ -698,12 +673,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, ath9k_cmn_init_crypto(ah); ath9k_init_channels_rates(priv); ath9k_init_misc(priv); - - if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) { - ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE; - if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) - ath9k_init_btcoex(priv); - } + ath9k_htc_init_btcoex(priv, product); return 0; @@ -741,6 +711,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->queues = 4; hw->channel_change_time = 5000; hw->max_listen_interval = 10; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index ef4c60661290..2b8f61c210e1 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -919,7 +919,6 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) /* setup initial channel */ init_channel = ath9k_cmn_get_curchannel(hw, ah); - ath9k_hw_htc_resetinit(ah); ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false); if (ret) { ath_err(common, @@ -957,12 +956,8 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) mod_timer(&priv->tx.cleanup_timer, jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) { - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); - ath9k_hw_btcoex_enable(ah); - ath_htc_resume_btcoex_work(priv); - } + ath9k_htc_start_btcoex(priv); + mutex_unlock(&priv->mutex); return ret; @@ -1009,12 +1004,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); - if (ah->btcoex_hw.enabled && - ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { - ath9k_hw_btcoex_disable(ah); - if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) - ath_htc_cancel_btcoex_work(priv); - } + ath9k_htc_stop_btcoex(priv); /* Remove a monitor interface if it's present. */ if (priv->ah->is_monitoring) @@ -1409,6 +1399,21 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw, if (htc_modparam_nohwcrypt) return -ENOSPC; + if ((vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT) && + (key->cipher == WLAN_CIPHER_SUITE_TKIP || + key->cipher == WLAN_CIPHER_SUITE_CCMP) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + /* + * For now, disable hw crypto for the RSN IBSS group keys. This + * could be optimized in the future to use a modified key cache + * design to support per-STA RX GTK, but until that gets + * implemented, use of software crypto for group addressed + * frames is a acceptable to allow RSN IBSS to be used. + */ + return -EOPNOTSUPP; + } + mutex_lock(&priv->mutex); ath_dbg(common, CONFIG, "Set HW Key\n"); ath9k_htc_ps_wakeup(priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 1b90ed8795c3..c25226a32ddc 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -431,11 +431,8 @@ struct htc_target *ath9k_htc_hw_alloc(void *hif_handle, struct htc_target *target; target = kzalloc(sizeof(struct htc_target), GFP_KERNEL); - if (!target) { - printk(KERN_ERR "Unable to allocate memory for" - "target device\n"); + if (!target) return NULL; - } init_completion(&target->target_wait); init_completion(&target->cmd_wait); diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index c4ad0b06bdbc..265bf77598a2 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -24,7 +24,7 @@ static inline void ath9k_hw_configpcipowersave(struct ath_hw *ah, bool power_off) { - if (ah->aspm_enabled != true) + if (!ah->aspm_enabled) return; ath9k_hw_ops(ah)->config_pci_powersave(ah, power_off); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 87db1ee1c298..6c69e4e8b1cb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -23,6 +23,7 @@ #include "hw-ops.h" #include "rc.h" #include "ar9003_mac.h" +#include "ar9003_mci.h" static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type); @@ -448,6 +449,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->slottime = ATH9K_SLOT_TIME_9; ah->globaltxtimeout = (u32) -1; ah->power_mode = ATH9K_PM_UNDEFINED; + ah->htc_reset_init = true; } static int ath9k_hw_init_macaddr(struct ath_hw *ah) @@ -554,7 +556,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) return -EIO; } - if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) { + if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) { if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || ((AR_SREV_9160(ah) || AR_SREV_9280(ah)) && !ah->is_pciexpress)) { @@ -618,9 +620,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (!ah->is_pciexpress) ath9k_hw_disablepcie(ah); - if (!AR_SREV_9300_20_OR_LATER(ah)) - ar9002_hw_cck_chan14_spread(ah); - r = ath9k_hw_post_init(ah); if (r) return r; @@ -1385,10 +1384,16 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) static bool ath9k_hw_chip_reset(struct ath_hw *ah, struct ath9k_channel *chan) { - if (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) { - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) - return false; - } else if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) + int reset_type = ATH9K_RESET_WARM; + + if (AR_SREV_9280(ah)) { + if (ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) + reset_type = ATH9K_RESET_POWER_ON; + else + reset_type = ATH9K_RESET_COLD; + } + + if (!ath9k_hw_set_reset_reg(ah, reset_type)) return false; if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) @@ -1514,70 +1519,95 @@ bool ath9k_hw_check_alive(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_check_alive); -int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, - struct ath9k_hw_cal_data *caldata, bool bChannelChange) +/* + * Fast channel change: + * (Change synthesizer based on channel freq without resetting chip) + * + * Don't do FCC when + * - Flag is not set + * - Chip is just coming out of full sleep + * - Channel to be set is same as current channel + * - Channel flags are different, (eg.,moving from 2GHz to 5GHz channel) + */ +static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; - u32 saveLedState; - struct ath9k_channel *curchan = ah->curchan; - u32 saveDefAntenna; - u32 macStaId1; - u64 tsf = 0; - int i, r; - bool allow_fbs = false; - bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI); - bool save_fullsleep = ah->chip_fullsleep; + int ret; - if (mci) { + if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI) + goto fail; - ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan)); + if (ah->chip_fullsleep) + goto fail; - if (mci_hw->bt_state == MCI_BT_CAL_START) { - u32 payload[4] = {0, 0, 0, 0}; + if (!ah->curchan) + goto fail; - ath_dbg(common, MCI, "MCI stop rx for BT CAL\n"); + if (chan->channel == ah->curchan->channel) + goto fail; - mci_hw->bt_state = MCI_BT_CAL; + if ((chan->channelFlags & CHANNEL_ALL) != + (ah->curchan->channelFlags & CHANNEL_ALL)) + goto fail; - /* - * MCI FIX: disable mci interrupt here. This is to avoid - * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and - * lead to mci_intr reentry. - */ + if (!ath9k_hw_check_alive(ah)) + goto fail; - ar9003_mci_disable_interrupt(ah); + /* + * For AR9462, make sure that calibration data for + * re-using are present. + */ + if (AR_SREV_9462(ah) && (!ah->caldata || + !ah->caldata->done_txiqcal_once || + !ah->caldata->done_txclcal_once || + !ah->caldata->rtt_hist.num_readings)) + goto fail; - ath_dbg(common, MCI, "send WLAN_CAL_GRANT\n"); - MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); - ar9003_mci_send_message(ah, MCI_GPM, 0, payload, - 16, true, false); + ath_dbg(common, RESET, "FastChannelChange for %d -> %d\n", + ah->curchan->channel, chan->channel); - ath_dbg(common, MCI, "\nMCI BT is calibrating\n"); + ret = ath9k_hw_channel_change(ah, chan); + if (!ret) + goto fail; - /* Wait BT calibration to be completed for 25ms */ + ath9k_hw_loadnf(ah, ah->curchan); + ath9k_hw_start_nfcal(ah, true); - if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, - 0, 25000)) - ath_dbg(common, MCI, - "MCI got BT_CAL_DONE\n"); - else - ath_dbg(common, MCI, - "MCI ### BT cal takes to long, force bt_state to be bt_awake\n"); - mci_hw->bt_state = MCI_BT_AWAKE; - /* MCI FIX: enable mci interrupt here */ - ar9003_mci_enable_interrupt(ah); + if ((ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && ar9003_mci_is_ready(ah)) + ar9003_mci_2g5g_switch(ah, true); - return true; - } - } + if (AR_SREV_9271(ah)) + ar9002_hw_load_ani_reg(ah, chan); + + return 0; +fail: + return -EINVAL; +} + +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); + u32 saveLedState; + u32 saveDefAntenna; + u32 macStaId1; + u64 tsf = 0; + int i, r; + bool start_mci_reset = false; + bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI); + bool save_fullsleep = ah->chip_fullsleep; + if (mci) { + start_mci_reset = ar9003_mci_start_reset(ah, chan); + if (start_mci_reset) + return 0; + } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; - if (curchan && !ah->chip_fullsleep) - ath9k_hw_getnf(ah, curchan); + if (ah->curchan && !ah->chip_fullsleep) + ath9k_hw_getnf(ah, ah->curchan); ah->caldata = caldata; if (caldata && @@ -1590,47 +1620,14 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, } ah->noise = ath9k_hw_getchan_noise(ah, chan); - if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI) - bChannelChange = false; - - if (caldata && - caldata->done_txiqcal_once && - caldata->done_txclcal_once && - caldata->rtt_hist.num_readings) - allow_fbs = true; - - if (bChannelChange && - (ah->chip_fullsleep != true) && - (ah->curchan != NULL) && - (chan->channel != ah->curchan->channel) && - (allow_fbs || - ((chan->channelFlags & CHANNEL_ALL) == - (ah->curchan->channelFlags & CHANNEL_ALL)))) { - if (ath9k_hw_channel_change(ah, chan)) { - ath9k_hw_loadnf(ah, ah->curchan); - ath9k_hw_start_nfcal(ah, true); - if (mci && mci_hw->ready) - ar9003_mci_2g5g_switch(ah, true); - - if (AR_SREV_9271(ah)) - ar9002_hw_load_ani_reg(ah, chan); - return 0; - } - } - - if (mci) { - ar9003_mci_disable_interrupt(ah); - - if (mci_hw->ready && !save_fullsleep) { - ar9003_mci_mute_bt(ah); - udelay(20); - REG_WRITE(ah, AR_BTCOEX_CTRL, 0); - } - - mci_hw->bt_state = MCI_BT_SLEEP; - mci_hw->ready = false; + if (fastcc) { + r = ath9k_hw_do_fastcc(ah, chan); + if (!r) + return r; } + if (mci) + ar9003_mci_stop_bt(ah, save_fullsleep); saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA); if (saveDefAntenna == 0) @@ -1807,53 +1804,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_loadnf(ah, chan); ath9k_hw_start_nfcal(ah, true); - if (mci && mci_hw->ready) { - - if (IS_CHAN_2GHZ(chan) && - (mci_hw->bt_state == MCI_BT_SLEEP)) { - - if (ar9003_mci_check_int(ah, - AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) || - ar9003_mci_check_int(ah, - AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) { - - /* - * BT is sleeping. Check if BT wakes up during - * WLAN calibration. If BT wakes up during - * WLAN calibration, need to go through all - * message exchanges again and recal. - */ - - ath_dbg(common, MCI, - "MCI BT wakes up during WLAN calibration\n"); - - REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, - AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | - AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE); - ath_dbg(common, MCI, "MCI send REMOTE_RESET\n"); - ar9003_mci_remote_reset(ah, true); - ar9003_mci_send_sys_waking(ah, true); - udelay(1); - if (IS_CHAN_2GHZ(chan)) - ar9003_mci_send_lna_transfer(ah, true); - - mci_hw->bt_state = MCI_BT_AWAKE; - - ath_dbg(common, MCI, "MCI re-cal\n"); - - if (caldata) { - caldata->done_txiqcal_once = false; - caldata->done_txclcal_once = false; - caldata->rtt_hist.num_readings = 0; - } - - if (!ath9k_hw_init_cal(ah, chan)) - return -EIO; - - } - } - ar9003_mci_enable_interrupt(ah); - } + if (mci && ar9003_mci_end_reset(ah, chan, caldata)) + return -EIO; ENABLE_REGWRITE_BUFFER(ah); @@ -1894,24 +1846,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, #endif } - if (ah->btcoex_hw.enabled && - ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) + if (ath9k_hw_btcoex_is_enabled(ah)) ath9k_hw_btcoex_enable(ah); - if (mci && mci_hw->ready) { - /* - * check BT state again to make - * sure it's not changed. - */ - - ar9003_mci_sync_bt_state(ah); - ar9003_mci_2g5g_switch(ah, true); - - if ((mci_hw->bt_state == MCI_BT_AWAKE) && - (mci_hw->query_bt == true)) { - mci_hw->need_flush_btinfo = true; - } - } + if (mci) + ar9003_mci_check_bt(ah); if (AR_SREV_9300_20_OR_LATER(ah)) { ar9003_hw_bb_watchdog_config(ah); @@ -1962,8 +1901,7 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); /* Shutdown chip. Active low */ - if (!AR_SREV_5416(ah) && - !AR_SREV_9271(ah) && !AR_SREV_9462_10(ah)) { + if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) { REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); udelay(2); } @@ -2038,8 +1976,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) if (setChip) { if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { - if (ath9k_hw_set_reset_reg(ah, - ATH9K_RESET_POWER_ON) != true) { + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { return false; } if (!AR_SREV_9300_20_OR_LATER(ah)) @@ -2077,7 +2014,6 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) { struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; int status = true, setChip = true; static const char *modes[] = { "AWAKE", @@ -2101,20 +2037,8 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) break; case ATH9K_PM_FULL_SLEEP: - - if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) { - if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) && - (mci->bt_state != MCI_BT_SLEEP) && - !mci->halted_bt_gpm) { - ath_dbg(common, MCI, - "MCI halt BT GPM (full_sleep)\n"); - ar9003_mci_send_coex_halt_bt_gpm(ah, - true, true); - } - - mci->ready = false; - REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); - } + if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) + ar9003_mci_set_full_sleep(ah); ath9k_set_power_sleep(ah, setChip); ah->chip_fullsleep = true; @@ -2304,7 +2228,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); - struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; unsigned int chip_chainmask; u16 eeval; @@ -2423,30 +2346,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - if (common->btcoex_enabled) { - if (AR_SREV_9462(ah)) - btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI; - else if (AR_SREV_9300_20_OR_LATER(ah)) { - btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; - btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300; - btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300; - btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300; - } else if (AR_SREV_9280_20_OR_LATER(ah)) { - btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280; - btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280; - - if (AR_SREV_9285(ah)) { - btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; - btcoex_hw->btpriority_gpio = - ATH_BTPRIORITY_GPIO_9285; - } else { - btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; - } - } - } else { - btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE; - } - if (AR_SREV_9300_20_OR_LATER(ah)) { pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_FASTCLOCK; if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah)) @@ -2530,8 +2429,17 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9485_OR_LATER(ah)) ah->enabled_cals |= TX_IQ_ON_AGC_CAL; } - if (AR_SREV_9462(ah)) - pCap->hw_caps |= ATH9K_HW_CAP_RTT | ATH9K_HW_CAP_MCI; + + if (AR_SREV_9462(ah)) { + + if (!(ah->ent_mode & AR_ENT_OTP_49GHZ_DISABLE)) + pCap->hw_caps |= ATH9K_HW_CAP_MCI; + + if (AR_SREV_9462_20(ah)) + pCap->hw_caps |= ATH9K_HW_CAP_RTT; + + } + return 0; } @@ -2657,12 +2565,6 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) } EXPORT_SYMBOL(ath9k_hw_set_gpio); -u32 ath9k_hw_getdefantenna(struct ath_hw *ah) -{ - return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; -} -EXPORT_SYMBOL(ath9k_hw_getdefantenna); - void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna) { REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); @@ -2720,6 +2622,7 @@ bool ath9k_hw_phy_disable(struct ath_hw *ah) return false; ath9k_hw_init_pll(ah, NULL); + ah->htc_reset_init = true; return true; } EXPORT_SYMBOL(ath9k_hw_phy_disable); @@ -3080,12 +2983,6 @@ EXPORT_SYMBOL(ath_gen_timer_isr); /* HTC */ /********/ -void ath9k_hw_htc_resetinit(struct ath_hw *ah) -{ - ah->htc_reset_init = true; -} -EXPORT_SYMBOL(ath9k_hw_htc_resetinit); - static struct { u32 version; const char * name; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c8261d4fc780..aa1680a0c7fd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -209,11 +209,7 @@ enum ath9k_hw_caps { ATH9K_HW_CAP_5GHZ = BIT(12), ATH9K_HW_CAP_APM = BIT(13), ATH9K_HW_CAP_RTT = BIT(14), -#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT ATH9K_HW_CAP_MCI = BIT(15), -#else - ATH9K_HW_CAP_MCI = 0, -#endif ATH9K_HW_CAP_DFS = BIT(16), }; @@ -432,161 +428,6 @@ enum ath9k_rx_qtype { ATH9K_RX_QUEUE_MAX, }; -enum mci_message_header { /* length of payload */ - MCI_LNA_CTRL = 0x10, /* len = 0 */ - MCI_CONT_NACK = 0x20, /* len = 0 */ - MCI_CONT_INFO = 0x30, /* len = 4 */ - MCI_CONT_RST = 0x40, /* len = 0 */ - MCI_SCHD_INFO = 0x50, /* len = 16 */ - MCI_CPU_INT = 0x60, /* len = 4 */ - MCI_SYS_WAKING = 0x70, /* len = 0 */ - MCI_GPM = 0x80, /* len = 16 */ - MCI_LNA_INFO = 0x90, /* len = 1 */ - MCI_LNA_STATE = 0x94, - MCI_LNA_TAKE = 0x98, - MCI_LNA_TRANS = 0x9c, - MCI_SYS_SLEEPING = 0xa0, /* len = 0 */ - MCI_REQ_WAKE = 0xc0, /* len = 0 */ - MCI_DEBUG_16 = 0xfe, /* len = 2 */ - MCI_REMOTE_RESET = 0xff /* len = 16 */ -}; - -enum ath_mci_gpm_coex_profile_type { - MCI_GPM_COEX_PROFILE_UNKNOWN, - MCI_GPM_COEX_PROFILE_RFCOMM, - MCI_GPM_COEX_PROFILE_A2DP, - MCI_GPM_COEX_PROFILE_HID, - MCI_GPM_COEX_PROFILE_BNEP, - MCI_GPM_COEX_PROFILE_VOICE, - MCI_GPM_COEX_PROFILE_MAX -}; - -/* MCI GPM/Coex opcode/type definitions */ -enum { - MCI_GPM_COEX_W_GPM_PAYLOAD = 1, - MCI_GPM_COEX_B_GPM_TYPE = 4, - MCI_GPM_COEX_B_GPM_OPCODE = 5, - /* MCI_GPM_WLAN_CAL_REQ, MCI_GPM_WLAN_CAL_DONE */ - MCI_GPM_WLAN_CAL_W_SEQUENCE = 2, - - /* MCI_GPM_COEX_VERSION_QUERY */ - /* MCI_GPM_COEX_VERSION_RESPONSE */ - MCI_GPM_COEX_B_MAJOR_VERSION = 6, - MCI_GPM_COEX_B_MINOR_VERSION = 7, - /* MCI_GPM_COEX_STATUS_QUERY */ - MCI_GPM_COEX_B_BT_BITMAP = 6, - MCI_GPM_COEX_B_WLAN_BITMAP = 7, - /* MCI_GPM_COEX_HALT_BT_GPM */ - MCI_GPM_COEX_B_HALT_STATE = 6, - /* MCI_GPM_COEX_WLAN_CHANNELS */ - MCI_GPM_COEX_B_CHANNEL_MAP = 6, - /* MCI_GPM_COEX_BT_PROFILE_INFO */ - MCI_GPM_COEX_B_PROFILE_TYPE = 6, - MCI_GPM_COEX_B_PROFILE_LINKID = 7, - MCI_GPM_COEX_B_PROFILE_STATE = 8, - MCI_GPM_COEX_B_PROFILE_ROLE = 9, - MCI_GPM_COEX_B_PROFILE_RATE = 10, - MCI_GPM_COEX_B_PROFILE_VOTYPE = 11, - MCI_GPM_COEX_H_PROFILE_T = 12, - MCI_GPM_COEX_B_PROFILE_W = 14, - MCI_GPM_COEX_B_PROFILE_A = 15, - /* MCI_GPM_COEX_BT_STATUS_UPDATE */ - MCI_GPM_COEX_B_STATUS_TYPE = 6, - MCI_GPM_COEX_B_STATUS_LINKID = 7, - MCI_GPM_COEX_B_STATUS_STATE = 8, - /* MCI_GPM_COEX_BT_UPDATE_FLAGS */ - MCI_GPM_COEX_W_BT_FLAGS = 6, - MCI_GPM_COEX_B_BT_FLAGS_OP = 10 -}; - -enum mci_gpm_subtype { - MCI_GPM_BT_CAL_REQ = 0, - MCI_GPM_BT_CAL_GRANT = 1, - MCI_GPM_BT_CAL_DONE = 2, - MCI_GPM_WLAN_CAL_REQ = 3, - MCI_GPM_WLAN_CAL_GRANT = 4, - MCI_GPM_WLAN_CAL_DONE = 5, - MCI_GPM_COEX_AGENT = 0x0c, - MCI_GPM_RSVD_PATTERN = 0xfe, - MCI_GPM_RSVD_PATTERN32 = 0xfefefefe, - MCI_GPM_BT_DEBUG = 0xff -}; - -enum mci_bt_state { - MCI_BT_SLEEP, - MCI_BT_AWAKE, - MCI_BT_CAL_START, - MCI_BT_CAL -}; - -/* Type of state query */ -enum mci_state_type { - MCI_STATE_ENABLE, - MCI_STATE_INIT_GPM_OFFSET, - MCI_STATE_NEXT_GPM_OFFSET, - MCI_STATE_LAST_GPM_OFFSET, - MCI_STATE_BT, - MCI_STATE_SET_BT_SLEEP, - MCI_STATE_SET_BT_AWAKE, - MCI_STATE_SET_BT_CAL_START, - MCI_STATE_SET_BT_CAL, - MCI_STATE_LAST_SCHD_MSG_OFFSET, - MCI_STATE_REMOTE_SLEEP, - MCI_STATE_CONT_RSSI_POWER, - MCI_STATE_CONT_PRIORITY, - MCI_STATE_CONT_TXRX, - MCI_STATE_RESET_REQ_WAKE, - MCI_STATE_SEND_WLAN_COEX_VERSION, - MCI_STATE_SET_BT_COEX_VERSION, - MCI_STATE_SEND_WLAN_CHANNELS, - MCI_STATE_SEND_VERSION_QUERY, - MCI_STATE_SEND_STATUS_QUERY, - MCI_STATE_NEED_FLUSH_BT_INFO, - MCI_STATE_SET_CONCUR_TX_PRI, - MCI_STATE_RECOVER_RX, - MCI_STATE_NEED_FTP_STOMP, - MCI_STATE_NEED_TUNING, - MCI_STATE_DEBUG, - MCI_STATE_MAX -}; - -enum mci_gpm_coex_opcode { - MCI_GPM_COEX_VERSION_QUERY, - MCI_GPM_COEX_VERSION_RESPONSE, - MCI_GPM_COEX_STATUS_QUERY, - MCI_GPM_COEX_HALT_BT_GPM, - MCI_GPM_COEX_WLAN_CHANNELS, - MCI_GPM_COEX_BT_PROFILE_INFO, - MCI_GPM_COEX_BT_STATUS_UPDATE, - MCI_GPM_COEX_BT_UPDATE_FLAGS -}; - -#define MCI_GPM_NOMORE 0 -#define MCI_GPM_MORE 1 -#define MCI_GPM_INVALID 0xffffffff - -#define MCI_GPM_RECYCLE(_p_gpm) do { \ - *(((u32 *)_p_gpm) + MCI_GPM_COEX_W_GPM_PAYLOAD) = \ - MCI_GPM_RSVD_PATTERN32; \ -} while (0) - -#define MCI_GPM_TYPE(_p_gpm) \ - (*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) & 0xff) - -#define MCI_GPM_OPCODE(_p_gpm) \ - (*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) & 0xff) - -#define MCI_GPM_SET_CAL_TYPE(_p_gpm, _cal_type) do { \ - *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_cal_type) & 0xff;\ -} while (0) - -#define MCI_GPM_SET_TYPE_OPCODE(_p_gpm, _type, _opcode) do { \ - *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_type) & 0xff; \ - *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) = (_opcode) & 0xff;\ -} while (0) - -#define MCI_GPM_IS_CAL_TYPE(_type) ((_type) <= MCI_GPM_WLAN_CAL_DONE) - struct ath9k_beacon_state { u32 bs_nexttbtt; u32 bs_nextdtim; @@ -956,8 +797,9 @@ struct ath_hw { int firpwr[5]; enum ath9k_ani_cmd ani_function; - /* Bluetooth coexistance */ +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT struct ath_btcoex_hw btcoex_hw; +#endif u32 intr_txqs; u8 txchainmask; @@ -985,19 +827,14 @@ struct ath_hw { struct ar5416IniArray iniAddac; struct ar5416IniArray iniPcieSerdes; struct ar5416IniArray iniPcieSerdesLowPower; - struct ar5416IniArray iniModesAdditional; - struct ar5416IniArray iniModesAdditional_40M; + struct ar5416IniArray iniModesFastClock; + struct ar5416IniArray iniAdditional; struct ar5416IniArray iniModesRxGain; struct ar5416IniArray iniModesTxGain; - struct ar5416IniArray iniModes_9271_1_0_only; struct ar5416IniArray iniCckfirNormal; struct ar5416IniArray iniCckfirJapan2484; struct ar5416IniArray ini_japan2484; - struct ar5416IniArray iniCommon_normal_cck_fir_coeff_9271; - struct ar5416IniArray iniCommon_japan_2484_cck_fir_coeff_9271; struct ar5416IniArray iniModes_9271_ANI_reg; - struct ar5416IniArray iniModes_high_power_tx_gain_9271; - struct ar5416IniArray iniModes_normal_power_tx_gain_9271; struct ar5416IniArray ini_radio_post_sys2ant; struct ar5416IniArray ini_BTCOEX_MAX_TXPWR; @@ -1082,7 +919,7 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_deinit(struct ath_hw *ah); int ath9k_hw_init(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, - struct ath9k_hw_cal_data *caldata, bool bChannelChange); + struct ath9k_hw_cal_data *caldata, bool fastcc); int ath9k_hw_fill_cap_info(struct ath_hw *ah); u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan); @@ -1092,7 +929,6 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio); void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, u32 ah_signal_type); void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val); -u32 ath9k_hw_getdefantenna(struct ath_hw *ah); void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); /* General Operation */ @@ -1146,9 +982,6 @@ void ath_gen_timer_isr(struct ath_hw *hw); void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len); -/* HTC */ -void ath9k_hw_htc_resetinit(struct ath_hw *ah); - /* PHY */ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, u32 *coef_mantissa, u32 *coef_exponent); @@ -1158,7 +991,6 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan); * Code Specific to AR5008, AR9001 or AR9002, * we stuff these here to avoid callbacks for AR9003. */ -void ar9002_hw_cck_chan14_spread(struct ath_hw *ah); int ar9002_hw_rf_claim(struct ath_hw *ah); void ar9002_hw_enable_async_fifo(struct ath_hw *ah); @@ -1205,41 +1037,31 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); void ath9k_hw_proc_mib_event(struct ath_hw *ah); void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); -bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag, - u32 *payload, u8 len, bool wait_done, - bool check_bt); -void ar9003_mci_mute_bt(struct ath_hw *ah); -u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data); -void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, - u16 len, u32 sched_addr); -void ar9003_mci_cleanup(struct ath_hw *ah); -void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt, - bool wait_done); -u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, - u8 gpm_opcode, int time_out); -void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g); -void ar9003_mci_disable_interrupt(struct ath_hw *ah); -void ar9003_mci_enable_interrupt(struct ath_hw *ah); -void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done); -void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, - bool is_full_sleep); -bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints); -void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done); -void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done); -void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done); -void ar9003_mci_sync_bt_state(struct ath_hw *ah); -void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, - u32 *rx_msg_intr); - #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT +static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah) +{ + return ah->btcoex_hw.enabled; +} +void ath9k_hw_btcoex_enable(struct ath_hw *ah); static inline enum ath_btcoex_scheme ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) { return ah->btcoex_hw.scheme; } #else -#define ath9k_hw_get_btcoex_scheme(...) ATH_BTCOEX_CFG_NONE -#endif +static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah) +{ + return false; +} +static inline void ath9k_hw_btcoex_enable(struct ath_hw *ah) +{ +} +static inline enum ath_btcoex_scheme +ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) +{ + return ATH_BTCOEX_CFG_NONE; +} +#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ #define ATH9K_CLOCK_RATE_CCK 22 #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 53a005d288aa..60159f4ee532 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -172,7 +172,7 @@ static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) struct ath_common *common = ath9k_hw_common(ah); struct ath_softc *sc = (struct ath_softc *) common->priv; - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { unsigned long flags; spin_lock_irqsave(&sc->sc_serial_rw, flags); iowrite32(val, sc->mem + reg_offset); @@ -188,7 +188,7 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) struct ath_softc *sc = (struct ath_softc *) common->priv; u32 val; - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { unsigned long flags; spin_lock_irqsave(&sc->sc_serial_rw, flags); val = ioread32(sc->mem + reg_offset); @@ -219,7 +219,7 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl unsigned long uninitialized_var(flags); u32 val; - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { spin_lock_irqsave(&sc->sc_serial_rw, flags); val = __ath9k_reg_rmw(sc, reg_offset, set, clr); spin_unlock_irqrestore(&sc->sc_serial_rw, flags); @@ -419,66 +419,6 @@ fail: return error; } -static int ath9k_init_btcoex(struct ath_softc *sc) -{ - struct ath_txq *txq; - struct ath_hw *ah = sc->sc_ah; - int r; - - switch (ath9k_hw_get_btcoex_scheme(sc->sc_ah)) { - case ATH_BTCOEX_CFG_NONE: - break; - case ATH_BTCOEX_CFG_2WIRE: - ath9k_hw_btcoex_init_2wire(sc->sc_ah); - break; - case ATH_BTCOEX_CFG_3WIRE: - ath9k_hw_btcoex_init_3wire(sc->sc_ah); - r = ath_init_btcoex_timer(sc); - if (r) - return -1; - txq = sc->tx.txq_map[WME_AC_BE]; - ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); - sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - break; - case ATH_BTCOEX_CFG_MCI: - sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; - INIT_LIST_HEAD(&sc->btcoex.mci.info); - - r = ath_mci_setup(sc); - if (r) - return r; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) { - ah->btcoex_hw.mci.ready = false; - ah->btcoex_hw.mci.bt_state = 0; - ah->btcoex_hw.mci.bt_ver_major = 3; - ah->btcoex_hw.mci.bt_ver_minor = 0; - ah->btcoex_hw.mci.bt_version_known = false; - ah->btcoex_hw.mci.update_2g5g = true; - ah->btcoex_hw.mci.is_2g = true; - ah->btcoex_hw.mci.wlan_channels_update = false; - ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000; - ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff; - ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff; - ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff; - ah->btcoex_hw.mci.query_bt = true; - ah->btcoex_hw.mci.unhalt_bt_gpm = true; - ah->btcoex_hw.mci.halted_bt_gpm = false; - ah->btcoex_hw.mci.need_flush_btinfo = false; - ah->btcoex_hw.mci.wlan_cal_seq = 0; - ah->btcoex_hw.mci.wlan_cal_done = 0; - ah->btcoex_hw.mci.config = 0x2201; - } - break; - default: - WARN_ON(1); - break; - } - - return 0; -} - static int ath9k_init_queues(struct ath_softc *sc) { int i = 0; @@ -544,19 +484,11 @@ static void ath9k_init_misc(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); int i = 0; + setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); sc->config.txpowlimit = ATH_TXPOWER_MAX; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - sc->sc_flags |= SC_OP_TXAGGR; - sc->sc_flags |= SC_OP_RXAGGR; - } - - sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah); - memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); - sc->beacon.slottime = ATH9K_SLOT_TIME_9; for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) @@ -615,9 +547,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, mutex_init(&sc->mutex); #ifdef CONFIG_ATH9K_DEBUGFS spin_lock_init(&sc->nodes_lock); - spin_lock_init(&sc->debug.samp_lock); INIT_LIST_HEAD(&sc->nodes); #endif +#ifdef CONFIG_ATH9K_MAC_DEBUG + spin_lock_init(&sc->debug.samp_lock); +#endif tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, (unsigned long)sc); @@ -880,12 +814,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc) if (sc->sbands[IEEE80211_BAND_5GHZ].channels) kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels); - if ((sc->btcoex.no_stomp_timer) && - ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE) - ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); - - if (ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_MCI) - ath_mci_cleanup(sc); + ath9k_deinit_btcoex(sc); for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index e196aba77acf..f7bd2532269c 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -185,13 +185,6 @@ bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q) } EXPORT_SYMBOL(ath9k_hw_stop_dma_queue); -void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs) -{ - *txqs &= ah->intr_txqs; - ah->intr_txqs &= ~(*txqs); -} -EXPORT_SYMBOL(ath9k_hw_gettxintrtxqs); - bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, const struct ath9k_tx_queue_info *qinfo) { @@ -340,6 +333,15 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, } EXPORT_SYMBOL(ath9k_hw_setuptxqueue); +static void ath9k_hw_clear_queue_interrupts(struct ath_hw *ah, u32 q) +{ + ah->txok_interrupt_mask &= ~(1 << q); + ah->txerr_interrupt_mask &= ~(1 << q); + ah->txdesc_interrupt_mask &= ~(1 << q); + ah->txeol_interrupt_mask &= ~(1 << q); + ah->txurn_interrupt_mask &= ~(1 << q); +} + bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) { struct ath_common *common = ath9k_hw_common(ah); @@ -354,11 +356,7 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) ath_dbg(common, QUEUE, "Release TX queue: %u\n", q); qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; - ah->txok_interrupt_mask &= ~(1 << q); - ah->txerr_interrupt_mask &= ~(1 << q); - ah->txdesc_interrupt_mask &= ~(1 << q); - ah->txeol_interrupt_mask &= ~(1 << q); - ah->txurn_interrupt_mask &= ~(1 << q); + ath9k_hw_clear_queue_interrupts(ah, q); ath9k_hw_set_txq_interrupts(ah, qi); return true; @@ -510,26 +508,17 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) if (AR_SREV_9300_20_OR_LATER(ah)) REG_WRITE(ah, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN); - if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) + ath9k_hw_clear_queue_interrupts(ah, q); + if (qi->tqi_qflags & TXQ_FLAG_TXINT_ENABLE) { ah->txok_interrupt_mask |= 1 << q; - else - ah->txok_interrupt_mask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE) ah->txerr_interrupt_mask |= 1 << q; - else - ah->txerr_interrupt_mask &= ~(1 << q); + } if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) ah->txdesc_interrupt_mask |= 1 << q; - else - ah->txdesc_interrupt_mask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) ah->txeol_interrupt_mask |= 1 << q; - else - ah->txeol_interrupt_mask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) ah->txurn_interrupt_mask |= 1 << q; - else - ah->txurn_interrupt_mask &= ~(1 << q); ath9k_hw_set_txq_interrupts(ah, qi); return true; @@ -745,7 +734,10 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah) qi.tqi_aifs = 1; qi.tqi_cwmin = 0; qi.tqi_cwmax = 0; - /* NB: don't enable any interrupts */ + + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + qi.tqi_qflags = TXQ_FLAG_TXINT_ENABLE; + return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); } EXPORT_SYMBOL(ath9k_hw_beaconq_setup); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 11dbd1473a13..21c955609e6c 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -583,8 +583,7 @@ enum ath9k_tx_queue { #define ATH9K_WME_UPSD 4 enum ath9k_tx_queue_flags { - TXQ_FLAG_TXOKINT_ENABLE = 0x0001, - TXQ_FLAG_TXERRINT_ENABLE = 0x0001, + TXQ_FLAG_TXINT_ENABLE = 0x0001, TXQ_FLAG_TXDESCINT_ENABLE = 0x0002, TXQ_FLAG_TXEOLINT_ENABLE = 0x0004, TXQ_FLAG_TXURNINT_ENABLE = 0x0008, @@ -714,7 +713,6 @@ u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q); void ath9k_hw_abort_tx_dma(struct ath_hw *ah); -void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs); bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, const struct ath9k_tx_queue_info *qinfo); bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 4a00806e2852..38794850f005 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -118,13 +118,15 @@ void ath9k_ps_restore(struct ath_softc *sc) if (--sc->ps_usecount != 0) goto unlock; - if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK)) + if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) + goto unlock; + + if (sc->ps_idle) mode = ATH9K_PM_FULL_SLEEP; else if (sc->ps_enabled && !(sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | - PS_WAIT_FOR_PSPOLL_DATA | - PS_WAIT_FOR_TX_ACK))) + PS_WAIT_FOR_PSPOLL_DATA))) mode = ATH9K_PM_NETWORK_SLEEP; else goto unlock; @@ -332,17 +334,11 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, hchan = ah->curchan; } - if (fastcc && (ah->chip_fullsleep || - !ath9k_hw_check_alive(ah))) - fastcc = false; - if (!ath_prepare_reset(sc, retry_tx, flush)) fastcc = false; ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", - hchan->channel, !!(hchan->channelFlags & (CHANNEL_HT40MINUS | - CHANNEL_HT40PLUS)), - fastcc); + hchan->channel, IS_CHAN_HT40(hchan), fastcc); r = ath9k_hw_reset(ah, hchan, caldata, fastcc); if (r) { @@ -373,12 +369,8 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (sc->sc_flags & SC_OP_INVALID) return -EIO; - ath9k_ps_wakeup(sc); - r = ath_reset_internal(sc, hchan, false); - ath9k_ps_restore(sc); - return r; } @@ -647,7 +639,8 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, #endif an->sta = sta; an->vif = vif; - if (sc->sc_flags & SC_OP_TXAGGR) { + + if (sta->ht_cap.ht_supported) { ath_tx_node_init(sc, an); an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + sta->ht_cap.ampdu_factor); @@ -666,7 +659,7 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) an->sta = NULL; #endif - if (sc->sc_flags & SC_OP_TXAGGR) + if (sta->ht_cap.ht_supported) ath_tx_node_cleanup(sc, an); } @@ -741,12 +734,7 @@ void ath9k_tasklet(unsigned long data) ath_tx_tasklet(sc); } - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) - if (status & ATH9K_INT_GENTIMER) - ath_gen_timer_isr(sc->sc_ah); - - if ((status & ATH9K_INT_MCI) && ATH9K_HW_CAP_MCI) - ath_mci_intr(sc); + ath9k_btcoex_handle_interrupt(sc, status); out: /* re-enable hardware interrupt */ @@ -1004,12 +992,8 @@ static int ath9k_start(struct ieee80211_hw *hw) curchan->center_freq); ath9k_ps_wakeup(sc); - mutex_lock(&sc->mutex); - /* setup initial channel */ - sc->chan_idx = curchan->hw_value; - init_channel = ath9k_cmn_get_curchannel(hw, ah); /* Reset SERDES registers */ @@ -1058,9 +1042,6 @@ static int ath9k_start(struct ieee80211_hw *hw) sc->sc_flags &= ~SC_OP_INVALID; sc->sc_ah->is_monitoring = false; - /* Disable BMISS interrupt when we're not associated */ - ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - if (!ath_complete_reset(sc, false)) { r = -EIO; spin_unlock_bh(&sc->sc_pcu_lock); @@ -1081,16 +1062,7 @@ static int ath9k_start(struct ieee80211_hw *hw) spin_unlock_bh(&sc->sc_pcu_lock); - if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) && - !ah->btcoex_hw.enabled) { - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); - ath9k_hw_btcoex_enable(ah); - - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) - ath9k_btcoex_timer_resume(sc); - } + ath9k_start_btcoex(sc); if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en) common->bus_ops->extn_synch_en(common); @@ -1191,13 +1163,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) /* Ensure HW is awake when we try to shut it down. */ ath9k_ps_wakeup(sc); - if (ah->btcoex_hw.enabled && - ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { - ath9k_hw_btcoex_disable(ah); - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) - ath9k_btcoex_timer_pause(sc); - ath_mci_flush_profile(&sc->btcoex.mci); - } + ath9k_stop_btcoex(sc); spin_lock_bh(&sc->sc_pcu_lock); @@ -1303,7 +1269,6 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) iter_data->nwds++; break; default: - iter_data->nothers++; break; } } @@ -1589,12 +1554,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); - /* - * Leave this as the first check because we need to turn on the - * radio if it was disabled before prior to processing the rest - * of the changes. Likewise we must only disable the radio towards - * the end. - */ if (changed & IEEE80211_CONF_CHANGE_IDLE) { sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); if (sc->ps_idle) @@ -1793,7 +1752,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_node *an = (struct ath_node *) sta->drv_priv; - if (!(sc->sc_flags & SC_OP_TXAGGR)) + if (!sta->ht_cap.ht_supported) return; switch (cmd) { @@ -2005,7 +1964,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); - if (changed & BSS_CHANGED_BSSID) { + if (changed & BSS_CHANGED_ASSOC) { ath9k_config_bss(sc, vif); ath_dbg(common, CONFIG, "BSSID: %pM aid: 0x%x\n", @@ -2085,25 +2044,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath_beacon_config(sc, vif); } - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - ath_dbg(common, CONFIG, "BSS Changed PREAMBLE %d\n", - bss_conf->use_short_preamble); - if (bss_conf->use_short_preamble) - sc->sc_flags |= SC_OP_PREAMBLE_SHORT; - else - sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; - } - - if (changed & BSS_CHANGED_ERP_CTS_PROT) { - ath_dbg(common, CONFIG, "BSS Changed CTS PROT %d\n", - bss_conf->use_cts_prot); - if (bss_conf->use_cts_prot && - hw->conf.channel->band != IEEE80211_BAND_5GHZ) - sc->sc_flags |= SC_OP_PROTECT_ENABLE; - else - sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; - } - mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); } @@ -2161,15 +2101,10 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: - if (!(sc->sc_flags & SC_OP_RXAGGR)) - ret = -ENOTSUPP; break; case IEEE80211_AMPDU_RX_STOP: break; case IEEE80211_AMPDU_TX_START: - if (!(sc->sc_flags & SC_OP_TXAGGR)) - return -EOPNOTSUPP; - ath9k_ps_wakeup(sc); ret = ath_tx_aggr_start(sc, sta, tid, ssn); if (!ret) @@ -2332,6 +2267,7 @@ static int ath9k_tx_last_beacon(struct ieee80211_hw *hw) struct ath_vif *avp; struct ath_buf *bf; struct ath_tx_status ts; + bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); int status; vif = sc->beacon.bslot[0]; @@ -2342,7 +2278,7 @@ static int ath9k_tx_last_beacon(struct ieee80211_hw *hw) if (!avp->is_bslot_active) return 0; - if (!sc->beacon.tx_processed) { + if (!sc->beacon.tx_processed && !edma) { tasklet_disable(&sc->bcon_tasklet); bf = avp->av_bcbuf; diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 05c23ea4c633..29fe52d69973 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -42,24 +42,18 @@ static bool ath_mci_add_profile(struct ath_common *common, struct ath_mci_profile_info *entry; if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) && - (info->type == MCI_GPM_COEX_PROFILE_VOICE)) { - ath_dbg(common, MCI, - "Too many SCO profile, failed to add new profile\n"); + (info->type == MCI_GPM_COEX_PROFILE_VOICE)) return false; - } if (((NUM_PROF(mci) - mci->num_sco) == ATH_MCI_MAX_ACL_PROFILE) && - (info->type != MCI_GPM_COEX_PROFILE_VOICE)) { - ath_dbg(common, MCI, - "Too many ACL profile, failed to add new profile\n"); + (info->type != MCI_GPM_COEX_PROFILE_VOICE)) return false; - } entry = ath_mci_find_profile(mci, info); - if (entry) + if (entry) { memcpy(entry, info, 10); - else { + } else { entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return false; @@ -68,6 +62,7 @@ static bool ath_mci_add_profile(struct ath_common *common, INC_PROF(mci, info); list_add_tail(&info->list, &mci->info); } + return true; } @@ -79,10 +74,9 @@ static void ath_mci_del_profile(struct ath_common *common, entry = ath_mci_find_profile(mci, info); - if (!entry) { - ath_dbg(common, MCI, "Profile to be deleted not found\n"); + if (!entry) return; - } + DEC_PROF(mci, entry); list_del(&entry->list); kfree(entry); @@ -177,13 +171,12 @@ static void ath_mci_update_scheme(struct ath_softc *sc) btcoex->btcoex_period *= 1000; btcoex->btcoex_no_stomp = btcoex->btcoex_period * - (100 - btcoex->duty_cycle) / 100; + (100 - btcoex->duty_cycle) / 100; ath9k_hw_btcoex_enable(sc->sc_ah); ath9k_btcoex_timer_resume(sc); } - static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) { struct ath_hw *ah = sc->sc_ah; @@ -192,42 +185,24 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) switch (opcode) { case MCI_GPM_BT_CAL_REQ: - - ath_dbg(common, MCI, "MCI received BT_CAL_REQ\n"); - if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) { ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START, NULL); ieee80211_queue_work(sc->hw, &sc->hw_reset_work); - } else - ath_dbg(common, MCI, "MCI State mismatches: %d\n", + } else { + ath_dbg(common, MCI, "MCI State mismatch: %d\n", ar9003_mci_state(ah, MCI_STATE_BT, NULL)); - + } break; - case MCI_GPM_BT_CAL_DONE: - - ath_dbg(common, MCI, "MCI received BT_CAL_DONE\n"); - - if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_CAL) - ath_dbg(common, MCI, "MCI error illegal!\n"); - else - ath_dbg(common, MCI, "MCI BT not in CAL state\n"); - + ar9003_mci_state(ah, MCI_STATE_BT, NULL); break; - case MCI_GPM_BT_CAL_GRANT: - - ath_dbg(common, MCI, "MCI received BT_CAL_GRANT\n"); - - /* Send WLAN_CAL_DONE for now */ - ath_dbg(common, MCI, "MCI send WLAN_CAL_DONE\n"); MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE); ar9003_mci_send_message(sc->sc_ah, MCI_GPM, 0, payload, 16, false, true); break; - default: - ath_dbg(common, MCI, "MCI Unknown GPM CAL message\n"); + ath_dbg(common, MCI, "Unknown GPM CAL message\n"); break; } } @@ -247,6 +222,7 @@ static void ath_mci_process_profile(struct ath_softc *sc, btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD; mci->aggr_limit = mci->num_sco ? 6 : 0; + if (NUM_PROF(mci)) { btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)]; @@ -262,31 +238,24 @@ static void ath_mci_process_profile(struct ath_softc *sc, static void ath_mci_process_status(struct ath_softc *sc, struct ath_mci_profile_status *status) { - struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_btcoex *btcoex = &sc->btcoex; struct ath_mci_profile *mci = &btcoex->mci; struct ath_mci_profile_info info; int i = 0, old_num_mgmt = mci->num_mgmt; /* Link status type are not handled */ - if (status->is_link) { - ath_dbg(common, MCI, "Skip link type status update\n"); + if (status->is_link) return; - } memset(&info, 0, sizeof(struct ath_mci_profile_info)); info.conn_handle = status->conn_handle; - if (ath_mci_find_profile(mci, &info)) { - ath_dbg(common, MCI, - "Skip non link state update for existing profile %d\n", - status->conn_handle); + if (ath_mci_find_profile(mci, &info)) return; - } - if (status->conn_handle >= ATH_MCI_MAX_PROFILE) { - ath_dbg(common, MCI, "Ignore too many non-link update\n"); + + if (status->conn_handle >= ATH_MCI_MAX_PROFILE) return; - } + if (status->is_critical) __set_bit(status->conn_handle, mci->status); else @@ -314,43 +283,28 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) u32 seq_num; switch (opcode) { - case MCI_GPM_COEX_VERSION_QUERY: - ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n"); - version = ar9003_mci_state(ah, - MCI_STATE_SEND_WLAN_COEX_VERSION, NULL); + version = ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION, + NULL); break; - case MCI_GPM_COEX_VERSION_RESPONSE: - ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n"); major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION); minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION); - ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n", - major, minor); version = (major << 8) + minor; - version = ar9003_mci_state(ah, - MCI_STATE_SET_BT_COEX_VERSION, &version); + version = ar9003_mci_state(ah, MCI_STATE_SET_BT_COEX_VERSION, + &version); break; - case MCI_GPM_COEX_STATUS_QUERY: - ath_dbg(common, MCI, - "MCI Recv GPM COEX Status Query = 0x%02x\n", - *(rx_payload + MCI_GPM_COEX_B_WLAN_BITMAP)); - ar9003_mci_state(ah, - MCI_STATE_SEND_WLAN_CHANNELS, NULL); + ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_CHANNELS, NULL); break; - case MCI_GPM_COEX_BT_PROFILE_INFO: - ath_dbg(common, MCI, "MCI Recv GPM Coex BT profile info\n"); memcpy(&profile_info, (rx_payload + MCI_GPM_COEX_B_PROFILE_TYPE), 10); - if ((profile_info.type == MCI_GPM_COEX_PROFILE_UNKNOWN) - || (profile_info.type >= - MCI_GPM_COEX_PROFILE_MAX)) { - + if ((profile_info.type == MCI_GPM_COEX_PROFILE_UNKNOWN) || + (profile_info.type >= MCI_GPM_COEX_PROFILE_MAX)) { ath_dbg(common, MCI, - "illegal profile type = %d, state = %d\n", + "Illegal profile type = %d, state = %d\n", profile_info.type, profile_info.start); break; @@ -358,7 +312,6 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) ath_mci_process_profile(sc, &profile_info); break; - case MCI_GPM_COEX_BT_STATUS_UPDATE: profile_status.is_link = *(rx_payload + MCI_GPM_COEX_B_STATUS_TYPE); @@ -369,98 +322,66 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) seq_num = *((u32 *)(rx_payload + 12)); ath_dbg(common, MCI, - "MCI Recv GPM COEX BT_Status_Update: is_link=%d, linkId=%d, state=%d, SEQ=%d\n", + "BT_Status_Update: is_link=%d, linkId=%d, state=%d, SEQ=%d\n", profile_status.is_link, profile_status.conn_handle, profile_status.is_critical, seq_num); ath_mci_process_status(sc, &profile_status); break; - default: - ath_dbg(common, MCI, "MCI Unknown GPM COEX message = 0x%02x\n", - opcode); + ath_dbg(common, MCI, "Unknown GPM COEX message = 0x%02x\n", opcode); break; } } -static int ath_mci_buf_alloc(struct ath_softc *sc, struct ath_mci_buf *buf) -{ - int error = 0; - - buf->bf_addr = dma_alloc_coherent(sc->dev, buf->bf_len, - &buf->bf_paddr, GFP_KERNEL); - - if (buf->bf_addr == NULL) { - error = -ENOMEM; - goto fail; - } - - return 0; - -fail: - memset(buf, 0, sizeof(*buf)); - return error; -} - -static void ath_mci_buf_free(struct ath_softc *sc, struct ath_mci_buf *buf) -{ - if (buf->bf_addr) { - dma_free_coherent(sc->dev, buf->bf_len, buf->bf_addr, - buf->bf_paddr); - memset(buf, 0, sizeof(*buf)); - } -} - int ath_mci_setup(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_mci_coex *mci = &sc->mci_coex; - int error = 0; - - if (!ATH9K_HW_CAP_MCI) - return 0; + struct ath_mci_buf *buf = &mci->sched_buf; - mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE; + buf->bf_addr = dma_alloc_coherent(sc->dev, + ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE, + &buf->bf_paddr, GFP_KERNEL); - if (ath_mci_buf_alloc(sc, &mci->sched_buf)) { + if (buf->bf_addr == NULL) { ath_dbg(common, FATAL, "MCI buffer alloc failed\n"); - error = -ENOMEM; - goto fail; + return -ENOMEM; } - mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE; + memset(buf->bf_addr, MCI_GPM_RSVD_PATTERN, + ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE); - memset(mci->sched_buf.bf_addr, MCI_GPM_RSVD_PATTERN, - mci->sched_buf.bf_len); + mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE; mci->gpm_buf.bf_len = ATH_MCI_GPM_BUF_SIZE; - mci->gpm_buf.bf_addr = (u8 *)mci->sched_buf.bf_addr + - mci->sched_buf.bf_len; + mci->gpm_buf.bf_addr = (u8 *)mci->sched_buf.bf_addr + mci->sched_buf.bf_len; mci->gpm_buf.bf_paddr = mci->sched_buf.bf_paddr + mci->sched_buf.bf_len; - /* initialize the buffer */ - memset(mci->gpm_buf.bf_addr, MCI_GPM_RSVD_PATTERN, mci->gpm_buf.bf_len); - ar9003_mci_setup(sc->sc_ah, mci->gpm_buf.bf_paddr, mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4), mci->sched_buf.bf_paddr); -fail: - return error; + + ath_dbg(common, MCI, "MCI Initialized\n"); + + return 0; } void ath_mci_cleanup(struct ath_softc *sc) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_hw *ah = sc->sc_ah; struct ath_mci_coex *mci = &sc->mci_coex; + struct ath_mci_buf *buf = &mci->sched_buf; - if (!ATH9K_HW_CAP_MCI) - return; + if (buf->bf_addr) + dma_free_coherent(sc->dev, + ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE, + buf->bf_addr, buf->bf_paddr); - /* - * both schedule and gpm buffers will be released - */ - ath_mci_buf_free(sc, &mci->sched_buf); ar9003_mci_cleanup(ah); + + ath_dbg(common, MCI, "MCI De-Initialized\n"); } void ath_mci_intr(struct ath_softc *sc) @@ -474,19 +395,10 @@ void ath_mci_intr(struct ath_softc *sc) u32 more_data = MCI_GPM_MORE; bool skip_gpm = false; - if (!ATH9K_HW_CAP_MCI) - return; - ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg); if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) == 0) { - - ar9003_mci_state(sc->sc_ah, MCI_STATE_INIT_GPM_OFFSET, NULL); - ath_dbg(common, MCI, "MCI interrupt but MCI disabled\n"); - - ath_dbg(common, MCI, - "MCI interrupt: intr = 0x%x, intr_rxmsg = 0x%x\n", - mci_int, mci_int_rxmsg); + ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL); return; } @@ -499,11 +411,8 @@ void ath_mci_intr(struct ath_softc *sc) * only when BT wake up. Now they are always sent, as a * recovery method to reset BT MCI's RX alignment. */ - ath_dbg(common, MCI, "MCI interrupt send REMOTE_RESET\n"); - ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, payload, 16, true, false); - ath_dbg(common, MCI, "MCI interrupt send SYS_WAKING\n"); ar9003_mci_send_message(ah, MCI_SYS_WAKING, 0, NULL, 0, true, false); @@ -513,74 +422,51 @@ void ath_mci_intr(struct ath_softc *sc) /* * always do this for recovery and 2G/5G toggling and LNA_TRANS */ - ath_dbg(common, MCI, "MCI Set BT state to AWAKE\n"); ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, NULL); } - /* Processing SYS_WAKING/SYS_SLEEPING */ if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING; if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_SLEEP) { - - if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) - == MCI_BT_SLEEP) - ath_dbg(common, MCI, - "MCI BT stays in sleep mode\n"); - else { - ath_dbg(common, MCI, - "MCI Set BT state to AWAKE\n"); - ar9003_mci_state(ah, - MCI_STATE_SET_BT_AWAKE, NULL); - } - } else - ath_dbg(common, MCI, "MCI BT stays in AWAKE mode\n"); + if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) != + MCI_BT_SLEEP) + ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, + NULL); + } } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) { - mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING; if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) { - - if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) - == MCI_BT_AWAKE) - ath_dbg(common, MCI, - "MCI BT stays in AWAKE mode\n"); - else { - ath_dbg(common, MCI, - "MCI SetBT state to SLEEP\n"); + if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) != + MCI_BT_AWAKE) ar9003_mci_state(ah, MCI_STATE_SET_BT_SLEEP, NULL); - } - } else - ath_dbg(common, MCI, "MCI BT stays in SLEEP mode\n"); + } } if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) || (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) { - - ath_dbg(common, MCI, "MCI RX broken, skip GPM msgs\n"); ar9003_mci_state(ah, MCI_STATE_RECOVER_RX, NULL); skip_gpm = true; } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) { - mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO; offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET, NULL); } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) { - mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM; while (more_data == MCI_GPM_MORE) { pgpm = mci->gpm_buf.bf_addr; - offset = ar9003_mci_state(ah, - MCI_STATE_NEXT_GPM_OFFSET, &more_data); + offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET, + &more_data); if (offset == MCI_GPM_INVALID) break; @@ -591,44 +477,38 @@ void ath_mci_intr(struct ath_softc *sc) * The first dword is timer. * The real data starts from 2nd dword. */ - subtype = MCI_GPM_TYPE(pgpm); opcode = MCI_GPM_OPCODE(pgpm); - if (!skip_gpm) { - - if (MCI_GPM_IS_CAL_TYPE(subtype)) - ath_mci_cal_msg(sc, subtype, - (u8 *) pgpm); - else { - switch (subtype) { - case MCI_GPM_COEX_AGENT: - ath_mci_msg(sc, opcode, - (u8 *) pgpm); - break; - default: - break; - } + if (skip_gpm) + goto recycle; + + if (MCI_GPM_IS_CAL_TYPE(subtype)) { + ath_mci_cal_msg(sc, subtype, (u8 *)pgpm); + } else { + switch (subtype) { + case MCI_GPM_COEX_AGENT: + ath_mci_msg(sc, opcode, (u8 *)pgpm); + break; + default: + break; } } + recycle: MCI_GPM_RECYCLE(pgpm); } } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_HW_MSG_MASK) { - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL) mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL; - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_INFO) { + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_INFO) mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_INFO; - ath_dbg(common, MCI, "MCI LNA_INFO\n"); - } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) { - int value_dbm = ar9003_mci_state(ah, - MCI_STATE_CONT_RSSI_POWER, NULL); + MCI_STATE_CONT_RSSI_POWER, NULL); mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_INFO; @@ -636,33 +516,25 @@ void ath_mci_intr(struct ath_softc *sc) ath_dbg(common, MCI, "MCI CONT_INFO: (tx) pri = %d, pwr = %d dBm\n", ar9003_mci_state(ah, - MCI_STATE_CONT_PRIORITY, NULL), + MCI_STATE_CONT_PRIORITY, NULL), value_dbm); else ath_dbg(common, MCI, "MCI CONT_INFO: (rx) pri = %d,pwr = %d dBm\n", ar9003_mci_state(ah, - MCI_STATE_CONT_PRIORITY, NULL), + MCI_STATE_CONT_PRIORITY, NULL), value_dbm); } - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK) { + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK) mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_NACK; - ath_dbg(common, MCI, "MCI CONT_NACK\n"); - } - if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_RST) { + if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_RST) mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_RST; - ath_dbg(common, MCI, "MCI CONT_RST\n"); - } } if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) || (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR | AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT); - - if (mci_int_rxmsg & 0xfffffffe) - ath_dbg(common, MCI, "MCI not processed mci_int_rxmsg = 0x%x\n", - mci_int_rxmsg); } diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h index 29e3e51d078f..c841444f53c2 100644 --- a/drivers/net/wireless/ath/ath9k/mci.h +++ b/drivers/net/wireless/ath/ath9k/mci.h @@ -17,6 +17,8 @@ #ifndef MCI_H #define MCI_H +#include "ar9003_mci.h" + #define ATH_MCI_SCHED_BUF_SIZE (16 * 16) /* 16 entries, 4 dword each */ #define ATH_MCI_GPM_MAX_ENTRY 16 #define ATH_MCI_GPM_BUF_SIZE (ATH_MCI_GPM_MAX_ENTRY * 16) @@ -113,7 +115,6 @@ struct ath_mci_profile { u8 num_bdr; }; - struct ath_mci_buf { void *bf_addr; /* virtual addr of desc */ dma_addr_t bf_paddr; /* physical addr of buffer */ @@ -121,10 +122,8 @@ struct ath_mci_buf { }; struct ath_mci_coex { - atomic_t mci_cal_flag; struct ath_mci_buf sched_buf; struct ath_mci_buf gpm_buf; - u32 bt_cal_start; }; void ath_mci_flush_profile(struct ath_mci_profile *mci); diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index a427a16bb739..4f848493fece 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -567,10 +567,8 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, const struct ath_rate_table *rate_table, - u8 *mcs_set, u32 capflag) + struct ath_rateset *rateset, u32 capflag) { - struct ath_rateset *rateset = (struct ath_rateset *)mcs_set; - u8 i, j, hi = 0; /* Use intersection of working rates and valid rates */ @@ -750,7 +748,8 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, * If 802.11g protection is enabled, determine whether to use RTS/CTS or * just CTS. Note that this is only done for OFDM/HT unicast frames. */ - if ((sc->sc_flags & SC_OP_PROTECT_ENABLE) && + if ((tx_info->control.vif && + tx_info->control.vif->bss_conf.use_cts_prot) && (rate_table->info[rix].phy == WLAN_RC_PHY_OFDM || WLAN_RC_PHY_HT(rate_table->info[rix].phy))) { rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT; @@ -1212,7 +1211,7 @@ static void ath_rc_init(struct ath_softc *sc, { struct ath_rateset *rateset = &ath_rc_priv->neg_rates; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; + struct ath_rateset *ht_mcs = &ath_rc_priv->neg_ht_rates; u8 i, j, k, hi = 0, hthi = 0; /* Initial rate table size. Will change depending @@ -1228,7 +1227,7 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_init_valid_rate_idx(ath_rc_priv); for (i = 0; i < WLAN_RC_PHY_MAX; i++) { - for (j = 0; j < MAX_TX_RATE_PHY; j++) + for (j = 0; j < RATE_TABLE_SIZE; j++) ath_rc_priv->valid_phy_rateidx[i][j] = 0; ath_rc_priv->valid_phy_ratecnt[i] = 0; } @@ -1300,12 +1299,13 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta, return caps; } -static bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, +static bool ath_tx_aggr_check(struct ath_softc *sc, struct ieee80211_sta *sta, u8 tidno) { + struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_atx_tid *txtid; - if (!(sc->sc_flags & SC_OP_TXAGGR)) + if (!sta->ht_cap.ht_supported) return false; txtid = ATH_AN_2_TID(an, tidno); @@ -1376,13 +1376,11 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, if (ieee80211_is_data_qos(fc) && skb_get_queue_mapping(skb) != IEEE80211_AC_VO) { u8 *qc, tid; - struct ath_node *an; qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; - an = (struct ath_node *)sta->drv_priv; - if(ath_tx_aggr_check(sc, an, tid)) + if(ath_tx_aggr_check(sc, sta, tid)) ieee80211_start_tx_ba_session(sta, tid, 0); } } diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index b7a4bcd3eec7..75f8e9b06b28 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -25,8 +25,6 @@ struct ath_softc; #define ATH_RATE_MAX 30 #define RATE_TABLE_SIZE 72 -#define MAX_TX_RATE_PHY 48 - #define RC_INVALID 0x0000 #define RC_LEGACY 0x0001 diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 7e1a91af1497..f4ae3ba994a8 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -169,22 +169,17 @@ static void ath_rx_addbuffer_edma(struct ath_softc *sc, enum ath9k_rx_qtype qtype, int size) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - u32 nbuf = 0; + struct ath_buf *bf, *tbf; if (list_empty(&sc->rx.rxbuf)) { ath_dbg(common, QUEUE, "No free rx buf available\n"); return; } - while (!list_empty(&sc->rx.rxbuf)) { - nbuf++; - + list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) if (!ath_rx_edma_buf_link(sc, qtype)) break; - if (nbuf >= size) - break; - } } static void ath_rx_remove_buffer(struct ath_softc *sc, @@ -232,7 +227,6 @@ static void ath_rx_edma_cleanup(struct ath_softc *sc) static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size) { skb_queue_head_init(&rx_edma->rx_fifo); - skb_queue_head_init(&rx_edma->rx_buffers); rx_edma->rx_fifo_hwsize = size; } @@ -658,7 +652,9 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon) } static bool ath_edma_get_buffers(struct ath_softc *sc, - enum ath9k_rx_qtype qtype) + enum ath9k_rx_qtype qtype, + struct ath_rx_status *rs, + struct ath_buf **dest) { struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype]; struct ath_hw *ah = sc->sc_ah; @@ -677,7 +673,7 @@ static bool ath_edma_get_buffers(struct ath_softc *sc, dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr, common->rx_bufsize, DMA_FROM_DEVICE); - ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data); + ret = ath9k_hw_process_rxdesc_edma(ah, rs, skb->data); if (ret == -EINPROGRESS) { /*let device gain the buffer again*/ dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, @@ -690,20 +686,21 @@ static bool ath_edma_get_buffers(struct ath_softc *sc, /* corrupt descriptor, skip this one and the following one */ list_add_tail(&bf->list, &sc->rx.rxbuf); ath_rx_edma_buf_link(sc, qtype); - skb = skb_peek(&rx_edma->rx_fifo); - if (!skb) - return true; - bf = SKB_CB_ATHBUF(skb); - BUG_ON(!bf); + skb = skb_peek(&rx_edma->rx_fifo); + if (skb) { + bf = SKB_CB_ATHBUF(skb); + BUG_ON(!bf); - __skb_unlink(skb, &rx_edma->rx_fifo); - list_add_tail(&bf->list, &sc->rx.rxbuf); - ath_rx_edma_buf_link(sc, qtype); - return true; + __skb_unlink(skb, &rx_edma->rx_fifo); + list_add_tail(&bf->list, &sc->rx.rxbuf); + ath_rx_edma_buf_link(sc, qtype); + } else { + bf = NULL; + } } - skb_queue_tail(&rx_edma->rx_buffers, skb); + *dest = bf; return true; } @@ -711,18 +708,15 @@ static struct ath_buf *ath_edma_get_next_rx_buf(struct ath_softc *sc, struct ath_rx_status *rs, enum ath9k_rx_qtype qtype) { - struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype]; - struct sk_buff *skb; - struct ath_buf *bf; + struct ath_buf *bf = NULL; - while (ath_edma_get_buffers(sc, qtype)); - skb = __skb_dequeue(&rx_edma->rx_buffers); - if (!skb) - return NULL; + while (ath_edma_get_buffers(sc, qtype, rs, &bf)) { + if (!bf) + continue; - bf = SKB_CB_ATHBUF(skb); - ath9k_hw_process_rxdesc_edma(sc->sc_ah, rs, skb->data); - return bf; + return bf; + } + return NULL; } static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, @@ -954,6 +948,7 @@ static void ath9k_process_rssi(struct ath_common *common, struct ath_softc *sc = hw->priv; struct ath_hw *ah = common->ah; int last_rssi; + int rssi = rx_stats->rs_rssi; if (!rx_stats->is_mybeacon || ((ah->opmode != NL80211_IFTYPE_STATION) && @@ -965,13 +960,12 @@ static void ath9k_process_rssi(struct ath_common *common, last_rssi = sc->last_rssi; if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) - rx_stats->rs_rssi = ATH_EP_RND(last_rssi, - ATH_RSSI_EP_MULTIPLIER); - if (rx_stats->rs_rssi < 0) - rx_stats->rs_rssi = 0; + rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); + if (rssi < 0) + rssi = 0; /* Update Beacon RSSI, this is used by ANI. */ - ah->stats.avgbrssi = rx_stats->rs_rssi; + ah->stats.avgbrssi = rssi; } /* @@ -988,8 +982,6 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, { struct ath_hw *ah = common->ah; - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - /* * everything but the rate is checked here, the rate check is done * separately to avoid doing two lookups for a rate for each frame. @@ -1011,6 +1003,8 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, rx_status->signal = ah->noise + rx_stats->rs_rssi; rx_status->antenna = rx_stats->rs_antenna; rx_status->flag |= RX_FLAG_MACTIME_MPDU; + if (rx_stats->rs_moreaggr) + rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; return 0; } @@ -1845,6 +1839,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (sc->sc_flags & SC_OP_RXFLUSH) goto requeue_drop_frag; + memset(rxs, 0, sizeof(struct ieee80211_rx_status)); + rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; if (rs.rs_tstamp > tsf_lower && unlikely(rs.rs_tstamp - tsf_lower > 0x10000000)) diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 6e2f18861f5d..458f81b4a7cb 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -797,7 +797,6 @@ #define AR_SREV_VERSION_9580 0x1C0 #define AR_SREV_REVISION_9580_10 4 /* AR9580 1.0 */ #define AR_SREV_VERSION_9462 0x280 -#define AR_SREV_REVISION_9462_10 0 #define AR_SREV_REVISION_9462_20 2 #define AR_SREV_5416(_ah) \ @@ -898,10 +897,6 @@ #define AR_SREV_9462(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462)) -#define AR_SREV_9462_10(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ - ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_10)) - #define AR_SREV_9462_20(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_20)) @@ -1156,6 +1151,7 @@ enum { #define AR_INTR_PRIO_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4094 : 0x40d4) #define AR_ENT_OTP 0x40d8 #define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 +#define AR_ENT_OTP_49GHZ_DISABLE 0x00100000 #define AR_ENT_OTP_MIN_PKT_SIZE_DISABLE 0x00800000 #define AR_CH0_BB_DPLL1 0x16180 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3182408ffe35..834e6bc45e8b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -647,9 +647,8 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; - struct ath_mci_profile *mci = &sc->btcoex.mci; u32 max_4ms_framelen, frmlen; - u16 aggr_limit, legacy = 0; + u16 aggr_limit, bt_aggr_limit, legacy = 0; int i; skb = bf->bf_mpdu; @@ -694,14 +693,14 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy) return 0; - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit) - aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4; - else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED) - aggr_limit = min((max_4ms_framelen * 3) / 8, - (u32)ATH_AMPDU_LIMIT_MAX); - else - aggr_limit = min(max_4ms_framelen, - (u32)ATH_AMPDU_LIMIT_MAX); + aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX); + + /* + * Override the default aggregation limit for BTCOEX. + */ + bt_aggr_limit = ath9k_btcoex_aggr_limit(sc, max_4ms_framelen); + if (bt_aggr_limit) + aggr_limit = bt_aggr_limit; /* * h/w can accept aggregates up to 16 bit lengths (65535). @@ -956,7 +955,9 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, */ rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info); info->rtscts_rate = rate->hw_value; - if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) + + if (tx_info->control.vif && + tx_info->control.vif->bss_conf.use_short_preamble) info->rtscts_rate |= rate->hw_value_short; for (i = 0; i < 4; i++) { @@ -1291,14 +1292,11 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid an = (struct ath_node *)sta->drv_priv; - if (sc->sc_flags & SC_OP_TXAGGR) { - txtid = ATH_AN_2_TID(an, tid); - txtid->baw_size = - IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; - txtid->state |= AGGR_ADDBA_COMPLETE; - txtid->state &= ~AGGR_ADDBA_PROGRESS; - ath_tx_resume_tid(sc, txtid); - } + txtid = ATH_AN_2_TID(an, tid); + txtid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; + txtid->state |= AGGR_ADDBA_COMPLETE; + txtid->state &= ~AGGR_ADDBA_PROGRESS; + ath_tx_resume_tid(sc, txtid); } /********************/ @@ -1357,8 +1355,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) * based intr on the EOSP frames. */ if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { - qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE | - TXQ_FLAG_TXERRINT_ENABLE; + qi.tqi_qflags = TXQ_FLAG_TXINT_ENABLE; } else { if (qtype == ATH9K_TX_QUEUE_UAPSD) qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE; @@ -1524,7 +1521,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx); /* flush any pending frames if aggregation is enabled */ - if ((sc->sc_flags & SC_OP_TXAGGR) && !retry_tx) + if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !retry_tx) ath_txq_drain_pending_buffers(sc, txq); ath_txq_unlock_complete(sc, txq); @@ -1872,7 +1869,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, struct ath_buf *bf; u8 tidno; - if ((sc->sc_flags & SC_OP_TXAGGR) && txctl->an && + if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && txctl->an && ieee80211_is_data_qos(hdr->frame_control)) { tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; @@ -2142,7 +2139,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, } else ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true); - if (sc->sc_flags & SC_OP_TXAGGR) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) ath_txq_schedule(sc, txq); } @@ -2167,7 +2164,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (list_empty(&txq->axq_q)) { txq->axq_link = NULL; - if (sc->sc_flags & SC_OP_TXAGGR) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) ath_txq_schedule(sc, txq); break; } @@ -2264,10 +2261,9 @@ static void ath_tx_complete_poll_work(struct work_struct *work) void ath_tx_tasklet(struct ath_softc *sc) { + struct ath_hw *ah = sc->sc_ah; + u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1) & ah->intr_txqs; int i; - u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1); - - ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask); for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) @@ -2297,9 +2293,12 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) break; } - /* Skip beacon completions */ - if (ts.qid == sc->beacon.beaconq) + /* Process beacon completions separately */ + if (ts.qid == sc->beacon.beaconq) { + sc->beacon.tx_processed = true; + sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); continue; + } txq = &sc->tx.txq[ts.qid]; diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 6cfbb419e2f6..0cea20e3e250 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -559,6 +559,7 @@ int carl9170_set_hwretry_limit(struct ar9170 *ar, const u32 max_retry); int carl9170_upload_key(struct ar9170 *ar, const u8 id, const u8 *mac, const u8 ktype, const u8 keyidx, const u8 *keydata, const int keylen); int carl9170_disable_key(struct ar9170 *ar, const u8 id); +int carl9170_set_mac_tpc(struct ar9170 *ar, struct ieee80211_channel *channel); /* RX */ void carl9170_rx(struct ar9170 *ar, void *buf, unsigned int len); @@ -593,7 +594,6 @@ int carl9170_get_noisefloor(struct ar9170 *ar); /* FW */ int carl9170_parse_firmware(struct ar9170 *ar); -int carl9170_fw_fix_eeprom(struct ar9170 *ar); extern struct ieee80211_rate __carl9170_ratetable[]; extern int modparam_noht; diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index 3de61adacd34..cffde8d9a521 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c @@ -389,39 +389,6 @@ carl9170_find_fw_desc(struct ar9170 *ar, const __u8 *fw_data, const size_t len) return (void *)&fw_data[scan - found]; } -int carl9170_fw_fix_eeprom(struct ar9170 *ar) -{ - const struct carl9170fw_fix_desc *fix_desc = NULL; - unsigned int i, n, off; - u32 *data = (void *)&ar->eeprom; - - fix_desc = carl9170_fw_find_desc(ar, FIX_MAGIC, - sizeof(*fix_desc), CARL9170FW_FIX_DESC_CUR_VER); - - if (!fix_desc) - return 0; - - n = (le16_to_cpu(fix_desc->head.length) - sizeof(*fix_desc)) / - sizeof(struct carl9170fw_fix_entry); - - for (i = 0; i < n; i++) { - off = le32_to_cpu(fix_desc->data[i].address) - - AR9170_EEPROM_START; - - if (off >= sizeof(struct ar9170_eeprom) || (off & 3)) { - dev_err(&ar->udev->dev, "Skip invalid entry %d\n", i); - continue; - } - - data[off / sizeof(*data)] &= - le32_to_cpu(fix_desc->data[i].mask); - data[off / sizeof(*data)] |= - le32_to_cpu(fix_desc->data[i].value); - } - - return 0; -} - int carl9170_parse_firmware(struct ar9170 *ar) { const struct carl9170fw_desc_head *fw_desc = NULL; diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c index dfda91970995..53415bfd8bef 100644 --- a/drivers/net/wireless/ath/carl9170/mac.c +++ b/drivers/net/wireless/ath/carl9170/mac.c @@ -485,3 +485,38 @@ int carl9170_disable_key(struct ar9170 *ar, const u8 id) return carl9170_exec_cmd(ar, CARL9170_CMD_DKEY, sizeof(key), (u8 *)&key, 0, NULL); } + +int carl9170_set_mac_tpc(struct ar9170 *ar, struct ieee80211_channel *channel) +{ + unsigned int power, chains; + + if (ar->eeprom.tx_mask != 1) + chains = AR9170_TX_PHY_TXCHAIN_2; + else + chains = AR9170_TX_PHY_TXCHAIN_1; + + switch (channel->band) { + case IEEE80211_BAND_2GHZ: + power = ar->power_2G_ofdm[0] & 0x3f; + break; + case IEEE80211_BAND_5GHZ: + power = ar->power_5G_leg[0] & 0x3f; + break; + default: + BUG_ON(1); + } + + power = min_t(unsigned int, power, ar->hw->conf.power_level * 2); + + carl9170_regwrite_begin(ar); + carl9170_regwrite(AR9170_MAC_REG_ACK_TPC, + 0x3c1e | power << 20 | chains << 26); + carl9170_regwrite(AR9170_MAC_REG_RTS_CTS_TPC, + power << 5 | chains << 11 | + power << 21 | chains << 27); + carl9170_regwrite(AR9170_MAC_REG_CFEND_QOSNULL_TPC, + power << 5 | chains << 11 | + power << 21 | chains << 27); + carl9170_regwrite_finish(); + return carl9170_regwrite_result(); +} diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index db774212161b..8d2523b3f722 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -853,11 +853,6 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed) goto out; } - if (changed & IEEE80211_CONF_CHANGE_POWER) { - /* TODO */ - err = 0; - } - if (changed & IEEE80211_CONF_CHANGE_SMPS) { /* TODO */ err = 0; @@ -891,6 +886,12 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed) goto out; } + if (changed & IEEE80211_CONF_CHANGE_POWER) { + err = carl9170_set_mac_tpc(ar, ar->hw->conf.channel); + if (err) + goto out; + } + out: mutex_unlock(&ar->mutex); return err; @@ -1796,6 +1797,9 @@ void *carl9170_alloc(size_t priv_size) ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + + /* As IBSS Encryption is software-based, IBSS RSN is supported. */ + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; return ar; err_nomem: @@ -1931,10 +1935,6 @@ int carl9170_register(struct ar9170 *ar) if (err) return err; - err = carl9170_fw_fix_eeprom(ar); - if (err) - return err; - err = carl9170_parse_eeprom(ar); if (err) return err; diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c index 472efc7e3402..b72c09cf43a4 100644 --- a/drivers/net/wireless/ath/carl9170/phy.c +++ b/drivers/net/wireless/ath/carl9170/phy.c @@ -1426,15 +1426,15 @@ static void carl9170_calc_ctl(struct ar9170 *ar, u32 freq, enum carl9170_bw bw) #undef EDGES } -static int carl9170_set_power_cal(struct ar9170 *ar, u32 freq, - enum carl9170_bw bw) +static void carl9170_set_power_cal(struct ar9170 *ar, u32 freq, + enum carl9170_bw bw) { struct ar9170_calibration_target_power_legacy *ctpl; struct ar9170_calibration_target_power_ht *ctph; u8 *ctpres; int ntargets; int idx, i, n; - u8 ackpower, ackchains, f; + u8 f; u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS]; if (freq < 3000) @@ -1523,32 +1523,6 @@ static int carl9170_set_power_cal(struct ar9170 *ar, u32 freq, /* calc. conformance test limits and apply to ar->power*[] */ carl9170_calc_ctl(ar, freq, bw); - - /* set ACK/CTS TX power */ - carl9170_regwrite_begin(ar); - - if (ar->eeprom.tx_mask != 1) - ackchains = AR9170_TX_PHY_TXCHAIN_2; - else - ackchains = AR9170_TX_PHY_TXCHAIN_1; - - if (freq < 3000) - ackpower = ar->power_2G_ofdm[0] & 0x3f; - else - ackpower = ar->power_5G_leg[0] & 0x3f; - - carl9170_regwrite(AR9170_MAC_REG_ACK_TPC, - 0x3c1e | ackpower << 20 | ackchains << 26); - carl9170_regwrite(AR9170_MAC_REG_RTS_CTS_TPC, - ackpower << 5 | ackchains << 11 | - ackpower << 21 | ackchains << 27); - - carl9170_regwrite(AR9170_MAC_REG_CFEND_QOSNULL_TPC, - ackpower << 5 | ackchains << 11 | - ackpower << 21 | ackchains << 27); - - carl9170_regwrite_finish(); - return carl9170_regwrite_result(); } int carl9170_get_noisefloor(struct ar9170 *ar) @@ -1712,7 +1686,9 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, if (err) return err; - err = carl9170_set_power_cal(ar, channel->center_freq, bw); + carl9170_set_power_cal(ar, channel->center_freq, bw); + + err = carl9170_set_mac_tpc(ar, channel); if (err) return err; diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index bbc813dee983..aed305177af6 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -719,6 +719,8 @@ static void carl9170_tx_rate_tpc_chains(struct ar9170 *ar, else *chains = AR9170_TX_PHY_TXCHAIN_2; } + + *tpc = min_t(unsigned int, *tpc, ar->hw->conf.power_level * 2); } static __le32 carl9170_tx_physet(struct ar9170 *ar, @@ -1245,7 +1247,7 @@ static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb) tx_info = IEEE80211_SKB_CB(skb); if (unlikely(sta_info->sleeping) && - !(tx_info->flags & (IEEE80211_TX_CTL_POLL_RESPONSE | + !(tx_info->flags & (IEEE80211_TX_CTL_NO_PS_BUFFER | IEEE80211_TX_CTL_CLEAR_PS_FILT))) { rcu_read_unlock(); diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c index d9218fe02036..ea2c737138d3 100644 --- a/drivers/net/wireless/ath/main.c +++ b/drivers/net/wireless/ath/main.c @@ -57,7 +57,8 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, } EXPORT_SYMBOL(ath_rxbuf_alloc); -void ath_printk(const char *level, const char *fmt, ...) +void ath_printk(const char *level, const struct ath_common* common, + const char *fmt, ...) { struct va_format vaf; va_list args; @@ -67,7 +68,11 @@ void ath_printk(const char *level, const char *fmt, ...) vaf.fmt = fmt; vaf.va = &args; - printk("%sath: %pV", level, &vaf); + if (common && common->hw && common->hw->wiphy) + printk("%sath: %s: %pV", + level, wiphy_name(common->hw->wiphy), &vaf); + else + printk("%sath: %pV", level, &vaf); va_end(args); } |