diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-04-15 16:21:34 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-04-15 16:21:34 -0400 |
commit | 5c01d5669356e13f0fb468944c1dd4c6a7e978ad (patch) | |
tree | fa43345288d7b25fac92b3b35360a177c4947313 /drivers/net/wireless/ath | |
parent | fea069152614cdeefba4b2bf80afcddb9c217fc8 (diff) | |
parent | a5e944f1d955f3819503348426763e21e0413ba6 (diff) | |
download | blackbird-obmc-linux-5c01d5669356e13f0fb468944c1dd4c6a7e978ad.tar.gz blackbird-obmc-linux-5c01d5669356e13f0fb468944c1dd4c6a7e978ad.zip |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts:
Documentation/feature-removal-schedule.txt
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/wl12xx/wl1271_main.c
Diffstat (limited to 'drivers/net/wireless/ath')
56 files changed, 2209 insertions, 738 deletions
diff --git a/drivers/net/wireless/ath/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h index 826c45e6b274..ec8134b4b949 100644 --- a/drivers/net/wireless/ath/ar9170/cmd.h +++ b/drivers/net/wireless/ath/ar9170/cmd.h @@ -79,7 +79,7 @@ __regwrite_out : \ if (__nreg) { \ if (IS_ACCEPTING_CMD(__ar)) \ __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ - 8 * __nreg, \ + 8 * __nreg, \ (u8 *) &__ar->cmdbuf[1], \ 0, NULL); \ __nreg = 0; \ diff --git a/drivers/net/wireless/ath/ar9170/eeprom.h b/drivers/net/wireless/ath/ar9170/eeprom.h index d2c8cc83f1dd..6c4663883423 100644 --- a/drivers/net/wireless/ath/ar9170/eeprom.h +++ b/drivers/net/wireless/ath/ar9170/eeprom.h @@ -127,8 +127,8 @@ struct ar9170_eeprom { __le16 checksum; __le16 version; u8 operating_flags; -#define AR9170_OPFLAG_5GHZ 1 -#define AR9170_OPFLAG_2GHZ 2 +#define AR9170_OPFLAG_5GHZ 1 +#define AR9170_OPFLAG_2GHZ 2 u8 misc; __le16 reg_domain[2]; u8 mac_address[6]; diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h index 0a1d4c28e68a..06f1f3c951a4 100644 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -425,5 +425,6 @@ enum ar9170_txq { #define AR9170_TXQ_DEPTH 32 #define AR9170_TX_MAX_PENDING 128 +#define AR9170_RX_STREAM_MAX_SIZE 65535 #endif /* __AR9170_HW_H */ diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 7c4a7d84535c..0312cee39570 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -236,7 +236,7 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar, wiphy_name(ar->hw->wiphy), skb_queue_len(queue)); skb_queue_walk(queue, skb) { - printk(KERN_DEBUG "index:%d => \n", i++); + printk(KERN_DEBUG "index:%d =>\n", i++); ar9170_print_txheader(ar, skb); } if (i != skb_queue_len(queue)) @@ -281,7 +281,7 @@ static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar) unsigned long flags; spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags); - printk(KERN_DEBUG "%s: A-MPDU tx_status queue => \n", + printk(KERN_DEBUG "%s: A-MPDU tx_status queue =>\n", wiphy_name(ar->hw->wiphy)); __ar9170_dump_txqueue(ar, &ar->tx_status_ampdu); spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags); @@ -308,7 +308,7 @@ static void ar9170_recycle_expired(struct ar9170 *ar, if (time_is_before_jiffies(arinfo->timeout)) { #ifdef AR9170_QUEUE_DEBUG printk(KERN_DEBUG "%s: [%ld > %ld] frame expired => " - "recycle \n", wiphy_name(ar->hw->wiphy), + "recycle\n", wiphy_name(ar->hw->wiphy), jiffies, arinfo->timeout); ar9170_print_txheader(ar, skb); #endif /* AR9170_QUEUE_DEBUG */ @@ -689,7 +689,8 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) /* firmware debug */ case 0xca: - printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, (char *)buf + 4); + printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, + (char *)buf + 4); break; case 0xcb: len -= 4; @@ -1728,7 +1729,7 @@ static void ar9170_tx(struct ar9170 *ar) printk(KERN_DEBUG "%s: queue %d full\n", wiphy_name(ar->hw->wiphy), i); - printk(KERN_DEBUG "%s: stuck frames: ===> \n", + printk(KERN_DEBUG "%s: stuck frames: ===>\n", wiphy_name(ar->hw->wiphy)); ar9170_dump_txqueue(ar, &ar->tx_pending[i]); ar9170_dump_txqueue(ar, &ar->tx_status[i]); @@ -2512,7 +2513,7 @@ void *ar9170_alloc(size_t priv_size) * tends to split the streams into separate rx descriptors. */ - skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE, GFP_KERNEL); + skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL); if (!skb) goto err_nomem; diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 99a6da464bd3..c1c7c427501c 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -67,18 +67,28 @@ static struct usb_device_id ar9170_usb_ids[] = { { USB_DEVICE(0x0cf3, 0x1001) }, /* TP-Link TL-WN821N v2 */ { USB_DEVICE(0x0cf3, 0x1002) }, + /* 3Com Dual Band 802.11n USB Adapter */ + { USB_DEVICE(0x0cf3, 0x1010) }, + /* H3C Dual Band 802.11n USB Adapter */ + { USB_DEVICE(0x0cf3, 0x1011) }, /* Cace Airpcap NX */ { USB_DEVICE(0xcace, 0x0300) }, /* D-Link DWA 160 A1 */ { USB_DEVICE(0x07d1, 0x3c10) }, /* D-Link DWA 160 A2 */ { USB_DEVICE(0x07d1, 0x3a09) }, + /* Netgear WNA1000 */ + { USB_DEVICE(0x0846, 0x9040) }, /* Netgear WNDA3100 */ { USB_DEVICE(0x0846, 0x9010) }, /* Netgear WN111 v2 */ { USB_DEVICE(0x0846, 0x9001) }, /* Zydas ZD1221 */ { USB_DEVICE(0x0ace, 0x1221) }, + /* Proxim ORiNOCO 802.11n USB */ + { USB_DEVICE(0x1435, 0x0804) }, + /* WNC Generic 11n USB Dongle */ + { USB_DEVICE(0x1435, 0x0326) }, /* ZyXEL NWD271N */ { USB_DEVICE(0x0586, 0x3417) }, /* Z-Com UB81 BG */ diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 71fc960814f0..1fbf6b1f9a7e 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -48,6 +48,12 @@ enum ath_device_state { ATH_HW_INITIALIZED, }; +enum ath_bus_type { + ATH_PCI, + ATH_AHB, + ATH_USB, +}; + struct reg_dmn_pair_mapping { u16 regDmnEnum; u16 reg_5ghz_ctl; @@ -73,9 +79,10 @@ struct ath_ops { struct ath_common; struct ath_bus_ops { - void (*read_cachesize)(struct ath_common *common, int *csz); - bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); - void (*bt_coex_prep)(struct ath_common *common); + enum ath_bus_type ath_bus_type; + void (*read_cachesize)(struct ath_common *common, int *csz); + bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); + void (*bt_coex_prep)(struct ath_common *common); }; struct ath_common { diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile index 090dc6d268a3..cc09595b781a 100644 --- a/drivers/net/wireless/ath/ath5k/Makefile +++ b/drivers/net/wireless/ath/ath5k/Makefile @@ -12,5 +12,6 @@ ath5k-y += attach.o ath5k-y += base.o ath5k-y += led.o ath5k-y += rfkill.o +ath5k-y += ani.o ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c new file mode 100644 index 000000000000..584a32859bdb --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -0,0 +1,744 @@ +/* + * Copyright (C) 2010 Bruno Randolf <br1@einfach.org> + * + * 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 "ath5k.h" +#include "base.h" +#include "reg.h" +#include "debug.h" +#include "ani.h" + +/** + * DOC: Basic ANI Operation + * + * Adaptive Noise Immunity (ANI) controls five noise immunity parameters + * depending on the amount of interference in the environment, increasing + * or reducing sensitivity as necessary. + * + * The parameters are: + * - "noise immunity" + * - "spur immunity" + * - "firstep level" + * - "OFDM weak signal detection" + * - "CCK weak signal detection" + * + * Basically we look at the amount of ODFM and CCK timing errors we get and then + * raise or lower immunity accordingly by setting one or more of these + * parameters. + * Newer chipsets have PHY error counters in hardware which will generate a MIB + * interrupt when they overflow. Older hardware has too enable PHY error frames + * by setting a RX flag and then count every single PHY error. When a specified + * threshold of errors has been reached we will raise immunity. + * Also we regularly check the amount of errors and lower or raise immunity as + * necessary. + */ + + +/*** ANI parameter control ***/ + +/** + * ath5k_ani_set_noise_immunity_level() - Set noise immunity level + * + * @level: level between 0 and @ATH5K_ANI_MAX_NOISE_IMM_LVL + */ +void +ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level) +{ + /* TODO: + * ANI documents suggest the following five levels to use, but the HAL + * and ath9k use only use the last two levels, making this + * essentially an on/off option. There *may* be a reason for this (???), + * so i stick with the HAL version for now... + */ +#if 0 + const s8 hi[] = { -18, -18, -16, -14, -12 }; + const s8 lo[] = { -52, -56, -60, -64, -70 }; + const s8 sz[] = { -34, -41, -48, -55, -62 }; + const s8 fr[] = { -70, -72, -75, -78, -80 }; +#else + const s8 sz[] = { -55, -62 }; + const s8 lo[] = { -64, -70 }; + const s8 hi[] = { -14, -12 }; + const s8 fr[] = { -78, -80 }; +#endif + if (level < 0 || level > ARRAY_SIZE(sz)) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "level out of range %d", level); + return; + } + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE, + AR5K_PHY_DESIRED_SIZE_TOT, sz[level]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE, + AR5K_PHY_AGCCOARSE_LO, lo[level]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE, + AR5K_PHY_AGCCOARSE_HI, hi[level]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SIG, + AR5K_PHY_SIG_FIRPWR, fr[level]); + + ah->ah_sc->ani_state.noise_imm_level = level; + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level); +} + + +/** + * ath5k_ani_set_spur_immunity_level() - Set spur immunity level + * + * @level: level between 0 and @max_spur_level (the maximum level is dependent + * on the chip revision). + */ +void +ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level) +{ + const int val[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; + + if (level < 0 || level > ARRAY_SIZE(val) || + level > ah->ah_sc->ani_state.max_spur_level) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "level out of range %d", level); + return; + } + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR, + AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1, val[level]); + + ah->ah_sc->ani_state.spur_level = level; + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level); +} + + +/** + * ath5k_ani_set_firstep_level() - Set "firstep" level + * + * @level: level between 0 and @ATH5K_ANI_MAX_FIRSTEP_LVL + */ +void +ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level) +{ + const int val[] = { 0, 4, 8 }; + + if (level < 0 || level > ARRAY_SIZE(val)) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "level out of range %d", level); + return; + } + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SIG, + AR5K_PHY_SIG_FIRSTEP, val[level]); + + ah->ah_sc->ani_state.firstep_level = level; + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level); +} + + +/** + * ath5k_ani_set_ofdm_weak_signal_detection() - Control OFDM weak signal + * detection + * + * @on: turn on or off + */ +void +ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on) +{ + const int m1l[] = { 127, 50 }; + const int m2l[] = { 127, 40 }; + const int m1[] = { 127, 0x4d }; + const int m2[] = { 127, 0x40 }; + const int m2cnt[] = { 31, 16 }; + const int m2lcnt[] = { 63, 48 }; + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, + AR5K_PHY_WEAK_OFDM_LOW_THR_M1, m1l[on]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, + AR5K_PHY_WEAK_OFDM_LOW_THR_M2, m2l[on]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR, + AR5K_PHY_WEAK_OFDM_HIGH_THR_M1, m1[on]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR, + AR5K_PHY_WEAK_OFDM_HIGH_THR_M2, m2[on]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR, + AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT, m2cnt[on]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, + AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT, m2lcnt[on]); + + if (on) + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, + AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, + AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN); + + ah->ah_sc->ani_state.ofdm_weak_sig = on; + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "turned %s", + on ? "on" : "off"); +} + + +/** + * ath5k_ani_set_cck_weak_signal_detection() - control CCK weak signal detection + * + * @on: turn on or off + */ +void +ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on) +{ + const int val[] = { 8, 6 }; + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_CCK_CROSSCORR, + AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR, val[on]); + ah->ah_sc->ani_state.cck_weak_sig = on; + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "turned %s", + on ? "on" : "off"); +} + + +/*** ANI algorithm ***/ + +/** + * ath5k_ani_raise_immunity() - Increase noise immunity + * + * @ofdm_trigger: If this is true we are called because of too many OFDM errors, + * the algorithm will tune more parameters then. + * + * Try to raise noise immunity (=decrease sensitivity) in several steps + * depending on the average RSSI of the beacons we received. + */ +static void +ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, + bool ofdm_trigger) +{ + int rssi = ah->ah_beacon_rssi_avg.avg; + + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "raise immunity (%s)", + ofdm_trigger ? "ODFM" : "CCK"); + + /* first: raise noise immunity */ + if (as->noise_imm_level < ATH5K_ANI_MAX_NOISE_IMM_LVL) { + ath5k_ani_set_noise_immunity_level(ah, as->noise_imm_level + 1); + return; + } + + /* only OFDM: raise spur immunity level */ + if (ofdm_trigger && + as->spur_level < ah->ah_sc->ani_state.max_spur_level) { + ath5k_ani_set_spur_immunity_level(ah, as->spur_level + 1); + return; + } + + /* AP mode */ + if (ah->ah_sc->opmode == NL80211_IFTYPE_AP) { + if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL) + ath5k_ani_set_firstep_level(ah, as->firstep_level + 1); + return; + } + + /* STA and IBSS mode */ + + /* TODO: for IBSS mode it would be better to keep a beacon RSSI average + * per each neighbour node and use the minimum of these, to make sure we + * don't shut out a remote node by raising immunity too high. */ + + if (rssi > ATH5K_ANI_RSSI_THR_HIGH) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "beacon RSSI high"); + /* only OFDM: beacon RSSI is high, we can disable ODFM weak + * signal detection */ + if (ofdm_trigger && as->ofdm_weak_sig == true) { + ath5k_ani_set_ofdm_weak_signal_detection(ah, false); + ath5k_ani_set_spur_immunity_level(ah, 0); + return; + } + /* as a last resort or CCK: raise firstep level */ + if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL) { + ath5k_ani_set_firstep_level(ah, as->firstep_level + 1); + return; + } + } else if (rssi > ATH5K_ANI_RSSI_THR_LOW) { + /* beacon RSSI in mid range, we need OFDM weak signal detect, + * but can raise firstep level */ + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "beacon RSSI mid"); + if (ofdm_trigger && as->ofdm_weak_sig == false) + 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); + return; + } else if (ah->ah_current_channel->band == IEEE80211_BAND_2GHZ) { + /* beacon RSSI is low. in B/G mode turn of OFDM weak signal + * detect and zero firstep level to maximize CCK sensitivity */ + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "beacon RSSI low, 2GHz"); + if (ofdm_trigger && as->ofdm_weak_sig == true) + ath5k_ani_set_ofdm_weak_signal_detection(ah, false); + if (as->firstep_level > 0) + ath5k_ani_set_firstep_level(ah, 0); + return; + } + + /* TODO: why not?: + if (as->cck_weak_sig == true) { + ath5k_ani_set_cck_weak_signal_detection(ah, false); + } + */ +} + + +/** + * ath5k_ani_lower_immunity() - Decrease noise immunity + * + * Try to lower noise immunity (=increase sensitivity) in several steps + * depending on the average RSSI of the beacons we received. + */ +static void +ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) +{ + int rssi = ah->ah_beacon_rssi_avg.avg; + + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "lower immunity"); + + if (ah->ah_sc->opmode == NL80211_IFTYPE_AP) { + /* AP mode */ + if (as->firstep_level > 0) { + ath5k_ani_set_firstep_level(ah, as->firstep_level - 1); + return; + } + } else { + /* STA and IBSS mode (see TODO above) */ + if (rssi > ATH5K_ANI_RSSI_THR_HIGH) { + /* beacon signal is high, leave OFDM weak signal + * detection off or it may oscillate + * TODO: who said it's off??? */ + } 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) { + ath5k_ani_set_ofdm_weak_signal_detection(ah, + true); + return; + } + if (as->firstep_level > 0) { + ath5k_ani_set_firstep_level(ah, + as->firstep_level - 1); + return; + } + } else { + /* beacon signal is low: only reduce firstep level */ + if (as->firstep_level > 0) { + ath5k_ani_set_firstep_level(ah, + as->firstep_level - 1); + return; + } + } + } + + /* all modes */ + if (as->spur_level > 0) { + ath5k_ani_set_spur_immunity_level(ah, as->spur_level - 1); + return; + } + + /* finally, reduce noise immunity */ + if (as->noise_imm_level > 0) { + ath5k_ani_set_noise_immunity_level(ah, as->noise_imm_level - 1); + return; + } +} + + +/** + * ath5k_hw_ani_get_listen_time() - Calculate time spent listening + * + * Return an approximation of the time spent "listening" in milliseconds (ms) + * since the last call of this function by deducting the cycles spent + * transmitting and receiving from the total cycle count. + * Save profile count values for debugging/statistics and because we might want + * to use them later. + * + * We assume no one else clears these registers! + */ +static int +ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as) +{ + int listen; + + /* freeze */ + ath5k_hw_reg_write(ah, AR5K_MIBC_FMC, AR5K_MIBC); + /* read */ + as->pfc_cycles = ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE); + as->pfc_busy = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR); + as->pfc_tx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX); + as->pfc_rx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX); + /* clear */ + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); + /* un-freeze */ + ath5k_hw_reg_write(ah, 0, AR5K_MIBC); + + /* TODO: where does 44000 come from? (11g clock rate?) */ + listen = (as->pfc_cycles - as->pfc_rx - as->pfc_tx) / 44000; + + if (as->pfc_cycles == 0 || listen < 0) + return 0; + return listen; +} + + +/** + * ath5k_ani_save_and_clear_phy_errors() - Clear and save PHY error counters + * + * Clear the PHY error counters as soon as possible, since this might be called + * from a MIB interrupt and we want to make sure we don't get interrupted again. + * Add the count of CCK and OFDM errors to our internal state, so it can be used + * by the algorithm later. + * + * Will be called from interrupt and tasklet context. + * Returns 0 if both counters are zero. + */ +static int +ath5k_ani_save_and_clear_phy_errors(struct ath5k_hw *ah, + struct ath5k_ani_state *as) +{ + unsigned int ofdm_err, cck_err; + + if (!ah->ah_capabilities.cap_has_phyerr_counters) + return 0; + + ofdm_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1); + cck_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2); + + /* reset counters first, we might be in a hurry (interrupt) */ + ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_OFDM_TRIG_HIGH, + AR5K_PHYERR_CNT1); + ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_CCK_TRIG_HIGH, + AR5K_PHYERR_CNT2); + + ofdm_err = ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - ofdm_err); + cck_err = ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - cck_err); + + /* sometimes both can be zero, especially when there is a superfluous + * second interrupt. detect that here and return an error. */ + if (ofdm_err <= 0 && cck_err <= 0) + return 0; + + /* avoid negative values should one of the registers overflow */ + if (ofdm_err > 0) { + as->ofdm_errors += ofdm_err; + as->sum_ofdm_errors += ofdm_err; + } + if (cck_err > 0) { + as->cck_errors += cck_err; + as->sum_cck_errors += cck_err; + } + return 1; +} + + +/** + * ath5k_ani_period_restart() - Restart ANI period + * + * Just reset counters, so they are clear for the next "ani period". + */ +static void +ath5k_ani_period_restart(struct ath5k_hw *ah, struct ath5k_ani_state *as) +{ + /* keep last values for debugging */ + as->last_ofdm_errors = as->ofdm_errors; + as->last_cck_errors = as->cck_errors; + as->last_listen = as->listen_time; + + as->ofdm_errors = 0; + as->cck_errors = 0; + as->listen_time = 0; +} + + +/** + * ath5k_ani_calibration() - The main ANI calibration function + * + * We count OFDM and CCK errors relative to the time where we did not send or + * receive ("listen" time) and raise or lower immunity accordingly. + * This is called regularly (every second) from the calibration timer, but also + * when an error threshold has been reached. + * + * In order to synchronize access from different contexts, this should be + * called only indirectly by scheduling the ANI tasklet! + */ +void +ath5k_ani_calibration(struct ath5k_hw *ah) +{ + struct ath5k_ani_state *as = &ah->ah_sc->ani_state; + int listen, ofdm_high, ofdm_low, cck_high, cck_low; + + if (as->ani_mode != ATH5K_ANI_MODE_AUTO) + return; + + /* get listen time since last call and add it to the counter because we + * might not have restarted the "ani period" last time */ + listen = ath5k_hw_ani_get_listen_time(ah, as); + as->listen_time += listen; + + ath5k_ani_save_and_clear_phy_errors(ah, as); + + ofdm_high = as->listen_time * ATH5K_ANI_OFDM_TRIG_HIGH / 1000; + cck_high = as->listen_time * ATH5K_ANI_CCK_TRIG_HIGH / 1000; + ofdm_low = as->listen_time * ATH5K_ANI_OFDM_TRIG_LOW / 1000; + cck_low = as->listen_time * ATH5K_ANI_CCK_TRIG_LOW / 1000; + + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "listen %d (now %d)", as->listen_time, listen); + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "check high ofdm %d/%d cck %d/%d", + as->ofdm_errors, ofdm_high, as->cck_errors, cck_high); + + if (as->ofdm_errors > ofdm_high || as->cck_errors > cck_high) { + /* too many PHY errors - we have to raise immunity */ + bool ofdm_flag = as->ofdm_errors > ofdm_high ? true : false; + ath5k_ani_raise_immunity(ah, as, ofdm_flag); + ath5k_ani_period_restart(ah, as); + + } else if (as->listen_time > 5 * ATH5K_ANI_LISTEN_PERIOD) { + /* If more than 5 (TODO: why 5?) periods have passed and we got + * relatively little errors we can try to lower immunity */ + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "check low ofdm %d/%d cck %d/%d", + as->ofdm_errors, ofdm_low, as->cck_errors, cck_low); + + if (as->ofdm_errors <= ofdm_low && as->cck_errors <= cck_low) + ath5k_ani_lower_immunity(ah, as); + + ath5k_ani_period_restart(ah, as); + } +} + + +/*** INTERRUPT HANDLER ***/ + +/** + * ath5k_ani_mib_intr() - Interrupt handler for ANI MIB counters + * + * Just read & reset the registers quickly, so they don't generate more + * interrupts, save the counters and schedule the tasklet to decide whether + * to raise immunity or not. + * + * We just need to handle PHY error counters, ath5k_hw_update_mib_counters() + * should take care of all "normal" MIB interrupts. + */ +void +ath5k_ani_mib_intr(struct ath5k_hw *ah) +{ + struct ath5k_ani_state *as = &ah->ah_sc->ani_state; + + /* nothing to do here if HW does not have PHY error counters - they + * can't be the reason for the MIB interrupt then */ + if (!ah->ah_capabilities.cap_has_phyerr_counters) + return; + + /* not in use but clear anyways */ + ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT); + ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); + + if (ah->ah_sc->ani_state.ani_mode != ATH5K_ANI_MODE_AUTO) + return; + + /* if one of the errors triggered, we can get a superfluous second + * interrupt, even though we have already reset the register. the + * function detects that so we can return early */ + if (ath5k_ani_save_and_clear_phy_errors(ah, as) == 0) + return; + + if (as->ofdm_errors > ATH5K_ANI_OFDM_TRIG_HIGH || + as->cck_errors > ATH5K_ANI_CCK_TRIG_HIGH) + tasklet_schedule(&ah->ah_sc->ani_tasklet); +} + + +/** + * ath5k_ani_phy_error_report() - Used by older HW to report PHY errors + * + * This is used by hardware without PHY error counters to report PHY errors + * on a frame-by-frame basis, instead of the interrupt. + */ +void +ath5k_ani_phy_error_report(struct ath5k_hw *ah, + enum ath5k_phy_error_code phyerr) +{ + struct ath5k_ani_state *as = &ah->ah_sc->ani_state; + + if (phyerr == AR5K_RX_PHY_ERROR_OFDM_TIMING) { + as->ofdm_errors++; + if (as->ofdm_errors > ATH5K_ANI_OFDM_TRIG_HIGH) + tasklet_schedule(&ah->ah_sc->ani_tasklet); + } else if (phyerr == AR5K_RX_PHY_ERROR_CCK_TIMING) { + as->cck_errors++; + if (as->cck_errors > ATH5K_ANI_CCK_TRIG_HIGH) + tasklet_schedule(&ah->ah_sc->ani_tasklet); + } +} + + +/*** INIT ***/ + +/** + * ath5k_enable_phy_err_counters() - Enable PHY error counters + * + * Enable PHY error counters for OFDM and CCK timing errors. + */ +static void +ath5k_enable_phy_err_counters(struct ath5k_hw *ah) +{ + ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_OFDM_TRIG_HIGH, + AR5K_PHYERR_CNT1); + ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_CCK_TRIG_HIGH, + AR5K_PHYERR_CNT2); + ath5k_hw_reg_write(ah, AR5K_PHY_ERR_FIL_OFDM, AR5K_PHYERR_CNT1_MASK); + ath5k_hw_reg_write(ah, AR5K_PHY_ERR_FIL_CCK, AR5K_PHYERR_CNT2_MASK); + + /* not in use */ + ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT); + ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); +} + + +/** + * ath5k_disable_phy_err_counters() - Disable PHY error counters + * + * Disable PHY error counters for OFDM and CCK timing errors. + */ +static void +ath5k_disable_phy_err_counters(struct ath5k_hw *ah) +{ + ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT1); + ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT2); + ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT1_MASK); + ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT2_MASK); + + /* not in use */ + ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT); + ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); +} + + +/** + * ath5k_ani_init() - Initialize ANI + * @mode: Which mode to use (auto, manual high, manual low, off) + * + * Initialize ANI according to mode. + */ +void +ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode) +{ + /* ANI is only possible on 5212 and newer */ + if (ah->ah_version < AR5K_AR5212) + return; + + /* clear old state information */ + memset(&ah->ah_sc->ani_state, 0, sizeof(ah->ah_sc->ani_state)); + + /* older hardware has more spur levels than newer */ + if (ah->ah_mac_srev < AR5K_SREV_AR2414) + ah->ah_sc->ani_state.max_spur_level = 7; + else + ah->ah_sc->ani_state.max_spur_level = 2; + + /* initial values for our ani parameters */ + if (mode == ATH5K_ANI_MODE_OFF) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "ANI off\n"); + } else if (mode == ATH5K_ANI_MODE_MANUAL_LOW) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "ANI manual low -> high sensitivity\n"); + ath5k_ani_set_noise_immunity_level(ah, 0); + ath5k_ani_set_spur_immunity_level(ah, 0); + ath5k_ani_set_firstep_level(ah, 0); + ath5k_ani_set_ofdm_weak_signal_detection(ah, true); + ath5k_ani_set_cck_weak_signal_detection(ah, true); + } else if (mode == ATH5K_ANI_MODE_MANUAL_HIGH) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "ANI manual high -> low sensitivity\n"); + ath5k_ani_set_noise_immunity_level(ah, + ATH5K_ANI_MAX_NOISE_IMM_LVL); + ath5k_ani_set_spur_immunity_level(ah, + ah->ah_sc->ani_state.max_spur_level); + ath5k_ani_set_firstep_level(ah, ATH5K_ANI_MAX_FIRSTEP_LVL); + ath5k_ani_set_ofdm_weak_signal_detection(ah, false); + ath5k_ani_set_cck_weak_signal_detection(ah, false); + } else if (mode == ATH5K_ANI_MODE_AUTO) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "ANI auto\n"); + ath5k_ani_set_noise_immunity_level(ah, 0); + ath5k_ani_set_spur_immunity_level(ah, 0); + ath5k_ani_set_firstep_level(ah, 0); + ath5k_ani_set_ofdm_weak_signal_detection(ah, true); + ath5k_ani_set_cck_weak_signal_detection(ah, false); + } + + /* newer hardware has PHY error counter registers which we can use to + * get OFDM and CCK error counts. older hardware has to set rxfilter and + * report every single PHY error by calling ath5k_ani_phy_error_report() + */ + if (mode == ATH5K_ANI_MODE_AUTO) { + if (ah->ah_capabilities.cap_has_phyerr_counters) + ath5k_enable_phy_err_counters(ah); + else + ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) | + AR5K_RX_FILTER_PHYERR); + } else { + if (ah->ah_capabilities.cap_has_phyerr_counters) + ath5k_disable_phy_err_counters(ah); + else + ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) & + ~AR5K_RX_FILTER_PHYERR); + } + + ah->ah_sc->ani_state.ani_mode = mode; +} + + +/*** DEBUG ***/ + +#ifdef CONFIG_ATH5K_DEBUG + +void +ath5k_ani_print_counters(struct ath5k_hw *ah) +{ + /* clears too */ + printk(KERN_NOTICE "ACK fail\t%d\n", + ath5k_hw_reg_read(ah, AR5K_ACK_FAIL)); + printk(KERN_NOTICE "RTS fail\t%d\n", + ath5k_hw_reg_read(ah, AR5K_RTS_FAIL)); + printk(KERN_NOTICE "RTS success\t%d\n", + ath5k_hw_reg_read(ah, AR5K_RTS_OK)); + printk(KERN_NOTICE "FCS error\t%d\n", + ath5k_hw_reg_read(ah, AR5K_FCS_FAIL)); + + /* no clear */ + printk(KERN_NOTICE "tx\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX)); + printk(KERN_NOTICE "rx\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX)); + printk(KERN_NOTICE "busy\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR)); + printk(KERN_NOTICE "cycles\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE)); + + printk(KERN_NOTICE "AR5K_PHYERR_CNT1\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1)); + printk(KERN_NOTICE "AR5K_PHYERR_CNT2\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2)); + printk(KERN_NOTICE "AR5K_OFDM_FIL_CNT\t%d\n", + ath5k_hw_reg_read(ah, AR5K_OFDM_FIL_CNT)); + printk(KERN_NOTICE "AR5K_CCK_FIL_CNT\t%d\n", + ath5k_hw_reg_read(ah, AR5K_CCK_FIL_CNT)); +} + +#endif diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h new file mode 100644 index 000000000000..55cf26d8522c --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/ani.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2010 Bruno Randolf <br1@einfach.org> + * + * 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 ANI_H +#define ANI_H + +/* these thresholds are relative to the ATH5K_ANI_LISTEN_PERIOD */ +#define ATH5K_ANI_LISTEN_PERIOD 100 +#define ATH5K_ANI_OFDM_TRIG_HIGH 500 +#define ATH5K_ANI_OFDM_TRIG_LOW 200 +#define ATH5K_ANI_CCK_TRIG_HIGH 200 +#define ATH5K_ANI_CCK_TRIG_LOW 100 + +/* average beacon RSSI thresholds */ +#define ATH5K_ANI_RSSI_THR_HIGH 40 +#define ATH5K_ANI_RSSI_THR_LOW 7 + +/* maximum availabe levels */ +#define ATH5K_ANI_MAX_FIRSTEP_LVL 2 +#define ATH5K_ANI_MAX_NOISE_IMM_LVL 1 + + +/** + * enum ath5k_ani_mode - mode for ANI / noise sensitivity + * + * @ATH5K_ANI_MODE_OFF: Turn ANI off. This can be useful to just stop the ANI + * algorithm after it has been on auto mode. + * ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low, + * maximizing sensitivity. ANI will not run. + * ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high, + * minimizing sensitivity. ANI will not run. + * ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the + * amount of OFDM and CCK frame errors (default). + */ +enum ath5k_ani_mode { + ATH5K_ANI_MODE_OFF = 0, + ATH5K_ANI_MODE_MANUAL_LOW = 1, + ATH5K_ANI_MODE_MANUAL_HIGH = 2, + ATH5K_ANI_MODE_AUTO = 3 +}; + + +/** + * struct ath5k_ani_state - ANI state and associated counters + * + * @max_spur_level: the maximum spur level is chip dependent + */ +struct ath5k_ani_state { + enum ath5k_ani_mode ani_mode; + + /* state */ + int noise_imm_level; + int spur_level; + int firstep_level; + bool ofdm_weak_sig; + bool cck_weak_sig; + + int max_spur_level; + + /* used by the algorithm */ + unsigned int listen_time; + unsigned int ofdm_errors; + unsigned int cck_errors; + + /* debug/statistics only: numbers from last ANI calibration */ + unsigned int pfc_tx; + unsigned int pfc_rx; + unsigned int pfc_busy; + unsigned int pfc_cycles; + unsigned int last_listen; + unsigned int last_ofdm_errors; + unsigned int last_cck_errors; + unsigned int sum_ofdm_errors; + unsigned int sum_cck_errors; +}; + +void ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode); +void ath5k_ani_mib_intr(struct ath5k_hw *ah); +void ath5k_ani_calibration(struct ath5k_hw *ah); +void ath5k_ani_phy_error_report(struct ath5k_hw *ah, + enum ath5k_phy_error_code phyerr); + +/* for manual control */ +void ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level); +void ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level); +void ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level); +void ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on); +void ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on); + +void ath5k_ani_print_counters(struct ath5k_hw *ah); + +#endif /* ANI_H */ diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 1d7491c85460..2785946f659a 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -202,6 +202,8 @@ #define AR5K_TUNE_MAX_TXPOWER 63 #define AR5K_TUNE_DEFAULT_TXPOWER 25 #define AR5K_TUNE_TPC_TXPOWER false +#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL 10000 /* 10 sec */ +#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000 /* 1 sec */ #define AR5K_INIT_CARR_SENSE_EN 1 @@ -799,9 +801,9 @@ struct ath5k_athchan_2ghz { * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold * We currently do increments on interrupt by * (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2 - * @AR5K_INT_MIB: Indicates the Management Information Base counters should be - * checked. We should do this with ath5k_hw_update_mib_counters() but - * it seems we should also then do some noise immunity work. + * @AR5K_INT_MIB: Indicates the either Management Information Base counters or + * one of the PHY error counters reached the maximum value and should be + * read and cleared. * @AR5K_INT_RXPHY: RX PHY Error * @AR5K_INT_RXKCM: RX Key cache miss * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a @@ -889,10 +891,11 @@ enum ath5k_int { AR5K_INT_NOCARD = 0xffffffff }; -/* Software interrupts used for calibration */ -enum ath5k_software_interrupt { - AR5K_SWI_FULL_CALIBRATION = 0x01, - AR5K_SWI_SHORT_CALIBRATION = 0x02, +/* mask which calibration is active at the moment */ +enum ath5k_calibration_mask { + AR5K_CALIBRATION_FULL = 0x01, + AR5K_CALIBRATION_SHORT = 0x02, + AR5K_CALIBRATION_ANI = 0x04, }; /* @@ -981,6 +984,8 @@ struct ath5k_capabilities { struct { u8 q_tx_num; } cap_queues; + + bool cap_has_phyerr_counters; }; /* size of noise floor history (keep it a power of two) */ @@ -991,6 +996,15 @@ struct ath5k_nfcal_hist s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */ }; +/** + * struct avg_val - Helper structure for average calculation + * @avg: contains the actual average value + * @avg_weight: is used internally during calculation to prevent rounding errors + */ +struct ath5k_avg_val { + int avg; + int avg_weight; +}; /***************************************\ HARDWARE ABSTRACTION LAYER STRUCTURE @@ -1095,17 +1109,18 @@ struct ath5k_hw { struct ath5k_nfcal_hist ah_nfcal_hist; + /* average beacon RSSI in our BSS (used by ANI) */ + struct ath5k_avg_val ah_beacon_rssi_avg; + /* noise floor from last periodic calibration */ s32 ah_noise_floor; /* Calibration timestamp */ - unsigned long ah_cal_tstamp; - - /* Calibration interval (secs) */ - u8 ah_cal_intval; + unsigned long ah_cal_next_full; + unsigned long ah_cal_next_ani; - /* Software interrupt mask */ - u8 ah_swi_mask; + /* Calibration mask */ + u8 ah_cal_mask; /* * Function pointers @@ -1163,8 +1178,7 @@ int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase); bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah); int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask); enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask); -void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, - struct ieee80211_low_level_stats *stats); +void ath5k_hw_update_mib_counters(struct ath5k_hw *ah); /* EEPROM access functions */ int ath5k_eeprom_init(struct ath5k_hw *ah); @@ -1256,7 +1270,6 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah); int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); -void ath5k_hw_calibration_poll(struct ath5k_hw *ah); /* Spur mitigation */ bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, struct ieee80211_channel *channel); @@ -1308,4 +1321,27 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) return retval; } +#define AVG_SAMPLES 8 +#define AVG_FACTOR 1000 + +/** + * ath5k_moving_average - Exponentially weighted moving average + * @avg: average structure + * @val: current value + * + * This implementation make use of a struct ath5k_avg_val to prevent rounding + * errors. + */ +static inline struct ath5k_avg_val +ath5k_moving_average(const struct ath5k_avg_val avg, const int val) +{ + struct ath5k_avg_val new; + new.avg_weight = avg.avg_weight ? + (((avg.avg_weight * ((AVG_SAMPLES) - 1)) + + (val * (AVG_FACTOR))) / (AVG_SAMPLES)) : + (val * (AVG_FACTOR)); + new.avg = new.avg_weight / (AVG_FACTOR); + return new; +} + #endif diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index f571ad1a225e..e0c244b02f05 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -124,6 +124,8 @@ int ath5k_hw_attach(struct ath5k_softc *sc) ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; ah->ah_software_retry = false; ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT; + ah->ah_noise_floor = -95; /* until first NF calibration is run */ + sc->ani_state.ani_mode = ATH5K_ANI_MODE_AUTO; /* * Find the mac version diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 7ac3a720e52c..93005f1d326d 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -59,8 +59,8 @@ #include "base.h" #include "reg.h" #include "debug.h" +#include "ani.h" -static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); @@ -365,6 +365,7 @@ static void ath5k_beacon_send(struct ath5k_softc *sc); static void ath5k_beacon_config(struct ath5k_softc *sc); static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); static void ath5k_tasklet_beacon(unsigned long data); +static void ath5k_tasklet_ani(unsigned long data); static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) { @@ -830,6 +831,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc); tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); + tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc); ret = ath5k_eeprom_read_mac(ah, mac); if (ret) { @@ -1635,7 +1637,6 @@ ath5k_txq_cleanup(struct ath5k_softc *sc) sc->txqs[i].link); } } - ieee80211_wake_queues(sc->hw); /* XXX move to callers */ for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) if (sc->txqs[i].setup) @@ -1805,6 +1806,25 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, } } +static void +ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + struct ath5k_hw *ah = sc->ah; + struct ath_common *common = ath5k_hw_common(ah); + + /* only beacons from our BSSID */ + if (!ieee80211_is_beacon(mgmt->frame_control) || + memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0) + return; + + ah->ah_beacon_rssi_avg = ath5k_moving_average(ah->ah_beacon_rssi_avg, + rssi); + + /* in IBSS mode we should keep RSSI statistics per neighbour */ + /* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */ +} + /* * Compute padding position. skb must contains an IEEE 802.11 frame */ @@ -1923,6 +1943,8 @@ ath5k_tasklet_rx(unsigned long data) sc->stats.rxerr_fifo++; if (rs.rs_status & AR5K_RXERR_PHY) { sc->stats.rxerr_phy++; + if (rs.rs_phyerr > 0 && rs.rs_phyerr < 32) + sc->stats.rxerr_phy_code[rs.rs_phyerr]++; goto next; } if (rs.rs_status & AR5K_RXERR_DECRYPT) { @@ -2024,6 +2046,8 @@ accept: ath5k_debug_dump_skb(sc, skb, "RX ", 0); + ath5k_update_beacon_rssi(sc, skb, rs.rs_rssi); + /* check beacons in IBSS mode */ if (sc->opmode == NL80211_IFTYPE_ADHOC) ath5k_check_ibss_tsf(sc, skb, rxs); @@ -2060,6 +2084,17 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) list_for_each_entry_safe(bf, bf0, &txq->q, list) { ds = bf->desc; + /* + * It's possible that the hardware can say the buffer is + * completed when it hasn't yet loaded the ds_link from + * host memory and moved on. If there are more TX + * descriptors in the queue, wait for TXDP to change + * before processing this one. + */ + if (ath5k_hw_get_txdp(sc->ah, txq->qnum) == bf->daddr && + !list_is_last(&bf->list, &txq->q)) + break; + ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); if (unlikely(ret == -EINPROGRESS)) break; @@ -2095,7 +2130,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) info->status.rates[ts.ts_final_idx].count++; if (unlikely(ts.ts_status)) { - sc->ll_stats.dot11ACKFailureCount++; + sc->stats.ack_fail++; if (ts.ts_status & AR5K_TXERR_FILT) { info->flags |= IEEE80211_TX_STAT_TX_FILTERED; sc->stats.txerr_filt++; @@ -2498,9 +2533,6 @@ ath5k_init(struct ath5k_softc *sc) */ ath5k_stop_locked(sc); - /* Set PHY calibration interval */ - ah->ah_cal_intval = ath5k_calinterval; - /* * The basic interface to setting the hardware in a good * state is ``reset''. On return the hardware is known to @@ -2512,7 +2544,8 @@ ath5k_init(struct ath5k_softc *sc) sc->curband = &sc->sbands[sc->curchan->band]; sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | - AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI; + AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; + ret = ath5k_reset(sc, NULL); if (ret) goto done; @@ -2526,8 +2559,7 @@ ath5k_init(struct ath5k_softc *sc) for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) ath5k_hw_reset_key(ah, i); - /* Set ack to be sent at low bit-rates */ - ath5k_hw_set_ack_bitrate_high(ah, false); + ath5k_hw_set_ack_bitrate_high(ah, true); ret = 0; done: mmiowb(); @@ -2624,12 +2656,33 @@ ath5k_stop_hw(struct ath5k_softc *sc) tasklet_kill(&sc->restq); tasklet_kill(&sc->calib); tasklet_kill(&sc->beacontq); + tasklet_kill(&sc->ani_tasklet); ath5k_rfkill_hw_stop(sc->ah); return ret; } +static void +ath5k_intr_calibration_poll(struct ath5k_hw *ah) +{ + if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) && + !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) { + /* run ANI only when full calibration is not active */ + ah->ah_cal_next_ani = jiffies + + msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI); + tasklet_schedule(&ah->ah_sc->ani_tasklet); + + } else if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) { + ah->ah_cal_next_full = jiffies + + msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); + tasklet_schedule(&ah->ah_sc->calib); + } + /* we could use SWI to generate enough interrupts to meet our + * calibration interval requirements, if necessary: + * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */ +} + static irqreturn_t ath5k_intr(int irq, void *dev_id) { @@ -2653,7 +2706,20 @@ ath5k_intr(int irq, void *dev_id) */ tasklet_schedule(&sc->restq); } else if (unlikely(status & AR5K_INT_RXORN)) { - tasklet_schedule(&sc->restq); + /* + * Receive buffers are full. Either the bus is busy or + * the CPU is not fast enough to process all received + * frames. + * Older chipsets need a reset to come out of this + * condition, but we treat it as RX for newer chips. + * We don't know exactly which versions need a reset - + * this guess is copied from the HAL. + */ + sc->stats.rxorn_intr++; + if (ah->ah_mac_srev < AR5K_SREV_AR5212) + tasklet_schedule(&sc->restq); + else + tasklet_schedule(&sc->rxtq); } else { if (status & AR5K_INT_SWBA) { tasklet_hi_schedule(&sc->beacontq); @@ -2678,15 +2744,10 @@ ath5k_intr(int irq, void *dev_id) if (status & AR5K_INT_BMISS) { /* TODO */ } - if (status & AR5K_INT_SWI) { - tasklet_schedule(&sc->calib); - } if (status & AR5K_INT_MIB) { - /* - * These stats are also used for ANI i think - * so how about updating them more often ? - */ - ath5k_hw_update_mib_counters(ah, &sc->ll_stats); + sc->stats.mib_intr++; + ath5k_hw_update_mib_counters(ah); + ath5k_ani_mib_intr(ah); } if (status & AR5K_INT_GPIO) tasklet_schedule(&sc->rf_kill.toggleq); @@ -2697,7 +2758,7 @@ ath5k_intr(int irq, void *dev_id) if (unlikely(!counter)) ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); - ath5k_hw_calibration_poll(ah); + ath5k_intr_calibration_poll(ah); return IRQ_HANDLED; } @@ -2721,8 +2782,7 @@ ath5k_tasklet_calibrate(unsigned long data) struct ath5k_hw *ah = sc->ah; /* Only full calibration for now */ - if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION) - return; + ah->ah_cal_mask |= AR5K_CALIBRATION_FULL; /* Stop queues so that calibration * doesn't interfere with tx */ @@ -2738,18 +2798,29 @@ ath5k_tasklet_calibrate(unsigned long data) * to load new gain values. */ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); - ath5k_reset_wake(sc); + ath5k_reset(sc, sc->curchan); } if (ath5k_hw_phy_calibrate(ah, sc->curchan)) ATH5K_ERR(sc, "calibration of channel %u failed\n", ieee80211_frequency_to_channel( sc->curchan->center_freq)); - ah->ah_swi_mask = 0; - /* Wake queues */ ieee80211_wake_queues(sc->hw); + ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; +} + + +static void +ath5k_tasklet_ani(unsigned long data) +{ + struct ath5k_softc *sc = (void *)data; + struct ath5k_hw *ah = sc->ah; + + ah->ah_cal_mask |= AR5K_CALIBRATION_ANI; + ath5k_ani_calibration(ah); + ah->ah_cal_mask &= ~AR5K_CALIBRATION_ANI; } @@ -2852,6 +2923,8 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan) goto err; } + ath5k_ani_init(ah, ah->ah_sc->ani_state.ani_mode); + /* * Change channels and update the h/w rate map if we're switching; * e.g. 11a to 11b/g. @@ -3207,12 +3280,14 @@ ath5k_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; /* Force update */ - ath5k_hw_update_mib_counters(ah, &sc->ll_stats); + ath5k_hw_update_mib_counters(sc->ah); - memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats)); + stats->dot11ACKFailureCount = sc->stats.ack_fail; + stats->dot11RTSFailureCount = sc->stats.rts_fail; + stats->dot11RTSSuccessCount = sc->stats.rts_ok; + stats->dot11FCSErrorCount = sc->stats.fcs_error; return 0; } diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 33f1d8b87ee1..56221bc7c8cd 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -50,6 +50,7 @@ #include "ath5k.h" #include "debug.h" +#include "ani.h" #include "../regd.h" #include "../ath.h" @@ -105,14 +106,18 @@ struct ath5k_rfkill { struct tasklet_struct toggleq; }; -/* statistics (only used for debugging now) */ +/* statistics */ struct ath5k_statistics { + /* antenna use */ unsigned int antenna_rx[5]; /* frames count per antenna RX */ unsigned int antenna_tx[5]; /* frames count per antenna TX */ + + /* frame errors */ unsigned int rx_all_count; /* all RX frames, including errors */ unsigned int tx_all_count; /* all TX frames, including errors */ unsigned int rxerr_crc; unsigned int rxerr_phy; + unsigned int rxerr_phy_code[32]; unsigned int rxerr_fifo; unsigned int rxerr_decrypt; unsigned int rxerr_mic; @@ -121,6 +126,16 @@ struct ath5k_statistics { unsigned int txerr_retry; unsigned int txerr_fifo; unsigned int txerr_filt; + + /* MIB counters */ + unsigned int ack_fail; + unsigned int rts_fail; + unsigned int rts_ok; + unsigned int fcs_error; + unsigned int beacons; + + unsigned int mib_intr; + unsigned int rxorn_intr; }; #if CHAN_DEBUG @@ -135,7 +150,6 @@ struct ath5k_softc { struct pci_dev *pdev; /* for dma mapping */ void __iomem *iobase; /* address of the device */ struct mutex lock; /* dev-level lock */ - struct ieee80211_low_level_stats ll_stats; struct ieee80211_hw *hw; /* IEEE 802.11 common */ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; struct ieee80211_channel channels[ATH_CHAN_MAX]; @@ -211,6 +225,9 @@ struct ath5k_softc { bool enable_beacon; /* true if beacons are on */ struct ath5k_statistics stats; + + struct ath5k_ani_state ani_state; + struct tasklet_struct ani_tasklet; /* ANI calibration */ }; #define ath5k_hw_hasbssidmask(_ah) \ diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c index e618e71b1ce6..74f007126f41 100644 --- a/drivers/net/wireless/ath/ath5k/caps.c +++ b/drivers/net/wireless/ath/ath5k/caps.c @@ -109,6 +109,12 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) else ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; + /* newer hardware has PHY error counters */ + if (ah->ah_mac_srev >= AR5K_SREV_AR5213A) + ah->ah_capabilities.cap_has_phyerr_counters = true; + else + ah->ah_capabilities.cap_has_phyerr_counters = false; + return 0; } diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index bccd4a78027e..6fb5c5ffa5b1 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -69,6 +69,7 @@ module_param_named(debug, ath5k_debug, uint, 0); #include <linux/seq_file.h> #include "reg.h" +#include "ani.h" static struct dentry *ath5k_global_debugfs; @@ -307,6 +308,7 @@ static const struct { { ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" }, { ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" }, { ATH5K_DEBUG_TRACE, "trace", "trace function calls" }, + { ATH5K_DEBUG_ANI, "ani", "adaptive noise immunity" }, { ATH5K_DEBUG_ANY, "all", "show all debug levels" }, }; @@ -474,6 +476,7 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf, struct ath5k_statistics *st = &sc->stats; char buf[700]; unsigned int len = 0; + int i; len += snprintf(buf+len, sizeof(buf)-len, "RX\n---------------------\n"); @@ -485,6 +488,13 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf, st->rxerr_phy, st->rx_all_count > 0 ? st->rxerr_phy*100/st->rx_all_count : 0); + for (i = 0; i < 32; i++) { + if (st->rxerr_phy_code[i]) + len += snprintf(buf+len, sizeof(buf)-len, + " phy_err[%d]\t%d\n", + i, st->rxerr_phy_code[i]); + } + len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n", st->rxerr_fifo, st->rx_all_count > 0 ? @@ -565,6 +575,160 @@ static const struct file_operations fops_frameerrors = { }; +/* debugfs: ani */ + +static ssize_t read_file_ani(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + struct ath5k_statistics *st = &sc->stats; + struct ath5k_ani_state *as = &sc->ani_state; + + char buf[700]; + unsigned int len = 0; + + len += snprintf(buf+len, sizeof(buf)-len, + "HW has PHY error counters:\t%s\n", + sc->ah->ah_capabilities.cap_has_phyerr_counters ? + "yes" : "no"); + len += snprintf(buf+len, sizeof(buf)-len, + "HW max spur immunity level:\t%d\n", + as->max_spur_level); + len += snprintf(buf+len, sizeof(buf)-len, + "\nANI state\n--------------------------------------------\n"); + len += snprintf(buf+len, sizeof(buf)-len, "operating mode:\t\t\t"); + switch (as->ani_mode) { + case ATH5K_ANI_MODE_OFF: + len += snprintf(buf+len, sizeof(buf)-len, "OFF\n"); + break; + case ATH5K_ANI_MODE_MANUAL_LOW: + len += snprintf(buf+len, sizeof(buf)-len, + "MANUAL LOW\n"); + break; + case ATH5K_ANI_MODE_MANUAL_HIGH: + len += snprintf(buf+len, sizeof(buf)-len, + "MANUAL HIGH\n"); + break; + case ATH5K_ANI_MODE_AUTO: + len += snprintf(buf+len, sizeof(buf)-len, "AUTO\n"); + break; + default: + len += snprintf(buf+len, sizeof(buf)-len, + "??? (not good)\n"); + break; + } + len += snprintf(buf+len, sizeof(buf)-len, + "noise immunity level:\t\t%d\n", + as->noise_imm_level); + len += snprintf(buf+len, sizeof(buf)-len, + "spur immunity level:\t\t%d\n", + as->spur_level); + len += snprintf(buf+len, sizeof(buf)-len, "firstep level:\t\t\t%d\n", + as->firstep_level); + len += snprintf(buf+len, sizeof(buf)-len, + "OFDM weak signal detection:\t%s\n", + as->ofdm_weak_sig ? "on" : "off"); + len += snprintf(buf+len, sizeof(buf)-len, + "CCK weak signal detection:\t%s\n", + as->cck_weak_sig ? "on" : "off"); + + len += snprintf(buf+len, sizeof(buf)-len, + "\nMIB INTERRUPTS:\t\t%u\n", + st->mib_intr); + len += snprintf(buf+len, sizeof(buf)-len, + "beacon RSSI average:\t%d\n", + sc->ah->ah_beacon_rssi_avg.avg); + len += snprintf(buf+len, sizeof(buf)-len, "profcnt tx\t\t%u\t(%d%%)\n", + as->pfc_tx, + as->pfc_cycles > 0 ? + as->pfc_tx*100/as->pfc_cycles : 0); + len += snprintf(buf+len, sizeof(buf)-len, "profcnt rx\t\t%u\t(%d%%)\n", + as->pfc_rx, + as->pfc_cycles > 0 ? + as->pfc_rx*100/as->pfc_cycles : 0); + len += snprintf(buf+len, sizeof(buf)-len, "profcnt busy\t\t%u\t(%d%%)\n", + as->pfc_busy, + as->pfc_cycles > 0 ? + as->pfc_busy*100/as->pfc_cycles : 0); + len += snprintf(buf+len, sizeof(buf)-len, "profcnt cycles\t\t%u\n", + as->pfc_cycles); + len += snprintf(buf+len, sizeof(buf)-len, + "listen time\t\t%d\tlast: %d\n", + as->listen_time, as->last_listen); + len += snprintf(buf+len, sizeof(buf)-len, + "OFDM errors\t\t%u\tlast: %u\tsum: %u\n", + as->ofdm_errors, as->last_ofdm_errors, + as->sum_ofdm_errors); + len += snprintf(buf+len, sizeof(buf)-len, + "CCK errors\t\t%u\tlast: %u\tsum: %u\n", + as->cck_errors, as->last_cck_errors, + as->sum_cck_errors); + len += snprintf(buf+len, sizeof(buf)-len, + "AR5K_PHYERR_CNT1\t%x\t(=%d)\n", + ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1), + ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - + ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1))); + len += snprintf(buf+len, sizeof(buf)-len, + "AR5K_PHYERR_CNT2\t%x\t(=%d)\n", + ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2), + ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - + ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2))); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_ani(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + char buf[20]; + + if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) + return -EFAULT; + + if (strncmp(buf, "sens-low", 8) == 0) { + ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_MANUAL_HIGH); + } else if (strncmp(buf, "sens-high", 9) == 0) { + ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_MANUAL_LOW); + } else if (strncmp(buf, "ani-off", 7) == 0) { + ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_OFF); + } else if (strncmp(buf, "ani-on", 6) == 0) { + ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_AUTO); + } else if (strncmp(buf, "noise-low", 9) == 0) { + ath5k_ani_set_noise_immunity_level(sc->ah, 0); + } else if (strncmp(buf, "noise-high", 10) == 0) { + ath5k_ani_set_noise_immunity_level(sc->ah, + ATH5K_ANI_MAX_NOISE_IMM_LVL); + } else if (strncmp(buf, "spur-low", 8) == 0) { + ath5k_ani_set_spur_immunity_level(sc->ah, 0); + } else if (strncmp(buf, "spur-high", 9) == 0) { + ath5k_ani_set_spur_immunity_level(sc->ah, + sc->ani_state.max_spur_level); + } else if (strncmp(buf, "fir-low", 7) == 0) { + ath5k_ani_set_firstep_level(sc->ah, 0); + } else if (strncmp(buf, "fir-high", 8) == 0) { + ath5k_ani_set_firstep_level(sc->ah, ATH5K_ANI_MAX_FIRSTEP_LVL); + } else if (strncmp(buf, "ofdm-off", 8) == 0) { + ath5k_ani_set_ofdm_weak_signal_detection(sc->ah, false); + } else if (strncmp(buf, "ofdm-on", 7) == 0) { + ath5k_ani_set_ofdm_weak_signal_detection(sc->ah, true); + } else if (strncmp(buf, "cck-off", 7) == 0) { + ath5k_ani_set_cck_weak_signal_detection(sc->ah, false); + } else if (strncmp(buf, "cck-on", 6) == 0) { + ath5k_ani_set_cck_weak_signal_detection(sc->ah, true); + } + return count; +} + +static const struct file_operations fops_ani = { + .read = read_file_ani, + .write = write_file_ani, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE, +}; + + /* init */ void @@ -603,6 +767,11 @@ ath5k_debug_init_device(struct ath5k_softc *sc) S_IWUSR | S_IRUSR, sc->debug.debugfs_phydir, sc, &fops_frameerrors); + + sc->debug.debugfs_ani = debugfs_create_file("ani", + S_IWUSR | S_IRUSR, + sc->debug.debugfs_phydir, sc, + &fops_ani); } void @@ -620,6 +789,7 @@ ath5k_debug_finish_device(struct ath5k_softc *sc) debugfs_remove(sc->debug.debugfs_reset); debugfs_remove(sc->debug.debugfs_antenna); debugfs_remove(sc->debug.debugfs_frameerrors); + debugfs_remove(sc->debug.debugfs_ani); debugfs_remove(sc->debug.debugfs_phydir); } diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h index da24ff52e274..ddd5b3a99e8d 100644 --- a/drivers/net/wireless/ath/ath5k/debug.h +++ b/drivers/net/wireless/ath/ath5k/debug.h @@ -76,6 +76,7 @@ struct ath5k_dbg_info { struct dentry *debugfs_reset; struct dentry *debugfs_antenna; struct dentry *debugfs_frameerrors; + struct dentry *debugfs_ani; }; /** @@ -115,6 +116,7 @@ enum ath5k_debug_level { ATH5K_DEBUG_DUMP_TX = 0x00000200, ATH5K_DEBUG_DUMPBANDS = 0x00000400, ATH5K_DEBUG_TRACE = 0x00001000, + ATH5K_DEBUG_ANI = 0x00002000, ATH5K_DEBUG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 9d920fb14d5d..7d7b646ab65a 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -645,6 +645,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, rs->rs_status |= AR5K_RXERR_PHY; rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1, AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); + ath5k_ani_phy_error_report(ah, rs->rs_phyerr); } if (rx_status->rx_status_1 & diff --git a/drivers/net/wireless/ath/ath5k/desc.h b/drivers/net/wireless/ath/ath5k/desc.h index 56158c804e3e..64538fbe4167 100644 --- a/drivers/net/wireless/ath/ath5k/desc.h +++ b/drivers/net/wireless/ath/ath5k/desc.h @@ -112,15 +112,32 @@ struct ath5k_hw_rx_error { #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE 0x0000ff00 #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S 8 -/* PHY Error codes */ -#define AR5K_DESC_RX_PHY_ERROR_NONE 0x00 -#define AR5K_DESC_RX_PHY_ERROR_TIMING 0x20 -#define AR5K_DESC_RX_PHY_ERROR_PARITY 0x40 -#define AR5K_DESC_RX_PHY_ERROR_RATE 0x60 -#define AR5K_DESC_RX_PHY_ERROR_LENGTH 0x80 -#define AR5K_DESC_RX_PHY_ERROR_64QAM 0xa0 -#define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0 -#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0 +/** + * enum ath5k_phy_error_code - PHY Error codes + */ +enum ath5k_phy_error_code { + AR5K_RX_PHY_ERROR_UNDERRUN = 0, /* Transmit underrun */ + AR5K_RX_PHY_ERROR_TIMING = 1, /* Timing error */ + AR5K_RX_PHY_ERROR_PARITY = 2, /* Illegal parity */ + AR5K_RX_PHY_ERROR_RATE = 3, /* Illegal rate */ + AR5K_RX_PHY_ERROR_LENGTH = 4, /* Illegal length */ + AR5K_RX_PHY_ERROR_RADAR = 5, /* Radar detect */ + AR5K_RX_PHY_ERROR_SERVICE = 6, /* Illegal service */ + AR5K_RX_PHY_ERROR_TOR = 7, /* Transmit override receive */ + /* these are specific to the 5212 */ + AR5K_RX_PHY_ERROR_OFDM_TIMING = 17, + AR5K_RX_PHY_ERROR_OFDM_SIGNAL_PARITY = 18, + AR5K_RX_PHY_ERROR_OFDM_RATE_ILLEGAL = 19, + AR5K_RX_PHY_ERROR_OFDM_LENGTH_ILLEGAL = 20, + AR5K_RX_PHY_ERROR_OFDM_POWER_DROP = 21, + AR5K_RX_PHY_ERROR_OFDM_SERVICE = 22, + AR5K_RX_PHY_ERROR_OFDM_RESTART = 23, + AR5K_RX_PHY_ERROR_CCK_TIMING = 25, + AR5K_RX_PHY_ERROR_CCK_HEADER_CRC = 26, + AR5K_RX_PHY_ERROR_CCK_RATE_ILLEGAL = 27, + AR5K_RX_PHY_ERROR_CCK_SERVICE = 30, + AR5K_RX_PHY_ERROR_CCK_RESTART = 31, +}; /* * 5210/5211 hardware 2-word TX control descriptor diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 1b9fcb842167..174412fc81f8 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -113,39 +113,26 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) } /** - * ath5k_hw_update - Update mib counters (mac layer statistics) + * ath5k_hw_update - Update MIB counters (mac layer statistics) * * @ah: The &struct ath5k_hw - * @stats: The &struct ieee80211_low_level_stats we use to track - * statistics on the driver * - * Reads MIB counters from PCU and updates sw statistics. Must be - * called after a MIB interrupt. + * Reads MIB counters from PCU and updates sw statistics. Is called after a + * MIB interrupt, because one of these counters might have reached their maximum + * and triggered the MIB interrupt, to let us read and clear the counter. + * + * Is called in interrupt context! */ -void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, - struct ieee80211_low_level_stats *stats) +void ath5k_hw_update_mib_counters(struct ath5k_hw *ah) { - ATH5K_TRACE(ah->ah_sc); + struct ath5k_statistics *stats = &ah->ah_sc->stats; /* Read-And-Clear */ - stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); - stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); - stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK); - stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); - - /* XXX: Should we use this to track beacon count ? - * -we read it anyway to clear the register */ - ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); - - /* Reset profile count registers on 5212*/ - if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); - } - - /* TODO: Handle ANI stats */ + stats->ack_fail += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); + stats->rts_fail += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); + stats->rts_ok += ath5k_hw_reg_read(ah, AR5K_RTS_OK); + stats->fcs_error += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); + stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); } /** @@ -167,9 +154,9 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) else { u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; if (high) - AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); - else AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); + else + AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); } } @@ -392,7 +379,6 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) * (ACK etc). * * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma - * TODO: Init ANI here */ void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) { diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 3ee74c839768..3ce9afba1d88 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -980,7 +980,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, return -EINVAL; data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8); - } else if ((c - (c % 5)) != 2 || c > 5435) { + } else if ((c % 5) != 2 || c > 5435) { if (!(c % 20) && c >= 5120) { data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); data2 = ath5k_hw_bitswap(3, 2); @@ -993,7 +993,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, } else return -EINVAL; } else { - data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); + data0 = ath5k_hw_bitswap((10 * (c - 2 - 4800)) / 25 + 1, 8); data2 = ath5k_hw_bitswap(0, 2); } @@ -1021,7 +1021,7 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah, data0 = ath5k_hw_bitswap((c - 2272), 8); data2 = 0; /* ? 5GHz ? */ - } else if ((c - (c % 5)) != 2 || c > 5435) { + } else if ((c % 5) != 2 || c > 5435) { if (!(c % 20) && c < 5120) data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); else if (!(c % 10)) @@ -1032,7 +1032,7 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah, return -EINVAL; data2 = ath5k_hw_bitswap(1, 2); } else { - data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); + data0 = ath5k_hw_bitswap((10 * (c - 2 - 4800)) / 25 + 1, 8); data2 = ath5k_hw_bitswap(0, 2); } @@ -1103,28 +1103,6 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) PHY calibration \*****************/ -void -ath5k_hw_calibration_poll(struct ath5k_hw *ah) -{ - /* Calibration interval in jiffies */ - unsigned long cal_intval; - - cal_intval = msecs_to_jiffies(ah->ah_cal_intval * 1000); - - /* Initialize timestamp if needed */ - if (!ah->ah_cal_tstamp) - ah->ah_cal_tstamp = jiffies; - - /* For now we always do full calibration - * Mark software interrupt mask and fire software - * interrupt (bit gets auto-cleared) */ - if (time_is_before_eq_jiffies(ah->ah_cal_tstamp + cal_intval)) { - ah->ah_cal_tstamp = jiffies; - ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION; - AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); - } -} - static int sign_extend(int val, const int nbits) { int order = BIT(nbits-1); @@ -1411,7 +1389,10 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, i_coff = (-iq_corr) / i_coffd; i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */ - q_coff = (i_pwr / q_coffd) - 128; + if (ah->ah_version == AR5K_AR5211) + q_coff = (i_pwr / q_coffd) - 64; + else + q_coff = (i_pwr / q_coffd) - 128; q_coff = clamp(q_coff, -16, 15); /* signed 5 bit */ ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, @@ -2580,7 +2561,7 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, max_idx = (pdadc_n < table_size) ? pdadc_n : table_size; /* Fill pdadc_out table */ - while (pdadc_0 < max_idx) + while (pdadc_0 < max_idx && pdadc_i < 128) pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++]; /* Need to extrapolate above this pdgain? */ diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 47f04932ab8b..55b4ac6d236f 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -212,10 +212,10 @@ * MIB control register */ #define AR5K_MIBC 0x0040 /* Register Address */ -#define AR5K_MIBC_COW 0x00000001 /* Warn test indicator */ +#define AR5K_MIBC_COW 0x00000001 /* Counter Overflow Warning */ #define AR5K_MIBC_FMC 0x00000002 /* Freeze MIB Counters */ -#define AR5K_MIBC_CMC 0x00000004 /* Clean MIB Counters */ -#define AR5K_MIBC_MCS 0x00000008 /* MIB counter strobe */ +#define AR5K_MIBC_CMC 0x00000004 /* Clear MIB Counters */ +#define AR5K_MIBC_MCS 0x00000008 /* MIB counter strobe, increment all */ /* * Timeout prescale register @@ -1139,8 +1139,8 @@ #define AR5K_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */ #define AR5K_STA_ID1_DESC_ANTENNA 0x00400000 /* Update antenna from descriptor */ #define AR5K_STA_ID1_RTS_DEF_ANTENNA 0x00800000 /* Use default antenna for RTS */ -#define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mbit/s for ACK/CTS */ -#define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate for ACK/CTS [5211+] */ +#define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Rate to use for ACK/CTS. 0: highest mandatory rate <= RX rate; 1: 1Mbps in B mode */ +#define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* 802.11b base rate. 0: 1, 2, 5.5 and 11Mbps; 1: 1 and 2Mbps. [5211+] */ #define AR5K_STA_ID1_SELFGEN_DEF_ANT 0x04000000 /* Use def. antenna for self generated frames */ #define AR5K_STA_ID1_CRYPT_MIC_EN 0x08000000 /* Enable MIC */ #define AR5K_STA_ID1_KEYSRCH_MODE 0x10000000 /* Look up key when key id != 0 */ @@ -1516,7 +1516,14 @@ AR5K_NAV_5210 : AR5K_NAV_5211) /* - * RTS success register + * MIB counters: + * + * max value is 0xc000, if this is reached we get a MIB interrupt. + * they can be controlled via AR5K_MIBC and are cleared on read. + */ + +/* + * RTS success (MIB counter) */ #define AR5K_RTS_OK_5210 0x8090 #define AR5K_RTS_OK_5211 0x8088 @@ -1524,7 +1531,7 @@ AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211) /* - * RTS failure register + * RTS failure (MIB counter) */ #define AR5K_RTS_FAIL_5210 0x8094 #define AR5K_RTS_FAIL_5211 0x808c @@ -1532,7 +1539,7 @@ AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211) /* - * ACK failure register + * ACK failure (MIB counter) */ #define AR5K_ACK_FAIL_5210 0x8098 #define AR5K_ACK_FAIL_5211 0x8090 @@ -1540,7 +1547,7 @@ AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211) /* - * FCS failure register + * FCS failure (MIB counter) */ #define AR5K_FCS_FAIL_5210 0x809c #define AR5K_FCS_FAIL_5211 0x8094 @@ -1667,11 +1674,17 @@ /* * Profile count registers + * + * These registers can be cleared and freezed with ATH5K_MIBC, but they do not + * generate a MIB interrupt. + * Instead of overflowing, they shift by one bit to the right. All registers + * shift together, i.e. when one reaches the max, all shift at the same time by + * one bit to the right. This way we should always get consistent values. */ #define AR5K_PROFCNT_TX 0x80ec /* Tx count */ #define AR5K_PROFCNT_RX 0x80f0 /* Rx count */ -#define AR5K_PROFCNT_RXCLR 0x80f4 /* Clear Rx count */ -#define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle count (?) */ +#define AR5K_PROFCNT_RXCLR 0x80f4 /* Busy count */ +#define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle counter */ /* * Quiet period control registers @@ -1758,7 +1771,7 @@ #define AR5K_CCK_FIL_CNT 0x8128 /* - * PHY Error Counters (?) + * PHY Error Counters (same masks as AR5K_PHY_ERR_FIL) */ #define AR5K_PHYERR_CNT1 0x812c #define AR5K_PHYERR_CNT1_MASK 0x8130 @@ -1766,6 +1779,9 @@ #define AR5K_PHYERR_CNT2 0x8134 #define AR5K_PHYERR_CNT2_MASK 0x8138 +/* if the PHY Error Counters reach this maximum, we get MIB interrupts */ +#define ATH5K_PHYERR_CNT_MAX 0x00c00000 + /* * TSF Threshold register (?) */ diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index ca4994f13151..85fdd26039c8 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -47,6 +47,7 @@ static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) } static struct ath_bus_ops ath_ahb_bus_ops = { + .ath_bus_type = ATH_AHB, .read_cachesize = ath_ahb_read_cachesize, .eeprom_read = ath_ahb_eeprom_read, }; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 83c7ea4c007f..bdcd257ca7a4 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -178,9 +178,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, #define BAW_WITHIN(_start, _bawsz, _seqno) \ ((((_seqno) - (_start)) & 4095) < (_bawsz)) -#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum) -#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low) -#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) #define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) #define ATH_TX_COMPLETE_POLL_INT 1000 @@ -483,7 +480,6 @@ struct ath_softc { bool ps_enabled; bool ps_idle; unsigned long ps_usecount; - enum ath9k_int imask; struct ath_config config; struct ath_rx rx; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index b4a31a43a62c..22375a754718 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -524,6 +524,7 @@ static void ath9k_beacon_init(struct ath_softc *sc, static void ath_beacon_config_ap(struct ath_softc *sc, struct ath_beacon_config *conf) { + struct ath_hw *ah = sc->sc_ah; u32 nexttbtt, intval; /* NB: the beacon interval is kept internally in TU's */ @@ -539,15 +540,15 @@ static void ath_beacon_config_ap(struct ath_softc *sc, * prepare beacon frames. */ intval |= ATH9K_BEACON_ENA; - sc->imask |= ATH9K_INT_SWBA; + ah->imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); /* Set the computed AP beacon timers */ - ath9k_hw_set_interrupts(sc->sc_ah, 0); + ath9k_hw_set_interrupts(ah, 0); ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); /* Clear the reset TSF flag, so that subsequent beacon updation will not reset the HW TSF. */ @@ -566,7 +567,8 @@ static void ath_beacon_config_ap(struct ath_softc *sc, static void ath_beacon_config_sta(struct ath_softc *sc, struct ath_beacon_config *conf) { - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_beacon_state bs; int dtimperiod, dtimcount, sleepduration; int cfpperiod, cfpcount; @@ -605,7 +607,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc, * Pull nexttbtt forward to reflect the current * TSF and calculate dtim+cfp state for the result. */ - tsf = ath9k_hw_gettsf64(sc->sc_ah); + tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; num_beacons = tsftu / intval + 1; @@ -678,17 +680,18 @@ static void ath_beacon_config_sta(struct ath_softc *sc, /* Set the computed STA beacon timers */ - ath9k_hw_set_interrupts(sc->sc_ah, 0); - ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs); - sc->imask |= ATH9K_INT_BMISS; - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + ath9k_hw_set_interrupts(ah, 0); + ath9k_hw_set_sta_beacon_timers(ah, &bs); + ah->imask |= ATH9K_INT_BMISS; + ath9k_hw_set_interrupts(ah, ah->imask); } static void ath_beacon_config_adhoc(struct ath_softc *sc, struct ath_beacon_config *conf, struct ieee80211_vif *vif) { - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); u64 tsf; u32 tsftu, intval, nexttbtt; @@ -703,7 +706,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, else if (intval) nexttbtt = roundup(nexttbtt, intval); - tsf = ath9k_hw_gettsf64(sc->sc_ah); + tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE; do { nexttbtt += intval; @@ -719,20 +722,20 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, * self-linked tx descriptor and let the hardware deal with things. */ intval |= ATH9K_BEACON_ENA; - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) - sc->imask |= ATH9K_INT_SWBA; + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) + ah->imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); /* Set the computed ADHOC beacon timers */ - ath9k_hw_set_interrupts(sc->sc_ah, 0); + ath9k_hw_set_interrupts(ah, 0); ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); /* FIXME: Handle properly when vif is NULL */ - if (vif && sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) + if (vif && ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) ath_beacon_start_adhoc(sc, vif); } diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index d5026e4f484b..064f5b51dfcd 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -18,6 +18,7 @@ /* We can tune this as we go by monitoring really low values */ #define ATH9K_NF_TOO_LOW -60 +#define AR9285_CLCAL_REDO_THRESH 1 /* AR5416 may return very high value (like -31 dBm), in those cases the nf * is incorrect and we should use the static NF value. Later we can try to @@ -1091,7 +1092,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, EXPORT_SYMBOL(ath9k_hw_calibrate); /* Carrier leakage Calibration fix */ -static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) +static bool ar9285_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); @@ -1132,6 +1133,62 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) return true; } +static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) +{ + int i; + u_int32_t txgain_max; + u_int32_t clc_gain, gain_mask = 0, clc_num = 0; + u_int32_t reg_clc_I0, reg_clc_Q0; + u_int32_t i0_num = 0; + u_int32_t q0_num = 0; + u_int32_t total_num = 0; + u_int32_t reg_rf2g5_org; + bool retv = true; + + if (!(ar9285_cl_cal(ah, chan))) + return false; + + txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7), + AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX); + + for (i = 0; i < (txgain_max+1); i++) { + clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) & + AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S; + if (!(gain_mask & (1 << clc_gain))) { + gain_mask |= (1 << clc_gain); + clc_num++; + } + } + + for (i = 0; i < clc_num; i++) { + reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) + & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S; + reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) + & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S; + if (reg_clc_I0 == 0) + i0_num++; + + if (reg_clc_Q0 == 0) + q0_num++; + } + total_num = i0_num + q0_num; + if (total_num > AR9285_CLCAL_REDO_THRESH) { + reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5); + if (AR_SREV_9285E_20(ah)) { + REG_WRITE(ah, AR9285_RF2G5, + (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | + AR9285_RF2G5_IC50TX_XE_SET); + } else { + REG_WRITE(ah, AR9285_RF2G5, + (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | + AR9285_RF2G5_IC50TX_SET); + } + retv = ar9285_cl_cal(ah, chan); + REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org); + } + return retv; +} + bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 7902d287f671..09effdedc8c0 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -255,7 +255,8 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, keyix = rx_stats->rs_keyix; - if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { + if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error && + ieee80211_has_protected(fc)) { rxs->flag |= RX_FLAG_DECRYPTED; } else if (ieee80211_has_protected(fc) && !decrypt_error && skb->len >= hdrlen + 4) { @@ -303,88 +304,6 @@ int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb) } EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype); -/* - * Calculate the RX filter to be set in the HW. - */ -u32 ath9k_cmn_calcrxfilter(struct ieee80211_hw *hw, struct ath_hw *ah, - unsigned int rxfilter) -{ -#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) - - u32 rfilt; - - rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE) - | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST - | ATH9K_RX_FILTER_MCAST; - - /* If not a STA, enable processing of Probe Requests */ - if (ah->opmode != NL80211_IFTYPE_STATION) - rfilt |= ATH9K_RX_FILTER_PROBEREQ; - - /* - * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station - * mode interface or when in monitor mode. AP mode does not need this - * since it receives all in-BSS frames anyway. - */ - if (((ah->opmode != NL80211_IFTYPE_AP) && - (rxfilter & FIF_PROMISC_IN_BSS)) || - (ah->opmode == NL80211_IFTYPE_MONITOR)) - rfilt |= ATH9K_RX_FILTER_PROM; - - if (rxfilter & FIF_CONTROL) - rfilt |= ATH9K_RX_FILTER_CONTROL; - - if ((ah->opmode == NL80211_IFTYPE_STATION) && - !(rxfilter & FIF_BCN_PRBRESP_PROMISC)) - rfilt |= ATH9K_RX_FILTER_MYBEACON; - else - rfilt |= ATH9K_RX_FILTER_BEACON; - - if ((AR_SREV_9280_10_OR_LATER(ah) || - AR_SREV_9285_10_OR_LATER(ah)) && - (ah->opmode == NL80211_IFTYPE_AP) && - (rxfilter & FIF_PSPOLL)) - rfilt |= ATH9K_RX_FILTER_PSPOLL; - - if (conf_is_ht(&hw->conf)) - rfilt |= ATH9K_RX_FILTER_COMP_BAR; - - return rfilt; - -#undef RX_FILTER_PRESERVE -} -EXPORT_SYMBOL(ath9k_cmn_calcrxfilter); - -/* - * Recv initialization for opmode change. - */ -void ath9k_cmn_opmode_init(struct ieee80211_hw *hw, struct ath_hw *ah, - unsigned int rxfilter) -{ - struct ath_common *common = ath9k_hw_common(ah); - - u32 rfilt, mfilt[2]; - - /* configure rx filter */ - rfilt = ath9k_cmn_calcrxfilter(hw, ah, rxfilter); - ath9k_hw_setrxfilter(ah, rfilt); - - /* configure bssid mask */ - if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) - ath_hw_setbssidmask(common); - - /* configure operational mode */ - ath9k_hw_setopmode(ah); - - /* Handle any link-level address change. */ - ath9k_hw_setmac(ah, common->macaddr); - - /* calculate and install multicast filter */ - mfilt[0] = mfilt[1] = ~0; - ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); -} -EXPORT_SYMBOL(ath9k_cmn_opmode_init); - static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) { diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index bbcc57f6eba3..72a835d9e97f 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -128,10 +128,6 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, int ath9k_cmn_padpos(__le16 frame_control); int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb); -u32 ath9k_cmn_calcrxfilter(struct ieee80211_hw *hw, struct ath_hw *ah, - unsigned int rxfilter); -void ath9k_cmn_opmode_init(struct ieee80211_hw *hw, struct ath_hw *ah, - unsigned int rxfilter); void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw, struct ath9k_channel *ichan); struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 081e0085ed4c..9a8e419398f9 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -157,10 +157,10 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); - len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x \n", + len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x\n", REG_READ_D(ah, AR_OBS_BUS_1)); len += snprintf(buf + len, DMA_BUF_LEN - len, - "AR_CR: 0x%x \n", REG_READ_D(ah, AR_CR)); + "AR_CR: 0x%x\n", REG_READ_D(ah, AR_CR)); ath9k_ps_restore(sc); @@ -557,10 +557,8 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, } void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, - struct ath_buf *bf) + struct ath_buf *bf, struct ath_tx_status *ts) { - struct ath_desc *ds = bf->bf_desc; - if (bf_isampdu(bf)) { if (bf_isxretried(bf)) TX_STAT_INC(txq->axq_qnum, a_xretries); @@ -570,17 +568,17 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, TX_STAT_INC(txq->axq_qnum, completed); } - if (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO) + if (ts->ts_status & ATH9K_TXERR_FIFO) TX_STAT_INC(txq->axq_qnum, fifo_underrun); - if (ds->ds_txstat.ts_status & ATH9K_TXERR_XTXOP) + if (ts->ts_status & ATH9K_TXERR_XTXOP) TX_STAT_INC(txq->axq_qnum, xtxop); - if (ds->ds_txstat.ts_status & ATH9K_TXERR_TIMER_EXPIRED) + if (ts->ts_status & ATH9K_TXERR_TIMER_EXPIRED) TX_STAT_INC(txq->axq_qnum, timer_exp); - if (ds->ds_txstat.ts_flags & ATH9K_TX_DESC_CFG_ERR) + if (ts->ts_flags & ATH9K_TX_DESC_CFG_ERR) TX_STAT_INC(txq->axq_qnum, desc_cfg_err); - if (ds->ds_txstat.ts_flags & ATH9K_TX_DATA_UNDERRUN) + if (ts->ts_flags & ATH9K_TX_DATA_UNDERRUN) TX_STAT_INC(txq->axq_qnum, data_underrun); - if (ds->ds_txstat.ts_flags & ATH9K_TX_DELIM_UNDERRUN) + if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN) TX_STAT_INC(txq->axq_qnum, delim_underrun); } @@ -663,30 +661,29 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, #undef PHY_ERR } -void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf) +void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) { #define RX_STAT_INC(c) sc->debug.stats.rxstats.c++ #define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ - struct ath_desc *ds = bf->bf_desc; u32 phyerr; - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) + if (rs->rs_status & ATH9K_RXERR_CRC) RX_STAT_INC(crc_err); - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) + if (rs->rs_status & ATH9K_RXERR_DECRYPT) RX_STAT_INC(decrypt_crc_err); - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) + if (rs->rs_status & ATH9K_RXERR_MIC) RX_STAT_INC(mic_err); - if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_PRE) + if (rs->rs_status & ATH9K_RX_DELIM_CRC_PRE) RX_STAT_INC(pre_delim_crc_err); - if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_POST) + if (rs->rs_status & ATH9K_RX_DELIM_CRC_POST) RX_STAT_INC(post_delim_crc_err); - if (ds->ds_rxstat.rs_status & ATH9K_RX_DECRYPT_BUSY) + if (rs->rs_status & ATH9K_RX_DECRYPT_BUSY) RX_STAT_INC(decrypt_busy_err); - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) { + if (rs->rs_status & ATH9K_RXERR_PHY) { RX_STAT_INC(phy_err); - phyerr = ds->ds_rxstat.rs_phyerr & 0x24; + phyerr = rs->rs_phyerr & 0x24; RX_PHY_ERR_INC(phyerr); } diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 86780e68b31e..b2af9de755e6 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -167,8 +167,8 @@ void ath9k_debug_remove_root(void); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_rc(struct ath_softc *sc, int final_rate); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, - struct ath_buf *bf); -void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf); + struct ath_buf *bf, struct ath_tx_status *ts); +void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs); void ath_debug_stat_retries(struct ath_softc *sc, int rix, int xretries, int retries, u8 per); @@ -204,12 +204,13 @@ static inline void ath_debug_stat_rc(struct ath_softc *sc, static inline void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, - struct ath_buf *bf) + struct ath_buf *bf, + struct ath_tx_status *ts) { } static inline void ath_debug_stat_rx(struct ath_softc *sc, - struct ath_buf *bf) + struct ath_rx_status *rs) { } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 68db16690abf..0354fe50f8e0 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -43,7 +43,7 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) { ath_print(common, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); + "Unable to read eeprom region\n"); return false; } eep_data++; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 839d05a1df29..d8ca94c3fa0c 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -44,7 +44,7 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) { ath_print(common, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); + "Unable to read eeprom region\n"); return false; } eep_data++; diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index deab8beb0680..0ee75e79fe35 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -283,22 +283,17 @@ static void ath9k_gen_timer_start(struct ath_hw *ah, u32 timer_next, u32 timer_period) { - struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; - ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); - if ((sc->imask & ATH9K_INT_GENTIMER) == 0) { + if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { ath9k_hw_set_interrupts(ah, 0); - sc->imask |= ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, sc->imask); + ah->imask |= ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, ah->imask); } } static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) { - struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; ath9k_hw_gen_timer_stop(ah, timer); @@ -306,8 +301,8 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) /* if no timer is enabled, turn off interrupt mask */ if (timer_table->timer_mask.val == 0) { ath9k_hw_set_interrupts(ah, 0); - sc->imask &= ~ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, sc->imask); + ah->imask &= ~ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, ah->imask); } } @@ -364,7 +359,7 @@ static void ath_btcoex_no_stomp_timer(void *arg) bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN; ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, - "no stomp timer running \n"); + "no stomp timer running\n"); spin_lock_bh(&btcoex->btcoex_lock); diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index fc4f6e8c9ef3..fe994e229898 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -21,6 +21,7 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { ATH9K_FW_USB_DEV(0x9271, "ar9271.fw"), + ATH9K_FW_USB_DEV(0x1006, "ar9271.fw"), { }, }; @@ -31,27 +32,15 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev); static void hif_usb_regout_cb(struct urb *urb) { struct cmd_buf *cmd = (struct cmd_buf *)urb->context; - struct hif_device_usb *hif_dev = cmd->hif_dev; - - if (!hif_dev) { - usb_free_urb(urb); - if (cmd) { - if (cmd->skb) - dev_kfree_skb_any(cmd->skb); - kfree(cmd); - } - return; - } switch (urb->status) { case 0: break; case -ENOENT: case -ECONNRESET: - break; case -ENODEV: case -ESHUTDOWN: - return; + goto free; default: break; } @@ -60,8 +49,12 @@ static void hif_usb_regout_cb(struct urb *urb) ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle, cmd->skb, 1); kfree(cmd); - usb_free_urb(urb); } + + return; +free: + kfree_skb(cmd->skb); + kfree(cmd); } static int hif_usb_send_regout(struct hif_device_usb *hif_dev, @@ -89,11 +82,13 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev, skb->data, skb->len, hif_usb_regout_cb, cmd, 1); + usb_anchor_urb(urb, &hif_dev->regout_submitted); ret = usb_submit_urb(urb, GFP_KERNEL); if (ret) { - usb_free_urb(urb); + usb_unanchor_urb(urb); kfree(cmd); } + usb_free_urb(urb); return ret; } @@ -154,6 +149,13 @@ static void hif_usb_tx_cb(struct urb *urb) } } +static inline void ath9k_skb_queue_purge(struct sk_buff_head *list) +{ + struct sk_buff *skb; + while ((skb = __skb_dequeue(list)) != NULL) + dev_kfree_skb_any(skb); +} + /* TX lock has to be taken */ static int __hif_usb_tx(struct hif_device_usb *hif_dev) { @@ -212,7 +214,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev) ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC); if (ret) { tx_buf->len = tx_buf->offset = 0; - __skb_queue_purge(&tx_buf->skb_queue); + ath9k_skb_queue_purge(&tx_buf->skb_queue); __skb_queue_head_init(&tx_buf->skb_queue); list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf); hif_dev->tx.tx_buf_cnt++; @@ -279,7 +281,7 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id) unsigned long flags; spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); - __skb_queue_purge(&hif_dev->tx.tx_skb_queue); + ath9k_skb_queue_purge(&hif_dev->tx.tx_skb_queue); hif_dev->tx.tx_skb_cnt = 0; hif_dev->tx.flags |= HIF_USB_TX_STOP; spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); @@ -299,6 +301,8 @@ static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb, ret = hif_usb_send_regout(hif_dev, skb); break; default: + dev_err(&hif_dev->udev->dev, + "ath9k_htc: Invalid TX pipe: %d\n", pipe_id); ret = -EINVAL; break; } @@ -321,12 +325,14 @@ static struct ath9k_htc_hif hif_usb = { static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, struct sk_buff *skb) { - struct sk_buff *nskb, *skb_pool[8]; + struct sk_buff *nskb, *skb_pool[MAX_PKT_NUM_IN_TRANSFER]; int index = 0, i = 0, chk_idx, len = skb->len; int rx_remain_len = 0, rx_pkt_len = 0; u16 pkt_len, pkt_tag, pool_index = 0; u8 *ptr; + spin_lock(&hif_dev->rx_lock); + rx_remain_len = hif_dev->rx_remain_len; rx_pkt_len = hif_dev->rx_transfer_len; @@ -353,6 +359,8 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, } } + spin_unlock(&hif_dev->rx_lock); + while (index < len) { ptr = (u8 *) skb->data; @@ -370,6 +378,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, index = index + 4 + pkt_len + pad_len; if (index > MAX_RX_BUF_SIZE) { + spin_lock(&hif_dev->rx_lock); hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE; hif_dev->rx_transfer_len = MAX_RX_BUF_SIZE - chk_idx - 4; @@ -381,6 +390,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, dev_err(&hif_dev->udev->dev, "ath9k_htc: RX memory allocation" " error\n"); + spin_unlock(&hif_dev->rx_lock); goto err; } skb_reserve(nskb, 32); @@ -391,6 +401,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, /* Record the buffer pointer */ hif_dev->remain_skb = nskb; + spin_unlock(&hif_dev->rx_lock); } else { nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC); if (!nskb) { @@ -408,14 +419,11 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, } } else { RX_STAT_INC(skb_dropped); - dev_kfree_skb_any(skb); return; } } err: - dev_kfree_skb_any(skb); - for (i = 0; i < pool_index; i++) { ath9k_htc_rx_msg(hif_dev->htc_handle, skb_pool[i], skb_pool[i]->len, USB_WLAN_RX_PIPE); @@ -426,11 +434,13 @@ err: static void ath9k_hif_usb_rx_cb(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; - struct sk_buff *nskb; struct hif_device_usb *hif_dev = (struct hif_device_usb *) usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); int ret; + if (!skb) + return; + if (!hif_dev) goto free; @@ -448,38 +458,23 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) if (likely(urb->actual_length != 0)) { skb_put(skb, urb->actual_length); - - nskb = __dev_alloc_skb(MAX_RX_BUF_SIZE, GFP_ATOMIC); - if (!nskb) - goto resubmit; - - usb_fill_bulk_urb(urb, hif_dev->udev, - usb_rcvbulkpipe(hif_dev->udev, - USB_WLAN_RX_PIPE), - nskb->data, MAX_RX_BUF_SIZE, - ath9k_hif_usb_rx_cb, nskb); - - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - dev_kfree_skb_any(nskb); - goto free; - } - ath9k_hif_usb_rx_stream(hif_dev, skb); - return; } resubmit: skb_reset_tail_pointer(skb); skb_trim(skb, 0); + usb_anchor_urb(urb, &hif_dev->rx_submitted); ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) + if (ret) { + usb_unanchor_urb(urb); goto free; + } return; free: - dev_kfree_skb_any(skb); + kfree_skb(skb); } static void ath9k_hif_usb_reg_in_cb(struct urb *urb) @@ -490,6 +485,9 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); int ret; + if (!skb) + return; + if (!hif_dev) goto free; @@ -508,7 +506,7 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) if (likely(urb->actual_length != 0)) { skb_put(skb, urb->actual_length); - nskb = __dev_alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_ATOMIC); + nskb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_ATOMIC); if (!nskb) goto resubmit; @@ -519,7 +517,7 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret) { - dev_kfree_skb_any(nskb); + kfree_skb(nskb); goto free; } @@ -539,7 +537,8 @@ resubmit: return; free: - dev_kfree_skb_any(skb); + kfree_skb(skb); + urb->context = NULL; } static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) @@ -609,78 +608,66 @@ err: return -ENOMEM; } -static void ath9k_hif_usb_dealloc_rx_skbs(struct hif_device_usb *hif_dev) -{ - int i; - - for (i = 0; i < MAX_RX_URB_NUM; i++) { - if (hif_dev->wlan_rx_data_urb[i]) { - if (hif_dev->wlan_rx_data_urb[i]->transfer_buffer) - dev_kfree_skb_any((void *) - hif_dev->wlan_rx_data_urb[i]->context); - } - } -} - static void ath9k_hif_usb_dealloc_rx_urbs(struct hif_device_usb *hif_dev) { - int i; - - for (i = 0; i < MAX_RX_URB_NUM; i++) { - if (hif_dev->wlan_rx_data_urb[i]) { - usb_kill_urb(hif_dev->wlan_rx_data_urb[i]); - usb_free_urb(hif_dev->wlan_rx_data_urb[i]); - hif_dev->wlan_rx_data_urb[i] = NULL; - } - } -} - -static int ath9k_hif_usb_prep_rx_urb(struct hif_device_usb *hif_dev, - struct urb *urb) -{ - struct sk_buff *skb; - - skb = __dev_alloc_skb(MAX_RX_BUF_SIZE, GFP_KERNEL); - if (!skb) - return -ENOMEM; - - usb_fill_bulk_urb(urb, hif_dev->udev, - usb_rcvbulkpipe(hif_dev->udev, USB_WLAN_RX_PIPE), - skb->data, MAX_RX_BUF_SIZE, - ath9k_hif_usb_rx_cb, skb); - return 0; + usb_kill_anchored_urbs(&hif_dev->rx_submitted); } static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev) { + struct urb *urb = NULL; + struct sk_buff *skb = NULL; int i, ret; + init_usb_anchor(&hif_dev->rx_submitted); + spin_lock_init(&hif_dev->rx_lock); + for (i = 0; i < MAX_RX_URB_NUM; i++) { /* Allocate URB */ - hif_dev->wlan_rx_data_urb[i] = usb_alloc_urb(0, GFP_KERNEL); - if (hif_dev->wlan_rx_data_urb[i] == NULL) { + urb = usb_alloc_urb(0, GFP_KERNEL); + if (urb == NULL) { ret = -ENOMEM; - goto err_rx_urb; + goto err_urb; } /* Allocate buffer */ - ret = ath9k_hif_usb_prep_rx_urb(hif_dev, - hif_dev->wlan_rx_data_urb[i]); - if (ret) - goto err_rx_urb; + skb = alloc_skb(MAX_RX_BUF_SIZE, GFP_KERNEL); + if (!skb) { + ret = -ENOMEM; + goto err_skb; + } + + usb_fill_bulk_urb(urb, hif_dev->udev, + usb_rcvbulkpipe(hif_dev->udev, + USB_WLAN_RX_PIPE), + skb->data, MAX_RX_BUF_SIZE, + ath9k_hif_usb_rx_cb, skb); + + /* Anchor URB */ + usb_anchor_urb(urb, &hif_dev->rx_submitted); /* Submit URB */ - ret = usb_submit_urb(hif_dev->wlan_rx_data_urb[i], GFP_KERNEL); - if (ret) - goto err_rx_urb; + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret) { + usb_unanchor_urb(urb); + goto err_submit; + } + /* + * Drop reference count. + * This ensures that the URB is freed when killing them. + */ + usb_free_urb(urb); } return 0; -err_rx_urb: - ath9k_hif_usb_dealloc_rx_skbs(hif_dev); +err_submit: + kfree_skb(skb); +err_skb: + usb_free_urb(urb); +err_urb: ath9k_hif_usb_dealloc_rx_urbs(hif_dev); return ret; } @@ -689,6 +676,8 @@ static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev) { if (hif_dev->reg_in_urb) { usb_kill_urb(hif_dev->reg_in_urb); + if (hif_dev->reg_in_urb->context) + kfree_skb((void *)hif_dev->reg_in_urb->context); usb_free_urb(hif_dev->reg_in_urb); hif_dev->reg_in_urb = NULL; } @@ -702,7 +691,7 @@ static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev) if (hif_dev->reg_in_urb == NULL) return -ENOMEM; - skb = __dev_alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL); + skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL); if (!skb) goto err; @@ -712,12 +701,10 @@ static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev) ath9k_hif_usb_reg_in_cb, skb, 1); if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0) - goto err_skb; + goto err; return 0; -err_skb: - dev_kfree_skb_any(skb); err: ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); return -ENOMEM; @@ -725,6 +712,9 @@ err: static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev) { + /* Register Write */ + init_usb_anchor(&hif_dev->regout_submitted); + /* TX */ if (ath9k_hif_usb_alloc_tx_urbs(hif_dev) < 0) goto err; @@ -733,7 +723,7 @@ static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev) if (ath9k_hif_usb_alloc_rx_urbs(hif_dev) < 0) goto err; - /* Register Read/Write */ + /* Register Read */ if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0) goto err; @@ -830,6 +820,7 @@ err_fw_req: static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev) { + usb_kill_anchored_urbs(&hif_dev->regout_submitted); ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); ath9k_hif_usb_dealloc_tx_urbs(hif_dev); ath9k_hif_usb_dealloc_rx_urbs(hif_dev); diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index 7cc3762a6789..7d49a8af420e 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -34,6 +34,7 @@ #define MAX_RX_URB_NUM 8 #define MAX_RX_BUF_SIZE 16384 +#define MAX_PKT_NUM_IN_TRANSFER 10 #define MAX_REG_OUT_URB_NUM 1 #define MAX_REG_OUT_BUF_NUM 8 @@ -85,18 +86,17 @@ struct hif_device_usb { struct usb_interface *interface; const struct firmware *firmware; struct htc_target *htc_handle; - u8 flags; - struct hif_usb_tx tx; - - struct urb *wlan_rx_data_urb[MAX_RX_URB_NUM]; struct urb *reg_in_urb; - + struct usb_anchor regout_submitted; + struct usb_anchor rx_submitted; struct sk_buff *remain_skb; int rx_remain_len; int rx_pkt_len; int rx_transfer_len; int rx_pad_len; + spinlock_t rx_lock; + u8 flags; /* HIF_USB_* */ }; int ath9k_hif_usb_init(void); diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 777064945fca..78213fc71b09 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -309,6 +309,14 @@ struct ath_led { int brightness; }; +struct htc_beacon_config { + u16 beacon_interval; + u16 listen_interval; + u16 dtim_period; + u16 bmiss_timeout; + u8 dtim_count; +}; + #define OP_INVALID BIT(0) #define OP_SCANNING BIT(1) #define OP_FULL_RESET BIT(2) @@ -349,7 +357,11 @@ struct ath9k_htc_priv { struct sk_buff *beacon; spinlock_t beacon_lock; + bool tx_queues_stop; + spinlock_t tx_lock; + struct ieee80211_vif *vif; + struct htc_beacon_config cur_beacon_conf; unsigned int rxfilter; struct tasklet_struct wmi_tasklet; struct tasklet_struct rx_tasklet; @@ -360,6 +372,11 @@ struct ath9k_htc_priv { struct ath9k_htc_aggr_work aggr_work; struct delayed_work ath9k_aggr_work; struct delayed_work ath9k_ani_work; + struct work_struct ps_work; + + struct mutex htc_pm_lock; + unsigned long ps_usecount; + bool ps_enabled; struct ath_led radio_led; struct ath_led assoc_led; @@ -386,8 +403,7 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz) } void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf); + struct ieee80211_vif *vif); void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending); void ath9k_htc_beacon_update(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif); @@ -415,6 +431,11 @@ int ath9k_rx_init(struct ath9k_htc_priv *priv); void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); void ath9k_host_rx_init(struct ath9k_htc_priv *priv); void ath9k_rx_tasklet(unsigned long data); +u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv); + +void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv); +void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv); +void ath9k_ps_work(struct work_struct *work); void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv); void ath9k_init_leds(struct ath9k_htc_priv *priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 25f5b5377bac..5e21f4d92ff5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -19,7 +19,7 @@ #define FUDGE 2 static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, - struct ieee80211_bss_conf *bss_conf) + struct htc_beacon_config *bss_conf) { struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_beacon_state bs; @@ -34,8 +34,8 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, memset(&bs, 0, sizeof(bs)); - intval = bss_conf->beacon_int & ATH9K_BEACON_PERIOD; - bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_int); + intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD; + bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval); /* * Setup dtim and cfp parameters according to @@ -138,7 +138,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, } static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, - struct ieee80211_bss_conf *bss_conf) + struct htc_beacon_config *bss_conf) { struct ath_common *common = ath9k_hw_common(priv->ah); enum ath9k_int imask = 0; @@ -146,7 +146,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, int ret; u8 cmd_rsp; - intval = bss_conf->beacon_int & ATH9K_BEACON_PERIOD; + intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD; nexttbtt = intval; intval |= ATH9K_BEACON_ENA; if (priv->op_flags & OP_ENABLE_BEACON) @@ -154,7 +154,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, ath_print(common, ATH_DBG_BEACON, "IBSS Beacon config, intval: %d, imask: 0x%x\n", - bss_conf->beacon_int, imask); + bss_conf->beacon_interval, imask); WMI_CMD(WMI_DISABLE_INTR_CMDID); ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); @@ -239,18 +239,35 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending) spin_unlock_bh(&priv->beacon_lock); } + void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf) + struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(priv->ah); - - switch (vif->type) { + enum nl80211_iftype iftype; + struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + + if (vif) { + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + iftype = vif->type; + cur_conf->beacon_interval = bss_conf->beacon_int; + cur_conf->dtim_period = bss_conf->dtim_period; + cur_conf->listen_interval = 1; + cur_conf->dtim_count = 1; + cur_conf->bmiss_timeout = + ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; + } else + iftype = priv->ah->opmode; + + if (cur_conf->beacon_interval == 0) + cur_conf->beacon_interval = 100; + + switch (iftype) { case NL80211_IFTYPE_STATION: - ath9k_htc_beacon_config_sta(priv, bss_conf); + ath9k_htc_beacon_config_sta(priv, cur_conf); break; case NL80211_IFTYPE_ADHOC: - ath9k_htc_beacon_config_adhoc(priv, bss_conf); + ath9k_htc_beacon_config_adhoc(priv, cur_conf); break; default: ath_print(common, ATH_DBG_CONFIG, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 10c87605d2c4..aed53573c547 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -287,6 +287,7 @@ static bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data) } static const struct ath_bus_ops ath9k_usb_bus_ops = { + .ath_bus_type = ATH_USB, .read_cachesize = ath_usb_read_cachesize, .eeprom_read = ath_usb_eeprom_read, }; @@ -421,6 +422,7 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv) memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); priv->op_flags |= OP_TXAGGR; + priv->ah->opmode = NL80211_IFTYPE_STATION; } static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid) @@ -449,8 +451,10 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid) spin_lock_init(&priv->wmi->wmi_lock); spin_lock_init(&priv->beacon_lock); + spin_lock_init(&priv->tx_lock); mutex_init(&priv->mutex); mutex_init(&priv->aggr_work.mutex); + mutex_init(&priv->htc_pm_lock); tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet, (unsigned long)priv); tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, @@ -458,6 +462,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid) tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv); INIT_DELAYED_WORK(&priv->ath9k_aggr_work, ath9k_htc_aggr_work); INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work); + INIT_WORK(&priv->ps_work, ath9k_ps_work); /* * Cache line size is used to size and align various @@ -511,12 +516,17 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_HAS_RATE_CONTROL; + IEEE80211_HW_HAS_RATE_CONTROL | + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + 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 20a2c1341e20..eb7722b2cfcc 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -65,6 +65,56 @@ static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv, return mode; } +static bool ath9k_htc_setpower(struct ath9k_htc_priv *priv, + enum ath9k_power_mode mode) +{ + bool ret; + + mutex_lock(&priv->htc_pm_lock); + ret = ath9k_hw_setpower(priv->ah, mode); + mutex_unlock(&priv->htc_pm_lock); + + return ret; +} + +void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv) +{ + mutex_lock(&priv->htc_pm_lock); + if (++priv->ps_usecount != 1) + goto unlock; + ath9k_hw_setpower(priv->ah, ATH9K_PM_AWAKE); + +unlock: + mutex_unlock(&priv->htc_pm_lock); +} + +void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv) +{ + mutex_lock(&priv->htc_pm_lock); + if (--priv->ps_usecount != 0) + goto unlock; + + if (priv->ps_enabled) + ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP); +unlock: + mutex_unlock(&priv->htc_pm_lock); +} + +void ath9k_ps_work(struct work_struct *work) +{ + struct ath9k_htc_priv *priv = + container_of(work, struct ath9k_htc_priv, + ps_work); + ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); + + /* The chip wakes up after receiving the first beacon + while network sleep is enabled. For the driver to + be in sync with the hw, set the chip to awake and + only then set it to sleep. + */ + ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); +} + static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, struct ieee80211_hw *hw, struct ath9k_channel *hchan) @@ -87,7 +137,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, /* Fiddle around with fastcc later on, for now just use full reset */ fastcc = false; - + ath9k_htc_ps_wakeup(priv); htc_stop(priv->htc); WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); @@ -103,6 +153,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, ath_print(common, ATH_DBG_FATAL, "Unable to reset channel (%u Mhz) " "reset status %d\n", channel->center_freq, ret); + ath9k_htc_ps_restore(priv); goto err; } @@ -128,6 +179,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, priv->op_flags &= ~OP_FULL_RESET; err: + ath9k_htc_ps_restore(priv); return ret; } @@ -412,32 +464,31 @@ static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv, if (tid > ATH9K_HTC_MAX_TID) return -EINVAL; + memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr)); + rcu_read_lock(); + + /* Check if we are able to retrieve the station */ sta = ieee80211_find_sta(vif, sta_addr); - if (sta) { - ista = (struct ath9k_htc_sta *) sta->drv_priv; - } else { + if (!sta) { rcu_read_unlock(); return -EINVAL; } - if (!ista) { - rcu_read_unlock(); - return -EINVAL; - } + ista = (struct ath9k_htc_sta *) sta->drv_priv; - memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr)); + if (oper) + ista->tid_state[tid] = AGGR_START; + else + ista->tid_state[tid] = AGGR_STOP; aggr.sta_index = ista->index; + rcu_read_unlock(); + aggr.tidno = tid; aggr.aggr_enable = oper; - if (oper) - ista->tid_state[tid] = AGGR_START; - else - ista->tid_state[tid] = AGGR_STOP; - WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr); if (ret) ath_print(common, ATH_DBG_CONFIG, @@ -694,6 +745,10 @@ void ath9k_ani_work(struct work_struct *work) short_cal_interval = ATH_STA_SHORT_CALINTERVAL; + /* Only calibrate if awake */ + if (ah->power_mode != ATH9K_PM_AWAKE) + goto set_timer; + /* Long calibration runs independently of short calibration. */ if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { longcal = true; @@ -728,6 +783,9 @@ void ath9k_ani_work(struct work_struct *work) /* Skip all processing if there's nothing to do. */ if (longcal || shortcal || aniflag) { + + ath9k_htc_ps_wakeup(priv); + /* Call ANI routine if necessary */ if (aniflag) ath9k_hw_ani_monitor(ah, ah->curchan); @@ -749,8 +807,11 @@ void ath9k_ani_work(struct work_struct *work) ah->curchan->channelFlags, common->ani.noise_floor); } + + ath9k_htc_ps_restore(priv); } +set_timer: /* * Set timer interval based on previous results. * The interval must be the shortest necessary to satisfy ANI, @@ -995,7 +1056,7 @@ static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_hdr *hdr; struct ath9k_htc_priv *priv = hw->priv; - int padpos, padsize; + int padpos, padsize, ret; hdr = (struct ieee80211_hdr *) skb->data; @@ -1009,8 +1070,19 @@ static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) memmove(skb->data, skb->data + padsize, padpos); } - if (ath9k_htc_tx_start(priv, skb) != 0) { - ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, "Tx failed"); + ret = ath9k_htc_tx_start(priv, skb); + if (ret != 0) { + if (ret == -ENOMEM) { + ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, + "Stopping TX queues\n"); + ieee80211_stop_queues(hw); + spin_lock_bh(&priv->tx_lock); + priv->tx_queues_stop = true; + spin_unlock_bh(&priv->tx_lock); + } else { + ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, + "Tx failed"); + } goto fail_tx; } @@ -1075,6 +1147,12 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) priv->op_flags &= ~OP_INVALID; htc_start(priv->htc); + spin_lock_bh(&priv->tx_lock); + priv->tx_queues_stop = false; + spin_unlock_bh(&priv->tx_lock); + + ieee80211_wake_queues(hw); + mutex_unlock: mutex_unlock(&priv->mutex); return ret; @@ -1096,6 +1174,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) return; } + ath9k_htc_ps_wakeup(priv); htc_stop(priv->htc); WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); @@ -1103,8 +1182,10 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) ath9k_hw_phy_disable(ah); ath9k_hw_disable(ah); ath9k_hw_configpcipowersave(ah, 1, 1); - ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); + ath9k_htc_ps_restore(priv); + ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); + cancel_work_sync(&priv->ps_work); cancel_delayed_work_sync(&priv->ath9k_ani_work); cancel_delayed_work_sync(&priv->ath9k_aggr_work); cancel_delayed_work_sync(&priv->ath9k_led_blink_work); @@ -1145,6 +1226,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, goto out; } + ath9k_htc_ps_wakeup(priv); memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); @@ -1191,6 +1273,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, priv->vif = vif; out: + ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); return ret; } @@ -1259,6 +1342,16 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) } } + if (changed & IEEE80211_CONF_CHANGE_PS) { + if (conf->flags & IEEE80211_CONF_PS) { + ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); + priv->ps_enabled = true; + } else { + priv->ps_enabled = false; + cancel_work_sync(&priv->ps_work); + ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); + } + } if (changed & IEEE80211_CONF_CHANGE_MONITOR) { if (conf->flags & IEEE80211_CONF_MONITOR) { @@ -1295,16 +1388,18 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); + ath9k_htc_ps_wakeup(priv); changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; priv->rxfilter = *total_flags; - rfilt = ath9k_cmn_calcrxfilter(hw, priv->ah, priv->rxfilter); + rfilt = ath9k_htc_calcrxfilter(priv); ath9k_hw_setrxfilter(priv->ah, rfilt); ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", rfilt); + ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); } @@ -1382,6 +1477,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n"); + ath9k_htc_ps_wakeup(priv); switch (cmd) { case SET_KEY: @@ -1404,6 +1500,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw, ret = -EINVAL; } + ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); return ret; @@ -1419,6 +1516,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, struct ath_common *common = ath9k_hw_common(ah); mutex_lock(&priv->mutex); + ath9k_htc_ps_wakeup(priv); if (changed & BSS_CHANGED_ASSOC) { common->curaid = bss_conf->assoc ? @@ -1431,6 +1529,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ath_start_ani(priv); } else { priv->op_flags &= ~OP_ASSOCIATED; + cancel_work_sync(&priv->ps_work); cancel_delayed_work_sync(&priv->ath9k_ani_work); } } @@ -1450,7 +1549,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) { priv->op_flags |= OP_ENABLE_BEACON; - ath9k_htc_beacon_config(priv, vif, bss_conf); + ath9k_htc_beacon_config(priv, vif); } if (changed & BSS_CHANGED_BEACON) @@ -1459,7 +1558,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) { priv->op_flags &= ~OP_ENABLE_BEACON; - ath9k_htc_beacon_config(priv, vif, bss_conf); + ath9k_htc_beacon_config(priv, vif); } if (changed & BSS_CHANGED_ERP_PREAMBLE) { @@ -1490,6 +1589,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ath9k_hw_init_global_settings(ah); } + ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); } @@ -1518,9 +1618,11 @@ static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw) { struct ath9k_htc_priv *priv = hw->priv; + ath9k_htc_ps_wakeup(priv); mutex_lock(&priv->mutex); ath9k_hw_reset_tsf(priv->ah); mutex_unlock(&priv->mutex); + ath9k_htc_ps_restore(priv); } static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, @@ -1569,6 +1671,7 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) spin_lock_bh(&priv->beacon_lock); priv->op_flags |= OP_SCANNING; spin_unlock_bh(&priv->beacon_lock); + cancel_work_sync(&priv->ps_work); cancel_delayed_work_sync(&priv->ath9k_ani_work); mutex_unlock(&priv->mutex); } @@ -1577,13 +1680,17 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) { struct ath9k_htc_priv *priv = hw->priv; + ath9k_htc_ps_wakeup(priv); mutex_lock(&priv->mutex); spin_lock_bh(&priv->beacon_lock); priv->op_flags &= ~OP_SCANNING; spin_unlock_bh(&priv->beacon_lock); priv->op_flags |= OP_FULL_RESET; + if (priv->op_flags & OP_ASSOCIATED) + ath9k_htc_beacon_config(priv, NULL); ath_start_ani(priv); mutex_unlock(&priv->mutex); + ath9k_htc_ps_restore(priv); } static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index ac66cf0b2d53..0a7cb30af5b4 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -188,10 +188,20 @@ void ath9k_tx_tasklet(unsigned long data) hdr = (struct ieee80211_hdr *) skb->data; fc = hdr->frame_control; tx_info = IEEE80211_SKB_CB(skb); - sta = tx_info->control.sta; + + memset(&tx_info->status, 0, sizeof(tx_info->status)); rcu_read_lock(); + sta = ieee80211_find_sta(priv->vif, hdr->addr1); + if (!sta) { + rcu_read_unlock(); + ieee80211_tx_status(priv->hw, skb); + continue; + } + + /* Check if we need to start aggregation */ + if (sta && conf_is_ht(&priv->hw->conf) && (priv->op_flags & OP_TXAGGR) && !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { @@ -213,9 +223,21 @@ void ath9k_tx_tasklet(unsigned long data) rcu_read_unlock(); - memset(&tx_info->status, 0, sizeof(tx_info->status)); + /* Send status to mac80211 */ ieee80211_tx_status(priv->hw, skb); } + + /* Wake TX queues if needed */ + spin_lock_bh(&priv->tx_lock); + if (priv->tx_queues_stop) { + priv->tx_queues_stop = false; + spin_unlock_bh(&priv->tx_lock); + ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, + "Waking up TX queues\n"); + ieee80211_wake_queues(priv->hw); + return; + } + spin_unlock_bh(&priv->tx_lock); } void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, @@ -290,10 +312,84 @@ bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, /* RX */ /******/ +/* + * Calculate the RX filter to be set in the HW. + */ +u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) +{ +#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) + + struct ath_hw *ah = priv->ah; + u32 rfilt; + + rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE) + | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST + | ATH9K_RX_FILTER_MCAST; + + /* If not a STA, enable processing of Probe Requests */ + if (ah->opmode != NL80211_IFTYPE_STATION) + rfilt |= ATH9K_RX_FILTER_PROBEREQ; + + /* + * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station + * mode interface or when in monitor mode. AP mode does not need this + * since it receives all in-BSS frames anyway. + */ + if (((ah->opmode != NL80211_IFTYPE_AP) && + (priv->rxfilter & FIF_PROMISC_IN_BSS)) || + (ah->opmode == NL80211_IFTYPE_MONITOR)) + rfilt |= ATH9K_RX_FILTER_PROM; + + if (priv->rxfilter & FIF_CONTROL) + rfilt |= ATH9K_RX_FILTER_CONTROL; + + if ((ah->opmode == NL80211_IFTYPE_STATION) && + !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC)) + rfilt |= ATH9K_RX_FILTER_MYBEACON; + else + rfilt |= ATH9K_RX_FILTER_BEACON; + + if (conf_is_ht(&priv->hw->conf)) + rfilt |= ATH9K_RX_FILTER_COMP_BAR; + + return rfilt; + +#undef RX_FILTER_PRESERVE +} + +/* + * Recv initialization for opmode change. + */ +static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv) +{ + struct ath_hw *ah = priv->ah; + struct ath_common *common = ath9k_hw_common(ah); + + u32 rfilt, mfilt[2]; + + /* configure rx filter */ + rfilt = ath9k_htc_calcrxfilter(priv); + ath9k_hw_setrxfilter(ah, rfilt); + + /* configure bssid mask */ + if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + ath_hw_setbssidmask(common); + + /* configure operational mode */ + ath9k_hw_setopmode(ah); + + /* Handle any link-level address change. */ + ath9k_hw_setmac(ah, common->macaddr); + + /* calculate and install multicast filter */ + mfilt[0] = mfilt[1] = ~0; + ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); +} + void ath9k_host_rx_init(struct ath9k_htc_priv *priv) { ath9k_hw_rxena(priv->ah); - ath9k_cmn_opmode_init(priv->hw, priv->ah, priv->rxfilter); + ath9k_htc_opmode_init(priv); ath9k_hw_startpcureceive(priv->ah); priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER; } @@ -354,7 +450,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, padpos = ath9k_cmn_padpos(fc); padsize = padpos & 3; - if (padsize && skb->len >= padpos+padsize) { + if (padsize && skb->len >= padpos+padsize+FCS_LEN) { memmove(skb->data + padsize, skb->data, padpos); skb_pull(skb, padsize); } @@ -457,7 +553,7 @@ void ath9k_rx_tasklet(unsigned long data) struct ieee80211_rx_status rx_status; struct sk_buff *skb; unsigned long flags; - + struct ieee80211_hdr *hdr; do { spin_lock_irqsave(&priv->rx.rxbuflock, flags); @@ -484,6 +580,11 @@ void ath9k_rx_tasklet(unsigned long data) memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status, sizeof(struct ieee80211_rx_status)); skb = rxbuf->skb; + hdr = (struct ieee80211_hdr *) skb->data; + + if (ieee80211_is_beacon(hdr->frame_control) && priv->ps_enabled) + ieee80211_queue_work(priv->hw, &priv->ps_work); + spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); ieee80211_rx(priv->hw, skb); @@ -550,7 +651,6 @@ void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb, spin_lock(&priv->rx.rxbuflock); memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); - skb->len = rxstatus->rs_datalen; rxbuf->skb = skb; rxbuf->in_process = true; spin_unlock(&priv->rx.rxbuflock); diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 9a48999d0979..587d98ed0989 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -146,7 +146,7 @@ static int htc_config_pipe_credits(struct htc_target *target) struct htc_config_pipe_msg *cp_msg; int ret, time_left; - skb = dev_alloc_skb(50 + sizeof(struct htc_frame_hdr)); + skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC); if (!skb) { dev_err(target->dev, "failed to allocate send buffer\n"); return -ENOMEM; @@ -174,7 +174,7 @@ static int htc_config_pipe_credits(struct htc_target *target) return 0; err: - dev_kfree_skb(skb); + kfree_skb(skb); return -EINVAL; } @@ -184,7 +184,7 @@ static int htc_setup_complete(struct htc_target *target) struct htc_comp_msg *comp_msg; int ret = 0, time_left; - skb = dev_alloc_skb(50 + sizeof(struct htc_frame_hdr)); + skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC); if (!skb) { dev_err(target->dev, "failed to allocate send buffer\n"); return -ENOMEM; @@ -210,7 +210,7 @@ static int htc_setup_complete(struct htc_target *target) return 0; err: - dev_kfree_skb(skb); + kfree_skb(skb); return -EINVAL; } @@ -250,8 +250,8 @@ int htc_connect_service(struct htc_target *target, endpoint->dl_pipeid = service_to_dlpipe(service_connreq->service_id); endpoint->ep_callbacks = service_connreq->ep_callbacks; - skb = dev_alloc_skb(sizeof(struct htc_conn_svc_msg) + - sizeof(struct htc_frame_hdr)); + skb = alloc_skb(sizeof(struct htc_conn_svc_msg) + + sizeof(struct htc_frame_hdr), GFP_ATOMIC); if (!skb) { dev_err(target->dev, "Failed to allocate buf to send" "service connect req\n"); @@ -282,7 +282,7 @@ int htc_connect_service(struct htc_target *target, *conn_rsp_epid = target->conn_rsp_epid; return 0; err: - dev_kfree_skb(skb); + kfree_skb(skb); return ret; } @@ -321,16 +321,18 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, struct sk_buff *skb, bool txok) { struct htc_endpoint *endpoint; - struct htc_frame_hdr *htc_hdr; + struct htc_frame_hdr *htc_hdr = NULL; if (htc_handle->htc_flags & HTC_OP_CONFIG_PIPE_CREDITS) { complete(&htc_handle->cmd_wait); htc_handle->htc_flags &= ~HTC_OP_CONFIG_PIPE_CREDITS; + goto ret; } if (htc_handle->htc_flags & HTC_OP_START_WAIT) { complete(&htc_handle->cmd_wait); htc_handle->htc_flags &= ~HTC_OP_START_WAIT; + goto ret; } if (skb) { @@ -343,6 +345,14 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, htc_hdr->endpoint_id, txok); } } + + return; +ret: + /* HTC-generated packets are freed here. */ + if (htc_hdr && htc_hdr->endpoint_id != ENDPOINT0) + dev_kfree_skb_any(skb); + else + kfree_skb(skb); } /* @@ -367,7 +377,10 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle, epid = htc_hdr->endpoint_id; if (epid >= ENDPOINT_MAX) { - dev_kfree_skb_any(skb); + if (pipe_id != USB_REG_IN_PIPE) + dev_kfree_skb_any(skb); + else + kfree_skb(skb); return; } @@ -377,7 +390,7 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle, if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) { if (be32_to_cpu(*(u32 *) skb->data) == 0x00C60000) /* Move past the Watchdog pattern */ - htc_hdr = (struct htc_frame_hdr *) skb->data + 4; + htc_hdr = (struct htc_frame_hdr *)(skb->data + 4); } /* Get the message ID */ @@ -396,7 +409,7 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle, break; } - dev_kfree_skb_any(skb); + kfree_skb(skb); } else { if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 7fdaea3a1629..af730c7d50e6 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -28,9 +28,6 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type); static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan); -static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, - struct ar5416_eeprom_def *pEepData, - u32 reg, u32 value); MODULE_AUTHOR("Atheros Communications"); MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); @@ -548,7 +545,6 @@ static bool ath9k_hw_devid_supported(u16 devid) case AR9285_DEVID_PCIE: case AR5416_DEVID_AR9287_PCI: case AR5416_DEVID_AR9287_PCIE: - case AR9271_USB: case AR2427_DEVID_PCIE: return true; default: @@ -817,38 +813,46 @@ static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah) /* txgain table */ if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) { - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9285Modes_high_power_tx_gain_9285_1_2, - ARRAY_SIZE(ar9285Modes_high_power_tx_gain_9285_1_2), 6); + if (AR_SREV_9285E_20(ah)) { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9285Modes_XE2_0_high_power, + ARRAY_SIZE( + ar9285Modes_XE2_0_high_power), 6); + } else { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9285Modes_high_power_tx_gain_9285_1_2, + ARRAY_SIZE( + ar9285Modes_high_power_tx_gain_9285_1_2), 6); + } } else { - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9285Modes_original_tx_gain_9285_1_2, - ARRAY_SIZE(ar9285Modes_original_tx_gain_9285_1_2), 6); + if (AR_SREV_9285E_20(ah)) { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9285Modes_XE2_0_normal_power, + ARRAY_SIZE( + ar9285Modes_XE2_0_normal_power), 6); + } else { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9285Modes_original_tx_gain_9285_1_2, + ARRAY_SIZE( + ar9285Modes_original_tx_gain_9285_1_2), 6); + } } - } } static void ath9k_hw_init_eeprom_fix(struct ath_hw *ah) { - u32 i, j; - - if (ah->hw_version.devid == AR9280_DEVID_PCI) { - - /* EEPROM Fixup */ - for (i = 0; i < ah->iniModes.ia_rows; i++) { - u32 reg = INI_RA(&ah->iniModes, i, 0); + struct base_eep_header *pBase = &(ah->eeprom.def.baseEepHeader); + struct ath_common *common = ath9k_hw_common(ah); - for (j = 1; j < ah->iniModes.ia_columns; j++) { - u32 val = INI_RA(&ah->iniModes, i, j); + ah->need_an_top2_fixup = (ah->hw_version.devid == AR9280_DEVID_PCI) && + (ah->eep_map != EEP_MAP_4KBITS) && + ((pBase->version & 0xff) > 0x0a) && + (pBase->pwdclkind == 0); - INI_RA(&ah->iniModes, i, j) = - ath9k_hw_ini_fixup(ah, - &ah->eeprom.def, - reg, val); - } - } - } + if (ah->need_an_top2_fixup) + ath_print(common, ATH_DBG_EEPROM, + "needs fixup for AR_AN_TOP2 register\n"); } int ath9k_hw_init(struct ath_hw *ah) @@ -856,11 +860,13 @@ int ath9k_hw_init(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); int r = 0; - if (!ath9k_hw_devid_supported(ah->hw_version.devid)) { - ath_print(common, ATH_DBG_FATAL, - "Unsupported device ID: 0x%0x\n", - ah->hw_version.devid); - return -EOPNOTSUPP; + if (common->bus_ops->ath_bus_type != ATH_USB) { + if (!ath9k_hw_devid_supported(ah->hw_version.devid)) { + ath_print(common, ATH_DBG_FATAL, + "Unsupported device ID: 0x%0x\n", + ah->hw_version.devid); + return -EOPNOTSUPP; + } } ath9k_hw_init_defaults(ah); @@ -1121,23 +1127,23 @@ static void ath9k_hw_init_chain_masks(struct ath_hw *ah) static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, enum nl80211_iftype opmode) { - ah->mask_reg = AR_IMR_TXERR | + u32 imr_reg = AR_IMR_TXERR | AR_IMR_TXURN | AR_IMR_RXERR | AR_IMR_RXORN | AR_IMR_BCNMISC; if (ah->config.rx_intr_mitigation) - ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; + imr_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; else - ah->mask_reg |= AR_IMR_RXOK; + imr_reg |= AR_IMR_RXOK; - ah->mask_reg |= AR_IMR_TXOK; + imr_reg |= AR_IMR_TXOK; if (opmode == NL80211_IFTYPE_AP) - ah->mask_reg |= AR_IMR_MIB; + imr_reg |= AR_IMR_MIB; - REG_WRITE(ah, AR_IMR, ah->mask_reg); + REG_WRITE(ah, AR_IMR, imr_reg); ah->imrs2_reg |= AR_IMR_S2_GTT; REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg); @@ -1290,51 +1296,6 @@ static void ath9k_hw_override_ini(struct ath_hw *ah, } } -static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah, - struct ar5416_eeprom_def *pEepData, - u32 reg, u32 value) -{ - struct base_eep_header *pBase = &(pEepData->baseEepHeader); - struct ath_common *common = ath9k_hw_common(ah); - - switch (ah->hw_version.devid) { - case AR9280_DEVID_PCI: - if (reg == 0x7894) { - ath_print(common, ATH_DBG_EEPROM, - "ini VAL: %x EEPROM: %x\n", value, - (pBase->version & 0xff)); - - if ((pBase->version & 0xff) > 0x0a) { - ath_print(common, ATH_DBG_EEPROM, - "PWDCLKIND: %d\n", - pBase->pwdclkind); - value &= ~AR_AN_TOP2_PWDCLKIND; - value |= AR_AN_TOP2_PWDCLKIND & - (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S); - } else { - ath_print(common, ATH_DBG_EEPROM, - "PWDCLKIND Earlier Rev\n"); - } - - ath_print(common, ATH_DBG_EEPROM, - "final ini VAL: %x\n", value); - } - break; - } - - return value; -} - -static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, - struct ar5416_eeprom_def *pEepData, - u32 reg, u32 value) -{ - if (ah->eep_map == EEP_MAP_4KBITS) - return value; - else - return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value); -} - static void ath9k_olc_init(struct ath_hw *ah) { u32 i; @@ -1440,6 +1401,9 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, u32 reg = INI_RA(&ah->iniModes, i, 0); u32 val = INI_RA(&ah->iniModes, i, modesIndex); + if (reg == AR_AN_TOP2 && ah->need_an_top2_fixup) + val &= ~AR_AN_TOP2_PWDCLKIND; + REG_WRITE(ah, reg, val); if (reg >= 0x7800 && reg < 0x78a0 @@ -2840,7 +2804,7 @@ EXPORT_SYMBOL(ath9k_hw_getisr); enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) { - u32 omask = ah->mask_reg; + enum ath9k_int omask = ah->imask; u32 mask, mask2; struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); @@ -2912,7 +2876,6 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST); ah->imrs2_reg |= mask2; REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg); - ah->mask_reg = ints; if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { if (ints & ATH9K_INT_TIM_TIMER) @@ -3231,8 +3194,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT; } #endif - - pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; + if (AR_SREV_9271(ah)) + pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; + else + pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; if (AR_SREV_9280(ah) || AR_SREV_9285(ah)) pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 6b03e1688b22..f4821cf33b87 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -44,8 +44,6 @@ #define AR5416_AR9100_DEVID 0x000b -#define AR9271_USB 0x9271 - #define AR_SUBVENDOR_ID_NOG 0x0e11 #define AR_SUBVENDOR_ID_NEW_A 0x7065 #define AR5416_MAGIC 0x19641014 @@ -461,6 +459,7 @@ struct ath_hw { bool sw_mgmt_crypto; bool is_pciexpress; + bool need_an_top2_fixup; u16 tx_trig_level; u16 rfsilent; u32 rfkill_gpio; @@ -478,7 +477,7 @@ struct ath_hw { struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES]; int16_t curchan_rad_index; - u32 mask_reg; + enum ath9k_int imask; u32 imrs2_reg; u32 txok_interrupt_mask; u32 txerr_interrupt_mask; diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h index 177bdeb84ad7..455e9d3b3f13 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/initvals.h @@ -4184,7 +4184,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, - { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 }, { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, @@ -4198,8 +4198,8 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, - { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, - { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, @@ -4312,7 +4312,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, - { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 }, { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, @@ -4326,8 +4326,8 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, - { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, - { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, @@ -4731,17 +4731,12 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00007808, 0x54214514 }, { 0x0000780c, 0x02025830 }, { 0x00007810, 0x71c0d388 }, - { 0x00007814, 0x924934a8 }, { 0x0000781c, 0x00000000 }, { 0x00007824, 0x00d86fff }, - { 0x00007828, 0x26d2491b }, { 0x0000782c, 0x6e36d97b }, - { 0x00007830, 0xedb6d96e }, { 0x00007834, 0x71400087 }, - { 0x0000783c, 0x0001fffe }, - { 0x00007840, 0xffeb1a20 }, { 0x00007844, 0x000c0db6 }, - { 0x00007848, 0x6db61b6f }, + { 0x00007848, 0x6db6246f }, { 0x0000784c, 0x6d9b66db }, { 0x00007850, 0x6d8c6dba }, { 0x00007854, 0x00040000 }, @@ -4777,7 +4772,12 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8 }, + { 0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b }, + { 0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e }, { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 }, + { 0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe }, + { 0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20 }, { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe }, { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 }, { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 }, @@ -4813,7 +4813,12 @@ static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = { { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8 }, + { 0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b }, + { 0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e }, { 0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801 }, + { 0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe }, + { 0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20 }, { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 }, { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 }, { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 }, @@ -4825,6 +4830,86 @@ static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = { { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c }, }; +static const u_int32_t ar9285Modes_XE2_0_normal_power[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000 }, + { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8 }, + { 0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b }, + { 0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6dbae }, + { 0x00007838, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441 }, + { 0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe }, + { 0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c }, + { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 }, + { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 }, + { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 }, + { 0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, + { 0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c }, + { 0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, + { 0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c }, + { 0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, + { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c }, +}; + +static const u_int32_t ar9285Modes_XE2_0_high_power[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 }, + { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8 }, + { 0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b }, + { 0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e }, + { 0x00007838, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443 }, + { 0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe }, + { 0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c }, + { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe }, + { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 }, + { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, + { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 }, + { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, + { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 }, + { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, + { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 }, +}; + static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 7af823a1527d..4a2060e5a777 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -105,7 +105,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) if (ah->tx_trig_level >= ah->config.max_txtrig_level) return false; - omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL); + omask = ath9k_hw_set_interrupts(ah, ah->imask & ~ATH9K_INT_GLOBAL); txcfg = REG_READ(ah, AR_TXCFG); curLevel = MS(txcfg, AR_FTRIG); @@ -246,79 +246,80 @@ void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds) } EXPORT_SYMBOL(ath9k_hw_cleartxdesc); -int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds) +int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds, + struct ath_tx_status *ts) { struct ar5416_desc *ads = AR5416DESC(ds); if ((ads->ds_txstatus9 & AR_TxDone) == 0) return -EINPROGRESS; - ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum); - ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp; - ds->ds_txstat.ts_status = 0; - ds->ds_txstat.ts_flags = 0; + ts->ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum); + ts->ts_tstamp = ads->AR_SendTimestamp; + ts->ts_status = 0; + ts->ts_flags = 0; if (ads->ds_txstatus1 & AR_FrmXmitOK) - ds->ds_txstat.ts_status |= ATH9K_TX_ACKED; + ts->ts_status |= ATH9K_TX_ACKED; if (ads->ds_txstatus1 & AR_ExcessiveRetries) - ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; + ts->ts_status |= ATH9K_TXERR_XRETRY; if (ads->ds_txstatus1 & AR_Filtered) - ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT; + ts->ts_status |= ATH9K_TXERR_FILT; if (ads->ds_txstatus1 & AR_FIFOUnderrun) { - ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO; + ts->ts_status |= ATH9K_TXERR_FIFO; ath9k_hw_updatetxtriglevel(ah, true); } if (ads->ds_txstatus9 & AR_TxOpExceeded) - ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP; + ts->ts_status |= ATH9K_TXERR_XTXOP; if (ads->ds_txstatus1 & AR_TxTimerExpired) - ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED; + ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED; if (ads->ds_txstatus1 & AR_DescCfgErr) - ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR; + ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR; if (ads->ds_txstatus1 & AR_TxDataUnderrun) { - ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN; + ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN; ath9k_hw_updatetxtriglevel(ah, true); } if (ads->ds_txstatus1 & AR_TxDelimUnderrun) { - ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN; + ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN; ath9k_hw_updatetxtriglevel(ah, true); } if (ads->ds_txstatus0 & AR_TxBaStatus) { - ds->ds_txstat.ts_flags |= ATH9K_TX_BA; - ds->ds_txstat.ba_low = ads->AR_BaBitmapLow; - ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh; + ts->ts_flags |= ATH9K_TX_BA; + ts->ba_low = ads->AR_BaBitmapLow; + ts->ba_high = ads->AR_BaBitmapHigh; } - ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx); - switch (ds->ds_txstat.ts_rateindex) { + ts->ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx); + switch (ts->ts_rateindex) { case 0: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0); + ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0); break; case 1: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1); + ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1); break; case 2: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2); + ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2); break; case 3: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3); + ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3); break; } - ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined); - ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00); - ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01); - ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02); - ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10); - ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11); - ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12); - ds->ds_txstat.evm0 = ads->AR_TxEVM0; - ds->ds_txstat.evm1 = ads->AR_TxEVM1; - ds->ds_txstat.evm2 = ads->AR_TxEVM2; - ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); - ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); - ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); - ds->ds_txstat.ts_antenna = 0; + ts->ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined); + ts->ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00); + ts->ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01); + ts->ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02); + ts->ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10); + ts->ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11); + ts->ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12); + ts->evm0 = ads->AR_TxEVM0; + ts->evm1 = ads->AR_TxEVM1; + ts->evm2 = ads->AR_TxEVM2; + ts->ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); + ts->ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); + ts->ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); + ts->ts_antenna = 0; return 0; } @@ -858,7 +859,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) EXPORT_SYMBOL(ath9k_hw_resettxqueue); int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 pa, struct ath_desc *nds, u64 tsf) + struct ath_rx_status *rs, u64 tsf) { struct ar5416_desc ads; struct ar5416_desc *adsp = AR5416DESC(ds); @@ -869,70 +870,70 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, ads.u.rx = adsp->u.rx; - ds->ds_rxstat.rs_status = 0; - ds->ds_rxstat.rs_flags = 0; + rs->rs_status = 0; + rs->rs_flags = 0; - ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; - ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; + rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen; + rs->rs_tstamp = ads.AR_RcvTimestamp; if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) { - ds->ds_rxstat.rs_rssi = ATH9K_RSSI_BAD; - ds->ds_rxstat.rs_rssi_ctl0 = ATH9K_RSSI_BAD; - ds->ds_rxstat.rs_rssi_ctl1 = ATH9K_RSSI_BAD; - ds->ds_rxstat.rs_rssi_ctl2 = ATH9K_RSSI_BAD; - ds->ds_rxstat.rs_rssi_ext0 = ATH9K_RSSI_BAD; - ds->ds_rxstat.rs_rssi_ext1 = ATH9K_RSSI_BAD; - ds->ds_rxstat.rs_rssi_ext2 = ATH9K_RSSI_BAD; + rs->rs_rssi = ATH9K_RSSI_BAD; + rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD; + rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD; + rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD; + rs->rs_rssi_ext0 = ATH9K_RSSI_BAD; + rs->rs_rssi_ext1 = ATH9K_RSSI_BAD; + rs->rs_rssi_ext2 = ATH9K_RSSI_BAD; } else { - ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); - ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, + rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); + rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); - ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, + rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); - ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, + rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); - ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, + rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); - ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, + rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); - ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, + rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); } if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) - ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); + rs->rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); else - ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID; + rs->rs_keyix = ATH9K_RXKEYIX_INVALID; - ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads)); - ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; + rs->rs_rate = RXSTATUS_RATE(ah, (&ads)); + rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; - ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; - ds->ds_rxstat.rs_moreaggr = + rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; + rs->rs_moreaggr = (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; - ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); - ds->ds_rxstat.rs_flags = + rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); + rs->rs_flags = (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0; - ds->ds_rxstat.rs_flags |= + rs->rs_flags |= (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0; if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE; + rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE; if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST; + rs->rs_flags |= ATH9K_RX_DELIM_CRC_POST; if (ads.ds_rxstatus8 & AR_DecryptBusyErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY; + rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY; if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { if (ads.ds_rxstatus8 & AR_CRCErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC; + rs->rs_status |= ATH9K_RXERR_CRC; else if (ads.ds_rxstatus8 & AR_PHYErr) { - ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY; + rs->rs_status |= ATH9K_RXERR_PHY; phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); - ds->ds_rxstat.rs_phyerr = phyerr; + rs->rs_phyerr = phyerr; } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT; + rs->rs_status |= ATH9K_RXERR_DECRYPT; else if (ads.ds_rxstatus8 & AR_MichaelErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC; + rs->rs_status |= ATH9K_RXERR_MIC; } return 0; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index a5e543bd2271..68dbd7a8ddca 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -233,18 +233,9 @@ struct ath_desc { u32 ds_ctl0; u32 ds_ctl1; u32 ds_hw[20]; - union { - struct ath_tx_status tx; - struct ath_rx_status rx; - void *stats; - } ds_us; void *ds_vdata; } __packed; -#define ds_txstat ds_us.tx -#define ds_rxstat ds_us.rx -#define ds_stat ds_us.stats - #define ATH9K_TXDESC_CLRDMASK 0x0001 #define ATH9K_TXDESC_NOACK 0x0002 #define ATH9K_TXDESC_RTSENA 0x0004 @@ -702,7 +693,8 @@ void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 segLen, bool firstSeg, bool lastSeg, const struct ath_desc *ds0); void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds); -int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds); +int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds, + struct ath_tx_status *ts); void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds, u32 pktLen, enum ath9k_pkt_type type, u32 txPower, u32 keyIx, enum ath9k_key_type keyType, u32 flags); @@ -732,7 +724,7 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q); bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q); int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 pa, struct ath_desc *nds, u64 tsf); + struct ath_rx_status *rs, u64 tsf); void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags); bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 115e1aeedb59..f7ef11407e27 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -225,7 +225,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath_cache_conf_rate(sc, &hw->conf); ath_update_txpow(sc); - ath9k_hw_set_interrupts(ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); ps_restore: ath9k_ps_restore(sc); @@ -434,7 +434,7 @@ void ath9k_tasklet(unsigned long data) ath_gen_timer_isr(sc->sc_ah); /* re-enable hardware interrupt */ - ath9k_hw_set_interrupts(ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); ath9k_ps_restore(sc); } @@ -477,7 +477,7 @@ irqreturn_t ath_isr(int irq, void *dev) * value to insure we only process bits we requested. */ ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ - status &= sc->imask; /* discard unasked-for bits */ + status &= ah->imask; /* discard unasked-for bits */ /* * If there are no status bits set, then this interrupt was not @@ -518,7 +518,7 @@ irqreturn_t ath_isr(int irq, void *dev) * the interrupt. */ ath9k_hw_procmibevent(ah); - ath9k_hw_set_interrupts(ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); } if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) @@ -536,7 +536,7 @@ chip_reset: if (sched) { /* turn off every interrupt except SWBA */ - ath9k_hw_set_interrupts(ah, (sc->imask & ATH9K_INT_SWBA)); + ath9k_hw_set_interrupts(ah, (ah->imask & ATH9K_INT_SWBA)); tasklet_schedule(&sc->intr_tq); } @@ -887,7 +887,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) ath_beacon_config(sc, NULL); /* restart beacons */ /* Re-Enable interrupts */ - ath9k_hw_set_interrupts(ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); /* Enable LED */ ath9k_hw_cfg_output(ah, ah->led_pin, @@ -977,7 +977,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) if (sc->sc_flags & SC_OP_BEACONS) ath_beacon_config(sc, NULL); /* restart beacons */ - ath9k_hw_set_interrupts(ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); if (retry_tx) { int i; @@ -1162,23 +1162,23 @@ static int ath9k_start(struct ieee80211_hw *hw) } /* Setup our intr mask. */ - sc->imask = ATH9K_INT_RX | ATH9K_INT_TX + ah->imask = ATH9K_INT_RX | ATH9K_INT_TX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; if (ah->caps.hw_caps & ATH9K_HW_CAP_GTT) - sc->imask |= ATH9K_INT_GTT; + ah->imask |= ATH9K_INT_GTT; if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) - sc->imask |= ATH9K_INT_CST; + ah->imask |= ATH9K_INT_CST; ath_cache_conf_rate(sc, &hw->conf); sc->sc_flags &= ~SC_OP_INVALID; /* Disable BMISS interrupt when we're not associated */ - sc->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - ath9k_hw_set_interrupts(ah, sc->imask); + ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + ath9k_hw_set_interrupts(ah, ah->imask); ieee80211_wake_queues(hw); @@ -1372,14 +1372,15 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; int ret = 0; mutex_lock(&sc->mutex); - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) && + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) && sc->nvifs > 0) { ret = -ENOBUFS; goto out; @@ -1414,19 +1415,19 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, sc->nvifs++; - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) ath9k_set_bssid_mask(hw); if (sc->nvifs > 1) goto out; /* skip global settings for secondary vif */ if (ic_opmode == NL80211_IFTYPE_AP) { - ath9k_hw_set_tsfadjust(sc->sc_ah, 1); + ath9k_hw_set_tsfadjust(ah, 1); sc->sc_flags |= SC_OP_TSF_RESET; } /* Set the device opmode */ - sc->sc_ah->opmode = ic_opmode; + ah->opmode = ic_opmode; /* * Enable MIB interrupts when there are hardware phy counters. @@ -1435,11 +1436,11 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, if ((vif->type == NL80211_IFTYPE_STATION) || (vif->type == NL80211_IFTYPE_ADHOC) || (vif->type == NL80211_IFTYPE_MESH_POINT)) { - sc->imask |= ATH9K_INT_MIB; - sc->imask |= ATH9K_INT_TSFOOR; + ah->imask |= ATH9K_INT_MIB; + ah->imask |= ATH9K_INT_TSFOOR; } - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC || @@ -1495,15 +1496,16 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, void ath9k_enable_ps(struct ath_softc *sc) { + struct ath_hw *ah = sc->sc_ah; + sc->ps_enabled = true; - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { - if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { - sc->imask |= ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(sc->sc_ah, - sc->imask); + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) { + ah->imask |= ATH9K_INT_TIM_TIMER; + ath9k_hw_set_interrupts(ah, ah->imask); } } - ath9k_hw_setrxabort(sc->sc_ah, 1); + ath9k_hw_setrxabort(ah, 1); } static int ath9k_config(struct ieee80211_hw *hw, u32 changed) @@ -1579,10 +1581,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA | PS_WAIT_FOR_TX_ACK); - if (sc->imask & ATH9K_INT_TIM_TIMER) { - sc->imask &= ~ATH9K_INT_TIM_TIMER; + if (ah->imask & ATH9K_INT_TIM_TIMER) { + ah->imask &= ~ATH9K_INT_TIM_TIMER; ath9k_hw_set_interrupts(sc->sc_ah, - sc->imask); + ah->imask); } } } diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 9441c6718a30..1ec836cf1c0d 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -88,6 +88,7 @@ static void ath_pci_bt_coex_prep(struct ath_common *common) } static const struct ath_bus_ops ath_pci_bus_ops = { + .ath_bus_type = ATH_PCI, .read_cachesize = ath_pci_read_cachesize, .eeprom_read = ath_pci_eeprom_read, .bt_coex_prep = ath_pci_bt_coex_prep, diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 0999a495fd46..0132e4c9a9f9 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -503,6 +503,8 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah, #define AR_PHY_TX_PWRCTRL_ERR_EST_MODE_S 24 #define AR_PHY_TX_PWRCTRL7 0xa274 +#define AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX 0x0007E000 +#define AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX_S 13 #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000 #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19 @@ -513,8 +515,16 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah, #define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31 #define AR_PHY_TX_GAIN_TBL1 0xa300 -#define AR_PHY_TX_GAIN 0x0007F000 -#define AR_PHY_TX_GAIN_S 12 +#define AR_PHY_TX_GAIN_CLC 0x0000001E +#define AR_PHY_TX_GAIN_CLC_S 1 +#define AR_PHY_TX_GAIN 0x0007F000 +#define AR_PHY_TX_GAIN_S 12 + +#define AR_PHY_CLC_TBL1 0xa35c +#define AR_PHY_CLC_I0 0x07ff0000 +#define AR_PHY_CLC_I0_S 16 +#define AR_PHY_CLC_Q0 0x0000ffd0 +#define AR_PHY_CLC_Q0_S 5 #define AR_PHY_CH0_TX_PWRCTRL11 0xa398 #define AR_PHY_CH1_TX_PWRCTRL11 0xb398 diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 36083dde863d..3d8d40cdc99e 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -176,9 +176,9 @@ struct ath_rate_priv { #define ATH_TX_INFO_UNDERRUN (1 << 4) enum ath9k_internal_frame_type { - ATH9K_NOT_INTERNAL, - ATH9K_INT_PAUSE, - ATH9K_INT_UNPAUSE + ATH9K_IFT_NOT_INTERNAL, + ATH9K_IFT_PAUSE, + ATH9K_IFT_UNPAUSE }; int ath_rate_control_register(void); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 1ca42e5148c8..94560e2fe376 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -477,7 +477,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) struct ath_buf *bf; struct ath_desc *ds; - struct ath_rx_status *rx_stats; struct sk_buff *skb = NULL, *requeue_skb; struct ieee80211_rx_status *rxs; struct ath_hw *ah = sc->sc_ah; @@ -491,6 +490,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) struct ieee80211_hdr *hdr; int retval; bool decrypt_error = false; + struct ath_rx_status rs; spin_lock_bh(&sc->rx.rxbuflock); @@ -518,14 +518,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * on. All this is necessary because of our use of * a self-linked list to avoid rx overruns. */ - retval = ath9k_hw_rxprocdesc(ah, ds, - bf->bf_daddr, - PA2DESC(sc, ds->ds_link), - 0); + memset(&rs, 0, sizeof(rs)); + retval = ath9k_hw_rxprocdesc(ah, ds, &rs, 0); if (retval == -EINPROGRESS) { + struct ath_rx_status trs; struct ath_buf *tbf; struct ath_desc *tds; + memset(&trs, 0, sizeof(trs)); if (list_is_last(&bf->list, &sc->rx.rxbuf)) { sc->rx.rxlink = NULL; break; @@ -545,8 +545,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) */ tds = tbf->bf_desc; - retval = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr, - PA2DESC(sc, tds->ds_link), 0); + retval = ath9k_hw_rxprocdesc(ah, tds, &trs, 0); if (retval == -EINPROGRESS) { break; } @@ -569,9 +568,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) rxs = IEEE80211_SKB_RXCB(skb); hw = ath_get_virt_hw(sc, hdr); - rx_stats = &ds->ds_rxstat; - ath_debug_stat_rx(sc, bf); + ath_debug_stat_rx(sc, &rs); /* * If we're asked to flush receive queue, directly @@ -580,7 +578,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) if (flush) goto requeue; - retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, rx_stats, + retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, &rs, rxs, &decrypt_error); if (retval) goto requeue; @@ -601,9 +599,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) common->rx_bufsize, DMA_FROM_DEVICE); - skb_put(skb, rx_stats->rs_datalen); + skb_put(skb, rs.rs_datalen); - ath9k_cmn_rx_skb_postprocess(common, skb, rx_stats, + ath9k_cmn_rx_skb_postprocess(common, skb, &rs, rxs, decrypt_error); /* We will now give hardware our shiny new allocated skb */ @@ -626,9 +624,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * change the default rx antenna if rx diversity chooses the * other antenna 3 times in a row. */ - if (sc->rx.defant != ds->ds_rxstat.rs_antenna) { + if (sc->rx.defant != rs.rs_antenna) { if (++sc->rx.rxotherant >= 3) - ath_setdefantenna(sc, rx_stats->rs_antenna); + ath_setdefantenna(sc, rs.rs_antenna); } else { sc->rx.rxotherant = 0; } diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 198e41dd38a6..7e36ad7421b7 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -679,7 +679,7 @@ #define AR_WA 0x4004 #define AR_WA_D3_L1_DISABLE (1 << 14) -#define AR9285_WA_DEFAULT 0x004a05cb +#define AR9285_WA_DEFAULT 0x004a050b #define AR9280_WA_DEFAULT 0x0040073b #define AR_WA_DEFAULT 0x0000073f @@ -845,6 +845,10 @@ (AR_SREV_9271(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11)) +#define AR_SREV_9285E_20(_ah) \ + (AR_SREV_9285_12_OR_LATER(_ah) && \ + ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1)) + #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 #define AR_RAD2133_SREV_MAJOR 0xd0 @@ -1181,6 +1185,13 @@ enum { #define AR9285_AN_RF2G4_DB2_4 0x00003800 #define AR9285_AN_RF2G4_DB2_4_S 11 +#define AR9285_RF2G5 0x7830 +#define AR9285_RF2G5_IC50TX 0xfffff8ff +#define AR9285_RF2G5_IC50TX_SET 0x00000400 +#define AR9285_RF2G5_IC50TX_XE_SET 0x00000500 +#define AR9285_RF2G5_IC50TX_CLEAR 0x00000700 +#define AR9285_RF2G5_IC50TX_CLEAR_S 8 + /* AR9271 : 0x7828, 0x782c different setting from AR9285 */ #define AR9271_AN_RF2G3_OB_cck 0x001C0000 #define AR9271_AN_RF2G3_OB_cck_S 18 diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 00c0e21a4af7..105ad40968f6 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -220,7 +220,7 @@ static int ath9k_send_nullfunc(struct ath_wiphy *aphy, memset(&txctl, 0, sizeof(struct ath_tx_control)); txctl.txq = &sc->tx.txq[sc->tx.hwq_map[ATH9K_WME_AC_VO]]; - txctl.frame_type = ps ? ATH9K_INT_PAUSE : ATH9K_INT_UNPAUSE; + txctl.frame_type = ps ? ATH9K_IFT_PAUSE : ATH9K_IFT_UNPAUSE; if (ath_tx_start(aphy->hw, skb, &txctl) != 0) goto exit; diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 818dea0164ec..f2ff18cf3e60 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -169,7 +169,7 @@ void ath9k_wmi_tasklet(unsigned long data) break; } - dev_kfree_skb_any(skb); + kfree_skb(skb); } static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb) @@ -207,13 +207,13 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, ath9k_wmi_rsp_callback(wmi, skb); free_skb: - dev_kfree_skb_any(skb); + kfree_skb(skb); } static void ath9k_wmi_ctrl_tx(void *priv, struct sk_buff *skb, enum htc_endpoint_id epid, bool txok) { - dev_kfree_skb_any(skb); + kfree_skb(skb); } int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi, @@ -269,7 +269,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, if (!wmi) return -EINVAL; - skb = dev_alloc_skb(headroom + cmd_len); + skb = alloc_skb(headroom + cmd_len, GFP_ATOMIC); if (!skb) return -ENOMEM; @@ -313,7 +313,7 @@ out: ath_print(common, ATH_DBG_WMI, "WMI failure for: %s\n", wmi_cmd_to_name(cmd_id)); mutex_unlock(&wmi->op_mutex); - dev_kfree_skb_any(skb); + kfree_skb(skb); return ret; } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index a3b6cf20f8a1..02df4cbf179f 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -59,15 +59,14 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, struct list_head *bf_head); static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, - struct ath_txq *txq, - struct list_head *bf_q, - int txok, int sendbar); + struct ath_txq *txq, struct list_head *bf_q, + struct ath_tx_status *ts, int txok, int sendbar); static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, struct list_head *head); static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf); static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, - int txok); -static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, + struct ath_tx_status *ts, int txok); +static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, int nbad, int txok, bool update_rc); enum { @@ -223,6 +222,9 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, { struct ath_buf *bf; struct list_head bf_head; + struct ath_tx_status ts; + + memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); for (;;) { @@ -236,7 +238,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, ath_tx_update_baw(sc, tid, bf->bf_seqno); spin_unlock(&txq->axq_lock); - ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); spin_lock(&txq->axq_lock); } @@ -286,7 +288,7 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf, struct list_head *bf_q, - int txok) + struct ath_tx_status *ts, int txok) { struct ath_node *an = NULL; struct sk_buff *skb; @@ -296,7 +298,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ieee80211_tx_info *tx_info; struct ath_atx_tid *tid = NULL; struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; - struct ath_desc *ds = bf_last->bf_desc; struct list_head bf_head, bf_pending; u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; @@ -325,10 +326,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, memset(ba, 0, WME_BA_BMP_SIZE >> 3); if (isaggr && txok) { - if (ATH_DS_TX_BA(ds)) { - seq_st = ATH_DS_BA_SEQ(ds); - memcpy(ba, ATH_DS_BA_BITMAP(ds), - WME_BA_BMP_SIZE >> 3); + if (ts->ts_flags & ATH9K_TX_BA) { + seq_st = ts->ts_seqnum; + memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3); } else { /* * AR5416 can become deaf/mute when BA @@ -345,7 +345,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, INIT_LIST_HEAD(&bf_pending); INIT_LIST_HEAD(&bf_head); - nbad = ath_tx_num_badfrms(sc, bf, txok); + nbad = ath_tx_num_badfrms(sc, bf, ts, txok); while (bf) { txfail = txpending = 0; bf_next = bf->bf_next; @@ -359,7 +359,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, acked_cnt++; } else { if (!(tid->state & AGGR_CLEANUP) && - ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { + ts->ts_flags != ATH9K_TX_SW_ABORTED) { if (bf->bf_retries < ATH_MAX_SW_RETRIES) { ath_tx_set_retry(sc, txq, bf); txpending = 1; @@ -402,13 +402,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, spin_unlock_bh(&txq->axq_lock); if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { - ath_tx_rc_status(bf, ds, nbad, txok, true); + ath_tx_rc_status(bf, ts, nbad, txok, true); rc_update = false; } else { - ath_tx_rc_status(bf, ds, nbad, txok, false); + ath_tx_rc_status(bf, ts, nbad, txok, false); } - ath_tx_complete_buf(sc, bf, txq, &bf_head, !txfail, sendbar); + ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, + !txfail, sendbar); } else { /* retry the un-acked ones */ if (bf->bf_next == NULL && bf_last->bf_stale) { @@ -426,10 +427,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, spin_unlock_bh(&txq->axq_lock); bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, ds, nbad, + ath_tx_rc_status(bf, ts, nbad, 0, false); ath_tx_complete_buf(sc, bf, txq, - &bf_head, 0, 0); + &bf_head, ts, 0, 0); break; } @@ -752,8 +753,11 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum]; + struct ath_tx_status ts; struct ath_buf *bf; struct list_head bf_head; + + memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); if (txtid->state & AGGR_CLEANUP) @@ -780,7 +784,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) } list_move_tail(&bf->list, &bf_head); ath_tx_update_baw(sc, txtid, bf->bf_seqno); - ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); } spin_unlock_bh(&txq->axq_lock); @@ -1028,6 +1032,11 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) { struct ath_buf *bf, *lastbf; struct list_head bf_head; + struct ath_tx_status ts; + + memset(&ts, 0, sizeof(ts)); + if (!retry_tx) + ts.ts_flags = ATH9K_TX_SW_ABORTED; INIT_LIST_HEAD(&bf_head); @@ -1053,9 +1062,6 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) } lastbf = bf->bf_lastbf; - if (!retry_tx) - lastbf->bf_desc->ds_txstat.ts_flags = - ATH9K_TX_SW_ABORTED; /* remove ath_buf's of the same mpdu from txq */ list_cut_position(&bf_head, &txq->axq_q, &lastbf->list); @@ -1064,9 +1070,9 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) spin_unlock_bh(&txq->axq_lock); if (bf_isampdu(bf)) - ath_tx_complete_aggr(sc, txq, bf, &bf_head, 0); + ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0); else - ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); } spin_lock_bh(&txq->axq_lock); @@ -1568,12 +1574,12 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, tx_info->pad[0] = 0; switch (txctl->frame_type) { - case ATH9K_NOT_INTERNAL: + case ATH9K_IFT_NOT_INTERNAL: break; - case ATH9K_INT_PAUSE: + case ATH9K_IFT_PAUSE: tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE; /* fall through */ - case ATH9K_INT_UNPAUSE: + case ATH9K_IFT_UNPAUSE: tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL; break; } @@ -1852,9 +1858,8 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, } static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, - struct ath_txq *txq, - struct list_head *bf_q, - int txok, int sendbar) + struct ath_txq *txq, struct list_head *bf_q, + struct ath_tx_status *ts, int txok, int sendbar) { struct sk_buff *skb = bf->bf_mpdu; unsigned long flags; @@ -1872,7 +1877,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); ath_tx_complete(sc, skb, bf->aphy, tx_flags); - ath_debug_stat_tx(sc, txq, bf); + ath_debug_stat_tx(sc, txq, bf, ts); /* * Return the list of ath_buf of this mpdu to free queue @@ -1883,23 +1888,21 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, } static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, - int txok) + struct ath_tx_status *ts, int txok) { - struct ath_buf *bf_last = bf->bf_lastbf; - struct ath_desc *ds = bf_last->bf_desc; u16 seq_st = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; int ba_index; int nbad = 0; int isaggr = 0; - if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) + if (ts->ts_flags == ATH9K_TX_SW_ABORTED) return 0; isaggr = bf_isaggr(bf); if (isaggr) { - seq_st = ATH_DS_BA_SEQ(ds); - memcpy(ba, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3); + seq_st = ts->ts_seqnum; + memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3); } while (bf) { @@ -1913,7 +1916,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, return nbad; } -static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, +static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, int nbad, int txok, bool update_rc) { struct sk_buff *skb = bf->bf_mpdu; @@ -1923,24 +1926,24 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, u8 i, tx_rateindex; if (txok) - tx_info->status.ack_signal = ds->ds_txstat.ts_rssi; + tx_info->status.ack_signal = ts->ts_rssi; - tx_rateindex = ds->ds_txstat.ts_rateindex; + tx_rateindex = ts->ts_rateindex; WARN_ON(tx_rateindex >= hw->max_rates); - if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) + if (ts->ts_status & ATH9K_TXERR_FILT) tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) tx_info->flags |= IEEE80211_TX_STAT_AMPDU; - if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && + if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { if (ieee80211_is_data(hdr->frame_control)) { - if (ds->ds_txstat.ts_flags & + if (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN)) tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN; - if ((ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) || - (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO)) + if ((ts->ts_status & ATH9K_TXERR_XRETRY) || + (ts->ts_status & ATH9K_TXERR_FIFO)) tx_info->pad[0] |= ATH_TX_INFO_XRETRY; tx_info->status.ampdu_len = bf->bf_nframes; tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad; @@ -1978,6 +1981,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) struct ath_buf *bf, *lastbf, *bf_held = NULL; struct list_head bf_head; struct ath_desc *ds; + struct ath_tx_status ts; int txok; int status; @@ -2017,7 +2021,8 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) lastbf = bf->bf_lastbf; ds = lastbf->bf_desc; - status = ath9k_hw_txprocdesc(ah, ds); + memset(&ts, 0, sizeof(ts)); + status = ath9k_hw_txprocdesc(ah, ds, &ts); if (status == -EINPROGRESS) { spin_unlock_bh(&txq->axq_lock); break; @@ -2028,7 +2033,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) * can disable RX. */ if (bf->bf_isnullfunc && - (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) { + (ts.ts_status & ATH9K_TX_ACKED)) { if ((sc->ps_flags & PS_ENABLED)) ath9k_enable_ps(sc); else @@ -2047,7 +2052,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) &txq->axq_q, lastbf->list.prev); txq->axq_depth--; - txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_MASK); + txok = !(ts.ts_status & ATH9K_TXERR_MASK); txq->axq_tx_inprogress = false; spin_unlock_bh(&txq->axq_lock); @@ -2062,16 +2067,16 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) * This frame is sent out as a single frame. * Use hardware retry status for this frame. */ - bf->bf_retries = ds->ds_txstat.ts_longretry; - if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) + bf->bf_retries = ts.ts_longretry; + if (ts.ts_status & ATH9K_TXERR_XRETRY) bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, ds, 0, txok, true); + ath_tx_rc_status(bf, &ts, 0, txok, true); } if (bf_isampdu(bf)) - ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok); + ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok); else - ath_tx_complete_buf(sc, bf, txq, &bf_head, txok, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0); ath_wake_mac80211_queue(sc, txq); diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c index ecc9eb01f4fa..a8f81ea09f14 100644 --- a/drivers/net/wireless/ath/hw.c +++ b/drivers/net/wireless/ath/hw.c @@ -19,8 +19,8 @@ #include "ath.h" #include "reg.h" -#define REG_READ common->ops->read -#define REG_WRITE common->ops->write +#define REG_READ (common->ops->read) +#define REG_WRITE (common->ops->write) /** * ath_hw_set_bssid_mask - filter out bssids we listen diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 00489c40be0c..24d59883d944 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -50,6 +50,7 @@ #define ATH9K_5GHZ_ALL ATH9K_5GHZ_5150_5350, \ ATH9K_5GHZ_5470_5850 + /* This one skips what we call "mid band" */ #define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \ ATH9K_5GHZ_5725_5850 @@ -360,7 +361,7 @@ EXPORT_SYMBOL(ath_reg_notifier_apply); static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) { - u16 rd = ath_regd_get_eepromRD(reg); + u16 rd = ath_regd_get_eepromRD(reg); int i; if (rd & COUNTRY_ERD_FLAG) { |